Servlet
1.servlet的概念和运行流程
1.1 创建servlet
1.实现javax.servlet.Servlet接口
2.继承javax.servet.GenericServlet类 (适配器模式)
3.继承javax.servlet.http.HttpServlet类 (模板方法设计模式)(开发中常用方式)
继承关系:Servlet --> GenericServlet --> HttpServlet
注:在之后的笔记中,servlet均默认由继承HttpServlet进行创建
1.2 使用
1.创建普通的java类并继承HttpServlet
2.复写service方法
3.在service方法中书写逻辑代码
4.在webRoot下的WEB-INF文件夹下的web.xml中配置servlet
- 运行流程
浏览器发送请求到服务器,服务器根据请求URL地址中的URI信息在webapps目录下找到对应的项目文件夹,然后在web.xml中检索对应的servlet,找到后调用并执行Servlet
1.3 URL组成
服务器地址:端口号/项目名称/对应servlet的url-pattern
- 亦可在项目的
properties —— web project settings —— context root
的属性中设置项目的别名
注意:servlet类不能在web.xml中配置别名同时使用@webservlet注解
2.servlet的生命周期
完整生命周期是从第一次调用到服务器关闭
如果servlet在web.xml中配置了load-on-startup,生命周期为服务器启动到服务器关闭
2.1 具体方法
init()方法
初始化方法,在servlet第一次加载进存储时被调用
service()方法
真正处理请求的方法
destroy()方法
在servlet被销毁时执行,如servlet被卸载或服务器关闭时
3. service()和doGet()和doPost()方法的区别
3.1 HTTP协议中get和post请求方式的区别
- get请求方式
请求数据会以?的形式隔开拼接在请求头中,不安全,没有请求实体部分。HTTP协议虽然没有规定请求数据的大小,但是浏览器对URL的长度是有限制的,所以get请求不能携带大量的数据 - post请求方式
请求数据在请求实体中进行发送,在URL中看不到具体的请求数据安全。适合数据量大的数据发送
3.2 service()方法
可以处理get/post方式的请求,如果servlet中有service方法,会优先调用service方法对请求进行处理
在继承HttpServlet后,如果复写的service调用了父类的service()方法super.service(arg0,arg1)
,则在service方法处理完后,会再次根据请求方式相应doGet方法或doPost方法。所以,一般情况下,我们是不在复写的service()方法中调用父类的service()方法,避免出现405错误
3.3 doGet()方法
处理get方式的请求
3.4 doPost()方法
处理post方式的请求
4.Servlet常见报错总结
404错误
原因一:在请求地址中的servlet的别名书写错误
原因二:虚拟项目名称书写错误
500错误
原因一:web.xml中servlet类的全限定路径拼写错误
原因二:service方法体中的代码执行错误
405错误
原因:请求方式和servlet中的方法不匹配所造成的
解决:尽量使用service方法进行请求处理,并且不要在service方法中调用父类service方法
5.request&response
5.1 request
5.1.1 概述
服务器使用对象来存储请求,每接受一个请求,就创建一个对象专门的存储此次请求的请求数据
服务器接收到浏览器的请求后,会创建一个Request对象,对象中存储了此次请求相关的请求数据。服务器在调用Servlet时会将创建的Request对象作为实参传递给Servlet的方法,比如:service方法
5.1.2 作用
request对象中封存了当前请求的所有请求信息
注意:request对象由tomcat服务器创建,并作为实参传递给处理请求的servlet的service方法
5.1.3 使用
- 获取请求头数据
获取请求方式 String method = req.getMethod();
获取请求URL StringBuffer url = req.getReqestURL();
获取URI String uri = req.getRequestURI();
获取协议 String h = req.geSchme();
-
获取请求行数据
获取指定的请求行信息String value = req.getHeader("keyName")
获取所有的请求行的键的枚举Enumeration e = req.getHeaderNames();
-
获取用户数据
获取指定的用户数据(不能用来获取同健不同值情况)String value = req.getParameter("keyName")
获取同键不同值的请求数据数组String[] values = req.getParameterValues("keyName")
获取所有用户请求数据的枚举集合req.getParameterNames
注意:如果要获取的请求数据不存在,不会报错,只会返回null
5.1.4 请求乱码问题解决
- 使用String进行数据重新编码(适用于get和post)
uname = new String(uname.getBytes("iso8859-1"),"utf-8")
- 使用公共配置
get方式:步骤一:req.setCharacterEncoding("utf-8") 步骤二:在tomcat的目录下的conf目录中修改server.xml文件,然后在Connector标签中增加属性useBodyEncoding="true"
post方式:
req.setCharacterEncoding("utf-8")
5.1.5 请求转发
- 作用:实现多个servlet联动操作处理请求,避免代码冗余,提高内聚性
- 使用:
req.getRequestDispatcher("转发目标地址").forward(req,resp)
地址书写相对路径即可,即servlet的别名 - 特点:一次请求,浏览器地址信息栏信息不改变
- 注意:请求转发后直接return即可,之后业务由转发servlet进行处理
5.1.6 request对象作用域
- 使用:
request.setAttribute(object name,Object value);
request.getAttribute(Object obj);
- 作用:解决了一次请求内的不同Servlet的数据共享问题
- 作用域:基于请求转发,一次请求中的所有Servlet共享
- 注意:使用Request对象进行数据流转,数据只在一次请求内有效
- 特点: 服务器创建;每次请求都会创建;生命周期一次请求
5.1.7 重定向
- 需求:
servlet无法处理当前请求
请求转发造成表单数据(请求实体内容)重复提交 - 使用:
resp.sendRedirect(String uri)
- 特点:
两次请求,两个request对象
浏览器地址栏信息改变 - 时机:
如果请求中有表单数据,而数据又比较重要,不能重复提交,建议使用重定向
如果请求被Servlet接受后,无法进行处理,建议使用重定向定位到可以处理的资源 - 改进:可以用session技术完成两次请求间无记忆的特点
5.2 response
5.2.1 作用
用来响应数据到浏览器的一个对象
5.2.2 使用
- 设置响应头
在响应头中添加响应信息,但是会同键覆盖resp.setHeader("key","value")
在响应头中添加响应信息,但是不会覆盖resp.addHeader("key","value")
- 设置响应编码格式
resp.setHeader("content-type","text/html;charset=utf-8")
resp.setContentType("text/html;charset=utf-8")
- 设置响应状态码
resp.sendError(int num,String msg)
- 设置响应实体
响应具体的数据给浏览器resp.getWriter().write("String str")
5.2.3 service请求处理代码流程
- 设置响应编码格式
- 获取请求数据
- 处理请求数据(MVC思想)
逻辑代码
数据库操作 - 响应处理结果
6.Servlet流程总结
1> 浏览器发起请求到服务器(请求)
2> 服务器接收浏览器的请求,进行解析,创建request对象存储请求数据
3> 服务器调用对应的servlet进行请求处理,并将request对象作为实参传递给servlet的方法
4> servlet的方法执行进行请求处理
设置请求编码格式
设置响应编码格式
获取请求信息
处理请求信息
- 创建业务层对象
- 调用业务层对象的方法
相应处理结果
7.Cookie
7.1 作用
解决了发送的不同请求的数据共享问题
7.2 使用
7.2.1 Cookie的创建和存储
7.2.1.1 创建Cookie对象
Cookie c = new Cookie("String name", "String value")
7.2.1.2 设置Cookie(可选)
- 设置有效期
c2.setMaxAge(int seconds)
- 设置有效路径
c2.setPath("uri")
7.2.1.3 添加Cookie信息给客户端
resp.addCookie(c)
7.2.2 Cookie的获取
7.2.2.1 获取Cookie信息数组
Cookie[] cks = req.getCookies()
7.2.2.2 遍历数组获取Cookie信息
if(cks!=null) {
for(Cookie c:cks) {
String name = c.getName();
String value = c.getValue();
System.out.println(name+":"+value);
}
}
7.3 特点
浏览器端的数据存储技术
存储的数据声明在服务器端
默认Cookie信息存储好之后,每次请求都会附带,除非设置有效路径
- 注意 :一个Cookie对象存储一条数据,多条数据可以通过创建多个Cookie对象进行存储
7.4 分类
临时存储:存储在浏览器的运行内存中,浏览器关闭即失效
定时存储:设置了Cookie的有效期,存储在客户端的硬盘中,在有效期内符合路径要求的请求都会附带该信息
8.Session
8.1 概述
8.1.1 需求
一个用户的不同请求处理的数据共享的场景
8.1.2 解决
使用session技术
8.1.3 原理
用户第一次访问服务器,服务器会创建一个session对象给此用户,并将该session对象的JSEESSIONID使用Cookie技术存储到浏览器中,保证用户的其它请求能够获取到同一个session对象,也就保证了不同请求能够获取到共享的数据
8.1.4 特点
- 存储在服务器
- 服务器进行创建
- 依赖Cookie技术
- 有效期为一次会话
- 默认存储时间是30分钟
8.1.5 作用域
- 一次会话。服务器会将JSESSIONID作为一个单独Cookie附加到response上返回给客户端(session主要基于cookie技术,虽然也可通过URL重写),而这个Cookie会默认存放在浏览器内存中而不是硬盘上,所以在关闭浏览器后,该Cookie对象也会被清除,浏览器从而不持有该JSESSIONID,此时虽然服务器端可能持有JSESSIONID的对应对象,但在应用方面基本等同于失效,因为浏览器失去了对象的“指针”
- 在JSESSIONID和session对象不失效的情况下为整个项目内
8.2 使用
8.2.1 创建session对象/获取session对象
HttpSession hs = req.getSession();
- 如果请求中拥有session的标识符也就是JSESSIONID,则返回其对应的session对象
- 如果请求中没有session的标识符也就是JSESSIONID,则创建新的session对象,并将其JSESSIONID作为cookie数据存储到浏览器内存中
- 如果session对象失效了,也会重新创建一个session对象,并将其JSESSIONID存储在浏览器内存中
8.2.2 设置session存储时间
hs.setMaxInactival(int seconds)
即在指定的时间内session对象没有被使用则销毁。如果使用了则重新计时
8.2.3 设置session强制失效
hs.invalidate()
8.2.4 存储和获取数据
- 存储:
hs.setAttribute(String name,Object value)
- 获取:
hs.getAttribute(String name)
返回数据类型为Object - 注意: 存储的动作和取出的动作发生在不同的请求中,但是存储要先于取出执行
8.2.5 使用时机
一般的,用户在登录web项目时会将用户的个人信息存储到session中,供用户的其它请求使用
8.2.6 session失效处理
将用户请求中的JSESSIONID和后台获取到的SESSIONID进行比对,如果一致,则session没有失效,如果不一致则证明session失效。失效后重定向到登录页面,让用户重新登录
8.2.7 JSESSIONID存储
- JSESSIONID存储在了Cookie的临时存储空间中,浏览器关闭即失效。
- 原因:服务器会将JSESSIONID作为一个单独Cookie附加到response上返回给客户端(session主要基于cookie技术,虽然也可通过URL重写),而这个Cookie会默认存放在浏览器内存中而不是硬盘上,所以在关闭浏览器后,该Cookie对象也会被清除,浏览器从而不持有该JSESSIONID,此时虽然服务器端可能持有JSESSIONID的对应对象,但在应用方面基本等同于失效,因为浏览器失去了对象的“指针”
8.3 总结
session解决了一个用户的不同请求的数据共享问题,只要在JSESSIONID不失效和session对象不失效的情况下,用户的任意请求在处理时都能获取到同一个session对象
9.ServletContext
9.1 概述
9.1.1 需求
Request解决了一次请求内的数据共享问题,session解决了用户不同请求的数据共享问题,而ServletContext对象则是要解决不同用户之间的数据共享问题
9.1.2 特点
- 服务器进行创建
- 用户共享
- 一个项目只有一个
9.1.3 生命周期
服务器启动到关闭
9.1.4 作用域
项目内所有servlet
9.2 使用
9.2.1 获取ServletContext对象
- 第一种方式
ServletContext sc = this.getServletContext()
- 第二种方式
ServletContext sc2 = this.getServletConfig().getServletContext()
- 第三种方式
ServletContext sc3 = req.getSession().getServletContext()
9.2.2 使用ServletContext对象完成数据共享
- 数据存储
sc.setAttribute(String name, Object value)
- 数据获取
sc.getAttribute(String name)
返回的是Object类型 - 注意
不同的用户可以对ServletContext对象进行数据的存取
获取的数据不存在则返回null,不会报错
9.2.3 获取项目中web.xml文件中的全局配置数据
9.2.2.1 web.xml配置方式
<context-param>
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</context-param>
注意:一组 < context-param >标签只能存储一组键值对信息,多组数据可以通过声明多个< context-param >来进行存储
9.2.2.2 获取方法
sc.getInitParameter("String name")
根据键的名字返回web.xml中配置的全局数据的值,返回String类型
如果数据不存在则返回nullsc.getInitParameter()
返回键名的枚举
9.2.2.3 作用
将静态数据和代码进行解耦
9.2.4 获取项目webroot下的资源的绝对路径
String path = sc.getRealPath(String path)
获取的路径为项目根目录,path参数为项目根目录中的路径,即从项目根目录下开始写则可,无需书写项目名
9.2.5 获取项目webroot下的资源的流对象
InputStream is = sc.getResourceAsStream(String path)
获取的路径为项目根目录,path参数为项目根目录中的路径
注意:此种方式只能项目根目录下的资源流对象,class文件的流对象需要使用类加载器
10.ServletConfig
10.1 作用
ServletConfig对象是Servlet的专属配置对象,每个Servlet都单独拥有一个ServletConfig对象,用来获取web.xml中的配置信息
10.2 使用
10.2.1 web.xml配置方式
<servlet>
<servlet-name>ServletConfigServlet</servlet-name>
<servlet-class>servlet.ServletConfigServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
10.2.2 获取ServletConfig对象
ServletConfig sc = this.getServletConfig()
10.2.3 获取web.xml中的配置数据
sc.getInitParameter(String name)
11.web.xml文件
11.1 作用
- 存储项目相关的配置信息,保护servlet
- 解耦一些数据对程序的依赖
11.2 两个web.xml
11.2.1 使用位置
- 每个Web项目中
- Tomcat服务器中(在服务器目录conf目录中)
11.2.2 区别
- Web项目下的web.xml文件为局部配置,针对本项目的位置
- Tomcat下的web.xml文件为全局配置,配置公共信息
11.3 内容(核心组件)
11.3.1 组件列表
- 全局上下文配置(全局配置参数)
- servlet配置
- 过滤器配置
- 监听器配置
11.3.2 加载顺序
Web容器会按ServletContext -> context-param -> listener -> filter -> servlet这个顺序加载组件,这些元素可配置在web.xml文件中的任意位置
11.3.3 加载时机
服务器启动时
11.server.xml文件
11.1 概述
11.1.1 问题
浏览器发起请求后,服务器根据请求在webapps目录下调用对应的servlet进行请求处理,那么为什么是webapps目录难道不能是其它的目录吗?
11.1.2 解决
了解server.xml文件的配置信息
11.2 核心组件
<Server>
<Service>
<!-- Conector标签可以有多个 -->
<Connector>
</Connector>
<!-- 单个Service标签下只能有一个Engine标签 -->
<Engine>
<Host>
<Context/>
</Host>
</Engine>
</Service>
</Server>
- 热部署
<Context path="/项目名" reloadable="true" doBase="项目直至webapps下的绝对路径">
此种部署方式下,如果单个项目的绝对路径下文件被删除,则此项目会使服务器启动失败,导致服务器上的其他独立项目也不会启动