@RestController 也是 Spring Boot 新增的一个注解,在项目开发中,接口与接口之间,前后端之间数据的传输都使用 Json 格式,在 Spring Boot 中,接口 返回 Json 格式的数据很简单,在 Controller 中使用 @RestController 注解即可返回 Json 格式的数据。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
String value() default "";
}
可以看出, @RestController 注解包含了原来的@Controller 和 @ResponseBody 注解,使用过 Spring 的朋友对 @Controller 注解已经非常了解了,这里不再赘述, @ResponseBody 注解是将返回 的数据结构转换为 Json 格式。所以在默认情况下,使用了 @RestController 注解即可将返回的数据 结构转换成 Json 格式,Spring Boot 中默认使用的 Json 解析技术框架是 jackson。
点开 pom.xml 中的 spring-boot-starter-web 依赖,可以看到一个 spring-boot-starter-json 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
次点进去上面这个 spring-boot-starter-json 依赖,可以看到:
在实际项目中,常用的数据结构无非有类对象、List对象、Map对象,我们看一下默认的 jackson 框架 对这三个常用的数据结构转成 json 后的格式如何。
1.1创建测试实体类
public class User {
private Long id;
private String username;
private String password;
/* 省略get、set和带参构造方法 */
}
1.2创建controller类
@RestController
@RequestMapping("/json")
public class JsonController {
@RequestMapping("/user")
public User getUser() {
return new User(1l, "coder", "123456");
}
@RequestMapping("/list")
public List<User> getUserList() {
List<User> userList = new ArrayList<>();
User user1 = new User(1l, "coderfeng", "123456");
User user2 = new User(2l, "fengcoder", "123456");
userList.add(user1);
userList.add(user2);
return userList;
}
@RequestMapping("/map")
public Map<String, Object> getMap() {
Map<String, Object> map = new HashMap<>(3);
User user = new User(1l, "coderwang", "123456");
map.put("作者信息", user);
map.put("博客地址", "https://blog.csdn.net/CodersCoder");
map.put("CSDN地址", "https://blog.csdn.net/CodersCoder");
map.put("粉丝数量", 0);
return map;
}
}
1.3测试不同数据类型返回的json
写好了接口,分别返回了一个 User 对象、一个 List 集合和一个 Map 集合,其中 Map 集合中的value 存的是不同的数据类型。接下来我们依次来测试一下效果。
在浏览器中输入: localhost:8080/json/user 返回 json 如下:
{“id”:1,“username”:“coder”,“password”:“123456”}
在浏览器中输入: localhost:8080/json/list 返回 json 如下:
[{“id”:1,“username”:“coderfeng”,“password”:“123456”},{“id”:2,“username”:“fengcoder”,“password”:“123456”}]
在浏览器中输入: localhost:8080/json/map 返回 json 如下:
{“作者信息”:{“id”:1,“username”:“coderwang”,“password”:“123456”},“CSDN地址”:“https://blog.csdn.net/CodersCoder”,“粉丝数量”:0,“博客地址”:“https://blog.csdn.net/CodersCoder”}
1.4对null的处理
我们难免会遇到一些 null 值出现,我们转 json 时,是不希望有这些 null 出现的,比如我们期望所有的 null 在转 json 时都变成 “” 这种空字符串,那怎么做呢?在 Spring Boot 中,我们做一下配置即可,新建一个 jackson 的配置类:
@Configuration
public class JacksonConfig {
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jsonObjectMapper(Jackson2ObjectMapperBuilder builder){
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString("");
}
});
return objectMapper;
}
}
更改上面map的例子,将博客地址改为null,重启项目,并且输入localhost:8080/json/map查看结果:
@RequestMapping("/map")
public Map<String, Object> getMap() {
Map<String, Object> map = new HashMap<>(3);
User user = new User(1l, "coderwang", "123456");
map.put("作者信息", user);
map.put("博客地址", null);
map.put("CSDN地址", "https://blog.csdn.net/CodersCoder");
map.put("粉丝数量", 0);
return map;
}
{“作者信息”:{“id”:1,“username”:“coderwang”,“password”:“123456”},“CSDN地址”:“https://blog.csdn.net/CodersCoder”,“粉丝数量”:0,“博客地址”:""}
可以看到,null已经转为空字符串了。
有很多朋友习惯于使用阿里巴巴的 fastJson 来做项目中 json 转换的相关工作,目前我们项目中使用的就是阿里的 fastJson,那么 jackson 和 fastJson 有哪些区别呢?根据网上公开的资料比较得到下表。
2.1fastJson依赖导入
以1.2.58为例
>
>com.alibaba >
>fastjson >
>1.2.58 >
>
2.2fastJson处理null
使用 fastJson 时,对 null 的处理和 jackson 有些不同,需要继承 WebMvcConfigurationSupport类,然后覆盖 configureMessageConverters 方法,在方法中,我们可以选择对要实现 null 转换的场景,配置好即可。如下:
@Configuration
public class FastJsonConfigs extends WebMvcConfigurationSupport {
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(
// 保留map空的字段
SerializerFeature.WriteMapNullValue,
// 将String类型的null转成""
SerializerFeature.WriteNullStringAsEmpty,
// 将Number类型的null转成0
SerializerFeature.WriteNullNumberAsZero,
// 将List类型的null转成[]
SerializerFeature.WriteNullListAsEmpty,
// 将Boolean类型的null转成false
SerializerFeature.WriteNullBooleanAsFalse,
// 避免循环引用
SerializerFeature.DisableCircularReferenceDetect);
converter.setFastJsonConfig(config);
converter.setDefaultCharset(Charset.forName("UTF-8"));
List<MediaType> mediaTypeList = new ArrayList<>();
// 解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"
mediaTypeList.add(MediaType.APPLICATION_JSON);
converter.setSupportedMediaTypes(mediaTypeList);
converters.add(converter);
}
}
在实际项目中,除了要封装数据之外,我们往往需要在返回的 json 中添加一些其他信息,比如返回一些状态码 code ,返回一些 msg 给调用者,这样调用者可以根据 code 或者 msg 做一些逻辑判断。所以在实际项目中,我们需要封装一个统一的json 返回结构存储返回信息。
3.1定义统一的 json 结构
由于封装的 json 数据的类型不确定,所以在定义统一的 json 结构时,我们需要用到泛型。统一的 json结构中属性包括数据、状态码、提示信息即可,构造方法可以根据实际业务需求做相应的添加即可,一般来说,应该有默认的返回结构,也应该有用户指定的返回结构。如下:
public class JsonResult<T> {
private T data;
private String code;
private String msg;
//没有数据返回,默认状态码为0000,msg为:success
public JsonResult(){
this.code="0000";
this.msg="success";
}
//没有数据返回,可以人为指定状态码和提示信息
public JsonResult(String code,String msg){
this.code = code;
this.msg = msg;
}
//有数据返回时,状态码为0000,msg为:success
public JsonResult(T data){
this.data = data;
this.code = "0000";
this.msg = "success";
}
//有数据返回,状态码为0000,人为指定提示信息
public JsonResult(String msg){
this.data = data;
this.code = "0000";
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
3.2 创建测试Controller 中的返回值类型
@RestController
public class JsonResultController {
@RequestMapping("/users")
public JsonResult<User> getUser() {
User user = new User(1l, "coder", "123456");
return new JsonResult<>(user);
}
@RequestMapping("/lists")
public JsonResult<List> getUserList() {
List<User> userList = new ArrayList<>();
User user1 = new User(1l, "coderfeng", "123456");
User user2 = new User(2l, "fengcoder", "123456");
userList.add(user1);
userList.add(user2);
return new JsonResult<>(userList,"user list get success");
}
@RequestMapping("/maps")
public JsonResult<Map> getMap() {
Map<String, Object> map = new HashMap<>(3);
User user = new User(1l, "coderwang", "123456");
map.put("作者信息", user);
map.put("博客地址", "null");
map.put("CSDN地址", "https://blog.csdn.net/CodersCoder");
map.put("粉丝数量", 0);
return new JsonResult<>(map);
}
}
在浏览器中输入: localhost:8080/json/users 返回 json 如下:
{“id”:1,“username”:“coder”,“password”:“123456”}
在浏览器中输入: localhost:8080/lists 返回 json 如下:
{“code”:“0000”,“data”:[{“id”:1,“password”:“123456”,“username”:“coderfeng”},{“id”:2,“password”:“123456”,“username”:“fengcoder”}],“msg”:“user list get success”}
在浏览器中输入: localhost:8080/maps 返回 json 如下:
{“code”:“0000”,“data”:{“作者信息”:{“id”:1,“password”:“123456”,“username”:“coderwang”},“CSDN地址”:“https://blog.csdn.net/CodersCoder”,“粉丝数量”:0,“博客地址”:“null”},“msg”:“success”}