🍵 Servlet简称Server Applet(即服务器端小程序),是一种基于Java技术的Web组件,运行在服务器端。
1 Cookie会话
- Cookie会话
- HTTP(即超文本传输协议)是一个基于请求与响应模式的无状态协议。
- 用户通过浏览器访问Web应用时,服务器需要保存并跟踪用户的状态。
- HTTP协议无状态,无法保存和跟踪用户状态,采用会话技术来解决。
- 从用户打开浏览器访问某个网站到关闭浏览器的过程,称为一次会话。
- 会话技术指的是在会话过程中帮助服务器记录用户状态和数据的技术。
- 常用的会话技术:Cookie客户端会话技术、Session服务器端会话技术。
- Cookie是服务器发送给浏览器的小段文本信息,存储在客户端浏览器内存或硬盘上。
- 浏览器保存Cookie之后,每次访问服务器,都会在HTTP请求头中将其回传给服务器。
- 分类
- 持久的Cookie:Cookie会以文本文件的形式保存到用户的硬盘上。
- 会话级别Cookie(默认):保存到浏览器内存,浏览器关闭则失效。
- 访问
1-1 访问时间类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| import java.util.Date; import java.io.IOException; import java.net.URLDecoder; import java.net.URLEncoder; import javax.servlet.http.Cookie; import java.text.SimpleDateFormat; import javax.servlet.http.HttpServlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyServlet37") public class MyServlet37 extends HttpServlet { private static final long serialVersionUID = -5604481158386227221L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8"); Cookie[] cookies = request.getCookies(); Cookie cookie = getCookieByName(cookies, "lastTime"); if (cookie == null) { response.getWriter().write( "<div style='text-align: center;'>" + "<div style='display: inline-block; text-align: left;'>" + "www.baidu.com" + "<br />" + "欢迎访问百度一下!" + "</div>" + "</div>" ); } else { String value = cookie.getValue(); response.getWriter().write( "<div style='text-align: center;'>" + "<div style='display: inline-block; text-align: left;'>" + "www.baidu.com" + "<br />" + "百度欢迎您的归来!<br />您上次的访问时间:" + URLDecoder.decode(value, "UTF-8") + "<br />" + "<a href=\"/servletDemo/MyServlet38\">清除Cookie</a>" + "</div>" + "</div>" ); } Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String sDate = sdf.format(date); Cookie c = new Cookie("lastTime", URLEncoder.encode(sDate, "UTF-8")); c.setMaxAge(60 * 60 * 24); c.setPath("/servletDemo"); response.addCookie(c); }
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }
public static Cookie getCookieByName(Cookie[] cookies, String name) { if (cookies == null) { return null; } else { for (Cookie cookie : cookies) { if (cookie.getName().equals(name)) { return cookie; } } return null; } } }
|
1-2 移除会话类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import java.io.IOException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyServlet38") public class MyServlet38 extends HttpServlet { private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Cookie cookie = new Cookie("lastTime", ""); cookie.setMaxAge(0); cookie.setPath("/servletDemo"); response.addCookie(cookie); response.sendRedirect("/servletDemo/MyServlet37"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
2 Session会话
- Session会话
- 服务器端会话,浏览器访问Web服务器资源时,服务器为每个用户浏览器创建一个Session对象。
- 每个浏览器独占一个Session对象,用户访问服务器资源时,可以将数据保存在各自的Session中。
- Session vs Cookie
- Session不支持跨域名访问,Cookie支持跨域名访问。
- Session存放的数据类型是对象,Cookie存放的数据类型则是字符串。
- Session数据存在服务器端,安全性高,Cookie明文传递,安全性低。
- Session每个用户独占一个,占用资源,Cookie在客户端,不占资源。
- Session将数据存储在服务器端,Cookie存放在客户端浏览器内存或硬盘上。
- Session的大小和数量一般不受限制,浏览器对Cookie的大小和数量有限制。
- 生命周期
- Session对象在容器中第一次调用request.getSession()方法时创建。
- 客户端访问的Web资源是静态资源时,服务器不会创建Session对象。
- 对象被销毁的三种情况
- Session过期。
- 调用session.invalidate()方法,手动销毁。
- 服务器关闭或应用在服务器中部署被卸载。
2-1 设置过期时间
- 设置过期时间
- Session对象在服务器中驻留一段时间后未被使用,就会被销毁,这个时间即过期时间。
- 默认过期时间是30分钟,可通过使用
<session-config>或调用方法两种方式进行设置。
(1) <session-config>元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" metadata-complete="false" version="4.0"> <display-name>servletDemo</display-name>
<session-config> <session-timeout>10</session-timeout> </session-config> </web-app>
|
(2) setMaxInactiveInterval()
1 2
| request.getSession().setMaxInactiveInterval(60);
|
2-2 Session域对象
- Session域对象
- Session也是域对象,可对属性进行操作,实现会话中请求之间的数据通讯和数据共享。
- Session、Request、ServletContext合称为Servlet的三大域对象,都能保存和传递数据。
| 不同 |
Session |
Request |
ServletContext |
| 类型 |
HttpSession |
HttpServletRequest |
ServletContext |
| 数量 |
多个Session |
多个Request对象 |
唯一Context对象 |
| 创建 |
容器第一次调用getSession()时创建 |
客户端向容器发送请求时创建 |
Servlet容器启动时创建 |
| 销毁 |
过期、手动调用invalidate()、关闭服务器 |
容器对这次请求做出响应之后 |
容器关闭或应用被移除时 |
| 数据共享 |
会话内多请求共享 |
请求内组件共享 |
跨会话共享 |
| 有效范围 |
会话期间的所有Servlet |
当前请求相关的Servlet |
整个应用内的所有Servlet |
2-3 创建访问时间类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import java.util.Date; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyServlet39") public class MyServlet39 extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); writer.write( "<div style='text-align: center;'>" + "<div style='display: inline-block; text-align: left;'>" + "https://www.baidu.com/" + "<br />" + "百度一下,欢迎您的到来!" ); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date CreationTime = new Date(request.getSession().getCreationTime()); Date LastAccessedTime = new Date(request.getSession().getLastAccessedTime()); String sDate = sdf.format(date); request.getSession().setAttribute("lastTime", sDate); request.getSession().setMaxInactiveInterval(100); writer.write( "当前时间:" + sDate + "<br />" + "创建此会话的时间:" + sdf.format(CreationTime) + "<br />" + "当前会话的SessionID: " + request.getSession().getId() + "<br />" + "Sesssion上次关联的时间:" + sdf.format(LastAccessedTime) + "<br />" + "会话保持打开状态的最大时间间隔:" + request.getSession().getMaxInactiveInterval() + "<br />" + "</div>" + "</div>" ); String url = response.encodeURL("/servletDemo/MyServlet40"); writer.write("<center><a href=" + url + ">再次访问!</a></center>"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
2-4 创建再次访问类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import java.util.Date; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyServlet40") public class MyServlet40 extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); String value = (String) request.getSession().getAttribute("lastTime"); writer.write( "<div style='text-align: center;'>" + "<div style='display: inline-block; text-align: left;'>" + "https://www.baidu.com/" + "<br />" + "百度一下,欢迎您的归来!" + "<br />" + "您上次的访问时间是" + value + "</div>" + "</div>" ); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String sDate = sdf.format(date); request.getSession().setAttribute("lastTime", sDate); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
3 Filter过滤器
- Filter过滤器
- Filter过滤器在Servlet版本2.3中新定义,支持对对象进行检查修改。
- 是Servlet规范中最实用的技术,通过拦截从而实现一些特殊的功能。
- 生命周期
- 初始化阶段:调用init()方法初始化Filter实例,init()方法在生命周期内只执行一次。
- 拦截和过滤阶段:容器将对象以参数形式传递给doFilter(),调用方法进行拦截和过滤。
- 销毁阶段:调用destory()释放过滤器占用的资源,destory()在生命周期内只执行一次。
- 过滤器拦截资源被容器调用的方式
- FORWARD:目标资源通过RequestDispatcher的forward()方法访问,过滤器将被调用。
- INCLUDE:目标资源通过RequestDispatcher的include()方法访问,该过滤器将被调用。
- ERROR:目标资源通过声明式异常处理机制访问,该过滤器将被调用,除此之外不被调用。
- REQUEST:目标资源通过RequestDispatcher的include()或forward()访问,过滤器不被调用。
3-1 web.xml配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" metadata-complete="false" version="4.0"> <display-name>servletDemo</display-name>
<filter> <filter-name>MyServlet41</filter-name> <filter-class>MyServlet41</filter-class> <init-param> <param-name>name</param-name> <param-value>百度一下</param-value> </init-param> <init-param> <param-name>URL</param-name> <param-value>https://www.baidu.com/</param-value> </init-param> </filter> <filter-mapping> <filter-name>MyServlet41</filter-name> <url-pattern>/MyServlet41</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping> <filter-mapping> <filter-name>MyServlet41</filter-name> <servlet-name>ServletDemo</servlet-name> </filter-mapping> </web-app>
|
3-2 @WebFilter配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.DispatcherType; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletException; import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebInitParam;
@WebFilter( dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ERROR }, asyncSupported = true, description = "过滤器Filter", urlPatterns = { "/MyServlet41" }, initParams = { @WebInitParam(name = "name", value = "百度一下", description = "name的描述") }, servletNames = { "servletDemo" } ) public class MyServlet41 implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { } }
|
3-3 创建一个过滤器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.DispatcherType; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletException; import javax.servlet.annotation.WebFilter;
@WebFilter( dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ERROR }, urlPatterns = { "/MyServlet42" } ) public class MyServlet42 implements Filter { public void destroy() { }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("<center>欢迎访问【MyServlet42】页面!</center>"); }
public void init(FilterConfig fConfig) throws ServletException { } }
|
3-4 创建过滤器拦截类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import java.io.IOException; import javax.servlet.http.HttpServlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyServlet43") public class MyServlet43 extends HttpServlet { private static final long serialVersionUID = 1L;
public MyServlet43() { super(); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("<center>欢迎访问【MyServlet43】页面!</center>"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
4 FilterChain
- FilterChain
- 在Web应用中可以部署多个Filter,如果这些Filter都拦截同一目标资源,那么就组成一个过滤器链。
- 过滤器链中的过滤器负责特定的操作和任务,客户端的请求在它们之间传递,直到传递给目标资源。
- javax.servlet包中提供了一个FilterChain接口,该接口由容器实现。
- 使用FilterChain对象调用过滤器链中的下一个Filter的doFilter()方法。
- 如果Filter是链中的最后一个过滤器,则调用目标资源的service()方法。
- 过滤器链中Filter的执行顺序
- web.xml配置的Filter,执行顺序由
<filter-mapping>决定,靠前先执行。
- @WebFilter注解配置的Filter,无法进行排序,需排序建议使用web.xml。
4-1 web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" metadata-complete="false" version="4.0"> <display-name>servletDemo</display-name>
<filter> <filter-name>FirstChainFilter</filter-name> <filter-class>MyServlet45</filter-class> </filter> <filter-mapping> <filter-name>FirstChainFilter</filter-name> <url-pattern>/MyServlet44</url-pattern> </filter-mapping> <filter> <filter-name>SecondChainFilter</filter-name> <filter-class>MyServlet46</filter-class> </filter> <filter-mapping> <filter-name>SecondChainFilter</filter-name> <url-pattern>/MyServlet44</url-pattern> </filter-mapping> </web-app>
|
4-2 创建登录类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyServlet44") public class MyServlet44 extends HttpServlet { private static final long serialVersionUID = 1L;
public MyServlet44() { super(); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("<center>欢迎访问【MyServlet44】页面!</center>"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
4-3 FirstChainFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletException;
public class MyServlet45 implements Filter { public MyServlet45() { }
public void destroy() { }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); writer.write("<div style='width: fit-content; margin: 0 auto; text-align: left;'>"); writer.write("FirstChainFilter 对请求进行处理!<br />"); chain.doFilter(request, response); writer.write("FirstChainFilter 对响应进行处理!<br />"); writer.write("</div>"); }
public void init(FilterConfig fConfig) throws ServletException { } }
|
4-4 SecondChainFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletException;
public class MyServlet46 implements Filter { public MyServlet46() { }
public void destroy() { }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); writer.write("<div style='width: fit-content; margin: 0 auto; text-align: left;'>"); writer.write("SecondChainFilter 对请求进行处理!<br />"); chain.doFilter(request, response); writer.write("SecondChainFilter 对响应进行处理!<br />"); writer.write("</div>"); }
public void init(FilterConfig fConfig) throws ServletException { } }
|
5 FilterConfig
5-1 web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" metadata-complete="false" version="4.0"> <display-name>servletDemo</display-name>
<filter> <filter-name>BlackListFilter</filter-name> <filter-class>MyServlet47</filter-class> <init-param> <param-name>blackList1</param-name> <param-value>admin</param-value> </init-param> <init-param> <param-name>blackList2</param-name> <param-value>root</param-value> </init-param> <init-param> <param-name>blackList3</param-name> <param-value>user</param-value> </init-param> </filter> <filter-mapping> <filter-name>BlackListFilter</filter-name> <url-pattern>/logon</url-pattern> </filter-mapping> </web-app>
|
5-2 黑名单类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import java.io.IOException; import javax.servlet.Filter; import java.util.Enumeration; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletException;
public class MyServlet47 implements Filter { private FilterConfig fConfig;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); Boolean successde = true; String name = request.getParameter("username"); Enumeration<String> blackListNames = fConfig.getInitParameterNames(); if (name == null || "".equals(name)) { response.getWriter().write("<center>用户名不能为空!</center>"); } else { while (blackListNames.hasMoreElements()) { if (fConfig.getInitParameter(blackListNames.nextElement()).equals(name)) { successde = false; } } if (successde) { chain.doFilter(request, response); } else { response.getWriter().write( "<h1 align=\"center\" style=\"font-family:arial;color:red;\">" + "温馨提示:您的账号存在风险,暂时不能为您提供服务!</h1>\n" ); } } }
public void init(FilterConfig fConfig) throws ServletException { this.fConfig = fConfig; } }
|
5-3 用户登录类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/logon") public class MyServlet48 extends HttpServlet { private static final long serialVersionUID = 1L;
public MyServlet48() { super(); }
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("<h1 align=\"center\">百度百科 欢迎您!</h1>"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
5-4 logon.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <!DOCTYPE html> <html>
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>FilterConfig</title> </head>
<body> <form action="/servletDemo/logon" method="GET" style="text-align:center;"> <table border="1" width="50%" style="margin: 0 auto;"> <tr> <td colspan="2" align="center"> FilterConfig </td> </tr> <tr> <td>用户</td> <td> <input type="text" name="username" /> </td> </tr> <tr> <td>密码</td> <td> <input type="password" name="password" /> </td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="提交" /> </td> </tr> </table> </form> </body>
</html>
|
6 Servlet监听器
- Servlet监听器
- Listener是一个实现特定接口的Java程序,用于监听另一Java对象的方法调用或属性改变。
- Servlet规范定义了8个监听器接口,开发监听器需实现相应的监听器接口并重写接口方法。
- 监听对象的创建和销毁:ServletContextListener、HttpSessionListener、ServletRequestListener。
- 监听对象中的属性变更
- HttpSessionAttributeListener。
- ServletContextAttributeListener。
- ServletRequestAttributeListener。
- 监听HttpSession的对象状态改变:HttpSessionBindingListener、HttpSessionActivationListener。
- 用HttpSessionBindingListener、HttpSessionActivationListener时不必注册,直接创建类实现接口。
6-1 web.xml注册监听器
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" metadata-complete="false" version="4.0"> <display-name>servletDemo</display-name>
<listener> <listener-class>MyServlet49</listener-class> </listener> </web-app>
|
6-2 @WebListener注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import java.io.InputStream; import java.util.Properties; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener;
@WebListener public class MyServlet49 implements ServletContextListener { public MyServlet49() { }
public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); System.out.println("应用启动,开始加载配置...");
try (InputStream in = context.getResourceAsStream("/WEB-INF/classes/db.properties")) { Properties properties = new Properties(); if (in != null) { properties.load(in); context.setAttribute("config", properties); System.out.println("配置文件加载完成:" + properties); } else { System.out.println("配置文件并未找到!"); } } catch (Exception e) { e.printStackTrace(); } }
public void contextDestroyed(ServletContextEvent sce) { System.out.println("应用关闭,准备释放资源..."); ServletContext context = sce.getServletContext();
context.removeAttribute("config");
System.out.println("资源释放完毕,应用关闭完成。"); } }
|
6-3 创建Servlet读取属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import java.io.IOException; import java.io.PrintWriter; import java.util.Properties; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyServlet50") public class MyServlet50 extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Properties config = (Properties) getServletContext().getAttribute("config");
response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter();
out.println("<html><head><title>Servlet监听器</title></head><body>"); out.println("<center><h1>应用配置信息获取</h1></center>");
if (config != null) { out.println("<div style='text-align:center;'>"); out.println("<ul style='display:inline-block; text-align:left; list-style:none; padding:0;'>"); for (String key : config.stringPropertyNames()) { out.printf("<li>%s = %s</li>", key, config.getProperty(key)); } out.println("</ul>"); out.println("</div>"); } else { out.println("<center><p>未加载到配置信息。</p></center>"); }
out.println("</body></html>"); out.close(); } }
|
7 结合实现网站在线人数统计
7-1 登录类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpSession; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpServletResponse;
@WebServlet("/LoginServlet1") public class MyServlet51 extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("utf-8"); PrintWriter writer = response.getWriter();
String username = request.getParameter("username"); if (username == null || "".equals(username)) { response.sendRedirect("/servletDemo/WebContent/enroll1.html"); return; }
HttpSession session = request.getSession(); String sessionUser = (String) session.getAttribute("username");
ConcurrentHashMap<String, String> map = (ConcurrentHashMap<String, String>) getServletContext().getAttribute("onLineUserMap"); if (map == null) { map = new ConcurrentHashMap<>(); getServletContext().setAttribute("onLineUserMap", map); } String sessionId = session.getId(); String existSid = map.get(username);
writer.write("<html><head><title>登录页面</title></head><body style='text-align:center;'>");
if (sessionUser != null && !"".equals(sessionUser)) { writer.write("<h3>您好,您已经登录了账户:" + sessionUser + "</h3>"); writer.write("<p>如要登录其他账号,请先退出当前账号重新登录!</p>"); } else if (existSid != null && !sessionId.equals(existSid)) { writer.write("<h3>账号[" + username + "]已在其他浏览器登录,请先在其他地方退出!</h3>"); writer.write("<a href=\"/servletDemo/WebContent/enroll1.html\">返回登录!</a>"); writer.write("</body></html>"); return; } else { session.setAttribute("username", username); writer.write("<h3>" + username + ",欢迎您的到来</h3>"); }
writer.write("<h3>当前在线人数为:" + map.size() + "人</h3><table border=\"1\" width=\"50%\" align=\"center\">"); for (String user : map.keySet()) { writer.write("<tr><td align=\"center\">" + user + "</td></tr>"); } writer.write("</table>"); writer.write("<br/><a href=\"/servletDemo/LogoutServlet1\">退出登录!</a>"); writer.write("</body></html>"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
7-2 登出类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/LogoutServlet1") public class MyServlet52 extends HttpServlet { private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getSession().invalidate(); response.sendRedirect("/servletDemo/WebContent/enroll1.html"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
7-3 监听器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionListener; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionAttributeListener;
@WebListener public class MyServlet53 implements HttpSessionListener, HttpSessionAttributeListener { @SuppressWarnings("unchecked") @Override public void attributeAdded(HttpSessionBindingEvent se) { if ("username".equals(se.getName())) { ServletContext application = se.getSession().getServletContext(); ConcurrentHashMap<String, String> map = (ConcurrentHashMap<String, String>) application.getAttribute("onLineUserMap"); if (map == null) { map = new ConcurrentHashMap<>(); application.setAttribute("onLineUserMap", map); } String username = (String) se.getValue(); String sid = se.getSession().getId(); map.put(username, sid); } }
@SuppressWarnings("unchecked") @Override public void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); ServletContext application = session.getServletContext(); ConcurrentHashMap<String, String> map = (ConcurrentHashMap<String, String>) application.getAttribute("onLineUserMap"); if (map == null) return; String username = (String) session.getAttribute("username"); if (username != null) { String nowSid = map.get(username); if (session.getId().equals(nowSid)) { map.remove(username); } } }
@Override public void attributeRemoved(HttpSessionBindingEvent se) { }
@Override public void attributeReplaced(HttpSessionBindingEvent se) { }
@Override public void sessionCreated(HttpSessionEvent se) { } }
|
7-4 enroll1.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <!DOCTYPE html> <html>
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>结合实现网站在线人数统计</title> </head>
<body> <form action="/servletDemo/LoginServlet1" method="GET" style="text-align:center;"> <table border="1" width="50%" style="margin: 0 auto;"> <tr> <td colspan="2" align="center">结合实现网站在线人数统计</td> </tr> <tr> <td>账号</td> <td><input type="text" name="username" /></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="提交" /> </td> </tr> </table> </form> </body>
</html>
|
8 HttpSessionBindingListener
- HttpSessionBindingListener
8-1 登录类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| import java.util.Set; import java.util.HashSet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpSession; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/LoginServlet2") public class MyServlet54 extends HttpServlet { private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked") protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("utf-8"); PrintWriter writer = response.getWriter(); String username = request.getParameter("username"); if (username == null || "".equals(username)) { response.sendRedirect("/servletDemo/WebContent/enroll2.html"); return; }
Set<String> onlineUserSet = (Set<String>) getServletContext().getAttribute("onlineUserSet"); if (onlineUserSet == null) { onlineUserSet = new HashSet<>(); getServletContext().setAttribute("onlineUserSet", onlineUserSet); }
HttpSession session = request.getSession(); MyServlet56 loginedDemo = (MyServlet56) session.getAttribute("onlineUserBindingListener");
if (loginedDemo == null) { synchronized (onlineUserSet) { if (onlineUserSet.contains(username)) { writer.write("<center><h3>用户[" + username + "]已经登录!不能重复登录!</h3></center>"); writer.write("<center>如要重新登录,请先退出其他会话!</center><br/>"); writer.write("<center><a href=\"/servletDemo/LogoutServlet2\">退出登录!</a></center>"); return; } onlineUserSet.add(username); session.setAttribute("onlineUserBindingListener", new MyServlet56(username)); writer.write("<center>" + username + ",欢迎您的到来!</center>"); } } else { String logined = loginedDemo.getUsername(); writer.write( "<center><h3>您好,您已经登录了账户:" + logined + "</h3></center>" + "<center>如要登录其他账号,请先退出当前账号!</center>" ); }
writer.write("<div style=\"width:50%; margin: 0 auto; text-align: center;\">"); writer.write("<h1>当前在线人数为:" + onlineUserSet.size() + "</h1>"); writer.write("<table border=\"1\" width=\"100%\" style=\"margin: 0 auto;\">"); for (String user : onlineUserSet) { writer.write("<tr><td align=\"center\">" + user + "</td></tr>"); } writer.write("</table>"); writer.write("<br/><a href=\"/servletDemo/LogoutServlet2\">退出登录!</a>"); writer.write("</div>"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
8-2 登出类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import java.util.Set; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpSession; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet("/LogoutServlet2") public class MyServlet55 extends HttpServlet { private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked") protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(false); if (session != null) { MyServlet56 user = (MyServlet56) session.getAttribute("onlineUserBindingListener"); if (user != null) { String username = user.getUsername(); Set<String> onlineUserSet = (Set<String>) getServletContext().getAttribute("onlineUserSet"); if (onlineUserSet != null) { synchronized (onlineUserSet) { onlineUserSet.remove(username); } } session.removeAttribute("onlineUserBindingListener"); } session.invalidate(); } response.sendRedirect("/servletDemo/WebContent/enroll2.html"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
8-3 监听器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import java.util.List; import java.util.ArrayList; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener;
public class MyServlet56 implements HttpSessionBindingListener { private String username;
public MyServlet56(String username) { super(); this.username = username; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public MyServlet56() { }
@SuppressWarnings("unchecked") public void valueBound(HttpSessionBindingEvent event) { HttpSession session = event.getSession(); ServletContext application = session.getServletContext(); List<String> onlineUserList = (List<String>) application.getAttribute("onlineUserList"); if (onlineUserList == null) { onlineUserList = new ArrayList<String>(); } onlineUserList.add(this.username); application.setAttribute("onlineUserList", onlineUserList); System.out.println("***用户:" + this.username + ",已成功加入在线用户列表!"); }
@SuppressWarnings("unchecked") public void valueUnbound(HttpSessionBindingEvent event) { HttpSession session = event.getSession(); ServletContext application = session.getServletContext(); List<String> onlineUserList = (List<String>) application.getAttribute("onlineUserList"); onlineUserList.remove(this.getUsername()); application.setAttribute("onlineUserList", onlineUserList); System.out.println("用户[" + this.username + "]退出。"); System.out.println("当前在线人数:" + onlineUserList.size() + "人"); } }
|
8-4 enroll2.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <!DOCTYPE html> <html>
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>HttpSessionBindingListener</title> </head>
<body> <form action="/servletDemo/LoginServlet2" method="GET" style="text-align:center;"> <table border="1" width="50%" style="margin: 0 auto;"> <tr> <td colspan="2" align="center">HttpSessionBindingListener</td> </tr> <tr> <td>账号</td> <td><input type="text" name="username" /></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="提交" /> </td> </tr> </table> </form> </body>
</html>
|