Spring实战4之SpringMVC高级篇
来源:互联网 发布:sybase数据库有哪些 编辑:程序博客网 时间:2024/05/29 15:19
一、DispatcherServlet个性化配置
继承AbstractAnnotationConfigDispatcherServletInitializer时,同时还有许多其他方法可以重写从而可以实现更多的配置。
例如customizeRegistration()方法,在注册了DispatcherServlet之后,就会调用customizeRegistration()方法,并根据servlet的注册返回值传送ServletRegistration.Dynamic,通过对customizeRegistration()的重写,就可以对DispatcherServlet进行额外的配置。其中ServletRegistration.Dynamic作为入参,你可以做很多事情,比如调用setLoadOnStartup()来设置加载时优先级,调用setInitParameter()来设置初始化参数,调用setMultipartConfig()来设置Servlet3.0的多路支持
/** * Spring MVC如何处理多个请求和文件上传 * 设置了多路支持的上传文件临时存储路径为:/tmp/spittr/uploads。 */@Overrideprotected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig( new MultipartConfigElement("/tmp/spittr/uploads"));}
二、添加额外的Servlet和Filter
1.注册额外的Servlet、Filter或者Listener
(1)最简单的方法就是实现Spring的WebApplicationInitializer接口。
例如,下面的代码展示了如何通过实现WebApplicationInitializer接口的方式来注册一个Servlet:
public class MyServletInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { // 定义Servlet Dynamic myServlet = servletContext.addServlet("myServlet", MyServlet.class); // 映射Servlet myServlet.addMapping("/custom/**"); } }
(2)使用AbstractAnnotationConfigDispatcherServletInitializer注册Filter并将其映射到DispatcherServlet
@Overrideprotected Filter[] getServletFilters() { return new Filter[] { new MyFilter() };}
三、使用web.xml声明DispatcherServlet
1.典型的web.xml文件,其中对DispatcherServlet和ContextLoaderListener进行了声明:
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <listener> <!-- 注册ContextLoaderListener --> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>appServlet</servlet-name> <!-- 注册DispatcherServlet --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- DispatcherServlet映射 --> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping></web-app>
2.通过设置contextConfigLocation初始化参数的方式指定DispatcherServlet配置文件的位置,例如,下面的DispatcherServlet配置就会从/WEB-INF/spring/appServlet/servlet-context.xml文件中加载:
<servlet> <servlet-name>appServlet</servlet-name> <!-- 注册DispatcherServlet --> <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>
3.基于Java的配置方式,通过设置DispatcherServlet的contextClass参数和初始化参数来实现
为了使用基于Java的配置,需要通知DispatcherServlet和ContextLoaderListener去使用AnnotationConfigWebApplicationContext,该类是WebApplicationContext接口的实现类,它可以对Java配置类进行加载。
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 使用Java配置 --> <context-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </context-param> <!-- 指定所使用的Java配置类 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>spittr.config.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> <!-- 使用Java配置 --> <init-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </init-param> <!-- 指定DispatcherServlet的配置类 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value> spittr.config.WebConfigConfig </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表单数据
1.配置multipart解析器
从Spring3.1开始,Spring提供了两种MultipartResolver实现类供选择:
CommonsMultipartResolver:使用Jakarta Commons FileUpload来解析multipart请求;
StandardServletMultipartResolver:依靠Servlet 3.0支持来解析(Spring 3.1及以上,第一选择);
设置StandardServletMultipartResolver的,但是它的设置不是在Spring配置中进行的,而是在Servlet配置中。起码要配置一下存放临时文件的位置,进一步来讲,还要将multipart配置为DispatcherServlet的一部分。
(1)继承自WebMvcConfigurerAdapter的servlet初始化类中配置的DispatcherServlet,那么就可以在servlet注册时通过调用setMultipartConfig()方法来配置multipart详情。比如:
DispatcherServlet ds = new DispatcherServlet();Dynamic registration = context.addServlet("appServlet", ds);registration.addMapping("/");registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
(2)继承自AbstractAnnotationConfigDispatcherServletInitializer或者AbstractDispatcherServletInitializer的servlet初始化类进行的配置,没有创建DispatcherServlet的实例或者使用servlet上下文对其进行注册。因此就没有直接的引用供Dynamicservlet注册来使用。重写customizeRegistration()方法来进行配置:
@Overrideprotected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));}
(3)MultipartConfigElement的唯一参数设置了上传文件时临时文件的存放位置。也可以进行其他一些设置:
文件上传的最大值(byte),默认没有限制;
所有multipart请求的文件最大值(byte),不管有多少个请求,默认无限制;
直接上传文件(不需存储到临时目录)的最大值(byte),默认是0,也就是所有的文件都要写入硬盘;
例如,你想设置文件大小不超过2MB,所有请求的总和不超过4MB,并且所有文件都要写入硬盘,那么就可以这样设置:
@Overrideprotected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads", 2097152, 4194304, 0));}
(4)传统的web.xml的方式来设置的DispatcherServlet,那么就需要使用多个元素,其默认值和MultipartConfigElement相同,并且是必填项:
<servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <multipart-config> <location>/tmp/spittr/uploads</location> <max-file-size>2097152</max-file-size> <max-request-size>4194304</max-request-size> </multipart-config></servlet>
(5)配置Jakarta Commons FileUpload解析器CommonsMultipartResolver
这里设置了文件的最大大小为2MB,最大的内存中大小为0,即每个上传文件都会直接写入磁盘的。但是它是无法设置multipart请求总的文件大小的。
@Beanpublic MultipartResolver multipartResolver() throws IOException { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spittr/uploads")); multipartResolver.setMaxUploadSize(2097152); multipartResolver.setMaxInMemorySize(0); return multipartResolver;}
2.处理multipart请求
页面
<form method="POST" th:object="${spitter}" *enctype="multipart/form-data"*> <label>Profile Picture</label>: <input type="file" name="profilePicture" accept="image/jpeg,image/png,image/gif" /><br/> <input type="submit" value="Register" /> </form>
(1) @RequestPart注解一个控制器参数获取到上传的文件
/** * 当注册表单提交时,请求部分的数据就会赋予到profilePicture属性中, * 如果用户没有选中一个文件,那么该数组就会是一个空值(不是null) */@RequestMapping(value = "/register", method = RequestMethod.POST)public String processRegistration(@RequestPart("profilePicture") byte[] profilePicture, @Valid Spitter spitter, Errors errors) {}
(2)使用MultipartFile接口保存上传文件
MultipartFile提供获取上传文件的方法,同时提供了很多其他方法,比如原始文件名称、大小和内容类型等。另外还提供了一个InputStream可以将文件数据作为数据流读取。
另外,MultipartFile还提供了一个方便的transferTo()方法帮助你将上传文件写入到文件系统
public interface MultipartFile { String getName(); String getOriginalFilename(); String getContentType(); boolean isEmpty(); long getSize(); byte[] getBytes() throws IOException; InputStream getInputStream() throws IOException; void transferTo(File dest) throws IOException;}
(3)将文件保存到Amazon S3管理文件
下面的代码可以将上传的图像保存到Amazon S3:
private void saveImage(MultipartFile image) throws ImageUploadException { try { //设置Amazon Web Service (AWS)认证,你需要提供S3的密钥和私钥,这些在注册S3服务时Amazon都会给你的 AWSCredentials awsCredentials = new AWSCredentials(s3AccessKey, s2SecretKey); // 配置S3服务 S3Service s3 = new RestS3Service(awsCredentials); // 创建S3 bucket对象 S3Bucket bucket = s3.getBucket("spittrImages"); S3Object imageObject = new S3Object(image.getOriginalFilename()); // 设置图像数据 imageObject.setDataInputStream(image.getInputStream()); imageObject.setContentLength(image.getSize()); imageObject.setContentType(image.getContentType()); AccessControlList acl = new AccessControlList(); // 设置权限 acl.setOwner(bucket.getOwner()); acl.grantPermission(GroupGrantee.ALL_USERS, Permission.PERMISSION_READ); imageObject.setAcl(acl); // 保存图片 s3.putObject(bucket, imageObject); } catch (Exception e) { throw new ImageUploadException("Unable to save image", e); }
(4)在Servlet 3.0的容器上,Spring MVC也可以将javax.servlet.http.Part作为控制器的入参
@RequestMapping(value = "/register", method = RequestMethod.POST) public String processRegistration(@RequestPart("profilePicture") Part profilePicture, @Valid Spitter spitter,Errors errors) { }
Part接口
public interface Part { public InputStream getInputStream() throws IOException; public String getContentType(); public String getName(); public String getSubmittedFileName(); public long getSize(); public void write(String fileName) throws IOException; public void delete() throws IOException; public String getHeader(String name); public Collection<String> getHeaders(String name); public Collection<String> getHeaderNames();}
五、异常处理
(1)@ResponseStatus来将其映射到404。
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")public class SpittleNotFoundException extends Exception {}
(2)编写异常处理方法
@ExceptionHandler注解的方法在同一个控制器里是通用的,即无论SpittleController的哪一个方法抛出DuplicateSpittleException异常,handleDuplicateSpittle()方法都可以对其进行处理,而不再需要在每一个出现异常的地方进行捕获
@ExceptionHandler(DuplicateSpittleException.class)public String handleDuplicateSpittle() { return "error/duplicate";}
(3)@ControllerAdvice控制器增强类
使用@ControllerAdvice控制器增强类,不论哪一个controller抛出DuplicateSpittleException,都会调用handleDuplicateSpittle()方法来处理。
// 声明控制器增强@ControllerAdvicepublic class AppWideExceptionHandler { // 定义异常处理方法 @ExceptionHandler(DuplicateSpittleException.class) public String handleDuplicateSpittle() { return "error/duplicate"; } @ExceptionHandler(SpittleNotFoundException.class) public String handleSpittleNotFound() { return "error/duplicate"; }}
六、在redirect请求中携带数据进行传递
跳转的路径:
return “redirect:/spitter/” + spitter.getUsername();
两种方法用来从重定向的方法中获取数据:
(1)将数据转换为路径参数或者查询参数
使用URL模版重定向:使用路径参数和查询参数传递数据比较简单,它只适用于传递简单值,比如String和数字,不能传递比较复杂的东西。
由于model中的spitterId属性并没有映射到URL中的占位符,它会自动作为查询参数。
如果username是habuma,spitterId是42,那么返回的重定向路径将是/spitter/habuma?spitterId=42。
@RequestMapping(value="/register", method=POST)public String processRegistration(Spitter spitter, Model model) { spitterRepository.save(spitter); model.addAttribute("username", spitter.getUsername()); model.addAttribute("spitterId", spitter.getId()); return "redirect:/spitter/{username}";}
(2)在flash属性中发送数据
使用flash属性
在重定向中传送一个Spitter对象。
在重定向之前,所有的flash属性都会拷贝到session中,在重定向之后,存储在session中的flash属性会从session中移出到model中。然后处理重定向请求的方法就可以使用Spitter对象了
@RequestMapping(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}";}
- Spring实战4之SpringMVC高级篇
- Spring实战4之高级配置篇
- Spring实战4之SpringMVC篇
- spring之springmvc实战篇(二)
- Spring实战之三:高级装配
- springMVC+spring+MyBatis实战之搭建平台
- 【Spring实战4】10--搭建SpringMVC环境
- 【实战】4-13 Spring及SpringMVC配置
- spring mvc高级篇(一):Spring+SpringMVC+Hibernate整合
- spring mvc高级篇(二):Spring+SpringMVC+Mybatis整合
- spring实战4之容器篇
- Spring实战4之AOP篇
- Spring实战4之数据源篇
- Spring实战4之缓存篇
- Spring实战4之Spring Web Flow篇
- Spring MVC入门第4天--springmvc高级功能
- Spring实战4之Spring Security
- JPA 实战篇(二)JPA && Spring && SpringMVC 框架整合
- Caffe2
- Redis 安装以及基本使用
- 进阶4_更深入的了解AdapterView
- android 全局无标题透明dialog
- Android自定义RatingBar
- Spring实战4之SpringMVC高级篇
- Opencv HOG特征函数简介
- windows下vue-cli及webpack 构建网站及 路由vue-router的使用
- strncmp, strncat, strncpy函数的定义与实现
- AndroidStudio 编译异常java.lang.OutOfMemoryError: GC overhead limit exceeded
- Kotlin编写你的HelloKotlin
- ssm:数据回显
- 使input文本框随输入内容变化长度的方法
- EOJ-3261 字典树 + dp