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

时间:2011-08-12 12:46:46

标签: java rest jpa spring-mvc

我有一个域对象类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 是否是一个好主意,因为我必须保护一些不应被客户端直接修改的字段(即在这种情况下“启用”)。

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

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

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

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

1 个答案:

答案 0 :(得分:6)

还有另一种选择 - 您可以使用DataBinder.setDisallowedFields(..)(或使用.setAllowedFields(..)

禁止提交一组给定的属性
@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setDisallowedFields(..);
}

如果您有一个或两个不同的属性,则可以。

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

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