如何像SpringMVC一样访问磁盘静态资源

       目前在做基于Layui fly社区的项目epochFly,后台采用Jfinal来做。做好之后应该会开源出来,同时也会正式开放我的个人网站。因为前台静态资源较多,所以要考虑到如何访问到上传的磁盘资源 ,多方搜索,参考到了波总的一个回复。再次在总结一下给各位同学。

  1. 配置好上传目录,为 C:/epochFly,上传的所有文件都在这

    me.setBaseUploadPath(PropKit.get("config.upload.basePath", "upload"));

    默认路径为upload。

    配置一个hander

    如下:

  2. import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.jfinal.handler.Handler;
    
    public class FileHandler extends Handler {
    
    	@Override
    	public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
    		if (target.startsWith("/static/file")) {
    			String view = target.substring(target.lastIndexOf("/"));
    			request.setAttribute("view", view);
    			target = "/static/file";
    		}
    		next.handle(target, request, response, isHandled);
    	}
    
    }

需要在 config注册,

me.add(new FileHandler());

该类说明了,所有的静态资源访问请求是/static/file 请求,比如/static/file/aa.jpg

会自动拦截过滤到/static/file请求并携带参数view为aa.jpg

4.controller的配置如下

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.OutputStream;

import com.epoch.base.annotation.ControllerBind;
import com.epoch.base.controller.BaseController;
import com.jfinal.kit.PropKit;

@ControllerBind(controllerKey = "/static")
public class StaticResourceController extends BaseController{
	
	public void file() {
		String view = getAttr("view").toString();
		getResponse().setContentType("application/octet-stream;charset=UTF-8");
		try {
			FileInputStream inputStream = new FileInputStream(PropKit.get("config.upload.basePath", "upload")+view);
			int i=inputStream.available();
			byte[]data=new byte[i];
			inputStream.read(data);
			inputStream.close();

			OutputStream outputStream=new BufferedOutputStream(getResponse().getOutputStream());
			outputStream.write(data);
			outputStream.flush();
			outputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

如上,请求与handler请求对应,其中获取到view中,与上传文件的路径做匹配对应,

PropKit.get("config.upload.basePath", "upload")

该方法是获取到配置的静态资源上传目录为C:/epochFly

此时在代码中,只需要通过  项目名称/static/file/******文件

即可放到到磁盘对应的文件

评论区

JFinal

2018-07-09 11:09

博主的方案非常简单,代码也很省,在 outputStream.close() 后面应该要加上一句 renderNull()

这里有个改进建议,可以将 StaticResourceController 中的代码全部转移到 FileHandler 中,request、response 对象都在里面可以直接用,最后别忘了在 if 中加两行代码:
isHandled[0] = true;
return;
加这两行一是避免 tomcat、jetty 容器处理这个请求,二是辟免执行后面的 next.handle(...)

此外,建议在 finally 块中关闭 outputStream、inputStream

最后,再建议创建一个比较小的 byte[] buffer(例如 new byte[512]),一边从 inputStream 中读,一边往 outputStream 里面写,这样就避免了每次 new 出很大的 buffer,可提升性能

在 for 循环中判断读取的 len 是不是 -1,来代替 inputStream.available();

大致结构如下:
byte[] buf = new byte[512];
int len=-1;
while((len=inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}

JFinal

2018-07-09 11:10

最后别忘了搞定后,回来在本分享中追加上改进后的代码

JFinal

2018-07-09 11:12

再补充一下,如果再要做得细致一些,可以针对不同的响应数据,设置不同的 context type,具体的设置值可以参考一下 jfinal 源码中的 com.jfinal.render.ContextType 中的字符串常量

张胖胖

2018-07-09 11:12

年轻人

2018-07-09 16:13

很好奇为什么不直接设置好constants.setBaseDownloadPath();然后直接在action中直接renderFile();而是要自己写input流进行返回。 @JFinal @张胖胖

谷子

2018-07-09 17:36

@年轻人 查看源码,发现和renderFile实现代码是一样的。

欲风217

2018-07-10 15:09

@年轻人 从你的回复了解到 constants.setBaseDownloadPath(); 用法,感谢

dadu

2018-07-11 11:50

@张胖胖 预计几月份能搞完呀

张胖胖

2018-07-13 22:56

@dadu 至少1个月-2个月以上吧

千天涯

2018-07-28 10:36

根据波总意见改造,Constant.STATIC_FILE_PREFIX即是"/static/file"
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.jfinal.handler.Handler;
import com.lyw.base.config.Constant;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
* author: Andersen
* mail:
* Date: 2018/7/27 17:24
*/
public class FileHandler extends Handler {

@Override
public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
if (target.startsWith(Constant.STATIC_FILE_PREFIX)) {
String view = target.substring(Constant.STATIC_FILE_PREFIX.length());
response.setContentType("application/octet-stream;charset=UTF-8");
FileInputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new FileInputStream(Constant.UPLOAD_DEFAULT_PATH + view);
outputStream=new BufferedOutputStream(response.getOutputStream());
byte[] buf = new byte[512];
int len=-1;
while((len=inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}
inputStream.close();
outputStream.flush();
outputStream.close();
isHandled[0] = true;
return;
} catch (Exception e) {
e.printStackTrace();
} finally {
if(null != inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null != outputStream){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
next.handle(target, request, response, isHandled);
}

}

张胖胖

2018-07-30 21:10

@千天涯 牛牛。。我有了一个新的改造方法。已经成功应用。考虑到需要图片等大量存储访问,对服务器带宽有影响。因此我决定最后采用了阿里云的OSS存储,也就是说上传上来的我会进一步转到OSS存储。这样就不牵扯路径问题了

张胖胖

2018-07-30 21:11

@dadu 已经搞了70%以上了,如果有需要可以找我,授权便宜

dadu

2018-08-02 17:17

@张胖胖 qq:339188534 聊一下啊

热门分享

扫码入社