springmvc核心技術

目錄

  • 異常處理
  • 類型轉換器
  • 數據驗證
  • 文件上傳與下載
  • 攔截器

 異常處理

Spring MVC中, 系統的DAO, Service, Controller層出現異常, 均經過throw Exception向上拋出,web

最後由中央處理器DispatchServlet交由全局異常處理器進行異常處理, 以下圖所示spring

經常使用的Spring MVC異常處理方式主要有三種:瀏覽器

  • 使用系統定義好的異常處理器SimpleMappingExceptionResolver
  • 使用自定義異常處理器
  • 使用異常註解

SimpleMappingExceptionResolver服務器

只須要在配置文件中註冊該異常處理器Bean便可, 無需顯式調用, 當異常發生時會自動執行該類.mvc

1     <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
2         <property name="defaultErrorView" value="/errors/error.jsp"/>
3     </bean>

(1) 聲明一個自定義的異常類app

複製代碼
 1 public class NameException extends Exception {
 2 
 3     public NameException() {
 4         super();
 5     }
 6 
 7     public NameException(String message) {
 8         super(message);
 9     }
10     
11 }
複製代碼

(2) 註冊異常處理器框架

複製代碼
1     <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
2         <property name="defaultErrorView" value="/errors/error.jsp"/>
3         <property name="exceptionAttribute" value="ex"/>
4         <property name="exceptionMappings">
5             <props>
6                 <prop key="com.test.exceptions.NameException">/errors/nameError.jsp</prop>
7             </props>
8         </property>
9     </bean>
複製代碼

exceptionMapping: Properties類型屬性, 用於指定具體的不一樣類型異常對應的響應頁面.jsp

defaultErrorView: 默認的異常響應頁面, 若發生的異常不是自定義的異常, 則使用默認響應頁面.ide

exceptionAttribute: 捕獲到的異常對象, 通常異常響應頁面中使用.post

自定義異常處理器

SimpleMappingExceptionResolver能夠在發生異常的時候進行頁面跳轉, 可是若是想要在捕獲到特定異常後, 

執行一些操做, 則須要自定義異常. 自定義異常處理器須要實現HandlerExceptionResolver接口, 而且該類

須要在配置文件中進行註冊.

(1) 定義異常處理器

當一個類實現了HandlerExceptionResolver接口後, 只要有異常發生, 都會執行resolveException方法.

複製代碼
 1 public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
 2 
 3     public ModelAndView resolveException(HttpServletRequest request,
 4             HttpServletResponse response, Object handler, Exception ex) {
 5         
 6         ModelAndView mv = new ModelAndView();
 7         mv.addObject("ex", ex);
 8         mv.setViewName("/errors/error.jsp");
 9         
10         if(ex instanceof NameException) {
11             // 執行一些操做
12             mv.setViewName("/errors/nameError.jsp");
13         }
14         
15         return mv;
16     }
17 
18 }
複製代碼

(2) 註冊異常處理器

1     <!-- 註冊異常處理器 -->
2     <bean class="com.test.resolvers.MyHandlerExceptionResolver"/>

異常處理註解

使用註解@ExceptionHandler能夠將一個方法指定爲異常處理方法, 該註解有一個可選屬性value,

可用於指定該註解方法所須要處理的異常類. 

定義一個頂層Controller, 處理全部異常, 其餘Controller繼承該類便可實現異常集中管理.

複製代碼
 1 @Controller    
 2 public class BaseController {
 3 
 4     // 處理NameException異常
 5     @ExceptionHandler(NameException.class)
 6     public ModelAndView handlerNameException(Exception ex) {
 7         ModelAndView mv = new ModelAndView();
 8         mv.addObject("ex", ex);
 9         // 執行一些操做
10         mv.setViewName("/errors/nameError.jsp");
11         return mv;
12     }
13 
14 }
複製代碼

類型轉換器

能夠將用戶web端提交的數據, 在後臺轉爲須要的數據類型.

自定義類型轉換器

若要定義類型轉換器, 則須要實現Converter接口, 該Convert接口有兩個泛型:

第一個爲待轉換類型, 第二個爲目標類型, 該接口方法convert用於實現轉換.

複製代碼
 1 public class MyDateConverter implements Converter<String, Date> {
 2 
 3     public Date convert(String source) {
 4         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 5         try {
 6             return sdf.parse(source);
 7         } catch (ParseException e) {   
 8             e.printStackTrace();
 9         }
10         return null;
11     }
12 
13 }
複製代碼

