06【Filter】

文章目录

  • 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:代表只拦截浏览器发送过来的请求,不会拦截RequestDispatcherincludeforward发送过来的请求;也是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方法提交的汉字的编码。

  1. 有2个Servlet,一个是LoginServlet登录,一个是RegisterServlet注册

  2. 有2个JSP页面,1个是login.jsp,有表单,登录名。1个register.jsp,有表单,有注册的名字。都使用POST提交用户名使用汉字提交。

  3. 使用过滤器,对所有的Servlet的POST方法进行过滤。

  4. 在没有使用过滤器之前,每个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() {}
}

再次添加文章:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/69727.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

年度征文|一个业余电脑玩家的30年(1992-2022)

《论语为政》&#xff1a;“五十而知天命”。岁月真的是一把刀&#xff0c;一晃已过不惑之年&#xff0c;还有几天就要进入知非之年。不论知非还是知天命&#xff0c;反正是花甲将至而从心所欲了。年少时因某种不合机缘&#xff0c;错与IT界擦肩而过&#xff0c;每每想起就扼腕…

勾股定理·圓周率·無窮級數·微積分

勾股定理 勾股定理 圓 圓形的概念的形成&#xff0c;是人類認知歷史上的一大里程碑。 圓周率 定义1 一个圆形的周长与直径之比&#xff1a; 定义2 以圆形半径为边长作一正方形&#xff0c;然後把圆形面积和此正方形面积比。 圆与外接正方形 定义3 满足 的最小正实数。 ysin(x) …

谈古论津丨西沽公园

天津为退海之地&#xff0c;意思就是海面下降或者陆地上升形成的地理环境&#xff0c;现在塘沽、汉沽还有盐场&#xff0c;就在一定程度上说明了这一点。因此天津地势低洼&#xff0c;沽坑相连&#xff0c;素有七十二沽之说&#xff0c;所以天津的地名带“沽”字的也特别多&…

什么是事件响应策略?您知道如何起草一份吗?

如今&#xff0c;网络犯罪已在世界范围内变得越来越普遍&#xff0c;促使组织提前制定竞争策略来处理网络犯罪事件&#xff0c;减少业务停机风险并降低损失成本。因此&#xff0c;制定适当的事件响应策略或计划以应对网络攻击的影响并确保业务的平稳运行和业务数据的安全至关重…

美国空军停止使用【软盘】管理【核武器库】

平心而论&#xff0c;05后出生的&#xff0c;估计已经不知道软盘这个东西是什么了。 因此&#xff0c;为了缅怀历史&#xff0c;黑鸟还是想大概介绍一下&#xff0c;这个在当年被我拿来垫麻将桌的神器。 软盘&#xff0c;英文名Floppy Disk&#xff0c;是个人计算机&#xff08…

细菌拮抗作用在细菌生活中的核心作用

大多数细菌可能存在或至少有一部分时间处于单细胞状态。在这种单细胞状态下&#xff0c;细菌将更容易受到一系列威胁&#xff0c;包括其周围环境的物理或化学性质的简单波动&#xff0c;更容易受到更直接的生物威胁&#xff0c;如抗生素、噬菌体、拮抗细菌&#xff0c;甚至是捕…

中百信玄武库Kubernetes实践与探索

“Kubernetes其在自动化部署、扩展性、以及管理容器化的应用中已经体现出独特的优势&#xff0c;同样在企业中应用落地已经成为一种共识。中百信玄武库作为ToB服务产品&#xff0c;玄武库研究院在玄武库平台使用Kubernetes做了哪些实践和探索呢&#xff1f;我们今天和大家分享一…

微信论坛交流小程序系统毕业设计毕设(6)开题答辩PPT

整个项目包含了&#xff1a;开题报告 开题报告PPT 任务书 中期报告 论文模板 答辩PPT等 项目源码 主要安介绍了系统在开发过程中所应用到的一些关键的技术&#xff0c;主要包括了前端小程序开发的MINA框架&#xff1b;后台开发java的框架springboot、模板引擎 thymeleaf…

22、基于51单片机电压电流功率系统设计(程序+原理图+PCB图+Proteus仿真+答辩技巧+开题报告+参考论文+元器件清单等)

一、硬件方案 硬件组成&#xff1a;51系列单片机ADC0832按键LCD1602液晶LED设计而成。 二、设计功能 本设计基于单片机型号&#xff1a;STC89C52/51、AT89C52/51、AT89S52/51都可通用。 1、本设计基于51单片机实现电流、电压测量和功率的计算&#xff0c;并通过按键设置报警…

