Search code examples
javahtmlspringspring-bootthymeleaf

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.

Here is the specification about what I am doing:

1) I am using Spring boot, with ThyemeLeaf to load a temple.

2) I am pulling data from a DBF file

3) On the HTML page, I just load each of the row and its elements in a table.

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?

Here is the code that is being run.

What pulls the data from the 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

@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)

<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.

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. The first time it is not but the after refreshing, the logic is commented out?


Solution

  • 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.

    2. The DBFReader field is initialised only once by constructor and the reader uses the stream.

    The conclusion is that the first getRawData() method call works just fine. After the first call is made, the stream seems to reach its end: no records would be available at the consequent getRawData() method calls.

    Solution

    Consider updating the implementation of the getRawData() method. Alternatives:

    1. Create the reader (stream) right in the getRawData() method, on the every method call. 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.