为什么 java.io.File 对象集合的数据不会显示在 JSP forEach 标记中?

Why won't data for a collection of java.io.File objects display in a JSP forEach tag?

我 运行 陷入 JSP 不显示数据的常见问题。但是,我正在关注文档,并且还尝试了该站点上提出的许多问题的解决方案,但均未成功。

如何在 JSP 中显示 java.io.File 数据?如果我这样做是正确的,是否需要任何额外的配置?

我有一个使用 java.io.File 的文件[],它是在 javax.servlet.http.HttpServlet 中创建的。然后我获取 File[] 并将其作为属性添加到我的 HttpSession 中。然后将其转发到 JSP 文件,传递给 forEach 标记,并填充到 table 中。 (参见 this article

这是我的 java servlet:

public class LogManagement extends HttpServlet {

    private static final Logger logger = LoggerFactory.getLogger(LogManagement.class);

    
    private static final String BASE_DIRECTORY = System.getProperty("catalina.base");
    private static final File CURRENT_LOGS_FOLDER = new File(BASE_DIRECTORY + "/logs");
    private static final File CAPTURED_LOGS_FOLDER = new File(BASE_DIRECTORY + "/logs/captured");

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("GET called on LogManagement servlet");
        try {
            getLogs(request);
            getServletContext().getRequestDispatcher("/LogManagement.jsp").forward(request, response);
        } catch (Exception e) {
            logger.info("ERROR unable to GET log data");
            logger.info(e.getMessage());
        }
    }

    private void getLogs(HttpServletRequest request) {
        logger.info("Getting logs");
        File[] currentLogs = CURRENT_LOGS_FOLDER.listFiles();
        File[] capturedLogs = CAPTURED_LOGS_FOLDER.listFiles();

        HttpSession session = request.getSession();
        session.setAttribute("currentLogs", currentLogs);
        session.setAttribute("capturedLogs", capturedLogs);
        logger.info("Got logs");
    }
}

这是我从 here and here 尝试的两个解决方案的 jsp(是的,我知道它使用了一些已弃用的标签属性,但我无法更改这些属性)

解决方案 1:

        <table style="margin-top: 5px; width: 600px;" align="left">
            <tr>
                <td align="left">
                    Current Logs:
                </td>
            </tr>
            <tr>
                <td>
                    <div class="file-viewer">
                        <table>
                            <c:forEach var="file" items="${currentLogs}">
                                <tr>
                                    <td><c:out value="${file.name}"/></td>
                                    <td><c:out value="${file.length}"/></td>
                                    <td><c:out value="${file.lastModified}"/></td>
                                </tr>
                            </c:forEach>
                        </table>
                    </div>
                </td>
            </tr>
        </table>

解决方案 2:

        <table style="margin-top: 5px; width: 600px;" align="left">
            <tr>
                <td align="left">
                    Captured Logs:
                </td>
            </tr>
            <tr>
                <td>
                    <div class="file-viewer">
                        <table>
                            <c:forEach var="file" items="${capturedLogs}">
                                <tr>
                                    <td>${file.name}</td>
                                    <td>${file.length}</td>
                                    <td>${file.lastModified}</td>
                                </tr>
                            </c:forEach>
                        </table>
                    </div>
                </td>
            </tr>
        </table>

这是我在文档和各种 SO 答案中看到的两种解决方案。我也在 td 标签内尝试了 <% out.print(file.getName()); %> 但没有成功(参见

这是我得到的异常:

An exception occurred processing [/LogManagement.jsp] at line [51]__48: ________c:forEach var=file items=${currentLogs}49: _____tr__50: ___________td__c:out value=${file.name}//td__51: ___________td__c:out value=${file.length}//td__52: _________td__c:out value=${file.lastModified}//td__53: __________/tr__54: _________/c:forEach____Stacktrace:

如果我用虚拟数据替换我正在寻找的数据,我会打印出每一项。

<td>fileName</td>
<td>fileSize</td>
<td>lastEdited</td>

给出 table 行数等于我正在查看的文件数显示:

"fileName fileSize lastEdited"

这表明我的 forEach 正在工作,但对特定数据的引用没有。

您似乎缺少 c:out 标记,就像您在循环遍历 currentLogs 时在上面插入的标记一样。

附带说明一下,除非是大学课程或遗留项目的要求,否则在 2021 年学习 JSP 真的不值得。

问题是 JSTL 希望在搜索对象的 属性 时找到 getter 函数。具体是指有一些方法名的前三个字符是“get”。

在示例中,<td>${file.name}</td> 可以独立运行,因为 java.io.File 有一个名为“getName()”的方法。但是,length 和 lastModified 都没有“get”作为前缀(.length() 和 .lastModified()),尽管它们只是检索一个值。

有很多方法可以解决这个问题(扩展对象、添加“获取”方法等),但我认为最简单的方法是对新对象使用 class。

我在上面的 .java 文件的末尾添加了一个 class 并使用它来代替 java.io.File 对象。它工作得很好:

新 Class:

public class LogFile {
    private String name;
    private long length;
    private String lastModified;

    public LogFile(File file) {
        this.name = file.getName();
        this.length = file.length() / 1024;
        this.lastModified = timeStampFormat.format(file.lastModified());
    }

    public String getName() {
        return this.name;
    }

    public long getLength() {
        return this.length;
    }

    public String getLastModified() {
        return this.lastModified;
    }
}

使用对象:

    File[] currentLogFiles = CURRENT_LOGS_FOLDER.listFiles();
    File[] capturedLogFiles = CAPTURED_LOGS_FOLDER.listFiles();
    List<LogFile> currentLogs = new ArrayList<>();
    List<LogFile> capturedLogs = new ArrayList<>();

    if (currentLogFiles != null) {
        for (File file : currentLogFiles) {
            currentLogs.add(new LogFile(file));
        }
    }
    if (capturedLogFiles != null) {
        for (File file : capturedLogFiles) {
            currentLogs.add(new LogFile(file));
        }
    }

    HttpSession session = request.getSession();
    session.setAttribute("currentLogs", currentLogs);
    session.setAttribute("capturedLogs", capturedLogs);

附带说明:据我所知,${file.name}<c:out value="${file.name}" /> 都在 jst 中工作。