有哪些可以投稿软件工程/系统软件/程序设计语言类外文期刊、会议?

如果你是第一次投外文期刊、会议&#xff0c;往往不知道应该投到哪些期刊杂志或会议上。不要着急&#xff0c;有下面几种投稿策略可以采用。 第一种策略&#xff0c;根据你的论文质量来选择期刊、会议。也就是说&#xff0c;如果对论文质量十分自信&#xff0c;那就选择顶级的期…

大学毕业设计这样做可以吗

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

springboot论坛交流小程序毕业设计毕设作品开题报告开题答辩PPT

springboot论坛交流小程序毕业设计毕设作品开题报告开题答辩PPT 【小程序用户功能】 用户注册登录&#xff1a;注册普通账号&#xff0c;然后使用注册的账号登录登录 微信授权登录&#xff1a;直接使用微信作为账号&#xff0c;授权后登录 资讯列表&#xff1a;用户可以任意浏…

用这个工具,发朋友圈都可以自动了

今天推荐是一个比较骚气的工具&#xff0c;自动发朋友圈(不用root手机)&#xff0c;对于一天发10多条&#xff0c;甚至20条朋友圈的朋友&#xff0c;每次编辑比较麻烦。我之前也写过抢红包工具&#xff0c;当时上架应用市场时&#xff0c;又恰逢过年&#xff0c;那下载量&#…

如何选题、撰写微信小程序毕业论文,以及答辩流程?

一、开始准备选题 在大四上学期开学时&#xff0c;开始准备论文。首先需要确定论文主题&#xff0c;考虑自己想要做什么样的毕业设计。可以选择之前接触过或者做过的领域&#xff0c;这样可以更快地进展。如果选择了之前没有接触过的领域&#xff0c;一定要尽早开始准备。我打…

【毕业设计】7-基于STM32开发板的无线传输设计(原理图工程+源代码工程+答辩论文+答辩PPT)

【毕业设计】 基于STM32开发板的无线传输设计&#xff08;原理图工程源代码工程答辩论文答辩PPT&#xff09; 文章目录 【毕业设计】 基于STM32开发板的无线传输设计&#xff08;原理图工程源代码工程答辩论文答辩PPT&#xff09;资料下载链接任务书设计说明书摘要设计框架架构…

根据班级模型设计简易朋友圈(支持发动态、点赞、评论、回复等)

需求 将学校以班级为单位制作一个简易的朋友圈&#xff0c;默认用户在一个班级里&#xff0c;用户可以在朋友圈里发动态&#xff0c;支持9宫格&#xff0c;对动态进行评论&#xff0c;回复其他用户的评论&#xff0c;可删除自己的评论&#xff0c;对动态进行点赞&#xff0c;可…

毕业论文用什么流程图软件比较好?

在写作论文的时候使用流程图&#xff0c;会让我们的论文看起来更加有逻辑。并且流程图的图片都可以在PPT中随意插入以及使用。 基础流程图作为最为基本和简单的的流程图方式&#xff0c;一般不区分用户角色和场景&#xff0c;适用于简单场景&#xff0c;梳理单一的流程情况&am…

AI真的会抢“饭碗” ?

去年年底ChatGPT横空出世&#xff0c;并在全球掀起AI热潮&#xff0c;全世界的科技公司都在这场人工智能竞赛中迎头追赶。不过AI强大的能力&#xff0c;也让广大职场人担心&#xff0c;“AI取代人类劳动力”也随之成为热议话题。 事实上&#xff0c;AI创作会不会真的抢人类的“…

AI未来会取代哪些行业

AI的全称Artificial Intelligence, 人工智能&#xff0c;合起来就是人工智能。 它的目的是模仿人类智能&#xff0c;使电脑能够实现一些人类难以完成的任务&#xff0c;比如自动学习、自动推理和自动解决问题。 虽然AI和人工制造的实体&#xff0c;如机器人等&#xff0c;都可…

李德毅院士 :智能的困扰和释放

来源&#xff1a;中国人工智能学会 李德毅, 何雯 *军事科学院系统工程研究院&#xff0c;北京&#xff0c;100141 *通信作者. E-mail: colcloud126.com 摘要&#xff1a;智能回答整个认知活动中“在哪里”、“是什么”、“为什么”和“怎么做”四个基本问题&#xff0c;含有丰富…