JAVA WEB DAY 01_Tomcat & Servlet

冷暖自知 提交于 2020-09-28 19:47:30

Tomcat 服务器与 Servlet


目标

  • 理解软件架构
  • 启动 & 关闭 Tomcat 服务器
  • 解决 Tomcat 启动时遇到的问题
  • 运用 Tomcat 部署 web 项目
  • 使用 IDEA 编写 Servlet
  • 使用注解开发Servlet
  • 理解 Servlet 生命周期

01 软件架构 [★]

C/S 结构:客户端服务器

  • 优势:用户体验好,客户端完成一些运行,减轻服务器压力
  • 缺点:开发成本高,维护成本高,开发周期长

B/S 结构:浏览器服务器

  • 优点:开发成本低,维护成本低,开发周期短
  • 缺点:服务器压力大

02 web资源概述[★]

web资源:浏览器上显示的所有内容(文字、图片、视频、音频、超链接等)

分类 概述 技术
静态资源 写死在网页上,不和数据库交换 HTML/JS/CSS
动态资源 来自数据库 JSP/Servlet

03 web服务器概述[★★]

03_01 常见web服务器

web服务器的概念:运行在高性能计算机上的软件。
web服务器的作用:可以将开发出来的资源提供外界访问。

JavaEE规范:Java中所有服务器要实现一组Oracle公司规定的接口,这些接口称为JavaEE规范。在JavaEE中一共有13种规范。
常见的JavaEE规范:JSP、Servlet、JDBC、XML、EJB
Tomcat服务器只支持了JSP和Servlet规范,所以Tomcat服务器有称为Servlet容器。

名称 种类 公司 描述
WebLogic 大型服务器 Oracle 收费 非开源 支持全部JavaEE规范
WebSphere 大型服务器 IBM 收费 非开源 支持全部JavaEE规范
Glass Fish 中型服务器 Oracle 免费 开源 支持部分JavaEE规范
JBoss 中型服务器 JBoss 免费 开源 支持部分JavaEE规范
Resin 小型服务器 Caucho 免费 开源 支持部分JavaEE规范
Jetty 内置式服务器 Jetty/eclipse 免费 开源 支持部分JavaEE规范
Tomcat 小型服务器 Apache 免费 开源 支持部分JavaEE规范

04 模拟一个 web 服务器[★]

  • 需求:使用socket模拟一个web服务器:实现用户从浏览器访问服务器时返回一个网页给浏览器显示。
  • 步骤:
    1.采用多线程的方式,每个用户创建一个线程
    2.当有用户连接的时候在服务器控制台输出信息
    3.在线程的run方法中读取本地服务器的资源,得到输入流对象
    4.通过Socket得到输出流,输出到客户端
    5.客户端使用IE浏览器访问效果图如下
    在这里插入图片描述





public class MyTomcat extends Thread {
   
     
    private Socket socket;

    public MyTomcat(Socket socket) {
   
     
        this.socket = socket;
    }

    @Override
    public void run() {
   
     
        try {
   
     
            // 获得字节输出流对象
            OutputStream out = socket.getOutputStream();

            // 3 返回数据给浏览器显示
            // 3.1 创建字节数组:用来存储读取到的文件数据
            FileInputStream fis = new FileInputStream("G:\\project\\qrsx\\workspace\\day01\\hello.html");
            // 3.2 创建字节数组:用来存储读取的文件数据
            byte[] buf = new byte[1024];
            // 3.3 读取内容到字节数组中
            int len = -1;
            while ((len = fis.read(buf)) != -1) {
   
     
                // 4.1 将读取到的内容输出到浏览器
                out.write(buf);
            }
            socket.close();
            fis.close();
        } catch (IOException e) {
   
     
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
   
     
        // 1 创建ServerSocket对象:一个该对象代表一个服务器程序
        ServerSocket serverSocket = new ServerSocket(8888);

        while (true) {
   
     
            // 2 acceot:等待用户连接服务器并获得Socket
            Socket socket = serverSocket.accept();
            // 3 创建线程
            MyTomcat tomcat = new MyTomcat(socket);
            // 4 开启线程
            tomcat.start();
        }
    }
}

05 Tomcat 启动和关闭[★★★]

方式1 方式2
Tomcat启动 进入DOS窗口输入:startup.bat 进入安装目录下的bin双击startup.bat文件
Tomcat关闭 进入DOS窗口输入:shutdown.bat 进入安装目录下的bin双击shutdown.bat文件

06 Tomcat 目录结构[★★]

目录名 作用
bin 存储Tomcat所有的可以运行文件
conf 存储Tomcat核心配置文件:server.xml和web.xml
lib 存储Tomcat运行过程中使用到的jar包
logs 存储Tomcat运行过程中产生的日志信息:包括异常信息
temp 存储Tomcat运行过程中产生的临时文件
webapps 存储部署项目的位置
如果项目需要被外界访问,则需要将项目部署到该目录
work 存储Tomcat运行过程中编译产生的文件
比如jsp编译后的文件

07 Tomcat 启动时常见问题[★★★]

  1. 服务器启动一闪而过:
    -解决方案:配置 JAVA_HOME
  2. Tomcat 默认端口8080被其他程序占用:
    -解决方案:
    1. 找到占用8080端口的程序并杀死
    2. 修改 Tomcat 默认端口号,修改 conf/server.xml文件第69行

08 Tomcat项目的发布方式[★★★★]

08_01 方式1:webapps

  1. 在 webapps 目录下创建一个文件夹,名字任意,在文件下创建网页文件:index.html
  2. 启动 Tomcat 服务器,浏览器输入访问地址:
    http://localhost:8080/文件夹名称/index.html

缺点:项目发布在 webapps 下,如果项目太多,导致 Tomcat 启动越慢

08_02 方式2:虚拟目录

  • 在 conf/server.xml 文件的 host 元素中配置 Context 元
  • 案例:
  1. 发布项目到 e:\xxx\ 下,index.html 文件
  2. 找到 server.xml 文件中 143 行,host 元素,写下面的代码:
<!--上下文路径 ,path 访问地址,docBase目录-->
<Context path="/xxx" docBase="e:/xxx" />
  • Context 元素常用属性如下:
Context元素常用两个属性
path属性 虚拟访问目录的名称
docBase属性 web应用程序的真实路径地址

08_03 方式3:配置独立xml文件

IDEA 中默认使用该种方式

  • 步骤:
  1. 在 tomcat/conf 目录下创建一个 Catalina 文件夹(如果存在则无需创建)
  2. 在 Catalina 文件夹下创建 localhost 目录(如果存在则无需创建)
  3. 在 localhost 文件夹下创建 xml 配置文件,名称:second
    -配置文件名字可以任意,这个名字就是浏览器访问路径
  4. 在配置文件 second.xml 中添加如下内容:
<!-- docBase:web应用的路径 -->
<Context docBase="g:/project/workspace/web项目名称" >
  1. 在 web 项目下创建 index.html,在浏览器访问测试,访问地址如下:
    http://localhost:8080/second/index.html

09 IDEA 中配置和启动 Tomcat[★★]

  • 待完成

10 Servlet 概述和开发步骤[★★★★]

10_01 Servlet(Server Applet):

  • 服务器小程序;
  • 一个运行在服务器端的小程序(一个Java类)

10_02 Servlet 的作用:

  • 用来接收请求和响应数据

10_03 Servlet 的开发步骤:

  1. 创建一个类:实现一个 Servlet 接口
  2. 重写接口中的所有抽象方法
  3. 在重写的 service 方法中处理请求响应数据
  4. 配置Servlet访问路径:xml 配置或注解配置
  5. 将项目部署到服务器
  6. 打开浏览器访问 Servlet

11 Servlet 入门案例-配置文件方式[★★★]

