最近在看《Sring實戰》,看到第二章第3節時,出現了錯誤。
用Spring Tool Suite創建了一個專案,網頁模板用thymeleaf。
tacos.web.DesignTacoController.java
package tacos.web;
import ...; // 省略不重要代碼
import tacos.Taco;
import tacos.Ingredient;
import tacos.Ingredient.Type;
@Slf4j
@Controller
@RequestMapping("/design")
public class DesignTacoController {
@GetMapping
public String showDesignForm(Model model) {
List<Ingredient> ingredients = Arrays.asList(
new Ingredient("FLTO", "Flour Tortilla", Type.WRAP)... // 省略不重要代碼
);
Type[] types = Ingredient.Type.values();
for (Type type : types) {
model.addAttribute(type.toString().toLowerCase(), filterByType(ingredients, type));
}
model.addAttribute("design", new Taco()); // 這里在model里存入名為design的Taco Bean
return "design";
}
@PostMapping
public String processDesign(@Valid Taco design, Errors errors) { // 似乎是這里引起的錯誤,將@Valid去掉后,就不會報錯了
if (errors.hasErrors()) {
return "design";
}
log.info("Processing design: " + design);
return "redirect:/orders/current";
}
private List<Ingredient> filterByType(List<Ingredient> ingredients, Type type) { ... } // 省略不重要代碼
}
tacos.Taco.java
package tacos;
import ...;
@Data
public class Taco {
@NotNull
@Size(min = 5,message = "Name must be at least 5 character long")
private String name;
@NotNull
@Size(min = 1, message = "You must choose at least 1 ingredient")
private List<String> ingredients;
}
design.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Taco Cloud</title>
</head>
<body>
... <!--省略不重要代碼-->
<form method="POST" th:object="${design}"> <!--讀取背景關系中名為design的物件-->
<div class="grid">
<div class="ingredient-group" id="wraps">
<h3>Designate your wrap: </h3>
<div th:each="ingredient : ${wrap}">
<input name="ingredients" type="checkbox" th:value="https://bbs.csdn.net/topics/${ingredient.id}" />
<span th:text="${ingredient.name}">INGREDIENT</span><br />
</div>
</div>
... <!--這里基本是上面的div再重復4遍-->
</div>
<div>
<h3>Name your taco creation: </h3>
<input type="text" th:field="*{name}" /> <!--此處報錯:Caused by: org.attoparser.ParseException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "design" - line 58, col 28)-->
<br />
<button>Submit you taco</button>
</div>
</form>
</body>
</html>
首次訪問http://localhost:8080/design不會報錯。但是如果表單里填寫的資料不符合要求,例如未選擇任何一個復選框或未填寫名字,提交表單后就會報錯。下面是一些可能有用的錯誤資訊:
① 2021-02-11 23:52:52.551 ERROR 18440 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "design": An error happened during template parsing (template: "class path resource [templates/design.html]")
② Caused by: org.attoparser.ParseException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "design" - line 58, col 28)。注:此處的line 58, col 28即上面我在design.html中標注此處報錯的位置。
③:Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'design' available as request attribute。這里就是我說的Taco Bean丟失的錯誤。
在使用GET方法showDesignForm()時,我向model中存入了名為design的Taco Bean。提交表單時,由于表單沒有設定action屬性,會把請求仍然發送到/design。如果提交的表單的資料不符合要求,就會觸發錯誤,再次訪問/design,否則被重定向至/orders/current。可再次用POST方法訪問/design時,卻報告名為design的Taco Bean不存在了。
這到底是錯在哪?存在model里的物件的有效期是多久?兩個請求互相不能訪問對方model里的資料嗎?
--------20210212增加----------------------------------------------
回去再看《Spring實戰》,看到這么一段話:“Model物件負責在控制器和展現資料的視圖之間傳遞資料。實際上,放到Model屬性中的資料將會復制到Servlet Response的屬性中,這樣視圖就能在這里找到它們了 ”。現在大概明白錯誤的原因了。Model物件的資料會復制到Servlet Response中,所以Model物件的生存期和Servlet Response物件的生存期是一樣的,都只在一次請求中有效。所以在一次請求中存在Model內的東西,在下一次應該是不能訪問的。不過這里奇怪的是,為什么存在Model里的Taco Bean為什么可以多次訪問?
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/259078.html
標籤:Web 開發
上一篇:fgets函式使用
