发表于: 2018-03-07 23:05:27
1 523
今天完成的事情:
今天学习了拦截器、过滤器和监听器的一些知识,并实现了拦截器、过滤器的程序的Demo,监听器暂时还没有实现。
1、拦截器:
SpringMVC中实现Interceptor拦截请求是通过拦截器接口(HandlerInterceptor)来实现的。HandlerInterceptor有三个回调方法,preHandle在controller处理之前执行,postHandle在渲染之前执行,afterCompletion在渲染完毕之后执行。如果只需要实现三个回调方法中的某一个,Spring提供了HandlerInterceptorAdapter(拦截器适配器),允许我们只使用需要的回调方法。
之前做任务时,应用拦截器方法记录用户的登陆状态。拦截器类的代码如下:
public class Interceptor implements HandlerInterceptor {
@Autowired
private StudentService studentService;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
boolean checkResult = studentService.checkCookie(request,response);
if (checkResult == true) {
return true;
}else {
response.sendRedirect("/Task1-3/loginPage");
return false;
}
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
代码中的postHandle方法和afterCompletion方法都没有执行任何语句,但是不可或缺,要实现HandlerInterceptor接口,必须实现这三个方法。如果注释掉下边的两个方法,程序会报错。
如果现实中不需要这三个方法全部实现,那可以用HandlerInterceptorAdapter适配器。我做的demo如下:
public class testHandlerInterceptorAdapter extends HandlerInterceptorAdapter {
//此处所以三个回调方法都是空实现,preHandle返回true。
@Autowired
private StudentService studentService;
/**
* preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,SpringMVC中的Interceptor拦截器是链式的,可以同时存在
* 多个Interceptor,然后SpringMVC会根据声明的前后顺序一个接一个的执行,而且所有的Interceptor中的preHandle方法都会在
* Controller方法调用之前调用。SpringMVC的这种Interceptor链式结构也是可以进行中断的,这种中断方式是令preHandle的返
* 回值为false,当preHandle的返回值为false的时候整个请求就结束了。
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
boolean checkResult = studentService.checkCookie(request,response);
if (checkResult == true) {
return true;
}else {
response.sendRedirect("/Task1-3/loginPage");
return false;
}
}
}
我只使用了preHandle方法,其他两个方法不需要定义。
HandlerInterceptorAdapter和HandlerInterceptor两种方法在SpringMVC.xml中的配置没有本质差别。
2、过滤器:
过滤器(Filter)是Servlet技术中最激动人心的技术之一,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp,Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
是否调用目标资源(即是否让用户访问web资源)。
调用目标资源之前或者之后,让一段代码执行。
web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。
根据网上资料做的一个小demo:
一个用来在网页上过滤特定词汇的过滤器:
过滤器类:
public class WordsFilter implements Filter {
private List<String> banWords = new ArrayList<String>(); // 禁用词
private List<String> auditWords = new ArrayList<String>(); // 审核词
private List<String> replaceWords = new ArrayList<String>(); // 替换词
// WordsFilter过滤器只要一装载,WordsFilter对象只要一创建出来,init方法就会执行,init方法一执行,就会往List集合里面装东西。
/*
* 首先要将敏感词库读到系统里面去,而且敏感词库只要读一遍就行了。
* 我们可以在静态代码块里面做,但是我们还有一种方法,可以在init方法里面做,
* 因为filter对象只会创建一次,init方法也只会执行一次。
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
try {
String path = WordsFilter.class.getClassLoader().getResource("dirtyWords").getPath();
File[] files = new File(path).listFiles();
for (File file : files) {
if (!file.getName().endsWith(".txt")) {
continue;
}
BufferedReader br = new BufferedReader(new FileReader(file));
String line = null;
while ((line=br.readLine()) != null) {
String[] s = line.split("\\|");
if (s.length != 2) {
continue;
}
if (s[1].trim().equals("1")) {
banWords.add(s[0].trim());
}
if (s[1].trim().equals("2")) {
auditWords.add(s[0].trim());
}
if (s[1].trim().equals("3")) {
replaceWords.add(s[0].trim());
}
}
}
System.out.println("脏话过滤器启动。。。。。。。。。。。"); // 作断点调试用
System.out.println("banWord="+banWords);// 列出所有禁用词
System.out.println("replaceWords"+replaceWords);//列出所有替换词
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// 检查提交数据是否包含禁用词
/*
* 此刻是不知道客户机要提交过来的数据的,也即不知道客户机会以什么名称提交数据过来,
* 所以应得到客户机提交的所有数据,然后挨个检查,怎么得到客户机提交的所有数据呢?
* 可得到客户机提交的所有数据的名称,然后挨个取出来检查即可。
*/
Enumeration<String> e = request.getParameterNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
String data = request.getParameter(name);
for (String regex : banWords) {
Pattern pattern = Pattern.compile(regex); // 编译regex这个正则表达式,得到代表此正则表达式的对象
Matcher m = pattern.matcher(data); // 看data数据里面有没有和该正则表达式相匹配的内容
if (m.find()) { // 匹配器的find方法若返回true,则客户机提交的数据里面有和正则表达式相匹配的内容
request.setAttribute("message", "文章中包含非法词汇,请检查后再提交!!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("filter被destroy");
}
}
在web.xml中注册这个过滤器:
<!--脏话过滤器-->
<filter>
<filter-name>WordsFilter</filter-name>
<filter-class>com.byou.util.WordsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>WordsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
标记禁用词语,将词语写到resources文件夹下的一个txt文件中,在词语后写一个|标记和一个数字,表示禁用类型,1表示禁止,2表示审查,3表示替换。这里这标记了禁止。
然后当网页上传一个包含禁用词汇时,操作将不会得到执行,而是发生一个网页的跳转,提示输入禁用词,需要重新输入。
但是这里遇到一个问题,就是当输入禁用词的时候,网页跳转有问题,无法跳转到需要的页面。至少说明过滤器的功能达到了。明天针对这个再改改。
明天计划的事情:
继续学习监听器。
遇到的问题:
过滤器过滤到非法字段时,跳转页面失败。报错信息是无法找到网页。暂时没有解决。
收获:
学习自己写拦截器和过滤器,感觉很好。
评论