准確來說,@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進行設置;也就是說上面提及到的兩種方式是一模一樣的.
參考文檔: