sirve requestmapping que para mvc formulario example español ejemplo spring-mvc optimistic-locking post-redirect-get optimistic-concurrency

spring-mvc - requestmapping - spring mvc netbeans



Spring MVC: Validación, Post-redirección-Get, actualizaciones parciales, concurrencia optimista, seguridad de campo (1)

[Esta es una lista de preguntas comunes que veo sobre Spring MVC, que se resuelven de manera similar. Los he publicado aquí, así que puedo consultarlos fácilmente desde otras preguntas]

¿Cómo actualizo solo unos pocos campos de una entidad modelo con formularios?

¿Cómo uso el patrón Post-Redirect-Get con Spring MVC, especialmente con la validación de formularios?

¿Cómo aseguro ciertos campos en mis entidades?

¿Cómo implemento el Control de concurrencia optimista ?


  1. Para actualizar parcialmente una entidad, debe usar @SessionAttributes para almacenar el modelo en sesión entre solicitudes. Puede usar campos de formulario ocultos, pero la sesión es más segura.

  2. Para usar P / R / G con validación, use flashAttributes

  3. Para proteger los campos, use webDataBinder.setAllowedFields("field1","field2",...) o cree una clase específica para el formulario y luego copie los valores en su entidad. Las entidades no requieren establecedores para id y versión (si se usa Hibernate).

  4. Para usar el Control de concurrencia optimista, use la anotación @Version en su Entidad y use @SessionAttributes en su controlador.

Código de ejemplo:

@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 (compatible con 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 { }