赞
踩
JSON 是目前主流的前后端数据传输方式, Spring MVC 中使用消息转换器 HttpMessageConverter 对 JSON 的转换提供了很好的支持,在 Spring Boot 更进 ,对相关配置做了更进一步的简化。默认情况下,当开发者新创建一个 Spring Boot 项目后,添加 Web 依赖,代码如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
这个依赖中默认加入了 jackson-databind 作为 JSON 处理器,此时不需要添加额外的 JSON 理器就能返回一段 JSON 了。 新建一个 Person 实体类
public class Person {
private String name;
private Integer age;
@JsonFormat(pattern ="yyyy-MM-dd")
private Date birthday ;
//省略get/set方法
}
然后 PersonController 返回 Person 对象即可:
@GetMapping("/person")
public Person person() {
Person person = new Person();
person.setName("zhang san");
person.setAge(24);
person.setBirthday(new Date());
return person;
}
此时,在浏览器中输入 http://localhost:8080/person, 即可看到返回了 JSON 数据。
这是 Spring Booot 自带的处理方式。如果采用这种方式,那么对于字段忽略、日期格式化等常需求都可以通过注解来解决。这是通过 Spring 中默认提供的 MappingJackson2HttpMessageConert 来实现的,当然开发者在这里也可以根据实际需求自定义 JSON 转换器。
常见的 JSON 处理器除了 jackson-databind 外, 还有 Gson 和 fastjson。
Gson 是 Google 的一个开源 JSON 解析框架。使用 Gson,需要先除去默认的 jackson-databind,然后加入 Gson 依赖,代码如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
由于 Spring Boot 中默认提供了 Gson 自动转换类 GsonHttpMessageConvertersConfiguration,因此 Gson 的依赖添加成功后 可以像使用 jackson-databind 那样直接使用 Gson 。但是在 Gson 进行转换时,如果想对日期数据进行格式化, 那么还需要开发者自定义 HttpMessageConverter。自定义 HttpMessageConverter 可以通过如下方式。
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.GsonHttpMessageConverter; import java.lang.reflect.Modifier; @Configuration public class GsonConfig { @Bean GsonHttpMessageConverter gsonHttpMessageConverter() { GsonHttpMessageConverter converter = new GsonHttpMessageConverter(); GsonBuilder builder = new GsonBuilder(); builder.setDateFormat("yyyy-MM-dd"); builder.excludeFieldsWithModifiers(Modifier.PROTECTED); Gson gson = builder.create(); converter.setGson(gson); return converter; } }
代码解释:
此时,将 Person 类中的 birthday 字段的修饰符改为 protected 代码如下
public class Person {
private String name;
private Integer age;
@JsonFormat(pattern ="yyyy-MM-dd")
protected Date birthday ;
//省略get/set方法
}
此时,在浏览器中输入 http://localhost:8080/person, 即可看到返回中的 JSON 数据,其中 birthday 字段被过滤掉了。
fastjson 是阿里巴巴的一个开源 JSON 框架,是目前 JSO 解析速度最快的开源框架,该框架也可以集成到 Spring Boot 中。不同于 Gson,fastjson 承完成之后并不能立马使用, 需要开发者提供相应的 HttpMessageConverter 后才能使用,集成 fastjson 的步骤如下。
(1)首先除去 jackson-databind 依赖,引入 fastjson 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
(2)然后配置 fastjson HttpMessageConverter:
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.nio.charset.Charset; @Configuration public class MyFastJsonConfig { @Bean FastJsonHttpMessageConverter fastJsonHttpMessageConverter() { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); FastJsonConfig config = new FastJsonConfig(); config.setDateFormat("yyyy-MM-dd"); config.setCharset(Charset.forName("utf-8")); config.setSerializerFeatures( SerializerFeature.WriteClassName, SerializerFeature.WriteMapNullValue, SerializerFeature.PrettyFormat, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty); converter.setFastJsonConfig(config); return converter; } }
(3)MyFastJsonConfig 配置完成后,还需要配置一下响应编码,否则返回的 JSON 中文会乱码,在application. properties 添加如下配置:
spring.http.encoding.force-response=true
此时,在浏览器中输入 http://localhost:8080/person, 即可看到返回中的 JSON 数据
扩展:对于 FastJsonHttpMessageConverter 的配置,除了上面这种方式之外,还有另一种方式。在 Spring Boot 项目中,当开发者引入 spring-boot-starter-web 依赖之后,该依赖又依赖了spring-boot-autoconfigure 在这个自动化配置中,有一个 WebMvcAutoConfiguration 类提供了对 Spring MVC 最基本的配置, 如果某一项自动化配置不满足开发需求,开发者可以针对该项自定义配置,只需要实现 WebMvcConfigurer 接口即可(在 Spring 是通过继承 WebMvcConfigurerAdapter 类来实现的),代码如下:
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.nio.charset.Charset; import java.util.List; @Configuration public class MyWebMvcConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); FastJsonConfig config = new FastJsonConfig(); config.setDateFormat("yyyy-MM-dd"); config.setCharset(Charset.forName("utf-8")); config.setSerializerFeatures( SerializerFeature.WriteClassName, SerializerFeature.WriteMapNullValue, SerializerFeature.PrettyFormat, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty); converter.setFastJsonConfig(config); converters.add(converter); } }
代码解释:
注意: 如果使用了 Gson ,也可以采用这种方式配置,但是不推荐。 因为当项目中没有 GsonHttpMessageConverter 时, Spring Boot 自己会提供一个GsonHttpMessageConverter ,此时重写 configureMessageConverters 方法,参数converters 中已经有 GsonHttpMessageConverter 的实例了,需要替换已有的 GsonHttpMessageConverter 实例,操作比较麻烦,所以对于 Gson,推荐直接提供 GsonHttpMessageConverter
在SpringMVC 中,对于静态资源都需要开发者手动配置静态资源过滤。Spring Boot 中对此也提供了自动化配置,可以简化静态资源过滤配置。
在Spring Boot 中对于 SpringMVC 自动化配置都在 WebMvcAutoConfiguration 类中 ,因此对于默认静态资源过滤策略可以从这个类中一探究竟。
在WebMvcAutoConfiguration 类中有个静态内部类 WebMvcAutoConfigurationAdapter 实现了 WebMvcConfigurer 接口。 WeMvcConfigurer 接口中有个方法 addRsourceHandlers,
是用来配置静态资源过滤的。方法在 WebMvcAutoConfigurationAdapter 中得到了实现,部分核心代码如下:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(
this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
}
Spring Boot 在这里进行了默认的静态资源过滤配置,其中 staticPathPattern 默认定义在
WebMvcProperties 中,定义内容如下:
private String staticPathPattern = “/**”;
this.resourceProperties.getStaticLocations()
获取到的默认静态资源位置定义在ResourceProperties 中,代码如下:
从上面上可以看到, Spring Boot 默认会过滤所有的静态资源,开发者可以将静态资源放到这几个位置中的任意一处,注意:按照定义的顺序,资源位置的优先级依次降低 ,但是一般情况下,Spring Boot 项目不需要 webapp 目录。
在一个新创建的 Spring Boot 项目中, 添加了 spring-boot-starter-web 依赖之后,在 source 下分别创建4个目录放入资源文件,数字表示不同位置资源的优先级。
此时, 在浏览器中输入“ http://localhost:8080/1.jpg ”即可看 classpath:/META-INF/resources/
目录下的 1.jpg,如果将 classpath:/META-INF/resources/
目录下的 1.jpg 删除,就会访问到classpath:/resources/
目录下的 1.jpg ,以此类推。
如果开发者使用 IntelliJ IDEA 创建 Spring Boot 项目, 就会默认创建出 classpath:/static/
目录,静态资源一般放在这个目录下即可。
如果默认静态资源过滤策略不能满足开发需求,也可以自定义静态资源过滤策略,自定义静态资源过滤策略有以下两种方式:
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/
过滤规则为/static/**
, 静态资源位置classpath:/static/
。
重新启动项目,在浏览器中输入 http://localhost:8080/static/1.jpg ,即可看到 classpath:/static/
目录下的资源。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
}
重新启动项目,在浏览器中输入 http://localhost:8080/static/1.jpg ,即可看到 classpath:/static/
目录下的资源。
Spring MVC 对文件上传做了简化,在Spring Boot 中对此做了进一步简化, 文件上传更为方便。
Java 中的文件上传共涉及两个组件,CommonsMultipartResolver
和 StandardServletMultipartResolver
,其中CommonsMultipartResolver 使用 commons-fileupload 来处理 multipart 请求,而StandardServletMultipartResolver 是基于 Servlet 3.0 来处理 multipart 请求的,若使用 StandardServletMultipartResolver ,则不需要添加额外的 jar 包。 Tomcat 7.0 开始就支持Servlet 3.0 了,而 Spring Boot 2.0.4 内嵌的 Tomcat 为 Tomcat 8.5.32 ,因此可以直接使用StandardServletMultipartResolver。而在 Spring Boot 提供的文件上传自动化配置类 MultipartAutoConfiguration
中,默认也是采用 StandardServletMultipartResolver ,部分源码如下:
根据这里的配置可以看出,如果开发者没有提供 MultipartResolver ,那么默认采用的MultipartResolver 就是 StandardServletMultipartResolver。因此,在 Spring Boot 中上传文件甚至可以做到零配置。下面来看具体上传过程。
在 resource 录下的 static 目录中创建一个 upload.html 文件,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFile" value="请选择文件">
<input type="submit" value="上传">
</form>
</body>
</html>
/upload
注意请求方法是 post , enctype是multipart/form-data
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.UUID; @RestController public class FileUploadController { @PostMapping("/upload") public String upload(MultipartFile uploadFile, HttpServletRequest req) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String realPath = req.getSession().getServletContext().getRealPath("/uploadFile/"); String format = sdf.format(new Date()); File folder = new File(realPath + format); if (!folder.isDirectory()) { folder.mkdirs(); } String oldName = uploadFile.getOriginalFilename(); String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."), oldName.length()); try { //文件保存操作 uploadFile.transferTo(new File(folder, newName)); //生成上传文件的访问路径, 并将访问路径返回 String filePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/uploadFile/" + format + newName; return filePath; } catch (IOException e) { e.printStackTrace(); } return "文件上传失败"; } }
最后在浏览器中进行测试。运行项目,在浏览器中输入 进行文件上传,如图所示。
单击“选择文件”按钮上传文件,文件上传成功后会返回上传文件的访问路径,如图所示。
当然,如果开发者需要对文件上传的细节进行配 ,也是允许的,代码如下:
# 是否开启文件上传支持,默认为 true
spring.servlet.multipart.enabled=true
# 文件写入磁盘的阈值,默认为 0
spring.servlet.multipart.file-size-threshold=0
# 上传文件的临时保存位置
spring.servlet.multipart.location=E:\\temp
# 上传的单个文件的最大大小,默认为 1MB
spring.servlet.multipart.max-file-size=1MB
# 多文件上传时文件的总大小,默认为 10MB
spring.servlet.multipart.max-request-size=10MB
# 文件是否延迟解析,默认为 false
spring.servlet.multipart.resolve-lazily=false
多文件上传和单文件上传基本一致,首先修改 HTML 文件,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/uploadBatch" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFiles" value="请选择文件" multiple>
<input type="submit" value="上传">
</form>
</body>
</html>
然后修改控制器,代码如下:
@PostMapping("/uploadBatch")
public String uploadBatch(@RequestPart("uploadFile") MultipartFile[] uploadFiles, HttpServletRequest req) {
//遍历 uploadFiles 数组分别存储
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。