博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMvc4.1:注解JsonView与泛型返回类
阅读量:4231 次
发布时间:2019-05-26

本文共 6011 字,大约阅读时间需要 20 分钟。

前段时间,因工作需要,要做一个WEB层,放在展示层(HTML,JS,移动端)和服务层(DubboX)中间,使用JSON暴露数据给展示层。经过一番调研,决定使用SpringMVC4.1.6+Jackson2.5.1来搭建此项目。

 

常规搭建略去不提,因为用的是SpringMVC4.1以上的版本,因此决定在返回JSON数据的时候,使用新注解@JsonView来支持同一个VO显示不同的JSON视图,其目的主要是隐藏VO中的敏感字段,节约流量,减少不必要字段输出,方便展示层(JS)处理。框架搭建过程很顺利,但在返回封装好的泛型JSON类的时候,出现了问题,即泛型属性对象在指定JsonView的视图之后渲染失败。经过对Jackson源码的初步浏览和跟踪,终于找到问题所在,现将解决过程总结在此。

问题描述:

 

JsonView使用分为三步:

1:定义view相关接口。
2:在VO的属性上使用JsonView注解,此为定义阶段,此步可以和第一步放在一起。
3:在Action的方法上使用JsonView注解,此为使用阶段。

 
首先,

定义VO如下,同时在VO里面定义了两个接口(IOnlyIdView ,IOnlyIdView)用于显示不同JSON视图:

public final class Depot {    public interface IOnlyIdView {}    public interface IOnlyNameView{}    @JsonView(IOnlyIdView.class)    private long id;    @JsonView(IOnlyNameView.class)    private String name;    private long num;    public long getId() {        return id;    }    public void setId(long id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public long getNum() {        return num;    }    public void setNum(long num) {        this.num = num;    }}

然后,定义Action的方法如下:

@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})    @JsonView(Depot.IOnlyNameView.class)//定义不同的view 隐藏掉一些字段    public Depot getDepotInfo(@PathVariable long id) {        Depot depot = new Depot();        depot.setId(100);        depot.setName("北京001仓");        depot.setNum(888);        return depot;    } 

 

则将项目运行之后结果打印(说明Depot的JsonView视图生效):

{"name":"北京001仓"}
 
将该方法getDepotInfo返回值改为List<Depot> ,方法注解不变,方法体改为
Depot depot = new Depot();    depot.setId(100);    depot.setName("北京001仓");    depot.setNum(888);    List
ret = new ArrayList<>(); ret.add(depot); return ret;
 

则将项目运行之后结果打印(说明放在集合容器中,JsonView视图生效):

[{"name":"北京001仓"}]
 
 
   
将该方法返回值改为JsonResult<Depot>,方法注解不变,方法体改为:
depot.setId(100);    depot.setName("北京001仓");    depot.setNum(888);    List
ret = new ArrayList<>(); ret.add(depot); return new JsonResult(ret,true,"ok");
则将项目运行之后结果打印:
{}
 
JsonResult是我们架构设计中统一返回的类。所有VO都要放到该对象中返回。
 

JsonResult的定义如下:

public class JsonResult
implements Serializable { private static final long serialVersionUID = 3863559687276427577L; private boolean success = true; public String message; private String secure;//安全凭据 private T data;//数据 public JsonResult() { } public JsonResult(T data, Boolean success, String message) { // TODO Auto-generated constructor stub this.data = data; this.success = success; this.message = message; } public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public static
JsonResult
newResult() { return new JsonResult
(); } public String getSecure() { return secure; } public void setSecure(String secure) { this.secure = secure; }}

 
问题解决:
 

SpringMVC 将VO本身以及和Action上的JsonView 注解内容传递给Jackson,由Jackson在渲染视图时进行处理。经过跟踪,Jackson在解析不同的java对象的时候,使用不同的Serializer来把对象转换为json串。比如当Action返回值为Depot对象的时候,Jackson使用基础的BeanSerializer来处理,而返回值为List<Depot>的时候,则使用IndexedListSerializer来解析。

我们也可以通过在类上加注解 @JsonSerialize(using=CustomSerializer.class)来自定义某个类的Serializer。本例中,经过初步的跟踪,发现BeanSerializer在处理JsonResult的时候,如果JsonResult的属性不含JsonView视图接口,则不去过滤该属性所包含的所有视图。所以,要为JsonResult属性也定义一个视图注解,并且,视图注解接口要被泛型vo里面的属性视图接口所继承,才能实现整体视图的正常渲染和过滤。有点拗口,看解决范例吧。呵呵

为JsonResult定义一个视图接口,如下:

public class GeneralViews {	    /**	     * use in error views	     */	    public interface IErrorView{};	    /**	     * use in success views	     */	    public interface INormalView extends IErrorView{} ;	}
则JsonResult类改造为:
public class JsonResult
implements Serializable { private static final long serialVersionUID = 3863559687276427577L; @JsonView(GeneralViews.IErrorView.class) private boolean success = true; @JsonView(GeneralViews.IErrorView.class) public String message; @JsonView(GeneralViews.INormalView.class) private String secure;//安全凭据 @JsonView(GeneralViews.INormalView.class) private T data;//数据 public JsonResult() { } public JsonResult(T data, Boolean success, String message) { // TODO Auto-generated constructor stub this.data = data; this.success = success; this.message = message; } public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public static
JsonResult
newResult() { return new JsonResult
(); } public String getSecure() { return secure; } public void setSecure(String secure) { this.secure = secure; } }
最后,所用的业务VO改为:
public final class Depot {	    public interface IOnlyIdView extends GeneralViews.INormalView{}	    public interface IOnlyNameView extends GeneralViews.INormalView{}	    @JsonView(IOnlyIdView.class)	    private long id;	    @JsonView(IOnlyNameView.class)	    private String name;	    private long num;	    public long getId() {		return id;	    }	    public void setId(long id) {		this.id = id;	    }	    public String getName() {		return name;	    }	    public void setName(String name) {		this.name = name;	    }	    public long getNum() {		return num;	    }	    public void setNum(long num) {		this.num = num;	    }	}
再次运行Action,则结果为:
{"success":true,"message":"ok","secure":null,"data":[{"name":"北京001仓"}]} 
 
最终,通过这样的方式,成功实现了JsonView视图在泛型属性对象上的传递。

转载地址:http://mjpqi.baihongyu.com/

你可能感兴趣的文章
CentOS下YUM常用命令
查看>>
CentOS yum 源的配置与使用
查看>>
系统软件
查看>>
Linux Centos下软件的安装与卸载方法
查看>>
查看linux 下已经安装的软件包信息
查看>>
yum -y
查看>>
Centos5.7--64位下使用RPMForge软件仓库
查看>>
centos7 安装 mariadb 的正确命令
查看>>
CentOS配置YUM源(163、搜狐)
查看>>
linux 0号进程和1号init进程的用途。
查看>>
Linux下chkconfig命令详解
查看>>
centos添加yum源
查看>>
Linux centos添加源+网易163源+搜狐源
查看>>
Linux rpm 命令参数使用详解[介绍和应用]
查看>>
Redhat/CentOS 软件安装之RPM和YUM
查看>>
Linux strace命令
查看>>
看文档还是看源代码+调试--附带rsyslog的例子
查看>>
查看 SELinux状态及关闭SELinux
查看>>
CentOS常用到的查看系统命令
查看>>
如何查看已安装的CentOS版本信息
查看>>