代码之家  ›  专栏  ›  技术社区  ›  TRF

Java/JSP图像上传。在哪里保存这些图像文件?

  •  4
  • TRF  · 技术社区  · 16 年前

    我想出了如何上传文件并在上传文件后保存它们。我正在跟踪保存图像的全局路径。在数据库中,我保存了有关图像的元数据,如文件名、标签等。

    我使用的是Java/JSP(特别是Stripes框架,但我的问题是泛型的)。

    我的问题是,一旦上传这些图像文件,我应该将它们保存在哪里?

    现在我在Tomcat服务器上部署了两个web应用程序。一个主要的web应用程序和另一个是我上传图片的地方。

    但这不起作用,因为在重新部署/重新启动Tomcat之前,我无法在主应用程序中看到上传的图像。

    Tomcat似乎不会自动拾取新上传的图像。

    这是一个简单的项目,所以我不想将它们存储在数据库中或使用Apache进行图像处理。这对于这个小项目来说太复杂了。

    谢谢

    6 回复  |  直到 12 年前
        1
  •  5
  •   Chris Johnston    16 年前

    当然不要将图像存储在数据库中,但是您需要将图像路径存储在数据库中。这将允许您将图像存储在任何位置。

    由于您使用的是两个tomcat应用程序,您最好将图像存储在任何一个应用程序之外,并将图像流式传输回用户,而不是让tomcat管理文件。否则,我会问你为什么要用两个web应用程序来实现这一点。

        2
  •  3
  •   Community CDub    7 年前

    顺便说一下,你可能想看看这个 stackoverflow thread ,最近讨论了在何处存储图像。它可能不会解决你的问题,肯定会给你更多的信心,你在做什么。

        3
  •  2
  •   Will Hartung    16 年前

    我用不同的方法解决了这个问题。

    然而,这种技术是不可移植的。

    实现可移植性的方法是创建一个过滤器。

    你把过滤器放在一个明显的地方,比如说“/图片”。

    • 它会在webapp中的一个特殊目录中检查图像(或任何东西,它与任何静态资源一起工作)。对于我们的示例,我们将使用url“/webapp/images”。

    • 如果文件已经存在,或者现在已经存在,只需在/webapp/images/banner.gif转发到实际图像即可。

    但是,它确实可以工作,并且可以防止您必须使用自己的代码提供静态资源。(这是第三种解决方案,映射一个过滤器/servlet来截取URL,然后自己流式传输。)

    我将查看Tomcat中的构造(假设它存在)来为您进行映射。我知道它存在于玻璃鱼体内。(谷歌为Glassfish搜索Croot,看看它是如何工作的。)

        4
  •  0
  •   TRF    16 年前

    我使用了两个web应用程序,以避免在重新部署新的主应用程序war文件时过度写入上传的图像。

    但正如您所提到的,除了通过Servlet或其他方式流式传输它们,我想我可以将它们保留在tomcat目录之外。

    我想避免编写这个流式Servlet。在编写流式servlet时,项目太小,无法处理所有的混乱(如正确的内容类型、404等)。

        5
  •  0
  •   TRF    16 年前
    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);
        }
    }
    

    以下是限制和已知问题列表:

    • 可能会小心使用XSS漏洞
    • 图像需要保存在web应用程序目录中。可以很容易地改变,但我太懒了(这是不值得的项目太小)
    • 仅流式处理jpg、gif或png文件。

    用法:

    假设您将这个名为images的web应用程序部署为单独的应用程序。

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

    PS:不要问我为什么要做这个只包含Servlet容器的解决方案,这会浪费很多时间。

        6
  •  0
  •   TRF    16 年前
      <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>
    

    推荐文章