Java EE: Servlet API

javax.servlet

Java EE介绍

  • Java EE 8及之前,这个企业版是由Oracle开发的闭源项目,包括一系列大型或中小型的商业软件包,但由于Spring等框架的流行,Java EE开始力不从心

    于是在之后,Oracle将整个Java EE移交给Eclipse开源基金会维护,并强制要求Eclipse不能继续使用Java EE的项目名以及javax的命名空间,因此在Eclipse接手这个项目后迫不得已将javax改为jakarta,并将大版本号提升至5,表示不再向下兼容

    总而言之,javax命名空间适用于4.0及之前的企业版项目,jakarta适用于5.0及之后的企业版

  • Servlet源于Server Applet,即在服务端上运行的小程序

    SE的网络编程中对于Http的处理只介绍了HttpClient,即客户端的编写,是因为服务端需要考虑的东西过多

    Servlet项目致力于高效而安全地开发服务器

  • Servlet本质可用于任意通信协议,但主要用于HTTP

    它内部封装了线程池,通过多线程的方式处理请求,因此比起此前的方案性能更高

  • Servlet需要部署到专用的Web服务器上,称作Servlet容器,例如ApacheTomcat项目、EclipseJetty项目

    因为Servlet本质是一个Web应用,是Servlet容器向开发者暴露的规范接口,Servlet容器是更复杂的应用

servlet依赖

  • 接口依赖:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    </dependency>

    <dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0</version>
    </dependency>
  • Servlet接口的实现由Web容器提供,可以使用provided表示仅编译时需要

Servlet接口与HttpServlet实现类

  • Servlet有三个重要方法:init()service()destroy(),由Servlet容器调用进行生命周期管理

    service()含有两个参数HttpServletRequestHttpServletResponse

  • HttpServlet是最常用的实现类,有四个重要方法:doGet()doPost()doPut()doDelete()

    它们也均含有两个参数:HttpServletRequestHttpServletResponse

    重写它们来自定义处理逻辑

    一般不需要重写service(),由HttpServlet已经实现好了,他会自动解析请求方法并调用doXxx()

    除非需要使用HttpServlet处理其它通信协议

  • HttpServletRequest接口表示一个HTTP请求报文,常用方法如下:

    • setCharsetEncoding(String):设置解析的编码集

    • String getParameter(String name):获取某个请求参数

      这里的参数已经消除了GETPOST等不同请求方法的差异,但对于POST方法而言,只会解析类型为application/x-www-form-urlencodedmultipart/form-data,其它类型如application/json需要通过输入流获取

    • String getHeader(String name):获取某个请求头

    • getRequestDispatcher(String location):获取一个请求分发器,指向内部的另一个URI,通常会继续调用RequestDispatcher接口的forward(req, resp)内部转发出去或include(req, resp)转发后回来

    • getAttribute()setAttribute():可以主动设置属性,方便请求处理链条中数据的传递

  • HttpServletResponse接口表示一个HTTP响应报文,常用方法如下:

    • setCharsetEncoding(String):设置解析的编码集
    • setContentType(String type):设置响应体的类型
    • PrintWriter getWriter():获取绑定的字符输出流
    • ServletOutputStream getOutputStream():获取绑定的字节输出流
    • setStatus(int):设置状态码
    • setHeader(String name, String value):设置响应头
    • sendRedirect(String)302临时重定向到另一个URI
  • 一个服务器的所有Servlet实现类只会有一个实例,因此遇到多个请求时会用同一个实例来处理

    因此实现类的实例属性的所有访问需要保证线程安全

SessionCookie

  • Session用于存储客户端的某种状态,能保证每个Session唯一,内部类似于一个Map<String, Object>

  • HttpServletRequest对象的getSession()方法会(若不存在)创建并返回一个HttpSession对象,(若存在)直接返回HttpSession对象

    getSession(false)则不会创建,而只是返回已有的对象,若无则返回null

  • HttpSession实例的常用方法为setAttribute(String, Object)Object getAttribute(Stirng)以及removeAttribute(String)

    分别为设置、获取、删除其存储的对象数据

  • Session通常是通过Cookie技术实现的,它会让客户端在发送请求时同时发送一个Session

    自定义Cookie需直接通过构造方法new Cookie(String name, String value)创建

    Cookie可设置最大时间setMaxAge(seconds)

    通过HttpServletResponse实例的addCookie(Cookie)方法传递给客户端

    通过HttpServletRequest实例的getCookies()获取Cookie[]数组

    通过Cookie实例的getName()getValue()获取键值对

