【JavaWeb】Filter案例:登录验证、敏感词汇过滤

接上一遍Filter基础知识,本文在两个应用场景下使用FIlter过滤器,加深理解应用。



Filter案例

练习场景下使用过滤器,利用过滤器完成一些通用的操作。


一.案例1_登录验证

我们先正常的将登录流程走一遍,再对案例进行分析、实现。

1.0 正常的登录流程

用户登录界面:

在这里插入图片描述
登录成功:

在这里插入图片描述
比较简单的逻辑:

在这里插入图片描述

1.1 需求
  1. 访问用户登录后的资源。验证其是否登录
  2. 如果登录了,则直接放行。
  3. 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。

案例分析

在这里插入图片描述
过滤器核心代码:LoginFilter.java

需要注意的是:

  • 拦截请求过程中需要判断用户请求是否包含访问登录相关资源路径,要注意排除掉 css/js/图片/验证码等其它资源,否则请求这些资源也会被拦截掉,页面的样式就会丢失。
/**
 * 登录验证的过滤器
 */
@WebFilter("/*")
public class LoginFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //0.强制转换,因为ServletRequest接口的子接口HttpServletRequest才有获取请求路径的方法
        HttpServletRequest request = (HttpServletRequest) req;

        //1.获取资源请求路径
        String uri = request.getRequestURI();
        //2.判断是否包含登录相关资源路径,要注意排除掉 css/js/图片/验证码等资源
        if("/login.jsp".contains(uri) || "/LoginServlet".contains(uri) || "/css/".contains(uri) || "/js/".contains(uri) || "/fonts/".contains(uri) ){
            //包含,用户就是想登录。放行
            chain.doFilter(req, resp);
        }else{
            //不包含,需要验证用户是否登录
            //3.从获取session中获取user
            Object user = request.getSession().getAttribute("user");
            if(user != null){
                //登录了。放行
                chain.doFilter(req, resp);
            }else{
                //没有登录。跳转登录页面
                request.setAttribute("login_msg","您尚未登录,请登录!");
                request.getRequestDispatcher("/login.jsp").forward(request,resp);
            }
        }
    }

    public void init(FilterConfig config) throws ServletException {

    }

    public void destroy() {
    }
}

1.2 代码实现
1.2.1 目录结构

在这里插入图片描述
登录案例可以参考另一篇博文:【JavaWeb】综合案例:用户登录.

1.2.2 数据库准备

在这里插入图片描述

1.2.3 页面login.jsp和index.jsp

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body>
<form action="/LoginServlet" method="post">
    用户账号:<input type="text" placeholder="请输入账号" name="username"><br>
    用户密码:<input type="text" placeholder="请输入密码" name="password"><br>
    <input type="submit" value="登录">
</form>
<!--提示信息-->
<p>${login_msg}</p>
</body>
</html>

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>用户主页</title>
  <!--导入css文件-->
  <link rel="stylesheet" type="text/css" href="css/style.css" />

</head>
<body>
<p>登录成功,用户名${user.username}欢迎您!</p>

<form action="/UpdateServlet" method="post">
  <input type="hidden" name="id" value="${user.id}">
  <label for="introduce">自我介绍:</label>
  <input type="text" name="introduce" id="introduce" value="${user.introduce}">
  <input type="submit" value="修改自我介绍">
</form>
</body>
</html>

style.css

label{
    color: red;
}
1.2.4 dao层

UserDao.java

/**
 * 操作数据库的类
 */
public class UserDao {

    //声明JDBCTemplate对象共用
    private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());

    /**
     * 登录方法
     *
     * @param loginUser
     * @return user包含用户全部数据,没有查询到,放回null
     */
    public User login(User loginUser) {
        try {
            //1.编写sql语句
            String sql = "select * from info where username=? and password=?";
            //2.调用JDBCTemplate对象的查询方法
            User user = jdbcTemplate.queryForObject(sql //sql语句
                    , new BeanPropertyRowMapper<User>(User.class) //RowMapper接口实现类,将数据自动封装成指定对象
                    , loginUser.getUsername() //sql参数
                    , loginUser.getPassword()); // sql参数

            return user;
        } catch (Exception e) {
            e.printStackTrace();//以后会将异常记录到日志文件中
            return null;
        }
    }

    /**
     * 修改用户自我介绍
     *
     * @param updateUser
     * @return
     */
    public User update(User updateUser) {
        //1.编写sql语句
        String sql = "update info set introduce = ? where id = ? ";

        //2.调用JDBCTemplate对象的方法
        jdbcTemplate.update(sql,updateUser.getIntroduce(),updateUser.getId());

        //3.再次查询
        return jdbcTemplate.queryForObject("select * from info where id = ?" //sql语句
                , new BeanPropertyRowMapper<User>(User.class) //RowMapper接口实现类,将数据自动封装成指定对象
                , updateUser.getId()); // sql参数
    }
}
1.2.5 domain层

User.java

/**
 * 用户实体类
 */
public class User implements Serializable {
    private int id;
    private String username;
    private String password;
    private String introduce;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getIntroduce() {
        return introduce;
    }

    public void setIntroduce(String introduce) {
        this.introduce = introduce;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", introduce='" + introduce + '\'' +
                '}';
    }
}
1.2.6 util层

JDBCUtils.java

/**
 * JDBC工具类,使用Druid连接池
 */
public class JDBCUtils {

    private static DataSource ds;

