Spring mvc做爲一個web mvc框架的後起之秀,其易用性,拓展性則實讓人在使用之餘,讚歎不已。本文從Spring mvc的Controller的執行過程當中,找出一些開發者用到的幾個拓展點。 html
首先,按前後順序列一下Spring mvc中controller的執行過程: java
1. 執行全部的攔截器(實現HandlerInterceptor接口的類); web
2. 調用controller方法以前,對方法參數進行解釋綁定(實現WebArgumentResolver接口,spring3.1之後推薦使用HandlerMethodArgumentResolver); spring
3. 調用controller方法,返回邏輯視圖(一般是一個視圖的名稱); session
4. 將邏輯視圖映射到物理視圖(使用實現ViewResolver接口的類處理); mvc
5. 物理視圖渲染輸出到客戶端(實現View接口); app
6. 若在以上執行過程當中拋出了異常,能夠自定義異常處理器對不一樣的異常進行處理(實現HandlerExceptionResolver接口)。 框架
開發者經過實現以上的接口(通常狀況下不須要從接口實現,經過繼承Spring mvc實現的一些抽象類更簡單),就能夠自定義controller執行過程當中的一些行爲,從而讓程序更富靈活性。 ide
如下是幾個經常使用的例子: post
1. 自定義攔截器,攔截未登陸用戶的請求。
AuthorityInterceptor.java
@Component public class AuthorityInterceptor extends HandlerInterceptorAdapter{ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Integer userId = (Integer)request.getSession().getAttribute("userId"); //登陸才能夠繼續訪問 if (userId != null) { return true; } String contextPath = request.getContextPath(); response.sendRedirect(contextPath + "/index.html"); return false; } }
applicationContext-mvc.xml添加配置:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/user/**"/> <ref bean="authorityInterceptor"/> </mvc:interceptor> </mvc:interceptors>
值得一提的是:HandlerInterceptor接口有三個方法,preHandle在controller方法調用前攔截,postHandle在controller方法調用後攔截,afterCompletion在客戶端請求處理結束後(controller方法調用後,返回視圖,而且視圖已經渲染輸出後)攔截。
2. 自定義controller方法參數的解釋器,從session從取值綁定到方法參數。
SessionValue.java
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SessionValue { String value() default ""; }
SessionValueResolver.java
@Component public class SessionValueResolver implements WebArgumentResolver { @Override public Object resolveArgument(MethodParameter parameter, NativeWebRequest webRequest) throws Exception { SessionValue svAnnotation = parameter.getParameterAnnotation(SessionValue.class); if(svAnnotation == null) { return WebArgumentResolver.UNRESOLVED; } return _resolveArgument(parameter, webRequest); } private Object _resolveArgument(MethodParameter parameter, NativeWebRequest webRequest) throws Exception { SessionValue sessionValueAnnot = parameter.getParameterAnnotation(SessionValue.class); String attrName = sessionValueAnnot.value(); if(attrName == null || attrName.equals("")) { attrName = parameter.getParameterName(); } HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); Object value = request.getSession().getAttribute(attrName); if(value == null) { throw new Exception("SessionValueResolver: session 內沒有該屬性:" + attrName); } return value; } }
applicationContext-mvc.xml添加配置:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="customArgumentResolvers"> <list> <ref bean="sessionValueResolver"/> </list> </property> <property name="order" value="1"></property> </bean>
在controller中使用:
@RequestMapping("/get") public String getUser(@SessionValue("userId")Integer userId) { //do something return "user"; }
3. 自定義文件視圖解釋器,在controller方法裏返回文件路徑,實現文件下載
FileViewResolver.java
public class FileViewResolver extends AbstractCachingViewResolver implements Ordered{ private int order = Integer.MAX_VALUE; @Override protected View loadView(String viewName, Locale locale) throws Exception { if(viewName.startsWith(FileView.FILE_VIEW_PREFIX)) { return new FileView(viewName); } return null; } @Override public int getOrder() { return this.order; } public void setOrder(int order) { this.order = order; } }
FileView.java
public class FileView extends AbstractView { public static final String FILE_VIEW_PREFIX = "file:"; private String viewName; public FileView(String viewName) { this.viewName = viewName; } @Override protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { File file = getOutputFile(); downloadFile(request, response, file); } private File getOutputFile() throws Exception { Integer beginIndex = viewName.indexOf(FILE_VIEW_PREFIX) + FILE_VIEW_PREFIX.length(); String filePath = viewName.substring(beginIndex).trim(); File file = new File(filePath); if(file.exists()) { return file; } throw new Exception("下載的文件不存在: " + filePath); } private void downloadFile(HttpServletRequest request, HttpServletResponse response, File file) { //將文件寫入輸出流 } }
applicationContext-mvc.xml添加配置:
<bean class="com.plugin.FileViewResolver"> <property name="order" value="1" /> </bean>
在controller中使用:
@RequestMapping("/download") public String download() { String filePath = "f://download/text.txt"; return "file:" + filePath; }
4. 自定義異常處理,拋出如下異常時,返回錯誤頁面
CustomExceptionResolver.java
@Component public class CustomExceptionResolver implements HandlerExceptionResolver { private static List<String> exceptionList; static{ exceptionList = new ArrayList<String>(); exceptionList.add("InvalidExcelException"); exceptionList.add("NoSuchCourseExcption"); exceptionList.add("NoTraineeExcption"); exceptionList.add("NoQuestionExcption"); } @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { if(exceptionList.contains(ex.getClass().getSimpleName())) { return new ModelAndView("error"); } return null; } }
自定義異常處理器只須要成爲spring容器的bean,無需其它配置。
Spring mvc使用拓展點介紹結束。
各位Oscer,如有關於Spring mvc使用的優秀實踐,請不吝分享,分享快樂。