场景:
SpringMVC Controller类中不同的方法对应不同的Rest请求地址和逻辑视图返回地址,但是为了模块化,各个方法的Rest地址前缀和返回逻辑视图的地址前缀都应该相同。其中请求Rest地址的前缀可以在类上用@RequestMapping声明,而返回视图的逻辑地址前缀仍需要手动写。本文通过使用Spring MVC拦截器为Controller类方法返回的逻辑视图动态添加了模块Rest地址前缀,因此,在Controller类的方法只需要返回逻辑视图名称。
拦截器代码:
package com; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class ViewInterceptor extends HandlerInterceptorAdapter { //Controller类名称 <-> Controller类映射地址 private Map<String, String> ControllerRestPathMap = new HashMap<String, String>() ; /** * 拦截返回的逻辑视图,并在逻辑视图上加上Controller映射地址 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { String requestRest = (String)request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE) ; //获取spring web容器 WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext()) ; //获取声明类在spring容器中的名称 String[] beanNames = webApplicationContext.getBeanNamesForType(((HandlerMethod) handler).getMethod().getDeclaringClass()) ; for (String beanName : beanNames) { if(!StringUtils.hasLength(beanName)){ continue ; } //映射当前类的Rest地址 if(ControllerRestPathMap.get(beanName)==null){ //获取类的映射Rest地址 RequestMapping requestMapping = webApplicationContext.findAnnotationOnBean(beanName, RequestMapping.class) ; if(requestMapping!=null&&!ObjectUtils.isEmpty(requestMapping.value())){ String basePath = requestMapping.value()[0] ; //去掉类请求地址后缀“/” if(basePath.lastIndexOf("/")==basePath.length()-1){ basePath = basePath.substring(0, basePath.length()-1) ; } ControllerRestPathMap.put(beanName, basePath) ; } } //根据请求Rest地址前缀匹配处理的类 if(ControllerRestPathMap.get(beanName)!=null&&requestRest.startsWith(ControllerRestPathMap.get(beanName))){ modelAndView.setViewName(ControllerRestPathMap.get(beanName)+"/"+modelAndView.getViewName()); break ; } } // System.out.println("映射地址 -> "+modelAndView.getViewName()); } }
注:
1.Controller类中每个方法对应的Rest地址,以属性的型式存放在Request中。可以通过如下方式获取: request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)
2.拦截Rest地址匹配策略:根据Rest地址的匹配方式,查找处理它的Controller类。找到Controller类之后,将Controller类的逻辑视图地址加到方法返回逻辑地址前面,构成完整的逻辑视图地址。
在Spring MVC配置文件中装载拦截器:
<mvc:interceptors> <bean class="com.ViewInterceptor"></bean> </mvc:interceptors>