控制器从Thymeleaf发送空对象 – Spring Boot

huangapple go评论82阅读模式
英文:

Controller sends empty Object from Thymeleaf - Spring Boot

问题

大家好!

我一直在Spring Boot中实现一个服务,允许用户将匿名问卷发送到服务器。

我已经实现了大部分的后端功能,比如添加用户等等。目前,我正在处理一个动作,该动作从用户那里获取答案并发送到服务器(保存在数据库中)。包含答案的对象(filledSurvey)被发送为空。在相同的逻辑中,从表单中记录用户字段是正确发送的。

这是显示问卷的端点:

@RequestMapping(path = {"/try", "/try/{id}"})
public String tryCompletingSurvey(Model model, @PathVariable("id") Long id) {
    Connection connection = connectionService.getConnection(id);
    FilledSurvey filledSurvey = connection.getSurvey().getTemplate();

    for (FilledQuestion filledQuestion : filledSurvey.getFilledQuestions()) {
        filledQuestion.getFilledAnswers().get(0).setCheck(true);
    }

    model.addAttribute("filledSurvey", filledSurvey);

    return "completing/completing";
}

这是Thymeleaf的HTML代码:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <title>Completing survey</title>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
</head>

<body>
    <center>
        <form action="#" th:action="@{/user/surveys/finish}" th:object="${filledSurvey}" method="post">

            <h2>Survey name: </h2>
            <h3 th:text="${filledSurvey.getSurveyName()}"></h3>

            <h2>Number of questions: </h2>
            <h3 th:text="${filledSurvey.filledQuestions.size()}"></h3>
            <div class="col-md-6">
                <input type="submit" style="align-content: center" class="btn btn-primary" value="  Send  ">
            </div>
        </form>
    </center>
</body>
</html>

这是将空对象从Thymeleaf存储的端点:

@RequestMapping(path = "/finish", method = RequestMethod.POST)
public String getHash(FilledSurvey filledSurvey) {

    StringBuilder sb = new StringBuilder();
    for (FilledQuestion question : filledSurvey.getFilledQuestions()) {
        for (FilledAnswer answer : question.getFilledAnswers()) {
            if (answer.isCheck()) sb.append(answer.getAnswer());
        }
    }
    LocalDateTime date = LocalDateTime.now();
    sb.append(date);

    String hash = sb.toString();
    hash = Base64.getEncoder().encodeToString(sb.toString().getBytes());
    filledSurvey.setHash(hash);

    surveyMagazinService.addSurveyToMagazin(filledSurvey);

    return "completing/finish";
}

我已经修改了代码来自动标记答案。下一个端点中对象的图片:
filledSurvey object

我知道这是一个常见的问题,但我已经寻找答案有一段时间了,但仍然无法弄清楚。控制台中也没有错误。我会感激任何帮助或反馈。

英文:

Hi Guys!

I have been implementing service in Spring Boot which
allows users to send anonymouse questionaries to server.

I have already implemented most of the backend like adding users etc. and right now I have been struggling with one action which take answers from user and sends into server (save in database).
Object containing answers (filledSurvey) is being sent as empty. In this same logic in logging users fields from form are corectly send forward.

This endpoint displays questionary:

@RequestMapping(path = {&quot;/try&quot;, &quot;/try/{id}&quot;})
    public String tryCompletingSurvey(Model model, @PathVariable(&quot;id&quot;) Long id) {
        Connection connection = connectionService.getConnection(id);
        FilledSurvey filledSurvey = connection.getSurvey().getTemplate();

        for (FilledQuestion filledQuestion : filledSurvey.getFilledQuestions()) {
            filledQuestion.getFilledAnswers().get(0).setCheck(true);
        }

        model.addAttribute(&quot;filledSurvey&quot;, filledSurvey);

        return &quot;completing/completing&quot;;
    }

This is thymeleaf html:

&lt;!DOCTYPE html&gt;
&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;

&lt;head&gt;
    &lt;title&gt;Completing survey&lt;/title&gt;
    &lt;meta charset=&quot;utf-8&quot;&gt;
    &lt;meta http-equiv=&quot;x-ua-compatible&quot; content=&quot;ie=edge&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;https://use.fontawesome.com/releases/v5.4.1/css/all.css&quot;&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;center&gt;
    &lt;form action=&quot;#&quot; th:action=&quot;@{/user/surveys/finish}&quot; th:object=&quot;${filledSurvey}&quot; method=&quot;post&quot;&gt;

