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) |