{"id":20573542,"url":"https://github.com/lightweight-component/aj-s3client","last_synced_at":"2026-07-16T18:04:50.519Z","repository":{"id":299567769,"uuid":"1003368283","full_name":"lightweight-component/aj-s3client","owner":"lightweight-component","description":"A Lightweight S3 Client in Java","archived":false,"fork":false,"pushed_at":"2025-06-17T12:32:48.000Z","size":38,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-14T11:08:32.746Z","etag":null,"topics":["s3","s3-client","s3-java"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lightweight-component.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-17T03:39:21.000Z","updated_at":"2025-06-17T12:32:51.000Z","dependencies_parsed_at":"2025-06-17T07:42:08.115Z","dependency_job_id":"4af27065-8385-43cb-960f-19018982671f","html_url":"https://github.com/lightweight-component/aj-s3client","commit_stats":null,"previous_names":["lightweight-component/aj-s3client"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lightweight-component/aj-s3client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightweight-component%2Faj-s3client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightweight-component%2Faj-s3client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightweight-component%2Faj-s3client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightweight-component%2Faj-s3client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lightweight-component","download_url":"https://codeload.github.com/lightweight-component/aj-s3client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightweight-component%2Faj-s3client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35553387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-16T02:00:06.687Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["s3","s3-client","s3-java"],"created_at":"2024-11-16T05:28:02.985Z","updated_at":"2026-07-16T18:04:50.499Z","avatar_url":"https://github.com/lightweight-component.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Maven Central](https://img.shields.io/maven-central/v/com.ajaxjs/aj-s3client?label=Latest%20Release)](https://central.sonatype.com/artifact/com.ajaxjs/aj-s3client)\n[![Javadoc](https://img.shields.io/badge/javadoc-1.2-brightgreen.svg?)](https://javadoc.io/doc/com.ajaxjs/aj-s3client)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/lightweight-component/aj-s3client)\n[![License](https://img.shields.io/badge/license-Apache--2.0-green.svg?longCache=true\u0026style=flat)](http://www.apache.org/licenses/LICENSE-2.0.txt)\n[![Email](https://img.shields.io/badge/Contact--me-Email-orange.svg)](mailto:frank@ajaxjs.com)\n\n# A Lightweight S3 Client / S3 存储 Java 客户端\n\nCurrently, it's uncommon to store binary files directly on application servers. Instead, people prefer using \"object storage\" solutions such as Amazon AWS S3, Alibaba Cloud OSS, Cloudflare R2, etc.\nAWS was the pioneer in this area, making its S3 protocol almost a de facto standard.\nMost major vendors have implemented this protocol in their object storage offerings.\nAlmost all of them provide convenient SDKs for quickly integrating S3 services.\nSpeaking of complexity, building an S3 client isn't overly challenging.\nDriven by a momentary itch to create something, I decided to build my own S3 client.\nThis component focuses on being lightweight, consisting of no more than ten classes, while still covering the basic operations needed for daily OSS tasks.\n\nSupport these S3 Storages directly:\n\n- Cloudflare R2\n- Scaleway\n- Backblaze\n- Aliyun OSS\n- Netease OSS\n\n\nTutorial(For Chinese): https://blog.csdn.net/zhangxin09/article/details/137671230.\n\n\n## Source code\n\n[Github](https://github.com/lightweight-component/aj-s3client) | [Gitcode](https://gitcode.com/lightweight-component/aj-s3client)\n\n\n## Install\n\nRequires Java 8 or higher.\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ajaxjs\u003c/groupId\u003e\n    \u003cartifactId\u003eaj-s3client\u003c/artifactId\u003e\n    \u003cversion\u003e1.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nThe configuration file `application.yml` for unit tests was not committed with the VCS. Its content is as follows:\n\n```yaml\nS3Storage:\n  Nso:\n    accessKey: xx\n    accessSecret: xx\n    api: nos-eastchina1.126.net\n    bucket: xx\n  Oss:\n    accessKeyId: xx\n    secretAccessKey: xx\n    endpoint: oss-cn-beijing.aliyuncs.com\n    bucket: xx\n  LocalStorage: # 本地保存\n    absoluteSavePath: c:\\temp\\ # 若有此值，保存这个绝对路径上\n```\n\n## Usage\n\n### Step 1: Set Up OSS Parameters\n\nThe first step is to configure all necessary OSS parameters. These parameters are detailed in the configuration object `Config`. Below is an example of how to set up these parameters:\n\n```java\n/**\n * 配置\n */\n@Data\npublic class Config {\n    /**\n     * 访问 API\n     */\n    private String endPoint;\n\n    /**\n     * 访问 Key\n     */\n    private String accessKey;\n\n    /**\n     * 访问密钥\n     */\n    private String secretKey;\n\n    /**\n     * 存储桶名称\n     */\n    private String bucketName;\n\n    /**\n     * 签名中的标识，每个厂商不同\n     */\n    private String remark;\n}\n```\n\nThis POJO can be injected into each vendor's implementation using Spring.\nIf you're not using Spring, the simplest way is to instantiate and configure it manually like this:\n\n![https://i-blog.csdnimg.cn/blog_migrate/4fd200e1c60016fe1acc5afd70a54ada.png]()\n\nFor various OSS API operations, please refer to the S3Client interface.\nSince Java developers are generally familiar with this, we won't go into detailed explanations here.\n\n```java\npackage com.ajaxjs.s3client;\n\nimport java.util.Map;\n\n/**\n * S3 客户端\n */\npublic interface S3Client {\n    /**\n     * 列出存储桶中的所有对象\n     *\n     * @return XML List\n     */\n    String listBucket();\n\n    /**\n     * 列出存储桶中的所有对象\n     *\n     * @return XML List Map\n     */\n    Map\u003cString, String\u003e listBucketXml();\n\n    /**\n     * 创建一个存储桶（Bucket）\n     *\n     * @param bucketName 存储桶的名称，必须全局唯一\n     * @return true=操作成功\n     */\n    boolean createBucket(String bucketName);\n\n    /**\n     * 删除一个存储桶（Bucket）\n     *\n     * @param bucketName 存储桶的名称\n     * @return true=操作成功\n     */\n    boolean deleteBucket(String bucketName);\n\n    /**\n     * 将字节数据上传到指定的存储桶中\n     *\n     * @param bucketName 存储桶的名称\n     * @param objectName 对象（文件）在存储桶中的名称\n     * @param fileBytes  要上传的文件的字节数据\n     * @return true=操作成功\n     */\n    boolean putObject(String bucketName, String objectName, byte[] fileBytes);\n\n    /**\n     * 将字节数据上传到指定的存储桶中\n     *\n     * @param objectName 对象（文件）在存储桶中的名称\n     * @param fileBytes  要上传的文件的字节数据\n     * @return true=操作成功\n     */\n    boolean putObject(String objectName, byte[] fileBytes);\n\n    /**\n     * 将字节数据上传到指定的存储桶中\n     *\n     * @param bucketName 存储桶的名称\n     * @param objectName 对象（文件）在存储桶中的名称\n     * @return true=操作成功\n     */\n    boolean getObject(String bucketName, String objectName);\n\n    /**\n     * 将字节数据上传到指定的存储桶中\n     *\n     * @param objectName 对象（文件）在存储桶中的名称\n     * @return true=操作成功\n     */\n    boolean getObject(String objectName);\n\n    /**\n     * 删除指定的文件\n     *\n     * @param bucketName 存储桶的名称\n     * @param objectName 要删除的文件名称\n     * @return true=操作成功\n     */\n    boolean deleteObject(String bucketName, String objectName);\n\n    /**\n     * 删除指定的文件\n     *\n     * @param objectName 要删除的文件名称\n     * @return true=操作成功\n     */\n    boolean deleteObject(String objectName);\n}\n```\n\n## Development Insights\n\nDuring the implementation of this client, I’ve gained the following insights:\n\n1. **Reliance on HTTP Communication**  Despite being an object storage service, OSS operations fundamentally revolve around file management — uploading, downloading, and deleting files — along with handling \"Buckets\". All these interactions are done via HTTP APIs. Therefore, the client must encapsulate an HttpClient component to handle API calls properly. Cloudflare R2 provides Postman examples for their APIs, which greatly helped me in reconstructing the Java HTTP requests.\n1. **Authentication and Signing Requests** As with any protocol-based communication, authentication is a key challenge. The S3 protocol requires each HTTP request to include an `Authorization` header. Generating a valid signature is a relatively complex process involving multiple parameters and encryption steps, which takes up a significant portion of the codebase. There are two main signing versions: SigV2 and SigV4. This component supports both protocols.\n1. **Variations Across Vendors** Although most vendors implement the S3 protocol, there are often subtle differences in their respective APIs. To accommodate these variations, the code design uses inheritance:`BaseS3Client–\u003eBaseS3ClientSigV2/BaseS3ClientSigV4–\u003eVariations Across Vendors`. This structure allows for shared logic at the base level while enabling customization per vendor.\n1. **Signature Generation Is the Most Tricky Part** The most challenging part during development was generating the correct signature. Even a small mistake can lead to an invalid signature, causing the server to reject the request due to failed validation. Among the two versions, SigV2 is relatively simpler, while SigV4 involves more steps and stricter rules. So I found a great open-source implementation called [aws-v4-signer-java](https://github.com/lucasweb78/aws-v4-signer-java) — it’s zero-dependency, which fit my needs perfectly. I simplified and refactored a lot of its code to better suit this project. In addition, Alibaba Cloud's documentation on S3-compatible signing was also very clear and helpful. For more details, please refer to their [documentation](https://help.aliyun.com/zh/oss/developer-reference/recommend-to-use-signature-version-4?spm=a2c4g.11186623.0.0.398d28871Sob7M) and the [source code](https://github.com/aliyun/aliyun-oss-java-sdk/blob/master/src/main/java/com/aliyun/oss/internal/signer/OSSV4Signer.java).\n1. **Unit testing is still extremely important** — especially when developing or refactoring components. In many cases, reproducing issues would be difficult without unit tests. Having solid test coverage can also significantly improve development efficiency.\n\nThis component is not a complete S3 client implementation. Rather, it covers only a small portion of the S3 features that our software requires. The design goals were simplicity, minimal external dependencies, and low memory footprint.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightweight-component%2Faj-s3client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flightweight-component%2Faj-s3client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightweight-component%2Faj-s3client/lists"}