Spring MVC: how to connect two models in one table

2019-08-25 16:11发布

问题:

I am preparing a project where I have two relational tables. Type of relation - one to many. This is a library system. I have one table for books and one table for clients.

rent-form.jsp:

<h1>${book.title}</h1>

        <form:form action="rentBook" modelAttribute="book" method="POST">
        <!--  need to associate this data with customer id -->
        <form:hidden path="id" />

        <table>
            <tbody>
                <tr>
                    <td><label>Rental Date:</label></td>
                    <td><spring:bind path="book"><form:input path="rentalDate" /></spring:bind></td>
                </tr>

                <tr>

                    <td><label>Return Date:</label></td>
                    <td><spring:bind path="book"><form:input path="returnDate" /></spring:bind></td>
                </tr>

                <tr>
                    <td><label>Client:</label></td>
                    <td>
                    <form:select path="client">
                        <form:option value="NONE" label="--- Select ---" />
                        <c:forEach var="tempClient" items="${client}">
                         <form:option value="${tempClient.id}">${tempClient.id} ${tempClient.firstName} ${tempClient.lastName}</form:option>
                        </c:forEach>
                    </form:select>
                    </td>
                </tr>


                <tr>
                    <td><label></label></td>
                    <td><input type="submit" value="Save" class="save" /></td>
                </tr>
            </tbody>
        </table>        
        </form:form>

BookController.java:

@RequestMapping("/showFormForRent")
public String showFormForRent(@RequestParam("bookId") int theId, Model theModel) {

    List<Client> theClients = bookService.getClients();

    theModel.addAttribute("client", theClients);

    Book theBook = bookService.getBook(theId);

    theModel.addAttribute("book", theBook);


    return "rent-form";
}
@PostMapping("/rentBook")
public String rentBook(@ModelAttribute("book") Book theBook, @ModelAttribute("client") Client theClient) {

    theBook.setClient(theClient);
    bookService.saveBook(theBook);

    return "redirect:/book/list-books";
}

What I want to do, I want to get the clients from the drilldown, then I would like to chose (I am choosing in drilldown menu) and add the client to the book, by using the theBook.setClient(theClient). In this case in the "book" table I should have a client id. What is more, in this form I want to add the rental date and return date.

Database diagram:

I am not sure if my approach is correct, for now I received the error message:

HTTP Status 400 – Bad Request

The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

I am suppose that it is related with the the model in one form. Perhaps Spring doesn't know what the client model are doing in the book form. Do you have guys any advice for me please?

回答1:

You need to create and register a converter.

You are binding the select

<form:select path="client">

to the client property in book. The browser only sends the id so you need to tell Spring how to convert this ID to a Client instance.

See 6.5.1 Converter SPI in https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/validation.html

package org.springframework.core.convert.support;

final class StringToClient implements Converter<String, Client> {

    //wire in repository

    public Client convert(String source) {
        return clientRepo.find(Integer.valueOf(source));
    }

}

With that in place your controller code is simply as below i.e. the client returned by the converter is automatically bound to the book by the MVC framework.

@PostMapping("/rentBook")
public String rentBook(@ModelAttribute("book") Book theBook) {

    bookService.saveBook(theBook);

    return "redirect:/book/list-books";
}