Spring MVC: область запроса, попытка обновить объект команды с помощью binder.setDisallowedFields

У меня есть этот объект

public class Deportista implements Serializable {

    private static final long serialVersionUID = 6229604242306465153L;

    private String id;
    ...

    @NotNull(message="{field.null}")
    public String getId() {
        return id;
    }
    ...

}

У меня есть следующие методы контроллера

@InitBinder(value="deportistaRegistrar")
public void registrarInitBinder(WebDataBinder binder) {
    logger.info(">>>>>>>> registrarInitBinder >>>>>>>>>>>>>");
}

@RequestMapping(value="/registrar.htm", method=RequestMethod.GET)
public String crearRegistrarFormulario(Model model){
    logger.info("crearRegistrarFormulario GET");
    Deportista deportista = new Deportista();
    model.addAttribute("deportistaRegistrar", deportista);
    return "deportista.formulario.registro";
}

@RequestMapping(value="/registrar.htm", method=RequestMethod.POST)
public String registrarPerson(@Validated @ModelAttribute("deportistaRegistrar") Deportista deportista, 
                              BindingResult result){

    logger.info("registrarPerson POST");
    logger.info("{}", deportista.toString());

    if(result.hasErrors()){
        logger.error("There are errors!!!!");

        for(ObjectError objectError : result.getAllErrors()){
            logger.error("Error {}", objectError);
        }

        return "deportista.formulario.registro";
    }

    logger.info("All fine!!!!");
    this.fakeMultipleRepository.insertDeportista(deportista);
    return "redirect:/manolo.htm";
}

Пока контроллер не может создать форму (GET) и отправить (POST) объект new command, код Validation работает хорошо.

Проблема с обновлением.

У меня есть следующее:

@InitBinder(value="deportistaActualizar")
public void actualizarInitBinder(WebDataBinder binder) {
    logger.info(">>>>>>>> actualizarInitBinder >>>>>>>>>>>>>");
    binder.setDisallowedFields("id");
}

Заметьте, у меня есть binder.setDisallowedFields("id")

public String crearActualizarFormulario(@PathVariable("id") String id, Model model){
    logger.info("crearActualizarFormulario GET");
    Deportista deportista = this.fakeMultipleRepository.findDeportista(id);
    model.addAttribute("deportistaActualizar", deportista);
    return "deportista.formulario.actualizacion";
}   

@RequestMapping(value="/{id}/actualizar.htm", method=RequestMethod.POST)
public String actualizarPerson(@Validated @ModelAttribute("deportistaActualizar") Deportista deportista, 
                           BindingResult result){

    logger.info("actualizarPerson POST");
    logger.info("{}", deportista.toString());

    if(result.hasErrors()){
        logger.error("There are errors!!!!");

        for(ObjectError objectError : result.getAllErrors()){
            logger.error("Error {}", objectError);
        }

        return "deportista.formulario.actualizacion";
    }

    logger.info("All fine!!!!");
    this.fakeMultipleRepository.updateDeportista(deportista);
    return "redirect:/manolo.htm";
}

Проблема в:

  • когда в форме или команде есть какая-либо ошибка, контроллер повторно отображает представление, и форма появляется, показывая сообщения об ошибках, как ожидается, но без значения идентификатора

or

  • если я попытаюсь обновить объект, конечно, сохранив значение id, и без каких-либо ошибок просто приступить к обновлению, это не удастся

В консоли появится следующее:

- -------- createCollections ---------------
- >>>>>>>> actualizarInitBinder >>>>>>>>>>>>>
- Skipping URI variable 'id' since the request contains a bind value with the same name.
- actualizarPerson POST
- Deportista [id=null, nombre=Manuel, ...]
- There are errors!!!!
- Error Field error in object 'deportistaActualizar' on field 'id': rejected value [null]; codes [NotNull.deportistaActualizar.id,NotNull.id,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [deportistaActualizar.id,id]; arguments []; default message [id]]; default message [The field must be not empty]

id имеет значение null. Как мне решить эту проблему, сохранив Область запроса?

