簡體   English   中英

Java / JSP圖像上傳。 在哪里保存這些圖像文件?

[英]Java/JSP Image upload. Where to keep these image files?

我正在編寫一個簡單的應用程序,讓用戶上傳圖像。 上傳后,用戶可以標記或刪除它們。

我想出了如何上傳文件並在文件上傳后保存它們。 我一直在跟蹤保存圖像的全局路徑。 在數據庫中,我保留有關圖像的元數據,如文件名,標簽等。

我正在使用Java / JSP(特別是Stripes框架,但我的問題是通用的)。

我的問題是,一旦上傳這些圖像文件,我該將它保存在哪里?

現在我在Tomcat服務器上部署了兩個Web應用程序。 一個主要的Web應用程序和另一個是我上傳圖像的位置。

但這不起作用,因為在重新部署/重新啟動Tomcat之前,我無法在主應用程序中看到上傳的圖像。

似乎Tomcat不會自動選擇新上傳的圖像。

有沒有人有任何解決方案?

這是一個簡單的項目,所以我不想將它們存儲在數據庫中或使用Apache來存儲圖像。 對於這個小項目來說,這一切都太復雜了。

謝謝。

絕對不要將圖像存儲在數據庫中,但是您需要將圖像路徑存儲在數據庫中。 這將允許您將圖像存儲在任何地方。

由於您使用的是兩個tomcat應用程序,因此最好的辦法是將圖像存儲在任一應用程序之外,然后將圖像流式傳輸回用戶,而不是讓tomcat管理文件。 否則,我會問你為什么要用兩個網絡應用程序來做這件事。

但是,將上傳的圖像存儲在web-app目錄中並不是明智之舉,而且你知道。

順便說一下,你可能想看看這個stackoverflow線程 ,最近討論了存儲圖像的位置。 它可能無法解決您的問題,肯定會讓您對自己的工作更有信心。

我用不同的方式解決了這個問題。

首先,不可移植的方式是Glassfish(我也相信Tomcat)允許您將外部目錄映射到webapps層次結構。 這非常有效,並且完全符合您的要求。 它允許您將圖像存儲在遠離Web應用程序的外部目錄中,但仍然可以為其提供服務。

但是,這種技術不便攜。

我可以輕松完成它的方法是創建一個過濾器。

您將過濾器置於顯而易見的位置,例如“/ images”。

過濾器的作用是:

  • 它在webapp中的特殊目錄中檢查圖像(或任何東西,它適用於任何靜態資源)。 對於我們的示例,我們將使用url“/ webapp / images”。

  • 如果文件不存在,我們將文件從您的外部位置復制到webapp中的適當位置。 所以,讓我們說reqyest url是“/images/banner.gif”。 並且您的文件存儲在磁盤“/ home / app / images”中。 所以,我們的源文件是“/home/app/images/banner.gif”。 然后我們將它復制到webapp樹中我們想要的位置。 我們使用“ServletContext.getRealPath”。 因此,目標將是“ServletContext.get RealPath(”/ webapp / images / banner.gif“)。只需將源復制到目標。

  • 如果文件已存在或現在存在,只需轉發到/webapp/images/banner.gif處的實際圖像。

實際上,您最終會在Web應用程序部署樹中擁有文件緩存。 缺點是它是一個緩存,因此需要進行維護(即,您應該檢查原始文件是否比緩存更新,確保刪除源是否被刪除等)。 此外,它會復制您的資源,因此您的圖像最終會消耗兩倍的磁盤空間。 最后,啟動時有初始復制成本。

但是,它可以工作,它可以防止您使用自己的代碼提供靜態資源。 (這是第三種解決方案,映射過濾器/ servlet以攔截URL並簡單地將其自行傳輸。)

我會看看Tomcat中的構造(假設它存在)為你做映射。 我知道它存在於Glassfish中。 (谷歌交替使用Glassfish來了解它是如何工作的。)

我正在使用兩個Web應用程序來避免過度編寫上傳的圖像,以防我重新部署新的主應用程序war文件。

但正如你所提到的那樣,沒有其他選擇,只能通過Servlet或其他東西流式傳輸它們,我想我可以將它們保存在tomcat目錄之外。

