安卓手机扫二维码从FTP服务器下载apk
Devops平台的APP下载页面:
Linux服务器的FTP目录下的apk包:
Controller层:
/**
* getFtpApk:安卓下载FTP上的apk
* @author liuyongzhan
* @param proSysEnv 主体-业务系统-环境
* @param apkPath 版本/apk文件名称
* @param request
* @param response InputStream
*/
@ApiOperation(value = "安卓下载FTP上的apk", notes = "")
@RequestMapping(value = { "getFtpApk" }, method = RequestMethod.GET)
public void getFtpApk(String proSysEnv,String apkPath,String currentLoginName,HttpServletRequest request,HttpServletResponse response) {
String userName = currentLoginName;
InputStream ins = null;
try {
Map map = appDownloadService.getFtpClient();
FtpUtilForDownLoad ftpDl = (FtpUtilForDownLoad) map.get("FtpUtilForDownLoad");
FTPClient ftp = (FTPClient) map.get("FTPClient");
String ftpPath = (String) map.get("ftpPath");
int apkSize = appDownloadService.getFtpFileSize(proSysEnv,apkPath,ftpDl,ftp,ftpPath);
ins = appDownloadService.getFtpApk(proSysEnv,apkPath,ftpDl,ftp,ftpPath);
String[] apkPathArr = apkPath.split("/");
String fileName = apkPathArr[1];
// 初始化文件流,提供客户端下载
BufferedInputStream bins = new BufferedInputStream(ins);//放到缓冲流里面
OutputStream outs = response.getOutputStream();//获取文件输出IO流
BufferedOutputStream bouts = new BufferedOutputStream(outs);
response.setContentType("application/vnd.android.package-archive");//设置response内容的类型 下载安卓应用apk
response.setContentLength(apkSize);//设置文件大小
response.setHeader("Content-disposition","attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));//设置头部信息
int bytesRead = 0;
byte[] buffer = new byte[8192];//这个取决于硬盘的扇区大小是512byte/sec;8192/512 = 16,表明写入了16扇区。
//开始向网络传输文件流
while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
bouts.write(buffer, 0, bytesRead);
}
bouts.flush();//这里一定要调用flush()方法
ins.close();
bins.close();
outs.close();
bouts.close();
} catch (Exception e) {
logger.error("账号:"+userName+",安卓下载FTP上的apk异常,"+e.getMessage());
logRunService.addLogRun(Module.MODULE_PUBLISH, "平台", 2, "安卓下载FTP上的apk异常",LogFileName.MODULE_PUBLISH);
}
}
ServiceImpl层:
/**
* 获取FtpUtilForDownLoad和FTPClient对象
* @see service.publish.AppDownloadService#getFtpClient()
*/
@Override
public Map getFtpClient() throws Exception {
Map resMap = new HashMap();
int ftpPort = 21;
String ftpIp = "10.10.101.111";
String ftpUser = "admin";
String ftpPwd = "admin123";
String ftpPath ="/opt/vftp/";
FtpUtilForDownLoad ftpDl = new FtpUtilForDownLoad();
FTPClient ftp = ftpDl.connectFTP(ftpIp,ftpPort,ftpUser,ftpPwd);
resMap.put("FtpUtilForDownLoad", ftpDl);
resMap.put("FTPClient", ftp);
resMap.put("ftpPath", ftpPath);
return resMap;
}
/**
* 获取ftp文件的size
*/
@Override
public int getFtpFileSize(String proSysEnv, String apkPath,FtpUtilForDownLoad ftpDl,FTPClient ftp,String ftpPath) throws Exception {
String arr[] = proSysEnv.split("-");
String[] apkPathArr = apkPath.split("/");
String fileName = apkPathArr[1];
String ftpApkPath = ftpPath+arr[0]+"_"+arr[1]+"/"+arr[0]+"_"+arr[1]+"_"+arr[2]+"/"+apkPathArr[0]+"/program/program/"+fileName;
int apkSize = ftpDl.getFtpFileSize(ftpApkPath, ftp);
return apkSize;
}
/**
* 获取ftp文件的InputStream
*/
@Override
public InputStream getFtpApk(String proSysEnv, String apkPath,FtpUtilForDownLoad ftpDl,FTPClient ftp,String ftpPath) throws Exception {
String arr[] = proSysEnv.split("-");
String[] apkPathArr = apkPath.split("/");
String fileName = apkPathArr[1];
String ftpApkPath = ftpPath+arr[0]+"_"+arr[1]+"/"+arr[0]+"_"+arr[1]+"_"+arr[2]+"/"+apkPathArr[0]+"/program/program/"+fileName;
InputStream ins = ftpDl.getFtpFileInputStream(ftpApkPath,ftp);
return ins;
}
FTP工具类:
package com.devops.plugins.ftp;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
public class FtpUtilForDownLoad {
/**
* connectFTP: 连接ftp
* @author liuyongzhan
* @param url 必须是IP地址, 否则提示异常
* @param port 端口
* @param username ftp用户
* @param password ftp密码
* @return FtpClient
*/
public FTPClient connectFTP(String url, int port, String username, String password) {
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(url,port);
ftpClient.login(username, password);
} catch (IOException e) {
e.printStackTrace();
}
return ftpClient;
}
/**
* getFtpFileInputStream:获取文件的InputStream
* @author liuyongzhan
* @param ftpFile ftp上文件的路径
* @param ftp FtpClient对象
* @return InputStream 文件的InputStream
* @throws Exception
*/
public InputStream getFtpFileInputStream(String ftpFile,FTPClient ftp) throws Exception {
InputStream is = null;
ftp.setBufferSize(1024);
//设置文件类型(二进制)
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
// if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) {// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK).
// ftpClient.setControlEncoding("UTF-8");
// }
String fileName = new String(ftpFile.getBytes("utf-8"), "iso-8859-1");
is = ftp.retrieveFileStream(fileName);
return is;
}
/**
* getFtpFileSize:获取文件的大小
* @author liuyongzhan
* @param ftpFile ftp上文件的路径
* @param ftp FtpClient对象
* @return int 文件的大小
* @throws Exception
*/
public int getFtpFileSize(String ftpFile,FTPClient ftp) throws Exception {
String fileName = new String(ftpFile.getBytes("utf-8"), "iso-8859-1");
FTPFile[] files = ftp.listFiles(fileName);
long aSize = files[0].getSize();
int apkSize = new Long(aSize).intValue();
return apkSize;
}
public static void main(String[] args) {
FtpUtilForDownLoad ftpDl = new FtpUtilForDownLoad();
FTPClient ftp = ftpDl.connectFTP("10.10.101.111", 21, "admin", "admin123");
String ftpPath = "/opt/vftp/ftp1_sysftp/ftp1_sysftp_DEV/201710111837/program/program/中文.apk";
try {
// ftpDl.getFtpFileInputStream(ftpPath, ftp);
ftpDl.getFtpFileSize(ftpPath, ftp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Js:
/**
* 生成下载地址的二维码
*/
show:function (obj,apkPath) {
var curWwwPath=window.document.location.href;
//获取主机地址之后的目录,如: uimcardprj/share/meun.jsp
var pathName=window.document.location.pathname;
var pos=curWwwPath.indexOf(pathName);
//获取主机地址,如: http://localhost:8083
var localhostPaht=curWwwPath.substring(0,pos);
//获取带"/"的项目名,如:/uimcardprj
var projectName=pathName.substring(0,pathName.substr(1).indexOf('/')+1);
var projectPath = localhostPaht+projectName;//项目路径
var ftpPath = projectPath+"/appDownload/getFtpApk.do?proSysEnv="+keys+"&apkPath="+apkPath+"¤tLoginName="+currentLoginName;
$("#code").empty();
var path = $.APPDownload.utf16to8(ftpPath);
var aPath = path.replace(/\s/g, "%20");
$("#code").qrcode({
// render: "table", //table方式
correctLevel:0,
width: 230, //宽度
height:230, //高度
text:aPath
});
$("#del_modal").modal({backdrop: 'static', keyboard: false},"show");
},
/**
* 转码
*/
utf16to8:function (str) {
var out, i, len, c;
out = "";
len = str.length;
for(i = 0; i < len; i++) {
c = str.charCodeAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
out += str.charAt(i);
} else if (c > 0x07FF) {
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
} else {
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
}
}
return out;
},
/**
* 隐藏二维码
*/
hide:function (obj) {
var objDiv = $("#code");
$(objDiv).css("display", "none");
}