实习总结三:文件迁移
来源:互联网 发布:绘画小区平面图软件 编辑:程序博客网 时间:2024/06/13 02:45
根据项目需求,将文件从FDFS,SASS迁移到azure。此文章记录了java对三个服务器文件上传下载简单的实现。
@Controller@RequestMapping("/file")public class FileFloadMigrationController extends BaseController { private static Logger log = LoggerFactory.getLogger(FileServiceImpl.class); @Autowired @Qualifier("fileUploadServiceImpl") private FileService fileService; @Autowired private FileUploadedToDao fileUploadedToDao; @Autowired(required = false) protected MongoTemplate mongoTemplate; @Autowired private FileMapDao fileMapDao; @Autowired private FileMapService fileMapService; @Autowired private FileUploadedService fileUploadedService; /** * 文件迁移 * * @Title: fileMigration * @param state * 状态:fail:失败 upload:上传 * @param module * 模块名 module=all:所有模块 * @param lastModifyTime * 最后修改时间:存在该项时证明要导入新增数据 * @return * @throws Exception */ @RequestMapping(value = "/filefload/{state}/{module}", method = RequestMethod.GET) public @ResponseBody Rest fileMigration(@PathVariable String state, @PathVariable String module, String lastModifyTime) throws Exception { new HttpClient().getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(0, false)); List<FileUploaded> fileUploadeds = new ArrayList<FileUploaded>(); List<FileUploadedTo> findFileUploadedTos = new ArrayList<FileUploadedTo>(); Map<Integer, Object> result = new HashMap<Integer, Object>(); // 上传失败后 if (state.equals("fail")) { // 从新上传所有模块中失败数据 if (module.equals("all")) { findFileUploadedTos = getFileUploadsFail(); } else { // 按模块上传 findFileUploadedTos = getFileUploadsFail(module); } result = uploadFileFail(findFileUploadedTos); } else if (state.equals("upload")) { if (module.equals("all")) { // 上传所有模块中数据 fileUploadeds = getFileUploadsNomal(); } else { // 按模块上传数据 fileUploadeds = getFileUploadsNomal(module); } // 最后修改时间不为空,需要上传新文件 // 比如2017-11-09日转移一次后,11日需要在转移。此时lastModifyTime 需要写为2017-11-09 if (lastModifyTime != null && !lastModifyTime.equals("")) { fileUploadeds = getFileUploadTosByLastModify(lastModifyTime); } result = uploadFileNomal(fileUploadeds); } return Rest.item(StateCode.STATUS_CODE_SUCCESS, result); } /** * 正常情况下文件迁移,不按照模块。所有模块 * * @return List<FileUploaded> */ private List<FileUploaded> getFileUploadsNomal() { List<FileUploaded> fileUploadeds = new ArrayList<FileUploaded>(); Query query = new Query(); fileUploadeds = mongoTemplate.find(query, FileUploaded.class); return fileUploadeds; } /** * 正常情况下文件迁移,按照模块 * * @Title: getFileUploadsNomal * @param module * 模块名字 * @return List<FileUploaded> */ private List<FileUploaded> getFileUploadsNomal(String module) { List<FileUploaded> fileUploadeds = new ArrayList<FileUploaded>(); Query query = new Query(); Criteria criteria = Criteria.where("module").is(module); query.addCriteria(criteria); fileUploadeds = mongoTemplate.find(query, FileUploaded.class); return fileUploadeds; } /** * 上传过程中出现失败情况。从新上传。所有模块 * * @Title: getFileUploadsFail * @return List<FileUploadedTo> */ private List<FileUploadedTo> getFileUploadsFail() { List<FileUploadedTo> findFileUploadedTos = new ArrayList<FileUploadedTo>(); Query query = new Query(); Criteria criteria = Criteria.where("isSuccess").is(false); query.addCriteria(criteria); findFileUploadedTos = mongoTemplate.find(query, FileUploadedTo.class); return findFileUploadedTos; } /** * 上传过程中出现失败情况。从新上传。按模块进行上传 * * @Title: getFileUploadsFail * @param module * 模块名 * @return List<FileUploadedTo> */ private List<FileUploadedTo> getFileUploadsFail(String module) { List<FileUploadedTo> findFileUploadedTos = new ArrayList<FileUploadedTo>(); Query query = new Query(); Criteria criteria = Criteria.where("fileUploaded.module").is(module).and("isSuccess").is(false); query.addCriteria(criteria); findFileUploadedTos = mongoTemplate.find(query, FileUploadedTo.class); return findFileUploadedTos; } /** * 上传部分后,出现新增数据。根据文件最后更新时间,进行操作 * * @Title: getFileUploadTosByLastModify * @param lastModifyTime * 最后修改时间 * @return List<FileUploadedTo> * @throws ParseException */ private List<FileUploaded> getFileUploadTosByLastModify(String lastModifyTime) throws ParseException { List<FileUploaded> fileUploadeds = new ArrayList<FileUploaded>(); Query query = new Query(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Criteria criteria = Criteria.where("lastModify").gte(sdf.parse(lastModifyTime)); query.addCriteria(criteria); fileUploadeds = mongoTemplate.find(query, FileUploaded.class); return fileUploadeds; } /** * 正常情况下上传文件主方法 * * @Title: uploadFileNomal * @param fileUploadeds * @return * @throws Exception */ private Map<Integer, Object> uploadFileNomal(List<FileUploaded> fileUploadeds) throws Exception { Map<Integer, Object> map = new HashMap<Integer, Object>(); List<FileUploadedTo> fileUploadedTos = new ArrayList<FileUploadedTo>(); if (fileUploadeds == null || fileUploadeds.size() == 0) { return map; } System.out.println("共有文件:" + fileUploadeds.size() + "条"); long startTime = System.currentTimeMillis(); // 将表中的数据复制到扩展表中(将文件所有信息复制、设置org为要迁移文件的org、设置迁移失败(false)) for (FileUploaded fileUploaded : fileUploadeds) { FileUploadedTo fileUploadedTo = new FileUploadedTo(); fileUploadedTo.setFileUploaded(fileUploaded); fileUploadedTo.setOrg(fileUploaded.getOrg()); fileUploadedTo.setSuccess(false); fileUploadedTos.add(fileUploadedTo); } // 保存复制表 fileUploadedToDao.save(fileUploadedTos); uploadFileCurrency(fileUploadedTos); long endTime = System.currentTimeMillis(); System.out.println("程序运行时间: " + (endTime - startTime) + "ms"); return map; } /** * 上传失败后重新上传主方法 * * @Title: uploadFileFail * @param fileUploadedTos * @return */ private Map<Integer, Object> uploadFileFail(List<FileUploadedTo> fileUploadedTos) throws Exception { Map<Integer, Object> map = new HashMap<Integer,Object>(); uploadFileCurrency(fileUploadedTos); return map; } /** * 上传文件通用方法 * * @Title: uploadFileCurrency * @param fileUploadedTos */ private void uploadFileCurrency(List<FileUploadedTo> fileUploadedTos) { int i = 0; for (FileUploadedTo fileUploadedTo : fileUploadedTos) { String path = fileUploadedTo.getFileUploaded().getPath(); if (path != null && path.indexOf("group") != -1) { byte fileByte[] = fileService.getFileBytes(path); if (fileByte == null) { System.out.println("第" + i++ + "个 fileByte不存在,path是" + path); } else { if (path.indexOf(".pdf.") == -1) {// 不是从文件 uploadFile(fileUploadedTo, fileByte); } else {// 是从文件 uploadSlaveFile(fileByte, "file.pdf", fileUploadedTo); } } } } } /** * 上传文件到分布式系统,并写入文件 文件限制大小 上传的文件可以直接通过id使用特定接口访问 上传失败return null * * @param fileBytes * 文件 * @param name * 文件名称 * @param module * 模块标示 * @return */ private void uploadFile(FileUploadedTo fileUploadedTo, byte[] fileBytes) { // 获取fileUpload FileUploaded fileUploaded = fileUploadedTo.getFileUploaded(); // 获取模板名 String module = fileUploaded.getModule(); // 获取当前文件信息内的org String org = fileUploaded.getOrg(); // 获取文件名 String name = fileUploaded.getName(); // 获取文件ID String fileId = fileUploaded.getId(); if (!isLegal(module)) { log.error("module ilegal: 模块名称非法"); } try { // 长度小于3报错 if (org.length() < 4) { org = "org" + org; } CloudBlockBlob blob = BlobClient.uploadFile(fileBytes, org, module, name); // 如果上传成功会返回一个Blob对象(不为空) // 那么此时就将上传后的新路径以及是否上传成功状态进行更改。 if (blob != null) { // 设置更新成功 fileUploadedTo.setSuccess(true); // 设置新路径 String newPath = BlobClient.getPath(org, blob.getName()); fileUploadedTo.setNewPath(newPath); fileUploadedToDao.update(fileUploadedTo); // 更新fileUpload路径。 fileUploaded.setPath(newPath); mongoTemplate.save(fileUploaded); // 更新filemap路径 FileMap fileMap = findByFileId(fileId); if (fileMap != null) { fileMap.setFilePath(newPath); fileMapService.update(fileMap); } } } catch (Exception e) { e.printStackTrace(); } } /** * 根据fileId 获取 fileMap。 * * @Title: findByFileId * @param id * 文件ID * @return * @throws */ private FileMap findByFileId(String id) { Query query = new Query(Criteria.where("fileId").is(id)); return fileMapDao.findOne(query); } /** * 校验模块是否合法<br/> * 模块名在properties中存在即合法 * * @param module * 模块名称 * @return 合法返回true ,非法返回false */ private boolean isLegal(String module) { if (module.indexOf('.') >= 0) { return false; } String v = PropertiesUtils.getString("file.path." + module); if (v == null || v.length() < 1) { return false; } else { return true; } } /** * 上传从文件主方法 * * @Title: uploadSlaveFile * @param fileBytes * 从文件字节大小 * @param prefix_name * 从文件前缀 * @param fileUploadedTo * fileUploaded 复制表 */ private void uploadSlaveFile(byte[] fileBytes, String prefix_name, FileUploadedTo fileUploadedTo) { String org = fileUploadedTo.getFileUploaded().getOrg(); FileUploaded master = fileUploadedTo.getFileUploaded(); String preName = master.getName().substring(0, master.getName().lastIndexOf(".")); prefix_name = BlobClient.getPath(preName.concat("_cut"), preName.concat(".pdf")); System.out.println(prefix_name); try { CloudBlockBlob blob = BlobClient.uploadFile(fileBytes, org, master.getModule(), prefix_name); if (blob != null) { fileUploadedTo.setSuccess(true); } fileUploadedTo.setNewPath(BlobClient.getPath(org, blob.getName())); } catch (InvalidKeyException | URISyntaxException | StorageException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } fileUploadedToDao.update(fileUploadedTo); }}
上面的类首先获取数据库中的文件,然后根据文件的路径获取文件的字节。如果路径符合规范且字节不为空,那么就将该文件上传。下面的方法是上传到Azure的方法。
Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob、Queue、File 和 Table。
Azure Blob Storage 是用来存放大量的像文本、图片、视频等非结构化数据的存储服务。我们可以在任何地方通过互联网协议 http 或者 https 访问 Blob Storage。简单说,就是把文件放在云上,给它一个 URL,通过这个 URL 来访问文件。这就涉及到一个问题:如何控制访问权限?答案是我们可以根据自己的需要,设置 Blob 对象是只能被自己访问,还是可以被所有人访问。
下面是 Blog Storage 典型的应用场景:
- 存储图片和文档,这些文件可以直接通过浏览器访问。
- 支持分布式访问,主要用于 cdn。
- 提供视频、音频流。
- 存储基本的文件备份和归档文件。
static final String connectionString = String.format( "DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=core.chinacloudapi.cn", storageAccountName, storageAccountKey); /** * 通过容器的方式实现上传二进制文件 * @throws InvalidKeyException * @time:2017年9月22日 上午10:40:19 */ public static CloudBlockBlob uploadFile(byte[] fileBytes,String org,String module,String fileName) throws URISyntaxException, StorageException, IOException, InvalidKeyException{ // CloudStorageAccount 类表示一个 Azure Storage Account,我们需要先创建它的实例,才能访问属于它的资源。 // 注意连接字符串中的xxx和yyy,分别对应Access keys中的Storage account name 和 key。 CloudStorageAccount storageAccount = CloudStorageAccount.parse(connectionString); // Create the blob client object. CloudBlobClient blobClient = storageAccount.createCloudBlobClient(); CloudBlobContainer container = blobClient.getContainerReference(org); container.createIfNotExists(); // 创建一个容器(如果该容器不存在) // 保存到azure上的文件的名称,由于azure服务器对重名文件进行覆盖处理, // 上传时对文件名称进行唯一标识处理,缺点是在文件服务器看不到文件的真识名称了。 UUID token = UUID.randomUUID(); int postFixIndex = fileName.lastIndexOf("."); String fileFullName = ""; String postFix = ""; String startName = ""; if (postFixIndex > 0) { postFix = fileName.substring(postFixIndex + 1); startName = fileName.substring(0, postFixIndex); }else { startName = fileName; } /*azure服务器存储相同文件名的文件会覆盖之前的,因此需要对文件名进行处理 存储到azure上的文件名格试为:原文件名+"_"+uuid+扩展名 */ fileFullName = startName.concat("_").concat(token.toString()).concat(".").concat(postFix); /*getPath(module,fileFullName) 为放在 container 中的 Blob 的连接路径。 getBlockBlobReference 方法获得一个 Block 类型的 Blob 对象的引用。 您可以根据应用的需要,分别调用 getBlobReference,getAppendBlobReference 或 getPageBlobReference 来创建不同类型的 Blob 对象。 */ CloudBlockBlob blob = container.getBlockBlobReference(getPath(module,fileFullName)); try { InputStream stream = new ByteArrayInputStream(fileBytes); //blob.upload(stream, (long) fileBytes.length); PutBlock(blob,stream); } catch (StorageException e) { return null; } return blob; }
大文件分块上传:
/** *文件过大,分块上传 * @Title: PutBlock * @param blob * @param stream * @throws StorageException * @throws IOException */@SuppressWarnings({ "unchecked", "rawtypes" }) public static void PutBlock(CloudBlockBlob blob,InputStream stream) throws StorageException, IOException { Iterable<BlockEntry> blockList = new ArrayList<BlockEntry>(); int len = stream.available(); int bytesRead = 0; int cur_read_len = STEP_LENGTH; byte[] b = null; int index = 0; if (len <= STEP_LENGTH) {// 如果文件没有超过设定长度,一次上传上即可 blob.upload(stream, (long) len); } else {// 如果文件太大,分批上传 while (true) { if (len - bytesRead > STEP_LENGTH) { cur_read_len = STEP_LENGTH; } else { cur_read_len = len - bytesRead; } b = new byte[cur_read_len + 1]; int bytesReadLength = 0; bytesReadLength = stream.read(b, 0, cur_read_len); if (bytesReadLength == -1){// end of InputStream blob.commitBlockList(blockList); break; } bytesRead += bytesReadLength; if (bytesRead <= len) { try { String blockId = Base64.getEncoder().encodeToString(String.format("%08d",index).getBytes(StandardCharsets.UTF_8)); blob.uploadBlock(blockId, new ByteArrayInputStream(b),Long.valueOf(bytesReadLength)); ((AbstractCollection) blockList).add(new BlockEntry(blockId)); } catch (Exception e) { e.printStackTrace(); } } index++; } } }
阅读全文
0 0
- 实习总结三:文件迁移
- 三周实习总结
- 实习三周总结
- 实习项目三总结
- 实习总结(三)---Java语言特点
- laravel (三) laravel自定义迁移文件
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- 实习总结
- python学习总结---python注释方法
- Tubor C 直线裁剪算法 Cohen-Sutherland算法 (可运行代码)
- Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
- Eureka单节点及高可用(详细配置)
- 通过Function Score Query优化Elasticsearch搜索结果(综合排序)
- 实习总结三:文件迁移
- 个人订阅号认证步骤,个人公众号如何认证看这里巧妙绕过腾讯规则2天搞定认证
- 项目和中的前端页面
- 【Java】2.垃圾回收机制 读书笔记
- 通威太阳能打造全球最大太阳能电池“智慧工厂”
- HTTP状态码
- python 操作redis
- 第一次机房收费系统-VB变量和常量命名格式
- Default Activity not found---Android studio