1. Spring MVC配置
1.1 自定义DispatcherServlet配置
覆写AbstractAnnotationConfigDispatcherServletInitializer的customizeRegistration()方法
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
}
1.2 添加servlet、filter
实现WebApplicationInitializer接口
注册一个servlet:
package com.myapp.config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import com.myapp.MyServlet;
public class MyServletInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
Dynamic myServlet = servletContext.addServlet("myServlet", MyServlet.class);
myServlet.addMapping("/custom/**");
}
}
注册一个filter:
public class MyServletInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
javax.servlet.FilterRegistration.Dynamic filter =
servletContext.addFilter("myFilter", MyFilter.class);
filter.addMappingForUrlPatterns(null, false, "/custom/*");
}
}
WebApplicationInitializer适用于通用的添加servlet、filter、listener。
覆写AbstractAnnotationConfigDispatcherServletInitializer抽象类的getServletFilters()方法也可以添加filter:
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new MyFilter() };
}
1.3 在web.xml中声明DispatcherServlet
在web.xml中使用Java配置类:
2. 处理multipart form
在提交表单的时候,有时候会附带上传文件,文件会以二进制的形式提交。
multipart form回将提交的数据分成几个独立的部分,每个部分拥有自己的属性,自己的类型。
multipart request body样例:
2.1 配置multipart解析器
实现MultipartResolver。
Spring提供了两种MultipartResolver实现:
- CommonsMultipartResolver 使用Jakarta Commons FileUpload来解析multipart请求
- StandardServletMultipartResolver 依赖Servlet 3.0对于multipart请求的支持(since Spring 3.1)
使用Servlet3.0来解析multipart请求
@Bean
public MultipartResolver multipartResolver() throws IOException {
return new StandardServletMultipartResolver();
}
配置一些对于文件的上传的属性:
(1) 如果是配置DispatcherServlet时实现了WebApplicationInitializer接口
DispatcherServlet ds = new DispatcherServlet();
Dynamic registration = context.addServlet("appServlet", ds);
registration.addMapping("/");
registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
(2) 如果在配置DispatcherServlet时继承了AbstractAnnotationConfigDispatcherServletInitializer或AbstractDispatcherServletInitializer,那就覆写customizeRegistration()方法
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
}
MultipartConfigElement的构造方法的参数作用:
. 设置文件的临时位置
. 限定上传文件的最大size(in bytes),默认是没有上限的
. 配置整个multipart请求的最大size(in bytes),默认是没有上限的
. 限定一个上传的文件不写入临时位置,而直接写入到磁盘的最大size(in bytes),这个值默认是0,也就是说默认情况下,所有的文件都会写到磁盘上
/**
* 单个文件不能超过2MB,整个请求不能超过4MB,所有文件都要直接写到磁盘上
*/
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads", 2097152, 4194304, 0));
}
(3)如果在配置DispatcherServlet时使用了web.xml,就使用
appServlet
org.springframework.web.servlet.DispatcherServlet
1
/tmp/spittr/uploads
2097152
4194304
配置JAKARTA COMMONS FILEUPLOAD Multipart解析器
@Bean
public MultipartResolver multipartResolver() throws IOException {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spittr/uploads"));
multipartResolver.setMaxUploadSize(2097152);
multipartResolver.setMaxInMemorySize(0);
return multipartResolver;
}
2.2 处理multipart请求
最常用的方法是在controller的方法参数加上注解@RequestPart
前端form加上enctype="multipart/form-data"属性:
@RequestMapping(value="/register", method=POST)
public String processRegistration(@RequestPart("profilePicture") byte[] profilePicture,
@Valid Spitter spitter, Errors errors) {
...
}
接收MULTIPARTFILE
Spring提供了MultipartFile用来对上传的文件封装,便于操作
@RequestMapping(value="/register", method=POST)
public String processRegistration(@RequestPart("profilePicture") MultipartFile profilePicture,
@Valid Spitter spitter, Errors errors) {
...
}
package org.springframework.web.multipart;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
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;
}
transferTo方法可以将文件保存至指定位置
如果使用的Servlet3.0, 可以把上传的文件当做一个PART来解析
@RequestMapping(value="/register", method=POST)
public String processRegistration(
@RequestPart("profilePicture") Part profilePicture,
@Valid Spitter spitter,
Errors errors) {
...
}
package javax.servlet.http;
import java.io.*;
import java.util.*;
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 getHeaders(String name);
public Collection getHeaderNames();
}
使用write方法将文件保存至指定位置
3. 异常处理
3.1 将异常映射为Http状态码
(1)Spring默认提供了一些状态码映射
(2) 使用@ResponseStatus注解
首先自定义异常,并使用@ResponseStatus注解
package spittr.web;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")
public class SpittleNotFoundException extends RuntimeException {
}
然后跑出异常即可:
3.2 异常处理方法
使用@ExceptionHandler注解:
@ExceptionHandler(DuplicateSpittleException.class)
public String handleDuplicateSpittle() {
return "error/duplicate";
}
这个类可能会抛出DuplicateSpittleException异常:
@RequestMapping(method=RequestMethod.POST)
public String saveSpittle(SpittleForm form, Model model) {
spittleRepository.save(new Spittle(null, form.getMessage(), new Date(),
form.getLongitude(), form.getLatitude()));
return "redirect:/spittles";
}
4. 增强Controller
@ControllerAdvice注解
@ExceptionHandler注解
@InitBinder注解
@ModelAttribute注解
统一异常处理
package spitter.web;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class AppWideExceptionHandler {
@ExceptionHandler(DuplicateSpittleException.class)
public String duplicateSpittleHandler() {
return "error/duplicate";
}
}
5. redirect
controller返回页面时添加前缀redirect:
return "redirect:/spitter/" + spitter.getUsername()
5.1 在redirect时,使用url来传递参数
@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}";
}
5.2 在redirect时,使用flash属性
在Spring中,flash属性被定义为:携带数据到下一次请求
Spring使用Model的子类RedirectAttributes的addFlashAttribute()方法来做这个
@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}";
}
@RequestMapping(value="/{username}", method=GET)
public String showSpitterProfile(@PathVariable String username, Model model) {
if (!model.containsAttribute("spitter")) {
model.addAttribute(spitterRepository.findByUsername(username));
}
return "profile";
}