[这是我看到的有关 Spring MVC 的常见问题列表,它们以类似的方式解决。我已经把它们贴在这里,所以我可以很容易地从其他问题中引用它们]
如何使用表单仅更新模型实体的几个字段?
我如何使用 Post-Redirect-Get模式与 Spring MVC,尤其是表单验证?
如何保护实体中的某些字段?
我如何实现 Optimistic Concurrency Control ?
最佳答案
@SessionAttributes
将模型存储在请求之间的 session 中。您可以使用隐藏的表单字段,但 session 更安全。 flashAttributes
webDataBinder.setAllowedFields("field1","field2",...)
或创建特定于表单的类,然后将值复制到您的实体。实体不需要 id 和 version 的 setter(如果使用 Hibernate)。 @Version
在您的实体中添加注释并使用 @SessionAttributes
在您的 Controller 上。 示例代码:
@Controller
@RequestMapping("/foo/edit/{id}")
@SessionAttributes({FooEditController.ATTRIBUTE_NAME})
public class FooEditController {
static final String ATTRIBUTE_NAME = "foo";
static final String BINDING_RESULT_NAME = "org.springframework.validation.BindingResult." + ATTRIBUTE_NAME;
@Autowired
private FooRepository fooRepository;
/*
Without this, user can set any Foo fields they want with a custom HTTP POST
setAllowedFields disallows all other fields.
You don't even need setters for id and version, as Hibernate sets them using reflection
*/
@InitBinder
void allowFields(WebDataBinder webDataBinder){
webDataBinder.setAllowedFields("name");
}
/*
Get the edit form, or get the edit form with validation errors
*/
@RequestMapping(method = RequestMethod.GET)
String getForm(@PathVariable("id") long id, Model model) {
/* if "fresh" GET (ie, not redirect w validation errors): */
if(!model.containsAttribute(BINDING_RESULT_NAME)) {
Foo foo = fooRepository.findOne(id);
if(foo == null) throw new ResourceNotFoundException();
model.addAttribute(ATTRIBUTE_NAME, foo);
}
return "foo/edit-form";
}
/*
@Validated is better than @Valid as it can handle http://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html/chapter-groups.html
@ModelAttribute will load Foo from session but also set values from the form post
BindingResult contains validation errors
RedirectAttribute.addFlashAttribute() lets you put stuff in session for ONE request
SessionStatus lets you clear your SessionAttributes
*/
@RequestMapping(method = RequestMethod.POST)
String saveForm(
@Validated @ModelAttribute(ATTRIBUTE_NAME) Foo foo,
BindingResult bindingResult,
RedirectAttributes redirectAttributes,
HttpServletRequest request,
SessionStatus sessionStatus
) {
if(!bindingResult.hasErrors()) {
try {
fooRepository.save(foo);
} catch (JpaOptimisticLockingFailureException exp){
bindingResult.reject("", "This record was modified by another user. Try refreshing the page.");
}
}
if(bindingResult.hasErrors()) {
//put the validation errors in Flash session and redirect to self
redirectAttributes.addFlashAttribute(BINDING_RESULT_NAME, bindingResult);
return "redirect:" + request.getRequestURI();
}
sessionStatus.setComplete(); //remove Foo from session
redirectAttributes.addFlashAttribute("message", "Success. The record was saved");
return "redirect:" + request.getRequestURI();
}
}
Foo.java:
@Entity
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Version //for optimistic concurrency control
private int version;
@NotBlank
private String name;
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
edit-form.jsp(与 Twitter Bootstrap 兼容):
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<form:form modelAttribute="foo">
<spring:hasBindErrors name="foo">
<c:if test="${errors.globalErrorCount > 0}">
<div class="alert alert-danger" role="alert"><form:errors/></div>
</c:if>
</spring:hasBindErrors>
<c:if test="${not empty message}">
<div class="alert alert-success"><c:out value="${message}"/></div>
</c:if>
<div class="panel panel-default">
<div class="panel-heading">
<button class="btn btn-primary" name="btnSave">Save</button>
</div>
<div class="panel-body">
<spring:bind path="name">
<div class="form-group${status.error?' has-error':''}">
<form:label path="name" class="control-label">Name <form:errors path="name"/></form:label>
<form:input path="name" class="form-control" />
</div>
</spring:bind>
</div>
</div>
</form:form>
ResourceNotFoundException.java:
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
}
关于spring-mvc - Spring MVC : Validation, Post-Redirect-Get、部分更新、乐观并发、字段安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29039116/