[英]Thymeleaf + Spring Boot, dynamic fields with ArrayList
I'm using Spring Boot with Thymeleaf and trying to set elements (that are objects) of list using form.我正在使用 Spring 引导和 Thymeleaf 并尝试使用表单设置列表的元素(即对象)。 More precisely I have 2 entities: Question that aggregates List of Answers , I'm passing Question object to the model and trying to set each Answer object in iteration.更准确地说,我有 2 个实体: 汇总答案列表的问题,我将问题 object 传递给 model 并尝试在迭代中设置每个答案 object。 When pressing save (submiting form) i got exception:按保存(提交表单)时出现异常:
Field error in object 'question' on field 'answers': rejected value [[Answer(id=0, answerNumber=1, text=, correct=false), Answer(id=0, answerNumber=2, text=, correct=false), Answer(id=0, answerNumber=3, text=, correct=false), Answer(id=0, answerNumber=4, text=, correct=false)]]; object 字段“答案”上的“问题”中的字段错误:拒绝值 [[Answer(id=0, answerNumber=1, text=, correct=false), Answer(id=0, answerNumber=2, text=, correct=假),答案(id=0,答案号=3,文本=,正确=假),答案(id=0,答案号=4,文本=,正确=假)]]; codes [typeMismatch.question.answers,typeMismatch.answers,typeMismatch.java.util.List,typeMismatch];代码 [typeMismatch.question.answers,typeMismatch.answers,typeMismatch.java.util.List,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [question.answers,answers]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable:代码 [question.answers,answers]; arguments []; arguments []; default message [answers]];默认消息[答案]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'answers';默认消息 [无法将类型“java.lang.String”的属性值转换为属性“answers”所需的类型“java.util.List”; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.easetest.website.model.Answer' for property 'answers[0]': no matching editors or conversion strategy found]]嵌套异常是 java.lang.IllegalStateException:无法将类型“java.lang.String”的值转换为所需类型“com.easetest.website.model.Answer”属性“answers[0]”:没有匹配的编辑器或转换策略成立]]
My Controller class question methods我的 Controller class 问题方法
@PostMapping("/editQuestion")
public String editQuestion(Model model, @RequestParam("test_id") int id, @RequestParam(value = "question_id", required = false) Integer question_id) {
Test test = testService.getById(id);
List<Question> questions = test.getQuestions();
System.out.println(questions);
int realNumberOfQuestion = questions.size(); // mozliwe ze nie potrzebne
test.setMultipleAnswers(false);
Question q = question_id == null ? null : questionService.getById(question_id);
if(q == null) {
q = new Question();
if(realNumberOfQuestion < 1) {
q.setQuestionNumber(1);
} else if(questions.get(realNumberOfQuestion - 1).getQuestionBody().isEmpty()){
q = questions.get(realNumberOfQuestion - 1);
} else {
q.setQuestionNumber(realNumberOfQuestion);
}
}
model.addAttribute("test", test);
model.addAttribute("question", q);
System.out.println(q);
return "business/question_form";
}
@PostMapping("/saveQuestion")
public String saveQuestion(Model model, @ModelAttribute("question") Question question, @RequestParam("test_id") int id) {
System.out.println("Lubu dubu");
Test test = testService.getById(id);
test.setQuestion(question);
testService.save(test);
model.addAttribute("test", test);
model.addAttribute("question", question);
return "business/question_form";
}
Question Form问题表
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<!--Bootstrap dependencies-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"
integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI"
crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script th:unless="${test.multipleAnswers}">
$(document).on('click', 'input[type="checkbox"]', function () {
$('input[type="checkbox"]').not(this).prop('checked', false);
});
</script>
<meta charset="UTF-8">
<title>Create Question</title>
</head>
<body class="mb-2 bg-secondary text-white">
<div class="container">
<div>
<h2 th:text="${test.testName}"></h2>
</div>
<div class="form-group">
<h4>Add question</h4>
<form action="#" th:action="@{/business/saveQuestion}" th:object="${question}" method="post">
<div class="form-group">
<input type="hidden" th:field="*{id}">
<input type="hidden" th:field="*{answers}">
<input type="hidden" th:name="test_id" th:value="${test.id}">
<div class="form-group">
<label for="exampleFormControlTextarea1">Question body</label>
<textarea class="form-control" id="exampleFormControlTextarea1"
th:value="${question.questionBody}" rows="3"></textarea>
</div>
<br>
<div th:each="answer, itemStat : *{answers}">
<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">
<input type="hidden" th:field="*{answers[__${itemStat.index}__].id}">
<input type="hidden" th:field="*{answers[__${itemStat.index}__].answerNumber}">
<input type="checkbox" th:field="*{answers[__${itemStat.index}__].correct}">
</div>
</div>
<input type="text" class="form-control" th:field="*{answers[__${itemStat.index}__].text}">
</div>
</div>
</div>
<br>
<input type="submit" th:value="Save" class="btn btn-info">
</form>
</div>
<ul class="pagination">
<th:block th:each="question: ${test.questions}">
<form method="post" action="#" th:action="@{/business/editQuestion}">
<input type="hidden" th:name="test_id" th:value="${test.id}">
<input type="hidden" th:name="question_id" th:value="${question.id}">
<input type="submit" class="btn btn-danger" th:value=${question.questionNumber}>
</form>
</th:block>
<form method="post" action="#" th:action="@{/business/addQuestion}">
<input type="hidden" th:name="test_id" th:value="${test.id}">
<input type="hidden" th:name="question_id" th:value="${question.id}">
<input type="submit" class="btn btn-success" value="New Question">
</form>
</ul>
</div>
</body>
</html>
Question entity问题实体
@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Question {
@Id
@GeneratedValue(strategy= GenerationType.AUTO, generator="native")
@GenericGenerator(name = "native", strategy = "native")
private int id;
@EqualsAndHashCode.Exclude
private int questionNumber;
@EqualsAndHashCode.Exclude
private String questionBody = "";
@EqualsAndHashCode.Exclude
@ToString.Exclude
@ManyToOne
@JoinColumn(name = "test_id", nullable = false)
private Test test;
@EqualsAndHashCode.Exclude
@OneToMany(cascade = CascadeType.ALL, mappedBy = "question", orphanRemoval = true)
private List<Answer> answers = Arrays.asList(
new Answer(1, "", false),
new Answer(2, "", false),
new Answer(3, "", false),
new Answer(4, "", false));
public Question(int questionNumber) {
this.questionNumber = questionNumber;
}
public void setAnswer(Integer num, String answer, boolean correct) {
System.out.println(answers);
if(answers == null) {
answers = new ArrayList<>();
}
Answer a = answers.get(num - 1) != null ? answers.get(num - 1) : new Answer();
a.setAnswerNumber(num);
a.setText(answer);
a.setCorrect(correct);
a.setQuestion(this);
answers.set(num-1, a);
}
public void removeAnswer(Integer num) {
if(answers == null) {
return;
}
answers.set(num-1, new Answer(num, "", false));
}
}
Answer entity回答实体
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Answer {
@Id
@GeneratedValue(strategy= GenerationType.AUTO, generator="native")
@GenericGenerator(name = "native", strategy = "native")
private int id;
@EqualsAndHashCode.Exclude
private int answerNumber;
@EqualsAndHashCode.Exclude
private String text;
@EqualsAndHashCode.Exclude
private boolean correct;
@EqualsAndHashCode.Exclude
@ToString.Exclude
@ManyToOne
@JoinColumn(name = "question_id")
private Question question;`enter code here`
public Answer(int answerNumber, String text, boolean correct) {
this.answerNumber = answerNumber;
this.text = text;
this.correct = correct;
}
}
Does anyone know what cause that error and how can I solve it?有谁知道导致该错误的原因以及我该如何解决?
The most important message of the error message is: Cannot convert value of type 'java.lang.String' to required type 'com.easetest.website.model.Answer' .错误消息中最重要的消息是: Cannot convert value of type 'java.lang.String' to required type 'com.easetest.website.model.Answer' 。 To solve the problem I had to:为了解决这个问题,我必须:
create converter that implements Converter<String, Answer>创建实现 Converter<String, Answer> 的转换器
add that converter in WebConfig在 WebConfig 中添加该转换器
implementation below:下面的实现:
Converter class:转换器 class:
import com.easetest.website.model.Answer;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class StringToAnswerConverter implements Converter<String, Answer> {
@Override
public Answer convert(String s) {
String[] data = s.split(",");
return new Answer(
Integer.parseInt(getSubstringAfterChar(data[1], '=')),
new String(getSubstringAfterChar(data[2], '=')),
Boolean.parseBoolean(getSubstringAfterChar(data[3], '=')));
}
private String getSubstringAfterChar(String text, char character) {
return text.substring(text.lastIndexOf(character) + 1);
}
}
WebConfig class WebConfig class
import com.easetest.website.converters.StringToAnswerConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToAnswerConverter());
}
}
Hope it will be usefull to somebody.希望它对某人有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.