阅读 17 SEO

SpringBoot2.x整合(cos,oss,本地挂载盘)文件存储的小而美的项目实现

由于项目升级,文件存储由本地磁盘(挂载盘)升级为cos(腾讯云)存储,由此实现了一套整合各家文件存储的项目。

1. 设计思想

1.1 使用到的设计模式

  1. 例如cos和oss提供的client不同,以及本地磁盘存储需要自己实现client端。所以需要自己实现一个公共的接口,使用适配器模式,将各种client端转换为统一的client接口实现;
  2. 业务端依旧使用Template类操作文件,Template类使用模板方法模式,来支持业务放进行扩展。
  3. Template类通过组合的方式选择client类,使用策略模式来自由的切换存储介质(cos,oss,本地磁盘)。

1.2 设计思想

项目默认提供cos腾讯云存储和本地挂载盘存储的template类。当业务方在依赖中移除腾讯cos的依赖,且使用阿里云oss的依赖后。template类将自动切换为阿里云oss的存储。

        <dependency>
            <groupId>com.tellme</groupId>
            <artifactId>xos-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <artifactId>cos_api</artifactId>
                    <groupId>com.qcloud</groupId>
                </exclusion>
                <exclusion>
                    <groupId>com.tencent.cloud</groupId>
                    <artifactId>cos-sts-java</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>2.8.3</version>
        </dependency>

其思想借鉴与SpringBoot2.x-Redis实现Jedis客户端和Lettuce客户端的切换。

2. 代码实现

2.1 pom依赖

pom依赖中,使用SpringBoot2.0.4版本。

引入了

  1. 腾讯云cos提供的jar;
  2. 阿里云oss提供的jar;
  3. 以及相关的工具jar;

当然阿里云oss的依赖不向下传递。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tellme</groupId>
    <artifactId>xos-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- 通信-->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.8.1</version>
        </dependency>


        <dependency>
            <groupId>com.qcloud</groupId>
            <artifactId>cos_api</artifactId>
            <version>5.6.8</version>
        </dependency>
        <dependency>
            <groupId>com.tencent.cloud</groupId>
            <artifactId>cos-sts-java</artifactId>
            <version>3.0.5</version>
        </dependency>
        <!--jar不向下传递(阿里云oos)-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>2.8.3</version>
            <scope>provided</scope>
        </dependency>


    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.0.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2.2 starter的实现

在spring.factories文件中定义自动装配的类。

image.png
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.tellme.os.config.OSAutoConfiguration

2.3 client端(适配器模式)

首先是需要提供一个项目内公共的接口类(OSClient)。无论各个厂商的client客户端都要进行适配。

public interface OSClient {

    /**
     * 上传文件
     *
     * @param storageName  (bucketName)存储桶
     * @param relativePath 文件上传的地址
     * @param fileBytes    文件流
     */
    void uploadFile(String storageName, String relativePath, byte[] fileBytes);

    /**
     * 下载文件
     *
     * @param filePath 文件地址
     * @return 文件输出流
     */
    ByteArrayOutputStream downloadFile(String filePath);

    /**
     * 客户端关闭
     */
    void shutdown();
}

由于云文件存储,下载文件的方法是相同的,故可以使用模板方法模式来进行扩展。

@Slf4j
public abstract class NetOsClient implements OSClient {

    @Override
    public ByteArrayOutputStream downloadFile(String filePath) {
        ByteArrayOutputStream data;
        data = OkHttpUtil.get(filePath);
        if (data == null) {
            throw new OsException("下载照片失败,照片地址:" + filePath);
        }
        //转换流信息
        return data;
    }

}

2.3.1 适配腾讯云cos客户端

@Data
public class CosClient extends NetOsClient {

    private COSClient cosClient;

    /**
     *
     * @param bucketName   存储桶
     * @param relativePath 文件上传的地址
     * @param fileBytes    文件流
     */
    @Override
    public void uploadFile(String bucketName, String relativePath, byte[] fileBytes) {
        ByteArrayInputStream input = new ByteArrayInputStream(fileBytes);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        // 设置输入流长度
        objectMetadata.setContentLength(input.available());
        cosClient.putObject(bucketName, relativePath, input, objectMetadata);
    }
    /**
     * 关闭客户端
     */
    @Override
    public void shutdown() {
        cosClient.shutdown();
    }
}

2.3.2 适配阿里云oss客户端

@Data
public class OssClient extends NetOsClient{

    private OSSClient ossClient;

    @Override
    public void uploadFile(String bucketName, String relativePath, byte[] fileBytes) {
        ByteArrayInputStream input = new ByteArrayInputStream(fileBytes);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        // 设置输入流长度
        objectMetadata.setContentLength(input.available());
        ossClient.putObject(bucketName, relativePath, input, objectMetadata);
    }

    @Override
    public void shutdown() {
        ossClient.shutdown();
    }
}

2.3.3 适配本地挂载盘客户端

@Slf4j
public class FileOsClient implements OSClient {

    /**
     * @param bucketName  上传的根路径
     * @param relativePath 文件上传的地址
     * @param fileBytes    文件流
     */
    @Override
    public void uploadFile(String bucketName, String relativePath, byte[] fileBytes) {
        File file = new File(bucketName + File.separator + relativePath);
        //获取文件夹目录
        String fullPath = file.getParent();
        File dir = new File(fullPath);
        //创建目录
        dir.mkdirs();
        try {
            //构建输出流
            ByteArrayInputStream is = new ByteArrayInputStream(fileBytes);
            FileOutputStream os = new FileOutputStream(file);
            byte[] b = new byte[1024];
            int nRead;
            while ((nRead = is.read(b)) != -1) {
                os.write(b, 0, nRead);
            }
        } catch (Exception e) {
            log.error("", e);
            throw new OsException("", e);
        }
    }

    /**
     * 读取本地文件
     *
     * @param filePath 文件地址
     * @return 文件数组输出流
     */
    @Override
    public ByteArrayOutputStream downloadFile(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new OsException("文件不存在!");
        }
        InputStream is = IOUtil.getInputStream(file);
        return IOUtil.convertInputStream(is);
    }

    @Override
    public void shutdown() {

    }

}

2.4 template类(模板模式+策略模式)

  1. template通过组合的方式引入client对象,在Spring容器初始化的时候选择合适的client策略。
  2. template采用模板方法模式,可自由扩展。
public interface OsTemplate {

    /**
     * 上传文件
     *
     * @param relativePath 上传文件的相对地址
     * @param fileBytes    文件流
     * @return 上传后的地址
     */
    String saveFile(String relativePath, byte[] fileBytes);

    /**
     * 拼接路径,上传照片
     *
     * @param modulePath 项目路径
     * @param fileSuffix 文件后缀
     * @param base64Str  base64
     * @return 格式:{@code PATH_COMMON / modulePath / calculatePath() /UUID.randomUUID() + fileSuffixEnum.getType()}
     */
    String saveFile(String modulePath, String fileSuffix, String base64Str);

    /**
     * 拼接路径,上传文件
     *
     * @param modulePath 项目路径
     * @param fileBytes  文件流
     * @param fileSuffix 文件后缀
     * @return 格式:{@code PATH_COMMON / modulePath / calculatePath() /UUID.randomUUID() + fileSuffixEnum.getType()}
     */
    String saveFile(String modulePath, byte[] fileBytes, String fileSuffix);


    /**
     * 拼接路径,上传到特定的存储桶
     *
     * @param bucketName 存储桶的名字
     * @param modulePath 项目路径
     * @param fileSuffix 文件后缀
     * @param fileBytes  文件流
     * @return 格式:{@code PATH_COMMON / modulePath / calculatePath() /UUID.randomUUID() + fileSuffix}
     */
    String saveFile(String bucketName, String modulePath, String fileSuffix, byte[] fileBytes);

    /**
     * 拼接路径,上传到特定的存储桶
     *
     * @param bucketName   存储桶的名字
     * @param relativePath 文件的相对路径
     * @param fileBytes    文件流
     * @return 格式:{@code PATH_COMMON / modulePath / calculatePath() /UUID.randomUUID() + fileSuffix}
     */
    String saveFile(String bucketName, String relativePath, byte[] fileBytes);


    /**
     * 文件下载
     *
     * @param filePath 文件地址
     * @return 下载字节流
     */
    ByteArrayOutputStream downloadFile(String filePath);

    /**
     * CDN前缀地址
     *
     * @return CDN地址
     */
    String getCdnHost();
}

2.4.1 云存储的template

@Data
@Slf4j
public class NetOsTemplate implements OsTemplate {

    //cos连接对象
    protected OSClient client;

    protected OsConfigProperties osConfigProperties;

    /**
     * 存储介质:
     * cos存储的是:bucketName
     * file存储的是:根路径
     */
    protected String bucketName;

    /**
     * cdn地址
     */
    protected String cdnHost;

    protected static  String PATH_COMMON = "/xos";


    /**
     * (经常使用)使用配置文件的存储桶上传照片
     *
     * @param modulePath 模块路径
     * @param fileSuffix 文件后缀,需要携带.
     * @param base64Str  照片的base64信息
     * @return 图片上传的地址
     */
    public String saveFile(String modulePath, String fileSuffix, String base64Str) {
        return saveFile(bucketName, modulePath, fileSuffix, IOUtil.base64ToBytes(base64Str));
    }


    /**
     * (经常使用)使用配置文件的存储桶上传文件
     *
     * @param modulePath 模块路径
     * @param fileSuffix 文件后缀,需要携带.
     * @param fileBytes  文件流字节数组
     * @return 图片上传的地址
     */
    public String saveFile(String modulePath, byte[] fileBytes, String fileSuffix) {
        return saveFile(bucketName, modulePath, fileSuffix, fileBytes);
    }

    /**
     * 腾讯云上传文件
     * 只需要传入模块目录,自动拼装上传腾讯云的路径。
     * {@code PATH_COMMON / modulePath / calculatePath() /UUID.randomUUID() + fileSuffixEnum.getType()}
     *
     * @param bucketName 存储目录
     * @param modulePath  模块路径(业务路径格式:{@code exercise/plan/answerImage })
     * @param fileSuffix  文件后缀,需要携带.
     * @param fileBytes   文件流字节数组
     * @return 图片上传的地址
     */
    public String saveFile(String bucketName, String modulePath, String fileSuffix, byte[] fileBytes) {
        return saveFile(bucketName, getRelativeDir(modulePath) + getFileName(fileSuffix), fileBytes);
    }

    /**
     * 腾讯云上传文件
     * 返回的路径:{@code PATH_COMMON / modulePath / calculatePath() /UUID.randomUUID() + fileSuffix}
     *
     * @param relativePath 上传文件的相对地址
     * @param fileBytes    文件流
     * @return 保存到腾讯云的地址
     */
    @Override
    public String saveFile(String relativePath, byte[] fileBytes) {
        //读取配置信息的存储桶信息
        return saveFile(bucketName, relativePath, fileBytes);
    }

    /**
     * 腾讯云上传文件
     *
     * @param bucketName  存储桶
     * @param relativePath 文件的相对地址
     * @param fileBytes    文件流的字节数组
     * @return 腾讯云上的相对地址
     */
    public String saveFile(String bucketName, String relativePath, byte[] fileBytes) {
        client.uploadFile(bucketName, relativePath, fileBytes);
        return relativePath;
    }


    /**
     * 文件下载
     * 若下载失败或者照片不存在,抛出{@link com.xdf.pscommon.os.exception.OsException}异常。
     *
     * @param filePath 文件地址
     * @return 文件输出流
     */
    @Override
    public ByteArrayOutputStream downloadFile(String filePath) {
        return client.downloadFile(filePath);
    }


    /**
     * 获取腾讯云的前缀地址
     *
     * @return 腾讯云的CDN地址
     */
    public String getCdnHost() {
        return cdnHost;
    }

    /**
     * 创建文件夹的相对路径
     *
     * @return 格式:{@code exam/modulePath/2021/11/1}
     */
    protected String getRelativeDir(String modulePath) {
        return PATH_COMMON + File.separator + modulePath + File.separator + calculatePath();
    }

    /**
     * 创建文件名(使用UUID创建)
     */
    protected String getFileName(String fileSuffix) {
        return UUID.randomUUID() + fileSuffix;
    }

    /**
     * 时间戳作为路径名
     */
    protected String calculatePath() {
        Calendar calendar = Calendar.getInstance();
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        String month = String.valueOf(calendar.get(Calendar.MONTH) + 1);
        String date = String.valueOf(calendar.get(Calendar.DATE));
        return year + "/" + month + "/" + date + "/";
    }

}

2.4.2 挂载盘存储的template

挂载盘在创建目录时,需要随机路由到不同的挂载盘上,所以需要重写getRelativeDir方法即可。

public class FileOsTemplate extends NetOsTemplate {

    private long index;

    private final static String ROOTPATH = "rootPath";
    private final static String FORWARDMARK = "forwardMark";


    /**
     * 路径填充挂载盘路径
     */
    @Override
    public String getRelativeDir(String modulePath) {
        OperatingSystemEnum operatingSystem = IOUtil.getOperatingSystem();
        if (OperatingSystemEnum.LINUX.equals(operatingSystem) &&
                osConfigProperties.getFile().getRootPath() != null &&
                osConfigProperties.getFile().getRootPath().size() > 1) {
            Map<String, String> rootPathMap = returnRootPathMap(osConfigProperties.getFile().getRootPath());
            return PATH_COMMON + File.separator + rootPathMap.get(FORWARDMARK) + File.separator + modulePath + File.separator + calculatePath();
        } else {
            return super.getRelativeDir(modulePath);
        }
    }

    /**
     * 返回挂载盘的具体配置
     */
    private Map<String, String> returnRootPathMap(Map<String, String> rootPaths) {
        int size = 2; //最少有个原磁盘以及加的共享盘,共享磁盘个数
        if (rootPaths != null && rootPaths.size() > 1) {
            size = rootPaths.size() - 1;
        }
        int rootPathIndex = Math.toIntExact(index++ % size);
        Map<String, String> rootPathMap = new HashMap<>();
        switch (rootPathIndex) {
            case 0:
                rootPathMap.put(ROOTPATH, rootPaths.get("files1"));
                rootPathMap.put(FORWARDMARK, "files1/");
                break;
            case 1:
                rootPathMap.put(ROOTPATH, rootPaths.get("files2"));
                rootPathMap.put(FORWARDMARK, "files2/");
                break;
            case 2:
                rootPathMap.put(ROOTPATH, rootPaths.get("files3"));
                rootPathMap.put(FORWARDMARK, "files3/");
                break;
            default:
                rootPathMap.put(ROOTPATH, rootPaths.get("files"));
                rootPathMap.put(FORWARDMARK, "files/");
                break;
        }
        return rootPathMap;
    }

}

2.5 加入到Spring容器中

  1. 使用@ConditionalOnClass注解,当某个依赖存在时,才加载bean类;
  2. 使用@ConditionalOnProperty注解,当某个配置存在时,才加载bean类;
  3. 使用@Import注解,当多个配置均存在时,优先加载哪个配置;
  4. 配合@ConditionalOnMissingBean(name = "netOsTemplate")注解,当加载某个配置后,便不加载同名的bean。

2.5.1 配置类

当本地磁盘加载时,支持windows,mac,linux各个配置。

@Data
@ConfigurationProperties("xos")
public class OsConfigProperties {

    /**
     * 腾讯云COS配置
     */
    private CosProperties cos;

    /**
     * 阿里云OOS配置
     */
    private OssProperties oss;
    /**
     * 共享盘文件存储配置
     */
    private FileProperties file;

    /**
     * 云存储——存储桶
     */
    private String bucketName;
    /**
     * 云存储——cdn地址
     */
    private String cdnHost;

    @Data
    public static class CosProperties {

        private String accessKeyId;

        private String accessKeySecret;

        private String region;


    }


    @Data
    public static class OssProperties {
        private String endpoint;

        private String accessKeyId;

        private String accessKeySecret;

    }


    @Data
    public static class FileProperties {
        /**
         * Linux支持的根路径
         */
        private String linuxRootPath;
        /**
         * window支持的根路径
         */
        private String windowsRootPath;
        /**
         * mac支持的根路径
         */
        private String macRootPath;

        /**
         * Linux系统设置,挂载盘映射关系
         */
        private Map<String, String> rootPath;
        /**
         * cdn地址
         */
        private String cdnHost;
    }
}

2.5.2 腾讯云cos的client加入到Spring中

只有存在COSClient.class类且存在xos.cos.accessKeyId配置时,才会加载改bean。

@Configuration
@ConditionalOnClass(COSClient.class)
public class CosClientConfiguration {

    /**
     * 初始化腾讯云客户端
     */
    @Bean(name = "netOSClient", destroyMethod = "shutdown")
    @ConditionalOnProperty("xos.cos.accessKeyId")
    @ConditionalOnMissingBean(name = "netOSClient")
    public OSClient cosClient(OsConfigProperties osConfigProperties) {
        CosClient cosClient = new CosClient();
        OsConfigProperties.CosProperties cosProperties = osConfigProperties.getCos();
        // 1 初始化用户身份信息(secretId, secretKey)。
        COSCredentials cred = new BasicCOSCredentials(cosProperties.getAccessKeyId(), cosProperties.getAccessKeySecret());
        // 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region cosRegion = new Region(cosProperties.getRegion());
        ClientConfig clientConfig = new ClientConfig(cosRegion);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        cosClient.setCosClient(cosClient);
        return cosClient;
    }

}

2.5.3 阿里云oss的client加入到Spring容器

@Configuration
@ConditionalOnClass(OSSClient.class)
public class OssClientConfiguration {

    /**
     * 初始化阿里云oss客户端
     */
    @Bean(name = "netOSClient", destroyMethod = "shutdown")
    @ConditionalOnProperty("xos.oss.accessKeyId")
    @ConditionalOnMissingBean(name = "netOSClient")
    public  OSClient ossClient(OsConfigProperties osConfigProperties) {
        OssClient ossClient = new OssClient();
        OsConfigProperties.OssProperties ossProperties = osConfigProperties.getOss();
        OSSClient ossClient = new OSSClient(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
        ossClient.setOssClient(ossClient);
        return ossClient;
    }
}

2.5.4 自动装配的config

  1. @EnableConfigurationProperties将配置文件类加入到Spring容器;
  2. @Import({CosClientConfiguration.class,OssClientConfiguration.class})将config类加入到Spring容器;
@Slf4j
@Configuration
@EnableConfigurationProperties(value = OsConfigProperties.class)
@Import({CosClientConfiguration.class,OssClientConfiguration.class})
public class OSAutoConfiguration {



    /**
     * 初始化文件流客户端
     */
    @Bean
    @ConditionalOnMissingBean(name = "fileClient")
    public lFileOsClient fileClient(OsConfigProperties osConfigProperties) {
        return new FileOsClient();
    }


    /**
     * 创建云存储的模板类
     *
     * @param oSClient           cos的客户端
     * @param osConfigProperties 配置信息
     * @return 模板工具类
     */
    @Bean
    @Primary
    @ConditionalOnBean(name = {"netOSClient"})
    @ConditionalOnMissingBean(name = "netOsTemplate")
    public NetOsTemplate netOsTemplate(@Qualifier("netOSClient") OSClient oSClient, OsConfigProperties osConfigProperties) {
        NetOsTemplate osTemplate = new NetOsTemplate();
        //放入客户端
        osTemplate.setClient(oSClient);
        osTemplate.setBucketName(osConfigProperties.getBucketName());
        //配置文件
        osTemplate.setOsConfigProperties(osConfigProperties);
        osTemplate.setCdnHost(osConfigProperties.getCdnHost());
        return osTemplate;
    }

    /**
     * 共享盘OS的模板类
     */
    @Bean
    @ConditionalOnMissingBean(name = "fileOsTemplate")
    public OsTemplate fileOsTemplate(FileOsClient cosClient, OsConfigProperties osConfigProperties) {
        FileOsTemplate osTemplate = new FileOsTemplate();
        //放入客户端
        osTemplate.setClient(cosClient);
        OperatingSystemEnum operatingSystem = IOUtil.getOperatingSystem();
        osConfigProperties.FileProperties fileProperties =osConfigProperties.getFile();
        //获取对应的根路径
        String bucketName = null;
        String cdnHost = null;
        if (fileProperties != null) {
            if (OperatingSystemEnum.WINDOWS.equals(operatingSystem)) {
                bucketName = fileProperties.getWindowsRootPath();
            } else if (OperatingSystemEnum.MAC.equals(operatingSystem)) {
                bucketName = fileProperties.getMacRootPath();
            } else {
                bucketName = fileProperties.getLinuxRootPath();
            }
            cdnHost = fileProperties.getCdnHost();
        }
        if (bucketName == null) {
            log.warn("File root path is null. use '/' is root");
            //默认是根路径
            bucketName = "/";
        }
        if (cdnHost == null) {
            log.warn("File cdnHost is null.");
        }
        osTemplate.setCdnHost(cdnHost);

        //设置存储名字
        osTemplate.setBucketName(bucketName);
        //配置文件
        osTemplate.setOsConfigProperties(osConfigProperties);
        return osTemplate;
    }
}

2.6 工具类

@Slf4j
public abstract class IOUtil {


