搭建自用单点OOS服务

学习小项目系列目录

项目1:SSM + Layui + Mysql8 公司测评系统
项目2:SpringBoot+Vue+ Mysql8 大学社团管理系统
项目3:搭建自用单点OOS服务
项目4:搭建一套自己的验证授权及资源访问服务

文章目录

  • 学习小项目系列目录
  • 前言
    • 一、安装MinIo
    • 二、自定义`starter`
      • 2.1 `starter`命名规范
      • 2.2 创建`maven`工程
        • 2.1.1 项目目录结构
        • 2.1.2 依赖
      • 2.3 编写配置文件
        • 2.2.1 启动配置文件映射实体
        • 2.2.1 配置类
      • 2.4 编写 spring.factories
      • 2.5 完成业务逻辑工程
      • 2.6 自定义`banner`
        • 2.6.1 生成
          • 2.6.2 配置
      • 2.7 打包部署到本地仓库
      • 2.8 完整代码地址
    • 三、开发`service`
      • 3.1 创建`SpringBoot`项目
        • 3.1.1 项目结构概览
        • 3.1.2 依赖
      • 3.2配置包扫描
      • 3.2配置文件
      • 3.3接口开发
      • 2.4 完整代码地址
    • 四、启动测试
      • 4.1 `banner`
      • 4.2 准备好`MinIo`服务
      • 4.3测试文件上传
        • 4.3.1 上传
        • 4.3.2 验证

前言

本篇文章记录了搭建自用单点OOS服务的过程,避坑记录等。采用SpingBoot自定义starter形式,构建自己的文件存储服务。主要涉及到的技术有:SpringBoot、Docker 、MinIo。

一、安装MinIo

详细见我的另外一片文章。https://blog.csdn.net/qq_38020915/article/details/117386512

二、自定义starter

2.1 starter命名规范

  • Spring 官方命名规则
    • 前缀:spring-boot-starter-{name}
    • 模式:spring-boot-starter-模块名
      • 举例:spring-boot-starter-web、spring-boot-starter-thymeleaf
  • 自定义命名规则
  • 后缀:{name}-spring-boot-starter
  • 模式:模块-spring-boot-starter
    • 举例:mybatis-spring-boot-starter

2.2 创建maven工程

2.1.1 项目目录结构

搭建自用单点OOS服务_第1张图片

2.1.2 依赖


<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.5.0version>
        <relativePath/> 
    parent>
    <groupId>com.dingwengroupId>
    <artifactId>dingwen-minio-starterartifactId>
    <version>1.0-SNAPSHOTversion>
    <name>dingwen-minio-startername>
    <description>dingwen-minio-starterdescription>
    <properties>
        <java.version>1.8java.version>
        <minio.version>7.0.2minio.version>
        <commons.io.version>2.6commons.io.version>
        <spring.boot.version>2.4.1spring.boot.version>
    properties>
    <dependencies>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-dependenciesartifactId>
           <version>${spring.boot.version}version>
            <type>pomtype>
            <scope>importscope>
        dependency>

        
        <dependency>
            <groupId>io.miniogroupId>
            <artifactId>minioartifactId>
            <version>${minio.version}version>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-configuration-processorartifactId>
            <optional>trueoptional>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-autoconfigureartifactId>
        dependency>

        
        <dependency>
            <groupId>commons-iogroupId>
            <artifactId>commons-ioartifactId>
            <version>${commons.io.version}version>
        dependency>
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-javadoc-pluginartifactId>
                <version>3.0.1version>
                <configuration>
                    <encoding>UTF-8encoding>
                    <charset>UTF-8charset>
                    <docencoding>UTF-8docencoding>
                    <doclint>nonedoclint>
                configuration>
                <executions>
                    <execution>
                        <id>attach-javadocsid>
                        <phase>packagephase>
                        <goals>
                            <goal>jargoal>
                        goals>
                    execution>
                executions>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-source-pluginartifactId>
                <version>3.0.0version>
                <configuration>
                    <attach>trueattach>
                configuration>
                <executions>
                    <execution>
                        <phase>compilephase>
                        <goals>
                            <goal>jargoal>
                        goals>
                    execution>
                executions>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <version>2.3.1version>
                <configuration>
                    <source>1.8source>
                    <target>1.8target>
                configuration>
            plugin>
        plugins>
    build>

