SpringBoot学习笔记8(过滤器、监听器、拦截器)

过滤器介绍

filter是servlet规范中定义的一种特殊类。用于对指定的请求进行过滤,然后将请求交给对应的servlet进行处理并生成响应,最后filter再对服务器响应进行后处理,可以实现访问权限控制、过滤敏感词汇、压缩响应信息等功能。

监听器介绍

listener也是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。在事件发生前后做一些必要的处理,可以实现在线人数统计等功能。

拦截器介绍

interceptor在面向切面编程(Aspect-Oriented Programming,AOP)中用于在某个方法或字段被访问之前进行拦截,然后在处理前后加入某些功能,例如:日志,安全等功能。一般拦截器方法都是通过动态代理的方式实现,可以通过它来进行权限验证、判断用户是否登陆、日志记录。

下面是一个简单的实例:

文件夹结构.png

FilterConfig.java

// 标识本类为配置类
@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<LoginFilter> registFilter() {
        // 创建注册器
        FilterRegistrationBean<LoginFilter> registration = new FilterRegistrationBean<LoginFilter>();
        // 设置过滤器
        registration.setFilter(new LoginFilter());

        // 设置属性exclusions,不需要过滤的URL
        registration.addInitParameter("exclusions", "/user/login");

        // 添加过滤规则
        registration.addUrlPatterns("/*");
        // 过滤器设置名称
        registration.setName("LoginFilter");
        // 设置过滤器顺序,值越小优先级越高
        registration.setOrder(1);

        return registration;
    }
}

InterceptorConfig.java

// 标识本类为配置类
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport{

    @Autowired
    private WordInterceptor wordInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册敏感词汇拦截器,设置拦截路径
        registry.addInterceptor(wordInterceptor).addPathPatterns("/user/search");

        super.addInterceptors(registry);
    }
}

ListenerConfig.java

// 标识本类为配置类
@Configuration
public class ListenerConfig {

    @Bean
    public OnlineListener init() {
        return new OnlineListener();
    }
}

UserController.java

@RestController
@RequestMapping("user")
public class UserController {

    // 统计在线用户数,请求方法类型get,URL:/user/online
    @GetMapping("online")
    public ResultObject setSession(HttpServletRequest request,
                                   HttpServletResponse response) {
        // 获取session
        HttpSession session = request.getSession();
        // 获取sessionid,即JSESSIONID
        String sessionId = session.getId();
        System.out.println(sessionId);

        // 获取session属性
        Object onlineNumber = session.getServletContext().getAttribute("onlineNumber");
        System.out.println(onlineNumber);
        // 返回结果
        return new ResultObject(onlineNumber);
    }

    // 登录验证用户,请求方法类型post,URL:/user/login
    @PostMapping("login")
    public ResultObject login(@RequestBody User user, HttpServletRequest request, HttpServletResponse response) {

        // 正确账号密码,模拟数据库中的信息
        User realUser = new User("jacky", "112233");
        // 判断账号、密码是否正确
        if (realUser.equals(user)) {
            // 获取session,获取不到则新建
            HttpSession session = request.getSession();

            // 获取sessionid,即JSESSIONID
            String sessionId = session.getId();
            System.out.println(sessionId);

            // 设置session属性user
            session.setAttribute("user", user);

            return new ResultObject("login success");
        } else {
            return new ResultObject(-1, "fail", "login fail");
        }
    }

    // 搜索功能,过滤敏感词汇,请求方法类型get,URL:/user/search
    @GetMapping("search")
    public ResultObject search(@RequestParam String word) {
        // 若关键字是敏感词,在拦截器中已经被拦截不可能走到这里
        return new ResultObject("search word " + "'" + word + "'" + " is valid.");
    }
}

ResultObject.java

public class ResultObject {

    // 后台返回码
    private int code;
    // 后台返回消息
    private String msg;
    // 结果
    private Object result;

    // 构造函数
    public ResultObject() {
        super();
        // TODO Auto-generated constructor stub
    }

    // 构造函数
    public ResultObject(int code, String msg, Object result) {
        super();
        this.code = code;
        this.msg = msg;
        this.result = result;
    }

    // 后台处理成功时使用的构造函数
    public ResultObject(Object result) {
        super();
        this.code = 0;
        this.msg = "success";
        this.result = result;
    }

    // 属性的setter、getter方法
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public Object getResult() {
        return result;
    }
    public void setResult(Object result) {
        this.result = result;
    }
    @Override
    public String toString() {
        return "ResultObject [code=" + code + ", msg=" + msg + ", result=" + result + "]";
    }
}

User.java

public class User{

