目录
1.Servlet简介
Servlet接口的实现类是一个Java程序,是在服务上运行以处理客户端请求并做出响应的程序。
Servlet的继承体系如下
Servlet接口
GenericServlet抽象类
HttpServlet抽象子类
2.Servlet的常用方法
Servlet接口的常用抽象方法有
void init(ServletConfig var1) throws ServletException:初始化方法
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException:服务方法
void destroy():销毁方法
其中init()方法会在服务器启动或者服务器端第一次接收客户端发送的请求时调用(具体是什么时候调用见下文Servlet的初始化时机)。
当客户端向服务器端发请求时,service方法会被自动执行。service方法在GenericServlet抽象类中没有重写,仍然是抽象的。在HttpServlet类中重写了,其会先获取请求的method(也就是请求类型),然后根据method的类型来调用HttpServlet类中相应的doxxx方法。所有的doxxx方法在HttpServlet类中的都是405错误。如果没有重写请求类型的method相对应的doxxx方法则会报405错误。
destroy方法会在服务器关闭时调用,用来销毁servlet对象。
3.Servlet的生命周期
Servlet的生命周期包括:初始化、服务、销毁;分别对应上面的init()、service()、destroy()。
调用init()后,Servlet会初始化,之后会一直处于服务状态直到容器销毁Servlet结束。
Servlet只会初始化一次,可以有无数次服务。
从上面可以看出:Servlet在整个生命周期只有一个实例,所有的服务都由同一个实例完成(单例模式)。
4.客户端请求和Servlet绑定
当客户端通过浏览器发送一个请求,服务端会按照web.xml文件或注解中的配置为依据,根据请求中的action参数来绑定相关的Servlet实现类并调用其的servlet()方法。该请求会被封装成一个ServletRequest实现类的对象作为该方法的第一个参数。
配置web.xml或注解的方式如下:
(举例为客户端发送action="add",服务器端需要为该请求绑定servlet包下的AddServlet类)
①配置web.xml文件
<servlet>
<servlet-name>addServlet</servlet-name>
<servlet-class>servlet.AddServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>addServlet</servlet-name>
<url-pattern>/add</url-pattern>
</servlet-mapping>
该方式的绑定过程如下:客户端发送请求xxxxx/add,服务器端接受该请求后会在web.xml文件中在所有<servlet-mapping>标签中找到<url-pattern>标签内容为/add的唯一<servlet-mapping>标签,并获取其内部的<servlet-name>标签内容;之后在所有<servlet>标签中寻找<servlet-name>标签内容与之匹配的<servlet>标签,获取其内部的<servlet-class>内容,进而和AddServlet类绑定。
②注解方式
在AddServlet类上面加上@WebServlet("/add")
5.Servlet的初始化时机
Servlet默认情况下是在服务器端第一次接收客户端请求时才调用init()来进行初始化,这样的好处是在启动服务器时减少了初始化Servlet的时间,可以提高服务器启动的速度。这样的坏处是当客户端第一次向服务器端发送请求时,服务器端需要进行Servlet的初始化,需要时间,使得第一次请求的用户等待较久的时间,响应速度比较慢。如果要提高响应速度要设置Servlet的初始化时机。
可以通过在<servlet>中添加<load-on-startup>来设置servlet的启动先后顺序,<load-on-startup>标签里面的内容是数字。通过这样设置的Servlet会在服务器启动时调用init(),数字越小初始化越靠前,最小值为0。
6.Servlet的注意点
Servlet是线程不安全的所以尽量不要在Servlet中定义成员变量,如果不得不定义则不要修改成员变量的值。
7.HttpServlet类的常用方法
doXxx():用来处理Xxx方式的请求
8.ServletRequest接口的常用方法
Object getParameter(String name):获取请求中参数名为name的参数的参数值
void setCharacterEncoding(String cha):设置获取参数时参数的字符串,默认为ISO-8859-1
void setAttribute(String name,Object value):将属性名为name的属性的属性值设置成value
void getAttribute(String name):获取属性名为name的属性的属性值
void removeAttribute(String name):移除属性名为name的属性
注意点:
①通过getParameter()方法来获取参数值得到的是字符串类型,需要将数据进行转换。
②获取到的字符串使用的字符集是ISO-8859-1,需要进行字符集转换成数据库对应的字符集,不然会出现乱码。
9.设置编码
①post方式下通过如下方式来设置编码,ServletRequest对象调用setCharacterEncoding("UTF-8")
②get方式在Tomcat8以后不需要设置编码,在Tomcat8之前通过如下方式设置编码①获取参数②通过String对象的getBytes("ISO-8859-1")来将字符串变成字节数组③通过String构造器String(Byte [] byte,String character)来将字节数组变成字符串。
注意点:在post方式下设置编码必须要把设置编码的语句放在所有的参数获取之前。
10.Http协议
Http协议:超文本传输协议,最大的作用就是确定了请求和响应数据的格式。Http是无状态的。浏览器发给服务器的数据称为:请求报文;服务器发给浏览器的数据称为:响应报文。
请求报文包括:请求行、请求头、请求体
请求行包括:请求方式、请求URL、请求协议
请求头包括:客户端告诉服务器本次请求的详细信息
请求体分三种情况
①get方式:没有请求体,但是有一个queryString
②post方式:有请求体,form data
③json方式:有请求体,request payload
响应报文包括:响应行、响应头、响应体
响应行:响应协议;响应状态码;响应状态
响应头:服务器告诉浏览器本次请求的详细信息
响应体:响应的实际内容(如请求add.html页面时响应的内容就是<html><head>...</head></html>)
11.session会话跟踪技术
对http无状态的理解:服务器无法判断两次请求是否是同一个浏览器(客户端)发来的。
无状态带来的问题:当有多个请求时,可能会出现响应错误。
解决方法:通过会话跟踪技术。
会话跟踪技术:当客户端第一次给服务器端发请求时,服务器端会获取session,但获取不到,此时给其分配一个新的session然后响应给客户端;当客户端下一次向服务器端发请求时,会将sessionid带给服务器端,服务器端根据客户端带过来的唯一sessionid来区分不同的请求。
步骤
①获取session,如果获取不到则创建一个新的session。
HttpSession session=request.getSession();
常用API
HttpServletRequest中
Httpsession getSession() 获取当前会话,没有则创建新会话。
Httpsession getSession(true) 和上面的效果一样。
Httpsession getSession(false) 获取当前会话,没有不会创建新会话。
HttpSession中
String getId():获取sessionid
boolean isNew():判断当前会话是否是新的会话
int getMaxInactiveInterval():获取最大的非激活间隔时间(默认为半个小时)
void sexMaxInactiveInterval(int timeLength):设置最大的非激活间隔时间
void invalidate():强制让会话失效
long getCreationTime():获取创建时间(时间戳形式)
long getLastAccessedTime():获取上次访问时间(时间戳形式)
12.session保存作用域
会话:一个客户端和服务器端之间的通信就叫做会话。
因为有时候每个会话之间有独立的数据需要在客户端和服务器端之间使用,而Http是无状态的,也就是说其不能分辨一个请求是否是同一个客户端发送的,我们没办法把这数据保存在一次请求中,但是可以保存在一次会话中,这样这个会话中的使用到的数据就是同一份了。对于同一个会话,服务器端会有专门的一块内存用来存储数据,不同的会话之间不能获取彼此的数据。
HttpSession中
void setAttribute(Object key,Object value):向session保存作用域中保存数据
void getAttribute(Object key):通过key向session保存作用域获取数据
void removeAttribute(Object key):移除session保存作用域中的与key对应的数据
13.服务器端转发和客户端重定向
有时候我们可能需要在Servlet处理数据后跳转到另一个Servlet中继续进行处理,这时候我们有两种方式来完成这个需求,一种是服务器端转发,一种是客户端重定向。
服务器端转发:request.getRequestDispatcher("页面1").forward(request,response)
执行服务器端转发代码后会跳转到页面1,由页面1负责响应。
客户端重定向:response.sendRedirect("页面1")
执行客户端重定向代码后服务器会立刻给客户端发送响应,并告诉客户端要求其立刻给页面1发送请求,然后客户端会向页面1发送请求,页面1会给客户端发送响应。
14.Thymeleaf-视图模板技术
(这里简单介绍thymeleaf)
在HTML页面上,加载Java内存中的数据的过程我们称为渲染(render);thymeleaf是用来帮助视图渲染的技术。
使用步骤
①添加thymeleaf的jar包
②在web.xml文件中添加配置
<context-param>
<param-name>view-prefix</param-name><!--前缀-->
<param-value>/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name><!--后缀-->
<param-value>.html</param-value>
</context-param>
③新建一个Servlet类ViewBaseServlet
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ViewBaseServlet extends HttpServlet {
private TemplateEngine templateEngine;
@Override
public void init() throws ServletException {
// 1.获取ServletContext对象
ServletContext servletContext = this.getServletContext();
// 2.创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
// 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
// ②设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
// ③设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);
// ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4.创建模板引擎对象
templateEngine = new TemplateEngine();
// 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
// 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, getServletContext());
// 3.处理模板数据
templateEngine.process(templateName, webContext, resp.getWriter());
}
}
ViewBaseServlet类的init方法会读取view-prefix和view-suffix
processTemplate(String templateName,HttpServletRequest request,HttpServletRespond respond)方法会将逻辑视图名称对应到物理视图名称上去,并且完成渲染和跳转。
逻辑视图名称:index
物理视图名称:前缀+逻辑视图名称+后缀
④使我们的类继承ViewBaseServlet
表头要修改成www.thymeleaf.org
th:if="${#lists.isEmpty(session.key)}" 判断集合session.key是否为空
th:unless="${#lists.isEmpty()}"判断集合是否为空
th:each="fruit :${session.key}"遍历集合session.key
th:text="${}"设置text的值
15.保存作用域
有四个保存作用域:page(页面)、request(一次请求范围)、session(一次会话)、application(整个应用程序范围)
page在使用thymeleaf后使用的不多,这里不进行介绍;request对应的是HttpServletRequest,直接使用HttpServletRequest对象即可;session对应的是HttpSession,使用HttpServletRequest中的getSession()来获取HttpSession对象;application对应的是ServletContext用HttpServletRequest中的getServletContext()获取ServletContext对象。
这三个类都有setAttribute(String name,Object value)和getAttribute(String name)方法来设置属性和获取属性值。
16.路径问题
在HTML中,可以在head标签中使用<base href="https://localhost:8080/项目名"/>来使当前页面的所有路径都以该路径为基础
在thymeleaf中,使用th:="@{}"来代替上述功能
例:<link th:href="@{/css/shopping.css}">