類型轉換器定義完畢後, 須要在配置文件中進行註冊, 而後註冊一個轉換服務Bean, 將轉換器注入給該Bean, 

最後由處理器適配器來使用該轉換服務器Bean. 該Bean由ConversionServiceFactory工廠建立, 工廠有Set集合屬性, 

能夠提供多種轉換功能的Bean來處理多種數據類型轉換.

複製代碼
 1     <!-- 註冊類型轉換器 -->
 2     <bean id="myDateConverter" class="com.test.converters.MyDateConverter"/>
 3     
 4     <!-- 註冊轉換服務對象 -->
 5     <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
 6         <property name="converters" ref="myDateConverter"/>
 7     </bean>
 8     
 9     <!-- 註冊mvc註解驅動 -->
10     <mvc:annotation-driven conversion-service="conversionService"/>
複製代碼

數據驗證

主要是校驗客戶端發來的數據是否合法, 例如不能爲空, 或者長度不符合等等. Spring MVC沒有校驗功能,

可是支持JSR303-Bean Validation, 能夠用實現該規範的Hibernate Validator校驗框架.

(1) 配置驗證器

1     <!-- 生成驗證器 -->
2     <bean id="myValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
3         <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
4     </bean>

(2) 在Bean上添加驗證註解

複製代碼
 1 public class Student {
 2     
 3     @NotNull(message="姓名不能爲空")
 4     @Size(min=3, max=6, message="姓名長度應在{min}-{max}個字符")
 5     private String name;
 6     
 7     @Min(value=0, message="成績不能小於{value}")
 8     @Max(value=100, message="成績不能大於{value}")
 9     private double score;
10     
11     
12     @NotNull(message="電話不能爲空")
13     @Pattern(regexp="^1[34578]\\d{9}$", message="手機號格式不正確")
14     private String mobile;
15 
16         ......
17 }
複製代碼

(3) 修改Controller

在須要校驗的參數前面加上@Validated註解, 同時追加一個BindingResult參數, 用於獲取驗證異常信息.

複製代碼
 1 @Controller    
 2 @RequestMapping("/test")    
 3 public class MyController {
 4 
 5     @RequestMapping("/register.do")
 6     public ModelAndView doRegister(@Validated Student student, BindingResult br) {
 7         
 8         ModelAndView mv = new ModelAndView();
 9         mv.addObject("student", student);
10         mv.setViewName("/WEB-INF/jsp/welcome.jsp");
11         
12         int errorCount = br.getErrorCount();
13         if(errorCount > 0) {
14             FieldError nameError = br.getFieldError("name");
15             
16             if (nameError != null) {
17                 String nameErrorMSG = nameError.getDefaultMessage();
18                 mv.addObject("nameErrorMSG", nameErrorMSG);
19             }
20             mv.setViewName("/index.jsp");
21         }
22         
23         return mv;
24     }
25 }
複製代碼

文件上傳與下載

上傳

Spring MVC中文件上傳須要添加Apache Commons FileUpload相關的jar包,

基於該jar, Spring中提供了MultipartResolver實現類: CommonsMultipartResolver.

註冊該Bean到配置文件中

複製代碼
   <bean id="multipartResolver"  
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
        <!-- 上傳文件大小上限,單位爲字節(10MB) -->
        <property name="maxUploadSize">  
            <value>10485760</value>  
        </property>  
        <!-- 請求的編碼格式,必須和jSP的pageEncoding屬性一致,以便正確讀取表單的內容,默認爲ISO-8859-1 -->
        <property name="defaultEncoding">
            <value>UTF-8</value>
        </property>
    </bean>
複製代碼

Spring MVC會將上傳的文件綁定到MultipartFile對象, 該對象提供獲取內容, 文件名等方法.

經過transferTo方法能夠將文件存儲到磁盤.

