问题描述
项目中有一个需求,需要从客户端(网页)批量下载服务器存储的图片到本地,但是服务器只存储了图片url地址,图片本身存在于别的服务器上,当我们请求图片的时候,会出现跨域问题,尽管前端解决了跨域,但是还需要服务器允许跨域请求资源,因为有多个服务器所以从服务器端解决不太理想。
解决思路
首先,可以通过后台JAVA方法,把别的服务器上的图片下载到项目服务器(后台请求没有跨域的问题),下载到本地之后,在通过前端轮子从项目服务器下载就不会跨域了。
一. 后台下载
public EiInfo ExportPhoto(EiInfo inInfo) {
EiInfo outInfo = new EiInfo();
HashMap map=new HashMap();
//从前端获取查询条件
map.put("number",inInfo.getBlock("inqu_status").getRow(0).get("number"));
map.put("jgsjStart",inInfo.getBlock("inqu_status").getRow(0).get("jgsjStart"));
map.put("jgsjEnd",inInfo.getBlock("inqu_status").getRow(0).get("jgsjEnd"));
map.put("deviceaddress",inInfo.getBlock("inqu_status").getRow(0).get("deviceaddress"));
map.put("csys",inInfo.getBlock("inqu_status").getRow(0).get("csys"));
map.put("hpys",inInfo.getBlock("inqu_status").getRow(0).get("hpys"));
map.put("cerType",inInfo.getBlock("inqu_status").getRow(0).get("cerType"));
map.put("fxbh",inInfo.getBlock("inqu_status").getRow(0).get("fxbh"));
//获取需要导出的数据集
List<HashMap> list = dao.query( "BMGS02.queryJgclPhoto", map);
List result = list;
int num=0;
ArrayList arrayList = new ArrayList();
//遍历数据集,获取每条数据的图片地址
for(int i=0;i<result.size();i++){
BM05 bm05 = new BM05();
bm05.fromMap((Map) result.get(i));
int i1 = bm05.getTpurl().lastIndexOf("/"); //因为图片地址很长,我们需要找到图片名称并截取出来,图片下载到服务器上之后重新拼接上服务器IP形成新的地址
String substring = bm05.getTpurl().substring(i1+1, bm05.getTpurl().length());
arrayList.add(substring);
//调用根据url下载图片的方法,需要传下载的url,下载路径(建议在项目所在文件夹创建文件,因为浏览器保护没办法直接访问到项目服务器的本地文件,但是我们可以访问项目文件),图片名称
boolean b = httpDownload("图片地址", "图片下载地址" + substring);
if(b){
num+=1;
}
}
outInfo.set("photoList",arrayList);
return outInfo;
}
public static boolean httpDownload(String httpUrl, String saveFile) {
// 1.下载网络文件
int byteRead;
URL url;
try {
url = new URL(httpUrl);
} catch (MalformedURLException e1) {
e1.printStackTrace();
return false;
}
try {
//2.获取链接
URLConnection conn = url.openConnection();
//3.输入流
InputStream inStream;
inStream = conn.getInputStream();
//3.写入文件
FileOutputStream fs = new FileOutputStream(saveFile);
byte[] buffer = new byte[1024];
while ((byteRead = inStream.read(buffer)) != -1) {
fs.write(buffer, 0, byteRead);
}
inStream.close();
fs.close();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
//删除指定文件夹下的所有文件,避免下载图片过多导致服务器内存不足
public EiInfo deletePhoto(EiInfo inInfo) {
delAllFile(文件路径);
return inInfo;
}
public static boolean delAllFile(String path){
boolean flag = false;
File file = new File(path);
if(!file.exists()){
return flag;
}
if (!file.isDirectory()) {
return flag;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
} else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
// delFolder(path + "/" + tempList[i]);//再删除空文件夹
flag = true;
}
}
return flag;
}
二.前端下载
//引入需要的js
<script src="../static/js/jszip.js"></script>
<script src="../static/js/FileSaver.js"></script>
//先从服务器上下载图片 然后清除服务器上缓存下来的图片
var photoList=eiInfo.get("photoList"); //获取服务器上新的图片地址列表
var photoArr=[];
for(var i=0;i<photoList.length;i++){ //遍历图片列表
//根据图片名称 拼接图片对象
photoArr.push({url:"http://localhost:8080/rc/static/downPhoto/"+photoList[i],name:photoList[i]})
}
//调用批量下载图片的方法
FunLib.download(photoArr);
// 下载图片
var FunLib = { //该方法需要服务器支持跨域 或者从跨域的服务器上获取图片到本地服务器
// 图片打包下载
download: function (images) {
FunLib.packageImages(images)
},
// 打包压缩图片
packageImages: function (imgs) {
var imgBase64 = []
var imageSuffix = [] // 图片后缀
var zip = new JSZip()
var img = zip.folder("images")
for (var i = 0; i < imgs.length; i++) {
var src = imgs[i].url
var suffix = src.substring(src.lastIndexOf("."))
imageSuffix.push(suffix)
FunLib.getBase64(imgs[i].url).then(function (base64) {
imgBase64.push(base64.substring(22))
if (imgs.length === imgBase64.length) {
for (var i = 0; i < imgs.length; i++) {
img.file(imgs[i].name + imageSuffix[i], imgBase64[i], {base64: true})
}
zip.generateAsync({type: "blob"}).then(function (content) {
saveAs(content, "images.zip")
downPhoto=true;
})
}
}, function (err) {
console.log(err)
})
}
},
// 传入图片路径,返回base64
getBase64: function (img) {
var image = new Image()
image.src = img+'?time=' + new Date().valueOf();
image.crossOrigin = '*';
var deferred = $.Deferred()
if (img) {
image.onload = function () {
var canvas = document.createElement("canvas")
canvas.width = image.width
canvas.height = image.height
var ctx = canvas.getContext("2d")
ctx.drawImage(image, 0, 0, canvas.width, canvas.height)
var dataURL = canvas.toDataURL()
deferred.resolve(dataURL)
}
return deferred.promise()
}
}
}
三.过程中的坑
1.跨域不仅需要前端解决,还需要资源服务器允许跨域
2.图片下载到项目服务器时,如果下载到本地目录里,那么前端无法通过ip:8080路径访问到图片。所以需要在项目文件夹里新建文件存放图片。
3.tomcat文件新增图片资源的时候 需要加载图片,不然虽然可以在文件里看到图片,但是再打开的项目上无法访问到图片。把文件建在构建好的文件里,就不会出现tomcat需要时间加载的问题了。
4.下载完图片记得删除,不然可能占太多服务器内存。