覆盖java.io.FileOutputStream方法

时间:2015-04-16 18:34:54

标签: java servlet-filters

我不确定这是否是正确的方式,但我会尝试解释我的情况和我需要的东西。

我有一个很棒的java项目,它在许多不同的java类中上传文件,比如太多了,我有大约7个不同的主文件夹来上传文件。此时的文件保存在webapp上下文中,我需要将它们保存在上下文之外。

如果只有几个类上传这些文件,我可以花几天时间更改每个类并将其指向上下文的路径,但是有太多的类,所以我必须想办法在不改变每个课程或任何课程的情况下这样做是理想的。

每次上传都按以下方式完成:

我得到了一个主要文件夹的真实路径:

String realpath = httpServletRequest.getSession()
                                    .getServletContext()
                                    .getRealPath("/mainfolder1/mainsubfolder1/");

然后我获取文件并设置自定义文件名:

FormFile file = myForm.getFile();
String contentType = file.getContentType();
String fileName  = file.getFileName();
int fileSize     = file.getFileSize();
customFileName = "anyName" + fileName.substring(fileName.lastIndexOf("."));

然后我验证并保存文件:

if (fileSize > 0 && contentType != null && fileName.length() > 0){
    InputStream in = file.getInputStream();
    OutputStream bos = new FileOutputStream(realpath + "/" + customFileName);

    int byteRead = 0;
    byte[] buffer = new byte[8192];
    while ((byteRead = in.read(buffer, 0, 8192)) != -1){
      bos.write(buffer, 0, byteRead);
    }
    bos.close();
    in.close();
}

保存文件的简单方法,如您所见,它们保存在上下文中。

因此,如果我能以某种方式覆盖java.io.FileOutputStream,不仅要将其保存在上下文中,而且要在上下文之外复制,那就太好了,比如将它保存在指定的路径中以及其他一些路径上超出背景的道路。

但我不知道这是否可行,或者如何重现这种行为。

我需要的是保持类代码的完整性,但是要写两次文件:

  

首先:“/insideContext/mainfolder1/mainsubfolder1/

     

然后:“/outsideContext/mainfolder1/mainsubfolder1/

这可能吗?如果没有,那么最好的方法是什么?

1 个答案:

答案 0 :(得分:2)

我重构并使用Decorator或Wrapper模式。关于它的更多信息here

下面你可以使用一些简单的想法。

public class ContextAwareDuplicatorOutputStream extends OutputStream {

FileOutputStream insideContext;
FileOutputStream outsideContext;

public ContextAwareDuplicatorOutputStream(String insideContextPath,
        String outsideContextPath, String fileName)
        throws FileNotFoundException {
    insideContext = new FileOutputStream(insideContextPath
            + File.pathSeparator + fileName);
    outsideContext = new FileOutputStream(outsideContextPath
            + File.pathSeparator + fileName);
}

@Override
public void close() throws IOException {
    insideContext.close();
    outsideContext.close();
}

@Override
public void flush() throws IOException {
    insideContext.flush();
    outsideContext.flush();
}

@Override
public void write(byte[] b) throws IOException {
    insideContext.write(b);
    outsideContext.write(b);
}

@Override
public void write(byte[] b, int off, int len) throws IOException {
    insideContext.write(b, off, len);
    outsideContext.write(b, off, len);
}

@Override
public void write(int b) throws IOException {
    insideContext.write(b);
    outsideContext.write(b);
}

}

由于您不想编辑代码中的任何内容,因此请创建一个ServletContextListener来监控您上传的文件夹,并在新文件事件中将其复制到正确的目录中。这是如何监视目录的awnsered。 Directory listener in Java

下面是一个小代码,不是很完美,但想法是

public class FileMonitorServletContextListener implements
        ServletContextListener {

    public interface FileMonitor {

        void start(String fromFolder, String toFolder);

        void stop();

    }

    public class SimpleThreadedWatcher implements FileMonitor {

        private class SimpleThread extends Thread {

            private boolean running = true;
            private String fromFolder;
            private String toFolder;

            public SimpleThread(String fromFolder, String toFolder) {
                this.fromFolder = fromFolder;
                this.toFolder = toFolder;
            }

            private void copy(Path child, String toFolder) {
                // Copy the file to the folder
            }

            @Override
            public void run() {
                try {
                    WatchService watcher = FileSystems.getDefault()
                            .newWatchService();
                    Path fromPath = Paths.get(fromFolder);
                    watcher = FileSystems.getDefault().newWatchService();

                    WatchKey key = fromPath.register(watcher,
                            StandardWatchEventKinds.ENTRY_CREATE);

                    while (running) {

                        for (WatchEvent<?> event : key.pollEvents()) {
                            // Context for directory entry event is the file
                            // name of
                            // entry
                            @SuppressWarnings("unchecked")
                            WatchEvent<Path> ev = (WatchEvent<Path>) event;

                            Path name = ev.context();
                            Path child = fromPath.resolve(name);

                            // print out event
                            System.out.format("%s: %s\n", event.kind().name(),
                                    child);

                            copy(child, toFolder);

                            boolean valid = key.reset();
                            if (!valid) {
                                break;
                            }
                        }

                        Thread.sleep(1000);
                    }
                } catch (Exception e) {
                    throw new RuntimeException("Error: ", e);
                }
            }

            public void stopWorking() {
                running = false;
            }

        }

        private SimpleThread worker;

        @Override
        public void start(String fromFolder, String toFolder) {
            worker = new SimpleThread(fromFolder, toFolder);
            worker.start();
        }

        @Override
        public void stop() {
            worker.stopWorking();
        }

    }

    FileMonitor fileMonitor = new SimpleThreadedWatcher();

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        fileMonitor.stop();
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        fileMonitor.start("FROM", "TO");
    }

}