如果您对【原创】遨游springmvc之HandlerAdapter和遨游客户端感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解【原创】遨游springmvc之HandlerAdapter的各种
如果您对【原创】遨游springmvc之HandlerAdapter和遨游客户端感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解【原创】遨游springmvc之HandlerAdapter的各种细节,并对遨游客户端进行深入的分析,此外还有关于HandlerAdapter与适配器模式以及SpringMVC核心接口、spring boot使用HandlerInterceptorAdapter+WebMvcConfigurerAdapter拦截、Spring MVC 中 HandlerInterceptorAdapter的使用、Spring MVC 中 HandlerInterceptorAdapter过滤器的使用的实用技巧。
本文目录一览:- 【原创】遨游springmvc之HandlerAdapter(遨游客户端)
- HandlerAdapter与适配器模式以及SpringMVC核心接口
- spring boot使用HandlerInterceptorAdapter+WebMvcConfigurerAdapter拦截
- Spring MVC 中 HandlerInterceptorAdapter的使用
- Spring MVC 中 HandlerInterceptorAdapter过滤器的使用
【原创】遨游springmvc之HandlerAdapter(遨游客户端)
1.前言
前一篇我们讲述了HandlerMapping,它返回了请求对应的controller实例和对应的处理方法,很多读者认为就完事了,其实不然。所以我们需要这一片来讲述一下HandlerAdapter的作用。HandlerAdapter是用来无线扩展DistapcherServlet的一个接口,通过适配器模式实现的,举个例子:读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。HandlerAdapter作用其实就跟这个读卡器差不多:它定义了如何处理请求的策略,将请求对应的参数和返回结果进行了一翻修饰,然后返回对应的视图ModelAndView。
HandlerAdapter定义了三个方法,如源码1.1:support方法的作用是判断处理适配器是不是支持该Handler。hanle方法,调用对应的Handler中适配到的方法,并返回一个ModelView,getLastModified返回请求最后被修改的时间,如果未知可以简单地返回-1
源码1.1
public interface HandlerAdapter {
/**
* Given a handler instance, return whether or not this {@code HandlerAdapter}
* can support it. Typical HandlerAdapters will base the decision on the handler
* type. HandlerAdapters will usually only support one handler type each.
* <p>A typical implementation:
* <p>{@code
* return (handler instanceof MyHandler);
* }
* @param handler handler object to check
* @return whether or not this object can use the given handler
*/
boolean supports(Object handler);
/**
* Use the given handler to handle this request.
* The workflow that is required may vary widely.
* @param request current HTTP request
* @param response current HTTP response
* @param handler handler to use. This object must have previously been passed
* to the {@code supports} method of this interface, which must have
* returned {@code true}.
* @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required
* model data, or {@code null} if the request has been handled directly
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* Same contract as for HttpServlet''s {@code getLastModified} method.
* Can simply return -1 if there''s no support in the handler class.
* @param request current HTTP request
* @param handler handler to use
* @return the lastModified value for the given handler
* @see javax.servlet.http.HttpServlet#getLastModified
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified
*/
long getLastModified(HttpServletRequest request, Object handler);
}
spring3.2之前会默认给我们提供3个适配器:
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter
AnnotationMethodHandlerAdaptor
缺省使用DefaultAnnotationHandlerMapping 来注册handler method和request的mapping关系。 AnnotationMethodHandlerAdapter来在实际调用handlermethod前对其参数进行处理。
其中3.2版本之后变成了
RequestMappingHandlerAdapter
通常在我们的spring-mvc的配置文件中我们会看到一行配置<mvc:annotation-driven/>,它提供了RequestMappingHandlerAdapter(还有RequestMappingHandlerMapping),RequestMappingHandlerAdapter适配了RequestMappingInfoHandlerMapping。
2.源代码解刨
RequestMappingHandlerAdapter在springmvc中其实算是一个非常重要的类
2.1.RequestMappingHandlerAdapter依赖图
2.2 源码解刨
初始化了一系列的参数解析器(参数解析器我们将在专门的一篇介绍,测出省略这些参数解析器的作用)
源码2.2.1
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
初始化了一系列的返回值处理器(和参数解析器一样将在专门一篇介绍)
源码2.2.2
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
最终处理请求的执行方法
源码2.2.3
/**
* Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
* if view resolution is required.
* @since 4.2
* @see #createInvocableHandlerMethod(HandlerMethod)
*/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//获取WebDataBinder,实现类型绑定转换,相当于一个转化工具,将参数转换成服务端真正需要的类型
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
//最终执行方法(包含参数解析,返回值包装)
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
处理返回值,并将之包装
源码2.2.4
/**
* Invokes the method and handles the return value through one of the
* configured {@link HandlerMethodReturnValueHandler}s.
* @param webRequest the current request
* @param mavContainer the ModelAndViewContainer for this request
* @param providedArgs "given" arguments matched by type (not resolved)
*/
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//包装结果
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取包装过的参数,已经经过参数解析器处理
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Invoking [");
sb.append(getBeanType().getSimpleName()).append(".");
sb.append(getMethod().getName()).append("] method with arguments ");
sb.append(Arrays.asList(args));
logger.trace(sb.toString());
}
//doInvoke执行方法返回结果
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
}
解析参数
源码2.2.6
/**
* Get the method argument values for the current request.
*/
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
//循环springmvc初始化的参数解析器
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//获得匹配的参数解析器,得到处理后的参数结果
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
throw new IllegalStateException(msg);
}
}
return args;
}
结果包装
源码2.2.7
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
//根据指定的HandlerMethodReturnValueHandler处理结果
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
3.小结
HandlerAdapter是在DispatcherServlet正真处理事情的家伙,这一步处理了原理图中的4、5、6、7部分
期待下一章WebDataBinder
发现一个机智的导航
HandlerAdapter与适配器模式以及SpringMVC核心接口
HandlerAdapter,顾名思义,是Handler的适配器,为了适配各种Handler,从而可以以统一的方式获取ModelAndView。
// request => Handler
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request);
}
//常用:
// - BeanNameUrlHandlerMapping
// - RequestMappingHandlerMapping
// Handler => ModelAndView
public interface HandlerAdapter {
boolean support(Object handler);
ModelAndView handler(HttpServletRequest request, HttpServletResponse response, Object handler);
long getLastModified(HttpServletRequest request, Object handler);
}
//常用:
// - HttpRequestHandlerAdapter
// - SimpleControllerHandlerAdapter
// - RequestMappingHandlerAdapter
// viewName => View
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale);
}
//常用:
// - InternalResourceViewResolver
// - FreeMarkerViewResolver
// - ThymeleafViewResolver
// 渲染
public interface View {
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response);
}
//常用:
// - InternalResourceView
// - FreeMarkerView
// - ThymeleafView
这段话说的很好:
springmvc通过HandlerMapping获取到可以处理的handler,这些handler的类型各不相同,对请求的预处理,参数获取都不相同,最简单的做法是根据不同的handler类型,做一个分支处理,不同的handler编写不同的代码。
这样的问题是很明显的,分支判断复杂,代码庞大,不符合单一职责原则。如果要增加一种handler类型,需要修改代码增加分支处理,违反了开闭原则。DispatcherServelt与多个handler发生了交互,违反迪米特法则。
而使用适配器模式,就可以很好的解决这个问题:
不直接对handler进行处理,而是将handler交给适配器HandlerAdapter去处理,这样DispatcherServlet交互的类就只剩下一个接口,HandlerAdapter,符合迪米特法则,尽可能少的与其他类发生交互;
将handler交给HandlerAdapter处理后,不同类型的handler被对应类型的HandlerAdapter处理,每个HandlerAdapter都只完成单一的handler处理,符合单一职责原则;
如果需要新增一个类型的handler,只需要新增对应类型的HandlerAdapter就可以处理,无需修改原有代码,符合开闭原则。
这样,不同的handler的不同处理方式,就在HandlerAdapter中得到了适配,对于DispatcherServlet来讲,只需要统一的调用HandlerAdapter的handle()方法就可以了,无需关注不同handler的处理细节。
设计模式的原则 1.单一职责原则 一个类只完成单一的功能,粒度越小越好
2.开闭原则 对扩展开放,对修改关闭。 一个类开发完成后,应当可以通过扩展的方式实现新的功能,而不是通过修改原有类来达到目的。
3.里氏替换原则 所有引用父类的地方都可以透明的使用其子类
4.依赖倒置原则 抽象不应该依赖于细节,细节应该依赖于抽象。 应该针对接口或抽象类编程,而不是针对具体的实现编程
5.接口隔离原则 接口的划分应该更细致,使用多个功能单一的接口,而不是将所有的功能放到一个接口中实现,客户端不应该去依赖它所不需要的接口方法。
6.迪米特法则 一个类应尽可能少的与其他类进行交互。降低耦合。
参考链接:http://blog.sina.com.cn/s/blog_e660c25b01030kbj.html
spring boot使用HandlerInterceptorAdapter+WebMvcConfigurerAdapter拦截
最近在做考试系统,是个微信小程序,页面都是前端那里做好的,数据都是调的后端接口,自然后端就使用到了拦截器。时间有点紧,这篇只是大概写个结构,以后再补。
1.HandlerInterceptorAdapter
preHandle 业务处理器在处理业务之前被调用,预处理。
postHandle 在业务处理之后调用,后处理,
afterCompletion 在DispatcherServlet完全处理完请求后被调用,可用于清理资源。也可以根据ex是否为null来判断是否发生了异常。
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author suwan
*/
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String url = request.getRequestURI().toString();
System.out.println("preHandle:" + url);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
String url = request.getRequestURI().toString();
System.out.println("postHandle:" + url);
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion:" + ex);
super.afterCompletion(request, response, handler, ex);
}
}
2.WebMvcConfigurerAdapter添加拦截器
addInterceptors 需要一个实现HandlerInterceptor接口的拦截器实例
addPathPatterns 用于设置拦截器的过滤路径规则
excludePathPatterns:用于设置不需要拦截的过滤规则
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @author suwan
*/
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor()).addPathPatterns("/login/**").excludePathPatterns("/hello/**");
}
@Bean
public LoginInterceptor loginInterceptor(){return new LoginInterceptor();}
}
3.测试设置拦截器的路径
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author suwan
*/
@RestController
@RequestMapping("/login")
public class UserController {
@GetMapping("/test")
public void test(){
System.out.println("loginTest");
}
}
浏览器请求:http://localhost:8080/login/test
输出:
preHandle:/login/test
loginTest
postHandle:/login/test
afterCompletion:null
4.测试未设置拦截的路径
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author suwan
* @date 2019/6/13
*/
@RestController
@RequestMapping("/hello")
public class HelloController {
@GetMapping("/test")
public void test(){
System.out.println("helloTest");
}
}
浏览器请求:http://localhost:8080/hello/test
输出:
helloTest
Spring MVC 中 HandlerInterceptorAdapter的使用
一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的,这种方式可以实现Bean预处理、后处理。
Spring MVC的拦截器不仅可实现Filter的所有功能,还可以更精确的控制拦截精度。
Spring为我们提供了org.springframework.web.servlet.handler.HandlerInterceptorAdapter这个适配器,继承此类,可以非常方便的实现自己的拦截器。他有三个方法:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
如果基于xml配置使用Spring MVC,
可以利用SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping进行Url映射(相当于struts的path映射)和拦截请求(注入interceptors),
如果基于注解使用Spring MVC,可以使用DefaultAnnotationHandlerMapping注入interceptors。
注意无论基于xml还是基于注解,HandlerMapping bean都是需要在xml中配置的。
一个demo:
在这个例子中,我们假设UserController中的注册操作只在9:00-12:00开放,那么就可以使用拦截器实现这个功能。
public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
private int openingTime;
private int closingTime;
private String mappingURL;//利用正则映射到需要拦截的路径
public void setOpeningTime(int openingTime) {
this.openingTime = openingTime;
}
public void setClosingTime(int closingTime) {
this.closingTime = closingTime;
}
public void setMappingURL(String mappingURL) {
this.mappingURL = mappingURL;
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String url=request.getRequestURL().toString();
if(mappingURL==null || url.matches(mappingURL)){
Calendar c=Calendar.getInstance();
c.setTime(new Date());
int now=c.get(Calendar.HOUR_OF_DAY);
if(now<openingTime || now>closingTime){
request.setAttribute("msg", "注册开放时间:9:00-12:00");
request.getRequestDispatcher("/msg.jsp").forward(request, response);
return false;
}
return true;
}
return true;
}
}
xml配置:
<bean id="timeBasedAccessInterceptor" >
<property name="openingTime" value="9" />
<property name="closingTime" value="12" />
<property name="mappingURL" value=".*/user\.do\?action=reg.*" />
</bean>
<bean >
<property name="interceptors">
<list>
<ref bean="timeBasedAccessInterceptor"/>
</list>
</property>
</bean>
这里我们定义了一个mappingURL属性,实现利用正则表达式对url进行匹配,从而更细粒度的进行拦截。当然如果不定义mappingURL,则默认拦截所有对Controller的请求。
UserController:
@Controller
@RequestMapping("/user.do")
public class UserController{
@Autowired
private UserService userService;
@RequestMapping(params="action=reg")
public ModelAndView reg(Users user) throws Exception {
userService.addUser(user);
return new ModelAndView("profile","user",user);
}
// other option ...
}
这个Controller相当于Struts的DispatchAction
Spring MVC 中 HandlerInterceptorAdapter过滤器的使用
一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的,这种方式可以实现Bean预处理、后处理。
Spring MVC的拦截器不仅可实现Filter的所有功能,还可以更精确的控制拦截精度。
Spring为我们提供了org.springframework.web.servlet.handler.handlerinterceptorAdapter这个适配器,继承此类,可以非常方便的实现自己的拦截器。他有三个方法:
一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的,这种方式可以实现Bean预处理、后处理。
Spring MVC的拦截器不仅可实现Filter的所有功能,还可以更精确的控制拦截精度。
Spring为我们提供了org.springframework.web.servlet.handler.handlerinterceptorAdapter这个适配器,继承此类,可以非常方便的实现自己的拦截器。他有三个方法:
public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler)
throws Exception {
return true;
}
public void postHandle(
HttpServletRequest request,Object handler,ModelAndView modelAndView)
throws Exception {
}
public void afterCompletion(
HttpServletRequest request,Exception ex)
throws Exception {
}
分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
如果基于xml配置使用Spring MVC,
可以利用SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping进行Url映射(相当于struts的path映射)和拦截请求(注入interceptors),
如果基于注解使用Spring MVC,可以使用DefaultAnnotationHandlerMapping注入interceptors。
注意无论基于xml还是基于注解,HandlerMapping bean都是需要在xml中配置的。
一个demo:
在这个例子中,我们假设UserController中的注册操作只在9:00-12:00开放,那么就可以使用拦截器实现这个功能。
public class TimeBasedAccessInterceptor extends handlerinterceptorAdapter {
private int openingTime;
private int closingTime;
private String mappingURL;//利用正则映射到需要拦截的路径
public void setopeningTime(int openingTime) {
this.openingTime = openingTime;
}
public void setClosingTime(int closingTime) {
this.closingTime = closingTime;
}
public void setMappingURL(String mappingURL) {
this.mappingURL = mappingURL;
}
@Override
public boolean preHandle(HttpServletRequest request,Object handler) throws Exception {
String url=request.getRequestURL().toString();
if(mappingURL==null || url.matches(mappingURL)){
Calendar c=Calendar.getInstance();
c.setTime(new Date());
int Now=c.get(Calendar.HOUR_OF_DAY);
if(Now<openingTime || Now>closingTime){
request.setAttribute("msg","注册开放时间:9:00-12:00");
request.getRequestdispatcher("/msg.jsp").forward(request,response);
return false;
}
return true;
}
return true;
}
}
xml配置:
<bean id="timeBasedAccessInterceptor">
<property name="openingTime" value="9" />
<property name="closingTime" value="12" />
<property name="mappingURL" value=".*/user\.do\?action=reg.*" />
</bean>
<bean>
<property name="interceptors">
<list>
<ref bean="timeBasedAccessInterceptor"/>
</list>
</property>
</bean>
这里我们定义了一个mappingURL属性,实现利用正则表达式对url进行匹配,从而更细粒度的进行拦截。当然如果不定义mappingURL,则默认拦截所有对Controller的请求。
UserController:
@Controller
@RequestMapping("/user.do")
public class UserController{
@Autowired
private UserService userService;
@RequestMapping(params="action=reg")
public ModelAndView reg(Users user) throws Exception {
userService.addUser(user);
return new ModelAndView("profile","user",user);
}
// other option ...
}
这个Controller相当于Struts的dispatchAction
你也可以配置多个拦截器,每个拦截器进行不同的分工.
我们项目里面的例子
package com.shishuo.studio.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handlerinterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.shishuo.studio.entity.User;
import com.shishuo.studio.exception.CookieNotFoundException;
import com.shishuo.studio.service.UserService;
import com.shishuo.studio.util.CookieUtils;
/**
* @author Herbert 拦截器的实现
*/
@Component
public class AuthInterceptor implements handlerinterceptor {
@Autowired
private UserService userService;
public void afterCompletion(HttpServletRequest request,HttpServletResponse respone,Object object,Exception exception)
throws Exception {
// Todo Auto-generated method stub
}
public void postHandle(HttpServletRequest request,ModelAndView modelAndView) throws Exception {
}
public boolean preHandle(HttpServletRequest request,Object handler) throws Exception {
try {
User user = userService.getUserById(request);
if (userService.checkAuth(user,request,response)) {
return true;
} else {
response.sendRedirect("/user/login.htm");
return false;
}
} catch (Exception e) {
e.printstacktrace();
}
response.sendRedirect("/user/login.htm");
return false;
}
}
package com.shishuo.studio.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handlerinterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.shishuo.studio.service.CategoryService;
/**
* @author Herbert
*
*/
@Component
public class GlobalInterceptor implements handlerinterceptor {
@Autowired
private CategoryService categoryService;
@Override
public boolean preHandle(HttpServletRequest request,Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request,ModelAndView modelAndView) throws Exception {
if (null == modelAndView) {
return;
}
// 系统配置参数
modelAndView.addobject("categoryList",categoryService.getCategorylistofdisplayByFatherId(0));
}
@Override
public void afterCompletion(HttpServletRequest request,Exception ex)
throws Exception {
// Todo Auto-generated method stub
}
}
package com.shishuo.studio.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handlerinterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.shishuo.studio.entity.User;
import com.shishuo.studio.entity.vo.StudioVo;
import com.shishuo.studio.exception.StudioNotFoundException;
import com.shishuo.studio.service.StudioService;
import com.shishuo.studio.service.UserService;
/**
* @author Herbert
*
*/
@Component
public class StudioInterceptor implements handlerinterceptor {
@Autowired
private StudioService studioService;
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request,Object handler) throws Exception {
User user = userService.getUserById(request);
try {
StudioVo studio = studioService.getStudioById(user.getUserId());
return true;
} catch (StudioNotFoundException e) {
response.sendRedirect("/auth/teacher/studio.htm");
return false;
}
}
@Override
public void postHandle(HttpServletRequest request,ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request,Exception ex)
throws Exception {
}
}
今天的关于【原创】遨游springmvc之HandlerAdapter和遨游客户端的分享已经结束,谢谢您的关注,如果想了解更多关于HandlerAdapter与适配器模式以及SpringMVC核心接口、spring boot使用HandlerInterceptorAdapter+WebMvcConfigurerAdapter拦截、Spring MVC 中 HandlerInterceptorAdapter的使用、Spring MVC 中 HandlerInterceptorAdapter过滤器的使用的相关知识,请在本站进行查询。
本文标签: