创建、更新和获取REST终点中使用相同/不同的DTO对象?

28
考虑以下UserDTO类和公开端点以创建、更新和获取用户的UserController。
对于创建和更新操作,在UserDTO类中使用id属性没有意义。如果我使用swagger或其他自动生成的API文档,则会显示可以在创建终点传递ID。但系统不使用它,因为ID是在内部生成的。
如果我查看获取操作,可能可以摆脱ID属性,但在列出用户终点上肯定需要它。
我考虑在获取/列表终点返回内部User域对象。这样,我就可以从UserDTO类中删除id属性。
是否有更好的选项可供使用?
public class UserDTO {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@RestController
@RequestMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController {
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<Void> create(@RequestBody UserDTO user) {
    }

    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<UserDTO> get(@PathVariable("id") int id) {
    }

    @RequestMapping(value = "{id}", method = RequestMethod.PUT)
    @ResponseBody
    public ResponseEntity<Void> update(@PathVariable("id") int id, @RequestBody UserDTO user) {
    }
}

这个问题可能已经被问过,但我找不到。所以请原谅我重复提问。

2个回答

13

数据传输对象(DTO)是一种旨在向远程接口传输数据的模式,就像web服务一样。这种模式非常适合于REST API,并且使用DTO可以让您在长期运行中获得更多的灵活性

我建议您为端点使用定制的类,因为REST资源表示不需要与持久化对象具有相同的属性。

为了避免样板代码,您可以使用映射框架,例如MapStruct将您的REST API DTO从/到您的持久化对象进行映射。

有关在REST API中使用DTO的好处的详细信息,请查看以下答案:

要为您的DTO提供更好的名称,请查看以下答案:


2
创建两个不同的界面是什么意思:
interface UserDTO {

    public String getName ();

    public void setName (String name);

}

interface IdentifiableUserDTO extends UserDTO {

    public Long getId ();

    public void setId (Long id);

}


class DefaultUserDTO implements IdentifiableUserDTO {

}

然后在您的控制器中使用接口而不是DTO类:

@RestController
@RequestMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController {
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<Void> create(@RequestBody IdentifiableUserDTO user) {
    }

    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<UserDTO> get(@PathVariable("id") int id) {
    }

    @RequestMapping(value = "{id}", method = RequestMethod.PUT)
    @ResponseBody
    public ResponseEntity<Void> update(@PathVariable("id") int id, @RequestBody UserDTO user) {
    }
}

2
Wael,是的,那是其中一种选择。但我只提到了一个这样的属性。还有许多其他属性,例如createdBy、createdTime、updatedBy、updatedTime等,在获取时是必需的,但在创建/更新时没有意义。也许可以使用这种模式,而不是调用IdentifiableUserDTO,调用其他名称,不确定什么名称更合适。 - Bhushan Bhangale

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接