ServletContext

  • ServletContextWeb应用上下文的抽象,可以用它获取整个Web应用的信息,最常用的方法如下:
  • 获取Web应用的属性:Object getAttribute(String)
  • 设置Web应用的属性:void setAttribute(String, Object)
  • 移除Web应用的属性:void removeAttribute(String)
  • 记录日志:log(String)
  • 使用上下文需注意,因为处于多线程环境,虽然ServletContext本身是线程安全的,但传入的属性值需要自行确保线程安全

ServletConfig

  • ServletConfig是某个Servlet服务的配置的抽象,可以用它获取某个Servlet服务独有的配置项,最常用的方法如下:
  • 获取初始参数:String getInitParameter(),这个初始参数可以用XML或注解的形式设置,也可由内嵌TomcatWrapper配置

JSP技术

  • JSP技术比较落后,了解即可

  • 由于Servlet本质是内嵌HTMLJava微服务程序,大量的HTML文本由一行行的输出流打印比较麻烦,因此JSP技术出现

    JSP本质也是一个Servlet应用,由Web服务器在启动时自动将其编译成Servlet程序并在服务器上运行

    JSP作为静态资源可由Web容器自动部署,但也可以自定义部署URL路径

  • JSP语法:

    • Jsp脚本:<% Java代码 %>,只执行代码,没有返回值
    • Jsp表达式:<%= Expr %>,返回表达式的值
    • Jsp声明:<%! 成员变量、方法 %>
    • Jsp指令:<%@ 指令 %>
    • Jsp动作:<jsp:action />
    • Jsp注释:<%-- 注释 --%>
    • EL表达式:$ { expr }
  • JSP隐含对象:在Jsp脚本中不用声明就可使用的对象,但不能重复定义

    • HttpServletRequest requestHttpServletResponse response:因为JSP本身就是一个Servlet,自然有requestresponse参数
    • HttpSession session:等价于request.getSession()
    • ServletConfig configJSP这个Servlet的配置
    • JspWriter out:不常用
    • PageContext pageContext:是整个页面上下文的抽象
    • page:等价于this,是这个Jsp翻译得到的Servlet程序实例,因为this是可省略的所以page不会被直接使用
    • Exception exception:用于异常处理
  • JSP指令:

    • 声明页面的属性:<%@ page import="java.util.*, java.net.*" %>
    • 声明页面包含其它页面:<%@ include other.jsp %>
    • 声明Tag的来源以及前缀:<%@ taglib uri="" prefix="" %>
  • EL表达式的隐含对象

    • PageContext pageContext:除它之外,以下所有都是Map
    • param:对应request的参数表
    • paramValues:对应request的参数表,只不过值是数组用于存储含多个值的参数
    • header:对应request的请求头表
    • headerValues:对应request的请求头表,只不过值是数组用于存储含多个值的请求头
    • cookie:对应cookie
    • initParam:对应ServletConfig的初始参数表
    • pageScope:页面作用域,可通过它访问所有在页面内定义的标识符
    • requestScope:请求作用域,可通过它访问所有在request中定义的attribute
    • sessionScope:会话作用域,可通过它访问所有在session中定义的attribute
    • applicationScope:应用作用域
    • EL表达式可以不指定隐含对象地输出字段,此时会从小到大(pageScope->requestScope->sessionScope->applicationScope)地查找该字段
  • EL表达式的关键字:not、le、lt、ge、gt、eq、ne、div

  • Jsp动作:

    • <jsp:useBean id="a" class="com.Clazz" scope="page|request|session|application"/>

      创建一个标识为a、类型为com.Clazz、所属作用域为所有作用域的对象

    • <jsp:getProperty name="a" property="age"/>

      获取标识为a的对象的age属性

    • <jsp:setProperty name="a" property="age" value="value"/>

      设置标识为a的对象的age属性为字面量"value"

    • <jsp:setProperty name="a" property="age" param="age"/>

      设置标识为a的对象的age属性为引用变量age的值

Filter

  • Filter接口作用于收到请求、初始化响应之后,Servlet服务处理请求之前,可用于身份校验、初始化配置等
  • 实现Filter接口需要实现doFilter(ServletRequest, ServletResponse, FilterChain)方法,如果需要拦截则直接return,如果放行则需要调用FilterChain实例的doFilter(ServletRequest, ServletResponse)方法

Listener

  • Listener采用观察者模式,当某种实例创建、更改、销毁时,自定义的Listener组件会随之调用对应的方法
  • Listener本身并不存在,只存在一系列的XxxListener接口