&lt;!--        &lt;div th:each=&quot;question, questionStat : ${survey.getFilledQuestions()}&quot; &gt;--&gt;
&lt;!--            &lt;p th:text=&quot;${question.getQuestion()}&quot;&gt;&lt;/p&gt;--&gt;
&lt;!--            &lt;div th:each=&quot;answer, answerStat: ${question.getFilledAnswers()}&quot; &gt;--&gt;
&lt;!--                &lt;input type=&quot;radio&quot;--&gt;
&lt;!--                       th:name=&quot;question+${questionStat.index}&quot;--&gt;
&lt;!--                       th:field=&quot;*{}&quot;--&gt;
&lt;!--                       th:value=&quot;${true}&quot;&gt;--&gt;
&lt;!--                &lt;label th:text=&quot;${answer.answer}&quot;&gt;--&gt;
&lt;!--                &lt;/label&gt;--&gt;
&lt;!--            &lt;/div&gt;--&gt;
&lt;!--        &lt;/div&gt;--&gt;

        &lt;h2&gt;Survey name: &lt;/h2&gt;
        &lt;h3 th:text=&quot;${filledSurvey.getSurveyName()}&quot;&gt;&lt;/h3&gt;

        &lt;h2&gt;Number of questions: &lt;/h2&gt;
        &lt;h3 th:text=&quot;${filledSurvey.filledQuestions.size()}&quot;&gt;&lt;/h3&gt;
        &lt;div class=&quot;col-md-6&quot;&gt;
            &lt;input type=&quot;submit&quot; style=&quot;align-content: center&quot; class=&quot;btn btn-primary&quot; value=&quot;  Send  &quot;&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/center&gt;
&lt;/body&gt;
&lt;/html&gt;

And this is endpoint which stores empty object from thymeleaf:

@RequestMapping(path = &quot;/finish&quot;, method = RequestMethod.POST)
    public String getHash(FilledSurvey filledSurvey) {

        StringBuilder sb = new StringBuilder();
        for (FilledQuestion question : filledSurvey.getFilledQuestions()) {
            for (FilledAnswer answer : question.getFilledAnswers()) {
                if (answer.isCheck()) sb.append(answer.getAnswer());
            }
        }
        LocalDateTime date = LocalDateTime.now();
        sb.append(date);

        String hash = sb.toString();
        hash = Base64.getEncoder().encodeToString(sb.toString().getBytes());
        filledSurvey.setHash(hash);

        surveyMagazinService.addSurveyToMagazin(filledSurvey);

        return &quot;completing/finish&quot;;
    }

I changed code to automaticly mark answers for now.
This the picture of the object in the next endpoint:
filledSurvey object

I am aware that this is common question but i have been looking for the answer for a while now and couldn't figure it out. I have no errors in the console as well. I would appreciate any help or feedback.

答案1

得分: 1

如果我理解正确的话,我看到以下问题:
您正在使用表单提交调查数据,并使用th:object="${filledSurvey}"来绑定数据。但实际上,在表单提交时没有数据发送回控制器,因为没有定义具有应用了th:field属性的输入字段。
在提交时将发送到服务器的请求将包含所有分配了th:field属性的字段的表单编码数据。控制器将使用Java Bean约定将表单编码数据映射到FilledSurvey对象中的getHash方法。
编辑:您可以尝试添加@ModelAttribute注解:

@RequestMapping(path = "/finish", method = RequestMethod.POST)
public String getHash(@ModelAttribute FilledSurvey filledSurvey) {
...

请尝试在您的表单中添加像这样的输入字段:

<input type="hidden" th:field="*{surveyId}">

这应该至少为您提供一个带有id设置的FilledSurvey对象,可以在您的“/finish”端点上使用该id来获取调查,就像在第一个代码片段中所做的那样。

您在问题列表中使用th:field的方式将无法正常工作,因为Spring无法映射这种类型的结构。请参阅https://spring.io/guides/gs/handling-form-submission/ 以了解Spring MVC处理表单提交的工作原理。
希望这能有所帮助,最好的祝愿;)

英文:

If I understood correctly, I see following issue:<br>
You are using a form to submit the survey data and use the th:object="${filledSurvey}" to bind the data. But there is actually not data send back to the controller, when the form is submitted, because there are no input fields defined that have the th:field attribute applied. <br>
The request that will be send to the server on a submit, will contain form encoded data of all fields that you assign a th:field attribute to. The controller will map the form encoded data to a FilledSurvey object using java bean convention in the getHash method.<br>
EDIT: can you try adding the @ModelAttribute annotation:

@RequestMapping(path = &quot;/finish&quot;, method = RequestMethod.POST)
    public String getHash(@ModelAttribute FilledSurvey filledSurvey) {
...

Try adding an input field like this inside your form:

&lt;input type=&quot;hidden&quot; th:field=&quot;*{surveyId}&quot; &gt;

This should give you at least an FilledSurvey object with the id set on your "/finish" endpoint. You can then use the id to fetch the survey like its done in the first code snippet. <br>
<br>
The way you are using the th:field within your list of questions will not work, because spring cannot map this kind of structure. See https://spring.io/guides/gs/handling-form-submission/ to understand how form submission works with spring mvc.
<br>
I hope this helps a bit, best regards 控制器从Thymeleaf发送空对象 – Spring Boot

huangapple
  • 本文由 发表于 2020年6月29日 04:43:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/62628008.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定