十一、Filter 过滤器
11.1 什么是Filter
访问某个servlet,可以先经过filter,再访问servlet,返回时也经过filter,画个图:
也就是在servlet之前加了一层过滤器。
有什么用呢?比如我们可以用它来处理中文乱码而不用在每个servlet中都加上这样一段代码:
req.setCharacterEncoding("utf8");
resp.setContentType("text/html;charset=utf8");
假如有这么一个servlet,直接输出那多半是中文乱码:
public class DealWithEncoding extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("解决乱码问题");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
解决方法:添加一个过滤器,用于设置编码。
怎么做呢?
-
导入依赖 <dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
-
实现Filter接口 注意!一定要是javax.servlet下的Filter import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf8");
servletResponse.setContentType("text/html;charset=utf8");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("过滤成功");
}
@Override
public void destroy() {
System.out.println("filter销毁");
}
}
-
注册过滤器,和注册servlet一毛一样,url-pattern表示访问哪个servlet时要经过过滤器 <filter>
<filter-name>test</filter-name>
<filter-class>vip.yangsf.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>test</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-
配置好后,当我们访问相应的servlet,就会解决乱码问题。
11.2 Filter权限拦截
现在有这么三个jsp页面,要实现,用户名为admin即可跳转到成功页面,不为admin则跳转到失败页面:
-
登录界面,名为login.jsp <%@ page contentType = "text/html;charset=UTF-8" language = "java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="/servlet/login" name="username" method="post">
用户名:<input type="text" name="user">
<br>
<input type="submit" value="登录">
</form>
</body>
</html>
-
登录成功页面,名为success.jsp <%@ page contentType = "text/html;charset=UTF-8" language = "java" %>
<html>
<head>
<title>秘密乐园</title>
</head>
<body>
vip用户页面
<a href="/servlet/logout">注销</a>
</body>
</html>
-
登录失败页面,名为failed.jsp <%@ page contentType = "text/html;charset=UTF-8" language = "java" %>
<html>
<head>
<title>失败</title>
</head>
<body>
<h1>
对不起,您没有权限
<br>
<a href="/servlet/logout">返回登录页面</a>
</h1>
</body>
</html>
通过代码我们也看出来了,我们写了一个servlet实现验证以及页面跳转,一个servlet实现注销,可以通过session验证:
public class CheckUser extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String user = req.getParameter("user");
if ("admin".equals(user)) {
req.getSession().setAttribute(Constant.USER_NAME, req.getSession().getId());
resp.sendRedirect("/sys/success.jsp");
} else {
resp.sendRedirect("/failed.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册servlet:
<servlet>
<servlet-name>login3</servlet-name>
<servlet-class>vip.yangsf.servlet.CheckUser</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login3</servlet-name>
<url-pattern>/servlet/login</url-pattern>
</servlet-mapping>
通过删除session的值注销(创建销毁session耗资源,删掉值就可以了):
public class LogOut extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String user = (String) req.getSession().getAttribute(Constant.USER_NAME);
if (user != null) {
req.getSession().removeAttribute(Constant.USER_NAME);
resp.sendRedirect("/Login.jsp");
} else {
resp.sendRedirect("/Login.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册servlet:
<servlet>
<servlet-name>LogOut</servlet-name>
<servlet-class>vip.yangsf.servlet.LogOut</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogOut</servlet-name>
<url-pattern>/servlet/logout</url-pattern>
</servlet-mapping>
这样确实可以实现功能,但是,会有安全问题,比如我们直接访问localhost:8080/sys/success.jsp也能访问到登录成功页面,怎么办呢?
可以通过filter过滤掉这些请求:
public class LoginIndex implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("开启权限检测");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String user = (String) request.getSession().getAttribute(Constant.USER_NAME);
if (request.getSession().getAttribute(Constant.USER_NAME) == null) {
response.sendRedirect("/failed.jsp");
}
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("服务已关闭");
}
}
注册filter:
<filter>
<filter-name>check</filter-name>
<filter-class>vip.yangsf.filter.LoginIndex</filter-class>
</filter>
<filter-mapping>
<filter-name>check</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>
访问sys目录下的文件就要经过这个filter
于是我们就用filter实现了权限拦截。
十二、Listener 监听器
用于监听一些事件,比如我们可以通过监听session的创建和销毁来统计在线人数,直接开干:
-
实现一个监听器接口(我们监听session就实现javax.servlet.http下的HttpSessionListener接口) import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class SessionListened implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
}
}
-
监听session的创建和销毁,设置、获取上下文属性。 import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class SessionListened implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
ServletContext context = httpSessionEvent.getSession().getServletContext();
System.out.println(httpSessionEvent.getSession().getId());
Integer onlineCount = (Integer) context.getAttribute("onlineCount");
if (onlineCount == null) {
onlineCount = 1;
} else {
onlineCount++;
}
context.setAttribute("onlineCount", onlineCount);
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
ServletContext context = httpSessionEvent.getSession().getServletContext();
httpSessionEvent.getSession().invalidate();
Integer onlineCount = (Integer) context.getAttribute("onlineCount");
if (onlineCount ==null) {
onlineCount = 0;
} else {
onlineCount--;
}
context.setAttribute("onlineCount", onlineCount);
}
}
-
编写jsp页面 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>在线人数</title>
</head>
<body>
<h1>
当前在线人数:<span><%=this.getServletConfig().getServletContext().getAttribute("onlineCount")%></span>
</h1>
</body>
</html>
-
注册监听器 <listener>
<listener-class>vip.yangsf.listener.SessionListened</listener-class>
</listener>
-
这样,我们就实现了统计在线人数的功能。
|