<!--阿里云对象存储服务-->
        <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;
    }
}