You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+Java+Thymeleaf环境下HTML页面无法加载问题排查

问题排查:Spring Boot中/numasc路径仅返回JSON不加载Thymeleaf页面

问题描述

访问/numasc路径时,后端AppController的getNumAsc方法已正确返回Troops列表的JSON数据,但对应的Thymeleaf HTML页面未被加载,其他结构类似的HTML页面均正常工作。

Controller代码

@Controller
public class AppController {

    @Autowired
    private UserRepository userRepo;

    @GetMapping("")
    public String viewHomePage() {
        return "index";
    }

    @GetMapping("/index")
    public String logoutPage() {return "index";}

    @GetMapping("/menu")
    public String menuPage() {return "menu";}

    @GetMapping("/register")
    public String showRegistrationForm(Model model) {
        model.addAttribute("user", new User());
        return "signup_form";
    }

    @PostMapping("/process_register")
    public String processRegister(User user) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encodedPassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodedPassword);
        userRepo.save(user);
        return "menu";
    }

    @GetMapping("/users")
    public String listUsers(Model model) {
        List<User> listUsers = userRepo.findAll();
        model.addAttribute("listUsers", listUsers);
        return "users";
    }

    public List<Troops> getTroops() {
        List<Troops> TroopList = new LinkedList<>();
        try {
            // File path to the XML file.
            Path filePath = Paths.get("C:\\Users\\amani\\OneDrive\\WYWM\\Java\\Capstone 1\\dataset.xml");
            File file = new File(String.valueOf(filePath.toAbsolutePath()));

            if (file.exists()) {
                DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
                Document document = documentBuilder.parse(String.valueOf(filePath.toAbsolutePath()));
                // Reads the XML tagName of full_name and id.
                NodeList[] user = { document.getElementsByTagName("full_name"), document.getElementsByTagName("id") };

                for (int i = 0; i < user[0].getLength(); i++) {
                    String fullName = user[0].item(i).getTextContent();
                    int id = Integer.parseInt(user[1].item(i).getTextContent());
                    Troops newTroop = new Troops(fullName, id);
                    TroopList.add(newTroop);
                }
            } else {
                System.out.println("File not found");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        // Returns the TroopList with data from the XML file.
        return TroopList;
    }

    @RequestMapping(value = "/numasc", method = RequestMethod.GET)
    @ResponseBody
    public List<Troops> getNumAsc() {
        List<Troops> ascList = new LinkedList<Troops>();
        ascList.addAll(getTroops());
        ascList.sort((u1, u2) -> u1.getId() - u2.getId());
        return ascList;
    }
}

返回的JSON数据

[{"fullName":"Maridel MacCostye","id":1},{"fullName":"Phineas Bonnet","id":2},{"fullName":"Oates McGillivray","id":3},{"fullName":"Curtice Comelli","id":4},{"fullName":"Phillis Wontner","id":5},{"fullName":"Bradley Hasell","id":6},{"fullName":"Carling Cokely","id":7},{"fullName":"Bertrand Samms","id":8},{"fullName":"Chiarra Trill","id":9},{"fullName":"Willie Balmadier","id":10}]

/numasc对应的HTML页面代码

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

<head>
  <meta charset="ISO-8859-1">
  <title>Soldiers Deployed</title>
  <link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
  <script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
  <script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>

<body>
<div class="container text-center">
  <div>
    <form th:action="@{/logout}" method="post">
      <p>
        Welcome <b>[[${#request.userPrincipal.principal.fullName}]]</b>
      </p>
      <input type="submit" value="Sign Out" />
    </form>
  </div>
  <div>
    <h1>Soldiers Deployed</h1>
  </div>

  <div>

    <table class="table table-striped table-bordered">
      <thead class="thead-dark">
      <tr>
        <th>ID</th>
        <th>Full Name</th>

      </tr>
      </thead>
      <tbody>

      <a th:href="@{/menu}" class="button primary">Back to Menu</a>

      <tr th:each=" ${ascList}">
        <td th:text=${ascList.id}>ID</td>>
        <td th:text=${ascList.fullName}>Full name</td>>
      </tr>
      </tbody>
    </table>
  </div>
</div>
</body>

</html>

排查分析与解决方案

核心问题1:@ResponseBody注解导致直接返回JSON

getNumAsc方法添加了@ResponseBody注解,这个注解会将方法返回的对象直接序列化为JSON响应体返回给前端,而非返回视图名称让Spring渲染Thymeleaf页面。其他正常方法(如listUsers)无此注解,通过返回视图名+Model传值实现页面渲染。

核心问题2:数据未传入Model,Thymeleaf无法获取数据

即使去掉@ResponseBody,当前方法也未将排序后的ascList放入Model,页面无法拿到渲染数据。

核心问题3:Thymeleaf遍历语法错误

页面中<tr th:each=" ${ascList}">语法错误,正确格式应为th:each="变量名 : ${集合}",需通过变量名访问集合元素的属性。

修改步骤

1. 修改Controller的getNumAsc方法

移除@ResponseBody,添加Model参数并传入数据,返回视图名称:

@GetMapping("/numasc")
public String getNumAsc(Model model) {
    List<Troops> ascList = new LinkedList<>(getTroops());
    ascList.sort((u1, u2) -> u1.getId() - u2.getId());
    model.addAttribute("ascList", ascList);
    return "numasc";
}

2. 修正Thymeleaf页面的遍历代码

修改遍历语法与属性访问方式:

<tr th:each="troop : ${ascList}">
    <td th:text="${troop.id}">ID</td>
    <td th:text="${troop.fullName}">Full name</td>
</tr>

3. 确认页面路径

确保numasc.html放在Spring Boot默认Thymeleaf模板路径src/main/resources/templates/下,文件名与方法返回的视图名一致。

内容的提问来源于stack exchange,提问作者Neet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 03:15:58