SpringBoot版本:2.1.6.RELEASE
SpringMVC版本:5.1.8.RELEASE

SpringMVC拦截器

比如说在SpringMVC Web环境下,需要实现一个权限拦截的功能,一般情况下,大家都是实现了org.springframework.web.servlet.AsyncHandlerInterceptor或者org.springframework.web.servlet.HandlerInterceptor接口,从而实现的SpringMVC拦截。而要实现拦截功能,通常都是通过preHandle方法返回false拦截。

拦截器的preHandle

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return false;
}

那么拦截后,如果你什么都不做,会直接返回空页面,页面上什么也没有。如果要返回结果,需要自己给response写数据。简单的写法网上很多,这里不赘述,这里将会讲解如何通过SpringMVC本身的处理机制在拦截后返回结果。

拦截后返回结果

拦截后返回数据通常是两种,第一种如果是返回的Restful接口,那么返回一个json数据即可,第二种如果返回的是一个页面,那么需要返回错误页面(比如无权限页面)。

SpringMVC的所有结果都是通过HandlerMethodReturnValueHandler接口的实现类返回的,无论是Json,还是View。因此可以通过具体的实现类返回我们想要的数据。与之对应的还有``,这些所有的参数和返回结果的处理器,都定义在RequestMappingHandlerAdapter中,这个Adapter可以从容器中获取到。这里我们主要用到的只有两个RequestResponseBodyMethodProcessorViewNameMethodReturnValueHandler

返回纯数据

返回纯数据,适用于返回Controller的方法通过@ResponseBody标注了。因此需要用到RequestResponseBodyMethodProcessor
RequestResponseBodyMethodProcessor里面对不同的数据会有不同的处理方式,一般都是处理为json,具体实现可以看HttpMessageConverter的实现类。这里是直接将结果写到了response中。实现代码在文末。

返回视图

返回视图,适用于返回Controller的方法通过是个String,其实是ViewName。因此需要用到ViewNameMethodReturnValueHandler

通过查看DispatcherServlet代码会发现,其实preHandle方法执行在RequestMappingHandlerAdapter执行前,所以没有ModelAndView生成,因此需要自己向Response里面写数据。这里只是借助了RequestMappingHandlerAdapter生产需要写入的数据。然后通过抛出异常ModelAndViewDefiningException,从而将我们的生产的ModeAndView透出给Spring进行渲染DispatcherServlet#processDispatchResult

实现代码在文末。

直接使用视图解析器方法

如果你知道自己的视图解析器是谁,那么还有一个方法,比如,我用的是Velocity的视图解析器,Velocity的视图解析器配置的beanName是velocityViewResolver,因此可以用下面的方法实现。

String viewName = "yourViewName";
UrlBasedViewResolver viewResolver = (UrlBasedViewResolver) SpringContextHolder.getBean("velocityViewResolver");
View view = viewResolver.resolveViewName(viewName, Locale.CHINA);
if (view == null) {throw new RuntimeException("cannot find " + viewName + " view.");
}
view.render(null, request, response);

完整代码实现