  • 需求:使用 Servlet 往浏览器输出:Hello Servlet
  • 步骤:
    1.在 com.ntt.servlet 包下创建一个 HelloServlet 类实现 Servlet 接口;
    2.重写 service 方法,在浏览器上使用打印流输出:Hello Servlet

  • java 代码
// 1. 创建一个类:实现一个Servlet接口
public class HelloServlet implements Servlet {
   
     
    // 2. 重写接口中的所有抽象方法
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
   
     

    }

    @Override
    public ServletConfig getServletConfig() {
   
     
        return null;
    }

    // 3. 在重写的service方法中处理请求和响应数据
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
   
     
        // 获得字符输出流
        PrintWriter pw = servletResponse.getWriter();
        // 输出数据到浏览器
        pw.println("Hello Servlet");
    }

    @Override
    public String getServletInfo() {
   
     
        return null;
    }

    @Override
    public void destroy() {
   
     

    }
}
  • web.xml 配置文件信息
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
         
    <servlet>
        <!--配置Servlet的名字-->
        <servlet-name>hello</servlet-name>
        <!--配置Servlet的类全名字符串:包含包名+类名的-->
        <servlet-class>com.ntt.HelloServlet</servlet-class>
    </servlet>
    <!--配置servlet的访问地址-->
    <servlet-mapping>
        <!--必须和上面的一致 -->
        <servlet-name>hello</servlet-name>
        <!-- Servlet的访问路径,必须/开头-->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

问题:
浏览器输入地址请求 Servlet 时会调用 Servlet 哪个方法?

  • 调用 service 方法

12 Servlet 入门案例-注解配置方法[★★★★]

  • 需求:同上

@webServlet 作用:设置 Servlet 访问地址

  • urlPatterns 属性:访问路径;
    等价 xml 配置的标签:<url-pattern>/hello</url-pattern>
  • name 属性:设置名字:
    等价 xml 配置的标签:<servlet-name>hello</servlet-name>

注意:name 和 urlPatterns 属性值必须唯一

@WebServlet(name="hello",urlPatterns="/hello")
public class HelloServlet implements Servlet {
   
     

}

问题:
使用注解 @WebServlet 配置 servlet 时通过哪个属性设置访问路径?

  • 通过 urlPatterns 属性配置:@WebServlet(urlPatterns="/hello")

13 Servlet 生命周期[★★]

13_01 Servlet 运行过程:

Servlet 运行过程

  • Java 代码
@WebServlet(urlPatterns = "/life")
public class LifeCycleServlet implements Servlet {
   
     
    // 构造方法:浏览器第一次访问时执行,只会执行一次
    public LifeCycleServlet(){
   
     
        System.out.println("执行了无参数构造方法.....");
    }

    // 初始化方法:执行初始化操作,构造方法执行之后  只会执行1次
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
   
     
        System.out.println("init调用了...");
    }

    // 处理请求和响应,浏览器每次访问都会执行
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
   
     
        System.out.println("service方法执行了....");
    }

    // 销毁方法:服务器关闭或重启时执行  执行1次
    @Override
    public void destroy() {
   
     
        System.out.println("destroy调用....");
    }

    @Override
    public ServletConfig getServletConfig() {
   
     
        return null;
    }

    @Override
    public String getServletInfo() {
   
     
        return null;
    }
}

13_02 Servlet 生命周期相关方法

与Servlet生命周期相关的方法 作用 运行次数
构造方法 创建对象 1次
void init(ServletConfig config) 初始化方法 1次
void service(ServletRequest req,ServletResponse res) 处理请求和响应数据 n次
void destroy() 销毁资源 1次

问题:
Servlet 是谁负责创建?

  • web 服务器(Tomcat)

什么时候创建 Servlet?

  • 浏览器第一次访问时

什么时候销毁 Servlet?

  • 服务器关闭或重启

一个 Servlet 在 Tomcat 中会生成几个对象?

  • 1个

