Servlet的学习日常
文章目录
1.Servlet设置编码问题
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请求方式:
request.setCharacterEncoding("UTF-8");
tomcat8开始,设置编码,只需要针对post方式
request.setCharacterEncoding("UTF-8");
注意:需要注意的是,设置编码(post)这一句代码必须在所有获取参数动作之前
request.setCharacterEncoding("UTF-8");//之前
String fname = request.getParameter("fname");
String remark = request.getParameter("remark");
2.Servlet的继承关系
1.继承关系:HttpServlet -> GenericServlet -> Servlet接口
2.Servlet中的核心方法: init() , service() , destroy()
3.service方法:当有请求过来时serice方法会自动响应(其实是tomcat容器调用的)
在HttpServlet中会分析我们请求的方式:到底是get, post. head 还是 delete等等
然后再决定调用哪个do开头的方法
那么在HttpServlet中这些do方法默认都是405的实现风格-要我们在子类去实现对应的方法,否则默认会报405错误
因此,我们在新建Servlet时,我们才会考虑请求方法,从而决定重写哪个do方法
3.Servlet的生命周期
1.生命周期:从出生到死亡的过程叫做生命周期。对应的Servlet中的 init() , service() , destroy()
2.默认情况下Servlet的生命周期:
第一次接受请求时,这个Servlet会进行实例化(调用构造方法),初始化(调用init()方法),然后调用服务(调用service()方法)
从第二次请求开始,每一次请求都是服务(调用service()方法)
当容器关闭(idea 结束tomcat服务)时,其中的所有servlet实例才会被销毁,调用销毁方法(调用destroy()方法)
3.通过案例我们发现:
- tomcat只会创建一个Servlet实例,所有请求都是这个实例去响应。
- 默认情况下,第一次请求时,tomcat才会去实例化,初始化,然后再服务。好处是提高系统的启动速度。缺点是第一次请求时,耗时较长。
- 因此得出结论:如果需要提高系统的启动速度。当前默认的情况就是这样。如果需要提高响应速度,我们应该设置初始化时机。
- servlet在容器中是单例的,是线程不安全的。
- 因为servlet是线程不安全的,给我们的启发是:尽量不要在servlet中定义成员变量。如果不得不定义成员变量。
- 1.不要去修改成员变量的值
- 2.不要根据成员变量的值做一些逻辑判断。
servlet线程不安全解释:一个线程需要根据这个实例中的某个成员变量去做逻辑判断。但是在中间的某个时机,另一个线程改变了这个成员变量的值,从而导致第一个线程的执行路径发生了变化。
因为是单例模式,多线程时都会进入service()方法,此时如果存在成员变量,多线程进行抢占。
如图:线程2在线程1进入if判断之前对变量进行赋值操作,则会改变线程1的路线。
4.Servlet的初始化时机:
- 默认是第一次接收请求时,实例化,初始化
- 我们可以通过来设置servlet启动的先后顺序,数字越小,启动越靠前,最小值0
<servlet>
<servlet-name>Demo02Servlet</servlet-name>
<servlet-class>com.Demo02Servlet</servlet-class>
<!-- 启动时机参数:数字越小启动的时间越靠前-->
<load-on-startup>1</load-on-startup>
</servlet>
4.Http协议
https://heavy_code_industry.gitee.io/code_heavy_industry/pro001-javaweb/lecture/chapter06/
1.Http 称之为 超文本传输协议
2.Http是无状态的
3.Http请求响应包含两个部分:请求和响应
请求:
请求包含三个部分: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页面时,响应的内容就是…)
5.会话
1.Http是无状态的
-
HTTP无状态:服务器无法判断这两次请求时同一个客户端发过来的,还是不同的客户端发过来的
-
无状态带来的现实问题:第一次请求是添加商品到购物车,第二次请求是结账;如果这两次请求服务器无法区分是同一个用户的,那么就会导致混乱。
-
通过会话跟踪技术解决这个问题。
2.会话跟踪技术
-
客户端第一次发请求给服务器,服务器获取session,获取不到,则创建新的,然后响应给客户端
-
下次客户端给服务器端发送请求时,会把session 带给服务器,那么服务器就能获取到了,那么服务器就判断这次请求和上次某次请求是同一个客户端,从而能够区分开客户端。
-
常用的API:
request.getSession() -> 获取当前的会话,没有则创建新的
request.getSession(true) -> 效果和没有参数的相同
request.getSession(false) -> 获取当前的会话,没有则返回null,不会创建新的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);
下面那个请求来自不同浏览器session是不同的 所以拿不到uname的值
6.服务器内部转发以及客户端重定向
1.服务器内部转发:request.getRequestDispatcher(“…”).forward(request,response);
一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端是不知道的
地址栏没有变化
2.客户端重定向:response.sendRedirect(“…”)
两次请求响应的过程。客户端肯定知道URL的变化
地址栏有变化
7.Thymeleaf 视图模板技术
1.添加thymeleaf的jar包
2.新建一个Servlet类viewBaseServlet(源代码考出来的)
3.在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>
4.使得我们的Servlet继承ViewBaseServlet
5.根据逻辑视图名称 得到 物理视图名称
//此处的视图名称是index
//那么thymeleaf会将这个 逻辑视图名称 对应到物理视图名称上去
//逻辑视图名称 : index
//物理视图名称: view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是:/ index .html
super.processTemplate("index",request,response);
6.使用thymeleaf的标签
th:if , th:unless , th:each , th:text
8.保存作用域
1.保存作用域
原始情况下,保存作用域我们可以认为有四个:page(页面级别,现在基本不用) , request(一次请求响应级别) , session(一次会话范围) , application(一次应用程序范围)
request作用域 现象:第一个过程请求不到因为不同请求,第二个过程可以是因为同一个请求。
session作用域 现象:因为客户端不同产生的session也不同,所以第二次是null
application作用域 现象除非tomcat停止否则都可以请求到