jfinal 臨時文件下載(用戶下載完成後刪除服務器的文件)

本人在使用jfinal作一個項目的時候,須要下載一些臨時文件,就是有程序產生,而且被用戶下載後就失效的小文件,在使用jfinal的renderFile(file);後,調用 file.delete();發現,文件沒法下載,因而找問題java

查看jfinal controller的renderFile源碼後發現,調用render系列方法後,並無立刻執行render操做,代碼以下:app

/**
 * Render with file
 */
public void renderFile(String fileName) {
	render = renderFactory.getFileRender(fileName);
}

/**
 * Render with file
 */
public void renderFile(File file) {
	render = renderFactory.getFileRender(file);
}

因而可知,renderFile只不過是產生了一個render對象而已,這樣就能解釋了,由於調用renderFile後咱們把文件刪除了,因而就沒法下載了,因而繼續找,而後找到調用這個方法的地方,發現是在一個叫作ActionHandler的了類裏面,找到這個類的handler方法,關鍵部位代碼以下:ide

Controller controller = action.getControllerClass().newInstance();
controller.init(request, response, urlPara[0]);

if (devMode) {
	boolean isMultipartRequest = ActionReporter.reportCommonRequest(controller, action);
	new ActionInvocation(action, controller).invoke();
	if (isMultipartRequest) ActionReporter.reportMultipartRequest(controller, action);
} else {
	new ActionInvocation(action, controller).invoke();
}

Render render = controller.getRender();
if (render instanceof ActionRender) {
	String actionUrl = ((ActionRender)render).getActionUrl();
	if (target.equals(actionUrl))
		throw new RuntimeException("The forward action url is the same as before.");
	else
		handle(actionUrl, request, response, isHandled);
	return ;
}

if (render == null)
	render = renderFactory.getDefaultRender(action.getViewPath() + action.getMethodName());
  
render.setContext(request, response, action.getViewPath()).render();

咱們發如今 new ActionInvocation(action, controller).invoke();後纔去執行的render方法,render.setContext(request, response, action.getViewPath()).render();this

問題已經找到了,因而咱們須要解決,剛開始問羣裏的時候,你們都是建議使用定時刪除,隊列的方式來執行,我我的不喜歡這種繞圈子的作法,因而有了方案1url

方案1

本身寫代碼去renderFile,這樣就能夠避免這個問題了,代碼大體以下(基本上是從FileRender類中拷貝而來):設計

String contentType = getRequest().getServletContext().getMimeType(file.getName());
if (contentType == null) {
    contentType = "application/octet-stream";		// "application/octet-stream";
}


System.out.println(contentType);

getResponse().setContentType(contentType);
getResponse().setContentLength((int) file.length());
OutputStream out = getResponse().getOutputStream();
FileInputStream in = new FileInputStream(file);

try {
    byte[] buf= new byte[1024];

    for(int n;(n = in.read(buf)) != -1;) {
        out.write(buf,0,n);
    }

} finally {
    try {
        in.close();
        out.close();
    } finally {
        file.delete();
        file.deleteOnExit();
    }
}

這種代碼解決了問題,可是仍是不夠好,我相信大部分人也不喜歡這種方式,雖然能夠封裝一個方法去作這個事情.後來用了一種更好的方式來解決這個問題,並且比較符合jfinal的設計哲學code

方案2

自定義render對象

因爲jfinal已經有了FileRender,咱們能夠直接繼承它,咱們重寫 render方法就行了,這種方法作到了代碼重用,我的很喜歡,代碼以下:繼承

public class TempFileRender extends FileRender {
  private String fileName;
  private File file;
  public TempFileRender(String fileName) {
      super(fileName);
      this.fileName = fileName;
  }

  public TempFileRender(File file) {
      super(file);
      this.file = file;
  }

  @Override
  public void render() {
      try {
          super.render();
      } finally {

          if(null != fileName) {
              file = new File(fileName);
          }

          if(null != file) {
              file.delete();
              file.deleteOnExit();
          }
      }
  }
}

這樣在controller中使用就只須要 render(new TempFileRender(file|fileName))隊列

打完收工

相關文章
相關標籤/搜索