project>

注意:引入spring-boot-autoconfigure与spring-boot-autoconfigure-processor(xml、properties)来加载配置

2.3 编写配置文件

2.2.1 启动配置文件映射实体

package com.dingwen.minsta.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * minio 配置类
 *
 * @author dingwen
 * 2021.05.25 17:05
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "dingwen.minio")
public class DingwenMinioStarterProperties {
     
    /**
     * 一天的毫秒数
     */
    private static final Long DAY_MILLISECOND = 1000L * 60 * 60 * 24;

    /**
     * 临时缓存目录
     */
    private static final String TEMP_DIR = "." + File.separator + "temp" + File.separator;

    /**
     * 访问minio服务URL
     */
    private String endPoint;
    /**
     * 存储桶
     */
    private String bucket;

    /**
     * 访问密钥
     */
    private String accessKey;

    /**
     * 秘密密钥
     */
    private String secretKey;

    /**
     * 临时dir
     */
    private String tempDir = TEMP_DIR;


    /**
     * 是否进行缓存清理
     */
    private boolean tempCleanFlag = true;


    /**
     * 第一次临时清理时间
     */
    private Date tempCleanFirstTime;


    /**
     * 临时清洁周期(延时时间)
     */
    private Long tempCleanPeriod;

    /**
     * 临时清洁时间(间隔时间)
     */
    private Long tempCleanDuration;

    public void setTempCleanFirstTime(String tempCleanFirstTime) {
     
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        try {
     
            this.tempCleanFirstTime = format.parse(tempCleanFirstTime);
        } catch (ParseException e) {
     
            e.printStackTrace();
        }
    }
}

2.2.1 配置类

package com.dingwen.minsta.config;


import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * 自动配置类
 *
 * @author dingwen
 * 2021.05.25 17:03
 */
@Configuration
@EnableConfigurationProperties(DingwenMinioStarterProperties.class)
public class DingwenMinioStarterAutoConfiguration {
     

}

@Configuration: 告诉Spring该类是配置类 @EnableConfigurationProperties(DingwenMinioStarterProperties.class)
:配置映射

2.4 编写 spring.factories

由于starter工程和service工程包路径不一致了,是两个工程@Configuration注解标注的类扫描不到无法加入IOC容器,需要在此处配置。
SpringBoot 启动类默认的@SpringBootApplication注解中默认包含了@EnableAutoConfiguration注解,启动时就能扫描本项目下被@Configuration注解修饰的类并将其注入IOC容器。而对于引入的starter项目来说,@Configuration不能在本项目中扫描到,是无法加载的。所以需要启动时读取/META-INF/spring.factories文件,然后读取org.springframework.boot.autoconfigure.EnableAutoConfiguration指向的由@Configuration注解修饰的类并将其注入IOC容器。

搭建自用单点OOS服务_第2张图片

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.dingwen.minsta.config.DingwenMinioStarterAutoConfiguration

2.5 完成业务逻辑工程

  • 根据配置定时清除上传临时目录
  • 创建bucket
  • 删除bucket
  • 上传文件
  • 下载文件

2.6 自定义banner

2.6.1 生成

到工具网站生成banner新建txt文件。http://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something%20

搭建自用单点OOS服务_第3张图片

2.6.2 配置

存放到该目录下即可,注意文件名称。
搭建自用单点OOS服务_第4张图片

 ${AnsiColor.BRIGHT_CYAN} # 指定颜色
 ${application.version})  # 获取版本信息
 ${spring-boot.version} # 获取版本信息

2.7 打包部署到本地仓库

mvn clean install

2.8 完整代码地址

