Skip to content

Jackson 4-使用@JsonView

本文介绍如何在Jackson中@JsonView的用法以及@JsonView在Spring中的用法。参考链接:https://www.baeldung.com/jackson-json-view-annotation

1. 使用@JsonView进行序列化

@JsonView的作用是当序列化一个类时,只序列化其中某些字段。虽然@JsonIgnore也可以实现该目的,但@JsonView可定义多个视图,每个视图可序列化不同的字段。

首先准备基础类和测试方法:

java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods {
    private int id;
    private String goodsCode;
    private String goodsName;
    private String unit;
    private String spec;
    private BigDecimal price;
    // 成本价
    private BigDecimal costPrice;
    // 库存
    private int stock;
}
java
@Test
void test03() throws JsonProcessingException {
    Goods goods = new Goods(
            1,
            "1001",
            "手机",
            "部",
            "12GB+1TB",
            new BigDecimal(6000),
            new BigDecimal(4800),
            1000
    );

    ObjectMapper objectMapper = new ObjectMapper();
    String jsonString = objectMapper.writeValueAsString(goods);

    System.out.println(jsonString);
}

结果显而易见,所有字段都序列化了:

txt
{"id":1,"goodsCode":"1001","goodsName":"手机","unit":"部","spec":"12GB+1TB","price":6000,"costPrice":4800,"stock":1000}

如果我们使用@JsonView,就可以定义不同的序列化结果了。首先定义视图,视图就是一个类,我们定义在Goods类中:

java
public class Goods {
    // 表示外部需要的视图
    public static class OuterJsonView{}
  	// 表示内部需要的视图,继承自外部视图
    public static class InnerJsonView extends OuterJsonView{}
}

然后使用@JsonView在字段上定义该字段属于哪个视图:

java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods {
    @JsonView(InnerJsonView.class)
    private int id;
    @JsonView(OuterJsonView.class)
    private String goodsCode;
    @JsonView(OuterJsonView.class)
    private String goodsName;
    @JsonView(OuterJsonView.class)
    private String unit;
    @JsonView(OuterJsonView.class)
    private String spec;
    @JsonView(OuterJsonView.class)
    private BigDecimal price;
    // 成本价
    @JsonView(InnerJsonView.class)
    private BigDecimal costPrice;
    // 库存
    @JsonView(OuterJsonView.class)
    private int stock;

    public static class OuterJsonView{}
    public static class InnerJsonView extends OuterJsonView{}
}

最后,使用ObjectMapper序列化时,决定使用哪个视图:

java
@Test
void test03() throws JsonProcessingException {
    Goods goods = new Goods(
            1,
            "1001",
            "手机",
            "部",
            "12GB+1TB",
            new BigDecimal(6000),
            new BigDecimal(4800),
            1000
    );

    ObjectMapper objectMapper = new ObjectMapper();
//        objectMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);

    String jsonString = objectMapper
            .writerWithView(Goods.OuterJsonView.class)
            .writeValueAsString(goods);

    System.out.println(jsonString);
}
txt
{"goodsCode":"1001","goodsName":"手机","unit":"部","spec":"12GB+1TB","price":6000,"stock":1000}
  • 注意,第18行指定了要使用的视图;
  • 第15行的配置MapperFeature.DEFAULT_VIEW_INCLUSION是指,如果字段没有标注@JsonView,那么在所有的视图中是否应该包含,默认情况下开启,也可以使用第15行关闭该配置。

2. 使用@JsonView进行反序列化

java
@Test
void test04() throws IOException {
    String jsonString = "{\"goodsCode\":\"1001\",\"goodsName\":\"手机\",\"unit\":\"\",\"spec\":\"12GB+1TB\",\"price\":6000,\"stock\":1000}";

    ObjectMapper objectMapper = new ObjectMapper();
    Goods goods = objectMapper.readerWithView(Goods.OuterJsonView.class)
            .readValue(jsonString, Goods.class);

    System.out.println(goods);
}

好像用处不大,直接反序列化也可以,缺少的字段赋默认值。

3. 在Spring中使用@JsonView

我们可以在控制器的方法上标注@JsonView来指定使用的视图。

java
@RestController
public class GoodsController {

    @GetMapping("/goods/{id}")
    @JsonView(Goods.OuterJsonView.class)
    public Goods getGoodsById(@PathVariable("id") int id) {
        Goods goods = new Goods(
                id,
                "1001",
                "手机",
                "部",
                "12GB+1TB",
                new BigDecimal(6000),
                new BigDecimal(4800),
                1000
        );

        return goods;
    }
}

在方法上标注@JsonView可以控制返回对象的不同视图。

但是,我们希望在控制器中返回统一的结构,例如:

java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class R<T> {
    private int code;
    private String msg;
    private T data;

    public static <T> R ok(T data){
        return new R<T>(1, "success", data);
    }

    public static <T> R error(String msg, T data){
        return new R<T>(-1, msg, data);
    }
}

我们想要控制的数据视图是统一返回结构的字段,这要如何实现呢?