准確來說,@JsonView注解不是Spring的,它位於jackson-annotation包中; 作用:SpringMvc使用@ResponseBody將結果以json返回客戶端, 有些實體類的某些字段可以不被包括在JSON中;
思考了這種情況可能適用的情形:有多方調用這個接口,需要針對不同業務場景返回不同形式的JSON,但是這種情況的話 只拷貝需要的屬性 再返回也能達到目的,就當多學了一種注解、處理方式了;
一.作為 Jackson Api使用:
public class View {
public static class UserPublic{}
public static class UserPrivacy{}
}
public class User {
@JsonView(View.UserPublic.class)
public int id;
@JsonView(View.UserPrivacy.class)
public String name;
}
補充說明:每一個@JsonView標注在屬性上,代表該屬性在被序列化時候會被轉化,視圖名字為value指向的class;
public class User {
@JsonView(View.UserPublic.class)
int id;
@JsonView(View.UserPrivacy.class)
String name;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) throws JsonProcessingException {
User user = new User();
user.setId(1);
user.setName("lvbb");
ObjectMapper mapper = new ObjectMapper();
String res1 = mapper.writerWithView(View.UserPublic.class).writeValueAsString(user);
System.out.println(res1);
String res2 = mapper.writerWithView(View.UserPrivacy.class).writeValueAsString(user);
System.out.println(res2);
}
輸出結果:

@JsonView注解沒有@Repeatable注解標注,意味着一個屬性只能標注一個@JsonView注解, 比如 View.UserPrivacy 這個Json View也需要有id字段,解決方案就是 讓 UserPrivacy 繼承 UserPublic視圖

同樣的main方法查看輸出: {"id":1,"name":"lvbb"}
二. 結合Spring的使用方式. (注解@JsonView的 value只能為一個)
簡單列舉個例子如下: 在@ResponseBody標注下添加 @JsonView指定要展示的JSON View即可.
@RequestMapping("/demo2")
@ResponseBody
@JsonView(value = MyView.UserDetail.class)
public User demo2(){
User user = new User();
user.setName("lvbinbin");
user.setPassword("qwer0-5");
return user;
}
上面的代碼使用效果和下面一段是一模一樣的:
@RequestMapping(value = "/demo4")
@ResponseBody
public MappingJacksonValue demo4(){
User user = new User();
user.setName("lvbinbin");
user.setPassword("qwer0-5");
MappingJacksonValue mjv=new MappingJacksonValue(user);
mjv.setSerializationView(MyView.UserDetail.class);
return mjv;
}
Json View Api使用:
User user = new User();
user.setId(1);
user.setName("lvbb");
ObjectMapper mapper = new ObjectMapper();
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(user);
mappingJacksonValue.setSerializationView(View.UserPrivacy.class);
ObjectWriter writer = mapper.writerWithView(mappingJacksonValue.getSerializationView());
String res4= writer.writeValueAsString(mappingJacksonValue.getValue());
System.out.println(res4);
當然MappingJacksonValue好像也是支持SpringMvc跨域JSONP調用的,具體不太了解以后補上.
同樣類似的,接收JSON請求參數使用 @RequestBody同樣可以和 @JsonView使用,這時候前台接收到參數就可以忽略指定的字段
@RequestMapping("/demo5")
@ResponseBody
public String demo5(@RequestBody @JsonView(MyView.UserSimple.class) User user){
System.out.println(user);
return "Hello World";
}
Spring底層對MappingJacksonValue以及 @JsonView 流程記錄:
MappingJackson的處理過程如下
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal 有這樣一個代碼片段:
@ResponseBody的返回值類型是MappingJacksonValue類型時,會做的多一步轉換工作,取出mappingJackson的value值.

org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters
在往響應對象Response寫回結果之前, 會調用ResponseBodyAdvice接口的beforeBodyWrite方法進行切面處理,當前對象為 RequestResponseBodyAdviceChain,其持有JsonViewResponseBodyAdvice 以及JsonViewRequestBodyAdvice, 前者就是處理@ResponseBody的;

JsonViewResponseBodyAdvice 直接獲取了 方法上的JsonView注解,然后調用Jackson View Api進行設置;也就是說上面提及到的兩種方式是一模一樣的.

參考文檔:
