springboot的出现简化了web程序的开发, 想返回一个json的内容,只需在controller上加上 @RestController
即可实现. 非常方便.
但是项目中往往会有一些特殊的场景, 需要我们对返回json内容做特殊定制化处理.
需求场景
比如一个返回json内容
{
"name":"孙悟空",
"img":"http://www.majingjing.cn/static/123.png",
"bankCard":{
"bankName":"农业银行",
"cardId":"ABC-10001"
}
}
现在有两个url请求, 分别会得到这个user的json内容
- GET /customer/user
- GET /admin/user
此时有个场景是这样的
- GET /customer/user 返回内容如下
{
"name":"孙悟空",
"img":"http://www.majingjing.cn/static/123.png"
}
- GET /admin/user
{
"name":"孙悟空",
"img":"http://www.majingjing.cn/static/123.png",
"bankCard":{
"bankName":"农业银行",
"cardId":"ABC-10001"
}
}
返回内容为全部信息
分析
在不考虑写多个UserDto的情况下, 如何来实现了. 我们看下如何利用 jackson 来完成不同url来动态处理 对象的序列化操作.
实现
定义UserDto
@Getter
@Setter
public class UserDto {
private String name;
private String img;
private BankCard bankCard;
@Getter
@Setter
public static class BankCard{
private String bankName;
private String cardId;
}
}
定义Api
@RestController
public class UserController {
@GetMapping("/customer/user")
public UserDto user(){
return getUser();
}
@GetMapping("/admin/user")
public UserDto adminUser(){
return getUser();
}
private UserDto getUser(){
UserDto.BankCard bankCard = new UserDto.BankCard();
bankCard.setBankName("农业银行");
bankCard.setCardId("ABC-10001");
UserDto userDto = new UserDto();
userDto.setName("孙悟空");
userDto.setImg("http://www.majingjing.cn/static/123.png");
userDto.setBankCard(bankCard);
return userDto;
}
}
自定义MappingJackson2HttpMessageConverter
public abstract class AbstractMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
public AbstractMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper);
}
/**
* 判断给定的url是否匹配
*
* @param url 请求的url
* @return boolean 是否匹配
*/
abstract boolean isMatch(String url);
private boolean isMatch() {
//从上下文中拿到请求地址
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(null ==requestAttributes){
return false;
}
String requestPath = requestAttributes.getRequest().getRequestURI();
if (StringUtils.isBlank(requestPath)) {
return false;
}
return isMatch(requestPath);
}
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
if (!isMatch()) {
return false;
}
return super.canRead(clazz, mediaType);
}
@Override
public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
if (!isMatch()) {
return false;
}
return super.canRead(type, contextClass, mediaType);
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
if (!isMatch()) {
return false;
}
return super.canWrite(clazz, mediaType);
}
@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
if (!isMatch()) {
return false;
}
return super.canWrite(type, clazz, mediaType);
}
}
public class AdminMappingJackson2HttpMessageConverter extends AbstractMappingJackson2HttpMessageConverter {
public AdminMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper);
}
/**
* 判断给定的url是否匹配
*
* @param url 请求的url
* @return boolean 是否匹配
*/
boolean isMatch(String url){
return url.startsWith("/admin/");
}
}
``````java
public class CustomerMappingJackson2HttpMessageConverter extends AbstractMappingJackson2HttpMessageConverter {
public CustomerMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper);
}
/**
* 判断给定的url是否匹配
*
* @param url 请求的url
* @return boolean 是否匹配
*/
boolean isMatch(String url){
return url.startsWith("/customer/");
}
}
配置HttpMessageConverter
@JsonIgnoreType
public @interface IgnoreType {
}
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder customerBuilder = new Jackson2ObjectMapperBuilder()
//忽略UserDto.BankCard
.mixIn(UserDto.BankCard.class, IgnoreType.class);
Jackson2ObjectMapperBuilder adminBuilder = new Jackson2ObjectMapperBuilder();
converters.add(0, new CustomerMappingJackson2HttpMessageConverter(customerBuilder.build()));
converters.add(1, new AdminMappingJackson2HttpMessageConverter(adminBuilder.build()));
}
}
此时我们已经将自定义的两个 HttpMessageConverter
加人到WebConfiguration
中了
结果验证
启动项目, 验证下结果
可以看到已经实现了预期的结果, 实现了
- GET /customer/user 不显示
bankCard
- GET /admin/user 显示
bankCard
通过此示例介绍, 我们可以在项目中配合jackson
完成各种定制化的操作.
比如之前写过的文章, 多语言 , 特殊对象的解析等.