“th:text/each”未显示数据(Spring Boot/Thymeleaf)

huangapple 未分类评论76阅读模式
英文:

"th:text/each" not displaying data (Spring Boot/Thymeleaf)

问题

这个应用程序应该从一个网页上获取关于冠状病毒的信息,并将其输出到我们自己网页上的漂亮表格中。

所有的表头都在,但是列本身是空的。

尽管数据在控制器中正确传递,但Thymeleaf不会显示传递给它的数据。我会感激任何输入,谢谢。

LocationStats.java (已编辑)

package io.javabrains.coronavirustracker.models;

public class LocationStats
{
    private String state;
    private String country;
    private int latestTotalCases;

    public String getState() { return this.state; }

    public void setState(String state) { this.state = state; }

    public String getCountry() { return this.country; }

    public void setCountry(String country) { this.country = country; }

    public int getLatestTotalCases() { return this.latestTotalCases; }

    public void setLatestTotalCases(int latestTotalCases) { this.latestTotalCases = latestTotalCases; }

    @Override
    public String toString()
    {
        return "LocationStats{" + "state='" + state + '\'' + ", country='" + country + '\'' + ", latestTotalCases=" + latestTotalCases + '}';
    }
}

CoronaVirusDataService.java

package io.javabrains.coronavirustracker.services;

import io.javabrains.coronavirustracker.models.LocationStats;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;

@Service
public class CoronaVirusDataService
{
    private static String VIRUS_DATA_URL = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv";
    private List<LocationStats> allStats = new ArrayList<>();

    public List<LocationStats> getAllStats() { return allStats; }

    @PostConstruct
    @Scheduled(cron = "* * 1 * * *")
    public void fetchVirusData() throws IOException, InterruptedException
    {
        List<LocationStats> newStats = new ArrayList<>();
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create(VIRUS_DATA_URL)).build();
        HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(httpResponse.body()); // 如预期地打印出所有数据

        StringReader csvBodyReader = new StringReader(httpResponse.body());
        Iterable<CSVRecord> records = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(csvBodyReader);

        for(CSVRecord record : records)
        {
            LocationStats locationStat = new LocationStats();

            locationStat.setCountry(record.get("Country/Region"));
            locationStat.setState(record.get("Province/State"));
            locationStat.setLatestTotalCases(Integer.parseInt(record.get(record.size() - 1)));
            newStats.add(locationStat);

            System.out.println(locationStat); // 如预期地打印出数据
        }

        this.allStats = newStats;
    }
}

HomeController.java

package io.javabrains.coronavirustracker.controllers;

import io.javabrains.coronavirustracker.models.LocationStats;
import io.javabrains.coronavirustracker.services.CoronaVirusDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

@Controller
public class HomeController
{
    @Autowired
    CoronaVirusDataService coronaVirusDataService;

    @GetMapping("/")
    public String home(Model model)
    {
        List<LocationStats> allStats = coronaVirusDataService.getAllStats();
        int testNumber = 999; // 用于测试属性

        model.addAttribute("locationStats", allStats); // 实际属性
        model.addAttribute("testInt", testNumber); // 测试属性

        return "home";
    }
}

home.html (已编辑)

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

<head>
    <title>Corona Virus Tracker Application</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>

<body>

<h1 th:text="${testInt}">-1</h1>

<table>
    <tr>
        <th>State</th>
        <th>Country</th>
        <th>Total Cases</th>
    </tr>
    <tr th:each="locationStat : ${locationStats}">
        <td th:text="${locationStat.state}"></td>
        <td th:text="${locationStat.country}"></td>
        <td th:text="${locationStat.latestTotalCases}">0</td>
    </tr>
</table>

</body>

</html>

CoronavirusTrackerApplication.java

package io.javabrains.coronavirustracker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class CoronavirusTrackerApplication
{
	public static void main(String[] args)
	{
		SpringApplication.run(CoronavirusTrackerApplication.class, args);
	}
}

pom.xml

<!-- 这里省略了 POM 文件的内容 -->

网页的当前状态

英文:

This application is supposed to take info on the corona virus from a webpage and output it into a nice table on our own webpage.

All table headers are there but the columns themselves are empty.

Thymeleaf doesn't display data passed to it in model despite data being passed correctly in the controller. I would appreciate any input, thank you.

LocationStats.java (Edited)

package io.javabrains.coronavirustracker.models;

public class LocationStats
{
    private String state;
    private String country;
    private int latestTotalCases;

    public String getState() { return this.state; }

    public void setState(String state) { this.state = state; }

    public String getCountry() { return this.country; }

    public void setCountry(String country) { this.country = country; }

    public int getLatestTotalCases() { return this.latestTotalCases; }

    public void setLatestTotalCases(int latestTotalCases) { this.latestTotalCases = latestTotalCases; }

    @Override
    public String toString()
    {
        return &quot;LocationStats{&quot; + &quot;state=&#39;&quot; + state + &#39;\&#39;&#39; + &quot;, country=&#39;&quot; + country + &#39;\&#39;&#39; + &quot;, latestTotalCases=&quot; + latestTotalCases + &#39;}&#39;;
    }
}

CoronaVirusDataService.java

package io.javabrains.coronavirustracker.services;

import io.javabrains.coronavirustracker.models.LocationStats;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;

@Service
public class CoronaVirusDataService
{
    private static String VIRUS_DATA_URL = &quot;https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv&quot;;
    private List&lt;LocationStats&gt; allStats = new ArrayList&lt;&gt;();

    public List&lt;LocationStats&gt; getAllStats() { return allStats; }