複製代碼
 1      //上傳文件會自動綁定到MultipartFile中
 2      @RequestMapping(value="/upload",method=RequestMethod.POST)
 3      public String upload(HttpServletRequest request,
 4             @RequestParam("description") String description,
 5             @RequestParam("file") MultipartFile file) throws Exception {
 6 
 7         System.out.println(description);
 8         //若是文件不爲空,寫入上傳路徑
 9         if(!file.isEmpty()) {
10             //上傳文件路徑
11             String path = request.getServletContext().getRealPath("/images/");
12             //上傳文件名
13             String filename = file.getOriginalFilename();
14             File filepath = new File(path,filename);
15             //判斷路徑是否存在,若是不存在就建立一個
16             if (!filepath.getParentFile().exists()) { 
17                 filepath.getParentFile().mkdirs();
18             }
19             //將上傳文件保存到一個目標文件當中
20             file.transferTo(new File(path + File.separator + filename));
21             return "success";
22         } else {
23             return "error";
24         }
25 
26      }
複製代碼

下載

下載比較簡單, Spring MVC中提供了ResponseEntity類型, 能夠很方便的返回HTTPHeaders, HttpStatus.

複製代碼
     @RequestMapping(value="/download")
     public ResponseEntity<byte[]> download(HttpServletRequest request,
             @RequestParam("filename") String filename,
             Model model)throws Exception {
        //下載文件路徑
        String path = request.getServletContext().getRealPath("/images/");
        File file = new File(path + File.separator + filename);
        HttpHeaders headers = new HttpHeaders();  
        //下載顯示的文件名,解決中文名稱亂碼問題  
        String downloadFielName = new String(filename.getBytes("UTF-8"),"iso-8859-1");
        //通知瀏覽器以attachment(下載方式)打開圖片
        headers.setContentDispositionFormData("attachment", downloadFielName); 
        //application/octet-stream : 二進制流數據(最多見的文件下載)。
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),    
                headers, HttpStatus.CREATED);  
     }
複製代碼

攔截器

攔截器註冊與使用

Spring MVC中攔截器須要實現HandlerInterceptor接口, 該接口包含三個方法

preHandle(req, res, handler)

在處理器方法以前執行, 返回boolean, 若爲true, 則緊接着執行處理器方法, 且會將

afterCompletion()方法放入一個專門的方法棧中等待執行.

postHandler(req, res, handler, ModelAndView)

在處理器方法以後執行, 處理器方法若未執行, 則該方法不執行.

該方法能夠修改處理器方法返回的結果, 並能夠跳轉到其餘頁面.

afterCompletion(req, res, handler, exception)

當preHandle返回ture後, 會將該方法放入等待區, 等全部請求響應結束, 執行該方法.

即中央處理器渲染了響應頁面以後執行, 此時對ModelAndView修改也不會影響到頁面結果.

複製代碼
 1 public class OneInterceptor implements HandlerInterceptor {
 2 
 3     public boolean preHandle(HttpServletRequest request,
 4             HttpServletResponse response, Object handler) throws Exception {
 5         System.out.println("執行OneIntercepor ---- preHandle() ------");
 6         return false;
 7     }
 8 
 9     public void postHandle(HttpServletRequest request,
10             HttpServletResponse response, Object handler,
11             ModelAndView modelAndView) throws Exception {
12         System.out.println("執行OneIntercepor ---- postHandle() ------");
13     }
14 
15     public void afterCompletion(HttpServletRequest request,
16             HttpServletResponse response, Object handler, Exception ex)
17             throws Exception {
18         System.out.println("執行OneIntercepor ---- afterCompletion() ------");
19     }
20 
21 }
複製代碼

在配置文件中註冊

複製代碼
1     <!-- 註冊攔截器 -->
2     <mvc:interceptors>
3         <mvc:interceptor>
4             <mvc:mapping path="/**"/>
5             <bean class="com.test.interceptors.OneInterceptor"/>
6         </mvc:interceptor>
7     </mvc:interceptors>
複製代碼

 

<mvc:mapping/>用於指定當前攔截器攔截的請求路徑, /**表示攔截全部請求.

多個攔截器

當有多個攔截器時, 造成攔截器鏈, 攔截器鏈執行順序與註冊順序一致, 須要注意的是,

當一個攔截器preHandle()返回false時, 上部的攔截器鏈將被斷開, 後續的處理器以及對於的postHandle()

都沒法執行, 只有已經執行經過的攔截器的afterCompletion()方法會執行.

實際運用

  • 權限校驗: 判斷當前請求是否登錄, 若未登陸或者無權限, 返回對應的界面.
  • 性能監控: 監控系統指定方法執行的時間, 尋找系統性能調優勢.
  • 日誌打印: 記錄請求日誌, 用於系統監控, 信息統計與分析等等.
  • ......
相關文章
相關標籤/搜索