Spring Controller:使用域对象作为@RequestBody

我有一个域对象类User (它是一个JPA实体):

 @Entity public class User { private String name; private boolean enabled = true; // getters/setters } 

我正在尝试使用Spring 3 MVC提供REST API以允许客户端创建新用户:

 @Controller public class UserController { @RequestMapping(value="/user", method=RequestMethod.POST) @ResponseBody public String createRealm(@RequestBody User user) { user.setEnabled(true); // client is not allowed to modify this field userService.createUser(user); ... } } 

它工作得很好,但我不知道将域对象用作@RequestBody是否是一个好主意,因为我必须保护一些不应被客户端直接修改的字段(即在这种情况下为“enabled”)。

这些替代方案的优缺点是什么:

  1. 使用域对象并保护不允许用户修改的字段(例如,将它们设置为null或手动设置为其默认值)
  2. 使用一组新的辅助对象 (类似于DTO),例如仅包含我想通过REST API公开的字段的UserRequest,并将它们(即使用Dozer )映射到域对象。

第二种选择如下:

 @Entity public class User { private String name; private boolean enabled = true; // getters/setters } public class UserRequest { private String name; // enabled is removed // getters/setters } @Controller public class UserController { @RequestMapping(value="/user", method=RequestMethod.POST) @ResponseBody public String createRealm(@RequestBody UserRequest userRequest) { User user = ... // map UserRequest -> User userService.createUser(user); ... } } 

有没有其他方法可以避免代码重复并且更容易维护?

还有另一种选择 – 您可以使用DataBinder.setDisallowedFields(..) (或使用.setAllowedFields(..) )禁止提交给定的属性集

 @InitBinder public void initBinder(WebDataBinder binder) { binder.setDisallowedFields(..); } 

如果您有一个或两个不同的属性,这很好。

否则,拥有一个特殊对象(如ProfileDetailsUserRequest )会更有意义。 我在这个场景中使用了类似DTO的对象,然后使用来自commons-beanutils的BeanUtils.copyProperties(..)传输字段

第三个也许更好的选择是将所有与配置文件相关的字段放入一个单独的实体(用@OneToOne与用户映射)或@Embeddable对象,然后使用它。