    // 用户名称
    private String username;
    // 用户密码
    private String password;

    // 构造函数
    public User() {
        super();
        // TODO Auto-generated constructor stub
    }

    // 构造函数
    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }

    // 属性的setter、getter方法
    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;
    }

    // 重写toString方法
    @Override
    public String toString() {
        return "Book [username=" + username + ", password=" + password + "]";
    }

    // 重写hashCode方法
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((password == null) ? 0 : password.hashCode());
        result = prime * result + ((username == null) ? 0 : username.hashCode());
        return result;
    }

    // 重写equals方法,便于直接比较user对象
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (password == null) {
            if (other.password != null)
                return false;
        } else if (!password.equals(other.password))
            return false;
        if (username == null) {
            if (other.username != null)
                return false;
        } else if (!username.equals(other.username))
            return false;
        return true;
    }
}

LoginFilter.java

public class LoginFilter implements Filter {

    // 存储不需要过滤的URLs,一个对象
    private static String exclusions;
    // 存储不需要过滤的URLs,exclusions分解而来的字符串数组
    private static String[] ALLOWEDURLS;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
        // 获取在filterconfig中配置好的,不需要过滤的URLs
        exclusions = filterConfig.getInitParameter("exclusions");
        if (!exclusions.isEmpty()) {
            // 获取不需要过滤的URLs,可以直接访问的URLs
            ALLOWEDURLS = exclusions.split(",");
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest,
                         ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {

        // 强转
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        // 获取当前请求的URL
        String url = request.getRequestURI();

        // 获取session,false表示如果没有获取到也不会创建
        HttpSession session = request.getSession(false);
        // 如果当前请求的URL不需要过滤或者已经登录的用户的请求,则继续处理
        if (isAllowed(url) || session != null && session.getAttribute("user") != null) {
            chain.doFilter(request, response);
        } else {
            // 若用户没有登录,否则直接返回
            render(response, "not login");
        }
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    // 当前请求是否需要过滤
    public boolean isAllowed(String url) {
        for (String ALLOWEDURL: ALLOWEDURLS) {
            if (ALLOWEDURL.equals(url)) {
                return true;
            }
        }
        return false;
    }

    // 返回请求失败消息
    public void render(HttpServletResponse response, String msg) throws IOException {
        // 构造返回消息
        ResultObject resultObject = new ResultObject(-1, "fail", msg);

        // 生成json数据
        JSONObject object = new JSONObject(resultObject);

        // 返回json数据
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        out.write(object.toString().getBytes("UTF-8"));
        out.flush();
        out.close();
    }

}

WordInterceptor.java

@Component
public class WordInterceptor implements HandlerInterceptor{

    // 设置敏感词汇
    private static final String[] forbitWords = {"apple", "pear", "peach", "Lemon "};

    // 处理前方法
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        // 获取请求中的参数word
        String word = request.getParameter("word");
        // 与敏感词汇对比
        for (String forbitWord: forbitWords) {
            if (word.equals(forbitWord)) {
                render(response, "search word " + "'" + word + "'" + " is not allowed.");
                // 返回假,中断请求
                return false;
            }
        }

        // 返回真,继续处理请求
        return true;
    }

    // 处理后方法
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
    }

    // 完成后方法
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }

    // 返回失败消息
    public void render(HttpServletResponse response, String msg) throws IOException {
        ResultObject resultObject = new ResultObject(-1, msg, null);

        JSONObject object = new JSONObject(resultObject);

        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        out.write(object.toString().getBytes("UTF-8"));
        out.flush();
        out.close();
    }
}

OnlineListener.java

@WebListener
public class OnlineListener implements HttpSessionListener{

    // 记录当前登录用户数
    private int onlineNumber = 0;

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        // 监听到创建了新的session,在线用户累加1
        onlineNumber++;
        // 设置session属性
        se.getSession().getServletContext().setAttribute("onlineNumber", onlineNumber);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        // 监听到销毁了旧的session,在线用户减少1
        onlineNumber--;
        // 设置session属性
        se.getSession().getServletContext().setAttribute("onlineNumber", onlineNumber);
    }

}

文集推荐:

Java基础方法集1
Python基础知识完整版
Spring Boot学习笔记
Linux指令进阶
Java高并发编程
SpringMVC基础知识进阶
Mysql基础知识完整版
健康管理系统学习花絮(学习记录)
Node.js基础知识(随手笔记)
MongoDB基础知识
Dubbo学习笔记
Vue学习笔记(随手笔记)

声明:发表此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本我们(QQ:981086665;邮箱:981086665@qq.com)联系联系,我们将及时更正、删除,谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容