SpringBoot 遗忘后的简单快速回忆之拦截器(和处理用AJAX 异步请求,拦截器的重定向页面无效的问题)

SpringBoot的拦截器

其实拦截器的原理很简单,就是利用AOP 的原理,来根据需求判断程序是继续执行,还是跳到另外的方面!通常大多用于判断用户是否登录,是否让其访问正常数据

正常情况下,拦截器不会拦截静态资源,Spring Boot 的默认静态目录为 resources/static,该目录下的静态页面、JS、CSS、图片等不会被拦截

其实SpringBoot 用的拦截器和我们学的SpringMVC的是一样的

自定义拦截器

定义拦截器,只需要实现 HandlerInterceptor 接口。HandlerInterceptor 接口是所有自定义拦截器或者 Spring Boot 提供的拦截器的鼻祖,所以,首先来了解下该接口。该接口中有三个方法, 我们可以根据需求来选择性覆盖!


import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TextInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       /**
        *该方法的执行时机是,当某个客户端请求已经匹配到对应的 Controller 中的某个方法,且在这个方法执行之前。
        * 所以 preHandle(……) 方法可以决定是否将请求放行,这是通过返回值来决定的,
        * 返回 true 则放行,返回 false 则不会向后执行。
        * */
        Object user = request.getSession().getAttribute("user");
        // 获取到项目名,以便下面进行重定向
        String homeUrl = request.getContextPath();
        if(user==null){//拦截让其重定向到其他页面
            response.sendRedirect(homeUrl+"/index.html");
            return false;
        }else{//表示放行
            return true;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        /**
         *该方法的执行时机是,当某个客户端请求已经匹配到对应的 Controller 中的某个方法,
         *且在执行完了该方法,但是在 DispatcherServlet 视图渲染之前。
         * 所以在这个方法中有个 ModelAndView 参数,可以在此做一些修改动作。
         * */
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        /**
         * 该方法是在整个请求处理完成后(包括视图渲染)执行,这时做一些资源的清理工作,
         * 这个方法只有在 preHandle(……) 被成功执行后并且返回 true 才会被执行。
         * */
    }
}

配置拦截器所要拦截的方法

如果是在SpringMVC中的话我们需要在springmvc.xml中配置,因为SpringBoot摒弃了xml开发所以我们要换种方式

我们自定义个类来实现WebMvcConfigurer 接口 用来配置要拦截的方法

import com.baizhi.interceptors.UserInterceptors;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class UserDefineMvcConfiogure implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new 自定义拦截器类名())
                .addPathPatterns("/**")//这个方法是表示拦截那些方法,/**表示拦截所有的Controller
                .excludePathPatterns(//这个方法是表示那些方法不需要拦截  /*表示该根下的方法,/**表示该下的所有方法
                        "/leaming/dialog/*",
                        "/static/**",
                        "/TextController/userLogin",
                        "/TextController/registerUser",
                        "/TextController/existsUser",
                        "/TextController/createImg"
                );
    }
}

提示:其实除了实现WebMvcConfigurer 我们还可以继承WebMvcConfigurationSupport 不过因为此WebMvcConfigurationSupport方法 又会导致默认的静态资源被拦截,这就需要我们手动将静态资源放开。所以通常我们都使用WebMvcConfigurer

不过拦截器有个很大的问题就是只能拦截控制器而不能拦截页面

因为现在基本是都是在用AJAX 异步请求,我们就会发现拦截器的重定向页面无效的问题
这是因为:
ajax,何为ajax,简单说就是局部网页刷新技术。前后端分离以后,后台逐渐淡化了对页面逻辑跳转的控制,将这些交给了前端去做,前台利用ajax,异步请求后台,获得数据,局部刷新网页,实现了许多方便的功能;

因此,即使后台进行页面跳转的编码,然后前台请求完毕以后,只会执行 ajax的回调函数,至于后台那些逻辑,对不起,我ajax一概不管;
所以便出现了这样的问题,那么该如何解决那!

此解决方案来自与 https://www.cnblogs.com/young-youth/p/11665595.html 页面,作者为young-youth

解决方案如下
在改动 ajax 之前不要着急,如果在上面提到的回调函数里面进行修改,那么前端同学的代码,就要改动很多,凡是涉及ajax请求的方法,都要加上页面跳转的逻辑了。。。
这里使用$.ajaxSetup( ),可以看着是对 ajax 的增强,对比与 spring事务的后置增强,$.ajaxSetup( )会在每个 ajax请求完成以后得到执行(是不是感觉就是一个后置增强啊);

将下面的代码,交给前端童鞋,让他放到 引入的公共的 js文件里面。
我的补充:可以创建一个js文件将下面代码复制过去,在页面引用

<script type="text/javascript" src="/static/common/setuo.js"></script>

// 解决Ajax异步请求 springMvc 不跳转页面的问题
$.ajaxSetup( {
	//设置ajax请求结束后的执行动作
    complete :
        function(XMLHttpRequest, textStatus) {
			// 通过XMLHttpRequest取得响应头,sessionstatus
            var sessionstatus = XMLHttpRequest.getResponseHeader("sessionstatus");
            if (sessionstatus == "TIMEOUT") {
                var win = window;
                while (win != win.top){
                    win = win.top;
                }
                win.location.href= XMLHttpRequest.getResponseHeader("CONTEXTPATH");
            }
        }
});

这段代码的含义,大抵就是,在 ajax请求完成以后,执行 complete 回调方法,里面进行一些逻辑的判断;

这里判断 session 的状态,如果是超时被销毁了,则进行页面的跳转,跳到 CONTEXTPATH 的值那 ;

session 的状态以及 CONTEXTPATH 的值,由我们后台同学定义;

如下:在拦截器的preHandle方法中,添加如下逻辑


 		HttpSession session = httpServletRequest.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            // 获取到项目名,以便下面进行重定向
            String homeUrl = httpServletRequest.getContextPath();
         	// 如果是 ajax 请求,则设置 session 状态 、CONTEXTPATH 的路径值
         	// 如果是ajax请求响应头会有,x-requested-with
            if (httpServletRequest.getHeader("x-requested-with") != null && httpServletRequest.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")){
                httpServletResponse.setHeader("SESSIONSTATUS", "TIMEOUT");
                httpServletResponse.setHeader("CONTEXTPATH", homeUrl+"/index.html");
                // FORBIDDEN,forbidden。也就是禁止、403
                httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); 
            }else{
                // 如果不是 ajax 请求,则直接跳转即可
                httpServletResponse.sendRedirect(homeUrl+"/index.html");
            }
            return false;
        }

因为以上处理,SpringBoot 就又可以继续愉快的处理页面的跳转了;
主要是记住 ajax异步请求,前台的逻辑最后都走ajax的回调函数,只会接受后台的返回数据,不会搭理页面跳转这样的要求的,因为人家毕竟只是局部刷新,而后台却要整个页面刷新。。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值