Java/JSP 이미지 업로드. 이 이미지 파일을 어디에서 보관해야합니까?

StackOverflow https://stackoverflow.com/questions/385332

  •  23-08-2019
  •  | 
  •  

문제

사용자가 이미지를 업로드 할 수있는 간단한 응용 프로그램을 작성하고 있습니다. 업로드 후 사용자는 태그를 붙이거나 제거 할 수 있습니다.

파일을 업로드하고 파일을 업로드하면 저장하는 방법을 알아 냈습니다. 이미지가 유지되는 글로벌 경로를 추적하고 있습니다. 데이터베이스에서 파일 이름, 태그 등과 같은 이미지에 대한 메타 데이터를 유지합니다.

Java/JSP를 사용하고 있습니다 (특히 Stripes 프레임 워크이지만 내 문제는 일반적입니다).

내 질문은이 이미지 파일이 업로드되면 어디에 보관해야합니까?

지금은 Tomcat 서버에 두 개의 웹 응용 프로그램이 배포되었습니다. 하나의 주요 웹 응용 프로그램과 다른 하나는 이미지를 업로드하는 곳입니다.

그러나 Tomcat을 재배치/다시 시작할 때까지 기본 응용 프로그램에서 업로드 된 이미지를 볼 수 없으므로 이것은 작동하지 않습니다.

Tomcat이 새로 업로드 된 이미지를 자동으로 선택하지 않은 것 같습니다.

누구든지 해결책이 있습니까?

이것은 간단한 프로젝트이므로 데이터베이스에 저장하거나 이미지에 Apache를 사용하고 싶지 않습니다. 이 작은 프로젝트에는 너무 복잡합니다.

감사.

도움이 되었습니까?

해결책

이미지를 데이터베이스에 저장하지는 않지만 이미지 경로를 데이터베이스에 저장하려고합니다. 이렇게하면 어디서나 이미지를 저장할 수 있습니다.

두 개의 Tomcat 응용 프로그램을 사용하고 있으므로 Tomcat이 파일을 관리하는 대신 이미지를 앱 외부에 저장하고 이미지를 사용자에게 다시 스트리밍하는 것이 가장 좋습니다. 그렇지 않으면 두 개의 웹 앱 으로이 작업을 수행하려는 이유를 묻습니다.

다른 팁

그러나 Web-App 디렉토리 안에 업로드 된 이미지를 저장하는 것은 현명한 일이 아니므로 알고 있습니다.

그건 그렇고, 당신은 이것을보고 싶을 것입니다 stackoverflow 스레드, 최근 이미지를 저장할 위치에 대해 논의했습니다. 그것은 당신의 문제를 해결하지 못할 수도 있습니다. 반드시 당신이하고있는 일에 대해 더 많은 자신감을 줄 것입니다.

나는 이것을 다른 방식으로 해결했습니다.

첫째, 포트가 불가능한 방법은 Glassfish (그리고 Tomcat도 믿는다)를 사용하면 외부 디렉토리를 WebApps 계층에 매핑 할 수 있다는 것입니다. 이것은 정말 잘 작동하고 원하는 것을 정확하게 수행합니다. 이미지를 WebApp에서 멀리 떨어진 외부 디렉토리에 저장할 수 있지만 여전히 서비스를 제공 할 수 있습니다.

그러나이 기술은 휴대용이 아닙니다.

내가 그것을 완료 할 수있는 방법은 필터를 만드는 것입니다.

"/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의 실제 이미지로 전달하십시오.

효과적으로 WebApps 배포 트리 내에 파일 캐시가 있습니다. 아래쪽은 캐시라는 것이므로 유지 관리해야합니다 (즉, 원본이 캐시보다 새롭고 소스가 삭제 된 경우 삭제해야합니다. 또한 리소스를 복제하므로 이미지는 결국 두 배의 디스크 공간을 소비합니다. 마지막으로, 시작시 초기 사본 비용이 있습니다.

그러나 효과가 있으며 자신의 코드를 사용하여 정적 자원을 제공하지 않아도됩니다. (세 번째 솔루션 인 경우 필터/서블릿을 매핑하여 URL을 가로 채고 간단히 스트리밍하십시오.)

나는 당신을 위해 매핑을하기 위해 Tomcat 내의 구조를 살펴 봅니다 (존재한다고 가정). 나는 그것이 Glassfish에 존재한다는 것을 알고 있습니다. (Google은 Glassfish가 작동하는 방법을 보려면 Google AlternateCroot입니다.)

새로운 메인 애플리케이션 전쟁 파일을 재배치 할 경우 업로드 된 이미지를 과도하게 작성하지 않기 위해 두 개의 웹 응용 프로그램을 사용하고있었습니다.

그러나 당신이 언급했듯이 다른 옵션은 없지만 서블릿이나 무언가를 통해 스트리밍하는 것은 Tomcat 디렉토리 외부에 보관할 수 있다고 생각합니다.

이 스트리밍 서블릿을 쓰지 않기를 원했습니다. 스트리밍 서블릿을 작성하는 동안 모든 혼란 (적절한 콘텐츠 유형, 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);
    }
}

좋아 여기 이미지를 스트리밍 할 수있는 신속하게 쓴 서블릿이 있습니다.

다음은 제한 사항 목록과 알고있는 문제입니다.

  • 주의해서 XSS 취약성이 사용될 수 있습니다
  • 생산 준비가되지 않음 참조로 사용됩니다
  • 웹 애플리케이션 디렉토리에 이미지가 필요합니다. 쉽게 바꿀 수 있지만 나도 게으르다 (프로젝트가 너무 작아서 가치가 없습니다)
  • JPG, GIF 또는 PNG 파일 만 스트리밍합니다.

용법:

이미지라는이 웹 응용 프로그램을 별도의 응용 프로그램으로 배포한다고 가정 해 보겠습니다.

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

이 이미지 웹 애플리케이션에서 "promo.jpg"가있는 "프로모션"에 디렉토리가 있어야한다는 것을 의미합니다.

추신 : 내가 왜이 서블릿 컨테이너 전용 솔루션을하고 있는지 묻지 마십시오.

  <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>

Oh ya 최상의 결과를 위해 위와 같이 서블릿을 구성합니다 : P

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top