Servlet的基本使用

1、Servlet的基本介绍

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,依赖于服务器才能运行。Servlet 类实际上就是一个接口,它没有主方法,没有main方法,由 tomcat 来执行它,它定义了能被 tomcat 识别的规则。

2、Servlet 的基本使用

servlet 就是一个接口,通过一个类 implements 实现这个接口,在 web.xml 中配置该类,由此该类就可以依赖于服务器运行起来,无需主方法。

一个简单的类实现 servlet :

package cn.servletPackageTest;

import javax.servlet.*;
import java.io.IOException;

public class ServletTest01 implements Servlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        
    }

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

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

    @Override
    public void destroy() {

    }
}

在 web.xml 配置该 servlet :

<?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-name>test01</servlet-name>
        <servlet-class>cn.servletPackageTest.ServletTest01</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>test01</servlet-name>
        <url-pattern>/test01</url-pattern>
    </servlet-mapping>
</web-app>

其中,servlet-class 是完整的类名,servlet-name 给你所配置的类名指定了一个名称,下面的 servlet-mapping 里面的 servlet-name 跟上面的 servlet-name 相匹配,url-pattern 指定的是你今天访问该 servlet 的路径,配置完后你就可以通过 ' 资源路径 + url-pattern ' 来访问 servlet,比如:http://localhost:8080/test01 

2.2、使用注解配置(@WebServlet())

在 servlet 3.0 及以上的版本当中,servlet 可以不用 web.xml 文件进行配置,而是使用注解配置:@WebServlet()。JDK6 及以上即可支持 servlet 3.0 及以上版本

由此我们在创建一个 java ee 项目时就可以不用创建 web.xml 文件,直接在 servlet 上进行配置:

@WebServlet(urlPatterns = "/demo01")
//或者直接写即可,无需写urlPatterns,如下:
//@WebServlet("/demo01")
public class ServletDemo01 implements Servlet {
    
   .....

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("servlet 3.0 测试。。。");
    }
    
    .....  
}

@WebServlet() 里面的 urlpatterns 可以有多个写法:

//写成数组,匹配多个路径
@WebServlet({"/demo01", "/demo02", "demo03"})

//多层路径
@WebServlet({"/demo01/demo02"})

