场景

我们团队现在面临着多端数据接口对接的问题,为了解决这个问题我们定义了接口对接的规范,

前端(安卓,Ios,web前端)和后端进行了数据的格式规范的讨论,确定了json的数据格式:

  1. {
  2. "code":"200",
  3. "data":{"":""},
  4. "message":"处理成功"
  5. }
  6. {
  7. "code":"300",
  8. "data":{"":""},
  9. "message":"没有此用户"
  10. }

code代表请求处理状态:200为正常处理,300为业务异常处理,500就系统异常处理。

data代表后台返回的数据。

message后台的提示语,正常或者成功的时候会返回错误原因。

问题来了

让每一个人对每一个json视图的返回值都要进行包装的话,岂不很麻烦,

这个时候AOP就登场了,我们可以利用aop的思想在请求返回json之后还未response到客户端时为其包装上一层。

实现步骤

启用aop

  1. <!-- base-package 如果多个,用“,”分隔 -->
  2. <context:component-scan base-package="com.we,cn.isuyang">
  3. <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
  4. <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
  5. </context:component-scan>
  6. <!-- 打开aop 注解 -->
  7. <aop:aspectj-autoproxy />

创建切面

  1. /**
  2. * json返回切面
  3. * <p>
  4. * 用于处理json返回结果
  5. *
  6. * @author ZhuangJunxiang(529272571@qq.com)
  7. * @Date 2017年4月28日
  8. */
  9. @Component
  10. @Aspect
  11. @Order(2)
  12. public class JsonReturnAspect {
  13. /**
  14. * 设置分页默认值
  15. * <p>
  16. * 如果分页没有设置值,则默认从系统的配置文件里读取
  17. *
  18. * @param pjp 切点
  19. */
  20. @Around(value = "@annotation(org.springframework.web.bind.annotation.ResponseBody)")
  21. @Order(1)
  22. public Object warp(final ProceedingJoinPoint pjp) throws Throwable {
  23. Object list = pjp.proceed();
  24. if (isReturnVoid(pjp)) {
  25. HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
  26. .getResponse();
  27. if (isNeedWrap(pjp)) {
  28. response.getWriter().write(JsonUtil.toJson(success("操作成功")));
  29. }
  30. return list;
  31. }
  32. return data(list);
  33. }
  34. /**
  35. * 是否需要包裹
  36. *
  37. * @param pjp 切点
  38. *
  39. * @return true表示不需要
  40. */
  41. private boolean isNeedWrap(final ProceedingJoinPoint pjp) {
  42. Method method = AspectUtil.getMethod(pjp);
  43. return !method.isAnnotationPresent(Void.class);
  44. }
  45. /**
  46. * 是否返回空
  47. *
  48. * @param pjp
  49. * @return true:返回类型为void,false:返回类型不是void
  50. */
  51. private boolean isReturnVoid(ProceedingJoinPoint pjp) {
  52. Method method = AspectUtil.getMethod(pjp);
  53. Class<?> returnType = method.getReturnType();
  54. return "void".equals(returnType.getName());
  55. }
  56. /**
  57. * 构建成功后的返回对象
  58. * <p>
  59. * 消息为空时,不提示,不为空则进行提示
  60. *
  61. * @param message 成功消息
  62. * @return json对象
  63. */
  64. public static Map<String, Object> success(final String message) {
  65. Map<String, Object> map = MapUtil.map();
  66. map.put("code", StatusCode.SUCCESS.key());
  67. map.put("message", message);
  68. map.put("data","");
  69. return map;
  70. }
  71. /**
  72. * 构建成功后的返回对象
  73. * <p>
  74. * 消息为空时,不提示,不为空则进行提示
  75. *
  76. * @param message 成功消息
  77. * @return json对象
  78. */
  79. public static Map<String, Object> data(final Object data) {
  80. Map<String, Object> map = MapUtil.map();
  81. map.put("code", StatusCode.SUCCESS.key());
  82. map.put("message", message);
  83. map.put("data",data);
  84. return map;
  85. }
  86. }

分析一下

@Component 这个注解表示将这个对象交给spring容器进行实例化

@Aspect 表示这是一个切面类

@Around(value = "@annotation(org.springframework.web.bind.annotation.ResponseBody)")

表示凡是方法上带有@ResponseBody注解的都是这个切面中切点,换句话说都会被拦截。

注意:

warp方法中的ProceedingJoinPoint参数只有环绕通知才可以使用JoinPoint的子类ProceedingJoinPoint,

各连接点类型可以调用代理的方法,并获取、改变返回值。否则就是用JoinPoint。

情况一:假设conroller类中的函数不需要任何返回值

比如:我对一个实体对象进行更新我只需要把更新结果返回去就OK了,不需要填充数据

返回的数据格式:

{

"code":"200",

"data":"",

"message":"处理成功"

}

实现思路:

在切面处理类的处理函数中获取到这个函数的返回值类型如果是void就返回指定格式的数据。

上面的isReturnVoid()就是做这样的一个判断。

你只需要将函数的返回值为void即可:

  1. @RequestMapping
  2. @ResponseBody
  3. public void add(long matchId, Model model) {
  4. slxSignupViewService.setAddInfo(matchId, model);
  5. }

情况二:假设conroller类中的函数的返回值不需要包裹呢

比如:

某些前端插件以及第三方对接(支付)的返回值是规定好的,

以及下载文件,我们这些就是多余了,

