一、返回JSON数据二、静态资源访问三、文件上传
一、返回JSON数据- 默认实现
JSON是目前主流的前后端数据创输方式,SpringMVC中使用消息转换器HttpMessageConverter对JSON的转换提供了很好的支持,在SpringBoot中更进一步,对相关配置做了进一步简化。默认情况下
添加依赖
org.springframework.boot spring-boot-starter-web
这个依赖中默认加入了jackson-databind作为JSON处理器,此时不需要添加额外的JSON处理器就能返回一段JSON了。
如果需要频繁的使用@ResponseBody注解,可以采用@RestController组合注解代替@Controller和@ResponseBody
这是通过Spring中默认提供的MappingJackson2HttpMessageConverter来实现的。
- 自定义转换器
常见的JSON处理器除了jackson-databind之外,还有Gson和fastjson。
使用Gson
Gson是Google是一个开源JSON解析框架。使用GSON,需要除去默认的jackson-databind,然后添加Gson依赖。
org.springframework.boot spring-boot-starter-web com.fasterxml.jackson.core jackson-databind com.google.code.gson gson
由于SpringBoot中默认提供了Gson的自动转换类GsonHttpMessageConvertersConfiguration,因此Gson的依赖添加成功后,可以像使用jackson-databind那样直接使用Gson。如果对日期数据进行格式化,那么需要开发者自动义HttpMessageConverter,自定义HttpMessageConverter可以通过如下方式:
首先GsonHttpMessageConvertersConfiguration中的一段源码:
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnBean({Gson.class})
@Conditional({GsonHttpMessageConvertersConfiguration.PreferGsonOrJacksonAndJsonbUnavailableCondition.class})
static class GsonHttpMessageConverterConfiguration {
GsonHttpMessageConverterConfiguration() {
}
@Bean
@ConditionalOnMissingBean
GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
converter.setGson(gson);
return converter;
}
}
@ConditionalOnMissingBean注解表示当前项目中没有提供GsonHttpMessageConverter时才会使用默认的GsonHttpMessageConverter所以只需要提供一个GsonHttpMessageConverter即可。
@Configuration
public class gsonConverter {
@Bean
GsonHttpMessageConverter gsonHttpMessageConverter() {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("yyyy-MM-dd");
gsonBuilder.excludeFieldsWithModifiers(Modifier.PROTECTED);
Gson gson = gsonBuilder.create();
converter.setGson(gson);
return converter;
}
}
解释:
提供一个 GsonHttpMessageConverter 的实例设置Gson解析时日期的格式设置Gson解析时修饰符为PROTECTED的字段被过滤掉创建Gson对象放入GsonHttpMessageConverter 的实例并返回converter
Book修改如下price改为protected类型。
使用fastjson
fastjson是阿里巴巴的一个开源JSON框架,是目前JSON解析速度最快的开源框架,该框架也可以集成到Spring Boot中。不同于Gson,fastjson继承完成之后并不能立马使用。需要开发者提供相应的HttpMessageConverter后才能使用,集成fastjson的步骤如下:
org.springframework.boot spring-boot-starter-web com.fasterxml.jackson.core jackson-databind
@Configuration
public class fastjsonConverter {
@Bean
FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setCharset(Charset.forName("GBK"));
fastJsonConfig.setDateFormat("yyyy-MM-dd");
fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteClassName,
SerializerFeature.WriteMapNullValue,
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty
);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
return fastJsonHttpMessageConverter;
}
}
解析:配置了JSON解析过程的一些细节,例如日期格式、数据编码、是否在生成的JSON中输出类名、是否输出value为null的数据、生成的JSON格式化、空集合输出[]而非null、空字符串输出“”而非null等基本配置
fastJson配置另一种方式
在SpringBoot项目中,当开发者引入spring-boot-starter-web依赖之后,该依赖又依赖了spring-boot-autoconfigure,在这个自动化配置中,有一个WebMvcAutoConfiguration类提供了对SpringMVC的基本配置,如果某一项自动化配置不满足开发需求,可以针对该项自定义配置,只需要实现WebMvcConfigurer接口即可(在Spring5.0之前是通过继承WebMvcConfigurerAdapter类来实现的)
package com.example.demo.config;
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 org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.Charset;
import java.util.List;
@Configuration
public class fastjsonMvcConverter implements WebMvcConfigurer {
public void configureMessageConverters(List> converters) {
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setCharset(Charset.forName("GBK"));
fastJsonConfig.setDateFormat("yyyy-MM-dd");
fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteClassName,
SerializerFeature.WriteMapNullValue,
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty
);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
converters.add(fastJsonHttpMessageConverter);
}
}
gson也可以使用实现WebMvcConfigurer接口这种方式
package com.example.demo.config;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.lang.reflect.Modifier;
import java.util.List;
@Configuration
public class fastjsonMvcConverter implements WebMvcConfigurer {
public void configureMessageConverters(List> converters) {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("yyyy-MM-dd");
gsonBuilder.excludeFieldsWithModifiers(Modifier.PROTECTED);
Gson gson = gsonBuilder.create();
converter.setGson(gson);
converters.add(converter);
}
}
此时的效果如下:
上述结果中发现转换并没有生效。
原因如下:
这是因为SpringBoot在项目中没有GsonHttpMessageConverter时,SpringBoot自己会提供一个GsonHttpMessageConverter,所以此时需要替换掉原有的GsonHttpMessageConverter。代码如下:
package com.example.demo.config;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.lang.reflect.Modifier;
import java.util.List;
@Configuration
public class fastjsonMvcConverter implements WebMvcConfigurer {
public void configureMessageConverters(List> converters) {
converters.remove(7);
converters.remove(7);
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("yyyy-MM-dd");
gsonBuilder.excludeFieldsWithModifiers(Modifier.PROTECTED);
Gson gson = gsonBuilder.create();
converter.setGson(gson);
converters.add(converter);
}
}
二、静态资源访问
- 默认策略
SpringBoot中对于SpringMVC的自动化配置都在WebMvcAutoConfiguration类中,因此对于默认的静态资源过滤策略可以从这个类一窥究竟。
在WebMvcAutoConfiguration类中有一个静态内部类WebMvcAutoConfigurationAdapter,实现了WebMvcConfigurer接口。WebMvcConfigurer接口中有一个方法addResourceHandlers,是用来配置静态资源过滤的。方法在WebMvcAutoConfigurationAdapter类中得到了实现。
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
this.addResourceHandler(registry, "/webjars/**", "classpath:/meta-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
SpringBoot在这里进行了默认的静态资源过滤位置,其中staticPathPattern默认定义在WebMvcProperties中定义内容如下:
staticLocation获取到的默认静态资源位置定义在Resources resourceProperties中代码如下:
注意:按照定义的顺序,静态资源位置的优先级依次降低。
如果使用Idea创建SpringBoot项目,就会默认创建出classpath:/static/目录
- 自定义策略
如果默认的静态资源策略不能满足开发需求,也可以自定义静态资源过滤策略,自定义静态资源过滤策略有以下两种方式:
在配置文件中定义
可以在application.properties中直接定义过滤规则和静态,代码如下:
spring.mvc.static-path-pattern=/static/** spring.resources.static-locations=classpath:/static/ ---过时啦
Java编码定义
只需要实现WebMvcConfigurer接口即可,然后实现该接口的addResourceHandlers方法即可。
package com.example.demo.config;
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 WebMvcResourceConfig implements WebMvcConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
}
三、文件上传
java中的文件上传一共涉及两个组件,一个是CommonsMultipartResolver,另一个是StandardServletMuttipartResolver,其中CommonsMultipartResolver使用commons-fileupload来处理multipart请求,而StandardServletMultipartResolver则是基于Servlet3.0来处理multipart请求的,因此若使用StandardServletMultipartResolver,则不需要添加额外的jar包。Tomcat7.0开始就支持Servlet3.0了,而SpringBoot 2.0.4内嵌的Tomcat为Tomcat 8.5.32,因此可以直接使用StandardServletMultipartResovler。而SpringBoot提供的文件上传自动化配置类MultipartAutoConfiguration中,默认也是采用StandardServletMultipartResovler。
public class MultipartAutoConfiguration {
....
@Bean(
name = {"multipartResolver"}
)
@ConditionalOnMissingBean({MultipartResolver.class})
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
}
根据这里的配置可以看出,如果开发者没有提供MultipartResolver,那么默认采用的MultipartResolver就是StandardServletMultipartResolver。因此,在SpringBoot中上传文件可以做到零配置。
单文件上传
@RestController
public class FileUploadController {
SimpleDateFormat simpleDataFormat = new SimpleDateFormat("yyyy-MM-dd");
@PostMapping("/upload")
//可以使用@RequestPart
public String upload(@RequestParam("uploadfile") MultipartFile multipartFile, HttpServletRequest request) throws IOException {
String filepath = "C:" + File.separator + "Users" + File.separator + "tiaoxiaozi" + File.separator + "Desktop" + File.separator + "uploadFile" + File.separator + "aa" + File.separator;
String format = simpleDataFormat.format(new Date());
File folder = new File(filepath + format);
if (!folder.exists()) {
folder.mkdirs();
}
String uploadfile = request.getParameter("uploadfile");
String oldName = multipartFile.getOriginalFilename();
String oldName_org = oldName.substring(0, oldName.indexOf("."));
String uuid = UUID.randomUUID().toString();
String newName = uuid + oldName.substring(oldName.indexOf("."));
multipartFile.transferTo(new File( folder , newName));
return "上传成功";
}
@RequestParam注释还可用于将“多部分/表单数据”请求的一部分与支持相同方法参数类型的方法参数相关联。主要区别在于,当方法参数不是字符串或原始多部分文件/部分时,@RequestParam依赖于通过注册转换器或PropertyEditor进行的类型转换,而RequestPart依赖于HttpMessageConverters,同时考虑到请求部分的“内容类型”头。RequestParam可能与name-value表单字段一起使用,而RequestPart可能与包含更复杂内容的部分(例如JSON、XML)一起使用。
spring.servlet.multipart.enabled=true //是否开启文件上传支持,默认为true spring.servlet.multipart.file-size-threshold=0 //文件写入磁盘的阈值,默认为0 spring.servlet.multipart.location=E:\temp // 上传文件的临时保存位置 spring.servlet.multipart.max-file-size=1MB // 上传的单个文件的最大大小 默认为1MB spring.servlet.multipart.max-request-size=10MB // 多文件上传时的总大小,默认为10MB spring.servlet.multipart.resolve-lazily=true // 文件是否延迟解析,默认为false
多文件上传
@RestController
public class FileUploadController {
SimpleDateFormat simpleDataFormat = new SimpleDateFormat("yyyy-MM-dd");
@PostMapping("/upload")
//可以使用@RequestPart
public String upload(@RequestParam("uploadfile") MultipartFile[] multipartFile, HttpServletRequest request) throws IOException {
String filepath = "C:" + File.separator + "Users" + File.separator + "tiaoxiaozi" + File.separator + "Desktop" + File.separator + "uploadFile" + File.separator + "aa" + File.separator;
String format = simpleDataFormat.format(new Date());
File folder = new File(filepath + format);
if (!folder.exists()) {
folder.mkdirs();
}
String uploadfile = request.getParameter("uploadfile");
for (int i = 0; i < multipartFile.length; i++) {
String oldName = multipartFile[i].getOriginalFilename();
String oldName_org = oldName.substring(0, oldName.indexOf("."));
String uuid = UUID.randomUUID().toString();
String newName = uuid + oldName.substring(oldName.indexOf("."));
multipartFile[i].transferTo(new File( folder , newName));
}
return "上传成功";
}
}



