摘要:其实很简单的处理方式,只不够优雅,或者说没有找到fastjson为其提供便捷的处理方式。因此记录下处理该问题的过程。

目标:将所有api请求,即响应为APPLICATION_JSON的内容做统一格式处理。 例如:@RestController 标注类方法放回值为List、 Map 或PO 类 增加响应字段 status。

  1. 当成功响应List 时,返回 {"data":[],"status":true}
  2. 当成功响应非List时,
  • String : {"msg":"str","status":true}
  • Map: {"k1":"v1","status":true}
  • PO: {"column1":"v1","status":true}
  1. 当业务不能如预期处理,即异常响应:{"msg":"异常理由","status":false}

1:业务预期失败 在spring boot中配置HandlerExceptionResolver后,即可拦截处理所有异常,在此便可处理错误信息的json化。

@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver { @Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
response.setStatus(getStatusCodeValue());
response.setContentType(ContentType.APPLICATION_JSON.toString());
response.setCharacterEncoding(Charsets.UTF_8.toString());
...
}

**2.集合情况 ** 使用ControllerAdvice注册专用的内容拦截

@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
private static Class<?>[] types = { Iterable.class, Iterator.class }; @Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
Class<?> clz = returnType.getMethod().getReturnType();
for (Class<?> c : types) {
if (c.isAssignableFrom(clz)) {
return true;
}
}
return clz.isArray();
} @Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
Pages<?> p = Pages.builder(body);
if (MediaType.TEXT_HTML.equals(selectedContentType) || MediaType.TEXT_PLAIN.equals(selectedContentType)) {
if (!Stream.of(returnType.getMethod().getAnnotations())
.anyMatch(a -> a instanceof RequestMapping && !Objs.isEmpty(((RequestMapping) a).produces())))
response.getHeaders().setContentType(MediaType.parseMediaType(MediaType.APPLICATION_JSON_UTF8_VALUE));
return JSONObject.toJSONString(p);
}
return p;
}

3.基本类型,如String,Number等

	private static Class<?>[] types = { Clob.class, java.lang.CharSequence.class, java.lang.Number.class,
LocalDate.class, LocalDateTime.class, LocalTime.class, java.util.Date.class, java.sql.Blob.class,
java.sql.Array.class, }; @Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
Class<?> clz = returnType.getMethod().getReturnType();
for (Class<?> t : types) {
if (t.isAssignableFrom(clz)) {
return true;
}
}
return false;
} @Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
JSONObject js = new JSONObject();
js.put(AppEnum.status.getValue(), true);
js.put(AppEnum.message.getValue(), body);
if (MediaType.TEXT_HTML.equals(selectedContentType) || MediaType.TEXT_PLAIN.equals(selectedContentType)) {
if (!Stream.of(returnType.getMethod().getAnnotations())
.anyMatch(a -> a instanceof RequestMapping && !Objs.isEmpty(((RequestMapping) a).produces())))
response.getHeaders().setContentType(MediaType.parseMediaType(MediaType.APPLICATION_JSON_UTF8_VALUE));
return js.toString();
}
return js;
}

4.map

	@SuppressWarnings({ "serial", "unchecked", "rawtypes" })
private static final Map<Class<?>, Function<Object, Object>> types = new LinkedHashMap<Class<?>, Function<Object, Object>>() {
{
put(Map.class, obj -> {
((Map) obj).putIfAbsent(AppEnum.status.getValue(), true);
return obj;
});
put(org.json.JSONObject.class, obj -> {
JSONObject js = (JSONObject) obj;
if (!js.containsKey(AppEnum.status.getValue()))
js.put(AppEnum.status.getValue(), true);
return js;
});
}
}; @Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
Class<?> clz = returnType.getMethod().getReturnType();
if (types.containsKey(clz))
return true;
for (Class<?> c : types.keySet()) {
if (c.isAssignableFrom(clz)) {
return true;
}
}
return false;
} @Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
body = types.get(returnType.getMethod().getReturnType()).apply(body);
if (MediaType.TEXT_HTML.equals(selectedContentType) || MediaType.TEXT_PLAIN.equals(selectedContentType)) {
if (!Stream.of(returnType.getMethod().getAnnotations())
.anyMatch(a -> a instanceof RequestMapping && !Objs.isEmpty(((RequestMapping) a).produces())))
response.getHeaders().setContentType(MediaType.parseMediaType(MediaType.APPLICATION_JSON_UTF8_VALUE));
return JSONObject.toJSONString(body);
}
return body;
}

