前面学习了简单的
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
,以及如何处理异常和控制器通知,最后分析如何在重定向时传递数据。