前面學習了簡單的
Spring Web
知識,接着學習更高階的Web
技術。java
在第五章咱們曾編寫過以下代碼。web
public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }
能夠看到SpitterWebinitializer
實現了AbstractAnnotationConfigDispatcherServletInitializer
抽象類,並重寫了三個必須的方法,實際上還可對更多方法進行重寫,以便實現額外的配置,如對customizeRegistration
方法進行重寫,該方法是AbstractDispatcherServletInitializer
的方法,無實際的方法體。當AbstractAnnotationConfigDispatcherServletInitializer
將DispatcherServlet
註冊到Servlet
容器中後,就會調用customizeRegistration
方法,並將Servlet
註冊後獲得的Registration.Dynamic
傳入。可經過重寫customizeRegistration
方法設置MultipartConfigElement
,以下所示。spring
@Override protected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig( new MultipartConfigElement("/tmp/spittr/uploads")); }
AbstractAnnotationConfigDispatcherServletInitializer
會建立DispatcherServlet
和ContextLoaderListener
,當須要添加其餘Servlet
和Filter
時,只須要建立一個新的初始化器便可,最簡單的方式是實現WebApplicationInitializer
接口。spring-mvc
import org.springframework.web.WebApplicationInitializer; import javax.servlet.FilterRegistration; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration.Dynamic; public class MyServletInitializer implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException { Dynamic servlet = servletContext.addServlet("myServlet", MyServlet.class); servlet.addMapping("/custom/**"); FilterRegistration.Dynamic filter = servletContext.addFilter("myFilter", MyFilter.class); filter.addMappingForUrlPatterns(null, false, "/custom/*"); } }
對基本的Spring MVC
應用而言,須要配置DispatcherServlet
和ContextLoaderListener
,web.xml
配置以下。安全
<web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
能夠看到在web.xml
中配置了DispatcherServlet
和ContextLoaderListener
,而且定義了上下文,該上下文會被ContextLoaderListener
加載,從中讀取bean
。也可指定DispatcherServlet
的應用上下文並完成加載,配置web.xml
以下。mvc
<servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
上面使用DispatcherServlet
和ContextLoaderListener
加載各自的上下文,但實際狀況中,基於Java
的配置更爲通用,此時只須要配置DispatcherServlet
和ContextLoaderListener
使用AnnotationConfigWebApplicationContext
,這樣它即可加載Java
配置類,而非使用xml
,可設置contextClass
和DispathcerServlet
的初始化參數,以下所示。app
<web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>contextClass</param-name> <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>ch7.RootConfig</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextClass</param-name> <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </init-param> <init-param> <param-name>contextConfigLocation</param-name> <param-value>ch7.WebConfig</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
處理multipart
數據主要用於處理文件上傳操做。須要配置multipart
解析器讀取multipart
請求。ide
DispatcherServlet
並未實現任何解析multipart
請求數據功能,它只是將任務委託給MultipartResolver
策略接口實現,經過該實現解析multipart
請求內容,Spring
中內置了CommonsMultipartResolver
和StandardServletMultipartResolver
兩個解析器。學習
使用Java
配置以下url
@Override protected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads", 2 * 1024 * 1024, 4 * 1024 * 1024, 0)); }
使用xml
配置以下,在servlet
標籤中配置multipart-config
。
<multipart-config> <location>/tmp/spittr/uploads</location> <max-file-size>2 * 1024 * 1024</max-file-size> <max-request-size>4 * 1024 * 1024</max-request-size> </multipart-config>
使用Java
配置以下
@Bean public MultipartResolver multipartResolver() throws IOException { CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); commonsMultipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spittr/uploads")); return commonsMultipartResolver; }
可在控制器的方法參數上添加@RequestPart
註解,以下所示。
@RequestMapping(value="/register", method=POST) public String processRegistration( @RequestPart("profilePicture") byte[] profilePicture, @Valid Spittr spitter, Errors errors) { profilePicture.transferTo(new File("/data/spittr" + profilePicture.getOriginalFilename())); }
Spring
提供了多種方式將異常轉換爲響應
HTTP
狀態碼。@ResponseStatus
註解,從而將其映射爲某個HTTP
狀態碼。@ExceptionHandler
註解,使其用來處理異常。Spring
異常與狀態碼對應關係以下。
可在請求中直接使用try/catch
處理異常,其與正常Java
方法中的try/catch
相同,同時,也可編寫處理器來處理特定異常,當出現特定異常時,將有處理器委託方法進行處理。
@ExceptionHandler(DuplicateSpittleException.class) public String handleDuplicateSpittle() { return "error/duplicate"; }
控制器通知是任意帶有@ControllerAdvice
註解的類,該類包含以下類型的一個或多個方法。
@ExceptionHandler
註解標註的方法。@InitBinder
註解標註的方法。@ModelAttribute
註解標註的方法。上面方法會運用到整個應用程序全部控制器中帶有@RequestMapping
註解的方法上。
@ControllerAdvice public class AppWideExceptionHandler { @ExceptionHandler(DuplicateSpittleException.class) public String duplicateSpittleHandler() { return "error/duplicate"; } }
通過上述配置,任意控制器方法拋出了DuplicateSpittleException
異常,都會調用這個duplicateSpittleHandler
方法處理異常。
對於重定向而言,若須要從發起重定向的方法傳遞數據給處理重定向方法中,有以下兩種方法
URL
模版以路徑變量和/或查詢參數形式傳遞數據。flash
屬性發送數據。如前面講到的經過redirect:/spitter/{username}
進行重定向,該方法會直接根據username
肯定url
,並不是十分安全的作法,可以使用進行以下處理。
model.addAttribute("username", spitter.getUsername()); return "redirect:/spitter/{username}";
當須要傳遞參數,如id時,可進行以下處理。
model.addAttribute("username", spitter.getUsername()); model.addAttribute("spitterId", spitter.getId()); return "redirect:/spitter/{username}";
若username
爲leesf
;id
爲123456
。這樣訪問的url
爲/spitter/leesf?spitterId=123456
。這種方法只能傳遞簡單的值,沒法發送更爲複雜的值,此時須要使用flash
屬性。
經過RedirectAttributes
設置flash
屬性,這樣可直接傳遞對象。
@ReuqestMapping(value="/register", method=POST) public String processRegistration(Spitter spitter, RedirectAttributes model) { spitterRepository.save(spitter); model.addAttribute("username", spitter.getUsername()); model.addFlashAttribute("spitter", spitter); return "redirect:/spitter/{username}"; }
這樣spitter
對象也被傳遞到重定向頁面中,可直接訪問spitter
對象。
本篇博文講解了如何配置DispatcherServlet
和ContextLoaderListener
,以及如何處理異常和控制器通知,最後分析如何在重定向時傳遞數據。