java - Spring MVC 中如何在页面提交时绑定(bind)对象属性?

标签 java spring hibernate spring-mvc

阅读完教程和文档后,我仍然不明白在 SpringMVC + hibernate 中绑定(bind)某些对象属性背后的机制。

假设我们有一个类Poem:

package com.test.poems.model;

import com.tastyminerals.poems.model.Author;
import com.tastyminerals.poems.model.Genre;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;


@Entity
@Table(name = "P_POEM")
public class Poem {

    @Id
    @GeneratedValue
    @Column(name="ID")
    private Integer id;

    @Column(name="TITLE")
    private String title;

    @Column(name="BODY")
    private String body;

    @Column(name="DATE")
    private String date;


    @ManyToOne
    @JoinColumn(name="ID", referencedColumnName="ID_AUTHOR", insertable = false, updatable = false)
    private Author author;

    @ManyToOne
    @JoinColumn(name="ID", referencedColumnName="ID_GENRE", insertable = false, updatable = false)
    private Genre genre;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Author getAuthor() {
        return author;
    }

    public Genre getGenre() {
        return genre;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }

    public void setGenre(Genre genre) {
        this.genre = genre;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

}

和一个类作者:

@Entity
@Table(name = "AUTHORS")
public class Author {

    @Id
    @GeneratedValue
    @Column(name="ID_AUTHOR")
    private Integer id;

    @Column(name="NAME")
    private String name;

/* getters and setters */

我需要通过 hibernate 将我的诗提交到 mysql 数据库。为此,我创建了一个简单的 jsp 页面,其中包含所有 Poem 属性的输入字段。 提交后,RequestMethod.POST 返回 titlebody 和作者 name 的字符串值。

但是,这会产生类型转换错误,例如:无法将类型“java.lang.String”的属性值转换为属性“author”所需的类型“com.test.model.Author”

Poem 类期望将 Author 对象设置到其中,但获取字符串 name 。我想知道为什么 Spring 不进行必要的转换,因为我在 Controller 方法中显式创建了 Author ?它的值不应该在页面提交后自动解析和设置吗?

@RequestMapping(value = "/poem/add", method = RequestMethod.GET)
    public ModelAndView addPoemPage() {
        ModelAndView modelAndView = new ModelAndView("poem-add");
        modelAndView.addObject("author", new Author());
        modelAndView.addObject("poem", new Poem());
        return modelAndView;
    }

    @RequestMapping(value = "/poem/add", method = RequestMethod.POST)
    public ModelAndView addingPoem(@ModelAttribute Poem poem,
            @ModelAttribute Author author) {

        ModelAndView modelAndView = new ModelAndView("home");
        authorService.addAuthor(author);

        poem.setAuthor(author);
        poemService.addPoem(poem);
        return modelAndView;
    }

我的jsp页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<c:set var="url">${pageContext.request.requestURL}</c:set>
<link
    href="${pageContext.request.contextPath}/resources/css/poem-add.css"
    rel="stylesheet" />
<title>Writing a poem</title>
</head>
<body>
    <h1>New poem</h1>
    <p>Here you can write your poem.</p>
    <form:form method="POST" commandName="poem"
        action="${pageContext.request.contextPath}/poem/add.html">
        <table>
            <tbody>
                <tr>
                    <td>Title:</td>
                    <td><input id="" title="Your poem's title" id="title"
                        name="title" type="text" class="input" /></td>
                </tr>
                <tr>
                    <td>Author:</td>
                    <td><input title="Author's name" id="author" name="author"
                        type="text" class="input" /></td>
                </tr>
                <tr>
                    <td>Date:</td>
                    <td><input title="Date of creation" id="date" name="date"
                        type="text" class="input" /></td>
                </tr>
                <tr>
                    <td>Text:</td>
                    <td><textarea title="Your poem goes here" rows="15" cols="50"
                            class="input"> </textarea></td>
                </tr>
            </tbody>
        </table>
        <table class="actions">
            <tr>
                <td><a
                    href="${pageContext.request.contextPath}/collection.html"><input
                        type="button" value="Back" class="button" /></a></td>
                <td><a
                    href="${pageContext.request.contextPath}/collection.html"><input
                        type="submit" value="Submit" class="button" /></a></td>
            </tr>
        </table>
    </form:form>
</body>
</html>

我知道我需要一个 PropertyEditorBeanWrapper。但我根本不明白在哪里以及如何实现它们?有什么区别?

总结我的问题,我需要在单击提交按钮后立即解释 hibernate 和 SpringMVC 之间“幕后”发生的情况。如果您能为我的案例提供 PropertyEditorBeanWrapper 示例,我将不胜感激。

最佳答案

I need an explanation of what is going on "behind-the-scenes" between hibernate and SpringMVC

:还没有 hibernate 。您只需使用 Spring MVC 将普通 bean(模型)映射到 JSP。

I know that I need a PropertyEditor or BeanWrapper.

:现阶段您不需要 PropertyEditor。 PropertyEditor 用于高级类型转换,例如当您希望将传入的日期字符串“dd-mm-yyyy Zone”转换为 java.util.Date 对象时,反之亦然。

I wonder why doesn't Spring make the necessary conversions since I explicitely create Author in my controller method? Shouldn't its values be automatically resolved and set after the page submission?

:如果使用Spring Form标签将JSP字段正确映射到模型属性,Spring将自动解析。在您的情况下,JSP 表单字段未正确映射到模型,应该如下所示

<form:form method="POST" modelAttribute="poem"
    action="${pageContext.request.contextPath}/poem/add.html">
    <table>
        <tbody>
            <tr>
                <td>Title:</td>
                <td><form:input path="poem.title" title="Your poem's title" 
                    type="text" class="input" /></td>
            </tr>
            <tr>
                <td>Author:</td>
                <td><form:input path="poem.author.name" title="Author's name"
                    type="text" class="input" /></td>
            </tr>
            <tr>
                <td>Text:</td>
                <td><form:textarea path="poem.body" title="Your poem goes here" rows="15" cols="50"
                        class="input" /></td>
            </tr>
        </tbody>
    </table>
    <table class="actions">
        <tr>
            <td><a
                href="${pageContext.request.contextPath}/collection.html"><input
                    type="button" value="Back" class="button" /></a></td>
            <td><a
                href="${pageContext.request.contextPath}/collection.html"><input
                    type="submit" value="Submit" class="button" /></a></td>
        </tr>
    </table>
</form:form>

您可以向模型添加多个属性,但只能将一个模型属性附加到 <form>而不是两个。你的 Controller 看起来像这样。

@RequestMapping(value = "/poem/add", method = RequestMethod.GET)
    public ModelAndView addPoemPage() {
        ModelAndView modelAndView = new ModelAndView("poem-add");
        Author author = new Author();
        Poem poem = new Poem();
        poem.setAuthor(author); 
        modelAndView.addObject("poem", new Poem());
        return modelAndView;
    }

    @RequestMapping(value = "/poem/add", method = RequestMethod.POST)
    public ModelAndView addingPoem(@ModelAttribute("poem") Poem poem) {

        ModelAndView modelAndView = new ModelAndView("home");
        authorService.addAuthor(poem.getAuthor);
        poemService.addPoem(poem);
        return modelAndView;
    }

关于java - Spring MVC 中如何在页面提交时绑定(bind)对象属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23877884/

相关文章:

java - 如何在接受下一个 MouseEvent 之前等待当前 MouseEvent EventHandler 结束?

java - 具有单个域对象和多个数据源的 Spring Boot

java - 如何将自定义转换器与@DataMongoTest 一起使用?

java - 具有额外连接条件的 JPA @JoinTable

java - Google App Engine SDK 弃用影响我的框架应用程序

java - CXF 客户端 + WS-Security + MTOM = 麻烦?

java - 使用 rest 调用更新 xml 文件路径

java - Spring JPA 功能允许在不同实体之间重用单个 Repo 方法

java - Spring 启动+JPA : Column name annotation ignored

sql - 删除域对象时获取 'Referential integrity constraint violation'