重写java.io.FileOutputStream方法

重写java.io.FileOutputStream方法,java,servlet-filters,Java,Servlet Filters,我不确定这样问是否正确,但我会尽力解释我的情况和我需要什么 我有一个很大的java项目,可以上传很多不同java类中的文件,就像太多了一样,我有大约7个不同的主文件夹来上传文件。目前的文件保存在webapp上下文中,我需要将它们保存在上下文之外 如果只有少数几个类可以上传这些文件,我可以花几天的时间修改每个类,并将其引导到一个与上下文无关的路径,但是类太多了,所以我必须找到一种方法,在不修改每个类或任何类的情况下完成,这将是理想的 每次上传都以以下方式完成: 我得到一个主文件夹的实际路径: St

我不确定这样问是否正确,但我会尽力解释我的情况和我需要什么

我有一个很大的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/


这可能吗?如果没有,那么实现这一点的最佳方法是什么?

我会重构并使用Decorator或Wrapper模式。更多信息

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

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
,并在“新建文件”事件中将其复制到适当的目录。下面介绍如何监视目录

下面是一个小代码,不是很完美,但它的思想是存在的

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");
    }

}
公共类FileMonitorServletContextListener实现
ServletContextListener{
公共接口文件监视器{
void start(字符串fromFolder,字符串toFolder);
无效停止();
}
公共类SimpleThreadedWatcher实现FileMonitor{
私有类SimpleThread扩展线程{
私有布尔运行=真;
文件夹中的私有字符串;
私人串托福;
公共SimpleThread(字符串fromFolder,字符串toFolder){
this.fromFolder=fromFolder;
this.toFolder=toFolder;
}
私有无效副本(路径子项、字符串到文件夹){
//将文件复制到文件夹中
}
@凌驾
公开募捐{
试一试{
WatchService watcher=FileSystems.getDefault()
.newWatchService();
Path fromPath=Path.get(fromFolder);
watcher=FileSystems.getDefault().newWatchService();
WatchKey key=fromPath.register(watcher,
StandardWatchEventTypes.ENTRY(创建);
(跑步时){
for(WatchEvent事件:key.pollEvents()){
//目录条目事件的上下文是文件
//姓名
//入口
@抑制警告(“未选中”)
WatchEvent ev=(WatchEvent)事件;
路径名=ev.context();
Path child=fromPath.resolve(名称);
//打印输出事件
System.out.format(“%s:%s\n”,event.kind().name(),
儿童);
复印件(儿童、托福);
布尔有效值=key.reset();
如果(!有效){
打破
}
}
睡眠(1000);
}
}捕获(例外e){
抛出新的运行时异常(“错误:”,e);
}
}
公共空间停止工作(){
运行=错误;
}
}
私人单工;
@凌驾
public void start(String fromFolder,String toFolder){
worker=newsimplethread(fromFolder,toFolder);
worker.start();
}
@凌驾
公共停车场(){
工人。停止工作();
}
}
FileMonitor FileMonitor=新的SimpleThreadedWatcher();
@凌驾
公共无效上下文已销毁(ServletContextEvent arg0){
fileMonitor.stop();
}
@凌驾
公共void contextInitialized(ServletContextEvent arg0){
fileMonitor.start(“从”、“到”);
}
}

将“保存”部分提取到一个专用的方法中,然后重构它来做你想做的事情怎么样?嘿,你的想法正是我想要的,我不介意重构它,但你会怎么做?搜索并替换每个“import java.io.OutputStream;”?或者你的方法是什么?老实说,我会把这段代码包装成一个实用程序类或其他东西,然后我会重写上传以使用新的实用程序类。那么下次你需要改变上传行为的时候,嘿,只需要改变这个实用程序类我还添加了一个小代码来监视一个文件夹,你可能想先试试吗?大文件可能会有问题,创建事件在文件完全写入磁盘之前就被调度了