Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用与RESTAPI返回的不同的spring实体的正确设计是什么?_Spring_Rest_Spring Boot_Spring Mvc - Fatal编程技术网

使用与RESTAPI返回的不同的spring实体的正确设计是什么?

使用与RESTAPI返回的不同的spring实体的正确设计是什么?,spring,rest,spring-boot,spring-mvc,Spring,Rest,Spring Boot,Spring Mvc,现在,我有一个@Entity,比如说Car,它有一组特定的属性。这将被持久化到数据库中 现在,在@RestController中,如果我想接受除某些属性之外的Car参数,我该怎么做?现在,我正在创建一个名为CarInput的不同类,它与Car减去这些属性相同 同样,对于RESTAPI响应,也是一样的。如果我想归还一辆车,但删除了某个字段。现在我创建了CarResponse作为一个模型 有没有更干净的方法 我认为您的外部表示和内部存储几乎不应该完全相同。当然,会有明显的重叠,但您的数据库和API应

现在,我有一个@Entity,比如说Car,它有一组特定的属性。这将被持久化到数据库中

现在,在@RestController中,如果我想接受除某些属性之外的Car参数,我该怎么做?现在,我正在创建一个名为CarInput的不同类,它与Car减去这些属性相同

同样,对于RESTAPI响应,也是一样的。如果我想归还一辆车,但删除了某个字段。现在我创建了CarResponse作为一个模型


有没有更干净的方法

我认为您的外部表示和内部存储几乎不应该完全相同。当然,会有明显的重叠,但您的数据库和API应该尽可能相互独立


我想说,为模型层和视图层提供单独的域模型是一个很好的实践(阅读:两个不同的汽车类,在不同的包中)。您可以使用像Dozer这样的映射框架,或者在这些不同的实体类型之间来回映射。

有两种常见的方法来解决此问题

  • 在要排除的字段/getter上使用。然而,这可能会导致注释地狱或通常难以阅读的代码
  • 创建数据将从中反序列化或序列化到的DTO类。我的意思是,当某个用户使用
    car
    定义发出POST请求时,它将被spring反序列化为
    CarDto
    ,然后由您在服务层解析为
    car
    对象,您可以将其保存到数据库中。类似地,如果用户请求数据,
    Car
    对象将被解析为
    CarDto
  • 另一方面,这可能导致有时使用Dto,有时使用类本身的情况。因此,考虑只在控制器层(与上面的例子不同)

    > > /从<代码> CarDto <代码>解析。
    另外,避免在一个文件中创建两个类也很好。之后很难找到想要的课程

    您仍然可以避免使用DTO类

    • 当您将汽车对象发布到控制器时,您可以控制想要的属性并对其进行操作

    • 要选择作为响应返回的字段,可以使用json视图

    实体:

    public Car {
      private String color;
    
      @JsonView(Views.Public.class)
      private Integer weight;
    
      // getters, setters
    }
    
    控制器:

    @RestController
    public CarController
      @Autowired
      private CarRepository carRepository;
    
      @GetMapping("/{id}")
      @JsonView(View.Public.class)
      public Book get(@PathVariable Long id){
         return carRepository.findOne(id);
      }
    
      @PostMapping
      public Book update(@RequestBody Car car) {
        // only properties we want to update
        if(car.getColor() != null) {
          // save in database or other operations
        }
      }
    }
    
    视图:

    public class Views {
        public static class Public {
        }
    }
    

    这样,控制器的方法“get”将只向客户端发送“weight”属性,“update”方法将只对选定的属性进行操作。

    在遵循REST体系结构模型的API中,您不关注类型,而是关注表示格式。通常所谓的RESTAPI使用的是,而不是正确地协商交换的格式。API的文档现在已成为事实,不能更改(以及API本身),否则客户端将崩溃。使用Sean建议的映射,您应该能够通过支持的表示来回转换您的业务对象。例如,对于userDto,它没有属性Id(因为它是用@GeneratedValue自动生成的)。所以我不想为addUser接受它,但我确实想用getUser返回它。这种方法有意义吗?试试
    @JsonIgnore(access=access.READ_ONLY)
    好的。那么,您是否建议我使用不同的REST输入和输出模型?例如,我不想接受userID作为输入,因为它是由后端自动生成的,但我想返回userID作为输出。对于模型层和视图层,
    code repeated
    ?重复编写
    代码将是一种不好的做法。即使使用自动工具在POO中中断。@erotsppa您似乎将
    汽车
    模型直接暴露给客户。这总是很糟糕。一般来说,RESTAPI的主要前提应该始终是服务器正在向客户机传授它下一步可以做什么。这类似于一个典型的Web页面,其中服务器将向您提供一个表单来输入数据,它通常将该数据作为
    www-form-urlencoded
    传输,并映射回某个内部业务对象。有一些基于JSON的表单的方法,例如hal+表单或siren,尽管它们可能不被广泛接受yet@RomanVottner是的,我现在知道了。但这就是为什么我要问,是否建议我创建两个模型(一个用于数据库映射)和(一个用于接受REST的输入)。然后使用MapStruct在2@erotsppa之间进行映射。当然,最好直接公开模型或使用定制的映射。也就是说,我为一家公司从事电子数据交换领域的工作,该公司在所有这些奇特的ERP系统之间充当中间人,每个系统都推广自己的定制格式。在所有这些系统之间交换消息是很麻烦的,因此我们有自己的、庞大的内部模型,在这个模型中,我们将这些格式映射到我们的格式,根据我们的模型处理请求,并将结果映射回预期的模型。尽管为每种类型都保留了大量M:N映射,但这并不简单
    @RestController
    public CarController
      @Autowired
      private CarRepository carRepository;
    
      @GetMapping("/{id}")
      @JsonView(View.Public.class)
      public Book get(@PathVariable Long id){
         return carRepository.findOne(id);
      }
    
      @PostMapping
      public Book update(@RequestBody Car car) {
        // only properties we want to update
        if(car.getColor() != null) {
          // save in database or other operations
        }
      }
    }
    
    public class Views {
        public static class Public {
        }
    }