简体   繁体   English

Thymeleaf HTML页面的表在刷新页面后停止工作

[英]Thymeleaf HTML page's table stops working after refreshing the page

I am very new to Spring boot and ThyemeLeaf and still learning it, so maybe I am not searching this correctly on the internet, but I don't see such problem anywhere. 我是Spring Boot和ThyemeLeaf的新手,并且仍然在学习它,所以也许我没有在Internet上正确地搜索它,但是在任何地方都看不到这样的问题。

Here is the specification about what I am doing: 这是关于我在做什么的规范:

1) I am using Spring boot, with ThyemeLeaf to load a temple. 1)我正在使用Spring Boot,并与ThyemeLeaf一起加载太阳穴。

2) I am pulling data from a DBF file 2)我正在从DBF文件中提取数据

3) On the HTML page, I just load each of the row and its elements in a table. 3)在HTML页面上,我只是将每一行及其元素加载到表中。

Problem: After redeploying the whole app, the page works fine, it loads everything just fine. 问题:重新部署整个应用程序后,页面运行正常,它可以正常加载所有内容。 when I refresh the page the table does not load. 当我刷新页面时,表格不会加载。

Is this a problem with thymeleaf or my HTML or the Spring? 这是百里香叶或HTML还是Spring的问题?

Here is the code that is being run. 这是正在运行的代码。

What pulls the data from the DBF 是什么从DBF中提取数据

@Component("DBFInterface")
public class DBFInterface {

    private String fileName;
    private DBFReader reader;

    // DBF reader is from a library to work with .dbf files, 
    // I have tested it in pure java, it works fine
    // https://github.com/albfernandez/javadbf
    public DBFInterface(String fileName) {
        // location of the .dbf file
        this.fileName = fileName == null ? DATA.DATA_FILE_NAME : fileName;
        init();
    }

    public DBFInterface() {
        fileName = DATA.DATA_FILE_NAME;
        init();
    }

