我理解@InitBinder用于安全原因,但它引起了各种各样的问题。
我有一个UserController,其更新方法如下。
@Secured(value={"ROLE_ADMIN"})
@Transactional
@RequestMapping(value="/user/{id}", method=RequestMethod.PUT)
public String userUpdate(User user, BindingResult userBinding, Model model, @PathVariable long id) {
if (userBinding.hasErrors()) {
return (String.format("user/{%s}/edit", String.valueOf(user.getId())));
}
try {
userService.updateUser(user);
}
catch (Exception e) {
logger.error("Unable to update user", e);
}
return "redirect:/user";
}
我还有我的UserController。
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
我的处理创建和更新的JSP在下面。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<div class="container">
<div class="row">
<div class="col-xs-12">
<spring:bind path="user.*">
<c:if test="${status.errors.errorCount > 0}">
<div class="alert alert-danger">
<p>Error: unable to save, please check the errors below</p>
</div>
</c:if>
</spring:bind>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-8 col-md-6">
<h3>User - Add</h3>
<br>
<c:choose>
<c:when test="${user.id > 0}">
<c:set var="formMethod" value="PUT" />
<c:url var="formAction" value="/user/${user.id}" />
</c:when>
<c:otherwise>
<c:set var="formMethod" value="POST" />
<c:url var="formAction" value="/user" />
</c:otherwise>
</c:choose>
<sf:form method="${formMethod}" action="${formAction}" commandName="user">
<spring:bind path="user.id">
<sf:hidden path="${status.expression}" id="user-id" />
</spring:bind>
<spring:bind path="user.firstName">
<div class="form-group">
<label for="first-name">First Name</label>
<sf:input path="${status.expression}" id="first-name" class="form-control" placeholder="First Name" />
<sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
</div>
</spring:bind>
<spring:bind path="user.lastName">
<div class="form-group">
<label for="last-name">Last Name</label>
<sf:input path="${status.expression}" id="last-name" class="form-control" placeholder="Last Name" />
<sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
</div>
</spring:bind>
<spring:bind path="user.email">
<div class="form-group">
<label for="email">Email</label>
<sf:input path="${status.expression}" id="email" class="form-control" placeholder="Email" />
<sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
</div>
</spring:bind>
<spring:bind path="user.username">
<div class="form-group">
<label for="user-name">Username</label>
<sf:input path="${status.expression}" id="user-name" class="form-control" placeholder="Username" />
<sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
</div>
</spring:bind>
<spring:bind path="user.password">
<div class="form-group">
<label for="password">Password</label>
<sf:password path="${status.expression}" id="password" class="form-control" placeholder="" />
<sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
</div>
</spring:bind>
<div class="form-group">
<label for="confirm-password">Confirm Password</label>
<input type="password" name="password-confirm" id="confirm-password" class="form-control" placeholder="" />
</div>
<spring:bind path="user.roleId">
<div class="form-group">
<label for="role">Role</label>
<sf:select path="${status.expression}" id="role" class="form-control" >
<sf:options items="${roles}" itemLabel="name" itemValue="id"/>
</sf:select>
<sf:errors path="${status.expression}" cssClass="error-message"></sf:errors>
</div>
</spring:bind>
<button type="submit" class="btn btn-default">Save</button>
<button type="button" class="btn btn-default">Cancel</button>
</sf:form>
</div>
</div>
</div>
对userService.update(user)的调用是调用JPA merge方法。它失败了,因为它试图插入一个包含数据库中已有的唯一约束的新记录。毋庸置疑,经过几个小时的挖掘代码,互联网和堆栈跟踪,我意识到从JSP回来的id是空的。一旦我注释掉了@InitBinder方法,一切都开始正常了。这让我想到了一个真正的问题,我是否因为安全原因需要@InitBinder,如果是这样,我如何处理我刚才描述的问题呢?