package com.xxxx.interceptor;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.ModelAndViewDefiningException;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;/*** 基础拦截器,通过@Configuration自行配置为Bean,可以配置成多个拦截器。** @author obiteaaron* @since 2019/12/26*/
public class BaseInterceptor implements AsyncHandlerInterceptor {private static final Logger LOGGER = LoggerFactory.getLogger(BaseInterceptor.class);private ApplicationContext applicationContext;protected InterceptorPreHandler interceptorPreHandler;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {boolean checkResult = interceptorPreHandler.check(request, response, handler);if (!checkResult) {postInterceptor(request, response, handler);return false;} else {return true;}}/*** 拦截后处理*/protected void postInterceptor(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 如果被拦截,返回信息if (((HandlerMethod) handler).getMethodAnnotation(ResponseBody.class) != null) {// 返回jsonHandlerMethod handlerMethod = new HandlerMethod(((HandlerMethod) handler).getBean(), ((HandlerMethod) handler).getMethod());Object returnValue = interceptorPreHandler.getResponseBody();MethodParameter returnValueType = handlerMethod.getReturnValueType(returnValue);applicationContext.getBean(RequestMappingHandlerAdapter.class).getReturnValueHandlers();RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = findRequestResponseBodyMethodProcessor();requestResponseBodyMethodProcessor.handleReturnValue(returnValue, returnValueType, new ModelAndViewContainer(), new ServletWebRequest(request, response));// end} else {// 返回页面HandlerMethod handlerMethod = new HandlerMethod(((HandlerMethod) handler).getBean(), ((HandlerMethod) handler).getMethod());String viewName = interceptorPreHandler.getViewName();MethodParameter returnValueType = handlerMethod.getReturnValueType(viewName);ViewNameMethodReturnValueHandler viewNameMethodReturnValueHandler = findViewNameMethodReturnValueHandler();ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();// viewNameMethodReturnValueHandler 内的实现非常简单,其实可以不用这个的,直接new ModelAndViewContainer()就好了。viewNameMethodReturnValueHandler.handleReturnValue(viewName, returnValueType, modelAndViewContainer, new ServletWebRequest(request, response));// 抛出异常由Spring处理ModelMap model = modelAndViewContainer.getModel();ModelAndView modelAndView = new ModelAndView(modelAndViewContainer.getViewName(), model, modelAndViewContainer.getStatus());throw new ModelAndViewDefiningException(modelAndView);// end}}private RequestResponseBodyMethodProcessor findRequestResponseBodyMethodProcessor() {RequestMappingHandlerAdapter requestMappingHandlerAdapter = applicationContext.getBean(RequestMappingHandlerAdapter.class);for (HandlerMethodReturnValueHandler value : Objects.requireNonNull(requestMappingHandlerAdapter.getReturnValueHandlers())) {if (value instanceof RequestResponseBodyMethodProcessor) {return (RequestResponseBodyMethodProcessor) value;}}// SpringMVC的环境下一定不会走到这里throw new UnsupportedOperationException("cannot find RequestResponseBodyMethodProcessor from RequestMappingHandlerAdapter by Spring Context.");}private ViewNameMethodReturnValueHandler findViewNameMethodReturnValueHandler() {RequestMappingHandlerAdapter requestMappingHandlerAdapter = applicationContext.getBean(RequestMappingHandlerAdapter.class);for (HandlerMethodReturnValueHandler value : Objects.requireNonNull(requestMappingHandlerAdapter.getReturnValueHandlers())) {if (value instanceof ViewNameMethodReturnValueHandler) {return (ViewNameMethodReturnValueHandler) value;}}// SpringMVC的环境下一定不会走到这里throw new UnsupportedOperationException("cannot find ViewNameMethodReturnValueHandler from RequestMappingHandlerAdapter by Spring Context.");}public void setApplicationContext(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}public void setInterceptorPreHandler(InterceptorPreHandler interceptorPreHandler) {this.interceptorPreHandler = interceptorPreHandler;}public interface InterceptorPreHandler {/*** @see HandlerInterceptor#preHandle(HttpServletRequest, HttpServletResponse, Object)*/boolean check(HttpServletRequest request, HttpServletResponse response, Object handler);/*** 拦截后返回的视图名称** @see ModelAndView* @see ViewNameMethodReturnValueHandler*/String getViewName();/*** 拦截后返回的对象** @see ResponseBody* @see RequestResponseBodyMethodProcessor*/Object getResponseBody();}
}

SpringBoot下注册拦截器:org.springframework.web.servlet.config.annotation.WebMvcConfigurer#addInterceptors

结尾

其他类型的实现,可以自行实现。

SpringMVC拦截器HandlerInterceptor拦截后返回数据或视图View相关推荐

  1. springboot项目拦截器中获取接口返回数据_Spring Boot自定义Annotation实现接口自动幂...

    在实际的开发项目中,一个对外暴露的接口往往会面临很多次请求,我们来解释一下幂等的概念:任意多次执行所产生的影响均与一次执行的影响相同.按照这个含义,最终的含义就是 对数据库的影响只能是一次性的,不能重 ...

  2. java 拦截器HandlerInterceptor 自定义返回结果

    Java的拦截器HandlerInterceptor允许你在请求处理之前或之后自定义返回结果.你可以通过实现HandlerInterceptor接口并重写其中的三个方法来实现自定义拦截器: publi ...

  3. SpringMVC拦截器HandlerInterceptor使用

    Spring MVC 拦截器(HandlerInterceptor)使用 Spring 拦截器--HandlerInterceptor 转载于:https://www.cnblogs.com/goto ...

  4. spring mvc拦截器HandlerInterceptor

    本文主要介绍springmvc中的拦截器,包括拦截器定义和的配置,然后演示了一个链式拦截的测试示例,最后通过一个登录认证的例子展示了拦截器的应用 拦截定义 定义拦截器,实现HandlerInterce ...

  5. JavaWeb——拦截器HandlerInterceptor

    一.引言 直接就知道拦截器这个概念,感觉没啥用没怎么用过,又重新看到了复习了下感觉用处大大的,登陆验证之类的都能用得到== 二.拦截器原理及应用场景 1.SpringWebMVC的处理器拦截器,类似于 ...

  6. 【Java Web开发学习】Spring MVC 拦截器HandlerInterceptor

    [Java Web开发学习]Spring MVC 拦截器HandlerInterceptor 转载:https://www.cnblogs.com/yangchongxing/p/9324119.ht ...

  7. 拦截器HandlerInterceptor+方法参数解析器HandlerMethodArgumentResolver用于统一获取当前登录用户信息

    文章目录 前言 一.拦截器+方法参数解析器 是什么? 二.具体实现步骤 1.自定义权限拦截器LoginInterceptor拦截所有request请求,并将token解析为currentUser,最终 ...

  8. springmvc拦截器无法拦截jsp

    为什么80%的码农都做不了架构师?>>>    问题:spring mvc的拦截器只拦截controller不拦截jsp文件,如果不拦截jsp文件也会给系统带安全性问题. 解决方案: ...

  9. java 登录拦截器_springMVC 拦截器-用户登录拦截实战

    各位小伙伴 咱们继续学习新知识 今天要分享的就是 拦截器 不知道小伙伴们平时上网的时候有没有注意到,尤其是上网购物的时候,不登录账号,就无法访问一些功能页面,比如你不登录账号,就没法查看购物车里面有什 ...

最新文章

  1. ajax走error的条件,Ajax进入ERROR的部分条件总结
  2. 毕业设计(3)基于MicroPython的篮球计时计分器模型的设计与实现
  3. 利用抽象工厂创建DAO、利用依赖注入去除客户端对工厂的直接依赖、将有关Article的各种Servlet封装到一个Servlet中(通过BaseServlet进行
  4. PSAM卡---中国人民银行PSAM卡管理规范.doc
  5. linux删除物理卷命令,如何安全的删除Linux LVM中的PV物理卷(硬盘或分区
  6. 这些职场办公神器,你会喜欢的!
  7. php 图片生成vr_PHP 使用Krpano 生成全景图
  8. leetcode125验证回文串
  9. 关于C/C++中的“auto”关键字
  10. flask 必知必会
  11. Kafka 分布式消息系统 基础概念剖析
  12. GlusterFS更换故障Brick
  13. php测试数组函数,PHP-数组函数
  14. cf1299C-Water Balance
  15. 用计算机绘制滴定曲线,利用Excel系统绘制酸碱滴定曲线
  16. linux怎么设置raid,如何在Linux中配置RAID-教程
  17. ns-3中的数据跟踪与采集——Tracing系统的配置
  18. 用js写一个简单的前世今生
  19. [附源码]计算机毕业设计springboot交通事故档案管理系统
  20. Game boy模拟器(7):精灵

热门文章

  1. 钉钉完全等同于OA办公系统吗?
  2. r语言 svm 大样本_R语言数据分析实战:十大算法之SVM模型 - 数据分析
  3. 应届生白手起家当老板
  4. petalinux vdma 学习笔记
  5. if [ $? -ne 0 ];then 是什么意思
  6. 拷贝构造函数和赋值函数
  7. 佳能Canon PIXMA MX330 打印机驱动
  8. ninja: error: manifest ‘build.ninja‘ still dirty after 100 tries
  9. 微信小程序页面传值的几种方式总结
  10. 解决macOS13安装Fusion13闪退的问题