2019独角兽企业重金招聘Python工程师标准>>>
摘要:其实很简单的处理方式,只不够优雅,或者说没有找到fastjson为其提供便捷的处理方式。因此记录下处理该问题的过程。
目标:将所有api请求,即响应为APPLICATION_JSON的内容做统一格式处理。 例如:@RestController 标注类方法放回值为List、 Map 或PO 类 增加响应字段 status。
- 当成功响应List 时,返回 {"data":[],"status":true}
- 当成功响应非List时,
- String : {"msg":"str","status":true}
- Map: {"k1":"v1","status":true}
- PO: {"column1":"v1","status":true}
- 当业务不能如预期处理,即异常响应:{"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
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, Function
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;
}