14 Servlet 运行原理[★★]

14_01 XML 配置运行原理[★]

14_01_01 Servlet的运行原理

  1. 服务器启动时会解析 web.xml 文件:读取配置信息
  2. 服务器内部会创建两个 Map 集合存储配置信息
    2.1 Map<String,String> map01 = new HashMap();
    * 键:Servlet 的名字 值:Servlet 类全名字符串
    map01.put("hello","com.ntt.HelloServlet");
    2.2 Map<String,String> map02 = new HashMap();
    * 键:Servlet 访问地址 值:Servlet 的名字
    map02.put("/hello","hello");





  3. 用户输入访问地址:http://localhost:8080/day01/hello
    服务器会从地址栏解析到请求的资源路径:/hello
  4. 将资源路径作为 map02 集合的键获得对应的值:map02.get("/hello");
    获得Servlet的名字
  5. 将 Servlet 的名字作为 map01 集合的键获得对应的值:map01.get(“hello”);
    获得 Servlet 的类全名字符串
  6. 利用反射根据类全名字符串获得Class对象,然后就可以创建对应 Servlet 的对象
  7. 调用 Servlet 对象的 service 方法

14_02 注解配置运行原理[★★]

在这里插入图片描述

  1. 浏览器发送请求,Tomcat 接收到请求并通过解析请求地址获取到要访问的项目和资源路径
    项目访问路径:/one
    资源路径:/hello

  2. Tomcat 服务器内部会扫描 one 项目下的所有 Servlet:获得每一个 Servlet 的访问地址并存储到集合中:
    Map<String,String> map = new HashMap<>();
    map.put("/hello","com.pkx.HelloServlet");

  3. 将 资源路径 /hello 作为键从 map 集合中获得值:类全名字符串
  4. 通过反射实例化这个 Servlet 对象
  5. 创建 request和 response 对象
  6. 调用 service 方法,将 request 和 response 对象传递进来。
  7. 在 service 方法中通过 response 对象返回输出到浏览器,在浏览器上显示出来。

15 创建 Servlet 之继承 HttpServlet[★★★]

  • 需求:同上
  • 继承 HttpServlet 开发步骤:
    1.创建一个类继承HttpServlet
    2.重写doGet或doPost方法:处理请求和响应数据
    3.配置访问路径
    4.部署到服务器并启动
    5.浏览器访问即可




@WebServlet(urlPatterns="/one")
public class OneServlet extends HttpServlet {
   
     
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   
     
        // 获得字符输出流
        PrintWriter pw = response.getWriter();
        // 往浏览器响应数据
        pw.println("Hello HttpServlet");
    }
}

16 Servlet 体系结构[★★]

16_01 Servlet 的体系结构图

Servlet的体系结构图

16_02 创建 Servlet 继承 GenericServlet

@WebServlet(urlPatterns = "/two")
public class TwoServlet extends GenericServlet {
   
     

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
   
     
        System.out.println("继承GenericServlet");
    }
}

问题
Servlet 继承体系?

  • Servlet ---- 接口
     GenericServlet ---- 抽象类
      HttpServlet ---- 抽象类

我们开发的 Servlet 类继承谁?

  • 因为浏览器和服务器通信使用的 Http 协议,所以以后开发 Servlet 都继承 HttpServlet 即可

17 HttpServlet 源码分析[★]

  • HttpServlet 源码
public abstract class HttpServlet extends GenericServlet {
   
     
    private static final String METHOD_GET = "GET";
    private static final String METHOD_POST = "POST";

    public HttpServlet() {
   
     
    }

