У меня очень странная проблема с Spring MVC 4.0.6, размещенная на JBoss 7.2. При обновлении существующего пользователя представленная информация иногда передается методу контроллера POST RequestMapping (validateUpdate method ниже).Странное поведение: атрибуты Spring Session против ModelAttribute
UserController.java
@Controller
@RequestMapping(value = "/security/user")
@SessionAttributes(value = {"userForm", "user"})
public class UserController {
private final String CREATE_VIEW = "user/createOrUpdate";
private final String READ_VIEW = "user/readOrDelete";
private final String UPDATE_VIEW = CREATE_VIEW;
private final String DELETE_VIEW = READ_VIEW;
@Autowired
private LocationService locationService;
@Autowired
private SecurityService securityService;
@Autowired
private UserValidator userValidator;
@InitBinder("userForm")
protected void initBinder(WebDataBinder binder) {
binder.setValidator(userValidator);
binder.setDisallowedFields("strId");
}
@ModelAttribute("regions")
public List<Region> populateRegions() {
Locale locale = LocaleContextHolder.getLocale();
List<Region> regions = this.locationService.lstRegions(locale.getLanguage());
return regions;
}
@RequestMapping(value = "/update/{intUserId}", method = RequestMethod.GET)
public String updateUser(@PathVariable Integer intUserId, Model model) {
User user = this.securityService.findUserByPk(intUserId);
if (user != null) {
UserForm userForm = new UserForm();
userForm.setUser(user);
model.addAttribute(userForm);
}
return UPDATE_VIEW;
}
@RequestMapping(value = "/update/validate", method = RequestMethod.POST)
public String validateUpdate(@Valid @ModelAttribute("userForm") UserForm userForm,
BindingResult result,
Model model,
RedirectAttributes redirectAttributes,
SessionStatus status) {
return this.performCreateOrUpdateOperation(userForm, result, model, redirectAttributes, status);
}
private String performCreateOrUpdateOperation(
UserForm userForm,
BindingResult result,
Model model,
SessionStatus status) {
if(result.hasErrors()) {
return UPDATE_VIEW;
} else {
User user = userForm.getUser();
this.securityService.validateCreateOrUpdateUser(result, user);
if (result.hasErrors() == false) {
if (userForm.isNew()) {
this.securityService.addUser(user);
} else {
this.securityService.updateUser(user);
}
model.addAttribute(user);
status.setComplete();
return "user/success";
} else {
return UPDATE_VIEW;
}
}
}
}
Форма Bean
public class UserForm {
private String strUserIdToSearch = "";
private String strId = "0";
private String strUserId = "";
private String strFirstName = "";
private String strLastName = "";
private String strEmail = "";
private String strRegionId = "0";
private boolean booArchived = false;
public User getUser() {
User user = new User();
user.setIntId(Integer.valueOf(this.strId));
user.setStrUserId(this.strUserId);
user.setStrFirstName(this.strFirstName);
user.setStrLastName(this.strLastName);
user.setStrEmail(this.strEmail);
Region region = new Region(Integer.valueOf(this.strRegionId));
user.setRegion(region);
user.setBooArchived(this.booArchived);
return user;
}
public void setUser(User user) {
this.strUserIdToSearch = user.getStrUserId();
this.strId = String.valueOf(user.getIntId());
this.strUserId = user.getStrUserId();
this.strFirstName = user.getStrFirstName();
this.strLastName = user.getStrLastName();
this.strEmail = user.getStrEmail();
this.strRegionId = String.valueOf(user.getRegion().getIntId());
this.booArchived = user.getBooArchived();
}
...getters and setters...
}
JSP (удален стиль для ясности) crudMethod является JSP тег возвращения "создать", "читать" , «обновить» или «удалить» в зависимости от $ {requestScope ['javax.servlet.forward.request_uri']}
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<spring:url var="userFormAction" value="/rest/security/user/${crudMethod}/validate" />
<form:form id="userForm" modelAttribute="userForm" action="${userFormAction}" method="POST">
<form:hidden path="strId" />
<form:hidden path="strUserId" id="strUserId" />
<form:hidden path="strLastName" id="strLastName" />
<form:hidden path="strFirstName" id="strFirstName" />
<form:hidden path="strEmail" id="strEmail" />
<form:select id="strRegionId" path="strRegionId">
<form:option value="0" label="${strSelectRegionLabel}" />
<form:options items="${regions}" itemValue="intId" itemLabel="${strRegionLabel}" />
</form:select>
</form:form>
Итак, когда я отправляю форму и, например, изменяю регион на другой идентификатор в списке (скажем, от 1 до 6). Иногда это работает, иногда нет. Под «works» я имею в виду, что я ударил страницу успеха, затем возвращаюсь к пользователю снова. Иногда он остается на 1, иногда он изменился до 6.
Я нашел шаблон/обходной путь, который работает все время, чтобы воспроизвести проблему:
- Загрузите обновление формы (UserController> updateUser)
- Изменить регион от 1 до 6
- Нажмите «Сохранить». Форма отправляется, поэтому вызывается метод UserController.validateUser.
- Получил страницу успеха. На этой странице успеха я получил ссылку на операцию чтения для пользователя. Нажимая на эту ссылку, я понимаю, что регион не изменился (основная проблема). Существует ссылка для обновления пользователя на странице чтения.
- Повторите то же самое изменение, которое я сделал на шаге 2.
- Нажмите «Сохранить». Форма отправляется, и я получил представление страницы успеха.
- Снова прочитайте гиперссылку, и теперь я вижу, что сработало изменение.
Вопрос: ПОЧЕМУ? Я что-то упускаю??
Примечание: это не связано с бизнес-слоем. Я тестировал его, и он стабилен. Это, безусловно, связано с моим использованием Spring MVC Framework.
Браузер IE11.
Благодарим за помощь.
* UPDATE 2015-06-29 *
После нескольких поисков, я обнаружил, что:
- , когда он не работает, значение заголовка Content-Length запроса 0.
- когда он работает, есть значение (например: 146).
тело сообщения запроса всегда правильно, например, так:
Strid = the_ID & strUserId = THE_USERID & strLastName = THE_LASTNAME & strFirstName = THE_FIRSTNAME & strEmail = THE_EMAILADDRESS & strRegionId = THE_REGIONID & booArchived = ложь
Обратите внимание, что «THE_REGIONID» хорош каждый раз.
Близкие по теме ресурсы
- Challenge-Response Authentication and Zero-Length Posts
- Form Submit Not working on IE intermittently with Spring MVC in backend
Это связано с вашим браузером и связано с кешированием. Я настоятельно рекомендую использовать шаблон post-redirect-get. После обновления сделайте перенаправление на страницу успеха, а не рендеринг. Поэтому вместо возврата 'user/success' return' redirect:/url/to/success.jsp-page'. Контроллер страницы успеха должен снова извлечь пользователя из базы данных (вместо того, чтобы добавлять его в модель), если вы действительно не хотите, чтобы пользователь в области флэш-памяти мог пережить перенаправление. –
Сначала я использовал атрибут flash, но если пользователь по какой-либо причине обновляет страницу успеха, содержимое очищается, поэтому это не вариант. Попробует реализовать шаблон post-redirect-get, а затем перезагрузите элемент из базы данных, как вы предложили. Спасибо. –
Наконец, я сомневаюсь, что это связано с кэшированием. Я добавил точку останова в методе «validateUpdate», чтобы сразу увидеть переданные значения. Даже в этот момент значение оставалось неизменным для региона. Если он работал, но не отображался должным образом, он придерживался вашей идеи кэширования ... но он даже не отправляется должным образом ... –