Nei*_*gan 2 spring-mvc post-redirect-get optimistic-locking optimistic-concurrency
[这是我看到的关于Spring MVC的常见问题列表,它们以类似的方式解决.我在这里发布了它们,所以我可以从其他问题中轻松地引用它们]
如何仅使用表单更新模型实体的几个字段?
如何在Spring MVC中使用Post-Redirect-Get模式,尤其是表单验证?
如何保护我的实体中的某些字段?
如何实现乐观并发控制?
Nei*_*gan 12
要部分更新实体,您应该使用@SessionAttributes
在请求之间的会话中存储模型.您可以使用隐藏的表单字段,但会话更安全.
要使用P/R/G进行验证,请使用 flashAttributes
要保护字段使用webDataBinder.setAllowedFields("field1","field2",...)
或创建特定于表单的类,请将值复制到您的实体.实体不需要id和版本的setter(如果使用Hibernate).
要使用Optimistic Concurrency Control,请使用@Version
实体中的注释并@SessionAttributes
在控制器上使用.
示例代码:
@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();
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
ResourceNotFoundException.java:
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7183 次 |
最近记录: |