Servlet 快速概览
目录
生命周期
我们自己创建的servlet,继承自HttpServlet,就相当于有了init()、doGet()、doService()、doPost()、destroy()这几个方法,而这几个方法就可以描述Servlet的声明周期。
方法名 | 被调用的时刻 以及 功能 | |
init() | 只有第一次访问该servlet的时候被调用,一般用来进行数据初始化 | |
doGet() | 通过get方式访问servlet的时候被调用,响应get请求 | |
doPost() | 通过post方式访问servlet的时候被调用,响应post请求 | |
service() | 接收所有方式的请求,service会在doGet和doPost之前调用 | |
destroy() | 服务器停止的时候被调用,一般用来进行一些清理操作 |
因为我们将代码部署到服务器Tomcat上面,也就是说,Tomcat是一个容器。同时,上面的那些方法都是都Tomcat服务器来调用(由容器来调用)。
web.xml
web.xml是项目的配置文件,该文件用来配置请求路径与servlet的对应关系。
全路径为project-root/WebContent/WEB-INF/web.xml。
需要注意的是,servlet有多个版本,在高版本中,可以通过注解@WebServlet("url-pattern")来设置。之前的版本需要使用web.xml来配置。
示例:
<web-app>
<display-name>tomcat</display-name>
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>lixin.gan.test.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/testServlet</url-pattern>
</servlet-mapping>
</web-app>
Tomcat使用web.xml的步骤:
- Tomcat服务器在启动的时候,会加载web.xml文件,并解析文件。
- 服务器收到客户端的请求时,首先会根据请求的url路径去web.xml中相同寻找匹配的url-pattern。
- 如果没有找到匹配的url-pattern,就表示出错了(返回404);如果存在url-pattern,那么就利用与之对应的servlet-name,去servlet标签中查找对应的servlet-class。
- 根据找到的servlet-class来确定调用哪一个servlet来处理请求。
获取表单数据(设置请求的编码格式)
表单提交的方式get和post 与 servlet中的doGet和doPost方法相对应,但是可以使用service来获取get或者post请求。默认情况下,如果没有重写doPost、doGet、service,则先执行service方法,然后service方法中根据请求方式,再调用doGet或者doPost。
获取表单数据常用的是下面三个方法:
// 获取请求参数中key对应的value
String HttpServletRequest.getParameter(String key) // 用于获取checkbox这种有多个同名的key参数
String[] HttpServletRequest.getParameterValues(String key) // 获取所有参数,并以map形式保存
Map<String, String[]> HttpServletRequest.getParameterMap()
上面的所有方法接收到的数据,传输过程中都是经过编码,如果请求中的数据全是英文,那么不会出现问题;但是如果有其他字符(比如中文字符),此时打印获取的数据,会出现乱码,可以通过getBytes("utf-8")来解码,也可以直接设置请求的编码格式:
request.setCharacterEncoding("utf-8");
如果通过req.setCharacterEncoding("utf-8"),只能对post提交的数据进行字符集编码,而不能对get方式进行编码。因为get方式传递的参数是在URL中,进行的是URL编码。
但是可以在tomcat的配置文件中,增加一个配置项即可:useBodyEncodingForUri="true"
<Connector
connectionTimeout="200000"
port="80"
protocol="HTTP/1.1"
redirectPort="8443"
useBodyEncodingForUri="true"
/>
返回响应内容(设置响应的编码格式)
要想发回响应给请求方,可以通过下面的格式来进行:
PrintWriter writer = response.getWriter();
writer.append("hello 你好\n");
writer.flush();
上面的代码是简单的返回一些文本内容给客户端,但是有两个需要注意的地方:
1、此时并没有告诉客户端这个内容是什么格式(XML? JSON?MP4?),所以客户端接收到数据之后,会原封不动的显示出来。
2、响应回来的内容是使用了什么编码格式,注意编码格式和内容格式不一样,编码格式决定着客户端能否正确无误地解析文件内容。
鉴于以上面个注意点,可以通过两个方法来解决:
// 只设置响应内容的编码格式,而没有设置响应内容的数据格式
response.setCharacterEncoding("utf-8"); // 设置响应内容的数据格式,同时也设置了响应内容的编码格式
response.setContentType("text/html; charset=utf-8");
结合前两点,总结基本模板
以doGet为例子:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 首先设置请求数据的字符编码
req.setCharacterEncoding("utf-8"); // 设置响应内容的数据格式以及编码格式
resp.setContentType("text/html; charset=utf-8"); // 然后是自己的业务代码 }
上面这个模板其实并不好,因为,这样做之后,每一个方法都需要加这两行代码,一旦字符编码或者响应格式改变,就要修改很多地方。
后期可以使用拦截器来完成设置 字符编码 以及 响应数据格式 的功能。
获取请求协议头部信息
获取请求协议中的头部信息,有三个方法,但通常使用最多的是下面这个方法
String req.getHeader(String key)
使用方式很简单,需要注意的是,请求中key和value都是要经过编码的(不能直接传输中文字符)。
设置响应头部信息
设置响应头信息,也很简单,最常用的是下面这个方法:
void resp.setHeader(String key, String value)
注意,如果value包含中文字符,需要先经过编码才能作为参数。
如果要设置响应状态码,可以使用setStatus()方法来设置:
void resp.setStatus(int statusCode);
如果还要设置状态码的信息,可以使用sendError()
void resp.sendError(int statusCode, String msg);
使用过滤器
过滤器是一种特殊的工具,功能如下:
1、在请求到达服务器的时候先于servlet处理请求。
2、在返回给客户端响应之前,对Servlet的响应再进行一次加工,之后在返回给客户端。
使用过滤器,可以在web.xml中进行配置,也可以使用注解@WebFilter("url-pattern")来设置,下面是在web.xml中的配置:
<filter>
<filter-name>testFilter</filter-name>
<filter-class>lixin.gan.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
filter中的三个主要的方法:
public void init(FilterConfig fConfig)
filter中的init(),功能和servlet中的init()一样,用于数据的初始化,第一次调用是在服务器启动的时候
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
调用doFilter()进行过滤操作。三个参数的意义以及作用:
1、第1个参数request是客户端的请求(还没有被servlet处理),此时可以修改请求中的数据。
2、第2个参数response是由servlet处理之后的返回的response,此时可以修改响应中的数据。
3、filter对request进行一些处理之后,调用第3个参数chain的doFilter(request, response)方法,来将请求转发给对应的servlet处理,表示通过了过滤。
public void destroy()
服务器关闭的时候被调用。
结合前面servlet中的service()、doPost()、doGet()中对于所有请求,都要设置请求的编码格式以及相应内容的数据格式和编码格式,有了过滤器,可以将这些操作都单独地写在过滤器中,可以消除冗余,同时维护起来也方便。
比如:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws Exception { // 统一设置字符集编码以及响应内容格式
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8"); // 放行,执行真正的servlet
chain.doFilter(request, response);
}
在web.xml中为过滤器配置参数
前面已经介绍了过滤器怎么使用,这里增加一点内容:从web.xml中读取过滤器的配置参数。过滤器的init()方法使用来对过滤器进行一些初始化工作,再进行初始化的时候,可能会有这种情况:有一些(配置)参数的值在程序代码中写死,这样的话,一旦要修改配置参数的话,就需要修改代码。
其实,完全可以在web.xml中配置,然后在init方法中,利用FilterConfig类来获取web.xml中的配置项。在web.xml中添加配置项的方法如下:
<filter>
<filter-name>testFilter</filter-name>
<filter-class>lixin.gan.filter.MyFilter</filter-class>
<init-param>
<param-name>token</param-name>
<param-value>123456abc</param-value>
</init-param>
<init-param>
<param-name>code</param-name>
<param-value>9999</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在Filter的init方法中这样使用:
public void init(FilterConfig fConfig) throws ServletException {
System.out.println(fConfig.getInitParameter("code"));
System.out.println(fConfig.getInitParameter("token"));
}
使用Cookie
设置响应cookie(通过response对象返回客户端)
Cookie cookie = new Cookie("key", "value"); // 不设置过期时间(临时cookie),默认在浏览器窗口关闭之前有效。
cookie.setMaxAge(100); // 若设置cookie的过期时间,单位为秒,0表示删除该cookie。
cookie.setMaxAge(0) cookie.setValue("value2") cookie.setDomain("www.baidu.com");
cookie.setPath("/demo/test"); // 将cookie放入response对象中,返回给客户端。
response.addCookie(cookie);
获取请求中的cookie(通过request对象来获取)
// 获取所有cookie
Cookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) {
System.out.println("name --> " + cookie.getName());
System.out.println("value --> " + cookie.getValue());
System.out.println("maxAge --> " + cookie.getMaxAge());
System.out.println("-----------------------------------");
if (cookie.getName().equals("id")) {
cookie.setMaxAge(0); // 销毁cookie
}
}
使用Session
session基于cookie。
// 如果请求中携带有session,那么就会返回请求中的session
// 如果没有携带session,那么就创建一个session,并返回。
HttpSession session = request.getSession(); // 获取session_id,即JSESSION
String session_id = session.getId(); // 设置过期时间,不设置的话,默认是30分钟
// session失效了之后,下一次访问,服务器会重新创建一个session,并返回。
// 失效是指 指定时间端内,如果用户都没有发起请求,那么时间一到就失效
session.setMaxInactiveInterval(60); // 设置session项
session.setAttribute("name", "小强");
session.setAttribute("age", 99); // 移除session中的某一项,即使key不存在也不报错
session.removeAttribute("key"); // 获取session值,如果不包含key对应的session项,则返回null
String name = (String)session.getAttribute("name");
int age = (int)session.getAttribute("age"); // 强制session失效
session.invalidate();
对字符串数据进行编码和解码
前面有几个地方需要注意字符编码:
1、设置header的时候,如果设置的值包含中文,客户端接收到之后是乱码。
2、是指cookie和session的时候,value如果包含中文,则会出现错误。
这两种情况需要进行手动编码,使用的是java.net.URLEncoder.encode()方法,
使用方式如下:
// 将msg按照操作系统默认的字符编码格式进行编码,然后再进行url编码
String java.net.URLEncoder.encode(String msg) // 将msg按照charset进行编码,然后再进行url编码
String java.net.URLEncoder.encode(String msg, String charset)
对于请求中的header、cookie、session数据,与编码对应的是解码,使用的是java.net.URLDecoder.decode()方法:
// 将内容进行URL解码之后,再按照charset编码
java.net.URLDecoder.decode(String msg, String charset)
注意上面的编码和解码方式都是:URL编码。
监听器
监听器可以用于对request、session、servlet被创建、修改、销毁时,触发的事件处理程序。
配置监听器有两种方式:
1、使用注解@WebListener来标明为监听器。
2、在web.xml中配置,格式如下:
<listener>
<listener-class>lixin.gan.listener.MyListener</listener-class>
</listener>
监听器的分类如下:
监听器可以对servlet context、session、request进行监听,监听的时候,分为两类:
1、对初始化和销毁的监听器(XxxListener)
2、对属性进行修改时触发的监听器(XxxAttributeListener)
监听器在javax.servlet包里面。
监听器分类 | 监听器 | 方法 |
servlet context | ServletContextListener | contextInitialized(ServletContextEvent arg0) |
contextDestroyed(ServletContextEvent arg0) | ||
ServletContextAttributeListener | attributeAdded(ServletContextAttributeEvent arg0) | |
attributeRemoved(ServletContextAttributeEvent arg0) | ||
attributeReplaced(ServletContextAttributeEvent arg0) | ||
Session | HttpSessionListener | sessionCreated(HttpSessionEvent arg0) |
sessionDestroyed(HttpSessionEvent arg0) | ||
HttpSessionAttributeListener | attributeAdded(HttpSessionBindingEvent arg0) | |
attributeRemoved(HttpSessionBindingEvent arg0) | ||
attributeReplaced(HttpSessionBindingEvent arg0) | ||
request | ServletRequestListener | requestInitialized(ServletRequestEvent arg0) |
requestDestroyed(ServletRequestEvent arg0) | ||
ServletRequestAttributeListener | attributeAdded(ServletRequestAttributeEvent arg0) | |
attributeRemoved(ServletRequestAttributeEvent arg0) | ||
attributeReplaced(ServletRequestAttributeEvent arg0) |
Servlet 快速概览的更多相关文章
- Servlet快速入门
servlet是运行在服务端的java小程序,用来处理客户端请求,响应给浏览器的动态资源 servlet规范:包含3个技术点 1.servlet技术 2.filter技术 3.listener技术 s ...
- 【servlet】Servlet快速入门&使用Eclipse发布web项目
创建时间:6.15 1.什么是Servlet Servlet 运行在服务端的Java小程序,是sun公司提供一套规范(接口),用来处理客户端请求.响应给浏览器的动态资源.但servlet的实质就是ja ...
- Servlet快速入门及运行流程
一.Servlet快速入门 1.创建一个web工程 2.在JavaResource中src下创建一个包名称为com.myxq.servlet 3.在创建的servlet包当中创建一个class文件起名 ...
- Solon Cloud 分布式开发套件清单与快速概览
Solon Cloud 是一系列的接口标准和配置规范.Solon Cloud 为常见的分布式系统模式提供了一种简单且方便的编程模式,帮助开发人员构建有弹性的.可靠的.协调的应用程序.Solon Clo ...
- HTTP和Servlet快速入门
目录 1.HTTP 1.1 请求数据格式 1.2 相应数据格式 2.Servlet 3.Servlert的xml配置 1.HTTP 1.1 请求数据格式 请求行:请求数据的第一行 包含三个内容,按顺序 ...
- Servlet快速入门:第一个Servlet程序
Servlet是整个JavaWeb开发的核心,同时也是一套规范,即公共接口.用于处理客户端发来的请求并作出响应.通常情况下我们会发送不同的请求并交由不同的处理程序来处理,例如处理用户信息和处理订单信息 ...
- Servlet 快速开始 表单中文字段
req.getParameter | getParameterValue 一大特点是 返回null表示没有. [web.xml] <servlet> <serlvlet-mappin ...
- Scala快速概览
IDEA工具安装及scala基本操作 目录 一. 1. 2. 3. 4. 二. 1. 2. 3. 三. 1. 2. 3. 4. 5. 6. 7. 四. 1. (1) (2) (3) (4) (5) ( ...
- 用 Flask 来写个轻博客 (9) — M(V)C_Jinja 语法基础快速概览
#目录 前文列表 扩展阅读 Jinja 变量名 注释 控制语句 if 语句 循环 过滤器 无参数调用 带参数调用 宏 定义宏 调用宏 结果 兼容 JavaScript 前文列表 用 Flask 来写个 ...
随机推荐
- JAVA的下载与安装和环境变量配置等详细教程
初学JAVA时,新手常常不知如何下载JAVA,也不知如何安装JAVA以及对JAVA配置环境变量.近期学弟学妹常请教我如何下载安装和配置JAVA,于是写下此博文以便更多新手快速入门,由于我本人是玩智能车 ...
- ASP.NET -- WebForm -- 缓存Cache的使用
ASP.NET -- WebForm -- 缓存Cache的使用 把数据从数据库或文件中读取出来,放在内存中,后面的用户直接从内存中取数据,速度快.适用于经常被查询.但不经常变动的数据. 1. Te ...
- LeetCode算法题-Ugly Number(Java实现-四种解法)
这是悦乐书的第199次更新,第208篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第64题(顺位题号是263).编写一个程序来检查给定的数字是否是一个丑陋的数字.丑陋的数 ...
- 牛客 小a与星际探索 bfs
链接:https://ac.nowcoder.com/acm/contest/317/C?&headNav=acm来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ ...
- 寒假特训——搜索——H - Nephren gives a riddle
What are you doing at the end of the world? Are you busy? Will you save us? Nephren is playing a gam ...
- SpringBoot实战之SpringBoot自动配置原理
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- Leetcode:234 回文链表
leetcode:234 回文链表 关键点:请判断一个链表是否为回文链表.示例 1:输入: 1->2输出: false示例 2:输入: 1->2->2->1输出: true. ...
- P2678 跳石头题解
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #i ...
- falcon常用参数解析
CPU.xxx cpu.idle cpu.idle表示除硬盘IO等待时间以外其它等待时间,这个值越大,表示cpu越空闲,还可以执行更多的任务,反之亦然,此处我们falcon展示的是idle的波动情况, ...
- Qt中使用Boost库
关于boost库的编译,请看https://www.cnblogs.com/HackerArt/p/10539516.html 网上可以查到很多介绍qt使用库文件的教程,但是大多都没有注意到,qt中支 ...