絕了!Spring Boot憑@JsonView注解,強大到逆天
環境:SpringBoot3.4.2
1. 簡介
在基于 RESTful 架構的 Web 應用開發里,后端服務與前端客戶端之間的數據交互通常采用 JSON 格式。然而,不同的業務場景對數據的需求存在差異。例如,在用戶列表展示場景中,僅需返回用戶的基本信息,如用戶名、頭像等;而在用戶詳情查看場景中,則需要返回用戶的全部信息,包括敏感信息如密碼等。
為滿足這種多樣化的數據需求,傳統方式可能需要創建多個數據傳輸對象(DTO),分別對應不同的數據展示場景,但這會導致代碼冗余和維護成本增加。
@JsonView 它是 Jackson 庫中的一個強大注解。通過定義不同的視圖類(通常為接口或類),并在實體類的字段上使用 @JsonView 注解標記該字段在哪個視圖中可見,同時在控制器方法中通過 @JsonView 注解指定返回的視圖,就可以靈活控制返回的字段內容,實現了根據不同場景動態選擇序列化字段的目的,大大提高了代碼的簡潔性和可維護性。
2. 實戰案例
2.1 基本使用
實體類定義
public class User {
public interface PublicView {} ;
public interface InternalView extends PublicView {} ;
@JsonView(PublicView.class)
private Long id ;
@JsonView(PublicView.class)
private String name ;
@JsonView(PublicView.class)
private String address ;
@JsonView(InternalView.class)
private String password ;
@JsonView(InternalView.class)
private String idCard ;
@JsonView(PublicView.class)
private String email ;
// getters, setters
}
Controller接口
@RestController
@RequestMapping("/users")
public class UserController {
@JsonView(User.PublicView.class)
@GetMapping("/query")
public User query() {
return new User(1L, "pack", "四川烏魯木齊市", "123456",
"152528202504096514", "pack@qq.com");
}
}
訪問接口輸出如下:
圖片
如果將接口上的@JsonView修改為InternalView輸出如下:
圖片
所有的字段都輸出了。
注意,如果你有字段沒有添加@JsonView注解,那么將不會被輸出(默認情況)。
2.2 編程方式
如果你想以編程方式實現上述功能(而不是聲明一個 @JsonView 注解),可以將返回值用 MappingJacksonValue 對象包裹起來,并利用它來指定序列化視圖:
@GetMapping("/getUser")
public MappingJacksonValue getUser() {
User user = new User(1L, "pack", "四川烏魯木齊市", "123456",
"152528202504096514", "pack@qq.com") ;
MappingJacksonValue value = new MappingJacksonValue(user);
value.setSerializationView(User.PublicView.class);
return value;
}
訪問該接口,輸出結果:
圖片
2.3 視圖Json
對于依賴視圖的控制器,只需將序列化視圖類添加到model中即可,如下例所示:
@Controller
public class UserViewController {
@GetMapping("/userview")
public ModelAndView userView(Model model) {
User user = new User(1L, "pack", "四川烏魯木齊市", "123456",
"152528202504096514", "pack@qq.com") ;
model.addAttribute("user", user) ;
model.addAttribute(JsonView.class.getName(), User.PublicView.class) ;
return new ModelAndView(new MappingJackson2JsonView()) ;
}
}
我們以JsonView的完整類名作為key添加到Model中,最后返回時定義MappingJacksonJsonView視圖對象即可控制輸出的字段。
訪問上面接口輸出:
圖片
2.4 限制反序列化
當我們不希望某些字段被反序列化時,我們也可以通過該視圖技術來限制,如下示例:
@PostMapping("/deserialize_json")
public User deserialize(@RequestBody String json) throws Exception {
ObjectMapper mapper = new ObjectMapper() ;
User user = mapper
.readerWithView(User.PublicView.class)
.forType(User.class)
.readValue(json) ;
return user ;
}
請求測試如下:
圖片
我們的接口并沒有對password和idCard兩個字段進行反序列化。
2.5 配置默認行為
通過上面的示例我們了解到,可以利用 @JsonView 注解來指定字段在哪些視圖下可以被序列化輸出。如果字段未添加 @JsonView 注解,則默認情況下該字段不會被輸出。然而,當實體類的字段數量較多時,為每個字段單獨添加注解會非常繁瑣。為此,我們可以通過如下配置來更改這一默認行為:
spring:
jackson:
mapper:
default-view-inclusion: true
接下來,我們將User修改如下:
public class User {
private Long id ;
private String name ;
private String address ;
@JsonView(InternalView.class)
private String password ;
@JsonView(InternalView.class)
private String idCard ;
private String email ;
}
我們將公共字段上的注解去掉,接下來,我們再次訪問上面的/users/query接口
圖片
沒有添加注解的字段也可以輸出了(這屬于默認字段)。
注:我們的接口上還是需要@JsonView(User.PublicView.class)注解。