5.javabean

	@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return ParserConfig.global.getDeserializer(returnType.getMethod().getReturnType()) instanceof JavaBeanDeserializer;
} @Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
BeanGenerator bg = new BeanGenerator();
bg.setSuperclass(body.getClass());
bg.addProperty("status", Boolean.class);
Object obj = bg.create();
BeanUtil.beanCopier(obj, body);
try {
BeanUtils.setProperty(obj, "status", true);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} if (MediaType.TEXT_HTML.equals(selectedContentType) || MediaType.TEXT_PLAIN.equals(selectedContentType)) {
if (!Stream.of(returnType.getMethod().getAnnotations())
.anyMatch(a -> a instanceof RequestMapping && !Objs.isEmpty(((RequestMapping) a).produces())))
response.getHeaders().setContentType(MediaType.parseMediaType(MediaType.APPLICATION_JSON_UTF8_VALUE));
return JSONObject.toJSONString(obj);
}
return obj;
}

对于javabean。之前采用的是fastjson的BeforeFilter,但有个问题,在JavaBeanSerializer会重复的对javaBean对象进行序列化,这会导致除了在最外层的javaBean 中添加status外,还会导致所有的javaBean都被添加。因此后续改成了通过net.sf.cglib.beans.BeanGenerator 对javaBean 进行代理。

