文章目录
1 Servlet简介
Servlet ,全称 Java Servlet 。是⽤ Java 编写的服务器端程序,其主要功能在于交互式地浏览和修改数据,⽣成动态Web内容。Servlet 是一个接口,我们一般使用的是它的实现类。Servlet 运行于支持 Java 的服务器中,理论上可以响应任何类型的请求,但绝⼤多数情况下Servlet 只⽤来扩展基于 HTTP 协议的 Web 服务器。
Servlet 工作模式:
- 客户端发送请求⾄服务器
- 服务器启动并调⽤ Servlet,Servlet 根据客户端请求⽣成响应内容并将其传给服务器
- 服务器将响应返回客户端
2 Servlet API
实现 Servlet 接口需要重写五个方法,继承 HTTPServlet 只需要重写两个方法,一般后者使用较多。
3 Servlet工作原理
- Servlet 接⼝定义了 Servlet 与 Servlet 容器之间的契约。这个契约是:Servlet 容器将 Servlet 类载⼊内存,并产⽣ Servlet 实例和调⽤它具体的⽅法。但是要注意的是,在⼀个应⽤程序中,每种 Servlet 类型只能有⼀个实例。
- ⽤户请求致使 Servlet 容器调⽤ Servlet 的 Service() ⽅法,并传⼊⼀个 ServletRequest 对象和⼀个 ServletResponse 对象。这两个对象都是由 Servlet 容器(例如 TomCat)封装好的,并不需要程序员去实现,可以直接使⽤这两个对象。
- ServletRequest 中封装了当前的 Http 请求,开发人员通过它获取请求数据。 ServletResponse 表示当前⽤户的 Http 响应,开发人员通过它就能把响应结果发回给⽤户。
- 对于每⼀个应⽤程序,Servlet 容器还会创建⼀个 ServletContext 对象。这个对象中封装了上下⽂ (应⽤程序)的环境详情。每个应⽤程序只有⼀个 ServletContext。每个 Servlet 对象也都有⼀个封装 Servlet 配置的 ServletConfig 对象。
4 Servlet生命周期
当客户端⾸次发送第⼀次请求后,由 web 服务器去解析请求,根据请求找到对应的 Servlet,判断该类的对象是否存在,不存在则创建Servlet 实例,然后调用 init() ⽅法进⾏初始化操作,初始化完成后调用 service() ⽅法,由 service() 判断客户端的请求⽅式,如果是get,则执⾏ doGet(),如果是 post 则执⾏ doPost(),处理⽅法完成后作出响应结果给客户端,单次请求处理完毕。
当⽤户发送第⼆次以后的请求时,会判断对象是否存在,但是不再执⾏ init(),⽽直接执⾏ service() ⽅法,接着调用 doGet() 或者doPost() ⽅法,最后返回响应结果给客户端。
当服务器关闭时调用 destroy() ⽅法进⾏销毁。
Servlet 执行过程:
- 实例化,创建 Servlet 实例
- 初始化,调用 init 方法
- 处理请求,调用 service 方法
- 服务终止,调用 destroy 方法
5 HttpServletRequest请求
HttpServletRequest 表示 Http 环境中的 Servlet 请求。它扩展于 javax.servlet.ServletRequest 接⼝。
5.1 请求常用方法
常用方法:
方法名 | 作用 |
---|---|
String getParameter(String name) | 根据表单组件的名称(name属性的值)来获取请求数据,无论提交时是什么类型,获取的数据都是 String 类型 |
String[] getParameterValues(String name) | 有多个表单组件的 name 属性为同一个值时,使用该方法一次获取多组数据 |
void setCharacterEncoding(String charset) | 指定 post 请求的编码方式,一般执行 setCharacterEncoding("utf-8") |
RequestDispatcher getRequestDispatcher(String path) | 跳转页面,一般用于请求转发,固定格式执行 getRequestDispatcher(path).forward(request,response) |
void setAttribute(String s,Object o) | 存值,s 和 o 一般以 key = value 的形式存储 |
Object getAttribute(String s) | 取值,根据 key 值取 value,得到是一个 Object 类型,需要向下转型 |
HttpSession getSession() | 获取会话 session,用于存值 |
5.2 请求方式
- 通过表单提交,提交方式 post 或 get 都行
- 通过 a 标签发送请求,只能是 get 提交,示例:
<a href="/login?name=abc&pass=123">
- 浏览器地址栏直接输入,只能是 get 提交,格式:地址?key=value&key=value…(同上 a 标签)
- js 提交,如
location.href="请求地址?key=value&key=value"
,只能是 get 提交 - ajax 提交,提交方式 post 或 get 都行
5.3 处理请求乱码
-
在 Servlet 中执行
request.setCharacterEncoding("UTF-8");
仅对 post 提交生效 -
String s=new String(request.getParameter("key").getBytes("ISO-8859-1"),"GBK");
仅对 get 提交生效 -
在 Tomcat ⽬录结构 \conf\server.xml 中设置字符集 URIEncoding=“UTF-8”
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />
注意:tomcat8.0 以后不需要⼿动设置这个属性了
5.4 get和post的区别
Get 提交,请求可见,它的请求数据都在请求 url 中;传输数据大小有限制,请求数据大小受限于 url 的大小;传输数据类型和编码受限,只能传递文本信息,且 url 都是用 ascll 编码,所以非 ascll 请求数据要编码后才能传递;安全性低,因为请求数据可见,当有账户密码的等信息时无法保证用户的安全,且使用 get 可能会造成 CSRF 攻击。
Post 提交。请求不可见,请求数据都在 http 请求包中,用户不可见;传输数据大小没有限制;传输数据可以是任何数据,文本,图片,视频,文件都可以,也可以是任意类型的编码;相比于 get 安全性高。
6 HttpServletResponse响应
HttpServletResponse 接⼝,它继承⾃ ServletResponse 接⼝,专⻔⽤来封装 HTTP 响应消息。 在 HttpServletResponse 接⼝中定义了向客户端发送响应状态码,响应消息头,响应消息体的⽅法。
6.1 响应常用方法
方法名 | 作用 |
---|---|
void addCookie(Cookie cookie) | 添加 cookie |
sendRedirect(String s) | 发送⼀条响应码,将浏览器重定向到指定的位置 |
PrintWriter getWriter() | 获得字符流,通过字符流的 write(String s) ⽅法可以将字符串设置到 response 缓冲区中,随后Tomcat 会将 response 缓冲区中的内容组装成 Http 响应返回给浏览器端 |
setContentType(String s) | 告诉浏览器响应的文件的 MIME 类型,以及文件的编码方式 |
setCharacterEncoding(String s) | 设置响应内容的编码方式 |
6.2 转发和重定向
转发: request.getRequestDispatcher(path).forward(request,response)
浏览器向服务器发送一个请求,服务器为了处理请求将请求转发到一个新的页面。
重定向: response.sendRedirect(path)
浏览器向服务器发送一个请求,服务器响应浏览器一个新的地址去处理请求,浏览器得到响应地址并向新的地址发送请求。
转发和重定向的区别:
区别 | 转发 | 重定向 |
---|---|---|
请求次数 | 请求一次 | 请求两次 |
地址栏 | 地址栏不变 | 地址栏变化 |
数据 | 转发一次请求,数据共享 | 重定向两次请求不共享数据 |
页面跳转 | 只能跳转本站点的资源 | 可以跳转到任意 URL |
行为目标 | 转发发生在服务器 | 重定向发生在客户端 |
7 session会话
从打开浏览器到关闭浏览器,期间访问服务器就称为⼀次会话,一次会话期间可以有多次请求。一个请求间的数据能够共享,但是不能跨页面,重定向的两次请求间数据不共享,一个会话期间的所有数据共享,也可以跨页面。
常用方法:
方法名 | 作用 |
---|---|
void setAttribute(String s,Object o) | 以 key=value 的形式存值,值存储于服务器端 |
Object getAttribute(String s) | 通过指定的 key 从 session 中获取对应存储的 value 值, |
void removeAttribute(String s) | 从 session 中删除指定 key 对应的 value 对象 |
void invalidate() | 使当前 session 对象失效 |
void setMaxInactiveInterval(int i) | 设置 session 的最大非活动时间(单位秒),每次该客户端访问服务器就会刷新最大活动时间,指定时间内该客户端无任何活动,则其存于服务器的 session 就会失效 |
8 web.xml
web.xml 文件的作用主要有两个:配置 Servlet 的映射关系,初始化参数设置。
8.1 Servlet映射
每个请求都有指定的 Servlet 去处理,如何确定它们的对应关系,这就需要在 web.xml 文件中配置映射关系。根据一个 Servlet 类在项目下的完整路径找到一个指定的 Servlet,然后为其取一个别名,然后在映射表中为该别名指定一个请求路径,如此映射关系就有了。
<servlet>
<servlet-name>⾃定义名称</servlet-name>
<servlet-class>处理请求的类的完整路径</servlet-class>
</servlet>
<servlet-mapping><!-- mapping 表示映射 -->
<servlet-name>⾃定义名称</servlet-name>
<url-pattern>请求名</url-pattern>
</servlet-mapping>
8.2 初始化参数
web.xml 中可以配置一些初始化参数,在 Servlet 初始化的时候可以获取参数进行相应的配置。
为参数指定名称和值就可以完成配置,如下方字符编码参数配置:
<servlet>
<servlet-name>⾃定义名称</servlet-name>
<servlet-class>处理请求的类的完整路径</servlet-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
使用方式,首先重写 init 方法,然后在方法中获取,如下:
@Override
public void init(ServletConfig config) throws ServletException {
String encoding = config.getInitParameter("encoding");
}
这种方式获取的参数仅限在当前指定的 Servlet 中使用。
全局初始化参数配置如下:
<context-param>
<param-name>bianma</param-name>
<param-value>utf-8</param-value>
</context-param>
获取方式如下:
@Override
public void init(ServletConfig config) throws ServletException {
String bianma = config.getServletContext().getInitParameter("bianma");
}
9 Servlet3.0
从 Servlet3.0 开始,配置 Servlet ⽀持注解⽅式,但还是保留了配置 web.xml ⽅式。
注解配置的方式更加简洁,高效,使用时只需在 Servlet 类上使用 @WebServlet 注解进⾏配置就行了。
@WebServlet常用属性:
属性名 | 类型 | 是否必须 | 说明 |
---|---|---|---|
asyncSupported | boolean | 否 | 指定Servlet是否⽀持异步操作模式 |
displayName | String | 否 | 指定Servlet显示名称 |
initParams | webInitParam[] | 否 | 配置初始化参数 |
loadOnStartup | int | 否 | 标记容器是否在应⽤启动时就加载这个 Servlet,等价于配置⽂件中的标签 |
name | String | 否 | 指定Servlet名称 |
urlPatterns/value | String[] | 否 | 这两个属性作⽤相同,指定Servlet处理的url |
属性名和属性值使用等号连接,多个属性间使用逗号分隔,如下:
@WebServlet(name = "myUserServlet",
urlPatterns = "/user/test", //斜杠必须
loadOnStartup = 1,
initParams = {
@WebInitParam(name="name", value="⼩明"),
@WebInitParam(name="pwd", value="123456")
})
public class UserServlet extends HttpServlet {
...
}
loadOnStartup属性
标记容器是否在启动应⽤时就加载 Servlet,默认不配置或数值为负数时表示客户端第⼀次请求 Servlet 时再加载;0 或正数表示启动应⽤就加载,正数情况下,数值越⼩,加载该 Servlet 的优先级越⾼。
name属性
可以指定也可以不指定,通过 getServletName() 可以获取到,若不指定,则为 Servlet 的完整类名。
urlPatterns/value属性
String[] 类型,可以配置多个映射,如:urlPatterns={"/user/test", “/user/example”}
使用注解注意事项
根元素中不能配置属性 metadata-complete=“true”,否则⽆法加载注解配置。metadata-complete 属性表示通知 Web 容器是否寻找注解,默认不写或者设置 false,容器会扫描注解,为 Web 应⽤程序构建有效的元数据;metadata-complete=“true”,会在启动时不扫描注解(annotation)。如果不扫描注解的话,⽤注解进⾏的配置就⽆法⽣效。
urlPatterns的使用规则
- 一个请求路径必须以 / 开头
- /* 或者 / 可以拦截所有请求
- 路径拦截:/user/test (只会拦截指定的一个请求路径,必定以 / 开头)
- 后缀名拦截:*.do (所有以 .do 结尾的请求都会拦截)
- 路径拦截和后缀名拦截不能一起使用,如:/user/.do 、/.do 、test*.do 都是⾮法的,启动时候会报错