//使用 * ,注意此时前面没有 / 
@WebServlet({"*.do")

3、servlet 的生命周期(init()、service()、destroy())

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 通过调用 init () 方法进行初始化。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 通过调用 destroy() 方法终止(结束)。

3.1、init() 方法

init() 方法只会被调用一次,默认情况下 init() 方法在 Servlet 创建时执行,而 Servlet 会在用户第一次调用该 Servlet 时被创建,所以 init() 方法只会在第一次调用 servlet 时执行,在后续每次用户请求调用时都不会被调用。

你也可以通过 <load-on-startup> 标签来指定 servlet 的 init() 方法在服务器第一次启动时被加载执行。

<servlet>
    <servlet-name>demo01</servlet-name>
    <servlet-class>cn.itcast.web.servlet.ServletDemo01</servlet-class>
    <!--指定servlet的创建时机
        值为负数时,在第一次被访问时创建
        值为0或正数时,在服务器启动时就创建-->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>demo01</servlet-name>
    <url-pattern>/demo01</url-pattern>
</servlet-mapping>

3.2、sevice() 方法

service() 方法是 servlet 用来处理客户端请求的,它会被服务器自动调用,Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。service() 方法在每次客户端请求 servlet 时都会被调用。

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

3.3、destroy() 方法

destroy() 方法会在 servlet 正常关闭时执行,在执行完 destroy() 方法后,servlet 才会被关闭。只有在服务器被正常关闭时,destroy() 方法才会被执行。 

4、servlet 是单例的

servlet 的 init() 方法只会执行一次,说明一个 servlet 只会被创建一次,一个 servlet 在内存中只存在一个 servlet 实例对象。所以说,servlet 是单例的。

由于 servlet 是单例的,所以在多个用户同时访问同一个 servlet 时,实际上访问的都是同一个实例对象,此时就有可能会存在线程安全问题。比如说 servlet 有一个成员变量 num,当任何人都可以通过调用 servlet 的 service() 方法来获取、输出、改变 num,这就有可能会导致线程安全问题,数据错乱。

可以通过加锁来解决线程安全问题,将方法改为同步方法,比如在张三处理完 service() 方法后,李四才能调用 service() 方法。但是这不适用于 servlet,因为对性能影响太大。

解决方法:

在一个对象当中,成员变量是被共享的,但是局部变量是不被共享的。所以我们建议尽量不要在 servlet 中定义成员变量,而是在 service() 方法内部定义局部变量。因为局部变量不被共享,所以彼此之间的函数调用不会产生影响。即使是在 servlet 中定义了成员变量,也不要在方法体内对其进行赋值。

5、HttpServlet类

HttpServlet 是一个抽象类,它继承了 GenericSerevlet 类(该也是一个抽象类,它实现了 Serlvet 接口)。HttpServlet 是专门用来处理 http 请求的,通过继承 HttpServlet 类可以获取 http 请求数据和响应 http 请求。

继承 HttpServlet 类无需覆写 service() 方法,只需覆写 http 响应的方法,比如 doGet()、doPost()、doDelete() 等。HttpServelt 类的 service() 方法内部会判断 servlet 所接收到的 http 请求方式,然后再来调用相应的 doGet、doPost等到方法。

@WebServlet("/demo02")
public class ServletDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("get请求");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = "myName";
        response.setCharacterEncoding("utf-8");
        request.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        //拼接json数据
        String jsonStr = "{"name":""+name+"","age":"20"}";
        //将数据写入流中
        response.getWriter().write(jsonStr);
    }
}

6、request 对象

HttpServletRequest 接口继承于 ServletRequest 接口,可以通过 HttpServletRequest 对象或者 ServletRequest 对象来获取请求的信息。

6.1、request 对象获取请求行数据

request 对象可以通过一系列方法来获取请求行的数据

//发出请求
http://localhost:8080/servlet_test01_war_exploded/demo03?username=wen&age=12

@WebServlet("/demo03")
public class ServletDemo03 extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest request, 
  HttpServletResponse response) throws ServletException, 
  IOException {
    //获取请求方式   GET
    String method = request.getMethod();

    //获取请求的虚拟目录    /servlet_test01_war_exploded
    String contextPath = request.getContextPath(); 

    //获取包含在URL后的请求参数,适用于GET请求   username=wen&age=12
    String queryString = request.getQueryString();
 
     //返回请求的URL:  http://localhost:8080/servlet_test01_war_exploded/demo03
    StringBuffer requestURL = request.getRequestURL();

    //返回请求的URI:  /servlet_test01_war_exploded/demo03
    String requestURI = request.getRequestURI();
  }
}

6.2、request 对象获取请求头数据

//发出请求
http://localhost:8080/servlet_test01_war_exploded/demo03?username=wen&age=12

@WebServlet("/demo03")
public class ServletDemo03 extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest request, 
  HttpServletResponse response) throws ServletException, 
  IOException {
    //获取请求的所有请求头的名称,返回一个枚举类型值
    Enumeration<String> headerNames = request.getHeaderNames();
   
   //遍历枚举类型的值
   while (headerNames.hasMoreElements()) {         
         String name = headerNames.nextElement();
         //根据请求头名称来获取请求头数据
         String value = request.getHeader(name);
         System.out.println(name + " --- " + value);
     }
  }

  //根据请求头名称来获取请求头数据,名称不区分大小写
  String userAgent = request.getHeader(“uesr-agent”);
  System.out.println(userAgent );
}
原文地址:https://www.cnblogs.com/wenxuehai/p/12566624.html