    static {
        try {
            //1.加载配置文件
            Properties prop = new Properties();
            InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            prop.load(is);

            //2.初始化数据库连接池对象
            ds = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接池对象
     *
     * @return
     */
    public static DataSource getDataSource() {
        return ds;
    }

    /**
     * 获取数据库连接对象
     *
     * @return
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
}
1.2.7 web层

过滤器LoginFilter.java

Servlet资源

LoginServlet.java

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.设置解码格式
        req.setCharacterEncoding("utf-8");
        //2.获取请求体参数username和password
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //3.将username和password封装成User对象
        User loginuser = new User();
        loginuser.setUsername(username);
        loginuser.setPassword(password);
        //4.调用UserDao的login方法
        UserDao dao = new UserDao();
        User user = dao.login(loginuser);
        //5.判断user是否为null
        if (user==null){
            //登录失败跳转到登录页面
            req.setAttribute("login_msg","登录失败!用户名或密码错误。");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }else {
            //登录成功,将用户信息存在Session中,跳转index.jsp
            HttpSession session = req.getSession();
            session.setAttribute("user",user);
            resp.sendRedirect("/index.jsp");
        }
    }
}

UpdateServlet.java

@WebServlet(name = "UpdateServlet", urlPatterns = "/UpdateServlet")
public class UpdateServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.设置解码格式
        request.setCharacterEncoding("utf-8");

        //2.获取请求体参数username和password
        String id = request.getParameter("id");
        String introduce = request.getParameter("introduce");

        //3.将id和introduce封装成User对象
        User Update_user = new User();
        Update_user.setId(Integer.parseInt(id));
        Update_user.setIntroduce(introduce);
        //4.调用UserDao的update方法
        UserDao dao = new UserDao();
        User user = dao.update(Update_user);

        //5.显示修改后用户的自我介绍
        request.setAttribute("user", user);
        request.getRequestDispatcher("/index.jsp").forward(request, response);
    }
}
1.3 测试

1.用户未登录,直接访问index.jsp:将会跳转到登录界面login.jsp,并给出提示信息

在这里插入图片描述
未登录,直接访问LoginServlet、updateSerlvet资源同样如此。

2.当前用户已经登录,即session域中存在user的键值对,再直接访问index.jsp、LoginServlet、updateSerlvet资源就无须执行登录业务逻辑了:

在这里插入图片描述

登录成功,此时重开一个新的标签页,直接访问index.jsp:

在这里插入图片描述
通过F12查看浏览器控制台,网络抓包,可以看到直接进入了用户主页,不会再访问LoginServlet资源。


二.案例2_敏感词汇过滤

使用上面登录案例,来实现敏感词汇的过滤。用户修改自我介绍的时候,如果包含了《敏感词汇.txt》里面的敏感词汇,则会将词汇替换为 ***

敏感词汇.txt

笨蛋
坏蛋

先来看下效果:

在这里插入图片描述
修改自我介绍:

在这里插入图片描述
点击修改自我介绍,将会回显用户修改后的自我介绍:

在这里插入图片描述
比较简单的例子,旨在能理解明白过滤器进行敏感词汇过滤的逻辑,下面就来实现这个效果。

2.1 需求分析

需求:

  • 1.对【用户登录案例】修改的自我介绍数据进行敏感词汇过滤
  • 2.敏感词汇参考《敏感词汇.txt》
  • 3.如果是敏感词汇,替换为 ***

过滤分析图

在这里插入图片描述
难点分析

  1. 对req对象进行增强。使用动态代理,增强获取参数相关方法,对请求参数中敏感词汇进行过滤;
  2. 放行。传递代理对象

代码模式不熟悉的小伙伴,可以先阅读下另一篇的博文:代理模式:动态代理、静态代理.

2.2 代码实现
2.2.1 目录结构

在这里插入图片描述

大部分代码与上面登录案例一致。

2.2.2 核心代码

核心代码就是:敏感词汇过滤器SensitiveWordsFilter.java

  • 使用缓冲字符输入流获取 《敏感词汇.txt》的词汇内容
  • 增强方法逻辑中,使用 “***” 替换掉请求参数里面的敏感词汇,并返回替换后的值
/**
 * 敏感词汇过滤器
 */
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
	//敏感词汇集合
    private List<String> list = new ArrayList<String>();

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1.创建代理对象,增强getParameter方法
        ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //增强getParameter方法
                //判断是否是getParameter方法
                if(method.getName().equals("getParameter")){
                    //增强返回值
                    //获取返回值
                    String value = (String) method.invoke(req,args);
                    if(value != null){
                        for (String str : list) {
                            if(value.contains(str)){
                                value = value.replaceAll(str,"***");
                            }
                        }
                    }
                    return  value;
                }
			   
                //考虑到可能使用其它获取请求参数的方法,那就都需要进行增强,思路是一样的,这里不展开了。
                //判断方法名是否是 getParameterMap

                //判断方法名是否是 getParameterValue

                return method.invoke(req,args);
            }
        });
        //2.放行
        chain.doFilter(proxy_req, resp);
    }

    public void init(FilterConfig config) throws ServletException {
        try{
            //1.获取文件真实路径
            ServletContext servletContext = config.getServletContext();
            String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
            //2.读取文件
            BufferedReader br = new BufferedReader(new FileReader(realPath));
            //3.将文件的每一行数据添加到list中
            String line = null;
            while((line = br.readLine())!=null){
                list.add(line);
            }
            //释放流
            br.close();
            System.out.println(list);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    public void destroy() {
    }
}

测试与前面演示效果一致,不赘述了。

到这两个过滤器的小案例就完成了,理解为主,当前还可以进行更多过滤器的延伸,相信小伙伴们都可以信手拈来~


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值