    /**
     * 输入流转换为输出流
     *
     * @param is 输入流
     * @return 输出流
     */
    public static ByteArrayOutputStream convertInputStream(InputStream is) {
        final byte[] by = new byte[1024];
        ByteArrayOutputStream data = new ByteArrayOutputStream();
        try {
            // 将内容读取内存中
            int len;
            while ((len = is.read(by)) != -1) {
                data.write(by, 0, len);
            }
        } catch (IOException e) {
            log.error("convertInputStream IO Exception", e);
        }
        return data;
    }

    /**
     * base64转化为byte[]字节流
     *
     * @param base64Str 照片的base64
     * @return 字节流
     */
    public static byte[] base64ToBytes(String base64Str) {
        if (StringUtils.isBlank(base64Str)) {
            throw new SealOsException("base64Str is blank!");
        }
        return Base64.decodeBase64(base64Str);
    }

    /**
     * 获取文件输入流
     *
     * @param file 文件对象
     * @return 文件输入流对象
     */
    public static InputStream getInputStream(File file) {
        FileInputStream fin;
        try {
            fin = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            if (log.isDebugEnabled()) {
                log.debug(String.valueOf(e));
            }
            String msg = "找不到指定的文件[" + file.getName() + "]。";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }
            throw new SealOsException(msg, e);
        }
        return fin;
    }

    /**
     * 获取当前系统的操作系统类型
     */
    public static OperatingSystemEnum getOperatingSystem() {
        if (System.getProperty("os.name").toUpperCase().contains("WINDOWS")) {
            return OperatingSystemEnum.WINDOWS;
        } else if (System.getProperty("os.name").toUpperCase().contains("MAC")) {
            return OperatingSystemEnum.MAC;
        } else {
            return OperatingSystemEnum.LINUX;
        }
    }

    /**
     * 文件后缀
     *
     * @param fileName 文件名或者文件路径
     * @return 后缀类型
     */
    public static String getFileSuffix(String fileName) {
        if (fileName == null) {
            return null;
        }
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 获取文件名
     */
    public static String getFileName(String filePath) {
        if (filePath == null) {
            return null;
        }
        File file=new File(filePath);
        return file.getName();
    }

    /**
     * 获取目录
     */
    public static String getDirName(String filePath) {
        if (filePath == null) {
            return null;
        }
        File file=new File(filePath);
        return file.getParent();
    }


}
public abstract class OkHttpUtil {

    /**
     * 最大连接时间
     */
    public final static int CONNECTION_TIMEOUT = 15;

    public final static Logger logger = LoggerFactory.getLogger(OkHttpUtil.class);

    /**
     * client
     * 配置重试
     */
    private final static OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
            .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
            .build();

    /**
     * get请求,无需转换对象
     *
     * @param url 链接
     * @return 响应信息
     */
    public static ByteArrayOutputStream get(String url) {
        try {
            Request request = new Request.Builder().url(url).build();
            Response response = HTTP_CLIENT.newCall(request).execute();

            if (response.isSuccessful() && response.body() != null) {
                InputStream inputStream = response.body().byteStream();
                return IOUtil.convertInputStream(inputStream);
            }
        } catch (Exception e) {
            logger.error("执行get请求,url: {} 失败!", url, e);
            throw new SealOsException(e);
        }
        return null;
    }
}

2.7 异常类

public class OsException extends RuntimeException {


    public OsException() {
    }

    public OsException(String message) {
        super(message);
    }

    public OsException(String message, Throwable cause) {
        super(message, cause);
    }

    public OsException(Throwable cause) {
        super(cause);
    }

    public OsException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
文章分类
后端
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 gxwowoo@163.com 举报,一经查实,本站将立刻删除。
相关推荐