Backend Development 21 min read

Building an OSS Spring Boot Starter Using Amazon S3

This article provides a step‑by‑step guide to creating a Spring Boot starter for enterprise‑grade object storage services, explaining OSS concepts, Amazon S3 basics, project setup, Maven dependencies, configuration classes, template interfaces, implementation details, auto‑configuration, packaging, and testing.

Top Architect
Top Architect
Top Architect
Building an OSS Spring Boot Starter Using Amazon S3

What is OSS?

Object Storage Service (OSS) is a cloud‑based storage solution that uses HTTP APIs to store and retrieve objects, offering features such as versioning, permission control, and lifecycle management.

OSS in Projects

OSS is essential for managing images, files, audio, and other objects in modern applications, providing upload, download, preview, and delete capabilities.

What is Amazon S3?

Amazon Simple Storage Service (S3) is the original cloud storage service whose protocol has become the de‑facto standard for object storage, offering a unified REST/SOAP interface, unlimited storage, high throughput, versioning, and access control.

Why Build a Spring Boot Starter Based on Amazon S3?

Since most OSS providers (Alibaba Cloud OSS, Tencent COS, Qiniu, MinIO, etc.) support the S3 protocol, a unified starter simplifies integration, migration, and extensibility across different vendors.

Create a Spring Boot Project

Generate a new Spring Boot project named oss-spring-boot-starter and add the required dependencies.

<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-s3</artifactId>
    <version>1.12.423</version>
</dependency>

Project pom.xml

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.9</version>
        <relativePath/>
    </parent>
    <groupId>com.qing</groupId>
    <artifactId>oss-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>oss-spring-boot-starter</name>
    <description>Demo oss-spring-boot-starter</description>
    <properties>
        <java.version>1.8</java.version>
        <aws.version>1.12.423</aws.version>
        <hutool.version>5.8.5</hutool.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-s3</artifactId>
            <version>${aws.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

Write OssProperties

Define configuration properties bound to the oss prefix.

oss.endpoint=xxx
oss.accessKey=xxx
oss.secretKey=xxx

/**
 * @Author 公众号:架构师指南
 * @Description Oss配置类
 * @ClassName OssProperties
 * @Date 2023/3/18 17:51
 */
@Data
@ConfigurationProperties(prefix = "oss")
public class OssProperties {
    /** 对象存储服务的URL */
    private String endpoint;
    /** 区域 */
    private String region;
    /** path‑style 访问模式 */
    private Boolean pathStyleAccess = true;
    /** Access key */
    private String accessKey;
    /** Secret key */
    private String secretKey;
    /** 最大线程数,默认 100 */
    private Integer maxConnections = 100;
}

Create OssTemplate Interface

Define the contract for OSS operations.

/**
 * @Author 公众号:架构师指南
 * @Description oss操作模板
 * @ClassName OssTemplate
 * @Date 2023/3/18 18:15
 */
public interface OssTemplate {
    /** 创建 bucket */
    void createBucket(String bucketName);
    /** 获取所有 bucket */
    List
getAllBuckets();
    /** 删除 bucket */
    void removeBucket(String bucketName);
    /** 上传文件(带 content type) */
    void putObject(String bucketName, String objectName, InputStream stream, String contextType) throws Exception;
    /** 上传文件(默认 content type) */
    void putObject(String bucketName, String objectName, InputStream stream) throws Exception;
    /** 获取对象 */
    S3Object getObject(String bucketName, String objectName);
    /** 获取对象 URL */
    String getObjectURL(String bucketName, String objectName, Integer expires);
    /** 删除对象 */
    void removeObject(String bucketName, String objectName) throws Exception;
    /** 按前缀查询对象 */
    List
getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive);
}

Implement OssTemplate

Use the Amazon S3 Java SDK to realize the methods.

/**
 * @Author 公众号:架构师指南
 * @Description OssTemplate的实现类
 * @ClassName OssTemplateImpl
 * @Date 2023/3/18 19:02
 */
@RequiredArgsConstructor
public class OssTemplateImpl implements OssTemplate {
    private final AmazonS3 amazonS3;

