过滤器和监听器
文章目录
1. 过滤器
1.1 过滤器定义
//也可以通过注解配置filter:@WebFilter("/*"),拦截所有请求
public class EncodFilter implements Filter {
//初始化的方法,可以通过FilterConfig获得xml配置的参数
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
//过滤器处理业务的方法,完成业务处理之后一定要放行。
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//放行
filterChain.doFilter(req,resp);
}
//销毁filter时执行的方法
@Override
public void destroy() {}
}
1.2 过滤器配置
<filter>
<filter-name>encode</filter-name>
<filter-class>com.yogie.lesson.filter.EncodFilter</filter-class>
//配置参数
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>force</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
//配置过滤路径:所有请求都要经过encode过滤器
<url-pattern>/*</url-pattern>
</filter-mapping>
1.3 过滤器的生命周期
启动tomcat的时候开始,先创建FilterConfig,再调用init方法,filter是单例模式,只有一个对象。关闭tomcat服务器或者停止虚拟机运行的时候,过滤器调用destroy方法。
1.4 过滤器的应用
1、对字符进行编码。
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.yogie.lesson.filter.EncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>force</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
public class EncodingFilter implements Filter {
private String charset;
private Boolean force;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//读取配置文件中filter中的配置
charset = filterConfig.getInitParameter("charset");
//如果用户没有配置编码方式
if(charset==null || "".equals(charset)){
//设置一个默认的编码
charset = "UTF-8";
}
//Boolean.parseBoolean(null)的结果也为false
force = Boolean.parseBoolean(filterConfig.getInitParameter("force"));
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse)servletResponse;
//获取请求对象携带过来的编码方式
String ce = req.getCharacterEncoding();
if( ce==null || "".equals(ce) || force){
//如果request请求中没有设置编码方式,
//如果配置了强制使用配置中的编码方式
req.setCharacterEncoding(charset);
}
filterChain.doFilter(req,resp);
}
@Override
public void destroy() {
}
}
2、让浏览器不缓存。
3、屏蔽非法文字(敏感词过滤处理)。
- 关键字过滤器
@WebFilter("/*")
public class SensitiveFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//将servletRequest转换成HttpServletRequest对象
HttpServletRequest req = (HttpServletRequest)servletRequest;
//HttpServletRequest转换成MyHttpRequestWapper,
//在这个转换的过程中,请求对象所携带的文本信息中的敏感信息被过滤掉了
MyHttpRequestWapper requestWapper = new MyHttpRequestWapper(req);
//放行后,request对象已经是经过包装的request对象了
filterChain.doFilter(requestWapper, servletResponse);
}
@Override
public void destroy() {
}
}
- 请求对象的装饰类
public class MyHttpRequestWapper extends HttpServletRequestWrapper {
private HttpServletRequest req = null;
public MyHttpRequestWapper(HttpServletRequest request) {
//必须显示调用父类的构造方法,因为父类没有默认的无参构造方法
super(request);
//将HttpServletRequest对象赋值给字段
req = request;
}
@Override
public String getParameter(String name) {
//根据参数名获取请求对象中的对应的值
String value = req.getParameter(name);
return SensitiveUtil.filterWords(value,"*");
}
@Override
public Map<String, String[]> getParameterMap() {
//获取请求对象中的键值对map
Map<String, String[]> map = req.getParameterMap();
//准备一个返回的map
Map<String, String[]> result = new HashMap<>();
//取出其中所有的键值对集合
Set<Map.Entry<String, String[]>> entries = map.entrySet();
//遍历集合
for (Map.Entry<String, String[]> entry : entries) {
//key
String key = entry.getKey();
//value:有的字段可能对应多个值,例如select标签
String[] value = entry.getValue();
//设计一个与value一致长度的数组
String[] arr = new String[value.length];
//遍历这个vlaue数组,将数组中每个元素的字符串都进行敏感词过滤
for (int i = 0; i < value.length; i++) {
arr[i] = SensitiveUtil.filterWords(value[i],"*");
}
//将过滤后的值保存到map集合中
result.put(key,arr);
}
return result;
}
}
- 敏感词替换的工具类
public class SensitiveUtil {
private static List<String> keyWords = new ArrayList<>();
static{
Scanner sc = new Scanner(Thread.currentThread().getContextClassLoader().getResourceAsStream("sensitive.txt"),"UTF-8");
while (sc.hasNextLine()){
String line = sc.nextLine();
if(line!=null || !"".equals(line)){
keyWords.add(line);
}
}
sc.close();
}
/**
* 将str中的敏感词替换为指定字符拼接成的字符串
* @param str
* @param mask
* @return
*/
public static String filterWords(String str,String mask){
for (String keyWord : keyWords) {
if(str!=null && str.indexOf(keyWord) >= 0){
str = str.replaceAll(keyWord,buildMask(keyWord,mask));
}
}
return str;
}
/**
* 配置keyword长度的替代字符
* @param keyWord
* @param mask
* @return
*/
private static String buildMask(String keyWord, String mask) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keyWord.length(); i++) {
sb.append(mask);
}
return sb.toString();
}
}
4、登录权限验证。
- 登录权限的过滤器
public class LoginFilter implements Filter {
String[] strs = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//将配置中不用验证的资源放入strs数组中
strs = filterConfig.getInitParameter("outs").split(",");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//从session中获得key为username的对象
Object obj = req.getSession().getAttribute("NAME_IN_SESSION");
//获取到请求路径中的uri描述,并按照反斜杠分割
String[] split = req.getRequestURI().split("/");
//将配置中的路径放到list中
List<String> list = Arrays.asList(strs);
//如果配置的路径中不包含此次请求资源且session为空,不能放行
if(!list.contains(split[split.length-1]) && obj==null){
resp.sendRedirect("/xx/index.html");
return;
}
//放行
filterChain.doFilter(req,resp);
}
@Override
public void destroy() {
}
}
- 配置
<filter>
<filter-name>login</filter-name>
<filter-class>com.yogie.lesson.filter.LoginFilter</filter-class>
<init-param>
<param-name>outs</param-name>
<!--除了这两个资源,其他都要验证权限-->
<param-value>index.html,login</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>login</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 登录的servlet
@WebServlet("/login")
public class LoginServlet extends HttpServlet{
StudentDao dao = new StudentDaoImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Student stu = BeanUtil.getBean(req, Student.class);
Student stu1 = dao.queryByUsernameAndPassword(stu.getUsername(),stu.getPassword());
if(stu1!=null){
//登录成功,将用户名存入session
req.getSession().setAttribute("NAME_IN_SESSION",stu.getUsername());
//跳转到系统列表
resp.sendRedirect("/xx/controller?cmd=query");
}else{
//登录失败,返回登录页面
resp.sendRedirect("/xx/index.html");
}
}
}
5、请求分发器。
6、页面伪静态化处理。
2. 过滤器链
多个过滤器链形成的一组过滤器,然后我们在访问最终的资源的时候会经过这一组过滤器,在返回的时候还会经过这一组过滤器。过滤器链的执行顺序是按照filter-mapping的顺序执行的。
3. FilterConfig对象
String getFilterName(); 获取filter的名称(配置的name)。
ServletContext getServletContext(); 获得web项目的上下文对象。
String getInitParameter(String var1); 根据参数名获取filter配置中的init-param的value。
Enumeration<String> getInitParameterNames(); 获取所有参数配置的name。
4. 特殊的请求过滤
4.1 请求转发过滤
<filter-mapping>
<filter-name>a</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
4.2 重定向过滤
<filter-mapping>
<filter-name>b</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REDIRECT</dispatcher>
</filter-mapping>
4.3 默认情况
<filter-mapping>
<filter-name>b</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
5. 监听器
在web中,监听器的监听内容一般有:
1、监听四大作用的生命周期(主要是创建与销毁)。
2、监听作用域属性的变化(主要是增删改查)。
5.1 作用域监听器接口
ServletRequestListener -> 对request作用域监听器
HttpSessionListener -> 对session作用域监听器
ServletContextListener -> 对application作用域监听器
ServletRequestAttributeListener -> 对request作用域的属性监听器
HttpSessionAttibuteListener -> 对session作用域的属性监听器
ServletContextAttributeListener -> 对application作用域的属性监听器
需要创建哪一种监听器,就去实现对应的接口。
5.2 监听器的配置
<listener>
<listener-class>com.yogie.filter.MyFilter</listener-class>
</listener>