文章目录
- 06【Filter】
- 一、过滤器简介
- 1.1 Filter概述
- 1.2 Filter的使用
- 1.2.1 Filter快速体验
- 1.2.2 XML配置Filter
- 1.2.3 Filter的拦截规则
- 1.3 Filter的生命周期
- 1.3.1 Filter生命周期介绍
- 1.3.2 Filter生命周期相关方法
- 1.3.3 FilterConfig类
- 1.4 Filter的拦截方式
- 1.4.1 REQUEST
- 1.4.2 FORWARD
- 1.4.3 INCLUDE
- 1.4.4 ERROR
- 1.4.5 ASYNC
- 1.5 过滤器的拦截类型小结
- 1.6 Filter小案例
- 二、过滤器链
- 2.1 过滤器链概念
- 2.2 过滤器链案例
- 2.3 过滤器链的执行顺序
- 2.3.1 注解方式
- 2.3.2 xml配置方式
- 三、过滤器综合案例
- 3.1 完成案例功能
- 3.1.1 搭建项目
- 1)执行SQL语句:
- 2)拷贝静态资源
- 3)拷贝jar包
- 4)jdbc.properties:
- 5)DataSourceUtils:
- 6)实体类:
- 3.1.2 登录业务
- 1)修改前端页面
- 2)LoginServlet
- 3)UserService
- 4)UserDao
- 3.1.3 文章列表
- 1)业务分析
- 2)ListServlet:
- 3)ArticleService
- 4)ArticleDao
- 5)list.jsp页面
- 3.1.4 文章添加
- 1)add.jsp页面
- 2)AddServlet:
- 3)ArticleService
- 4)ArticleDao
- 3.2 使用过滤器完成权限校验
- 3.2.1 分析需求
- 3.2.3 编写LoginFilter拦截器
- 3.3 使用过虑器完成特殊字符过滤
- 3.3.1 过滤字符表
- 3.3.2 字符过滤器
06【Filter】
一、过滤器简介
1.1 Filter概述
- Filter:也称之为过滤器,Filter可以在请求执行WEB资源之前或之后执行,他是一段可重用的代码,这就意味着一个Filter可以管理多个web资源;WEB开发人员通过Filter技术对WEB资源进行一些管理,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
过滤器可以作用于动态或静态内容
- Filter的执行流程:
从上图可以看出,在过滤器是在请求到达真实WEB资源之前执行的,因此我们可以在过滤器中做一些统一处理的操作,或者过滤掉一些请求;
1.2 Filter的使用
1.2.1 Filter快速体验
- 定义一个Servlet:
package com.dfbz.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("demo01Servlet....");}
}
- 定义Filter:
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebFilter("/*") // Filter的拦截规则
public class Demo01Filter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}/*** 当有新的请求被Filter拦截到时执行该方法** @param servletRequest* @param servletResponse* @param filterChain* @throws IOException* @throws ServletException*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("filter执行了...before");// 放行该请求filterChain.doFilter(servletRequest, servletResponse);System.out.println("filter执行了...after");}@Overridepublic void destroy() {}
}
访问:http://localhost:8080/demo01
查看IDEA控制台:
需要注意的是,只要访问的路径符合Filter的拦截规则,即使访问的web资源不存在,该请求也会经过Filter
访问:http://localhost:8080/abc
1.2.2 XML配置Filter
注释掉@WebFilter注解,在web.xml中编写配置:
<filter><filter-name>demo01Filter</filter-name><filter-class>com.dfbz.filter.Demo01Filter</filter-class>
</filter>
<filter-mapping><filter-name>demo01Filter</filter-name><!--所有的请求都经过该Filter--><url-pattern>/*</url-pattern>
</filter-mapping>
1.2.3 Filter的拦截规则
方式 | 示例 |
---|---|
精确匹配 | /user 、/user.jsp |
目录匹配 | /user/* 、/emp/* |
后缀匹配 | *action 、*.html 、*.jsp |
- 练习:
浏览器的访问地址 | 过滤器的配置 | 是否起作用 |
---|---|---|
http://localhost:8080/aaa | /* | 会 |
http://localhost:8080/aaa | /aaa | 会 |
http://localhost:8080/aaa.do | *.do | 会 |
http://localhost:8080/aaa/bbb | /aaa/* | 会 |
http://localhost:8080/bbb.do | /*.do | 不会,配置错误 |
http://localhost:8080/aaa/bbb.action | /aaa/*.action | 不会,配置错误 |
Tips:目录匹配不可用和后缀匹配一起使用;
- 编写Filter测试拦截规则:
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
//@WebFilter("/user")
//@WebFilter("/user.jsp")
//@WebFilter("/user/*")
@WebFilter("*.action")
public class Demo02Filter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("Demo02Filter...before");// 放行该请求filterChain.doFilter(servletRequest, servletResponse);System.out.println("Demo02Filter...after");}@Overridepublic void destroy() {}
}
1.3 Filter的生命周期
1.3.1 Filter生命周期介绍
- Filter生命周期:
- 何时创建?
- 服务器启动时创建
- 何时销毁?
- 服务器关闭时
- 创建几次?
- 在整个服务器的运行期间只会创建一次Filter的实例
- 何时创建?
1.3.2 Filter生命周期相关方法
Filter接口中的方法 | 作用和执行次数 |
---|---|
void init() | 初始化的方法,在服务器启动就加载,执行1次 |
void doFilter() | 拦截到请求之后执行的核心逻辑方法,执行N次 |
void destroy() | 销毁,在服务器关闭的时候,执行1次 |
- 编写一个Filter,启动服务器观察控制台输出:
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebFilter("/*")
public class Demo03Filter implements Filter {/*** 当Filter初始化时执行该方法** @param filterConfig* @throws ServletException*/@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("filter初始化了");}/*** 当有新的请求被Filter拦截到时执行该方法** @param servletRequest* @param servletResponse* @param filterChain* @throws IOException* @throws ServletException*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("filter执行了...before");// 放行该请求filterChain.doFilter(servletRequest, servletResponse);System.out.println("filter执行了...after");}/*** 当Filter销毁时执行该方法*/@Overridepublic void destroy() {System.out.println("filter销毁了");}
}
访问一个web资源,观察日志;
1.3.3 FilterConfig类
FilterConfig是Filter的配置类,主要用于获取ServletContext对象,以及获取一些其他的filter信息;
- FilterConfig相关方法:
String getFilterName()
:获取该Filter的名称,默认为该Filter类的全路径名ServletContext getServletContext()
:获取上下文对象(ServletContext)String getInitParameter(String var1)
:获取Filter的初始化参数Enumeration<String> getInitParameterNames()
:获取全部Filter的初始化参数;
- 测试类:
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebFilter(filterName = "demo04Filter", // filter的名称(默认为当前Filter类的全路径名)value = "/*",initParams = {// 自定义一些参数@WebInitParam(name = "param1", value = "123"),@WebInitParam(name = "param2", value = "456"),}
)
public class Demo04Filter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 获取该Filter的名称String filterName = filterConfig.getFilterName();System.out.println("【filterName】: " + filterName);// 获取初始化的一些自定义参数String param1 = filterConfig.getInitParameter("param1");String param2 = filterConfig.getInitParameter("param2");System.out.println("【param1】: " + param1);System.out.println("【param2】: " + param2);// 获取上下文对象ServletContext app = filterConfig.getServletContext();System.out.println(app);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("Demo04Filter...before");// 放行该请求filterChain.doFilter(servletRequest, servletResponse);System.out.println("Demo04Filter...after");}@Overridepublic void destroy() {}
}
启动服务器,查看IDEA控制台的信息:
1.4 Filter的拦截方式
拦截方式用于指定过滤器在什么样的请求方式下进行拦截,默认是只对直接来至浏览器发送的请求才拦截。
Tips:默认情况下,只拦截浏览器发送过来的请求
1.4.1 REQUEST
REQUEST
:代表只拦截浏览器发送过来的请求,不会拦截RequestDispatcher
的include
和forward
发送过来的请求;也是filter的默认值;
案例:编写一个filter只拦截/demo01
请求,编写一个Demo02Servlet,跳转到/demo01
请求,观察是否会被filter拦截到
- Demo02Servlet:
package com.dfbz.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("请求到达了demo02");request.getRequestDispatcher("/demo01").forward(request,response);}
}
- Demo05Filter:
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebFilter(value = "/demo01")
public class Demo05Filter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("Demo05Filter...before");// 放行该请求filterChain.doFilter(servletRequest, servletResponse);System.out.println("Demo05Filter...after");}@Overridepublic void destroy() {}
}
访问:http://localhost:8080/demo01
访问:http://localhost:8080/demo02
1.4.2 FORWARD
FORWARD
:只拦截RequestDispatcher的forward()方法发送过来的请求
- 注解方式配置:
@WebFilter(value = "/demo01", dispatcherTypes = {DispatcherType.FORWARD})
- xml方式配置:
<filter><filter-name>demo05</filter-name><filter-class>com.dfbz.filter.Demo05Filter</filter-class>
</filter><filter-mapping><filter-name>demo05</filter-name><url-pattern>/demo01</url-pattern><!--拦截类型--><dispatcher>FORWARD</dispatcher>-->
</filter-mapping>
重启服务器,访问:http://localhost:8080/demo01:
访问:http://localhost:8080/demo02:
1.4.3 INCLUDE
INCLUDE
:只拦截RequestDispatcher的include()方法发送过来的请求
修改Demo02Servlet:
request.getRequestDispatcher("/demo01").include(request,response);
重启服务器,访问:http://localhost:8080/demo02
发现Demo05Filter并不会拦截include发送过来的请求(此时Filter的拦截方式为FORWARD)
修改Demo03Filter:
@WebFilter(value = "/demo01", dispatcherTypes = {DispatcherType.INCLUDE})
重启服务器,访问:http://localhost:8080/demo02
1.4.4 ERROR
ERROR
:只拦截由于异常或错误引发跳转的请求
在web.xml中配置:
<error-page><!--根据错误码--><!-- <error-code>404</error-code>--><!--根据出现异常的类型--><exception-type>java.lang.ArithmeticException</exception-type><!--如果出现异常就跳转到/demo01--><location>/demo01</location>
</error-page>
- 修改Demo02Servlet:
package com.dfbz.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("请求到达了demo02");// request.getRequestDispatcher("/demo01").forward(request,response);
// request.getRequestDispatcher("/demo01").include(request,response);// 模拟出现异常int i = 1 / 0;}
}
重启服务器,访问:http://localhost:8080/demo02,出现错误,跳转到/demo01,发现并没有经过Demo05Filter(此时拦截方式是INCLOUD);
- 修改Demo05Filter:
@WebFilter(value = "/demo01", dispatcherTypes = {DispatcherType.ERROR})
重启服务器,访问:http://localhost:8080/demo02,查看控制台;发现经过了拦截器
1.4.5 ASYNC
在Servlet3.0中,支持了异步的Servlet;默认情况下Filter是不能拦截异步的Servlet的,需要开启ASYNC支持;
ASYNC
:开启拦截异步Servlet的支持
- 编写异步的Demo03Servlet:
package com.dfbz.servlet;import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebServlet(value = "/demo03", asyncSupported = true) // 1. 开启异步支持
public class Demo03Servlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 2. 开启异步模式AsyncContext startAsync = req.startAsync();System.out.println("主线程开始: " + Thread.currentThread().getName() + "【" + System.currentTimeMillis() + "】");// 3. 执行任务startAsync.start(new Runnable() {@Overridepublic void run() {System.out.println("任务线程1: " + Thread.currentThread().getName() + "【" + System.currentTimeMillis() + "】");// 执行任务task();// 异步处理完毕startAsync.complete();ServletResponse response = startAsync.getResponse();try {// 响应客户端response.getWriter().write("ok");} catch (IOException exception) {exception.printStackTrace();}System.out.println("任务线程3: " + Thread.currentThread().getName() + "【" + System.currentTimeMillis() + "】");}});System.out.println("主线程结束: " + Thread.currentThread().getName() + "【" + System.currentTimeMillis() + "】");}public void task() {System.out.println("任务线程2: " + Thread.currentThread().getName() + "【" + System.currentTimeMillis() + "】");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}
}
- 修改Demo05Filter,让其拦截
/demo03
请求:
@WebFilter(value = "/demo03",dispatcherTypes = {DispatcherType.ASYNC})
public class Demo05Filter implements Filter
访问:http://localhost:8080/demo03
默认情况下,Filter不支持拦截异步的Servlet;
修改Demo05Filter:
@WebFilter(value = "/demo03",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.ASYNC},asyncSupported = true)
重启服务器,访问:http://localhost:8080/demo03
1.5 过滤器的拦截类型小结
过滤类型 | 作用 |
---|---|
REQUEST | 只拦截来自浏览器发送过来的请求,默认值 |
FORWARD | 只拦截通过RequestDispatcher.forward()发送的请求 |
INCLUDE | 只拦截通过RequestDispatcher.include()发送的请求 |
ERROR | 只拦截由于异常/错误触发的请求 |
ASYNC | 拦截异步的Servlet,该Filter也要开启异步支持 |
1.6 Filter小案例
需求:编写过滤器,过滤所有Servlet中使用POST方法提交的汉字的编码。
-
有2个Servlet,一个是LoginServlet登录,一个是RegisterServlet注册
-
有2个JSP页面,1个是login.jsp,有表单,登录名。1个register.jsp,有表单,有注册的名字。都使用POST提交用户名使用汉字提交。
-
使用过滤器,对所有的Servlet的POST方法进行过滤。
-
在没有使用过滤器之前,每个Servlet必须加上汉字编码:request.setCharacterEncoding(字符集);字符集与网页的编码要一致
- login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>用户登录</title>
</head>
<body>
<h2>用户登录</h2>
<form action="/login" method="post">登录名:<input type="text" name="user"><br><hr><input type="submit" value="登录">
</form>
</body>
</html>
- register.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>用户注册</title>
</head>
<body>
<h2>用户注册</h2>
<form action="/register" method="post">注册名:<input type="text" name="name"><br><hr><input type="submit" value="注册">
</form>
</body>
</html>
- LoginServlet.java
package com.dfbz.servlet;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** @author lscl* @version 1.0* @intro:*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {PrintWriter out = response.getWriter();//得到登录的用户名,并且打印输出String user = request.getParameter("user");out.print("登录成功,用户名是:" + user);}
}
- RegisterServlet.java
package com.dfbz.servlet;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** @author lscl* @version 1.0* @intro:*/
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {PrintWriter out = response.getWriter();//得到注册的用户名String name = request.getParameter("name");out.print("注册成功,用户名:" + name);}
}
- EncodeFilter.java
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebFilter("/*")
public class EncodingFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {//对汉字进行编码request.setCharacterEncoding("utf-8");//放行,将请求向后传递chain.doFilter(request, response);}public void init(FilterConfig config) throws ServletException {}
}
二、过滤器链
2.1 过滤器链概念
概念:如果一个用户请求到达web资源中间经过多个过滤器,每个过滤器完成一个具体的功能。这多个过滤器就组成了一个过滤链。
- 过滤器链执行流程:
多个过滤器链的执行流程为:过滤器1--->dofilter--->过滤器2---->dofilter---->web资源---->过滤器2--->过滤器1--->客户端
2.2 过滤器链案例
需求:创建两个过滤器OneFilter和TwoFilter,访问ResourceServlet,每个过滤器的请求和响应各输出一句话,观察过滤器的执行过程。
- 第一个过滤器:OneFilter.java
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebFilter("/resource")
public class OneFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println("过滤器1:before");chain.doFilter(req, resp);System.out.println("过滤器1:after");}public void init(FilterConfig config) throws ServletException {}
}
- 第二个过滤器:TwoFilter.java
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebFilter("/resource")
public class TwoFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println("过滤器2:before");chain.doFilter(req, resp); //放行System.out.println("过滤器2:after");}public void init(FilterConfig config) throws ServletException {}
}
- Web资源ResourceServlet.java
package com.dfbz.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author lscl* @version 1.0* @intro:*/
@WebServlet("/resource")
public class ResourceServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("Resource...");response.getWriter().write("ok");}
}
访问:http://localhost:8080/resource
2.3 过滤器链的执行顺序
2.3.1 注解方式
使用注解方式配置:根据过滤器的类名字母的先后顺序再执行,例如A>B>C>D…
我们把TowFilter
的名字改为AowFilter
,重启服务器,访问:http://localhost:8080/resource
2.3.2 xml配置方式
使用xml方式配置时:配置在前面的filter先执行
<filter><filter-name>one</filter-name><filter-class>com.dfbz.filter.OneFilter</filter-class>
</filter>
<filter-mapping><filter-name>one</filter-name><url-pattern>/resource</url-pattern>
</filter-mapping><filter><filter-name>two</filter-name><filter-class>com.dfbz.filter.TwoFilter</filter-class>
</filter>
<filter-mapping><filter-name>two</filter-name><url-pattern>/resource</url-pattern>
</filter-mapping>
重启服务器,访问:http://localhost:8080/resource
三、过滤器综合案例
3.1 完成案例功能
3.1.1 搭建项目
1)执行SQL语句:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for article
-- ----------------------------
DROP TABLE IF EXISTS `article`;
CREATE TABLE `article` (`id` int(11) NOT NULL AUTO_INCREMENT,`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文章标题',`content` varchar(2550) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文章内容',`publish_date` datetime(0) NULL DEFAULT NULL COMMENT '发布时间',`publish_user` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '发布人',`u_id` int(11) NULL DEFAULT NULL COMMENT '发布人id',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of article
-- ----------------------------
INSERT INTO `article` VALUES (1, '宝贵的青春', '世界上美丽的东西千千万万,却没有一样比年轻更为美丽;世界上珍贵的东西数也数不清,却没有一样比青春更为宝贵。我们是多么值得骄傲多么让人羡慕啊!而我们若只是挥霍光阴,只是享受,不去奋斗拼搏,那我们真的算拥有青春吗答案是否定的,我们仅有发愤图强,努力耕耘才能做到无愧于青春,无愧于人生,才能拥有一个充实而完美的青春。', '2021-01-10 11:36:26', '张三', 1);
INSERT INTO `article` VALUES (2, '这世界,需要梦想', '这世界,不是所有的地方都能被阳光照耀,也不是时时刻刻都是阳光灿烂。如果你的眼,只是盯着阳光照射不到的地方,或者只是看到眼前的绵绵阴云,那么你的心,就会浸泡在没有阳光的日子里,感受到的,除了负面的情绪,还有什么呢?其实,你完全不必纠结于眼前的景象,你可以放飞自己的那颗自由的心,翱翔在阴云之上。在那时,你的世界就会充满阳光,你的灵魂就会跟着光明飞翔。因而,这世界,需要梦想!', '2020-12-19 11:36:46', '李四', 2);
INSERT INTO `article` VALUES (3, '向着太阳行走', '不改初心,方得始终。这个初心就是对日出的希望。“早晨是岁月的初心,初心在,岁月怎么会老?我每次早起,都是对自己初心的一次回归,不忘初心的人,又怎么会老呢?以朝霞为伴,跟旭日行走,每天都是初生。”这种对日出的初心随时可见,“每一个天亮,我都会重温一次初心,擦拭一下远年的纯真。”每一个天亮,都能感受到作者的初心,真美!', '2020-11-28 11:37:47', '王五', 3);
INSERT INTO `article` VALUES (4, '没尝过努力奋斗的滋味,怎能体会人生的珍贵', '人生的精彩之处,不仅在于取得怎样的成就,更在于拼搏奋斗的过程。\r\n\r\n 奋斗的沿途,也许有痛苦、有失望,但我们终将迎来希望。奋斗的路上,我们会遇见志同道合的朋友,收获更好的自己。我们的人生,也会因为充实的生活而充满色彩。\r\n\r\n 青春不是用来挥霍的,而是要去奋斗的。这是个高速发展的时代,也是奋斗者最好的时代,我们需要随时保持自我学习的能力,朝着前方努力奔跑,越过山丘和沟壑,收获更为精彩的人生。\r\n\r\n 奋斗的滋味,是苦中有甜,甜中带乐。只有品尝过奋斗的滋味,我们才能体会人生的珍贵。趁年轻,去放手一搏吧,这是献给青春最好的礼物,也是对生命最好的馈赠。', '2020-12-30 11:39:30', '张三', 1);
INSERT INTO `article` VALUES (5, '《满江红》· 岳飞', '怒发冲冠,凭栏处、潇潇雨歇。抬望眼、仰天长啸,壮怀激烈。三十功名尘与土,八千里路云和月。莫等闲、白了少年头,空悲切。\r\n靖康耻,犹未雪。臣子恨,何时灭。驾长车,踏破贺兰山缺。壮志饥餐胡虏肉,笑谈渴饮匈奴血。待从头、收拾旧山河,朝天阙。', '2021-01-24 12:18:33', '张三', 1);
INSERT INTO `article` VALUES (6, '《破阵子·为陈同甫赋壮词以寄之》 · 辛弃疾', '醉里挑灯看剑,梦回吹角连营。八百里分麾下炙,五十弦翻塞外声,沙场秋点兵。\r\n马作的卢飞快,弓如霹雳弦惊。了却君王天下事,赢得生前身后名。可怜白发生!', '2021-01-06 12:18:41', '张三', 1);
INSERT INTO `article` VALUES (7, '《过零丁洋》 · 文天祥', '辛苦遭逢起一经,干戈寥落四周星。\r\n山河破碎风飘絮,身世浮沉雨打萍。\r\n惶恐滩头说惶恐,零丁洋里叹零丁。\r\n人生自古谁无死?留取丹心照汗青。', '2021-01-05 12:18:44', '张三', 1);
INSERT INTO `article` VALUES (8, '《滕王阁序》 · 王勃', '豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟;人杰地灵,徐孺下陈蕃之榻。雄州雾列,俊采星驰。台隍枕夷夏之交,宾主尽东南之美。都督阎公之雅望,棨戟遥临;宇文新州之懿范,襜帷暂驻。十旬休假,胜友如云;千里逢迎,高朋满座。腾蛟起凤,孟学士之词宗;紫电青霜,王将军之武库。家君作宰,路出名区;童子何知,躬逢胜饯。 时维九月,序属三秋。潦水尽而寒潭清,烟光凝而暮山紫。俨骖騑于上路,访风景于崇阿;临帝子之长洲,得天人之旧馆。层峦耸翠,上出重霄;飞阁流丹,下临无地。鹤汀凫渚,穷岛屿之萦回;桂殿兰宫,即冈峦之体势。 披绣闼,俯雕甍,山原旷其盈视,川泽纡其骇瞩。闾阎扑地,钟鸣鼎食之家;舸舰弥津,青雀黄龙之舳。云销雨霁,彩彻区明。落霞与孤鹜齐飞,秋水共长天一色。渔舟唱晚,响穷彭蠡之滨;雁阵惊寒,声断衡阳之浦。 遥襟甫畅,逸兴遄飞。爽籁发而清风生,纤歌凝而白云遏。睢园绿竹,气凌彭泽之樽;邺水朱华,光照临川之笔。四美具,二难并。穷睇眄于中天,极娱游于暇日。天高地迥,觉宇宙之无穷;兴尽悲来,识盈虚之有数。望长安于日下,目吴会于云间。地势极而南溟深,天柱高而北辰远。关山难越,谁悲失路之人?萍水相逢,尽是他乡之客。怀帝阍而不见,奉宣室以何年? 嗟乎!时运不齐,命途多舛。冯唐易老,李广难封。屈贾谊于长沙,非无圣主;窜梁鸿于海曲,岂乏明时?所赖君子见机,达人知命。老当益壮,宁移白首之心?穷且益坚,不坠青云之志。酌贪泉而觉爽,处涸辙以犹欢。北海虽赊,扶摇可接;东隅已逝,桑榆非晚。孟尝高洁,空余报国之情;阮籍猖狂,岂效穷途之哭! 勃,三尺微命,一介书生。无路请缨,等终军之弱冠;有怀投笔,慕宗悫之长风。舍簪笏于百龄,奉晨昏于万里。非谢家之宝树,接孟氏之芳邻。他日趋庭,叨陪鲤对;今兹捧袂,喜托龙门。杨意不逢,抚凌云而自惜;钟期既遇,奏流水以何惭? 呜乎!胜地不常,盛筵难再;兰亭已矣,梓泽丘墟。临别赠言,幸承恩于伟饯;登高作赋,是所望于群公。敢竭鄙怀,恭疏短引;一言均赋,四韵俱成。请洒潘江,各倾陆海云尔: 滕王高阁临江渚,佩玉鸣鸾罢歌舞。 画栋朝飞南浦云,珠帘暮卷西山雨。 闲云潭影日悠悠,物换星移几度秋。 阁中帝子今何在?槛外长江空自流。', '2021-01-23 12:18:48', '李四', 2);
INSERT INTO `article` VALUES (9, '《出师表》 · 诸葛亮', '先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。\r\n\r\n宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。\r\n\r\n侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必能裨补阙漏,有所广益。\r\n\r\n将军向宠,性行淑均,晓畅军事,试用于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。\r\n\r\n亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。\r\n\r\n臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。\r\n\r\n先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐托付不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。\r\n\r\n愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。\r\n\r\n今当远离,临表涕零,不知所言。', '2021-01-18 12:18:51', '李四', 2);-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',`age` int(11) NULL DEFAULT NULL COMMENT '年龄',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'zhangsan', '123', '张三', 20);
INSERT INTO `user` VALUES (2, 'lisi', 'admin', '李四', 19);
INSERT INTO `user` VALUES (3, 'wangwu', '110', '王五', 24);
2)拷贝静态资源
拷贝资源到项目中,将html文件改为jsp文件,在文件首部加入如下代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
3)拷贝jar包
在/WEB-INF
中建立lib
文件夹,拷贝【配套资料】中准备的jar包
4)jdbc.properties:
jdbc.username=root
jdbc.password=admin
jdbc.url=jdbc:mysql://localhost:3306/xb
jdbc.driverClassName=com.mysql.jdbc.Driver
5)DataSourceUtils:
package com.dfbz.utils;import com.alibaba.druid.pool.DruidDataSource;import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;/*** 数据源的工具类*/
public class DataSourceUtils {private static DataSource ds;/*** 在静态代码块中创建数据源对象*/static {// 创建druid数据源DruidDataSource dataSource = new DruidDataSource();Properties prop = new Properties();try {// 加载配置文件prop.load(DataSourceUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"));} catch (IOException e) {e.printStackTrace();}dataSource.setUsername(prop.getProperty("jdbc.username"));dataSource.setPassword(prop.getProperty("jdbc.password"));dataSource.setUrl(prop.getProperty("jdbc.url"));dataSource.setDriverClassName(prop.getProperty("jdbc.driverClassName"));ds=dataSource;}/*** 得到数据源*/public static DataSource getDataSource() {return ds;}/*** 从连接池中得到连接对象*/public static Connection getConnection() {try {return ds.getConnection();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}/*** 释放资源*/public static void close(Connection conn, Statement stmt, ResultSet rs) {//关闭结果集if (rs!=null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}//关闭语句对象if (stmt!=null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}//关闭连接对象if (conn!=null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}/*** 关闭连接*/public static void close(Connection conn, Statement stmt) {close(conn, stmt, null);}
}
6)实体类:
- User:
/*** user实体类*/
public class User {private Integer id;private String username;private String password;private String name;private Integer age;
}
- Article:
/*** article实体类*/
public class Article {private Integer id;private String title;private String content;private Date publishDate;private String publishUser;private Integer uId;
}
3.1.2 登录业务
1)修改前端页面
<form action="/login" method="post">
2)LoginServlet
package com.dfbz.controller;import com.dfbz.entity.User;
import com.dfbz.service.UserService;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;/*** 控制器层*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {// 专门用于处理user的业务private UserService userService = new UserService();@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 解决POST提交乱码问题request.setCharacterEncoding("UTF-8");// 1. 接受前端传递的参数String username = request.getParameter("username");String password = request.getParameter("password");// 2.调用service进行业务处理User user = userService.findByUsername(username);if (user == null) {// 说明用户名不存在request.setAttribute("error","用户名不存在!");request.getRequestDispatcher("/login.jsp").forward(request,response);return;}if (!password.equals(user.getPassword())) {// 说明密码错误request.setAttribute("error","密码错误!");request.getRequestDispatcher("/login.jsp").forward(request,response);return;}// 说明用户名和密码都正确HttpSession session = request.getSession();// 存入到会话域中,方便其他地方取出当前登录用户的信息session.setAttribute("loginUser",user);// 重定向到ListServlet进行数据的查询,由ListServlet查询完数据后跳转到list.jsp页面response.sendRedirect(request.getContextPath()+"/list");}
}
3)UserService
package com.dfbz.service;import com.dfbz.dao.UserDao;
import com.dfbz.entity.User;/*** 业务逻辑层*/
public class UserService {private UserDao userDao=new UserDao();/*** 根据用户名查询用户,如果没有查询到返回Null* @param username* @return*/public User findByUsername(String username) {User user=userDao.findByUsername(username);return user;}
}
4)UserDao
package com.dfbz.dao;import com.dfbz.entity.User;
import com.dfbz.utils.DataSourceUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** 数据层*/
public class UserDao {/*** 根据用户名查询用户,如果没有查询到返回Null* @param username* @return*/public User findByUsername(String username) {try {// 获取数据库连接Connection connection = DataSourceUtils.getConnection();// 获取预定义SQL语句对象PreparedStatement ps = connection.prepareStatement("select * from user where username=?;");// 设置占位符的值ps.setString(1,username);// 执行查询获取结果集ResultSet rs = ps.executeQuery();User user=null;if(rs.next()){Integer id = rs.getInt("id");String dbUsername = rs.getString("username");String password = rs.getString("password");String name = rs.getString("name");Integer age = rs.getInt("age");user=new User(id,dbUsername,password,name,age);}return user;} catch (SQLException throwables) {throwables.printStackTrace();}return null;}
}
3.1.3 文章列表
1)业务分析
业务分析:
1)页面需要取出当前登录用户(从session取出)
2)来到list.jsp页面需要获取当前数据库中的所有文章信息,因此来到这个页面之前就应该准备好
3)文章列表是根据文章发布时间(publish_date)倒叙排序的
2)ListServlet:
package com.dfbz.controller;import com.dfbz.entity.Article;
import com.dfbz.service.ArticleService;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;/*** 控制器层*/
@WebServlet("/list")
public class ListServlet extends HttpServlet {private ArticleService articleService=new ArticleService();@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 查询数据库中所有的文章List<Article> articleList=articleService.findAll();// 将文章集合添加到域对象request.setAttribute("articleList",articleList);// 跳转到list.jsp页面request.getRequestDispatcher("/list.jsp").forward(request,response);}
}
3)ArticleService
package com.dfbz.service;import com.dfbz.dao.ArticleDao;
import com.dfbz.entity.Article;import java.util.List;/*** 业务逻辑层*/
public class ArticleService {private ArticleDao articleDao=new ArticleDao();/*** 查询所有文章,按照发布时间倒叙排序(最晚发布的在最前面)* @return*/public List<Article> findAll() {List<Article> articleList= articleDao.findAll();return articleList;}
}
4)ArticleDao
package com.dfbz.dao;import com.dfbz.entity.Article;
import com.dfbz.entity.User;
import com.dfbz.utils.DataSourceUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*** 数据层*/
public class ArticleDao {/*** 查询所有文章,按照发布时间倒叙排序(最晚发布的在最前面)* @return*/public List<Article> findAll() {try {// 获取数据库连接Connection connection = DataSourceUtils.getConnection();// 获取预定义SQL语句对象PreparedStatement ps = connection.prepareStatement("select * from article order by publish_date desc;");// 执行查询获取结果集ResultSet rs = ps.executeQuery();List<Article> articleList=new ArrayList<>();while(rs.next()){Integer id = rs.getInt("id");String title = rs.getString("title");String content = rs.getString("content");Date publishDate = rs.getDate("publish_date");String publishUser = rs.getString("publish_user");Integer uId = rs.getInt("u_id");// 添加到articleList集合中articleList.add(new Article(id,title,content,publishDate,publishUser,uId));}return articleList;} catch (SQLException throwables) {throwables.printStackTrace();}return null;}
}
5)list.jsp页面
<c:forEach items="${articleList}" var="article"><hr><div style="padding:20px;background-color: #eee;border-radius: 10px;"><h3 style="text-align: center;">${article.title}</h3><p>${article.content}</p><h4 style="text-align: right;">发布人:${article.publishUser}</h4><h4 style="text-align: left;">发布日期:${article.publishDate}</h4></div>
</c:forEach>
3.1.4 文章添加
1)add.jsp页面
修改表单提交路径和提交方式
<form action="/add" method="post">
2)AddServlet:
package com.dfbz.controller;import com.dfbz.entity.Article;
import com.dfbz.entity.User;
import com.dfbz.service.ArticleService;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Date;/*** 控制器层*/
@WebServlet("/add")
public class AddServlet extends HttpServlet {// 专门负责处理article的业务逻辑private ArticleService articleService=new ArticleService();@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 设置编码request.setCharacterEncoding("UTF-8");// 获取前端提交的参数String title = request.getParameter("title");String content = request.getParameter("content");Article article = new Article();article.setTitle(title);article.setContent(content);// 从session中获取用户HttpSession session = request.getSession();User loginUser = (User) session.getAttribute("loginUser");// 发布人article.setPublishUser(loginUser.getName());// 发布时间article.setPublishDate(new Date());// 发布人idarticle.setuId(loginUser.getId());// 将文章添加到数据库articleService.add(article);// 重定向到ListServlet重新查询文章数据response.sendRedirect(request.getContextPath()+"/list");}
}
3)ArticleService
/*** 添加文章到数据库* @param article*/
public void add(Article article) {articleDao.add(article);
}
4)ArticleDao
/*** 添加文章* @param article*/
public void add(Article article) {try {// 获取数据库连接Connection connection = DataSourceUtils.getConnection();// 获取预定义SQL语句对象PreparedStatement ps = connection.prepareStatement("insert into article values(null,?,?,?,?,?)");ps.setString(1,article.getTitle());ps.setString(2,article.getContent());// 转成时间戳ps.setTimestamp(3, new Timestamp(article.getPublishDate().getTime()));ps.setString(4,article.getPublishUser());ps.setInt(5,article.getuId());// 执行SQL语句ps.executeUpdate();} catch (SQLException throwables) {throwables.printStackTrace();}
}
3.2 使用过滤器完成权限校验
如上图所示,我们来到list.jsp
页面时需要显示当前登录人的姓名,换句话说,如果你没有登录那么就不能访问list.jsp
页面!
但仅仅是不能访问list.jsp
页面就完了吗?肯定不是的,如果我们不让客户端访问list.jsp
页面,他一样可以通过访问/list
请求来跳转到list.jsp
页面,而且用户如果没有登录应该也不能访问add.jsp
页面,以及/add
请求等,因此我们应该先分析需要拦截什么资源,需要放行什么资源;
3.2.1 分析需求
通过分析,我们发现静态资源全部需要放行,jsp页面除了login.jsp
放行外全部拦截,在请求访问除了/login
请求需要放行外,其他请求全部需要登录才可以访问;
需要拦截的请求:/list
、/list.jsp
、/add
、/add.jsp
;
3.2.3 编写LoginFilter拦截器
- LoginFilter:
package com.dfbz.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;// 拦截受限资源
@WebFilter({"/list", "/list.jsp", "/add", "/add.jsp"})
public class LoginFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {// 转成子接口,使功能更加强大HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;// 获取会话HttpSession session = request.getSession();// 获取当前登录用户Object loginUser = session.getAttribute("loginUser");if(loginUser == null){// 说明用户没有登录response.sendRedirect(request.getContextPath()+"/login.jsp");return;}// 用户登录了: 放行chain.doFilter(request,response);}@Overridepublic void destroy() {}
}
3.3 使用过虑器完成特殊字符过滤
拦截器除了做请求的拦截与放行外,还可以做一些通用的操作,比如,解决request编码问题!
3.3.1 过滤字符表
DROP TABLE IF EXISTS `words`;
CREATE TABLE `words` (`id` int(11) NOT NULL AUTO_INCREMENT,`word` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '敏感词汇',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of words
-- ----------------------------
INSERT INTO `words` VALUES (1, '笨蛋');
INSERT INTO `words` VALUES (2, '傻蛋');
3.3.2 字符过滤器
package com.dfbz.filter;import com.dfbz.utils.DataSourceUtils;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;/*** 特殊字符过滤* 拦截所有请求*/
@WebFilter("/*")
public class TextFilter implements Filter {private List<String> words = new ArrayList<>();@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 加载敏感词try {// 获取数据库连接Connection connection = DataSourceUtils.getConnection();// 获取预定义SQL语句对象PreparedStatement ps = connection.prepareStatement("select * from words;");// 执行查询获取结果集ResultSet rs = ps.executeQuery();while (rs.next()) {// 添加到词汇集合中words.add(rs.getString("word"));}} catch (SQLException throwables) {throwables.printStackTrace();}}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {request.setCharacterEncoding("UTF-8");// 需要增强request的getParameter()方法ServletRequest requestProxy = (ServletRequest) Proxy.newProxyInstance(TextFilter.class.getClassLoader(), // 和目标对象(ServletRequest)一样的类加载器request.getClass().getInterfaces(), // 目标对象(ServletRequest)实现的所以接口的字节码对象new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 获取执行的方法名String methodName = method.getName();if ("getParameter".equals(methodName)) {//增强getParameter方法// 原来的功能String returnVal = (String) method.invoke(request, args);for (String word : words) {if (returnVal.contains(word)) {// 如果包含有敏感词就把敏感词替换为***returnVal = returnVal.replaceAll(word, "***");}}// 相当于修改了request的getParameter()的返回值return returnVal;}// 其他的方法直接保留原有的功能return method.invoke(request, args);}});// 放行请求,传递代理对象给具体的servletchain.doFilter(requestProxy, response);}@Overridepublic void destroy() {}
}
再次添加文章: