我一直在寻找一种方法以某种方式减少我的Spring MVC控制器中带有微妙差异的重复代码量,但到目前为止搜索SO问题只会产生一些问题而没有任何令人满意的答案。
我要删除的一个重复示例是,用户创建页面和角色创建页面共享相似之处:
@RequestMapping(value = "user/create", method = RequestMethod.GET)
public String create(@ModelAttribute("user") User user, BindingResult errors) {
LOG.debug("Displaying user creation page.");
return "user/create";
}
@RequestMapping(value = "role/create", method = RequestMethod.GET)
public String create(@ModelAttribute("role") Role role, BindingResult errors) {
LOG.debug("Displaying role creation page.");
return "role/create";
}
我想要删除的一个稍微复杂的复制变体是发布创建表单的变体:
@RequestMapping(value = "user/create", method = RequestMethod.POST)
public String save(@ModelAttribute("user") User user, BindingResult errors) {
LOG.debug("Entering save ({})", user);
validator.validate(user, errors);
validator.validatePassword(user, errors);
validator.validateUsernameAvailable(user, errors);
String encodedPassword = encoder.encode(user.getPassword());
user.setPassword(encodedPassword);
if (errors.hasErrors()) {
return create(user, errors);
} else {
service.save(user);
}
return "redirect:/user/index/1";
}
@RequestMapping(value = "role/create", method = RequestMethod.POST)
public String save(@ModelAttribute("role") Role role, BindingResult errors) {
LOG.debug("Entering save({})", role);
validator.validate(role, errors);
if (errors.hasErrors()) {
return create(role, errors);
} else {
service.save(role);
}
return "redirect:/index";
}
此示例包含验证,然后保存,如果正确,并重定向到错误页面,如果事情没有按计划进行。
如何删除此重复项?
答案 0 :(得分:1)
Spring使用您的处理程序方法参数类型从请求参数或正文创建类实例。因此,无法创建可以使用@RequestMapping
并且检查它是Object
还是Role
的处理程序(User
)方法。 (从技术上讲,你可以同时拥有这两个参数,只检查哪一个不是null
,但那是一个糟糕的设计。)
因此,您需要一个处理程序方法。这是有道理的,因为即使逻辑类似,它仍然特定于您尝试创建的模型对象的确切类型。您执行不同的验证,调用不同的服务方法,并返回不同的视图名称。
我说你的代码很好。
答案 1 :(得分:0)
以为我会提供我所解决的解决方案,希望它可以帮助某人。我的gf建议我使用实体的名称作为控制器的路径变量,事实证明这可以为手头的问题提供一个非常好的解决方案。
这两种方法现在看起来像这样:
@RequestMapping(value = "{entityName}/create", method = RequestMethod.GET)
public String create(@PathVariable("entityName") String entityName, @ModelAttribute("entity") BaseEntity entity, BindingResult errors) {
LOG.debug("Displaying create page for entity named: [{}]", entityName);
return handlerFactory.getHandler(entityName).getCreateView();
}
@RequestMapping(value = "{entityName}/create", method = RequestMethod.POST)
public String save(@PathVariable("entityName") String entityName, @ModelAttribute("entity") BaseEntity entity, BindingResult errors) {
LOG.debug("Saving entity of type {}", entityName);
CrudHandler handler = handlerFactory.getHandler(entityName);
handler.getCreateValidator().validate(entity, errors);
if (errors.hasErrors()) {
return create(entityName, entity, errors);
}
handler.preSave(entity);
handler.getService().save(entity);
return "redirect:" + DASHBOARD_URL;
}
CrudHandler
接口具有每个实体的实现,并为控制器提供所需的实体特定类,例如服务和验证器。示例CrudHandler
实现对我来说是这样的:
@Component
public class RoleCrudHandler implements CrudHandler {
private static final String ENTITY_NAME = "role";
public static final String CREATE_VIEW = "role/create";
public static final String EDIT_VIEW = "role/edit";
@Resource
private RoleService roleService;
@Resource
private RoleValidator validator;
@Resource
private CrudHandlerFactory handlerFactory;
@PostConstruct
public void init() {
handlerFactory.register(ENTITY_NAME, this);
}
@Override
public GenericService getService() {
return roleService;
}
@Override
public Validator getCreateValidator() {
return validator;
}
@Override
public Validator getUpdateValidator() {
return validator;
}
@Override
public BaseEntity createEntity() {
return new Role();
}
@Override
public void preSave(BaseEntity entity) {
}
@Override
public String getCreateView() {
return CREATE_VIEW;
}
@Override
public String getUpdateView() {
return EDIT_VIEW;
}
}
如果有人看到了改善这种情况的方法,请随时分享。希望这对某人有用。