文章目录
8 HttpMessageConverter
HttpMessageConverter,报文信息转换器,它有两个作用:
- 将请求报文转换为Java对象
- 或将Java对象转换为响应报文
HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity,@ResponseEntity
8.1 环境准备
首先,新建一个Moodle,然后修改pom.xml内容如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>rest_mvc</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<packaging>war</packaging>
<dependencies>
<!--SpringMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!--ServletAPI-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--Spring5和Thymeleaf整合包-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
</project>
然后修改我们的springMVC.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--扫描组件-->
<context:component-scan base-package="com.zjw.mvc"/>
<!--配置Thymeleaf视图解析器(针对h5文件,抄就完了)-->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!--视图前缀-->
<property name="prefix" value="/WEB-INF/templates/"/>
<!--视图后缀-->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
<!--
处理静态资源,如html、js、css、jpg
若只设置该标签,则只访问静态资源,其他请求无法访问
此时必须设置<mvc:annotation-driven/>解决问题
-->
<mvc:default-servlet-handler/>
<!--开启mvc注解驱动-->
<mvc:annotation-driven>
<mvc:message-converters>
<!--处理响应中文乱码问题-->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8"/>
<property name="supportedMediaTypes">
<list>
<value>text/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
</beans>
编写一个首页页面index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
</form>
</body>
</html>
然后再编写一个成功跳转的页面success.html:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>成功页面</title>
</head>
<body>
<h1>成功跳转</h1>
</body>
</html>
同时在springMVC加上这两个页面的view-controller:
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="/success" view-name="success" />
8.2 @RequestBody
@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值。
首先在index页面增加一个表单:
<form th:action="@{/testRequestBody}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit">
</form>
同时在Controller类中增加相应的控制器方法:
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String requestBody){
System.out.println("requestBody:"+requestBody);
return "success";
}
此时控制台输出:
根据结果我们可以发现,输出的结果跟get方法地址栏的形式一样,key=value然后以?拼接
8.3 RequestEntity
RequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求体信息
在控制器类增加以下方法:
@RequestMapping("/testRequestEntity")
public String testRequestEntity(RequestEntity<String> requestEntity){
System.out.println("requestHeader:"+requestEntity.getHeaders());
System.out.println("requestBody:"+requestEntity.getBody());
return "success";
}
同时修改我们的index.html页面,增加以下表单:
<form th:action="@{/testRequestEntity}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit">
</form>
输出内容:
8.4 @ResponseBody
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器
8.4.1 使用@ResponseBody返回一个字符串类型数据
在控制器类中加入以下方法:
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
return "success";
}
然后在index页面,写一个跳转的超链接:
<h2>测试ResponseBody传字符串</h2>
<a th:href="@{/testResponseBody}">测试ResponseBody传字符串</a><br>
重启服务器
我们知道,如果没加@ResponseBody注解,我们应该跳转到success.html页面,但是,当加了ResponseBody注解后,显示的确实:
此时就相当于在之前JavaWeb中,在servlet中写了方法:
public void testResponseBody(HttpServletResponse response) throws IOException {
response.getWriter().write("success");
}
8.4.2 使用@ResponseBody返回一个JSON类型数据
@ResponseBody处理json的步骤:
-
导入jackson的依赖
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.1</version> </dependency>
-
在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:
MappingJackson2HttpMessageConverter
,可以将响应到浏览器的Java对象转换为Json格式的字符串<mvc:annotation-driven />
-
在处理器方法上使用@ResponseBody注解进行标识
@RequestMapping("/testResponseUser") @ResponseBody //随便新建一个User类即可,实现它的get,set和有参无参构造方法就可以 public User testResponseUser(){ return new User(1001,"admin","123456",23,"男"); }
-
将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串
-
在index编写超链接
<h2>测试ResponseBody传JSON对象</h2> <a th:href="@{/testResponseUser}">测试ResponseBody传JSON对象</a><br>
8.4.3 @RestController注解
以后会很重要,很常用的一个注解——@RestController。这个注解是SpringMVC提供的一个复合注解,标识在控制器的类上,相当于为这个类添加@Controller注解,并且为这个类中所有的方法添加@ResponseBody注解。
8.5 ResponseEntity类
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文
使用ResponseEntity实现下载文件的功能
返回一个ResponseEntity,我们不仅要返回我们想要的响应内容,还需要给它加上响应头和状态码
首先将我们需要下载的图片放到webapp/static/img
目录下
然会新建一个file.html来放置我们下载文件的超链接:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>文件的下载和上传</title>
</head>
<body>
<h2>测试文件下载</h2>
<a th:href="@{/testDownload}">点击下载SpringMVC.jpg</a><br>
</body>
</html>
在控制器类中加上file.html的控制器方法,以及文件下载的控制器方法
@RequestMapping("/file")
public String toFile(){
return "file";
}
@RequestMapping("/testDownload")
public ResponseEntity<byte[]> testDownload(HttpSession session) throws IOException {
/*获取ServletContext对象*/
ServletContext context = session.getServletContext();
/*获取服务器中文件的真实路径*/
String path = context.getRealPath("/static/img/SpringMVC.jpg");
/*创建输入流*/
InputStream inputStream = new FileInputStream(path);
/*创建字节数组*/
byte[] buffer = new byte[inputStream.available()];
/*将流读取到字节数组中*/
inputStream.read(buffer);
/*创建HttpHeaders对象设置响应头信息*/
MultiValueMap<String, String> headers = new HttpHeaders();
/*设置下载的方式和文件名*/
headers.add("Content-Disposition", "attachment;filename=SpringMVC.jpg");
/*设置响应状态码*/
HttpStatus status = HttpStatus.OK;
/*创建ResponseEntity对象*/
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(buffer,headers,status);
/*关闭输入流*/
inputStream.close();
return responseEntity;
}
重启服务器:
在此基础去实现下载别的文件,只需修改以下两处代码:
8.6 SpringMVC实现文件上传
文件上传要求form表单的请求方式必须为post,并且添加属性enctype="multipart/form-data"
(表示通过二进制形式传输,只有这样,服务器才能成功接收文件)SpringMVC中将上传的文件封装到MultipartFile
对象中,通过此对象可以获取文件相关信息
上传步骤:
- 添加依赖:
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
- 在SpringMVC的配置文件中添加配置:
<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
- 控制器方法:
@RequestMapping("/testUpload")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
//处理文件重名问题
String hzName = fileName.substring(fileName.lastIndexOf("."));
fileName = UUID.randomUUID().toString() + hzName;
//获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
File file = new File(photoPath);
if(!file.exists()){
file.mkdir();
}
String finalPath = photoPath + File.separator + fileName;
//实现上传功能
photo.transferTo(new File(finalPath));
return "success";
}
- 在file.html页面中增加以下代码:
<h2>测试文件上传</h2>
<!--
enctype="multipart/form-data"表示通过二进制形式传输
只有这样,服务器才能成功接收文件
-->
<form th:action="@{/testUpload}" method="post" enctype="multipart/form-data">
图片:<input type="file" name="photo"><br>
<input type="submit" value="提交">
</form>
- 结果展示:
成功上传后跳到success.html页面
然后在target目录下查看我们上传的文件,文件名字是UUID自动生成防止名字重复: