在开发中遇到总站发送命令请求分站将某资源通过FTP上传过来,也就是总站提取分站的资源问题。并且总站实时可以获取已经提取了文件的大小的比例。

  思路:1.首先分站要将文件大小告知总站

2.总站收到文件大小后,根据指定路径去判断指定路径文件夹(分站的文件存储的位置)下的文件大小,然后和当前文件大小/总大小,就获取了已经上传的所占比。

  总站发送请求就不再赘述了,直接说分站接收到请求后的处理,为了防止恶意请求,我们这对每次请求都加了“盐”,那么分站接收时需要判断是否带“盐”了,如果没有,则不予处理,返回错误。

  分站接收请求contorller

    @RequestMapping("/fileSize.htm")
@ResponseBody
public String getFileSize(HttpServletRequest request,HttpServletResponse response,String json) {
log.info(this.getClass().getSimpleName() + "."+ Thread.currentThread().getStackTrace()[1].getMethodName()+ "获取资源文件大小(字节)------start");
/*获取参数--start*/
String checkCode = "see-P2C";//校验码
JSONObject jsonObject = new JSONObject(json);
String tranno =jsonObject.getString("tranno"); //交易流水号
String isCheckcode = jsonObject.getString("checkCode"); //校验码
checkCode = tranno.substring(tranno.length()-6,tranno.length())+checkCode;
String mD5CheckCode = MD5Util.encrypt(checkCode);
Long ids =jsonObject.getLong("sid"); //资源ID
Map<String, Object>map = new HashMap<String, Object>();
map.put("ids", ids);
map.put("tranno", tranno);
map.put("isCheckcode", isCheckcode);
map.put("mD5CheckCode", mD5CheckCode);
log.info(this.getClass().getSimpleName() + "."+ Thread.currentThread().getStackTrace()[1].getMethodName()+ "获取资源文件大小(字节)------end");
return this.transRecordService.fileSizeHandle(map);
}

  TransRecordServiceImpl.java中我们处理这些请求,首先是总站第一遍请求时,分站会判断有没有这个文件,如果没有返回错误,如果有资源分站会告诉总站我的文件有多大、我会把文件放到你的FTP的哪个文件夹下(路径)。

    /**
* @desc 获取文件总大小
* @author zp
*/
@Override
public String fileSizeHandle(Map<String, Object> map) {
// TODO Auto-generated method stub
log.info(this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + "(获取视频总大小)----start");
String tranno = map.get("tranno").toString();
Long ids = (Long)map.get("ids");
String mD5CheckCode = map.get("mD5CheckCode").toString();
String isCheckcode = map.get("isCheckcode").toString();
/*交易记录表插入信息--start*/
TranCodeModel tranCodeModel = new TranCodeModel();
tranCodeModel.setTrandesc("总站提取分站视频资源");
tranCodeModel.setUrl("parentMsg/fileSizeHandle.htm");
tranCodeModel.setProjectphase("2");
tranCodeModel.setRspcode("00");
tranCodeModel.setRspinfo("交易成功");
tranCodeModel.setTranconent("提取资源(resourceid="+ids+")");
tranCodeModel.setTranno(tranno);
tranCodeModel.setCreatetime(DateUtil.getCurrentDateString("YYYY-MM-dd HH:mm:ss"));
/*交易记录表插入信息--end*/
if(!mD5CheckCode.equals(isCheckcode)){ // 身份验证失败
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("身份验证失败");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"identifyError\"}";
}
if(this.vertifyTranNo(tranno)>0){ // 流水号重复
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("交易流水号重复");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"trannoRepeat\"}";
}
Map<String, Object> resourceMap = this.resourceService.findById(ids);
if (Validator.isNull(resourceMap)||resourceMap==null) { // 资源被删除
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("资源被删除");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"delresource\"}";
}
if ("-1".equals(resourceMap.get("isextract").toString())) { // 提取异常
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("提取异常");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"errvideo\"}";
}
List<ResourceFileModel>rFiles = this.rFileService.findGroupByResourceId(ids);
if (rFiles.size()==0) { // 视频资源不存在
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("nofiles");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"novideo\"}";
}
Long filesize = (long)0;
for (ResourceFileModel resourceFileModel : rFiles) {
filesize += Long.parseLong(resourceFileModel.getSize());
}
String uuid = UUID.randomUUID().toString().replace("-", "");
log.info(this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + "(获取视频总大小)----end");
return "{\"rspcode\":\"00\",\"rspinfo\":\"success\",\"filesize\":\""+filesize+"\",\"uuid\":\""+uuid+"\"}";
}

  总站接收到分站第一次成功返回信息之后,然后通知分站,你可以开始上传了,总站也会将文件总大小进行保存,然后开始根据分站提供的文件路径进行实时查询文件大小,然后进行比对。

  分站接收到总站回信后,开始上传文件(总站的回信也是加盐的哦)。

  分站接收总站的第二次请求contorller