实现思路:

自定一个@Void的注解:

  1. /**
  2. * 空注解
  3. * <p>
  4. * 用于标识将controller层中的返回值原模原样的out出去
  5. *
  6. * @author WangSen(wangsenhehe@126.com)
  7. * @Date 2017年8月17日
  8. */
  9. @Target({ ElementType.METHOD })
  10. @Retention(RetentionPolicy.RUNTIME)
  11. @Documented
  12. public @interface Void {
  13. }

在controller层的方法上添加这个注解

  1. /**
  2. * 支付完成
  3. */
  4. @Void
  5. @ResponseBody
  6. @RequestMapping
  7. public void payFinish() throws IOException {
  8. alipayViewService.payFinish();
  9. }

在这个切面处理类上判断这个函数是否包含这个注解如果包含

就不作处理,原模原样的返回出去。

JsonReturnAspect类中的isNeedWrap()方法就是处理这个需求。

参考资料

http://blog.csdn.net/zx13525079024/article/details/51884234

自定义spring mvc的json视图的更多相关文章

  1. spring mvc返回json字符串的方式

    spring mvc返回json字符串的方式 方案一:使用@ResponseBody 注解返回响应体 直接将返回值序列化json            优点:不需要自己再处理 步骤一:在spring- ...

  2. Spring MVC 数据模型与视图

      从控制器获取数据后,会装载数据到数据模型和视图中,然后将视图名称转发到视图解析器中,通过解析器解析后得到最终视图,最后将数据模型渲染到视图中,展示最终的结果给用户. 用ModelAndView来定 ...

  3. spring mvc返回json字符串数据,只需要返回一个java bean对象就行,只要这个java bean 对象实现了序列化serializeable

    1.spring mvc返回json数据,只需要返回一个java bean对象就行,只要这个java bean 对象实现了序列化serializeable 2. @RequestMapping(val ...

  4. Spring Mvc 输出Json(iwantmoon.com出品)

    原文:http://iwantmoon.com/Post/f94e49caf9b6455db7158474bab4c4dd 因为工作需要,现在要去做开放平台,考虑了多种方案之后,基本确定 下来,Htt ...

  5. Spring MVC 的json问题(406 Not Acceptable)

    原因 : 就是程序转换JSON失败. 在pom.xml 加上 <dependency> <groupId>com.fasterxml.jackson.core</grou ...

  6. spring mvc: 资源绑定视图解析器(不推荐)

    spring mvc: 资源绑定视图解析器(不推荐) 不适合单控制器多方法访问,有知道的兄弟能否告知. 访问地址: http://localhost:8080/guga2/hello/index 项目 ...

  7. spring mvc:内部资源视图解析器2(注解实现)@Controller/@RequestMapping

    spring mvc:内部资源视图解析器2(注解实现)  @Controller/@RequestMapping 访问地址: http://localhost:8080/guga2/hello/goo ...

  8. spring mvc:内部资源视图解析器(注解实现)@Controller/@RequestMapping

    spring mvc:内部资源视图解析器(注解实现)@Controller/@RequestMapping 项目访问地址: http://localhost:8080/guga2/hello/prin ...

  9. ajax使用向Spring MVC发送JSON数据出现 org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported错误

    ajax使用向Spring MVC发送JSON数据时,后端Controller在接受JSON数据时报org.springframework.web.HttpMediaTypeNotSupportedE ...

随机推荐

  1. Django1.11搭建一个简易上传显示图片的后台

    本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 项目展示需要,之前没研究过Django,网上查资料快速做了一个后台,写下了防止自己忘了. p ...

  2. 版本控制之四:SVN客户端重新设置帐号和密码(转)

    在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果 ...

  3. Ionic3 遇到的一些错误-submodule update -q --init --recursive

    解决方法: ionic start myTabs tabs --skip-deps cd .\myTabs cnpm install --save-dev ionic serve > npm i ...

  4. glog 使用

    glog 使用 来源:http://www.cnblogs.com/tianyajuanke/archive/2013/02/22/2921850.html 一.安装配置 1.简介 google 出的 ...

  5. stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结

    stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结 1. auto_ptrauto_ptr主要是用来解决资源自动释放的问题,比如如下代码:voi ...

  6. GCD(欧拉函数)

    GCD Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissio ...

  7. ajax跨域请求解决方案

    大家好,今天我们学习了js的跨域请求的解决方案,由于JS中存在同源策略,当请求不同协议名,不同端口号.不同主机名下面的文件时,将会违背同源策略,无法请求成功!需要进行跨域处理! 方案一.后台PHP进行 ...

  8. hbase的HQuorumPeer和QuorumPeerMain

    hbase是列式数据库,既可以单机也可以以集群的方式搭建,以集群的方式搭建一般建立在hdfs之上. 分布式的hbase如何启动? 首先启动hadoop,然后就来问题了:zookeeper和hbase的 ...

  9. django 实现同一个ip十分钟内只能注册一次(redis版本)

    上一篇文章,django 实现同一个ip十分钟内只能注册一次 的时候,我们在注册的时候选择使用的使我们的数据库来报错我们的注册的ip信息,可是如果数据量大,用户多的时候,单单靠我们的数据库 来储存我们 ...

  10. Maven合并多个war包的工程需要用到的插件

    <build> <finalName>WebSite</finalName> <plugins> <!-- 配置war包合并的插件 --> ...