Java Web Servlet 技术

717 阅读8分钟

一、简介

1.1 什么是 Servlet

  • Servlet 是 JavaEE 规范之一。规范就是接口。
  • Servlet 就 JavaWeb 三大组件之一。三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。
  • Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。

1.2 示例代码

1.2.1 实现Servlet接口

public class ServletTest implements Servlet {
    /**
     * 第一次有人打开该网页之后,会构造该Servlet及初始化
     */
    public ServletTest() {
        System.out.println("构造器");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init 初始化");
    }

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

    /**
     * 每次刷新,会重新进行一次service服务
     *
     * @param servletRequest  请求
     * @param servletResponse 响应
     * @throws ServletException
     * @throws IOException
     */

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("servlet 服务响应");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String method = request.getMethod();
        // 判断请求是GET请求还是POST请求
        if (method.equals("GET"))
            doGet();
        else if (method.equals("POST"))
            doPost();
    }

    public void doGet() {
        System.out.println("GET 请求");
    }

    public void doPost() {
        System.out.println("POST 请求");
    }


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

    /**
     * 关闭之后,会销毁
     */
    @Override
    public void destroy() {
        System.out.println("销毁");
    }
}

1.2.2 web.xml 文件配置

<servlet>
    <!--        一般取和类名一样的名字-->
    <servlet-name>ServletTest</servlet-name>
    <!--        定位到指定的Servlet实现类上去
        应该用了反射的方法,进行了类的实例化
    -->
    <servlet-class>com.servlet.test.ServletTest</servlet-class>
</servlet>
<servlet-mapping>
    <!--        与servlet上面的名字相对应。同样,取和类名相同的名字即可-->
    <servlet-name>ServletTest</servlet-name>
    <!--        这个是网页访问之后的路径,也就是tomcat里面的那个config
    访问的路径也就是"http://localhost:8080/demo/ServletTest"
    -->
    <url-pattern>/ServletTest</url-pattern>
</servlet-mapping>

1.2.3 Servlet 的生命周期

  1. 执行 Servlet 构造器方法
  2. 执行 init 初始化方法
  3. 执行 service 方法 第三步,每次访问都会调用
  4. 执行 destroy 销毁方法第四步,在 web 工程停止的时候调用

第一、二步,是在第一次访问的时候创建 Servlet 程序会调用。

1.2.4 GET 和 POST 请求的分发处理

  • 通过httpServletRequest.getMethod()获取请求方式

1.3 通过继承 HttpServlet 实现 Servlet 程序

  • 一般在实际项目开发中,都是使用继承 HttpServlet 类的方式去实现 Servlet 程序。
    1. 编写一个类去继承 HttpServlet
    2. 根据业务需要重写 doGetdoPost 方法
    3. web.xml 中的配置 Servlet 程序的访问地址
  • Servlet 类的代码
public class HttpServletTest extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // super.doGet(req, resp); 默认无此服务,会抛异常的。因此旧方法不能继续留
    System.out.println("get 请求");
  }

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // super.doPost(req, resp);
    System.out.println("post 请求");
  }
}
  • Servlet 类的继承体系 在这里插入图片描述 在这里插入图片描述

二、ServletConfig 类

  • Servlet 程序的配置信息类
  • Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用
  • Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象
  • ServletConfig 类的三大作用
    1. 可以获取 Servlet 程序的别名,就是 servlet-name 的值
    2. 获取初始化参数 init-param,在xml文件中定义
    3. 获取 ServletContext 对象
  • init-param
    <servlet>
    	<!-- 别名 -->
        <servlet-name>HttpServletTest</servlet-name>
        <servlet-class>com.servlet.test.HttpServletTest</servlet-class>
        <!--  一个键值对  -->
        <init-param>
            <param-name>username</param-name>
            <param-value>root</param-value>
        </init-param>
        <!--        一个键值对-->
        <init-param>
            <param-name>password</param-name>
            <param-value>123</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>HttpServletTest</servlet-name>
        <url-pattern>/HttpServletTest</url-pattern>
    </servlet-mapping>
    
    public class HttpServletTest extends HttpServlet {
      /**
       * 重写这个init会安全一点,不担心忘记对config操作
       * 重写了无参的init方法,在Tomcat加载的时候,会调用那个有参的init方法,对config赋值之后,再调用这个无参的init方法
       * ServletConfig 测试
       *
       * @throws ServletException
       */
      @Override
      public void init() throws ServletException {
        ServletConfig config = getServletConfig();  // 另一个init已经注入了,因此直接调用函数获取就好了
        String username = config.getInitParameter("username"); // 获取指定key的value。类似于key-value
        System.out.println(username);
        String password = config.getInitParameter("password");
        System.out.println(password);
        //遍历所有init parameter的名字
        Enumeration<String> initParameterNames = config.getInitParameterNames();
        while (initParameterNames.hasMoreElements()) {
          System.out.println(initParameterNames.nextElement());
        }
      }
    
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("get 请求");
      }
    
      @Override
      protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("post 请求");
      }
    }
    

