Spring MVC - How do I update a model object's attributes using a controller method?

38,523

Solution 1

@RequestMapping(value = "/members/edit/{id}", method = RequestMethod.POST)
public String updateMember(@PathVariable int id, 
    HttpServletRequest request,@ModelAttribute("member") Member member) {

//Hope your MemberService looks similar

public void edit(Member member) {
logger.debug("Editing existing member");

// Retrieve session from Hibernate, if you are using hibernate
Session session = sessionFactory.getCurrentSession();

// Retrieve existing member via id
Member existingMember = (Member) session.get(Member.class, member.getId());

// Assign updated values to this member
existingMember.setForeName(member.getForeName());
existingMember.setSurName(member.getSurName());
...
...
existingMember.setPostcode(member.getPostcode());

// Save updates
session.save(existingMember);

}

Solution 2

@RequestMapping(value = "/members/edit/{id}", method = RequestMethod.POST)
public String updateMember(@PathVariable int id, 
        HttpServletRequest request,@ModelAttribute("member") Member member) {

add @ModelAttribute before Member. Then this instance will have all the edits. so you don't need to set new values by request.getParameter. Just save this instance in DB.

Solution 3


This may have to do with the form attribute :
enctype="multipart/form-data"

There are no error logs when multiple parts are not resolved in Spring (this is very tricky).
Spring cannot read multiple attachment parts in the POST request, and Spring does not update the model.

Please make sure that you have set the multipart resolver in the dispatcher servlet XML file.
dispatcher-servlet.xml:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

And also add the below dependency to your pom.
pom.xml:

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.2</version>
</dependency>
Share:
38,523
Ryan Deery
Author by

Ryan Deery

Updated on December 22, 2020

Comments

  • Ryan Deery
    Ryan Deery over 3 years

    Using Spring MVC 3.0, I am developing a member management system with basic CRUD operations and am having trouble with my Controller.

    I cannot update a member record using a Controller method. I have methods to display and process my 'Add Member' form and another to display my 'Edit Member' form and they all work fine.

    Here is my controller:

    @Controller
    public class MemberController {
    
    private MemberService memberService;
    
    @Inject
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
    
    // Show member list
    @RequestMapping(value = "/members/list", method = RequestMethod.GET)
    public String showMemberList(Map<String, Object> model) {
    
        model.put("members", memberService.getAllMembers());
    
        return "members/list";
    }
    
    // Display add member form
    @RequestMapping(value = "/members/add", method = RequestMethod.GET)
    public String showAddMemberForm(Model model) {
    
        model.addAttribute(new Member());
    
        return "members/add";
    }
    
    // Process add member form
    @RequestMapping(value = "/members/add", method = RequestMethod.POST)
    public String addMember(Member member) {
    
        memberService.addMember(member);
    
        return "redirect:list";
    }
    
    // Display edit member form
    @RequestMapping(value = "/members/edit/{id}", method = RequestMethod.GET)
    public String showEditMemberForm(Model model, @PathVariable int id) {
    
        String idAsString = Integer.toString(id);
        model.addAttribute("member", memberService.getMemberById(idAsString));
    
        return "members/edit/{id}";
    }
    
    // Process edit member form
    @RequestMapping(value = "/members/edit/{id}", method = RequestMethod.POST)
    public String updateMember(@PathVariable int id, 
            HttpServletRequest request, Member member) {
    
        // Uncommenting the next line of code sets the member objects forename attribute
        // to "test forename"
        // member.setForename("test forename");
    
        // Uncommenting the next line of code gives the following error:
        // HTTP Status 405 - Request method 'POST' not supported
        //member.setSurname(request.getParameter("surname"));
    
        memberService.updateMember(member);
    
        return "redirect:/members/list";
    }
    

    }

    Here is my update method:

    public void update(Member member) {
        jdbcTemplate.update(
                "UPDATE members SET forename=?, surname=?, address1=?, address1=?, "
                        + "city=?, postcode=? WHERE memberId=?",
                member.getForename(), member.getSurname(),
                member.getAddress1(), member.getAddress2(), member.getCity(),
                member.getPostcode(), member.getId());
    }
    

    And here is my Edit Member JSP form:

    <sf:form method="POST" modelAttribute="member"
        enctype="multipart/form-data" action="/members/edit/${member.id}">
        <fieldset>
            <table cellspacing="0">
                <tr>
                    <th><label for="member_id">Id:</label></th>
                    <td><sf:input path="id" size="15" id="member_id" /></td>
                </tr>
                <tr>
                    <th><label for="member_forename">Forename:</label></th>
                    <td><sf:input path="forename" size="15" id="member_forename" /></td>
                </tr>
                <tr>
                    <th><label for="member_surname">Surname:</label></th>
                    <td><sf:input path="surname" size="15" id="member_surname" /></td>
                </tr>
                <tr>
                    <th><label for="member_address1">Address 1:</label></th>
                    <td><sf:input path="address1" size="15" id="member_address1" />
                    </td>
                </tr>
                <tr>
                    <th><label for="member_address2">Address 2:</label></th>
                    <td><sf:input path="address2" size="15" id="member_address2" />
                    </td>
                </tr>
                <tr>
                    <th><label for="member_city">City:</label></th>
                    <td><sf:input path="city" size="15" id="member_city" /></td>
                </tr>
                <tr>
                    <th><label for="member_postcode">Postcode:</label></th>
                    <td><sf:input path="postcode" size="15" id="member_postcode" />
                    </td>
                </tr>
    
            </table>
            <input type="submit" value="Update" />
        </fieldset>
    </sf:form>
    

    Because the 'member.setForename("test forename")' code in my Controller sets the test string, I thought I could use the parameters that are posted from the form to set the atrributes as follows:

    'member.setSurname(request.getParameter("surname"))'

    But this causes an HTTP 405 error. Using Firebug, I have confirmed that the 'Edit Member' form is posting the 'forename', 'surname', 'address1', etc. parameters so I can't figure out why I can't pull them off the request.

    Any help would be greatly appreciated as I have been at this for 2 days and am going round in circles.

  • Ryan Deery
    Ryan Deery about 11 years
    I've added the @ModelAttribute annotation and it has made no difference. Once I submit the edit form I am redirected to the member list and the record is being displayed as empty, apart from the member id.
  • Anubhab
    Anubhab about 11 years
    Can you please log the values inside the controller before updating in db so that you know whther values are there?
  • Anubhab
    Anubhab about 11 years
    Also in the form tag add commandName attribute to have member value. commandName="member"
  • Anubhab
    Anubhab about 11 years
    Kindly check the edit where i have added ("member") with the annotation
  • Ryan Deery
    Ryan Deery about 11 years
    I have added the commandName to the form and ("member") after the annotation and still no difference. I'm unsure if I have logging set up but I will check now. Thanks
  • Anubhab
    Anubhab about 11 years
    how do you debug if you don't have any logging mechanism??
  • Anubhab
    Anubhab about 11 years
    @RyanDeery: how come only id is getting populated??In your update method you are passing memeber as an instance. If one variable is getting populated others should also get populated. Can you check if your jsp has path values exactly same as member variable names??
  • Ryan Deery
    Ryan Deery about 11 years
    The JSP path values are exactly the same as the member variable names. Id is declared as a @PathVariable in the controller method maybe that is why but I am unsure. I was previously debugging using test cases in JUnit but I will try to set up logging now. My update method is now in my initial question.
  • Ryan Deery
    Ryan Deery about 11 years
    I'm not using Hibernate. Sorry I can't make much sense of that code :(
  • Anubhab
    Anubhab about 11 years
    @RynaDeery: I know id is @Pathvariable but in your update method i see you are not passing id but you are passing the object as a whole. So inside that object id is getting populated correctly..Is your transactions commiting properly??Check that too..
  • Matteo Steccolini
    Matteo Steccolini over 5 years
    This solved my issue when my controller stopped working when migrating from Spring 3.2.5 to Spring 4.3.12, when apparently an explicit multipartResolver became necessary. I don't know what exactly changed between the two versions.