    @Override
    @SneakyThrows
    public void createBucket(String bucketName) {
        if (!amazonS3.doesBucketExistV2(bucketName)) {
            amazonS3.createBucket(bucketName);
        }
    }

    @Override
    @SneakyThrows
    public List
getAllBuckets() {
        return amazonS3.listBuckets();
    }

    @Override
    @SneakyThrows
    public void removeBucket(String bucketName) {
        amazonS3.deleteBucket(bucketName);
    }

    @Override
    @SneakyThrows
    public void putObject(String bucketName, String objectName, InputStream stream, String contextType) {
        putObject(bucketName, objectName, stream, stream.available(), contextType);
    }

    @Override
    @SneakyThrows
    public void putObject(String bucketName, String objectName, InputStream stream) {
        putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream");
    }

    @Override
    @SneakyThrows
    public S3Object getObject(String bucketName, String objectName) {
        return amazonS3.getObject(bucketName, objectName);
    }

    @Override
    @SneakyThrows
    public String getObjectURL(String bucketName, String objectName, Integer expires) {
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, expires);
        URL url = amazonS3.generatePresignedUrl(bucketName, objectName, calendar.getTime());
        return url.toString();
    }

    @Override
    @SneakyThrows
    public void removeObject(String bucketName, String objectName) {
        amazonS3.deleteObject(bucketName, objectName);
    }

    @Override
    @SneakyThrows
    public List
getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
        ObjectListing objectListing = amazonS3.listObjects(bucketName, prefix);
        return objectListing.getObjectSummaries();
    }

    @SneakyThrows
    private PutObjectResult putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) {
        byte[] bytes = IOUtils.toByteArray(stream);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(size);
        objectMetadata.setContentType(contextType);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        return amazonS3.putObject(bucketName, objectName, byteArrayInputStream, objectMetadata);
    }
}

Create OssAutoConfiguration

Auto‑configure the AmazonS3 client and the OssTemplate bean.

/**
 * @Author 公众号:架构师指南
 * @Description oss配置bean
 * @ClassName OssAutoConfiguration
 * @Date 2023/3/18 18:23
 */
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(OssProperties.class)
public class OssAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public AmazonS3 ossClient(OssProperties ossProperties) {
        ClientConfiguration clientConfiguration = new ClientConfiguration();
        clientConfiguration.setMaxConnections(ossProperties.getMaxConnections());
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(
                ossProperties.getEndpoint(), ossProperties.getRegion());
        AWSCredentials awsCredentials = new BasicAWSCredentials(ossProperties.getAccessKey(), ossProperties.getSecretKey());
        AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials);
        return AmazonS3Client.builder()
                .withEndpointConfiguration(endpointConfiguration)
                .withClientConfiguration(clientConfiguration)
                .withCredentials(awsCredentialsProvider)
                .disableChunkedEncoding()
                .withPathStyleAccessEnabled(ossProperties.getPathStyleAccess())
                .build();
    }

    @Bean
    @ConditionalOnBean(AmazonS3.class)
    public OssTemplate ossTemplate(AmazonS3 amazonS3) {
        return new OssTemplateImpl(amazonS3);
    }
}

Create spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.qing.oss.OssAutoConfiguration

Package and Install

Remove the default Spring Boot Maven plugin from the pom to avoid install errors, then run mvn install to publish the starter to the local repository.

Testing

Create a separate Spring Boot test project, add the starter dependency, configure oss.endpoint , oss.accessKey , and oss.secretKey , and write a simple test case.

@SpringBootTest
class TestOssSpringBootStarterApplicationTests {
    @Autowired
    private OssTemplate ossTemplate;

    @Test
    void contextLoads() {
        ossTemplate.createBucket("oss02");
    }
}

Conclusion

The article demonstrates how to build a reusable Spring Boot starter for enterprise OSS services, leveraging the Amazon S3 protocol to support Alibaba Cloud OSS, Tencent COS, Qiniu, MinIO, and other compatible providers, enabling quick integration and future extensibility.

BackendJavaSpring BootOSSObject StorageAmazon S3Starter
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.