困扰几天的图片显示问题今天解决了,中间走过了许多坑,下面一点点说:
需求:一个简单的意见反馈功能,要求有图片展示,一条记录可最多上传5张图片,前端用的是安卓,后端提供service,并展示在页面。
分析:
1、与安卓前端交互的是一个service的war包,请求通过封装,只能使用json格式传数据;
2、页面展示的是在另外一个web的war包上,有一点好处是两个war包会部署在同一个服务器上;
3、本地开发使用windows+tomcat,服务器使用jboss部署在linux环境下;
4、因为考虑到图片未来的增长量,不能直接存入数据库(每张图片压缩过后200k,对数据库的压力蛮大);
5、服务器上因为权限问题,存入的文件通过web直接访问路径是无法加载的;
6、前端使用extJS,对extjs加载图片的使用不熟悉;
解决方案:
1、使用解析json格式包文,使用 List<byte[]>
直接保存多张图片的byte数组数据;
2、考虑到服务器和war包的因素,在服务器上war包部署的根目录创建文件夹,并对访问war包的用户赋予读写权限;创建的文件夹在代码里使用绝对路径访问 (/opt/attach/dlv/images )
3、解析的byte数组直接保存在第二步创建的文件夹中,重新生成文件名,数据库保留文件名记录;
4、页面访问图片时,直接以流的形式加载上一步保存的图片,然后使用输出流的方式显示在前端页面;
5、访问图片的url需要加时间戳,来保证二次访问可以正常打开;
解析代码如下:
Object dataList = map.get("fileList");
List< byte[]> byteList = JSONObject. parseArray(dataList +"", byte [].class);
页面加载代码如下:
String filePath = "/opt/attach/dlv/images/" +yearMonth +"/" +imageName ;
File filePic = new File(filePath);
if(filePic.exists()){
FileInputStream is = new FileInputStream(filePic);
int i = is.available(); // 得到文件大小
byte data[] = new byte[i];
is.read(data); // 读数据
is.close();
response.setContentType( "image/*"); // 设置返回的文件类型
OutputStream toClient;
toClient = response.getOutputStream();
toClient.write(data); // 输出数据
toClient.close();
}
前端extJS加载图片代码:
aa.onDblClick = function (fileName ) {
var win_Watch = Ext.create( 'Ext.Window', {
width: 640,
height: 800,
modal: true, //是否模态窗口,默认为false
maximizable: true,
layout: "fit", //窗口布局类型
resizable: false,
closeAction: 'hide',
plain: true,
draggable: true,
border: false,
items: [
Ext.create( 'Ext.Img', {
height: '100%',
width: '100%',
src: 'loadSuggestPic.action?imageName=' +fileName+ '&exptoken='+ encodetoke
})
]
});
win_Watch.show();
}
PS:
1、之前尝试使用 ServletActionContext.getServletContext().getRealPath(“/images/”)的方式获取路径展示,但是在本地开发的时候可以使用,在服务器上是不能使用的,因为打war包到服务器上之后,上述代码获取的路径是一个临时路径,并不是你想要的路径,大概是“webapps/tmp/vfs/temp/tempb6c09149eda39ca6/xxxxx.war-45be899d46ab6225/images” 这样格式的,所以是不行的;
2、不要纠结action代码中异常以及流没关的问题。。。。只是为了篇幅,把代码贴出来而已。。。。囧