您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Spring MVC:验证,重定向后获取,部分更新,乐观并发,现场安全

Spring MVC:验证,重定向后获取,部分更新,乐观并发,现场安全

要部分更新实体,应使用@SessionAttributes模型在请求之间的会话中存储模型。您可以使用隐藏的表单字段,但是会话更为安全。

要将P / R / G与验证一起使用,请使用 flashAttributes

要保护字段安全,请使用webDataBinder.setAllowedFields("field1","field2",...)或创建特定于表单的类,然后将值复制到您的实体。实体不需要ID和版本的设置器(如果使用Hibernate)。

要使用乐观并发控制@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();
    }
}

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 {
}
Java 2022/1/1 18:13:35 有665人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