1.下载前端调用接口 (流式下载大文件可能比较慢!也可以直接下载URL的方式)
@GetMapping(value = "/downloadFile") public void downloadFile(@RequestParam String ossPath, HttpServletResponse response) { BufferedInputStream input; OutputStream outputStream; OSS ossClient = OssUtil.getOssBean(); try { OSSObject ossObject = ossClient.getObject(OssUtil.BUCKET_NAME, ossPath); // response.reset(); response.setCharacterEncoding("utf-8"); response.setContentType("application/x-msdownload"); response.addHeader("Content-Disposition", "attachment;fileName=\"" new String(ossPath.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8) "\""); // "attachment;filename=" new String(ossPath.getBytes("gb2312"), "ISO8859-1")); input = new BufferedInputStream(ossObject.getObjectContent()); byte[] buffBytes = new byte[1024]; outputStream = response.getOutputStream(); int read; while ((read = input.read(buffBytes)) != -1) { outputStream.write(buffBytes, 0, read); } outputStream.flush(); // 读取数据后,必须关闭获取的流量,否则会造成连接泄漏,导致要求无连接可用,程序无法正常工作。 ossObject.close(); } catch (OSSException | ClientException | IOException oe) { oe.printStackTrace(); } finally { if (ossClient != null) { ossClient.shutdown(); } } }
2.简单上传接口,官方可以上传进度条api实现,这块不做实现。
@PassToken @ApiOperation("简单上传") @PostMapping(value = "/uploadFile") public RestResult<Object> saveFile(HttpServletRequest request) throws IOException { ///获得上传文件夹的名称 String folderName = request.getParameter("folderName"); Map<String, Object> map = new HashMap<>(); MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; MultipartFile multipartFile = multipartRequest.getFile("file"); // 获取文件名 assert multipartFile != null; String fileName = multipartFile.getOriginalFilename(); // 获取文件后缀名 assert fileName != null; String suffixName = fileName.substring(fileName.lastIndexOf(".")); // 最后上传生成的文件名 String substring = fileName.substring(0, fileName.lastIndexOf(".")); String previewName = substring System.currentTimeMillis() "" new SecureRandom().nextInt(0x0400) suffixName; // oss中文件夹名 String ossPreviewName = folderName "/" previewName; // 创建上传文件的元信息,可通过文件元信息设置HTTP header(通过返回链接设置直接访问)。 ObjectMetadata objectMetadata = new ObjectMetadata(); //设置文件类型 objectMetadata.setContentType(GetFileType.getContentType(suffixName)); Date expiration = new Date(System.currentTimeMillis() 3600L * 1000 * 24 * 365 * 50); //文件预览 if ("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(objectMetadata.getContentType()) || "application/vnd.ms-powerpoint".equals(objectMetadata.getContentType()) || "application/msword".equals(objectMetadata.getContentType())) { OssUtil.getOssBeanInner().putObject("你自己的bucketName", ossPreviewName, new ByteArrayInputStream(multipartFile.getBytes()), objectMetadata); GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest("你自己的bucketName", ossPreviewName, HttpMethod.GET); req.setExpiration(expiration); req.setProcess(OssUtil.STYLE); map.put("previewUrl", OssUtil.getOssBeanOut().generatePresignedUrl(req)); } else { OssUtil.getOssBeanInner().putObject("你自己的bucketName", ossPreviewName, new ByteArrayInputStream(multipartFile.getBytes()), objectMetadata); String previewUrl = OssUtil.getOssBeanOut().generatePresignedUrl("你自己的bucketName", ossPreviewName, expiration).toString(); map.put("previewUrl", previewUrl); } map.put("fileName", fileName); map.put("ossPreviewName", ossPreviewName); map.put("fileType", suffixName); OssUtil.getOssBeanInner().shutdown(); OssUtil.getOssBeanOut().shutdown(); return RestResult.result(CommonResult.UPLOAD_SUCCESS, map); }
3.分片上传,官方分片上传不支持进度条,我用这个redis实现,也可用session
@PassToken @PostMapping(value = "/multipartUpload") public RestResult<Object> multipartUpload(HttpServletRequest request) throws Exception { MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; MultipartFile multipartFile = multipartRequest.getFile("file"); assert multipartFile != null; String fileame = multipartFile.getOriginalFilename();
assert fileName != null;
String suffixName = fileName.substring(fileName.lastIndexOf("."));
// 创建InitiateMultipartUploadRequest对象。
InitiateMultipartUploadRequest iuRequest = new InitiateMultipartUploadRequest(OssUtil.BUCKET_NAME, "test/" + fileName);
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType(GetFileType.getContentType(suffixName));
//设置文件类型
iuRequest.setObjectMetadata(objectMetadata);
InitiateMultipartUploadResult upresult = OssUtil.getOssBeanInner().initiateMultipartUpload(iuRequest);
// 返回uploadId,它是分片上传事件的唯一标识。您可以根据该uploadId发起相关的操作,例如取消分片上传、查询分片上传等。
String uploadId = upresult.getUploadId();
// partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
List<PartETag> partETags = new ArrayList<PartETag>();
// 每个分片的大小,用于计算文件有多少个分片。单位为字节。
final long partSize = 10 * 1024 * 1024L;
long fileLength = multipartFile.getSize();
int partCount = (int) (fileLength / partSize);
System.err.println(partCount);
if (fileLength % partSize != 0) {
partCount++;
}
// 遍历分片上传。
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
InputStream inputStream = multipartFile.getInputStream();
// 跳过已经上传的分片。
long skip = inputStream.skip(startPos);
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(OssUtil.BUCKET_NAME);
uploadPartRequest.setKey("test/" + fileName);
uploadPartRequest.setUploadId(uploadId);
uploadPartRequest.setInputStream(inputStream);
// 设置分片大小。除了最后一个分片没有大小限制,其他的分片最小为100 KB。
uploadPartRequest.setPartSize(curPartSize);
// 设置分片号。每一个上传的分片都有一个分片号,取值范围是1~10000,如果超出此范围,OSS将返回InvalidArgument错误码。
uploadPartRequest.setPartNumber(i + 1);
// 每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会按照分片号排序组成完整的文件。
UploadPartResult uploadPartResult = OssUtil.getOssBeanInner().uploadPart(uploadPartRequest);
// 每次上传分片之后,OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
partETags.add(uploadPartResult.getPartETag());
BigDecimal div = BigDecimalUtil.div(i * 100, partCount);
redisUtils.set("nowN", div.toString());
}
// 创建CompleteMultipartUploadRequest对象。
// 在执行完成分片上传操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(OssUtil.BUCKET_NAME, "test/" + fileName, uploadId, partETags);
redisUtils.set("nowN", "100", 10000);
// 完成分片上传。
CompleteMultipartUploadResult completeMultipartUploadResult = OssUtil.getOssBeanInner().completeMultipartUpload(completeMultipartUploadRequest);
String previewUrl = OssUtil.getOssBeanOut().generatePresignedUrl("你自己的bucketName","test/" + fileName , new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 50)).toString();
final String location = completeMultipartUploadResult.getLocation();
OssUtil.getOssBeanInner().shutdown();
OssUtil.getOssBeanOut().shutdown();
Map<String,Object> map = new HashMap<>();
map.put("previewUrl",URLDecoder.decode(previewUrl,"UTF-8"));
return RestResult.result(CommonResult.SUCCESS, map);
}
4,工具类Ossutil
@Slf4j
public class OssUtil {
public static final String STYLE = "imm/previewdoc,copy_1";
/**
* 查看自己的节点
* (接口调用的话)内网上传 oss地址
*/
public static final String INNER_ENDPOINT = "https://oss-cn-beijing-internal.aliyuncs.com";
/**
* 查看自己的节点
* (接口调用的话)外网下载或预览 oss地址 oss-cn-beijing.aliyuncs.com
*/
public static final String OUT_ENDPOINT = "https://oss-cn-beijing.aliyuncs.com";
public static final String KEY_ID = "你自己的";
public static final String KEY_SECRET = "你自己的";
public static final String BUCKET_NAME = "你自己的";
public static void delOssFile(String fileName) {
if (fileName.isEmpty()){
return;
}
OSS oss = new OSSClientBuilder().build(OUT_ENDPOINT, KEY_ID, KEY_SECRET);
oss.deleteObject(BUCKET_NAME, fileName);
oss.shutdown();
}
public static void delOssFile(String ossPreviewName,String ossDownloadName) {
if (ossPreviewName.isEmpty()||ossDownloadName.isEmpty()){
return;
}
OSS oss = new OSSClientBuilder().build(OUT_ENDPOINT, KEY_ID, KEY_SECRET);
oss.deleteObject(BUCKET_NAME, ossPreviewName);
oss.shutdown();
}
public static OSS getOssBeanInner(){
return new OSSClientBuilder().build(INNER_ENDPOINT, KEY_ID, KEY_SECRET);
}
public static OSS getOssBeanOut(){
return new OSSClientBuilder().build(OUT_ENDPOINT, KEY_ID, KEY_SECRET);
}
public static class PutObjectProgressListener implements ProgressListener {
private HttpSession session;
private long bytesWritten = 0;
private long totalBytes = -1;
private boolean succeed = false;
private int percent = 0;
//构造方法中加入session
public PutObjectProgressListener() {
}
public PutObjectProgressListener(HttpSession mSession) {
this.session = mSession;
session.setAttribute("upload_percent", percent);
}
@Override
public void progressChanged(ProgressEvent progressEvent) {
long bytes = progressEvent.getBytes();
ProgressEventType eventType = progressEvent.getEventType();
switch (eventType) {
case TRANSFER_STARTED_EVENT:
log.info("Start to upload......");
break;
case REQUEST_CONTENT_LENGTH_EVENT:
this.totalBytes = bytes;
log.info(this.totalBytes + " bytes in total will be uploaded to OSS");
break;
case REQUEST_BYTE_TRANSFER_EVENT:
this.bytesWritten += bytes;
if (this.totalBytes != -1) {
percent = (int) (this.bytesWritten * 100.0 / this.totalBytes);
//将进度percent放入session中
session.setAttribute("upload_percent", percent);
log.info(bytes + " bytes have been written at this time, upload progress: " + percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
} else {
log.info(bytes + " bytes have been written at this time, upload ratio: unknown" + "(" + this.bytesWritten + "/...)");
}
break;
case TRANSFER_COMPLETED_EVENT:
this.succeed = true;
log.info("Succeed to upload, " + this.bytesWritten + " bytes have been transferred in total");
break;
case TRANSFER_FAILED_EVENT:
log.info("Failed to upload, " + this.bytesWritten + " bytes have been transferred");
break;
default:
break;
}
}
public boolean isSucceed() {
return succeed;
}
}
}