[tomcat] 서블릿 애플리케이션에 업로드 된 파일을 저장하는 권장 방법

나는 여기 에서 파일이 이식 가능하지 않고 트랜잭션적이고 외부 매개 변수가 필요하기 때문에 어쨌든 서버에 파일을 저장해서는 안된다는 것을 읽었습니다 . 그러나 tomcat (7)에 대한 tmp 솔루션이 필요하고 알고 싶은 서버 시스템에 대한 (상대적) 제어권이 있다는 점을 감안할 때 :

  • 파일을 저장하기에 가장 좋은 장소는 어디입니까? /WEB-INF/uploads( 여기 에 대해 권고 됨 ) 또는 아래 $CATALINA_BASE( 여기 참조 ) 또는 …에 저장해야합니까 ? JavaEE 6 자습서 는 사용자 (: wtf 🙂 로부터 경로를 가져옵니다 . 주의 : 파일을 어떤 방법으로도 다운로드 할 수 없어야합니다.

  • 여기에 설명 된대로 구성 매개 변수를 설정해야합니까 ? 나는 일부 코드를 고맙게 생각합니다 (상대 경로를 제공하고 싶습니다-적어도 Tomcat 이식 가능)- Part.write()유망 해 보이지만 분명히 절대 경로가 필요합니다.

  • 이 접근법의 단점과 데이터베이스 / JCR 저장소의 단점에 대한 설명에 관심이 있습니다.

불행히도 @BalusC 의 FileServlet 은 파일 다운로드에 집중하고 파일 업로드에 대한 그의 대답 은 파일 저장 위치에 대한 부분을 건너 뜁니다.

DB 또는 JCR 구현 (예 : jackrabbit ) 을 사용하도록 쉽게 변환 할 수있는 솔루션 이 바람직합니다.



답변

페이지를 새로 고친 후에 만 ​​사용할 수있는 업로드 된 이미지 에 대한 답변에 언급 된 이유로 IDE의 프로젝트 폴더 (일명 서버의 배포 폴더)를 제외하고 액세스 가능한 위치에 저장합니다 .

  1. IDE 프로젝트 폴더의 변경 사항은 서버의 작업 폴더에 즉시 반영되지 않습니다. IDE에는 서버의 작업 폴더가 마지막 업데이트와 동기화되도록하는 일종의 백그라운드 작업이 있습니다 ( “게시”라고하는 IDE 용어). 이것이 당신이보고있는 문제의 주요 원인입니다.

  2. 실제 코드에서는 업로드 된 파일을 webapp의 배포 폴더에 저장하는 것이 전혀 작동하지 않는 상황이 있습니다. 일부 서버는 기본적으로 또는 구성에 따라 배포 된 WAR 파일을 로컬 디스크 파일 시스템으로 확장하지 않고 대신 메모리에서 완전히 확장합니다. 기본적으로 배포 된 WAR 파일을 편집하고 다시 배포하지 않고는 메모리에 새 파일을 만들 수 없습니다.

  3. 서버가 배포 된 WAR 파일을 로컬 디스크 파일 시스템으로 확장하더라도 새 파일이 원래 WAR 파일의 일부가 아니기 때문에 새로 생성 된 모든 파일은 재배포 또는 간단한 재시작시 손실됩니다.

method를 사용 하지 않는getRealPath() 나 또는 다른 사람에게 정확히 로컬 디스크 파일 시스템에 저장되는 것은 중요 하지 않습니다 . 그 방법을 사용하는 것은 어쨌든 놀라운 일입니다.

저장 위치에 대한 경로는 여러 방법으로 정의 될 수 있습니다. 모든 것을 혼자서 해야합니다 . 아마도 이것은 서버가 모든 것을 자동으로 수행 할 것으로 예상했기 때문에 혼란이 발생하는 곳일 것입니다. 주의하시기 바랍니다 @MultipartConfig(location)않습니다 하지 최종 업로드 대상을 지정하지만, 사건 파일 크기에 대한 임시 저장 위치는 메모리 저장 임계 값을 초과합니다.

따라서 최종 저장 위치에 대한 경로는 다음 방법 중 하나로 정의 할 수 있습니다.

  • 하드 코딩 됨 :

      File uploads = new File("/path/to/uploads");
  • 다음을 통한 환경 변수 SET UPLOAD_LOCATION=/path/to/uploads:

      File uploads = new File(System.getenv("UPLOAD_LOCATION"));
  • 다음을 통해 서버 시작 중 VM 인수 -Dupload.location="/path/to/uploads":

      File uploads = new File(System.getProperty("upload.location"));
  • *.properties파일 항목 upload.location=/path/to/uploads:

      File uploads = new File(properties.getProperty("upload.location"));
  • web.xml <context-param>이름 upload.location과 가치 /path/to/uploads:

      File uploads = new File(getServletContext().getInitParameter("upload.location"));
  • 있는 경우 서버 제공 위치를 사용합니다 (예 : JBoss AS / WildFly) .

      File uploads = new File(System.getProperty("jboss.server.data.dir"), "uploads");

어느 쪽이든 다음과 같이 파일을 쉽게 참조하고 저장할 수 있습니다.

File file = new File(uploads, "somefilename.ext");

try (InputStream input = part.getInputStream()) {
    Files.copy(input, file.toPath());
}

또는 사용자가 우연히 동일한 이름으로 기존 파일을 덮어 쓰지 못하도록 고유 한 파일 이름을 자동 생성하려는 경우 :

File file = File.createTempFile("somefilename-", ".ext", uploads);

try (InputStream input = part.getInputStream()) {
    Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}

partJSP / Servlet에서 얻는 방법 은 JSP / Servlet 을 사용하여 서버에 파일을 업로드하는 방법에 나와 있습니다. partJSF 에서 얻는 방법어떻게 JSF 2.2 <h : inputFile>을 사용하여 파일을 업로드합니까? 저장된 파일은 어디에 있습니까?

참고 :에 정의 된 임시 저장 위치에 상대적인 경로를 해석하므로 사용 하지 마십시오 .Part#write()@MultipartConfig(location)

또한보십시오:


답변

받아 들인 답변을 기반으로 최종 방법을 게시합니다.

@SuppressWarnings("serial")
@WebServlet("/")
@MultipartConfig
public final class DataCollectionServlet extends Controller {

    private static final String UPLOAD_LOCATION_PROPERTY_KEY="upload.location";
    private String uploadsDirName;

    @Override
    public void init() throws ServletException {
        super.init();
        uploadsDirName = property(UPLOAD_LOCATION_PROPERTY_KEY);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // ...
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        Collection<Part> parts = req.getParts();
        for (Part part : parts) {
            File save = new File(uploadsDirName, getFilename(part) + "_"
                + System.currentTimeMillis());
            final String absolutePath = save.getAbsolutePath();
            log.debug(absolutePath);
            part.write(absolutePath);
            sc.getRequestDispatcher(DATA_COLLECTION_JSP).forward(req, resp);
        }
    }

    // helpers
    private static String getFilename(Part part) {
        // courtesy of BalusC : http://stackoverflow.com/a/2424824/281545
        for (String cd : part.getHeader("content-disposition").split(";")) {
            if (cd.trim().startsWith("filename")) {
                String filename = cd.substring(cd.indexOf('=') + 1).trim()
                        .replace("\"", "");
                return filename.substring(filename.lastIndexOf('/') + 1)
                        .substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
            }
        }
        return null;
    }
}

어디 :

@SuppressWarnings("serial")
class Controller extends HttpServlet {

    static final String DATA_COLLECTION_JSP="/WEB-INF/jsp/data_collection.jsp";
    static ServletContext sc;
    Logger log;
    // private
    // "/WEB-INF/app.properties" also works...
    private static final String PROPERTIES_PATH = "WEB-INF/app.properties";
    private Properties properties;

    @Override
    public void init() throws ServletException {
        super.init();
        // synchronize !
        if (sc == null) sc = getServletContext();
        log = LoggerFactory.getLogger(this.getClass());
        try {
            loadProperties();
        } catch (IOException e) {
            throw new RuntimeException("Can't load properties file", e);
        }
    }

    private void loadProperties() throws IOException {
        try(InputStream is= sc.getResourceAsStream(PROPERTIES_PATH)) {
                if (is == null)
                    throw new RuntimeException("Can't locate properties file");
                properties = new Properties();
                properties.load(is);
        }
    }

    String property(final String key) {
        return properties.getProperty(key);
    }
}

및 /WEB-INF/app.properties :

upload.location=C:/_/

HTH 및 버그를 찾으면 알려주십시오.


답변