Dejvinczi
Dejvinczi

Reputation: 21

Controller sends empty Object from Thymeleaf - Spring Boot

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 = {"/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";
    }

This is 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">

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

        <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>

And this is endpoint which stores empty object from 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";
    }

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.

Upvotes: 2

Views: 953

Answers (1)

selmlin
selmlin

Reputation: 21

If I understood correctly, I see following issue:
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.
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.
EDIT: can you try adding the @ModelAttribute annotation:

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

Try adding an input field like this inside your form:

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

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.

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.
I hope this helps a bit, best regards ;)

Upvotes: 1

Related Questions