<!--阿里云对象存储服务-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
</dependency>
@RestController
@RequestMapping(value = "/file")
@AllArgsConstructor(onConstructor_ = {@Autowired})
public class FileController {
private FileService fileService;
@ApiOperation(value = "公共文件上传")
@PostMapping("/upload/commons")
public AjaxResult commonsUpload(@RequestParam(name = "file") MultipartFile multipartFile) {
return AjaxResult.success(fileService.fileUpload(multipartFile, FileType.COMMONS));
}
@ApiOperation(value = "私密文件上传")
@PostMapping("/upload/secret")
public AjaxResult secretUpload(@RequestParam(name = "file") MultipartFile multipartFile) {
return AjaxResult.success(fileService.fileUpload(multipartFile, FileType.SECRET));
}
@ApiOperation(value = "私密文件下载")
@PostMapping("/download/secret")
public AjaxResult secretDownload(@Validated @RequestBody ReqDownloadSecretFile fileName, HttpServletResponse response) {
fileService.secretDownload(fileName, response);
return AjaxResult.success();
}
/**
* @author
* @version 1.0
* @date 2018-12-28 16:58
**/
@Service
@AllArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
public class FileServiceImpl implements FileService {
private OSSClientUtil ossClientUtil;
private FileCheckUtil fileCheckUtil;
/**
* 文件上传
*
* @param multipartFile
*/
@Override
public String fileUpload(MultipartFile multipartFile, FileType type) {
boolean flag = type.equals(FileType.COMMONS);
fileCheckUtil.fileCheck(multipartFile.getOriginalFilename(), multipartFile.getSize());
//获得阿里OSSClient实例
try {
OSSClient ossClient = ossClientUtil.getOSSClient();
// 创建上传文件的元信息,可以通过文件元信息设置HTTP header。
ObjectMetadata meta = new ObjectMetadata();
meta.setContentDisposition("inline; filename=" + multipartFile.getOriginalFilename());
// 上传文件
String fileName = type.getMsg() + "/" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + "_" + multipartFile.getOriginalFilename();
ossClient.putObject(FileParams.bucketName, fileName, multipartFile.getInputStream(), meta);
if (flag) {
// 设置文件的访问权限为公共读。
ossClient.setObjectAcl(FileParams.bucketName, fileName, CannedAccessControlList.PublicRead);
}
ossClient.shutdown();//关流
return flag ? FileParams.bucketName + "." + FileParams.endpoint +"/"+ fileName : fileName;
} catch (Exception e) {
log.error("文件上传失败:" + e);
throw new ApiAssertException(FileErrorCodeEnum.FILE_UPLOAD_ERROR);
}
}
/**
* 私密文件下载
*
* @param fileName
*/
@Override
public void secretDownload(ReqDownloadSecretFile fileName, HttpServletResponse response) {
try {
OSSClient ossClient = ossClientUtil.getOSSClient();
// ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
OSSObject ossObject = ossClient.getObject(FileParams.bucketName, fileName.getFileName());
InputStream is = ossObject.getObjectContent();
byte[] buffer = readInputStream(is);
response.reset();
// 获取原始文件名
String downloadName = ossClient.getObjectMetadata(FileParams.bucketName, fileName.getFileName()).getContentDisposition().split("=")[1];
// 设置response的Header
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downloadName, "UTF-8"));
response.addHeader("Content-Length", "" + buffer.length);
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
toClient.write(buffer);
toClient.flush();
toClient.close();
response.flushBuffer();
} catch (Exception e) {
log.error("下载私密文件异常!" + e);
throw new ApiAssertException(FileErrorCodeEnum.FILE_SECRET_DOWNLOAD_ERROR);
}
}
/**
* 从输入流中获取数据
*/
private static byte[] readInputStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[10240];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
inStream.close();
return outStream.toByteArray();
}
}
/**
* 私密文件下载
*/
@Data
@ApiModel(description = "私密文件下载")
public class ReqDownloadSecretFile {
/**
* 文件名
*/
@NotEmpty(message = "文件名不能为空")
@ApiModelProperty(value = "文件名",dataType = "String",required = true)
private String fileName;
}
/**
* 上传文件类型/大小校验工具
*
* @author sunziwen
* @version 1.0
* @date 2018-12-28 16:58
**/
@Component
public class FileCheckUtil {
/**
* @param originalFilename 文件全名
* @param fileSize 文件大小
*/
public void fileCheck(String originalFilename, long fileSize) {
Set<String> types = fileTypeConfigCheck();
if (types == null) {
return;
}
ApiAssert.isTrue(FileErrorCodeEnum.FILE_TYPE_ERROR, types.contains(FilenameUtils.getExtension(originalFilename)));
ApiAssert.isTrue(FileErrorCodeEnum.FILE_SIZE_ERROR, fileSize < FileParams.picMaxSize);
}
/**
* 获取允许上传的文件类型
*/
private Set<String> fileTypeConfigCheck() {
//允许所有文件类型
if (allowFileTypes.length == 1 && FileType.ALL.name().equals(allowFileTypes[0])) {
return null;
}
return CollUtil.newHashSet(allowFileTypes);
}
}
/**
* OSS连接工具
*
* @author
* @version 1.0
* @date 2018-12-28 16:58
**/
@Component
public class OSSClientUtil {
public OSSClient getOSSClient() {
// 设置OSS连接配置
ClientConfiguration conf = getClientConfiguration();
// 创建OSS连接实例。
return new OSSClient(endpoint, accessKeyId, accessKeySecret, conf);
}
/**
* 设置OSS连接配置
*/
private ClientConfiguration getClientConfiguration() {
// 创建ClientConfiguration实例,按照您的需要修改默认参数。
ClientConfiguration conf = new ClientConfiguration();
// 设置OSSClient允许打开的最大HTTP连接数,默认为1024个。
conf.setMaxConnections(200);
// 设置Socket层传输数据的超时时间,默认为50000毫秒。
conf.setSocketTimeout(10000);
// 设置建立连接的超时时间,默认为50000毫秒。
conf.setConnectionTimeout(10000);
// 设置从连接池中获取连接的超时时间(单位:毫秒),默认不超时。
conf.setConnectionRequestTimeout(1000);
// 设置连接空闲超时时间。超时则关闭连接,默认为60000毫秒。
conf.setIdleConnectionTime(60000);
// 设置失败请求重试次数,默认为3次。
conf.setMaxErrorRetry(5);
// 设置是否支持将自定义域名作为Endpoint,默认支持。
conf.setSupportCname(true);
// 设置是否开启二级域名的访问方式,默认不开启。
conf.setSLDEnabled(false);
// 设置连接OSS所使用的协议(HTTP/HTTPS),默认为HTTP。
conf.setProtocol(Protocol.HTTPS);
return conf;
}
}
/**
* 文件服务异常
*
* @author
* @version 1.0
* @date 2018-12-28 10:32
**/
public enum FileErrorCodeEnum implements ErrorCodeInterface {
/**
* 文件类型不支持
*/
FILE_TYPE_ERROR(HttpServletResponse.SC_BAD_REQUEST, true, "文件类型不支持"),
/**
* 文件上传失败
*/
FILE_UPLOAD_ERROR(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, true, "文件上传失败"),
/**
* 私密文件下载失败
*/
FILE_SECRET_DOWNLOAD_ERROR(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, true, "私密文件下载失败"),
/**
* 超出文件大小限制
*/
FILE_SIZE_ERROR(HttpServletResponse.SC_BAD_REQUEST, true, "超出文件大小限制"),;
private final int httpCode;
private final boolean show;
private final String msg;
FileErrorCodeEnum(int httpCode, boolean show, String msg) {
this.httpCode = httpCode;
this.show = show;
this.msg = msg;
}
@Override
public ErrorCode toErrorCode() {
return ErrorCode.builder().httpCode(httpCode).show(show).error(name()).msg(msg).build();
}
@Override
public String getMsg() {
return msg;
}
}
public enum FileType {
/**
* 公共上传
*/
COMMONS(1, "COMMONS"),
/**
* 私密上传
*/
SECRET(2, "SECRET"),
/**
* 允许所有文件类型上传
*/
ALL(3, "ALL"),;
private int code;
private String msg;
FileType(int code, String msg) {
this.code = code;
this.msg = msg;
}
FileType(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
public FileType setMsg(String msg) {
this.msg = msg;
return this;
}
}