[英]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“)。只需將源復制到目標。
實際上,您最終會在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:
以下是限制列表和已知問題:
用法:
假設您將名為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.