- 示例工程
- 教程
- 后端
【免费下载链接】aws-doc-sdk-examples
Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below.
本指南完整讲解如何在aws-doc-sdk-examples仓库的javav2/usecases/creating_photo_analyzer_async示例基础上,从零构建名为AWS Photo Analyzer的 Spring Boot 动态 Web 应用。该应用以 AWS SDK for Java V2 的异步客户端(S3AsyncClient、RekognitionAsyncClient)为核心,实现照片上传、批量标签识别、Excel 报告生成与邮件发送的完整链路。读完本文,你将掌握异步客户端的CompletableFuture+AtomicReference编程模式、各 AWS 服务在 Spring Boot 中的装配方式,以及如何运行和部署这套完整的多服务用例。
应用概览与整体架构
| 项目 | 说明 |
|---|---|
| 示例名称 | AWS Photo Analyzer(异步版) |
| 源码位置 | javav2/usecases/creating_photo_analyzer_async |
| 目标读者 | 初中级开发者 |
| 前置技能 | Java、Maven |
| 涉及 AWS 服务 | Amazon Rekognition、Amazon S3、Amazon SES |
| 关键技术 | AWS SDK for Java V2异步客户端、Spring Boot MVC、Thymeleaf、JXL 报表 |
核心工作流程
- 用户通过 Web 界面将自然风景图片上传到 Amazon S3 桶(
/upload接口,S3AsyncClient.putObject); - 页面通过
/getimages接口读取桶内全部对象,并以 XML 形式回传(S3AsyncClient.listObjects); - 用户在
/process页面输入收件邮箱并点击Analyze Photos,控制器/report遍历桶内每个对象,读取图片字节后调用 Amazon Rekognition 的detectLabels对每张图做标签识别; - 识别结果(照片、标签、置信度)交给 JXL API 生成多 Sheet 的 Excel 报告;
- 报告通过 Amazon SES 的
sendRawEmail作为附件发送到指定邮箱; - 用户还可通过
/downloadphoto把桶内图片下载到浏览器。
整个示例的关键设计是:S3 与 Rekognition 均使用 SDK V2 的异步客户端,SES 仍使用同步的SesClient。如果希望对照使用同步客户端的同主题用例,可参阅仓库中姊妹项目 creating_photo_analyzer_app。
前置条件与资源准备
环境要求
- 一个可用的 AWS 账户;
- Java IDE(本教程以 IntelliJ IDEA 为例);
- Java JDK 17;
- Maven 3.6 或更高版本。
提示:文中涉及的 AWS 服务均包含在 AWS Free Tier 中;但并非所有服务在所有区域可用,代码运行可能产生费用,请在使用后及时终止相关资源以免持续计费。
创建 S3 桶
创建一个名为photos[somevalue]的 S3 桶(例如photos2026),并确保将桶名同步配置到PhotoController的bucketName字段中。同时按 AWS 官方指引完成开发环境配置,使 SDK 能通过环境变量获取凭证——本示例中AnalyzePhotos与S3Service均使用EnvironmentVariableCredentialsProvider.create()(源码见 AnalyzePhotos.java 与 S3Service.java)。
创建 IntelliJ Maven 项目
- 在 IntelliJ 中选择File → New → Project;
- 在New Project对话框中选择Maven,点击Next;
- GroupId填写
aws-spring; - ArtifactId填写
SpringPhotoAnalyzerAsync; - 点击Next与Finish完成创建。
项目骨架建立后,按仓库中的 pom.xml 配置依赖。
POM 依赖配置详解
以下是本示例使用的完整依赖清单(来自仓库 pom.xml):
| 依赖 | 作用 |
|---|---|
spring-boot-starter-parent2.6.1 | Spring Boot 父 POM,统一管理版本 |
spring-boot-starter-thymeleaf | 模板引擎,渲染 HTML 视图 |
spring-boot-starter-web | Spring MVC Web 能力 |
software.amazon.awssdk:bom2.21.20 | AWS SDK for Java V2 依赖清单(BOM,统一版本) |
software.amazon.awssdk:rekognition | Amazon Rekognition 客户端(含异步) |
software.amazon.awssdk:s3 | Amazon S3 客户端(含异步) |
software.amazon.awssdk:ses | Amazon SES 客户端 |
net.sourceforge.jexcelapi:jxl2.6.12 | JXL API,生成 Excel 报告(非 AWS 服务) |
commons-io:commons-io2.7 | 字节流/输入输出工具 |
javax.mail:javax.mail-api、com.sun.mail:javax.mail1.6.2 | 构建 MIME 邮件消息 |
spring-boot-starter-test | 测试依赖(scope=test) |
关键配置点:
<java.version>17</java.version>与maven.compiler.target/source均设为 17,务必使用 Java 17 运行;- AWS SDK 依赖通过
dependencyManagement引入bom(版本 2.21.20)统一管理,具体服务 artifact 无需写版本号; - 构建插件使用
spring-boot-maven-plugin,可直接以可执行 JAR 方式运行应用。
Java 类设计与源码实现
在main/java下创建包com.example.photo,共 8 个类:
| 类 | 职责 |
|---|---|
| AnalyzePhotos | 用 Rekognition 异步客户端识别图片标签 |
| BucketItem | 模型:S3 对象信息(key/owner/date/size) |
| PhotoApplication | Spring Boot 启动入口 |
| PhotoController | MVC 控制器,处理全部 HTTP 请求 |
| SendMessages | 用 SES 发送带附件的邮件 |
| S3Service | 用 S3 异步客户端完成对象操作 |
| WorkItem | 模型:Rekognition 标签数据(key/name/confidence) |
| WriteExcel | 用 JXL API 动态生成 Excel 报告 |
核心异步模式:CompletableFuture + AtomicReference
异步客户端 API 的特点是方法立即返回CompletableFuture,结果在回调中可用。以AnalyzePhotos.DetectLabels(见 AnalyzePhotos.java)为例,完整调用链如下:
RekognitionAsyncClient rekAsyncClient = RekognitionAsyncClient.builder() .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) .region(Region.US_EAST_2) .build(); final AtomicReference<ArrayList<WorkItem>> reference = new AtomicReference<>(); SdkBytes sourceBytes = SdkBytes.fromByteArray(bytes); Image souImage = Image.builder().bytes(sourceBytes).build(); DetectLabelsRequest detectLabelsRequest = DetectLabelsRequest.builder() .image(souImage) .maxLabels(10) // 最多返回 10 个标签 .build(); CompletableFuture<DetectLabelsResponse> futureGet = rekAsyncClient.detectLabels(detectLabelsRequest); futureGet.whenComplete((resp, err) -> { if (resp != null) { List<Label> labels = resp.labels(); ArrayList<WorkItem> list = new ArrayList<>(); for (Label label : labels) { WorkItem item = new WorkItem(); item.setKey(key); // 标识照片 item.setConfidence(label.confidence().toString()); item.setName(label.name()); list.add(item); } reference.set(list); } else { err.printStackTrace(); } }); futureGet.join(); return reference.get();这套代码演示了三个关键知识点:
CompletableFuture.whenComplete:注册回调,通过resp对象获取服务端数据。例如resp.labels()返回List<Label>,每个Label可取出标签名(name())与置信度(confidence());AtomicReference跨越回调传值:无法直接从whenComplete回调内部return数据(会引发编译错误),因此用AtomicReference在回调内set结果,再在回调外get取出并作为方法返回值;源码中futureGet.join()保证异步任务完成后才读取引用;rekAsyncClient.close():放在finally块中,确保客户端在完全用完后再关闭。
S3Service采用完全相同的模式实现三个方法(见 S3Service.java):
getObjectBytes(bucketName, keyName):构造GetObjectRequest,配合AsyncResponseTransformer.toBytes()调用s3AsyncClient.getObject(...),在回调中reference.set(resp.asByteArray())得到图片字节数组;ListBucketObjects(bucketName):调用s3AsyncClient.listObjects(...),遍历resp.contents()收集全部对象的 key;putObject(data, bucketName, objectKey):用AsyncRequestBody.fromBytes(data)作为请求体调用s3AsyncClient.putObject(...)完成上传。
注意S3Service构造客户端时区域为Region.US_WEST_2(S3Service.java#L44-L49),而AnalyzePhotos使用Region.US_EAST_2(AnalyzePhotos.java#L26),运行时请按你实际使用的区域调整。
PhotoController:HTTP 请求与业务编排
PhotoController(见 PhotoController.java)通过构造器注入S3Service、AnalyzePhotos、WriteExcel、SendMessages四个组件,映射了 6 个端点:
| 端点与方法 | 功能 |
|---|---|
GET /→root() | 返回首页index |
GET /process→process() | 返回报告生成页process |
GET /photo→photo() | 返回上传页upload |
POST /report→report() | 遍历桶内图片→识别标签→生成 Excel→发邮件 |
POST /upload→singleFileUpload() | 接收MultipartFile,写入 S3 桶 |
GET /getimages→getImages() | 返回桶内对象 XML |
GET /downloadphoto→buildDynamicReportDownload() | 下载指定照片到浏览器 |
其中/report是核心编排方法:
String email = request.getParameter("email"); ArrayList<String> myKeys = (ArrayList<String>) s3Service.ListBucketObjects(bucketName); ArrayList<List<WorkItem>> myList = new ArrayList<>(); for (String myKey : myKeys) { byte[] keyData = s3Service.getObjectBytes(bucketName, myKey); ArrayList<WorkItem> item = photos.DetectLabels(keyData, myKey); myList.add(item); } InputStream excelData = excel.exportExcel(myList); sendMessage.sendReport(excelData, email);/downloadphoto方法则通过response.setContentType("image/png")与Content-disposition: attachment; filename=...响应头,配合IOUtils.copy将图片字节写入输出流,实现浏览器直接下载。
务必修改的配置:将bucketName字段替换为你的 S3 桶名(PhotoController.java#L23中默认值为占位符<Enter your S3 bucket name>)。
模型类:BucketItem 与 WorkItem
BucketItem:封装key、owner、date、size四个字段,用于在/getimages视图渲染 S3 对象元数据;WorkItem:封装key、name、confidence三个字段,key标识照片,name是 Rekognition 返回的标签名,confidence为置信度字符串,作为 Excel 报告的数据载体。
WriteExcel:用 JXL 生成多 Sheet 报告
WriteExcel(见 WriteExcel.java)使用 JXL API(net.sourceforge.jexcelapi:jxl,非 AWS 服务)将List<List<WorkItem>>写成内存中的WritableWorkbook:
- 外层列表中的每个元素(一张照片的标签集合)对应一个名为
Sheet N的工作表(WriteExcel.java#L47-L54); - 每张表表头固定为Photo / Label / Confidence三列(
createLabel方法),使用带下划线的粗体 Times 字体并开启自动换行; createContent逐行写入key、name、confidence,列宽按内容字符数自动伸缩(超过 200 字符时固定为 150 列宽);- 最终
workbook.write()后转为ByteArrayInputStream返回,供邮件发送与浏览器展示使用。
SendMessages:SES 发送带附件邮件
SendMessages(见 SendMessages.java)使用标准 JavaMail 构建多部分 MIME 消息,再通过 SESsendRawEmail发送:
- 先构建
multipart/alternative子容器(同时携带纯文本与 HTML 正文),再包入multipart/mixed父容器,附加 Excel 附件; - 附件通过
ByteArrayDataSource(attachment, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")承载,文件名为PhotoReport.xls(SendMessages.java#L92-L98); - 将
MimeMessage序列化为字节后包装为SdkBytes,构造RawMessage与SendRawEmailRequest,调用client.sendRawEmail(...)发送; - 注意源码中
sender为<Enter a validated email address>占位符,且 SES 发送方地址必须在 SES 控制台中完成验证。
HTML 视图与脚本文件
在src/main/resources下创建templates目录,放置 4 个 Thymeleaf 模板(仓库源码对应位置见 creating_photo_analyzer_async 目录结构):
| 文件 | 视图角色 |
|---|---|
index.html | 首页,介绍应用与使用步骤 |
process.html | 输入邮箱生成报告、下载照片 |
upload.html | 上传图片、查看桶内对象表格 |
layout.html | 全站共享导航菜单(Home / Upload Photos / Analyze Photos) |
三个页面均通过<header th:replace="layout :: site-header"/>引入共享菜单,并引用 Bootstrap、jQuery、DataTables 等 CDN 资源;upload.html中<form method="POST" action="/upload" enctype="multipart/form-data">直连控制器的/upload端点,process.html提供邮箱输入框与Analyze Photos / Download Photo两个按钮。
还需要在resources下加入两个 JS 脚本(否则页面无法与控制器通信):
- items.js:
getImages()通过$.ajax('/getimages', { type: 'GET' })拉取 XML,解析每个<Item>节点的 Key/Owner/Date/Size,用 DataTables 的fnAddData填充表格; - message.js:
ProcessImages()通过$.ajax('/report', { type: 'POST', data: 'email=' + email })提交邮箱并显示进度条;DownloadImage()跳转至/downloadphoto?photoKey=...触发下载。
注意:仓库中
resources目录还包含其他 CSS 等静态资源文件,必须一并加入项目,否则页面样式与交互会缺失。
运行与部署
在 IntelliJ 中直接运行PhotoApplication主类(点击运行图标,见仓库示意图 run.png),Spring Boot 应用即在本机启动;随后按首页指引依次完成上传照片 → 查看图片列表 → 输入邮箱生成报告 → 查收邮件附件的完整流程。
部署方面,该 Spring Boot 应用可打包后部署到 AWS Elastic Beanstalk,具体可参考仓库中姊妹教程 creating_first_project。
后续步骤
恭喜你完成了 AWS Photo Analyzer 异步版应用的构建与运行!再次提醒:请务必终止本教程中创建的 S3 桶等所有资源,避免持续产生 AWS 费用。如需查看更多多服务用例,可浏览仓库的 javav2/usecases 目录。
- 示例工程
- 教程
- 后端
【免费下载链接】aws-doc-sdk-examples
Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below.
相关推荐
aws-doc-sdk-examples:基于 Spring Boot 与 S3 Java SDK V2 构建 S3 视频 HTTP 流媒体 Web 应用
aws doc sdk examples:基于 Spring Boot 与 S3 Java SDK V2 构建 S3 视频 HTTP 流媒体 Web 应用 本文
示例工程教程后端如何快速构建首个AWS SDK for Java Spring Boot Web应用:零基础入门指南
如何快速构建首个AWS SDK for Java Spring Boot Web应用:零基础入门指南 AWS SDK for Java是开发人员构建云原生应用的
示例工程教程后端aws-doc-sdk-examples 实战:用 Spring Boot、DynamoDB 增强客户端与 SNS 构建第一个 AWS Java Web 应用
aws doc sdk examples 实战:用 Spring Boot、DynamoDB 增强客户端与 SNS 构建第一个 AWS Java Web 应用
示例工程教程后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考