/**
* @desc 提取资源
* @author zp
* @throws IOException
* @date 2018-3-16
*/
@RequestMapping("/pickup.htm")
@ResponseBody
public String pickup(HttpServletRequest request,HttpServletResponse response,String json) throws IOException{
log.info(this.getClass().getSimpleName() + "."+ Thread.currentThread().getStackTrace()[1].getMethodName()+ "提取资源------start"); /*获取参数--start*/
String checkCode = "see-P2C";//校验码
JSONObject jsonObject = new JSONObject(json);
String tranno =jsonObject.getString("tranno"); //交易流水号
String isCheckcode = jsonObject.getString("checkCode"); //校验码
checkCode = tranno.substring(tranno.length()-6,tranno.length())+checkCode;
String mD5CheckCode = MD5Util.encrypt(checkCode);
Long ids =jsonObject.getLong("sid"); //资源ID
String ftpuser = jsonObject.getString("ftpuser");// ftp帐号
String ftppwd = jsonObject.getString("ftppwd");// ftp密码
String ftpport = jsonObject.getString("ftpport");// ftp端口
String ftpIP = jsonObject.getString("ftpIP");// ftpIP
String uuid = jsonObject.getString("uuid");// uuid
Map<String, Object>map = new HashMap<String, Object>();
map.put("ids", ids);
map.put("tranno", tranno);
map.put("isCheckcode", isCheckcode);
map.put("mD5CheckCode", mD5CheckCode);
map.put("ftpuser", ftpuser);
map.put("ftppwd", ftppwd);
map.put("ftpIP", ftpIP);
map.put("ftpport", ftpport);
map.put("uuid", uuid);
return this.transRecordService.pickHandle(map);
}

  TransRecordServiceImpl.java中,总站会提供自己的FTP的相关信息。然后开始上传。里边也会处理盐是否正确,是否有该文件等操作。 

/**
* @desc 处理总站提取请求
* @author zp
* @throws IOException
* @date 2018-3-19
*/
@Override
public String pickHandle(Map<String, Object>map) throws IOException {
String tranno = map.get("tranno").toString();
Long ids = (Long)map.get("ids");
String mD5CheckCode = map.get("mD5CheckCode").toString();
String isCheckcode = map.get("isCheckcode").toString();
String ftpuser = map.get("ftpuser").toString();
String ftppwd = map.get("ftppwd").toString();
String ftpIP = map.get("ftpIP").toString();
String ftpport = map.get("ftpport").toString();
/*交易记录表插入信息--start*/
TranCodeModel tranCodeModel = new TranCodeModel();
tranCodeModel.setTrandesc("总站提取分站视频资源");
tranCodeModel.setUrl("parentMsg/pickup.htm");
tranCodeModel.setProjectphase("2");
tranCodeModel.setRspcode("00");
tranCodeModel.setRspinfo("交易成功");
tranCodeModel.setTranconent("提取资源(resourceid="+ids+")");
tranCodeModel.setTranno(tranno);
tranCodeModel.setCreatetime(DateUtil.getCurrentDateString("YYYY-MM-dd HH:mm:ss"));
/*交易记录表插入信息--end*/
if(!mD5CheckCode.equals(isCheckcode)){ // 身份验证失败
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("身份验证失败");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"identifyError\"}";
}
if(this.vertifyTranNo(tranno)>0){ // 流水号重复
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("交易流水号重复");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"trannoRepeat\"}";
}
// 开始上传资源
// 1.判断该任务是否录制完成
Map<String, Object> reMap = this.resourceService.findById(ids);
if (Validator.isNull(reMap)) { // 不存在
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("资源已被删除");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"delResouces\"}";
}
if (!"3".equals(reMap.get("isextract").toString())&&!"2".equals(reMap.get("isextract").toString())) { // 资源未被提取或已被删除
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("资源还未被提取或已被删除");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"nopick\"}";
}
// 2.通过资源ID查找所有的资源信息
List<ResourceFileModel>rFiles = this.rFileService.findGroupByResourceId(ids);
if (rFiles.size()==0) { // 视频资源不存在
tranCodeModel.setRspcode("01");
tranCodeModel.setRspinfo("nofiles");
this.insertdata(tranCodeModel);
return "{\"rspcode\":\"01\",\"rspinfo\":\"novideo\"}";
}
// 3.开始上传
String filePath = "";
String arr = "";
String picktemp = PropertyUtil.getProperty("picktemp"); // 临时路径
String uuid = map.get("uuid").toString();
picktemp = picktemp+uuid+"\\";
picktemp = picktemp.replaceAll("\\\\", "/");
for (ResourceFileModel resourceFileModel : rFiles) {
filePath = resourceFileModel.getPath();
filePath = filePath.replaceAll("\\\\", "/");
String path = filePath.replaceAll("\\\\", "/");
String temp = filePath.substring(0,filePath.lastIndexOf("resources/")+10);
String temp2 = filePath.substring(filePath.lastIndexOf("resources/")+10,filePath.length());
temp2 = temp2.substring(0,temp2.indexOf("/")+1);
filePath = temp + temp2;
path = path .substring(filePath.length(),path.length());
path = picktemp + path;
path = path.replace("/picktemp/", "/resources/");
resourceFileModel.setPath(path);
String url = path.substring(path.indexOf("ResourcesManager/"),path.length());
resourceFileModel.setUrl(url);
arr += JSONObject.fromObject(resourceFileModel)+",";
}
if (arr.length()>0) {
arr = arr.substring(0, arr.length()-1);
}
// 将文件拷贝到指定的临时目录
CopyDirectory copyfile = new CopyDirectory();
copyfile.copyDirectiory(filePath, picktemp); // filePath 源文件 picktemp 目标地址
log.info(this.getClass().getSimpleName() + "."+ Thread.currentThread().getStackTrace()[1].getMethodName()+ "提取资源------end");
try {
String[] ip = ftpIP.split(":");
ftpIP = ip[0];
this.starFtp(picktemp, ftpIP, ftpuser, ftppwd, ftpport);
return "{\"rspcode\":\"00\",\"rspinfo\":\"success\",\"resource\":["+arr+"]}";
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
return "{\"rspcode\":\"01\",\"rspinfo\":\"ftperror\"}";
}
} /**
* @desc 开启线程进行FTP上传
* @author zp
* @date 2018-3-23
*/
public void starFtp(String picktemp, String ftpIP,String ftpuser,String ftppwd,String ftpport) {
log.info(this.getClass().getSimpleName() + "."+ Thread.currentThread().getStackTrace()[1].getMethodName()+ "准备开启FTP上传线程------start");
//创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
//创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
CreateTreadPool t1 = new CreateTreadPool(picktemp, ftpIP, ftpuser, ftppwd, ftpport);
//将线程放入池中进行执行
pool.execute(t1);
System.out.println(Thread.currentThread().getName()+"进入线程");
//关闭线程池
pool.shutdown();
log.info(this.getClass().getSimpleName() + "."+ Thread.currentThread().getStackTrace()[1].getMethodName()+ "准备开启FTP上传线程------end");
}

  开启线程对FTP上传进行操作,因为考虑到本次操作总站可能不关心上传过程,所以成功与否就不实时通知总站了~~~~~

public class CreateTreadPool implements Runnable {
private static Logger log = Logger.getLogger(CreateTreadPool.class);
// public static ReentrantLock lock=new ReentrantLock();
//定义信号量,只能5个线程同时访问
final Semaphore semaphore = new Semaphore(5);
public static int c=0;
public String picktemp; //路径
public String ftpIP; // ftpip
public String ftpuser ; // ftp帐号
public String ftppwd ; // ftp密码
public String ftpport; // ftp端口
// 通过构造方法 获取FTP相关信息。
public CreateTreadPool(String picktemp, String ftpIP,String ftpuser,String ftppwd,String ftpport){
this.picktemp = picktemp;
this.ftpIP = ftpIP;
this.ftpuser = ftpuser;
this.ftppwd = ftppwd;
this.ftpport = ftpport;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"---------上传准备中---------");
try {
//获取许可
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"获得锁");
System.out.println(Thread.currentThread().getName()+"====>"+c);
boolean isSuccess = this.FTPUpload(picktemp, ftpIP, ftpuser, ftppwd, ftpport);
if (isSuccess) {
System.out.println(Thread.currentThread().getName()+"---------上传成功---------");
}else {
System.out.println(Thread.currentThread().getName()+"---------上传失败---------");
}
c++;
} catch (Exception e) {
System.out.println(Thread.currentThread().getName()+"---------上传失败---------");
e.printStackTrace();
}finally{
System.out.println(Thread.currentThread().getName()+"------------释放锁");
semaphore.release();
}
}
/**
* @desc FTP上传
* @author zp
* @date 2018-3-23
*/
public boolean FTPUpload(String filePath, String serverIp,String ftpuser,String ftppwd,String ftpport) {
log.info(this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + "(给总站FTP上传视频)----start");
FtpUtil ftpTool = new FtpUtil(ftpuser, ftppwd, serverIp, ftpport); // 创建链接
boolean linkStatus = ftpTool.connectServer(ftpuser, ftppwd, serverIp, ftpport);
File file = new File(filePath); // 实例化
UploadListener listener = new UploadListener(ftpTool.client); // 创建监听
ftpTool.ftpUploadFolder(file, listener); // 上传
ftpTool.disconnect(); // 关闭
RemoveFilesUtil removeFilesUtil = new RemoveFilesUtil();
removeFilesUtil.DeleteFolder(filePath); // 移除本地临时上传的文件
log.info(this.getClass().getSimpleName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName() + "(给总站FTP上传视频)----end");
return linkStatus;
}

  

用多线程处理FTP上传的更多相关文章

  1. .net FTP上传文件

    FTP上传文件代码实现: private void UploadFileByWebClient() { WebClient webClient = new WebClient(); webClient ...

  2. 通过cmd完成FTP上传文件操作

    一直使用 FileZilla 这个工具进行相关的 FTP 操作,而在某一次版本升级之后,发现不太好用了,连接老是掉,再后来完全连接不上去. 改用了一段时间的 Web 版的 FTP 工具,后来那个页面也 ...

  3. FTP上传文件到服务器

    一.初始化上传控件. 1.我们这里用dropzone.js作为上传控件,下载地址http://www.dropzonejs.com/ 2.这里我们使用一个div元素作为dropzone载体. < ...

  4. 再看ftp上传文件

    前言 去年在项目中用到ftp上传文件,用FtpWebRequest和FtpWebResponse封装一个帮助类,这个在网上能找到很多,前台使用Uploadify控件,然后在服务器上搭建Ftp服务器,在 ...

  5. 【完整靠谱版】结合公司项目,仔细总结自己使用百度编辑器实现FTP上传的完整过程

    说在前面 工作中会遇到很多需要使用富文本编辑器的地方,比如我现在发布这篇文章离不开这个神器,而且现在网上编辑器太多了.记得之前,由于工作需要自己封装过一个编辑器的公共插件,是用ckeditor改版的, ...

  6. FTP上传文件提示550错误原因分析。

    今天测试FTP上传文件功能,同样的代码从自己的Demo移到正式的代码中,不能实现功能,并报 Stream rs = ftp.GetRequestStream()提示远程服务器返回错误: (550) 文 ...

  7. JAVA 实现FTP上传下载(sun.net.ftp.FtpClient)

    package com.why.ftp; import java.io.DataInputStream; import java.io.File; import java.io.FileInputSt ...

  8. FTP上传-封装工具类

    import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import ja ...

  9. 记一次FTP上传文件总是超时的解决过程

    好久没写博,还是重拾记录一下吧. 背景:买了一个阿里云的云虚拟机用来搭建网站(起初不了解云虚拟主机和云服务器的区别,以为都是有SSH功能的,后来发现不是这样样子啊,云虚拟机就是FTP上传网页+MySQ ...

随机推荐

  1. maomao的每日动向

    \(2019.02.04\) \(Nothing\) \(to\) \(do\). \(2019.02.05\) - 早上睡到\(12\)点 - 中午下午:吃饭串门拜年 - 晚上:吹爆<流浪地球 ...

  2. C# string.format用法详解

    String.Format 方法的几种定义: String.Format (String, Object) 将指定的 String 中的格式项替换为指定的 Object 实例的值的文本等效项. Str ...

  3. 运维监控-Zabbix Server 使用QQ SMTP发送邮件报警及定制报警内容

    运维监控-Zabbix Server 使用QQ SMTP发送邮件报警及定制报警内容 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客采用腾讯邮箱,想必大家都对QQ很了解,所以 ...

  4. hive metastore && hiveserver2 . jvm 配置调整优化

    hive-env.sh 添加如下,其中踩坑踩了不少. if [ "$SERVICE" = "metastore" ]; then if [ -z "$ ...

  5. MyBatis-注解方式整合SSM

    Spring.Spring MVC.MyBatis 整合 一.依赖 <?xml version="1.0" encoding="UTF-8"?> & ...

  6. vscode 编辑markdown文件

    关于换行问题 在vscode中编写Markdown文件时,会遇到明明按回车换行了但是预览的时候却没有换行的情况,这时在需要换行的地方多按两次空格键,就会换行 预览markdown文件 编辑器右上角有个 ...

  7. JSON.parse JSON.stringify

    JSON.stringify() undefined 值.函数或者XML值会被忽略 数组当中含有 undefined值,函数或XML值,该数组中的这些值将会被当成 null 正则对象会被转成空对象 J ...

  8. 关于Ant脚本

    在开发中,一个项目要经历单元测试l,集成测试,系统测试,测试过程中可能要不断修改代码,Ant脚本,通过一个xml文件,封装一系列繁琐又常用的操作,通过Ant指令执行xml脚本来批处理创建删除任务,编译 ...

  9. 观察者模式--java

    写在前面 钩子函数.注册函数.回调函数,他们的概念其实是一样的. 观察者模式,又可以称之为发布-订阅模式,观察者,顾名思义,就是一个监听者,类似监听器的存在,一旦被观察/监听的目标发生的情况,就会被监 ...

  10. IO流--字符流与字节流--File类常用功能

    IO流的常用方法: 1: 文件的读取和写入图解: 2:字节流: 读写文件的方法: 一般效率读取: 读取文件:        FileInputStream(); 写数据:            Fil ...