spring|SpringMVC文件上传、拦截器与异常处理
文件上传 Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。Spring 用Jakarta Commons FileUpload 技术实现了一个MultipartResolver 实现类:CommonsMultipartResovler,因此需要依赖commons-fileupload.jar。
Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring的文件上传功能,需要在上下文中配置 MultipartResolver:
【spring|SpringMVC文件上传、拦截器与异常处理】文件上传示例:
@Controller
public class FileUploadController {
/**
* 文件上传(支持多个文件),单个文件时也可以使用MultipartFile作为方法参数
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value = https://www.it610.com/article/{"/multiFileUpload"})
publicString multiFileUpload(MultipartHttpServletRequest request) throws IOException {
//获取所有的文件上传表单内容
Map filesMap = request.getFileMap();
Set entries = filesMap.entrySet();
//获取项目真实路径
String realPath = request.getSession().getServletContext().getRealPath("");
System.out.println(realPath);
//获取缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
for (Map.Entry entry : entries) {String key = entry.getKey();
MultipartFile file = entry.getValue();
//获取原始文件名
String filename = file.getOriginalFilename();
//创建输入/输出通道
FileInputStream fileInputStream = null;
FileChannel inChannel = null;
FileOutputStream fileOutputStream = null;
FileChannel outChannel = null;
try {
fileInputStream = (FileInputStream)file.getInputStream();
inChannel = fileInputStream.getChannel();
fileOutputStream = new FileOutputStream(new File(realPath+"\\WEB-INF\\classes\\"+filename));
outChannel = fileOutputStream.getChannel();
//上传文件
while (inChannel.read(byteBuffer) != -1) {
byteBuffer.flip();
outChannel.write(byteBuffer);
byteBuffer.clear();
}
System.out.println("上传文件的name属性" + key + "原始文件名:" + filename);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
fileInputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
if (inChannel != null) {
inChannel.close();
}
if (outChannel != null) {
outChannel.close();
}
}}
return "success";
}
}
拦截器 在SpringMVC源码分析之数据绑定与国际化中我们提到了LocaleChangeInterceptor拦截器用于拦截locale参数实现国际化切换。SpringMVC提供了HandlerInterceptor接口可用于自定义拦截器。
自定义拦截器示例:
public class MyInterceptor implements HandlerInterceptor {
/**
* @desc 在处理器实际执行之前执行
* 当方法返回 true时,处理器链会继续执行;
* 若方法返回 false, DispatcherServlet即认为拦截器自身已经完成了
* 对请求的处理(比如说,已经渲染了一个合适的视图),那么其余的拦
* 截器以及执行链中的其他处理器就不会再被执行了
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
/**
* @desc 在处理器实际执行之后执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandler");
}
/**
* @desc 出现异常或在整个请求处理完成之后被执行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
拦截器注册:
异常处理 Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。HandlerExceptionResolver 接口及实现类如下:
文章图片
SpringMVC默认装配AnnotationMethodHandlerExceptionResolver、ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver三种HandlerExceptionResolver,当开启
时与HandlerMapping相似,AnnotationMethodHandlerExceptionResolver会被ExceptionHandlerExceptionResolver所替代。ExceptionHandlerExceptionResolver 主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。
- @ExceptionHandler 注解定义的方法总是以更具体的Exception优先:例如发生的是NullPointerException,但是声明的异常有NullPointerException和RuntimeException ,此时会以NullPointerException优先
- ExceptionHandlerMethodResolver在处理器中若找不到@ExceptionHandler 注解的方法,会找@ControllerAdvice 中的@ExceptionHandler 注解方法
@RequestMapping("/testException")
public String testException(@RequestParam("i") int i) {
System.out.println(10/i);
return "success";
}/**
* 在@ExceptionHandler方法的入参中可以加入Exception类型的参数,该参数即对应发生的异常对象
* 如果想把异常信息传递给页面,不可以在方法参数中使用Map等参数,可以返回ModelAndView对象
* @param e
* @return
*/
@ExceptionHandler(value = https://www.it610.com/article/{ArithmeticException.class})
public ModelAndView handleArithmeticException(Exception e) {
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception",e);
System.out.println("出现异常:"+e);
return mv;
}
@ExceptionHandler方法也可以放在标注了@ControllerAdvice的类中作为全局处理。实际项目中,我们可以自定义异常做统一的封装然后通过@ControllerAdvice将异常信息存入ModelAndView中返回给客户端。
ResponseStatusExceptionResolver 在异常及异常父类中找到 @ResponseStatus 注解,然后使用这个注解的属性进行处理。
- 定义一个 @ResponseStatus 注解修饰的异常类
- 如果上述异常没有被ExceptionHandlerExceptionResolver解析,则会被ResponseStatusExceptionResolver 解析,根据@ResponseStatus 中注解的信息返回给客户端。
/**
* 自定义异常类,使用@ResponseStatus定义状态码和message信息
*/
@ResponseStatus(value = https://www.it610.com/article/HttpStatus.BAD_REQUEST,reason ="用户名与密码不匹配")
public class UserNamePasswordNotMatchException extends Exception {}@RequestMapping("/testException")
public String testException(@RequestParam("i") int i) throws UserNamePasswordNotMatchException {
try {
System.out.println(10/i);
} catch (Exception e) {
throw new UserNamePasswordNotMatchException();
}
return "success";
}
DefaultHandlerExceptionResolver 对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException等,具体看DefaultHandlerExceptionResolver的doResolveException方法源码。
SimpleMappingExceptionResolver 如果希望对所有异常进行统一处理,可以使用SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
error
error
Exception会被放入ModelAndView中,可以在页面获取异常信息。
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- django-前后端交互
- 如何在Mac中的文件选择框中打开系统隐藏文件夹
- 使用composer自动加载类文件
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- ssh生成公钥秘钥
- spring|spring boot项目启动websocket
- Android系统启动之init.rc文件解析过程