SpringBoot自定义拦截器

简介

拦截器是可以动态的拦截action的调用,它提供了一个接口可以使开发者在一个Action执行的前后添加自己的逻辑。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或者之后加入某些操作。目前,我们需要掌握的主要是Spring的拦截器。

原理

拦截器:它采用了java动态代理和反射的机制来实现。

实现自定义拦截器步骤。

1.创建一个spring Web项目。
2.创建一个实现HandlerInterceptor接口的自定义拦截器实体类。
3.创建一个实现WebMvcConfigurer接口的配置类。将自定义拦截器添加到容器中,并配置拦截的路径。

1 开发工具 :IntelliJ IDEA
当前spring boot备受欢迎的快速开发框架,我这里就采用spring boo框架搭建web项目 。
2 创建自定义拦截器
创建一个实现HandlerInterceptor接口的拦截器类MyInterceptor
HandlerInterceptor 接口中定义了三个接口,分别是:preHandle(在调取action之前调用),postHandle(在action调用之后,返回视图对象之前调用)和afterCompletion(在action调用完成之后,返回视图之后调用,一般用于清理资源)如下图所示。在这里插入图片描述
在jdk8之前,接口中是没有方法体的,如果实现拦截器接口的话,要同时重写三个方法。很多情况下,我们实际中用不到三个拦截方法。所以jdk8之前我们自定义拦截器一般时继承一个抽象类适配器HandlerInterceptorAdapter。这时候想使用哪个方法,就重写那方法即可。而jdk8之后,接口中可以出现了方法体。所以现在我们可以直接实现接口,使用哪个方法直接重写即可。我这是都重写了。

package com.wyz.study.interceptor;


import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;

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

/**
 * @author wyz
 * @version 1.0
 * @ClassName: MyInterceptor
 * @Description: 自定义拦截器
 * @date 2019/3/12 12:03
 **/
@Component
public class MyInterceptor implements HandlerInterceptor {
    /**
     * 在业务调用action对象之前被调用
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("preHandle........");
        //从session中获取用户信息
        String username = (String) request.getSession().getAttribute("userName");
        //判断userName是否为null
        if(null == username){
            System.out.println("用户未登录,请先登录!!!");
            // 跳转到登录页面
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
            return false;
        }
        return true;
    }

    /**
     * 在请求完成之后,呈现视图对象之前被调用
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle-----------执行了!!!!!");
        String viewName = modelAndView.getViewName();
        View view = modelAndView.getView();

        System.out.println("viewName==="+viewName);
        System.out.println("view==="+view);


    }

    /**
     * 在请求请求结束之后被调用,可以使用该方法清理资源
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("afterCompletion#############执行了。。。。。。");
 
    }
}

3.创建配置实体类
创建一个将自定义拦截器加入容器中的配置实体类。该配置类要实现WebMvcConfigurer接口。重写addInterceptors方法。

package com.wyz.study.interceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author wyz
 * @version 1.0
 * @ClassName: MySpringMVCConfig
 * @Description: 这是一个配置类,将自定义的拦截器注册到容器中。
 * @date 2019/3/13 13:02
 **/
@Configuration
public class MySpringMVCConfigurer implements WebMvcConfigurer {

    @Autowired
    private MyInterceptor myInterceptor;

    /**
     * 将拦截器注册到容器中
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //设置拦截路径
        registry.addInterceptor(myInterceptor).addPathPatterns("/userInfo");
    }
}

验证自定义拦截器是否成功

1.创建页面
接下来创建几个简单的jsp页面。login.jsp(简单的登录页面),success.jsp(登录成功的页面),userInfo.jsp(用户信息的页面) 。页面用于演示。所以很简陋。
在这里插入图片描述
login.jsp

<%--
  Created by IntelliJ IDEA.
  User: wyz
  Date: 2019/3/12
  Time: 11:57
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录页面</title>
</head>
<body>
    <form action="login" >
        用户名:<input type="text" name="userName">
        密码:<input type="password" name="passWord">
        <button >提交</button>
    </form>

</body>
</html>

success.jsp

<%--
  Created by IntelliJ IDEA.
  User: wyz
  Date: 2019/3/12
  Time: 11:57
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功页面</title>
</head>
<body>
   <h2>欢迎${userName},您已经登录成功!!!</h2>
    <<a href="userInfo">点击获取用户信息</a>
</body>
</html>

success.jsp

<%--
  Created by IntelliJ IDEA.
  User: wyz
  Date: 2019/3/13
  Time: 13:15
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户页面</title>
</head>
<body>
     <h2>用户名:${userName} 用户年龄:${age}(当用户名后面有名字出现,说明拦截器未设置成功,反之说明成功)</h2>
</body>
</html>

2.创建控制层
LoginController.java

package com.wyz.study.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

/**
 * @author wyz
 * @version 1.0
 * @ClassName: LoginController
 * @Description: 用户登录控制层
 * @date 2019/3/12 12:04
 **/
@Controller
public class LoginController {