https://gitee.com/dingwen-gitee/dingwen-minio-starter

三、开发service

3.1 创建SpringBoot项目

3.1.1 项目结构概览

搭建自用单点OOS服务_第5张图片

3.1.2 依赖


<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.5.0version>
        <relativePath/> 
    parent>
    <groupId>com.dingwengroupId>
    <artifactId>dingwen-minio-serviceartifactId>
    <version>1.0.0-SNAPSHOTversion>
    <name>dingwen-minio-servicename>
    <description>dingwen-minio-servicedescription>
    <properties>
        <java.version>1.8java.version>
        <fastjson.version>1.2.75fastjson.version>
    properties>
    <dependencies>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        
        <dependency>
            <groupId>com.dingwengroupId>
            <artifactId>dingwen-minio-starterartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>

        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>

        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>${fastjson.version}version>
        dependency>

        
        <dependency>
            <groupId>com.github.xiaoymingroupId>
            <artifactId>knife4j-spring-boot-starterartifactId>
            <version>2.0.7version>
        dependency>

    dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>

3.2配置包扫描

package com.dingwen.minser;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "com.dingwen")
public class DingwenMinioServiceApplication {
     

    public static void main(String[] args) {
     
        SpringApplication.run(DingwenMinioServiceApplication.class, args);
    }

}

3.2配置文件

dingwen:
  minio:
    end-point: http://192.168.233.129:9000
    bucket: image
    access-key: admin
    secret-key: 1234567890
    temp-dir: D:\temp\
    temp-clean-flag: true
    temp-clean-period: 12960000
    temp-clean-duration: 12960000
    temp-clean-first-time: 2020-1-17 11:45:00
spring:
  servlet:
    multipart:
      enabled: true
      max-file-size: 2048MB # 单个文件最大限制
      max-request-size: 3000MB # 整体请求大小限制

3.3接口开发

package com.dingwen.minser.controller;

import ch.qos.logback.core.util.FileUtil;
import com.dingwen.minser.exception.ServiceException;
import com.dingwen.minser.result.Result;
import com.dingwen.minser.result.ResultGenerator;
import com.dingwen.minsta.service.FileService;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * entrance controller
 *
 * @author dingwen
 * 2021.05.28 14:07
 */
@RestController
@RequestMapping("/minio")
@Api(value = "minio 服务", tags = "minio")
public class EntranceController {
     
    /**
     * 文件服务
     */
    private final FileService fileService;

    @Autowired
    EntranceController(FileService fileService) {
     
        this.fileService = fileService;
    }

    /**
     * 创建bucket
     *
     * @return {@link Result}
     */
    @ApiOperation("创建bucket")
    @ApiImplicitParam(value = "存储桶名称", name = "bucketName", required = true)
    @PostMapping("/bucket/add")
    public Result add(@RequestParam("bucketName") String bucketName) {
     
        boolean flag = fileService.createBucket(bucketName);
        return flag ? ResultGenerator.genOkResult(bucketName + "创建成功")
                : ResultGenerator.genFailureResult(bucketName + "创建失败");
    }


    /**
     * 删除
     *
     * @param bucketName bucket名称
     * @return {@link Result}
     */
    @ApiOperation("删除bucket")
    @ApiImplicitParam(value = "存储桶名称", name = "bucketName", required = true)
    @DeleteMapping("/bucket/remove")
    public Result remove(@RequestParam("bucketName") String bucketName) {
     
        boolean flag = fileService.removeBucket(bucketName);
        return flag ? ResultGenerator.genOkResult(bucketName + "删除成功")
                : ResultGenerator.genFailureResult(bucketName + "删除失败");
    }