У меня есть альтернативный контроллер, который работает с @SessionAttributes, и все работает отлично. Но поскольку существует огромный риск, если у пользователя открыто много вкладок в одном и том же веб-браузере, одна для создания, а другая для обновления, все будет очень неправильно. В соответствии с атрибутами Spring MVC + Session и несколькими вкладками вместо области сеанса следует использовать область запроса. Это имеет смысл.

К сожалению, похоже, Spring не собирается это исправлять: @SessionAttributes не работать с вкладками

Дополнение

По вашему предложению имею следующее:

@ModelAttribute("deportistaActualizar")
public Deportista populateActualizarFormulario(@RequestParam(defaultValue="") String id){
    logger.info("populateActualizarFormulario - id: {}", id);
    if(id.equals(""))
        return null;
    else
        return this.fakeMultipleRepository.findDeportista(id);
}

Обратите внимание, что метод использует @RequestParam, моя проблема заключается в том, как обновить этот метод для работы, когда URL-адрес для обновления имеет следующий стиль http://localhost:8080/spring-utility/deportista/1/actualizar.htm. В URL нет param, поэтому @RequestParam сейчас бесполезен.

Я уже прочитал справочную документацию Spring: Использование @ModelAttribute в методе

Второе дополнение

Да, вы были правы, и я сделал это вчера, но я забыл поделиться следующим:

@ModelAttribute("deportistaActualizar")
public Deportista populateActualizarFormulario(@PathVariable(value="id") String id){
    logger.info("populateActualizarFormulario - id: {}", id);
    if(id.equals(""))
        return null;
    else
        return this.fakeMultipleRepository.findDeportista(id);
}

Поскольку @ModelAttribute всегда вызывается перед любым handler методом, следующий URL терпит неудачу http://localhost:8080/spring-utility/deportista/registrar.htm, на странице появляется следующее

HTTP Status 400 -
type Status report
message
description The request sent by the client was syntactically incorrect.

Конечно, потому что URL-адрес не содержит ожидаемого id. Поэтому я не могу создавать новые записи для последующего редактирования/просмотра.

Могу подтвердить, что для следующих работ:

  • http://localhost:8080/spring-utility/deportista/1/detalle.htm
  • http://localhost:8080/spring-utility/deportista/1/actualizar.htm

идентификатор (1) извлекается.

Как я мог решить это?

Благодарю вас


person Manuel Jordan    schedule 17.09.2014    source источник
comment
Проблема в том, что вы используете 2 метода, которые в основном работают с одним и тем же объектом. Однако они не разделяют объект. Как я также ответил в другом вопросе, добавьте метод, аннотированный @ModelAttribtue, который извлекает желаемый объект на основе идентификатора. В основном удалите извлечение объекта из метода get и поместите его в метод с аннотацией @ModelAttribute.   -  person M. Deinum    schedule 18.09.2014
comment
Понятно, но см. раздел Addition. Благодарю вас.   -  person Manuel Jordan    schedule 19.09.2014
comment
Просто поместите туда @PathVariable, почти все аннотации, которые можно использовать в методе @RequestMapping, применяются к методам @ModelAttribute.   -  person M. Deinum    schedule 19.09.2014
comment
Не могли бы вы проверить раздел Second Addition, пожалуйста? Благодарю вас.   -  person Manuel Jordan    schedule 19.09.2014
comment
В настоящее время нет способа определить переменную пути по умолчанию или необязательную. В качестве обходного пути вы можете создать 2 контроллера, один для создания нового, другой для обновления существующих.   -  person M. Deinum    schedule 19.09.2014
comment
Я думал, что это худший сценарий. Просто интересно, как вы решаете проблему @SessionAttributes с проблемой нескольких вкладок. Благодарю вас.   -  person Manuel Jordan    schedule 19.09.2014
comment
Я собираюсь создать проблему JIRA (улучшение) с Spring 4 и 4.1, это должно быть исправлено. Спасибо всем, Мартен!   -  person Manuel Jordan    schedule 19.09.2014
comment
Я создал два контроллера, теперь все работает. Благодарю вас   -  person Manuel Jordan    schedule 20.09.2014