Search code examples
springjspspring-mvcdwr

Is it possible to manually set the command object in an @RequestMapping method before Spring binding?


I have a JSP that has a Spring form in it. The form's command object is added in the controller before the JSP is rendered. Spring binds the form in the JSP to this command object, and will correctly handle it when submitting a NEW instance.

However, I would like to persist the command object via DWR (which also works correctly), and THEN submit the form to the controller. At the point that the form is submitted to the controller, the command object is no longer a new object, but a persisted object that needs to be updated. This is where I want the form elements to automatically be bound to the command object and be updated via the binding, but they are not being bound.

SIMPLE Example: I will add a new Task to the ModelMap, so that the Spring form will bind to that command object. However, instead of submitting the new Task, I will persist that new Task through DWR, which will return the ID, and then continue editing the Task before submitting the form to the controller.

Controller Class

@Controller
public class ProjectController {

    /**
     * This adds the "task" command object to the session attributes and loads
     * the initial form.
     */
    @RequestMapping(value="/project", method=RequestMethod.GET)
    public String setupForm(@RequestParam(value="id", required=true) String id,
                            HttpServletRequest request, ModelMap modelMap) {

        modelMap.addAttribute("project", projectRepo.get(id));
        modelMap.addAttribute("task", new Task());

        return "/project/task";
    }

    /**
     * This processes the form submit, and should update the Task.
     */
    @RequestMapping(value="/project/task/update", method=RequestMethod.POST)
    public String updateTask(@ModelAttribute(value="task") Task task,
                             @RequestParam(value="taskId") String taskId,
                             HttpServletRequest request, ModelMap modelMap) {

        // BEFORE binding the parameters to the command object (task), 
        // I want to assign the command object as the one already persisted.
        task = taskRepo.get(taskId);

        // NOW, I want the request parameters to be bound to the task command object.
        // HOW ?????????

        // Persist the changes.
        taskRepo.merge(task);

        // BACK to the setupForm method/form view
        return "/project?id=" + task.getProject().getId();
    }
}

Spring Form

<form:form commandName="task" method="post" action="/project/task/update" id="taskForm">
    <form:hidden path="id" id="task.id"/>
    <form:input path="name" id="task.name"/>
    <!-- DWR will save the task (save and continue), then will return the id. -->
    <!-- After saved, the user can still change the name, 
         then submit the form for processing by the controller -->
</form:form>

Can a Spring bound command object be set to a persisted object before any post-submit binding occurs?


Solution

  • There is actually a better way to do this using annotations.

    Create a ModelAttribute method that returns the command object that you want from the repository.

    @ModelAttribute("task")
    public Task task(@RequestParam(value = "id", required = true) String id) {
        return taskRepo.get(taskId);
    }
    

    Then, simply add the ModelAttribute to your form submission method.

    @RequestMapping(value="/project/task/update", method=RequestMethod.POST)
    public String updateTask(@ModelAttribute(value="task") Task task,
                             HttpServletRequest request, ModelMap modelMap) {
    
        taskRepo.merge(task);
        ...
    }