Spring: one JPA model, many JSON respresentations

后端 未结 2 1603
抹茶落季
抹茶落季 2020-12-20 06:53

I\'m writing a RESTful web service using Spring/JPA. There\'s a JPA model which is exposed through the web service. The \'Course\' model is quite spacious - it actually is c

相关标签:
2条回答
  • 2020-12-20 07:32

    In Spring Data REST 2.1 there is a new mechanism for this purpose - Projections (It's now part of spring-data-commons).

    You'll need to define interface, containing exactly exposed fields:

    @Projection(name = "summary", types = Course.class)
    interface CourseGeneralInfo {
    
      GeneralInfo getInfo();
    
    }
    

    After that Spring will be able to find it automagically in your source, and you could make requests to your existing endpoints, like this:

    GET /api/courses?projection=general_info
    

    Based on https://spring.io/blog/2014/05/21/what-s-new-in-spring-data-dijkstra

    Spring sample project with projections: https://github.com/spring-projects/spring-data-examples/tree/master/rest/projections

    0 讨论(0)
  • 2020-12-20 07:32

    I was just reading about some really nifty features in Spring 4.1, which allow you to use different views via annotations.

    from: https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring

    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;
    }
    

    Thanks to Spring MVC @JsonView support, it is possible to choose, on a per handler method basis, which field should be serialized:

    @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);
        }
    }
    

    In this example, if all messages are retrieved, only the most important fields are serialized thanks to the getAllMessages() method annotated with @JsonView(View.Summary.class):

    [ {
      "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"
      }
    } ]
    

    In Spring MVC default configuration, MapperFeature.DEFAULT_VIEW_INCLUSION is set to false. That means that when enabling a JSON View, non annotated fields or properties like body or recipients are not serialized.

    When a specific Message is retrieved using the getMessage() handler method (no JSON View specified), all fields are serialized as expected:

    {
      "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"
      } ]
    }
    

    Only one class or interface can be specified with the @JsonView annotation, but you can use inheritance to represent JSON View hierarchies (if a field is part of a JSON View, it will be also part of parent view). For example, this handler method will serialize fields annotated with @JsonView(View.Summary.class) and @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();
        }
    }
    
    0 讨论(0)
提交回复
热议问题