注意:不要单独使用Enhancer代理,在com.alibaba.fastjson.serializer.SerializeConfig中:会对代理类进行解析。

	private ObjectSerializer getObjectWriter(Class<?> clazz, boolean create) {
if (TypeUtils.isProxy(clazz)) {
Class<?> superClazz = clazz.getSuperclass(); ObjectSerializer superWriter = getObjectWriter(superClazz);
put(clazz, superWriter);
return superWriter;
} if (Proxy.isProxyClass(clazz)) {
Class handlerClass = null; if (interfaces.length == 2) {
handlerClass = interfaces[1];
} else {
for (Class proxiedInterface : interfaces) {
if (proxiedInterface.getName().startsWith("org.springframework.aop.")) {
continue;
}
if (handlerClass != null) {
handlerClass = null; // multi-matched
break;
}
handlerClass = proxiedInterface;
}
} if (handlerClass != null) {
ObjectSerializer superWriter = getObjectWriter(handlerClass);
put(clazz, superWriter);
return superWriter;
}
} //-------------
//TypeUtils
public static boolean isProxy(Class<?> clazz){
for(Class<?> item : clazz.getInterfaces()){
String interfaceName = item.getName();
if(interfaceName.equals("net.sf.cglib.proxy.Factory") //
|| interfaceName.equals("org.springframework.cglib.proxy.Factory")){
return true;
}
if(interfaceName.equals("javassist.util.proxy.ProxyObject") //
|| interfaceName.equals("org.apache.ibatis.javassist.util.proxy.ProxyObject")
){
return true;
}
}
return false;
}
 

使用fastjson统一序列化响应格式的更多相关文章

  1. ASP.NET Web API 2.0 统一响应格式

    传统实现 在搭建 Web API 服务的时候,针对客户端请求,我们一般都会自定义响应的 JSON 格式,比如: { "Data" : { "Id" : 100, ...

  2. spring boot / cloud (二) 规范响应格式以及统一异常处理

    spring boot / cloud (二) 规范响应格式以及统一异常处理 前言 为什么规范响应格式? 我认为,采用预先约定好的数据格式,将返回数据(无论是正常的还是异常的)规范起来,有助于提高团队 ...

  3. WebAPI接口设计:SwaggerUI文档 / 统一响应格式 / 统一异常处理 / 统一权限验证

    为什么还要写这类文章?因为我看过网上很多讲解的都不够全面,而本文结合实际工作讲解了swaggerui文档,统一响应格式,异常处理,权限验证等常用模块,并提供一套完善的案例源代码,在实际工作中可直接参考 ...

  4. SpringBoot06 统一响应格式

    1 要求 每个请求成功后,后台返回的响应格式都是一致的,例如: 2 创建一个视图模型 该模型用于格式化响应数据 package cn.xiangxu.springboottest.model.data ...

  5. spring boot:使接口返回统一的RESTful格式数据(spring boot 2.3.1)

    一,为什么要使用REST? 1,什么是REST? REST是软件架构的规范体系,它把资源的状态用URL进行资源定位, 以HTTP动作(GET/POST/DELETE/PUT)描述操作 2,REST的优 ...

  6. 001-RESTful服务最佳实践-RestFul准则、HTTP动词表示含义、合理的资源命名、响应格式XML和JSON

    一.概述 因为REST是一种架构风格而不是严格的标准,所以它可以灵活地实现.由于这种灵活性和结构自由度,对设计最佳实践也有很大的差异. API的方向是从应用程序开发人员的角度考虑设计选择. 幂等性 不 ...

  7. SpringBoot Redis使用fastjson进行序列化

    在使用spring-data-redis,默认情况下是使用org.springframework.data.redis.serializer.JdkSerializationRedisSerializ ...

  8. FastJson bean序列化属性顺序问题

    fastjson序列化一个java bean,默认是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序,这个特性需要1.1.42以上版本.示例如下. import co ...

  9. fastjson自定义序列化竟然有这么多姿势?

    本文介绍下fastjson自定义序列化的各种操作. 一.什么是fastjson? fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSO ...

随机推荐

  1. 关于VS2010工程各种路径注意事项汇总

    关于VS2010工程各种路径注意事项汇总 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 说明:前段时间调试,利用cmake生成的vs2010工程文件,虽然该 ...

  2. 乐字节Java编程语言发展,面向对象和类

    大家好,上次我们讲过了乐字节Java编程之方法.调用.重载.递归,接下来我们将会进入到Java封装的内容.Java编程语言发展,面向对象和类. 一.编程语言的发展 机器语言——直接由计算机的指令组成, ...

  3. json 和对象互相转换

    json 和对象互相转换 导入 Jar 包: import com.fasterxml.jackson.databind.ObjectMapper; Maven 地址: <!-- https:/ ...

  4. 一个简单的一个sql表遍历

    简单的一个sql表遍历 一般我们写储存过程或者其他sql语句的时候都会用到循环遍历数据,最常用的两种就是 1.游标 2.临时表+while 下面贴出示例代码 DECLARE @MinReLogID I ...

  5. JavaIO -- Reader 和 Writer

    一.简介 设计Reader和Writer继承层次结构主要是为了国际化.InputStream和OutStream流继承层次结构仅支持8位字节流,并不能很好的处理16位的Unicode字符.由于Unic ...

  6. ESP32 - 乐鑫官方Flash烧录工具使用

    第一步:打开软件flash_download_tools_v3.6.6.exe 第二步:点击ESP32 DownloadTool,启动我们板子的烧录工具 第三步:按照下图顺序,加载bin_prog目录 ...

  7. MySQL创建用户、为用户授权

    一.创建用户 1.root用户(管理员)登录,进入mysql数据库 mysql> use mysql Database changed 2.创建用户 1.创建用户: # 指定ip:192.168 ...

  8. go hello world第一个程序

    main 函数所在的包名必须使用main import "fmt"  导入包fmt  fmt包包含了Println方法的定义 func main() 程序运行入口方法和c语言相似 ...

  9. MySQL SELECT表达式的执行顺序是从左往右依次执行

    例子如下:(确保这几个变量都是初次使用,因为mysql的用户自定义变量会在整个连接session中存在) ,,; +--------+-------+---------+-------+ | +--- ...

  10. (二十)SpringBoot之集成mybatis:使用mybatis注解

    一.使用mybatis注解的集成 1.1 引入maven依赖 <dependencies> <dependency> <groupId>org.springfram ...