    /**
     * 上传
     *
     * @param multipartFile       文件
     * @param bucketName          bucket名称
     * @param destinationFileName 目标文件的名字
     * @return {@link Result}
     */
    @ApiOperation("文件上传")
    @ApiImplicitParams(
            {
     
                    @ApiImplicitParam(value = "文件", required = true, name = "multipartFile"),
                    @ApiImplicitParam(value = "存储桶名称", required = true, name = "bucketName"),
                    @ApiImplicitParam(value = "目标文件名", required = false, name = "destinationFileName")
            }

    )
    @PostMapping("/file/upload")
    public Result upload(@RequestParam(value = "multipartFile", required = true) MultipartFile multipartFile,
                         @RequestParam(value = "bucketName", required = true) String bucketName,
                         @RequestParam(value = "destinationFileName", required = false) String destinationFileName) {
     
        try {
     
            String fileName = null;
            if (!StringUtils.hasText(destinationFileName)
                    || ObjectUtils.isEmpty(destinationFileName)
                    || destinationFileName.equalsIgnoreCase("null")) {
     
                destinationFileName = multipartFile.getOriginalFilename();
            }
            fileName = fileService.saveFile(bucketName, new ByteArrayInputStream(multipartFile.getBytes()), destinationFileName);
            return StringUtils.hasText(fileName) ? ResultGenerator.genOkResult("文件已成功上传,文件名:" + fileName) :
                    ResultGenerator.genFailureResult("文件上传失败").setCode(Integer.parseInt(HttpStatus.INTERNAL_SERVER_ERROR.name()));
        } catch (Exception e) {
     
            e.printStackTrace();
            throw new ServiceException("文件上传失败:{}", e.getMessage());
        }
    }


    /**
     * 下载
     *
     * @param response   响应
     * @param bucketName bucket名称
     * @param fileName   文件名称
     * @return {@link ResponseEntity}
     */

    @ApiOperation("文件下载")
    @ApiImplicitParams(
            {
     
                    @ApiImplicitParam(value = "存储桶名称", name = "bucketName"),
                    @ApiImplicitParam(value = "文件名称", name = "fileName"),
            }
    )
    @GetMapping("/file/download")
    public ResponseEntity<Resource> download(
            HttpServletResponse response,
            @RequestParam("bucketName") String bucketName,
            @RequestParam("fileName") String fileName
    ) throws UnsupportedEncodingException {
     
        fileName = fileName.trim();
        response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
        // 文件名中文乱码解决
        response.addHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1"));
        try {
     
            fileService.write(fileName, bucketName, response.getOutputStream());
        } catch (IOException e) {
     
            e.printStackTrace();
            throw new ServiceException("文件下载异常:{}", e.getMessage());
        }
        return null;
    }


    /**
     * 文件删除
     *
     * @param fileName   文件名称
     * @param bucketName bucket名称
     * @return {@link Result}
     */

    @ApiOperation("删除文件")
    @ApiImplicitParams(
            {
     
                    @ApiImplicitParam(value = "文件名称", name = "fileName"),
                    @ApiImplicitParam(value = "存储桶名称", name = "bucketName")
            }
    )
    @DeleteMapping("file/remove")
    public Result remove(@RequestParam("fileName") String fileName, @RequestParam(value = "bucketName", required = false) String bucketName) {
     
        boolean flag = false;
        if (StringUtils.hasText(bucketName)) {
     
            flag = fileService.removeFile(bucketName, fileName);
        } else {
     
            flag = fileService.removeFile(fileName);
        }
        return flag ? ResultGenerator.genOkResult("删除文件成功") : ResultGenerator.genFailureResult("删除文件失败");
    }
}

2.4 完整代码地址

https://gitee.com/dingwen-gitee/dingwen-minio-service

四、启动测试

4.1 banner

搭建自用单点OOS服务_第6张图片

4.2 准备好MinIo服务

搭建自用单点OOS服务_第7张图片
搭建自用单点OOS服务_第8张图片

4.3测试文件上传

4.3.1 上传

搭建自用单点OOS服务_第9张图片
搭建自用单点OOS服务_第10张图片

4.3.2 验证

搭建自用单点OOS服务_第11张图片

服务器data
搭建自用单点OOS服务_第12张图片

你可能感兴趣的:(SpringBoot,oos,study,project,spring,boot)