SpringMVC拦截器使用

源码地址

拦截器interceptor

拦截器是URL请求的第一道门,所有请求会先经过拦截器interceptor,然后再进入controller
下面,记录一种通过注解方法拦截所有需要登录才能发起的请求,并且把非法请求重定向到登录界面

xml文件基本配置

<!--配置拦截器, 多个拦截器,顺序执行 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
        <mvc:mapping path="/**" />
        <!--resource不拦截-->
        <mvc:exclude-mapping path="/asset/**"/>
        <mvc:exclude-mapping path="/assets/**"/>
        <!--聊天室websocket不拦截-->
        <mvc:exclude-mapping path="/sockjs/websocket"/>
        <mvc:exclude-mapping path="/websocket"/>
        <bean class="com.iss.blog.interceptor.AccessControlInterceptor"/>
    </mvc:interceptor>
    <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>
<!-- 静态资源访问(不拦截此目录下的东西的访问)  -->
<mvc:resources location="/asset/"  mapping="/asset/**" />
<mvc:resources location="/assets/"  mapping="/assets/**" />

关键实现HandlerInterceptorAdapter

public abstract class AbstractInterceptor extends HandlerInterceptorAdapter {
    /**
     * 是否有 PublicPage注解
     * @param handlerMethod
     * @return
     */
    protected  boolean isPublicPage(HandlerMethod handlerMethod){
        if (handlerMethod==null)
            return false;
        PublicPage publicPage = handlerMethod.getMethodAnnotation(PublicPage.class);
        if (publicPage!=null){
            return true;
        }
        return false;
    }
    /**
     * 某个请求是否ajax请求
     * @param request
     * @return
     */
    protected boolean isAjaxRequest(HttpServletRequest request){
        String requestType = request.getHeader("X-Requested-With");
        if("XMLHttpRequest".equals(requestType)){
            System.out.println("is AJAX request");
            return true;
        }else{
            System.out.println("is not AJAX request");
            return false;
        }
    }
}


    public class AccessControlInterceptor extends AbstractInterceptor {
    /**
     * 下面这段话参考了某片文章,由于找不回原文,所以参考链接不贴
     * 在业务处理器处理请求之前被调用
     * 如果返回false
     *     从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
     * 如果返回true
     *    执行下一个拦截器,直到所有的拦截器都执行完毕
     *    再执行被拦截的Controller
     *    然后进入拦截器链,
     *    从最后一个拦截器往回执行所有的postHandle()
     *    接着再从最后一个拦截器往回执行所有的afterCompletion()
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (handler instanceof  HandlerMethod &&isPublicPage((HandlerMethod) handler)){
            return true;
        }
        if(没有登录){
            PrintWriter out = response.getWriter();
            out.append(
                    "{'resultCode':1012,'resultMessage':'错误的请求'}"
            );
            if (!isAjaxRequest(request)) {
            //这里把请求转发给登录界面
                request.getRequestDispatcher("/login").forward(request, response);
            }
            return false;
        }else
            return true;
    }

    /**
     * 在业务处理器处理请求执行完成后,生成视图之前执行的动作
     * 可在modelAndView中加入数据,比如当前时间
     */
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
    }

    /**
     * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
     *
     * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
     */
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }
}

定义的注解

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PublicPage {
    String value() default "";
}

这样,在@RequestMapping上加上@PublicPage就代表,这样路由不需要登录就可以请求到,否则需要登录后才能请求到
比如登录页面:

@PublicPage
@RequestMapping("/login")
public  String loginPage(){
    return "frontend/account/login";
}

必须为ajax请求才可以访问

 @RequestMapping(value = "/registerValidate",headers = { "X-Requested-With=XMLHttpRequest" })
 

猜你喜欢

转载自www.cnblogs.com/chenjingquan/p/8973540.html