三、ServletContext 类

  • ServletContext 是一个接口,它表示 Servlet 上下文对象
  • 一个 web 工程,只有一个 ServletContext 对象实例
  • ServletContext 对象是一个域对象
  • ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁
  • 域对象:可以像 Map 一样存取数据的对象,叫域对象。这里的域指的是存取数据的操作范围,整个 web 工程。
    方法描述
    setAttribute()存数据
    getAttribute()取数据
    removeAttribute()删除数据
  • ServletContext 类的四个作用
    1. 获取 web.xml 中配置的上下文参数 context-param
    2. 获取当前的工程路径,格式: /工程路径
    3. 获取工程部署后在服务器硬盘上的绝对路径
    4. 像 Map 一样存取数据

3.1 示例代码

  • web.xml 文件(与Servlet标签并列关系)
    <!-- *********************Context*********************-->
    <!--    有点全局变量的味道,在建立工程的时候,就会导入-->
    <context-param>
        <param-name>username</param-name>
        <param-value>root</param-value>
    </context-param>
    <context-param>
        <param-name>password</param-name>
        <param-value>123</param-value>
    </context-param>
    
  • 调用
      @Override
      public void init() throws ServletException {
        //ServletContext servletContext = getServletConfig().getServletContext();
        ServletContext servletContext = getServletContext();  // 直接通过方法调用获取ServletContext就好了
        String username = servletContext.getInitParameter("username");
        System.out.println(username);
        String password = servletContext.getInitParameter("password");
        System.out.println(password);
    //        设置数据 和 initParameter没有关系
        servletContext.setAttribute("username", "root1");
        System.out.println(servletContext.getAttribute("username"));
    //      获取当前的工程路径
        System.out.println(servletContext.getContextPath());  // /demo
    //        获取部署的绝对路径。部署的内容和工程内容有一个映射关系
        System.out.println(servletContext.getRealPath("/")); //E:\Java\java-web\demo\target\demo-1.0-SNAPSHOT\
      }
    

四、HttpServletRequest 类

  • 作用:每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中。 然后传递到 service 方法(doGet 和 doPost)中给我们使用。我们可以通过 HttpServletRequest 对象,获取到所有请求的信息

4.1 常用方法

方法描述
getRequestURI()获取请求的资源路径
getRequestURL()获取请求的统一资源定位符(绝对路径)
getRemoteHost()获取客户端的 ip 地址
getHeader()获取请求头
getParameter()获取请求的参数
getParameterValues()获取请求的参数(多个值的时候使用)
getMethod()获取请求的方式 GET 或 POST
getRequestDispatcher()获取请求转发对象
setAttribute()设置属性,用于传递对象
getAttribute获取传递过来的对象

Parameter 和 Attribute 区别:介绍

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        获取请求资源的路径
    System.out.println(request.getRequestURI()); //demo/HttpServletTest2
//        获取请求的统一资源定位符
    System.out.println(request.getRequestURL()); // http://localhost:8080/demo/HttpServletTest2
//        获取客户端的ip
    System.out.println(request.getRemoteHost()); // 127.0.0.1
//        获取请求头的内容
    System.out.println(request.getHeader("Accept-Language"));
//        获取请求的参数(form传上来的数据)
    System.out.println(request.getParameter("username"));
//        获取请求的多个参数(多选列表之类的)
    String[] hobbies = request.getParameterValues("hobby");
    System.out.println(Arrays.toString(hobbies));
    // 获取请求的方式 GET 或 POST
    System.out.println(request.getMethod());
  }

4.2 doGet 请求的中文乱码解决(实测没用,反而捣乱)

