我們今天來介紹一個SpringMVC的基本配置,靈活的使用這些配置,可以讓我們在開發中更加靈活的處理業務邏輯。
OK,廢話不多說,那就開始吧。
SpringMVC基礎配置(通過注解配置,非xml配置)這篇文章中我們的案例都會有一個MvcConfig的類用來做一個簡單的配置,主要是通過ViewResolver來解決映射路徑和實際頁面的位置,這個類我們還可以繼續擴展,讓其解決更多的問題,我列舉幾個:
- 靜態資源映射
- 攔截器使用
- 全局配置問題
等等。這些問題我們可以重新定義一個新的類來解決,也可以擴展MvcConfig來解決。我們來一個個看看。
靜態資源映射
我們都知道在SpringMVC中靜態資源文件都是直接訪問的,而不需要映射,這些靜態資源主要包括js文件、css文件、圖片文件等,那么這個需要我們單獨處理,否則系統會找不到路徑。OK,這個問題的解決也很容易,假設我有一張圖片放在src/main/resources/assets/img目錄下,然后想在jsp頁面中將其展示出來,我們先來看看jsp頁面:
<%@ page contentType="text/html;charset=UTF-8" language="JAVA" %><html><head><title>Hello Sang!</title></head><body><p>Welcome To SpringMVC World!</p><p><img src="../assets/img/1.png"></p></body></html>
然后我們創建MVCConfig類,作用還是和上文一樣,不同的是這次我們繼承自WebMvcConfigurerAdapter,然后重寫WebMvcConfigurerAdapter類中的addResourceHandlers方法來解決這個問題。如下:
@Configuration@EnableWebMvc@ComponentScan("org.sang")public class MVCConfig extends WebMvcConfigurerAdapter{@Beanpublic InternalResourceViewResolver viewResolver() {InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setPrefix("/WEB-INF/classes/views/");viewResolver.setSuffix(".jsp");viewResolver.setViewClass(JstlView.class);return viewResolver;}/*** /**的意思是所有文件,包括文件夾中的子文件* /*是所有文件,不包含子文件* /是web項目的根目錄* @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {//兩個*表示以/assets開始的任意層級的路徑都可以訪問得到圖片,如<img src="../assets/img/1.png">//一個*表示只可以訪問assets目錄下的圖片文件registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");}}
OK,這里繼承WebMvcConfigureAdapter之后,我們可以重寫它里邊的很多方法,重寫這些方法我們可以對SpringMVC進行配置,addResourceHandler指的是訪問路徑,addResourceLocations指的是文件放置目錄。
攔截器
攔截器在JavaEE開發中還是非常重要的,亂碼解決、權限控制等等都會用到,使用Servlet的時候有一個Filter類用來進行過濾,那么SpringMVC也在這方面給我們提供了相應的解決方案。
定義攔截器
攔截器的定義我們可以通過繼承HandlerInterceptorAdapter或者實現HandlerInterceptor接口,我這里以實現接口為例:
public class MyInterceptors implements HandlerInterceptor {public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {System.out.println("preHandle");return true;}public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {System.out.println("postHandle");}public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {System.out.println("afterCompletion");}}
preHandle方法發生在請求發生前執行,postHandle發生在請求發生后執行,afterCompletion在請求完成時執行,實際上執行時機緊挨著postHandle這個方法。然后在MVCConfig類中添加addInterceptors方法注冊攔截器,如下:
@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myInterceptors());}@Beanpublic MyInterceptors myInterceptors() {return new MyInterceptors();}
這樣注冊成功之后,我們在瀏覽器中訪問時,打印日志如下:
全局配置
全局資源的配置問題,我們可以通過@ControllerAdvice來把控制器的全局配置放在同一個位置,這樣我們可以統一處理下面幾個問題:
- 1 .全局異常處理
- 2 .預設鍵值對綁定到Model中
- 3 .預處理前臺請求參數
OK,下面來一個一個看一下。
全局異常處理
全局異常主要是通過@ExceptionHandler這個注解來解決。如下:
@ControllerAdvicepublic class ExceptionHandlerAdvice {//@ExceptionHandler用來設置攔截條件,這里表示攔截所有的Exception@ExceptionHandler(value = Exception.class)public ModelAndView exception(Exception e, WebRequest request) {ModelAndView modelAndView = new ModelAndView("error");modelAndView.addObject("errorMsg", e.getMessage());return modelAndView;}}
首先通過@ControllerAdvice聲明一個控制器建言,由于這個注解組合了@Component注解,這個這個類會自動注冊為Spring容器中的Bean。@ExceptionHandler可以定義全局處理,其中Value屬性用來表示過濾攔截條件,Exception.class表示攔截所有的Exception。構造ModelAndView時傳入的error表示出錯的頁面。OK,我們來看一下控制器,我在控制器中添加如下方法:
@RequestMApping("/user")public String user(@ModelAttribute("msg") String msg, UserBean userBean) {System.out.println("username is :" + userBean.getUsername() + ";and id is :" + userBean.getId());throw new IllegalArgumentException("抱歉,參數異常/ 來自@ModelAttribute:" + msg);}
當我訪問/user這個地址的時候,直接拋一個異常,這個異常會被使用了@ExceptionHandler注解并且滿足過濾條件的方法接收并處理,我們這里當然是來到了exception這個方法中,在這個方法中我們又定位到了error.jsp頁面。同時這里的參數還使用了@ModelAttribute注解,這個注解我在下一小節再來說。我們再來看看這個error.jsp頁面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head><title>出錯啦</title></head><body><p><h1>${errorMsg}</h1></p></body></html>
這個頁面很簡單,就顯示一下錯誤信息就行了。我們來看看訪問結果:
控制臺輸出的錯誤信息:
預設鍵值對綁定到Model中
有的時候我們需要預設鍵值對到Model中,就像上面那個案例那樣,這個時候我們可以在ExceptionHandlerAdvice類中再添加一個方法:@ModelAttributepublic void addAttributes(Model model) {model.addAttribute("msg", "額外信息");}
在這個方法中我們向Model中綁定鍵值對,綁定完成之后,在任何Controller中我們都可以通過給方法的參數設定@ModelAttribute注解來訪問這里存入的值,相當于這里的值是一個全局變量。OK ,這里的訪問案例和上文一致,我就不再贅述了。
預處理前臺請求參數
OK,還有一種需求,有的時候我們需要預處理前臺傳來的參數,比如說禁止掉某一個參數,這個也可以統一處理,OK,繼續在ExceptionHandlerAdvice方法中添加方法
@InitBinderpublic void initBinder(WebDataBinder webDataBinder) {webDataBinder.setDisallowedFields("id");}
這個表示將客戶端傳來的id參數忽略掉,但是注意接收的方式,這里通過對象來接收參數的時候才有效(通過對象接收這個參數的時候才會屏蔽掉id),如果直接提取還是可以提取到的,我們來看一下控制器方法,還是剛才拋異常那個方法,但是在拋異常之前我先打印一下日志:
@RequestMapping("/user")public String user(@ModelAttribute("msg") String msg, UserBean userBean) {System.out.println("username is :" + userBean.getUsername() + ";and id is :" + userBean.getId());throw new IllegalArgumentException("抱歉,參數異常/ 來自@ModelAttribute:" + msg);}
我們看看控制臺的輸出:
OK, id已經被屏蔽掉了。
本案例下載地址:https://github.com/lenve/JavaEETest/tree/master/Test18-SpringMVC3
原文:https://blog.csdn.net/u012702547/article/details/53695789