为什么 servlet 会抛出 FileNotFoundException,而独立应用程序可以运行?

Why does servlet throw FileNotFoundException, while standalone application works?

我正在尝试在 servlet 中使用 Apache POI 打开一个 Excel 文件。

我已经在一个基本的 java 应用程序中测试了它,它可以正常工作,但在 servlet 中,我得到:

java.io.FileNotFoundException

这是我的 index.html:

<center>
<h2>
<a href="ExcelSrv">Click Here</a>
</h2>
</center>

ExcelGenerator.java:

package com.nody;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;


public class ExcelGenerator extends HttpServlet {
private static final long serialVersionUID = 1L;
public ExcelGenerator() 
{}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
{
response.setContentType("text/html");
PrintWriter out=response.getWriter();
try
{
FileInputStream file = new FileInputStream(new File("WebContent/files/source.xlsx"));       //Create Workbook instance holding reference to .xlsx file
XSSFWorkbook workbook = new XSSFWorkbook(file);
//Get first/desired sheet from the workbook
XSSFSheet sheet = workbook.getSheetAt(0);
//Iterate through each rows one by one
Iterator<Row> rowIterator = sheet.iterator();
 while (rowIterator.hasNext())
   {                        
    Row row = rowIterator.next();
    //For each row, iterate through all the columns
    Iterator<Cell> cellIterator = row.cellIterator();
  while (cellIterator.hasNext())
     {
      Cell cell = cellIterator.next();
      //Check the cell type and format accordingly
      switch (cell.getCellType())
       {
        case Cell.CELL_TYPE_NUMERIC:
        System.out.print(cell.getNumericCellValue() + "");
        break;
        case Cell.CELL_TYPE_STRING:
        System.out.print(cell.getStringCellValue() + "");
        break;
       }
     }
    System.out.println("");
   }
  file.close();
  }
  catch (Exception e)
  {
    e.printStackTrace();
  }
 }
}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>ExcelGenerator</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <description></description>
    <display-name>ExcelGenerator</display-name>
    <servlet-name>ExcelGenerator</servlet-name>
    <servlet-class>com.nody.ExcelGenerator</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ExcelGenerator</servlet-name>
    <url-pattern>/ExcelSrv</url-pattern>
  </servlet-mapping>
</web-app>

我的 Jar 文件:

dom4j-1.6.1.jar
poi-3.12-beta1-20150228.jar
poi-ooxml-3.12-beta1-20150228.jar
poi-ooxml-schemas-3.12-beta1-20150228.jar
servlet-api.jar
xmlbeans-2.6.0.jar

我将我的 Excel 文件保存在 WebContent/files/source.xlsx 中,它只包含一列。

使用

 getServletContext().getRealPath("")

你的情况

     FileInputStream file = new FileInputStream(new  File(getServletContext().getRealPath("/files/source.xlsx")));       //Create Workbook instance holding reference to .xlsx file

或者您可以使用

  FileInputStream file = getServletContext().getResourceAsStream("/files/source.xlsx");

您永远不应将 Web 资源作为 java.io.File 对象访问。在很多应用服务器中它们不会独立存在于文件系统中。

正确的方法是利用javax.servlet.ServletContext.getResourceAsStream(java.lang.String):

 InputStream sourceInput = request.getServletContext().getResourceAsStream("/files/source.xlsx");
 XSSFWorkbook workbook = new XSSFWorkbook(sourceInput);