一、设置编码
Tomcat8之前,设置编码:
1)get请求方式:
//get方式目前不需要设置编码(只针对于Tomcat8之前)
// 如果是get请求发送的中文数据,转码稍微有点麻烦只针对于(Tomcat8之前)
String fname = request.getParameter("fname");
//1.将字符串打散成字节数组
byte[] bytes = fname.getBytes("ISO-8859-1");
//2.将字节数组按照设定的编码重新组装成为字符串
fname = new String(bytes,"UTF-8");
这幅图片是是为了是我的文章看起来不是很单调^_^
2)post请求方式:
//post方式下,设置编码,防止中文乱码
request.setCharacterEncoding("utf-8"); //设置request对象的解码方式
Tomcat8开始,设置编码,只需针对与post方式
request.setCharacterEncoding("utf-8");
注意:
需要注意的是,设置编码值一句代码必须在所有获取参数动作之前
二、Servlet的关系继承
1) 继承关系
javax.servlet.Servlet 接口
javax.servlet.GenericServlet 抽象类
javax.servlet.http.HttpServlet 抽象子类
2)相关方法(三个重要方法)
javax.servlet.Servlet 接口中三个重要的方法:
void init(config) - 初始化方法
void service(request,response) - 服务方法
void destory() - 销毁方法
javax.servlet.GenericServlet 抽象类中实现了初始化和销毁方法,没有实现服务方法:
void service(request,response) - 仍然是抽象的
javax.servlet.http.HttpServlet 抽象子类中实现了这个 service 服务方法:
void service(request,response) - 不是抽象的,并且其中方法用的是 this.service() 表明实际执行的是子类中再重写的 service 服务方法
1:String method = req.getMethod;获取请求的方法
2:各种if判断,根据请求方式不同,决定去调用不同的do方法
if (method.equals("GET")) {
·····
} else if (method.equals("HEAD")) {
·····
} else if (method.equals("POST")) {
·····
} ·····
3:在HttpServlet这个抽象类中,do方法都差不多:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_get_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
private void sendMethodNotAllowed(HttpServletRequest req, HttpServletResponse resp, String msg) throws IOException {
String protocol = req.getProtocol();
if (protocol.length() != 0 && !protocol.endsWith("0.9") && !protocol.endsWith("1.0")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
3)小结:
1.继承关系: HttpServlet -> GenericServlet -> Servlet
2.Servlet中的核心方法: init() , service() , destroy()
3.服务方法: 当有请求过来时,service方法会自动响应(其实是 tomcat 容器调用的)
在 HttpServlet 中我们会去分析请求的方式:到底是 get、post、head 还是delete 等等
然后再决定调用的是哪个 do 开头的方法
那么在 HttpServlet 中这些 do 方法默认都是 405 的实现风格,要我们子类去实现对应的 方法,否则默认会报405错误
4.因此,我们在新建 Servlet 时,我们会去考虑请求方法,从而决定重写哪个 do 方法
三、Servlet的生命周期
1)生命周期:
从出生到死亡的过程就是生命周期。对应 Servlet 中的三个方法:init(), service(), destroy()
2)默认情况下:
第一次接收请求时出生,这个 Servlet 会进行实例化(调用构造方法)、初始化(调用init())、然后服务(调用service())
从第二次请求开始,每一次都只有服务,就没有实例化和初始化的过程了
当容器关闭时,其中的所有的 servlet 实例会被销毁,调用销毁方法
public class Demo2servlet extends HttpServlet {
public Demo2servlet() {
System.out.println("正在实例化!!!");
}
@Override
public void init() throws ServletException {
System.out.println("正在初始化!!!");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("正在服务!!!");
}
@Override
public void destroy() {
System.out.println("正在销毁!!!");
}
}
3)通过案例我们发现:
— Servlet 实例 tomcat 只会创建一个,所有的请求都是这个实例去响应。
— 默认情况下,第一次请求时,tomcat 才会去实例化,初始化,然后再服务,这样的好处是什么: 提高系统的启动速度,只有创建对象,就是说有请求,才创建 servlet 对象。这样的缺点是什么: 第一次请求时,耗时较长
— 因此得出结论:
如果需要提高系统的启动速度,当前默认情况就是这样。
如果需要提高响应速度,我们应该设置 Servlet 的初始化时机。
4)Servlet 的初始化时机:
默认是第一次接收请求时,实例化,初始化
我们可以通过修改 web.xml 文件中 Servlet 的 <load-on-startup> 标签来设置 servlet 启动的先后顺序,数字越小,启动越靠前,最小值0
修改配置文件:
<servlet>
<servlet-name>Demo2servlet</servlet-name>
<servlet-class>servlets.Demo2servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
5)Servlet 在容器中是:单例的、多线程情况下是线程不安全的
1:单例:
所有的请求都是同一个实例去响应
2:线程不安全:
一个线程需要根据这个实例中的某个成员变量值去做逻辑判断。但是在中间某个时机,另一个线程改变了这个成员变量的值,从而导致第一个线程的执行路径发生了变化
3: 我们已经知道了servlet是线程不安全的,给我们的启发是:尽量的不要在 servlet 中定义成员变量。如果不得不定义成员变量,那么不要去:①不要去修改成员变量的值;②不要去根据成员变量的值做一些逻辑判断。
四、HTML协议
1)HTTP 称之为 超文本传输协议。
2)Http是无状态的
3)Htpp请求响应包含两个部分:请求和响应
- 请求:
请求包含三个部分: 1.请求行 ; 2.请求消息头 ; 3.请求主体
1:请求行包含是三个信息: 1. 请求的方式 ; 2.请求的URL(资源地址);3.请求的协议版本(一般都是 HTTP1.1)
2:请求消息头中包含了很多客户端需要告诉服务器的信息,比如:我的浏览器型号、版本、我能接收的内容的类型、我给你发的内容的类型、内容的长度等等
3:请求体,三种情况
get 方式,没有请求体,但是有一个 queryString
post 方式,有请求体,form data
json 格式,有请求体,request payload
- 响应:
响应也包含三个部分: 1. 响应行 ; 2.响应头 ; 3.响应体
1:响应行包含三个信息:1.协议版本;2.响应状态码(200);3.响应状态(ok)
2:响应头:包含了服务器的信息;服务器发送给浏览器的信息(内容的媒体类型、编码、内容长度等)
3:响应体:响应的实际内容(比如请求 add.html 页面时,响应的内容就是<html><head><body><form…)
五、会话
1)Http 是无状态的
- HTTP 无状态 :服务器无法判断这两次请求是同一个客户端发过来的,还是不同的客户端发过来的
- 无状态带来的现实问题:第一次请求是添加商品到购物车,第二次请求是结账;如果这两次请求服务器无法区分是同一个用户的,那么就会导致混乱
- 通过会话跟踪技术来解决无状态的问题。
2)会话跟踪技术
- 客户端第一次发请求给服务器,服务器获取 session,获取不到,则创建新的,然后响应给客户端
- 下次客户端给服务器发请求时,会把 sessionID 带给服务器,那么服务器就能获取到了,那么服务器就判断这一次请求和上次某次请求是同一个客户端,从而能够区分开客户端
- 常用的API
- 1创建会话的 API:
request.getSession() -> 获取当前的会话,没有则创建一个新的会话
request.getSession(true) -> 效果和不带参数相同
request.getSession(false) -> 获取当前会话,没有则返回 null,不会创建新的
- 2其他常用 API:
session.getId() -> 获取 sessionID
session.isNew() -> 判断当前 session 是否是新的
session.getMaxInactiveInterval() -> session 的非激活间隔时长,默认1800秒
session.invalidate() -> 强制性让会话立即失效
3)session 保存作用域:
- session 保存作用域是和具体的某一个 session 对应
- 常用的API:
void session.setAttribute(k,v)
Object session.getAttribute(k)
void removeAttribute(k)
六、服务器内部转发以及客户端重定向
1)服务器内部转发:request.getRequestDispatcher("...").forward(request,response);
- 一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端是不知道的
- 地址栏没有变化
2)客户端重定向:response.sendRedirect("....");
- 两次请求响应的过程。客户端肯定知道,请求的 URL 有变化
- 地址栏有变化
七、thymeleaf
1)添加thymeleaf的jar包
我给你们找好了:http://t.csdnimg.cn/mQaI5
2)新建一个Servlet类ViewBaseServlet
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());
}
}
3)在web.xml文件中添加配置
- 配置前缀 view-prefix
- -配置后缀 view-suffix
<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>
4)使得我们的Servlet继承ViewBaseServlet
5)根据逻辑视图名称 得到 物理视图名称
//此处的视图名称是 index
//那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
//逻辑视图名称: index
//物理视图名称: view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是 : [ / index .html
super.processTemplate("index",request,response);
八、结尾
给大家分享一下自己的笔记,因我最近要应付其它的考试,所以只写了一部分给大家,希望对大家有帮助!
有大佬想要帮我补充一下可以分享到评论中!!