    /**
     * 跳转登录页面
     * @return
     */
    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }

    /**
     * 登录操作
     * @param request
     * @param userName
     * @param passWord
     * @return
     */
    @RequestMapping("/login")
    public String login(HttpServletRequest request,String userName, String passWord){
        request.getSession().setAttribute("userName",userName);
        request.getSession().setAttribute("age",20);
        return "success";
    }
}

UserInfoController.java

package com.wyz.study.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author wyz
 * @version 1.0
 * @ClassName: UserInfoController
 * @Description: 这是用户的控制层
 * @date 2019/3/13 13:18
 **/
@Controller
public class UserInfoController {

    @RequestMapping("/userInfo")
    public String userInfo(){

        System.out.println("返回pay.jsp页面!!!");
        return "userInfo";
    }
}

3.验证
启动项目,在浏览器直接访问http://127.0.0.1:8080/userInfo,结果返回的是登录页面。
在这里插入图片描述
然后让我们看看代码和控制台打印的日志信息:
在这里插入图片描述
接口中输出的语句没有输出到控制台,输出的是自定义拦截器的preHandle拦截方法中的信息,由于用户没有登录,所以在调取用户信息接口的时候被拦截掉了。然后重定向到登录页面。这也证明了preHandle方法是在调取action之前执行的。
然后我们就登录一下,在访问连接看看。(登录里的信息随便填写。)

在这里插入图片描述
看到下面的页面,说明登录成功了。
在这里插入图片描述
,然后在访问userInfo(或者点击超链接)。查看控制台输出。
在这里插入图片描述
根据控制台的输入,可以发现执行顺序:preHandle() --> userInfo() --> preHandle() --> afterCompletion()。之前说了,preHandle()是在视图对象呈现前执行,而afterCompletion()是在视图对象呈现之后执行,是不是这样,只能看源码。。。。

从截图中可以得出结论,拦截器中的postHandle方法是在actin方法执行完后,才执行。是不是视图对象呈现前后需要看源码:
进入DispatcherServlet.doDispatch()中。
在这里插入图片描述
追进解析的方法中:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {
			//这部分是对异常的解析
		boolean errorView = false;
		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// 判断程序是否返回要呈现的视图 
		if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isTraceEnabled()) {
				logger.trace("No view rendering, null ModelAndView returned.");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}
		
		if (mappedHandler != null) {
		//这是执行拦截器的afterCompletion方法。自定义的也是在这里执行的
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

render()
在这里插入图片描述
triggerAfterCompletion()
在这里插入图片描述
然后代码就会进入自定义的AfterCompletion()方法中。所以从源码上可以看出,postHandle()是在返回mv之后呈现视图对象之前执行。而AfterCompletion()实在视图呈现之后执行。

第一次写博客,写的不好请见谅,写的不好的地方请指出。谢谢

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot允许我们自定义拦截拦截请求并进行一些逻辑处理。下面是SpringBoot定义拦截的步骤: 1.创建一个拦截类并实现HandlerInterceptor接口,该接口有三个方法:preHandle、postHandle和afterCompletion。其中preHandle方法在请求处理之前被调用,postHandle方法在请求处理之后被调用,afterCompletion方法在视图渲染之后被调用。 2.在拦截类上使用@Component注解将其注入到Spring容中。 3.创建一个配置类并实现WebMvcConfigurer接口,该接口有一个addInterceptors方法,可以用来添加自定义拦截。 4.在addInterceptors方法中添加自定义拦截,并指定拦截的路径。 下面是一个简单的示例: 1.创建一个拦截类并实现HandlerInterceptor接口: ```java @Component public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在请求处理之前进行逻辑处理 // 如果返回false,则请求不会被处理 return true; } } ``` 2.创建一个配置类并实现WebMvcConfigurer接口: ```java @Configuration public class MyWebMvcConfigurer implements WebMvcConfigurer { @Autowired private MyInterceptor myInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 添加自定义拦截,并指定拦截路径 registry.addInterceptor(myInterceptor).addPathPatterns("/**"); } } ``` 在上面的示例中,我们创建了一个名为MyInterceptor的拦截类,并将其注入到Spring容中。然后,我们创建了一个名为MyWebMvcConfigurer的配置类,并在其中添加了我们的自定义拦截,并指定了拦截的路径为“/**”。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值