本人在使用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
本身寫代碼去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
自定義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))
了隊列
打完收工