    // starting the "reader" with lets me interface with the database
    private void init() {
        try {
            reader = new DBFReader(new FileInputStream(fileName));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public List<DBFField> getFieldList() {
        int count = reader.getFieldCount();
        List<DBFField> list = new ArrayList<>(count);

        for (int i = 0; i < count; i++) list.add(reader.getField(i));
        return list;
    }

    // all of the records in the database, 
    // each column in an element in the Object array
    public List<Object[]> getRawData() {
        int count = reader.getRecordCount();
        List<Object[]> list = new ArrayList<>(count);
        Object[] rowObjects;
        while ((rowObjects = reader.nextRecord()) != null) {
            list.add(rowObjects);
        }
        return list;
    }

    // getters and setters
}

The Part of the Controller that lets the HTML access the data 控制器的允许HTML访问数据的部分

@RequestMapping(method = RequestMethod.GET)
public String getSimpleTable(Model model) {
    List<Object[]> l = dbfInterface.getRawData();
    model.addAttribute("rawData", l);
    model.addAttribute("tableFields", dbfInterface.getFieldList());
    if (l.size() > 0) System.out.println("RAW DATA NOT EMPTY");
    return "simple_table";
}

The part of HTML that is to load the data (I will make it the columns dynamic later when I can solve this first) HTML的一部分,用于加载数据(稍后我将首先解决此问题时,将使它成为动态列)

<tr th:each="data:${rawData}">
  <td th:text="${data[0]}"></td>
  <td th:text="${data[1]}"></td>
  <td th:text="${data[2]}"></td>
  <td th:text="${data[3]}"></td>
  <td th:text="${data[4]}"></td>
  <td th:text="${data[5]}"></td>
  <td th:text="${data[6]}"></td>
  <td th:text="${data[7]}"></td>
  <td th:text="${data[8]}"></td>
  <td th:text="${data[9]}"></td>
  <td th:text="${data[10]}"></td>
</tr>

I have tried to toggle Thymeleaf's cache as well as fiddle with the HTML, the thing is I don't know where the problem is originating. 我试图切换Thymeleaf的缓存以及弄乱HTML,但事实是我不知道问题出在哪里。

I can tell you this, refreshing does not execute this bit again, It is executed the very first time I load the page. 我可以告诉您,刷新不会再次执行此位,而是在我第一次加载页面时执行。

2017-08-05 16:09:43.837  INFO 10409 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-08-05 16:09:43.838  INFO 10409 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2017-08-05 16:09:43.860  INFO 10409 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 22 ms
RAW DATA NOT EMPTY

Any suggestion? 有什么建议吗? or guidance on resources where I can look myself? 或关于资源的指导,让我自己看待自己? Again, it works fine the first time I load it after redeploying but the table does not load after I refresh the page. 同样,重新部署后我第一次加载它时,它工作正常,但是刷新页面后,该表未加载。

edit 编辑

Some more stuff I found out when I ran the dev mode in chrome, the HTML bit posted was commented out. 当我在chrome中运行开发模式时发现了更多内容,其中的HTML位被注释掉了。 The first time it is not but the after refreshing, the logic is commented out? 不是第一次,而是刷新后,逻辑被注释掉了吗?

Root cause analysis 根本原因分析

Facts: 事实:

  1. The Component annotation is being used without the Scope annotation, so the lifecycle of the instance of the DBFInterface class is the singleton. 使用Component注释时没有使用Scope注释,因此DBFInterface类实例的生命周期是单例。

  2. The DBFReader field is initialised only once by constructor and the reader uses the stream. DBFReader字段仅由构造函数初始化一次,并且阅读器使用该流。

The conclusion is that the first getRawData() method call works just fine. 结论是,第一个getRawData()方法调用可以正常工作。 After the first call is made, the stream seems to reach its end: no records would be available at the consequent getRawData() method calls. 进行第一次调用后,流似乎已到达末尾:随后的getRawData()方法调用将没有可用的记录。

Solution

Consider updating the implementation of the getRawData() method. 考虑更新getRawData()方法的实现。 Alternatives: 备择方案:

  1. Create the reader (stream) right in the getRawData() method, on the every method call. 在每个方法调用上,都在getRawData()方法中创建读取器(流)。 So, the reader becomes a local variable. 因此,阅读器成为局部变量。
  2. Rewind the reader (stream) to the beginning. 将阅读器(流)倒回开头。 Requires the reader state synchronisation in case of multithreading. 在多线程的情况下需要读取器状态同步。

The first alternative seems to be simpler and more straightforward than the second one. 第一种选择似乎比第二种选择更简单明了。

Also, make sure that the reader (its stream) is closed appropriately. 另外,请确保已正确关闭阅读器(其流)。

  1. The @Component("DBFInterface") annotation creates only one instance of DBFInterface . @Component("DBFInterface")批注仅创建一个DBFInterface实例。
  2. The first time that the pages is loaded the while ((rowObjects = reader.nextRecord()) != null) { retreives data because netxRecord() is not null, but the second time that pages is loaded there are no more rows to read because is the same reader object of the first time. 第一次加载页面while ((rowObjects = reader.nextRecord()) != null) {检索数据,因为netxRecord()不为null,但是第二次加载页面时,没有更多行可读取因为是第一次相同的reader对象。

One possible solution is: 一种可能的解决方案是:

  1. Go to DBFInterface class 转到DBFInterface
  2. Go to DBFInterface constructor and remove init() method call from it 转到DBFInterface构造函数并DBFInterface删除init()方法调用

Like this: 像这样:

 public  DBFInterface(){
        fileName = DATA.DATA_FILE_NAME; 
    }
  1. Change init method to public init方法更改为public

init() Method init()方法

 public void init(){
        try {
            reader = new DBFReader(new FileInputStream(fileName));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
  1. Go to the getSimpleTable method and call init() method before getRawData 转至getSimpleTable方法和调用init() getRawData前法

Like this: 像这样:

   @RequestMapping(method = RequestMethod.GET)
        public String getSimpleTable(Model model){
            dbfInterface.init();
            List<Object[]> l = dbfInterface.getRawData();
            model.addAttribute("rawData",l);
            model.addAttribute("tableFields",dbfInterface.getFieldList());
            if(l.size() > 0) System.out.println("RAW DATA NOT EMPTY");
            return "simple_table";
        }

The disadvantage of this alternative is that per every request you have to read the file from the beginning. 这种替代方法的缺点是,每个请求都必须从头开始读取文件。

Please also try to call DBFUtils.close(reader); 也请尝试调用DBFUtils.close(reader); at some point, maybe if you create a close() method on DBFInterface like this: 在某个时候,也许如果您像这样在DBFInterface上创建close()方法:

 public void close(){
        try {
            DBFUtils.close(reader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

And call it when you finish to read the data. 完成读取数据后调用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM