过滤序列化到 HTTP 响应正文的上下文对象有时会很有用。为了提供这样的功能,Spring MVC 现在内置了对 Jackson’s Serialization Views 的支持(从 Spring Framework 4.2 开始,@MessageMapping 处理程序方法也支持 JSON 视图)。
以下示例说明如何使用 @JsonView 根据序列化的上下文过滤字段 - 例如在处理集合时获得“摘要”视图,在处理单个资源时获得完整表示:
public class View {
interface Summary {}
}
public class User {
@JsonView(View.Summary.class)
private Long id;
@JsonView(View.Summary.class)
private String firstname;
@JsonView(View.Summary.class)
private String lastname;
private String email;
private String address;
private String postalCode;
private String city;
private String country;
}
public class Message {
@JsonView(View.Summary.class)
private Long id;
@JsonView(View.Summary.class)
private LocalDate created;
@JsonView(View.Summary.class)
private String title;
@JsonView(View.Summary.class)
private User author;
private List<User> recipients;
private String body;
}
感谢 Spring MVC @JsonView 支持,可以根据每个处理程序方法选择应该序列化的字段:
@RestController
public class MessageController {
@Autowired
private MessageService messageService;
@JsonView(View.Summary.class)
@RequestMapping("/")
public List<Message> getAllMessages() {
return messageService.getAll();
}
@RequestMapping("/{id}")
public Message getMessage(@PathVariable Long id) {
return messageService.get(id);
}
}
在此示例中,如果检索到所有消息,则只有最重要的字段会被序列化,这要归功于带有 @JsonView(View.Summary.class) 注释的 getAllMessages() 方法:
[ {
"id" : 1,
"created" : "2014-11-14",
"title" : "Info",
"author" : {
"id" : 1,
"firstname" : "Brian",
"lastname" : "Clozel"
}
}, {
"id" : 2,
"created" : "2014-11-14",
"title" : "Warning",
"author" : {
"id" : 2,
"firstname" : "Stéphane",
"lastname" : "Nicoll"
}
}, {
"id" : 3,
"created" : "2014-11-14",
"title" : "Alert",
"author" : {
"id" : 3,
"firstname" : "Rossen",
"lastname" : "Stoyanchev"
}
} ]
在 Spring MVC 默认配置中,MapperFeature.DEFAULT_VIEW_INCLUSION 设置为 false。这意味着在启用 JSON 视图时,未对正文或收件人等非注释字段或属性进行序列化。
当使用 getMessage() 处理程序方法(未指定 JSON 视图)检索特定的 Message 时,所有字段都按预期序列化:
{
"id" : 1,
"created" : "2014-11-14",
"title" : "Info",
"body" : "This is an information message",
"author" : {
"id" : 1,
"firstname" : "Brian",
"lastname" : "Clozel",
"email" : "bclozel@pivotal.io",
"address" : "1 Jaures street",
"postalCode" : "69003",
"city" : "Lyon",
"country" : "France"
},
"recipients" : [ {
"id" : 2,
"firstname" : "Stéphane",
"lastname" : "Nicoll",
"email" : "snicoll@pivotal.io",
"address" : "42 Obama street",
"postalCode" : "1000",
"city" : "Brussel",
"country" : "Belgium"
}, {
"id" : 3,
"firstname" : "Rossen",
"lastname" : "Stoyanchev",
"email" : "rstoyanchev@pivotal.io",
"address" : "3 Warren street",
"postalCode" : "10011",
"city" : "New York",
"country" : "USA"
} ]
}
@JsonView 注解只能指定一个类或接口,但您可以使用继承来表示 JSON 视图层次结构(如果字段是 JSON 视图的一部分,它也将是父视图的一部分)。例如,此处理程序方法将序列化带有@JsonView(View.Summary.class) 和@JsonView(View.SummaryWithRecipients.class) 注释的字段:
public class View {
interface Summary {}
interface SummaryWithRecipients extends Summary {}
}
public class Message {
@JsonView(View.Summary.class)
private Long id;
@JsonView(View.Summary.class)
private LocalDate created;
@JsonView(View.Summary.class)
private String title;
@JsonView(View.Summary.class)
private User author;
@JsonView(View.SummaryWithRecipients.class)
private List<User> recipients;
private String body;
}
@RestController
public class MessageController {
@Autowired
private MessageService messageService;
@JsonView(View.SummaryWithRecipients.class)
@RequestMapping("/with-recipients")
public List<Message> getAllMessagesWithRecipients() {
return messageService.getAll();
}
}