我想避免編寫這個Streaming Servlet。 在編寫流式servlet時,只是太小的項目來處理所有混亂(如正確的內容類型,404等)。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Image streaming Servlet.
 */
public class ImageDisplayServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public ImageDisplayServlet() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String relativePath = trimToEmpty(request.getPathInfo());

        // Make sure no one try to screw with us. 
        // This is important as user can literally access any file if we are not careful
        if(isXSSAttack(relativePath) == false) {
            String pathToFile = this.getServletContext().getRealPath(request.getPathInfo());
            File file = new File(pathToFile);

            System.out.println("Looking for file " + file.getAbsolutePath());

            // show a 404 page
            if(!file.exists() || !file.isFile()) {
                httpError(404, response);
            } else {
                try {
                    streamImageFile(file, response);
                } catch(Exception e) {
                    // Tell the user there was some internal server error.\
                    // 500 - Internal server error.
                    httpError(500, response);
                    e.printStackTrace();
                }
            }
        } else {
            // what to do if i think it is a XSS attack ?!?
        }
    }

    private void streamImageFile(File file, HttpServletResponse response) {
        // find the right MIME type and set it as content type
        response.setContentType(getContentType(file));
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            response.setContentLength((int) file.length());

            // Use Buffered Stream for reading/writing.
            bis = new BufferedInputStream(new FileInputStream(file));
            bos = new BufferedOutputStream(response.getOutputStream());

            byte[] buff = new byte[(int) file.length()];
            int bytesRead;

            // Simple read/write loop.
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        } catch (Exception e) {

            throw new RuntimeException(e);
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    // To late to do anything about it now, we may have already sent some data to user.
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    // To late to do anything about it now, we may have already sent some data to user.
                }
            }
        } 
    }

    private String getContentType(File file) {
        if(file.getName().length() > 0) {
            String[] parts = file.getName().split("\\.");
            if(parts.length > 0) {
                // only last part interests me
                String extention = parts[parts.length - 1];
                if(extention.equalsIgnoreCase("jpg")) {
                    return "image/jpg";
                } else if(extention.equalsIgnoreCase("gif")) {
                    return "image/gif"; 
                } else if(extention.equalsIgnoreCase("png")) {
                    return "image/png";
                }
            }
        }
        throw new RuntimeException("Can not find content type for the file " +  file.getAbsolutePath());
    }

    private String trimToEmpty(String pathInfo) {
        if(pathInfo == null) {
            return "";
        } else {
            return pathInfo.trim();
        }
    }

    private void httpError(int statusCode, HttpServletResponse response) {
        try {
            response.setStatus(statusCode);
            response.setContentType("text/html");
            PrintWriter writer = response.getWriter();
            writer.append("<html><body><h1>Error Code: " + statusCode + "</h1><body></html>");
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private boolean isXSSAttack(String path) {
        boolean xss = false;
        // Split on the bases of know file separator
        String[] parts = path.split("/|\\\\");

        // Now verify that no part contains anything harmful
        for(String part : parts) {
            // No double dots .. 
            // No colons :
            // No semicolons ;
            if(part.trim().contains("..") || part.trim().contains(":") || part.trim().contains(";")) {
                // Fire in the hole!
                xss = true;
                break;
            }
        }
        return xss;
    }

    /**
     * @see HttpServlet#doPost(Ht/promotions/some.jpgtpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

好的這是我快速寫的一個可以流式傳輸圖像的Servlet:

以下是限制列表和已知問題:

  • 可能會小心使用XSS漏洞
  • 不准備生產作為參考
  • 圖像需要在Web應用程序目錄中。 可以輕松改變,但我太懶了(不值得,項目太小)
  • 只流jpg,gif或png文件。

用法:

假設您將名為images的此Web應用程序部署為單獨的應用程序。

http://www.example.com/images/promotions/promo.jpg

意味着在此圖像Web應用程序中,“促銷”中應該有一個帶有圖像“promo.jpg”的目錄。

PS:不要問為什么我這樣做的Servlet Container只能解決大量時間問題。

  <servlet>
    <description></description>
    <display-name>ImageDisplayServlet</display-name>
    <servlet-name>ImageDisplayServlet</servlet-name>
    <servlet-class>com.example.images.ImageDisplayServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ImageDisplayServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

哦,你可以像上面一樣配置你的Servlet以獲得最佳效果:P

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM