Spring MVC:表单如何将对象传输到控制器??总是400错误

Spring MVC :how a form transfer an object to Controller?? Always 400 error

当我尝试访问时 http://localhost:8080/XX/articles/addArticle
并提交表单,总是出现“400 BAD REQUEST”错误。 我试图查找原因,我得到的只是从表单传输的对象与我的模型类型不同(这里是 Article 对象?)。但是,我觉得我真的不明白..

所有代码都在这里,配置都很好
这里有 2 个模型:
Article.java

@Entity
@Table(name="article_inf")
public class Article {
    private int articleId;
    private String title;
    private User author;
    private String content;
    public Article() {
    }
    public Article(String title, User author, String content) {
        this.title = title;
        this.author = author;
        this.content = content;
    }
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int getArticleId() {
        return articleId;
    }
    public void setArticleId(int articleId) {
        this.articleId = articleId;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    @ManyToOne(targetEntity=User.class)
    @JoinColumn(name="author", referencedColumnName="userId", nullable=false)
    public User getAuthor() {
        return author;
    }
    public void setAuthor(User author) {
        this.author = author;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }

User.java

@Entity
@Table(name="agri_user_inf")
public class User {
    private int userId;
    private String userName;
    private String password;
    private String cellPhone;
    private List<Article> articles;
    public User() {
        articles = new ArrayList<>();
    }
    public User(String userName, String password, String cellPhone) {
        this.userName = userName;
        this.password = password;
        this.cellPhone = cellPhone;
    }
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getCellPhone() {
        return cellPhone;
    }
    public void setCellPhone(String cellPhone) {
        this.cellPhone = cellPhone;
    }
    @OneToMany(targetEntity=Article.class, mappedBy="author")
    public List<Article> getArticles() {
        return articles;
    }
    public void setArticles(List<Article> articles) {
        this.articles = articles;
    }

控制器
ArticleController.java

@Controller
@RequestMapping("articles")
public class ArticleController {
    private ArticleDao articleDao;
    @Autowired
    public ArticleController(ArticleDao articleDao) {
        this.articleDao = articleDao;
    }
    @RequestMapping(value="addArticle", method=GET)
    public String addArticle(ModelMap modelMap) {
        List<User> authors = userDao.getAllUsers();
        // add all authors
        modelMap.addAttribute("authors", authors);
        return "articles/addArticleForm";
    }
    @RequestMapping(value="addArticle", method=POST)
    public String addArticle(Article article) {
        articleDao.addArticle(article);
        return "redirect:/articles";
    }
    // other code

我的表格addArticleForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form method="post">
        title: <input type="text" name="title"/><br/>
        author: <select name="author">
                <c:forEach items="${authors}" var="author">
                    <option value="${author}">${author.userName}</option>
                </c:forEach>
            </select>
            <br/>
        content: <input type="text" name="content"/><br/>
        <input type="submit" value="add"/>
    </form>
</body>
</html>
  1. 您违反了 REST 原则。之后始终在您的端点和资源名称中使用版本。示例 - /api/v1/articles。之后借助 HttpMethods 访问您的资源。例子 - 如果你想

1.1 添加新文章,使用POST请求/api/v1/articles 1.2 删除已有文章,使用DELETE请求/api/v1/articles/{articleId} 1.3 获取一篇文章,使用GET请求到/api/v1/articles/{articleId} 1.4 获取所有文章,使用GET请求到/api/v1/articles 1.5 更新现有文章,使用 PUT 请求 /api/v1/articles/{articleId}

  1. 切勿使用将在所有层的数据库中保留的实体。将实体与您的视图连接是一种不好的做法,您可以改用 DTO。

  2. 在您的控制器层中使用@ModelAttribute 注释,其名称与视图中的名称相同,以处理传入的 Article 对象。例子

    public String addArticle(@ModelAttribute("article") 文章文章 )

  3. 要首先添加新文章,您需要创建端点,该端点在 ModelMap 中返回空文章对象。然后你必须在你的前端处理这个(JSP)并按照步骤 3 提交此表单。

希望这会有所帮助。

我找到了解决方案:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form method="post">
        title: <input type="text" name="title"/><br/>
        author: <select name="author.userId">
                <c:forEach items="${authors}" var="author">
                    <option value="${author.userId}">${author.userName}</option>
                </c:forEach>
            </select>
            <br/>
        content: <input type="text" name="content"/><br/>
        <input type="submit" value="add"/>
    </form>
</body>
</html>