Servlet

一、概述


  1. servlet是javaEE规范之一,规范就是接口

  2. servlet是javaWeb的三大组件之一

    ​ 三大组件:servlet程序、filter过滤器、listener监听器

  3. servlet是一个运行在服务器上的一个java小程序,他可以接收用户发送过来的请求并进行一定的处理响应给客户端

  4. servlet是一种动态web资源开发技术,使用servlet可以实现不同请求处理完毕以后显示不同的内容

二、手动实现servlet程序


  1. 编写一个类,去实现servlet接口

  2. 实现接口中的抽象方法,service()是功能执行的方法

  3. 在新建的类上添加@WebServlet注解

    @WebServlet("/servlet1")
    public class MyServlet1 implements Servlet {
        /**
         * 初始化
         * @param servletConfig
         * @throws ServletException
         */
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
        }
    
        /**
         * 获取servlet配置
         * @return
         */
        @Override
        public ServletConfig getServletConfig() {
            return null;
        }
    
        /**
         * 服务
         * @param servletRequest
         * @param servletResponse
         * @throws ServletException
         * @throws IOException
         */
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            System.out.println("servlet1服务");
        }
    
        /**
         * 获取servlet信息
         * @return
         */
        @Override
        public String getServletInfo() {
            return null;
        }
    
        /**
         * 销毁
         */
        @Override
        public void destroy() {
    
        }
    }
    

1.ServletConfig(servlet配置的信息类)

ServletConfig的三个作用:

  1. 获取xml中servlet程序的别名

    servletConfig.getServletName();
    
  2. 获取初始化参数

    servletConfig.getInitParameter("user");
    
  3. 获取ServletContext对象(servlet的上下文,存储当前项目或servlet的一些信息)

    servletConfig.getServletContext();
    

2.ServletContext(servlet的上下文)

ServletContext的四个作用:

ServletContext servletContext = getServletContext();
  1. 获取web.xml中配置的上下文参数 context-param

    servletContext.getInitParameter("users");
    
  2. 获取当前的工作路径

    servletContext.getContextPath();
    
  3. 获取工程部署后在服务器硬盘上的绝对路径

    servletContext.getRealPath("/");
    
  4. 可以像Map集合一样存储数据

    servletContext.setAttribute("user","zs");
    

三、url到servlet程序的访问


1.URL:统一资源定位 包含了三部分:协议 服务器IP 端口号 资源

http://localhost:8080/maven_servlet/servlet1

http 表示HTTP协议

localhost 表示服务器IP(真实IP在实际中使用域名显示)

8080 表示服务器端口号

maven_servlet 表示工程路径

servlet1 表示工程中资源的路径

2.访问流程

- 根据服务器IP和端口号找到需要访问的tomcat服务器
- 根据工程路径找到部署在服务器上的项目
- 根据工程中资源的路径寻找当前项目上哪个servlet配置了@WebServlet("servlet1")注解的类并进行匹配
- 在匹配到的类里,tomcat会为其创建一个对象,并调用service()方法

service()中的两个参数

- ServletRequest	封装请求时的数据
- ServletResponse	封装响应时的数据--后期方便实现前后端交互

四、生命周期


指的是一个组件从创建到销毁的过程

Servlet运行在web容器 (Tomcat服务器 )中,它的生命周期由服务器来进行管理

1.servlet的加载和创建对象

默认情况下,当我们第一次访问servlet时,服务器会创建servlet对象,如果此时创建时间较长的话,会造成访问该Servlet的用户体验度比较差,由此我们会在服务器启动时就把 servlet准备就绪

我们可以改变servlet启动的时机,通过loadOnStartup来设置:

@WebServlet(urlPatterns = "/servlet2", loadOnStartup = 1)
  • 负整数:当第一次启动servlet时才创建Servlet对象

  • 整数或0:服务器启动时就创建servlet对象

  • @WebServlet注解的相关参数

    image-20230219091006132

2.生命周期流程

- 执行servlet的构造方法--—|
-					   --在第一次访问的时候创建servlet程序并初始化时会调用
- 执行init()方法--初始化--|
- 执行service()方法--服务--每次访问都会调用
- 执行destroy()方法--销毁--当web工程停止时调用

五、GET/POST的分发


service()用于处理请求和响应

但是请求的方式有多种,常用的有get和post,需要对get和post请求的不同,使用不同方式获取请求参数,需要对service()进行请求分发

/**
 * servlet中执行功能的方法
 *
 * @param servletRequest
 * @param servletResponse
 * @throws ServletException
 * @throws IOException
 */
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    //根据请求的不同,获取请求参数会有不同
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    //获取当前请求的请求方式
    String method = httpServletRequest.getMethod();
    if ("GET".equals(method)) {
        doGet(servletRequest, servletResponse);
    } else if ("POST".equals(method)) {
        doPost(servletRequest, servletResponse);
    }
}

最终我们要得到的结果就是get请求执行doGET()方法post请求执行doPost()方法,其实在 ServletAPl中已经为我们提供了实现分发的类HttpServlet,我们只需要继承自HttpServlet,重写doGet()和doPost()方法即可

补充 :

除了表单的method=post 提交是执行doPost()方法以外,其他清求( 直接访问、跳转等 )基本都是执行doGet()方法

六、访问路径与配置


sevlet程序写好后我们可以通过urlPatterns配置的路径访问对应的servlet

1.访问路径

如果有多个请求都需要经过一个servlet处理,我们可以在@WebServlet注解里配置多个路径

  1. 普通路径匹配:

    @WebServlet(urlPatterns = {"/TestServlet","TestServlet1"})
    
  2. 精确路径匹配(多级路径):

    @WebServlet(urlPatterns = "/TestServlet/select")
    
  3. 路径目录匹配:

    @WebServlet(urlPatterns = "/TestServlet/*")
    
  4. 扩展名路径匹配(匹配后面的扩展名)

    @WebServlet(urlPatterns = "*.do")
    
  5. 任意路径匹配:尽量避免

    @WebServlet(urlPatterns = "/*")或@WebServlet(urlPatterns = "/")
    

    注意:配置/会覆盖原来tomcat中DefaultServlet里专门用来处理静态资源的规则,如果配置/*或/还是会覆盖tomcat中的DefaultServlet规则,导致运行的是当前匹配的Servlet,此时静态资源就不会被处理,再次访问资源就会出现问题

2.Xml配置servlet

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <!--    配置上下文参数-->
    <context-param>
        <param-name>users</param-name>
        <param-value>root</param-value>
    </context-param>
    <!--    给tomcat配置一个servlet-->
    <servlet>
        <!--        为servlet程序取一个别名-->
        <servlet-name>XmlServlet</servlet-name>
        <!--        servlet程序所在的包和类名-->
        <servlet-class>com.controller.XmlServlet</servlet-class>
        <!--        servlet的初始化参数-->
        <init-param>
            <!--            参数名-->
            <param-name>user</param-name>
            <!--            参数值-->
            <param-value>root</param-value>
        </init-param>
    </servlet>
    <!--    配置servlet访问的地址-->
    <servlet-mapping>
        <!--        告诉服务器当前配置的使用对象-->
        <servlet-name>XmlServlet</servlet-name>
        <!--        配置访问servlet的路径-->
        <url-pattern>xml</url-pattern>
    </servlet-mapping>
</web-app>

七、HttpServletRequest接口


1.HttpServletRequest的作用

每次只要有请求进入到tomcat服务器,tomcat服务器就会把请求过来的http协议信息封装在 Request对象中,然后传递到service()方法 (判断执行doGet或doPost),此时就可以在doGet或doPost中通过HttpServletRequest获取所有的请求信息

2.HttpServletRequest和ServletRequest的关系

HttpServletRequest子接口继承于ServletRequest

3.Request对象是由tomcat创建的一个具体对象

Request对象的继承关系:
	ServletRequest -> HttpServletRequest -> RequestFacade

4.获取Request对象请求的数据

  1. 获取请求行

    GET /maven_servlet/request?name=zs HTTP/1.1
    
    • 获取请求方式

      req.getMethod();
      
    • 获取项目路径(服务器中的地址)

      req.getContextPath();
      
    • 获取url(统一资源定位符)、uri(统一资源标识符)路径

      //http://localhost:8080/maven_servlet/request
      req.getRequestURL();
      ///maven_servlet/request
      req.getRequestURI();
      
    • 获取参数 getQueryString()方法仅限Get请求

      req.getQueryString();
      
  2. 获取请求头

    除了第一行以外,以key :value的形式显示的数据行,可以根据key来获取

    req.getHeader("User-Agent");
    
  3. 获取请求体

    注意:浏览器发送Get请求时不存在请求体

    //获取字符输入流信息(纯文本)
    BufferedReader reader = req.getReader();
    //读取数据
    System.out.println(reader.readLine());
    ------------------------------------------------------
    //获取字节输入流信息(文件)
    ServletInputStream inputStream = req.getInputStream();
    

通过以上内容,我们发现无论是在Get提交后还是Post提交后,都需要获取数据,但是在获取数据的时候,两个方式的差异在于,请求参数的获取不同,其他都一样

5.通用的获取请求参数方法

  1. 获取所有参数封装的Map集合

    Map<String, String[]> parameterMap = req.getParameterMap();
    
  2. 根据参数的key(名称)获取单个值

    String user = req.getParameter("user");
    
  3. 根据参数的key(名称)获取值(数组)

    String[] lists = req.getParameterValues("list");
    
  4. 调用doPost()方法

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
        ...
    }
    

6.解决乱码问题

Post:

  • 设置获取字符输入流的字符集编码和页面上的参数保持一致

    req.setCharacterEncoding("utf-8");
    

Get:

  • 注意:tomcat8以前的版本需要转码

    user = new String(user.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
    

7.Request请求转发与数据共享

Request请求转发:

- 请求转发是tomcat服务器中一种内容资源的跳转方式(静态资源、动态资源)
- 请求转发的过程:浏览器发送请求给资源1 --> 资源1处理完后将请求转发给资源2,中间的过程叫做转发

语法

request.getRequestDispatcher("/forwords2").forward(request, response);

Request数据共享:

转发过程中,可以共享数据(Request对象),与它功能一致的对象称为域对象

Request共享数据的三种方法:

  1. 存储数据到request对象中

    request.setAttribute("user","zs");
    
  2. 根据key获取request对象中对应数据的value

    request.getAttribute("user");
    
  3. 根据key清除request对象中对应数据

    request.removeAttribute("user");
    

八、HttpServletResponse接口


1.HttpServletResponse的作用

和request搭配,主要用于处理响应的信息,其执行流程与request一致,每次浏览器请求进来以后Tomcat服务器就会创建一个response对象,传递给Servlet,用来封装响应的信息, 如果我们需要给客户端返回指定信息,就可以通过response来进行设置

2.Response设置响应数据

  1. 响应行

    HTTP/1.1 200 OK
    
    • 设置响应状态码

      response.setStatus(302); //302(重定向)
      
  2. 响应头

    • 设置响应的网页类型(key:value)

      response.setHeader("Content-Type","text/html;charset=ISO-8859-1");
      -------------------------------------------------------
      response.setContentType("text/html;charset=ISO-8859-1");
      
  3. 响应体

    字符流:

    //设置字符编码
    response.setContentType("text/html;charset=utf-8");
    PrintWriter writer = response.getWriter();
    //向浏览器写数据
    writer.write("responseServlet");
    

    字节流:

    • 手动

      //从硬盘读取文件到servlet中
      FileInputStream fileInputStream = new FileInputStream("");
      //获取输出流
      ServletOutputStream outputStream = response.getOutputStream();
      //声明数组存储文件字节
      byte[] bytes = new byte[1024];
      //声明整型变量存储字节长度(为-1说明字节长度读取完毕)
      int b = 0;
      //通过循环读取输入流里的数据并将读到的字节放在b里判断
      while ((b = fileInputStream.read(bytes)) != -1) {
          //从数组下标为0的元素中通过b获取到的长度读取字节并写入到浏览器(输出流)
          outputStream.write(bytes,0,b);
      }
      //关闭输入流
      fileInputStream.close();
      
    • 使用IOutils

      //从硬盘读取文件到servlet中
      FileInputStream fileInputStream = new FileInputStream("");
      //获取输出流
      ServletOutputStream outputStream = response.getOutputStream();
      //使用IOutils将输入流中的数据复制到输出流中
      IOUtils.copy(fileInputStream,outputStream);
      //关闭流
      fileInputStream.close();
      

2-1.重定向

2-1-1.重定向的应用

当浏览器给资源1发送请求,资源1接收到请求后表示自己无法处理,要处理的话需要访问另外
一个资源2

2-1-2.重定向的方式

方式一:

  • 设置响应状态码为302

    response.setStatus(302);
    
  • 设置响应头location的值为要访问的资源地址

    response.setHeader("location","/maven_servlet/Response2");
    

方式二:

  • 设置访问路径为要访问的资源地址

    response.sendRedirect("/maven_servlet/Response2");
    

    注意:一般项目名不能直接写,而是通过request对象获取

    request.getContextPath()	//获取项目路径
    
2-1-3.请求转发与请求重定向的区别
转发的特点 重定向的特点
浏览器的地址栏不会发送变化 浏览器的地址栏将会刷新
只能转发当前服务器内部的资源 可以重定向到任意位置的资源(tomcat、外部)
一次请求,可以共享资源间的数据 两次请求,不能共享资源间的数据

九、路径的写法


说明 路径
转发路径 /xx
重定向路径 /项目名/xx
路径给服务器用 /xx
路径给浏览器用 /项目名/xx

十、优化Servlet


package com.controller; 
/**
 * @Author: XIYAN
 * @Date: 2023/3/1 20:09
 * @注释:优化Servlet
 */

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class BasicServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置网页请求编码
        req.setCharacterEncoding("utf-8");
        //设置响应编码
        resp.setContentType("application/json;charset=utf-8");
        //获取路径
        String requestURI = req.getRequestURI();
        //截取最后一个/的路径
        int lastIndexOf = requestURI.lastIndexOf('/');
        String substring = requestURI.substring(lastIndexOf + 1);
        //获取当前访问的子类Servlet字节码的Class对象
        Class<? extends BasicServlet> aClass = this.getClass();
        try {
            //获取Class子类对象的公共的方法(方法名,参数)
            Method method = aClass.getMethod(substring, HttpServletRequest.class, HttpServletResponse.class);
            //调用方法
            method.invoke(this, req, resp);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
posted @ 2023-02-16 16:21  顔をして  阅读(22)  评论(0)    收藏  举报