    // doGet方法
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
     
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
   
     
            // 发送错误信息给浏览器
            resp.sendError(405, msg);
        } else {
   
     
            resp.sendError(400, msg);
        }

    }


    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
     
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
   
     
            resp.sendError(405, msg);
        } else {
   
     
            resp.sendError(400, msg);
        }

    }

    // 重载的service方法
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
     
        // 获取请求方式:GET 或 POST
        String method = req.getMethod(); // GET
      
        long lastModified;
        if (method.equals("GET")) {
   
     
            this.doGet(req, resp);
          
        }  else if (method.equals("POST")) {
   
     
            this.doPost(req, resp);
        } 

    }

 
    // 重写Servlet接口的service
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
   
     
        HttpServletRequest request;
        HttpServletResponse response;
        try {
   
     
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
   
     
            throw new ServletException("non-HTTP request or response");
        }
        this.service(request, response);
    }
}

问题
doPost 和 doGet 方法如何调用执行?

  • 在父类的 service 方法根据请求方式判断是调用 doGet 还是 doPost,如果是 get 请求则调用 doGet 方法,如果是 post 请求则触发 doPost 方法。

什么时候重写 doGet ?什么是重写 doPost ?

  • 如果表单中明确指定提交方式是 post 提交则重写 doPost 方法,其他一律重写 doGet 方法即可。

18 Servlet 映射多路径[★]

18_01 XML 方式1:

一个<servlet-mapping>中写多个<url-pattern>

18_02 XML 方式2:

一个<servlet>对应多个<servlet-mapping>

18_03 注解 方式3:

@WebServlet(urlPatterns = {"/bbb","/aaa"})

19 url-patterns 的通配符[★]

通配符格式 说明
/*
/目录名/*
/* :匹配所有的访问地址
/admin/*:匹配admin目录下的所有地址
*.扩展名 匹配某个扩展名结尾的访问地址。如:*.action *.do

注意:不能同时/*.扩展名的访问路径:会导致整个web项目加载失败,所有的web资源都不能访问。项目启动会报如下错误:


Caused by: java.lang.IllegalArgumentException: Invalid <url-pattern> /admin/*.action in servlet mapping


优先级:/ 开头的访问路径优先级高于扩展名结尾路径
匹配原则:最优匹配原则,地址越接近谁就执行谁

20 扩展-DefaultServlet概述

DefaultServlet的作用:处理项目中的静态资源

注意事项:
如果我们的项目中有 /* 的访问地址,则我们的地址会覆盖DefaultServlet的访问地址,会导致所有的 HTML 都无法访问。

总结

web 资源:网页上显示的所有数据:文本,图片,视频,音频…


web 资源的分类

  • 静态资源:没有与数据库交互,数据直接写死文件中 可以使用的技术:HTML/CSS/JS
  • 动态资源:数据来自数据库 可以使用的技术:JSP/Servlet

web 服务器:一个运行在高性能计算机上的软件,可以将本机的资源提供给外界访问。


Tomcat 发布项目方式

  • 方式1:直接将项目复制到webapps目录下
  • 方式2:虚拟目录:项目可以放在任意位置,需要修改 conf/server.xml 文件,在第69行添加如下代码:
    <Context path="/项目的访问路径" docBase="项目的真实路径" />
  • 方式3:配置独立的xml文件:在 conf/catalina/localhost 目录下创建xml文件,文件名任意(就是项目访问路径)
    在 xml 文件中添加配置信息: <Context docBase="项目的真实路径" />

Servlet 是什么

  • 运行在服务器端的一个小程序(一个实现Servlet的类)

Servlet 的作用

  • 接收浏览器的请求并响应数据给浏览器

Servlet的开发步骤

  1. 创建一个类继承HttpServlet
  2. 重写doGet或doPost方法:处理请求和响应数据
  3. 使用注解配置访问地址
  4. 部署项目到服务器并启动
  5. 通过浏览器访问即可

Servlet生命周期相关方法

  1. 无参数构造方法:浏览器第一次访问创建对象时调用,只会调用1次
  2. init:执行初始化操作 只会执行1次
  3. service:处理请求和响应 每次请求执行1次
  4. destory:服务器重启或关闭调用,用于释放资源 只会执行1次

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!