如何将SpringMVC HTTP消息转换器与文件上传下载及异常处理集成优化?

摘要:HttpMessageConverter(HTTP消息转换器) HTTP消息转换器主要是将请求的表单数据封装成对象,controller中的方法直接用对象接收数据。 HttpMessageConverter接口可以将请求协议转换为Java对
HttpMessageConverter(HTTP消息转换器) HTTP消息转换器主要是将请求的表单数据封装成对象,controller中的方法直接用对象接收数据。 HttpMessageConverter接口可以将请求协议转换为Java对象,也可以把Java对象转换为响应协议。 对于程序员来说,springmvc已经帮我们写好了,我们只需要在不同的业务场景下,选择合适的HTTP消息转换器即可。 我们可以使用不同的注解来启用不同的消息转换器。 @ResponseBody 这里使用的消息转换器是:StringHttpMessageConverter @GetMapping("/ajax") // @ResponseBody注解表示该方法的返回值直接作为字符串响应体返回,而不是视图名称 @ResponseBody public String ajax() { return "hello ajax"; } 直接返回Java对象,(这里使用的消息转换器是MappingJackson2HttpMessageConverter): @GetMapping("/ajax2") // @ResponseBody注解表示该方法的返回值直接作为响应体返回,而不是视图名称 @ResponseBody public User ajax2() { return new User("zhangsan", 20, "123456"); } 此时要加入jackson-databind依赖才能生效 <!-- 负责将Java对象转换为JSON格式,或者将JSON格式的数据转换为Java对象。 它提供了丰富的功能和灵活的配置选项,使得在Java应用程序中处理JSON数据变得非常方便。--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.20.2</version> </dependency> </dependencies> @RestController 标注在类上,等于@Controller+@ResponseBody @RequestBody 作用是直接将请求体传递给Java程序,程序中可以直接使用一个String类型的变量来接收。 此注解只能出现在方法的参数上。 使用的消息转换器是FormHttpMessageConverter @PostMapping("/ajax3") public String ajax3(@RequestBody String params) { System.out.println(params); return "hello ajax3"; } 如果前端请求体当中提交的数据是JSON格式,那么@RequestBody可以将提交的json格式的字符串转换成Java对象。同样需要使用jackson的依赖 @PostMapping("/ajax4") @ResponseBody public String ajax4(@RequestBody User user) { System.out.println(user); return "hello ajax4"; } RequestEntity类 RequestEntity类的实例封装了整个请求的协议:包括请求行、请求头、请求体的所有信息。 出现在控制器方法的参数上: @PostMapping("/ajax5") @ResponseBody public String ajax5(RequestEntity<User> requestEntity) { // 请求方式 HttpMethod method = requestEntity.getMethod(); // 请求体 User user = requestEntity.getBody(); // 请求头 HttpHeaders headers = requestEntity.getHeaders(); // 请求URL requestEntity.getUrl(); // 请求头中的Content-Type headers.getContentType(); return "hello ajax5"; } ResponseEntity类 ResponseEntity类的实例可与封装响应协议,包括状态行、响应头、响应体。如果你想定制属于自己的响应协议,可以使用该类。注意:返回值必须是ResponseEntity,泛型为什么是User。因为响应体的内容是User类型。 比如: @GetMapping("ajax6/{id}") public ResponseEntity<User> ajax6(@PathVariable("id") String id) { User user =userService.getUserById(id); if (user == null) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); }else{ return ResponseEntity.ok(user); } } 文件上传与下载 文件上传 添加以下依赖(SpringMVC6不需要添加依赖): <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> </dependency> 文件上传必须是post请求 文件上传呢的form标签中必须使用enctype="multipart/form-data" enctype是用来设置请求头的,默认是application/x-www-form-urlencoded <!-- 前端控制器--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>0</load-on-startup> <multipart-config> <!-- 设置单个文件的最大大小,单位为字节。超过这个大小的文件将被拒绝上传。--> <max-file-size>102400</max-file-size> <!-- 设置整个表单的最大大小,单位为字节。这个值包括所有文件和表单数据的总和。超过这个大小的请求将被拒绝。--> <max-request-size>1024000</max-request-size> <!-- 设置最小的文件大小,单位为字节。小于这个大小的文件将被拒绝上传。--> <file-size-threshold>0</file-size-threshold> </multipart-config> </servlet> 重点:在web.xml文件中DispatcherServlet配置时,添加multipart-config配置信息。(这是spring6的配置,如果是以前的版本。则不是这样配置) 前端代码: <form th:action="@{/file-upload}" method="post" enctype="multipart/form-data"> <input type="file" name="file"/> <button type="submit">上传</button> </form> 后端代码: @PostMapping("/file-upload") public String file(@RequestParam("file") MultipartFile file) throws IOException { // 获取参数名 String name = file.getName(); // 获取文件大小 long size = file.getSize(); // 获取文件类型 String contentType = file.getContentType(); // 获取原始文件名 String originalFilename = file.getOriginalFilename(); // 获取文件输入流 InputStream inputStream = file.getInputStream(); // 创建一个缓冲输入流对象,用于读取文件内容 BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); // 创建一个新的文件名,使用当前时间戳加上原始文件的扩展名 String newName = System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf(".")); String path = "D:/" + newName; // 创建一个缓冲输出流对象,用于将文件内容写入到指定路径 File file1 = new File(path); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( new FileOutputStream(file1) ); byte[] bytes = new byte[1024]; int length = 0; // 循环读取文件内容,并将其写入到指定路径 while ((length = bufferedInputStream.read(bytes)) != -1) { bufferedOutputStream.write(bytes, 0, length); } bufferedOutputStream.flush(); // 关闭输入流和输出流 bufferedInputStream.close(); bufferedOutputStream.close(); return "ok"; } 文件下载 前端代码: <a th:href="@{/download}">文件下载</a> 后端代码: @GetMapping("/download") public ResponseEntity<byte[]> download() throws IOException { // 读取文件内容 File file = new File("D:/xxx.jpg"); // 创建一个HttpHeaders对象,用于设置响应头信息 HttpHeaders headers = new HttpHeaders(); // 设置响应头中的Content-Type为application/octet-stream,表示下载文件的类型为二进制流 headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 设置响应头中的Content-Disposition为attachment,表示下载文件的方式为附件,并指定下载文件的名称为原始文件名 headers.setContentDispositionFormData("attachment", file.getName()); // 创建一个ResponseEntity对象,包含文件内容、响应头信息和HTTP状态码,并返回给客户端 ResponseEntity<byte[]> builder = new ResponseEntity<byte[]>(Files.readAllBytes(file.toPath()), headers, HttpStatus.OK); return builder; } 异常处理器 异常处理器的作用:处理器方法执行过程中出现了异常,跳转到对应的视图。在视图上展示友好信息。 核心接口:HandlerExceptionResolver。核心方法是resolveException,最终返回的ModelAndView视图对象。会跳转到指定页面。 HandlerExceptionResolver有2个常用的默认实现: DefaultHandlerExceptionResolver 默认的异常处理器 SimpleHandlerExceptionResolver 自定义异常处理器 自定义异常处理器 自定义异常处理器需要使用:SimpleHandlerExceptionResolver 自定义异常处理器机制的两种方式: 通过xml配置 通过注解 配置文件方式 在springmvc.xml文件中添加如下配置 <!-- 配置自定义异常处理器--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <!-- 这里可以配置很多种异常,只要发生异常,就会跳转到对应界面 配置异常类型和视图名称的映射关系--> <prop key="java.lang.ArithmeticException">error</prop> </props> </property> <!-- 将当前发生的异常对象存储到request域中,属性名为ex, 可以在error.html页面中通过${ex}获取异常对象--> <property name="exceptionAttribute" value="ex"/> </bean> 注解方式 @ControllerAdvice public class ExceptionController { @ExceptionHandler public String handleException(Exception e, Model model) { model.addAttribute("ex", e.getMessage()); System.out.println("发生了异常:" + e.getMessage()); return "error"; } } 控制器类使用@ControllerAdvice标注 具体的方法使用@ExceptionHandler标注