    @PostConstruct
    @Scheduled(cron = &quot;* * 1 * * *&quot;)
    public void fetchVirusData() throws IOException, InterruptedException
    {
        List&lt;LocationStats&gt; newStats = new ArrayList&lt;&gt;();
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create(VIRUS_DATA_URL)).build();
        HttpResponse&lt;String&gt; httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(httpResponse.body()); // Prints all data as expected

        StringReader csvBodyReader = new StringReader(httpResponse.body());
        Iterable&lt;CSVRecord&gt; records = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(csvBodyReader);

        for(CSVRecord record : records)
        {
            LocationStats locationStat = new LocationStats();

            locationStat.setCountry(record.get(&quot;Country/Region&quot;));
            locationStat.setState(record.get(&quot;Province/State&quot;));
            locationStat.setLatestTotalCases(Integer.parseInt(record.get(record.size() - 1)));
            newStats.add(locationStat);
            
            System.out.println(locationStat); // Prints data as expected
        }

        this.allStats = newStats;
    }
}

HomeController.java

package io.javabrains.coronavirustracker.controllers;

import io.javabrains.coronavirustracker.models.LocationStats;
import io.javabrains.coronavirustracker.services.CoronaVirusDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
public class HomeController
{
    @Autowired
    CoronaVirusDataService coronaVirusDataService;

    @GetMapping(&quot;/&quot;)
    public String home(Model model)
    {
        List&lt;LocationStats&gt; allStats = coronaVirusDataService.getAllStats();
        int testNumber = 999; // For test attribute

        model.addAttribute(&quot;locationStats&quot;, allStats); // Actual attribute
        model.addAttribute(&quot;testInt&quot;, testNumber); // Test attribute

        return &quot;home&quot;;
    }
}

home.html (Edited)

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;

&lt;head&gt;
    &lt;title&gt;Corona Virus Tracker Application&lt;/title&gt;
    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;
&lt;/head&gt;

&lt;body&gt;

&lt;h1 th:text=&quot;${testInt}&quot;&gt;-1&lt;/h1&gt;

&lt;table&gt;
    &lt;tr&gt;
        &lt;th&gt;State&lt;/th&gt;
        &lt;th&gt;Country&lt;/th&gt;
        &lt;th&gt;Total Cases&lt;/th&gt;

    &lt;/tr&gt;
    &lt;tr th:each=&quot;locationStat : ${locationStats}&quot;&gt;
        &lt;td th:text=&quot;${locationStat.state}&quot;&gt;&lt;/td&gt;
        &lt;td th:text=&quot;${locationStat.country}&quot;&gt;&lt;/td&gt;
        &lt;td th:text=&quot;${locationStat.latestTotalCases}&quot;&gt;0&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;/body&gt;

&lt;/html&gt;

CoronavirusTrackerApplication.java

package io.javabrains.coronavirustracker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class CoronavirusTrackerApplication
{
	public static void main(String[] args)
	{
		SpringApplication.run(CoronavirusTrackerApplication.class, args);
	}
}

pom.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
	&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
	&lt;parent&gt;
		&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
		&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
		&lt;version&gt;2.3.2.RELEASE&lt;/version&gt;
		&lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
	&lt;/parent&gt;
	&lt;groupId&gt;io.javabrains&lt;/groupId&gt;
	&lt;artifactId&gt;coronavirus-tracker&lt;/artifactId&gt;
	&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
	&lt;name&gt;coronavirus-tracker&lt;/name&gt;
	&lt;description&gt;Demo project for Spring Boot&lt;/description&gt;

	&lt;properties&gt;
		&lt;java.version&gt;14&lt;/java.version&gt;
	&lt;/properties&gt;

	&lt;dependencies&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
			&lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;/artifactId&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
			&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
		&lt;/dependency&gt;

		&lt;dependency&gt;
			&lt;groupId&gt;org.apache.commons&lt;/groupId&gt;
			&lt;artifactId&gt;commons-csv&lt;/artifactId&gt;
			&lt;version&gt;1.8&lt;/version&gt;
		&lt;/dependency&gt;

		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
			&lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
			&lt;scope&gt;runtime&lt;/scope&gt;
			&lt;optional&gt;true&lt;/optional&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
			&lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
			&lt;scope&gt;test&lt;/scope&gt;
			&lt;exclusions&gt;
				&lt;exclusion&gt;
					&lt;groupId&gt;org.junit.vintage&lt;/groupId&gt;
					&lt;artifactId&gt;junit-vintage-engine&lt;/artifactId&gt;
				&lt;/exclusion&gt;
			&lt;/exclusions&gt;
		&lt;/dependency&gt;
	&lt;/dependencies&gt;

	&lt;build&gt;
		&lt;plugins&gt;
			&lt;plugin&gt;
				&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
				&lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
			&lt;/plugin&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
                &lt;configuration&gt;
                    &lt;source&gt;14&lt;/source&gt;
                    &lt;target&gt;14&lt;/target&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
	&lt;/build&gt;

&lt;/project&gt;

Webpage's current state

答案1

得分: 0

Thymeleaf只能通过getters访问数据。在你的LocationStats类中添加getters。

澄清一下:

当你在Thymeleaf中编写:

<td th:text="${locationStat.state}"></td>

Thymeleaf中的.state实际上在底层使用了你的类中定义的getter来获取state。没有getter就没有Thymeleaf表示。

英文:

Thymeleaf can only access data through getters. Add getters to your LocationStats class.

To clarify:

when you write in Thymeleaf:

&lt;td th:text=&quot;${locationStat.state}&quot;&gt;&lt;/td&gt;

the .state in Thymeleaf is under the hood using the getter defined in your class to retrieve state. No getter = no thymeleaf representation.

huangapple
  • 本文由 发表于 2020年8月15日 01:21:08
  • 转载请务必保留本文链接:https://java.coder-hub.com/63417356.html
匿名

发表评论

匿名网友

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

确定