// 获取请求参数 
String username = req.getParameter("username"); 
//1 先以 iso8859-1 进行编码 
//2 再以 utf-8 进行解码 
username = new String(username.getBytes("iso-8859-1"), "UTF-8");

4.3 doPost 请求的中文乱码解决

@Override 
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         // 设置请求体的字符集为 UTF-8,从而解决 post 请求的中文乱码问题 
         req.setCharacterEncoding("UTF-8"); 
         System.out.println("-------------doPost------------"); 
         // 获取请求参数 
         String username = req.getParameter("username"); S
         tring password = req.getParameter("password"); 
         String[] hobby = req.getParameterValues("hobby"); 
         System.out.println("用户名:" + username); 
         System.out.println("密码:" + password); 
         System.out.println("兴趣爱好:" + Arrays.asList(hobby)); 
 }

4.4 请求转发

  • 请求的转发:服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发。(自己跳,不需要浏览器跳) 在这里插入图片描述
// 通过注解的方法,就不需要在xml文件上写了
// name 就是xml上面的 servlet-name,value就是url-pattern
@WebServlet(name = "RequestDispatcherTest1", value = "/RequestDispatcherTest1")
public class RequestDispatcherTest1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        获取请求参数
        String username = request.getParameter("username");
        System.out.println(username);
//        设置两个servlet之间需要传递的内容
        request.setAttribute("key", "盖章");
//        获取下一个传递的servlet
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/RequestDispatcherTest2");
//        将请求、响应传递给下一个servlet。然后就会触发下一个servlet的service方法
        requestDispatcher.forward(request, response);
    }
}
@WebServlet(name = "RequestDispatcherTest2", value = "/RequestDispatcherTest2")
public class RequestDispatcherTest2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        获取请求参数
        String username = request.getParameter("username");
        System.out.println(username);
//        获取通过context传递的参数
        System.out.println(request.getAttribute("key"));
//        处理自己的任务
        System.out.println("RequestDispatcherTest2 处理");

    }
}

4.5 base 标签

  • base 标签:可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>response</title>
</head>
<base href="http://localhost:8080/demo/">
<body>
    <!--http://localhost:8080/demo/ResponseServlet-->
    <form method="post" action="ResponseServlet">
        <label>
            <input type="text" name="msg" value="默认值"/>
        </label>
        <input type="submit">
    </form>
</body>
</html>
  • 在实际开发中,路径都使用绝对路径,而不简单的使用相对路径
    1. 绝对路径
    2. base+相对
  • web 中 / 斜杠的不同意义
    • 在 web 中 / 斜杠 是一种绝对路径
    • / 斜杠 如果被浏览器解析,得到的地址是:http://ip:port/
      <a href="/">斜杠</a>
      
    • / 斜杠 如果被服务器解析,得到的地址是:http://ip:port/工程路径
      1、<url-pattern>/servlet1</url-pattern> 
      2、servletContext.getRealPath(“/”); 
      3、request.getRequestDispatcher(“/”);
      
    • 特殊情况: response.sendRediect(“/”), 把斜杠发送给浏览器解析。得到 http://ip:port/

五、HttpServletResponse 类

  • 每次请求进来,Tomcat 服务器都会创建一个 Response 对象传 递给 Servlet 程序去使用。

  • HttpServletResponse 表示所有响应的信息,我们如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置

  • 两个输出流的说明:

    描述
    getOutputStream()字节流,常用于下载(传递二进制数据)
    getWriter()字符流,常用于回传字符串(常用)
  • 往客户端回传数据

      @Override
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String msg = request.getParameter("msg");
        PrintWriter writer = response.getWriter();
        writer.write(msg);
      }
    
  • 响应的乱码解决

    • 解决响应中文乱码方案一: java // 设置服务器字符集为 UTF-8 resp.setCharacterEncoding("UTF-8"); // 通过响应头,设置浏览器也使用 UTF-8 字符集 resp.setHeader("Content-Type", "text/html; charset=UTF-8");
    • 解决响应中文乱码方案二(将上面二合一): java // 它会同时设置服务器和客户端都使用 UTF-8 字符集,还设置了响应头 // 此方法一定要在获取流对象之前调用才有效 resp.setContentType("text/html; charset=UTF-8");
  • 请求重定向:请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说。我给你一些地址。你去新地址访问。 在这里插入图片描述

resp.sendRedirect("http://localhost:8080");