Java 项目实战: 交友项目 - 阿里云概述与项目中的云服务选型

概述

交友项目从第一行业务代码开始就要发短信验证码,而发送短信这件事个人和中小团队都做不了------没有运营商资质。本文讲清项目项目为什么必须接第三方云服务、具体接了阿里云的哪几个、以及从注册账号到密钥落地的完整接入流程,顺带把 AccessKey 的安全红线说透。

纲要

  • 云服务存在的意义:短信、对象存储、内容审核、人脸识别为什么不该自建
  • 阿里云简介:它提供什么,本项目用的是哪一类服务
  • 本项目实际接入的阿里云服务清单(短信 / OSS / 内容审核),以及一个容易搞错的点:人脸识别用的是百度
  • 第三方服务全景表:跟着项目走下来,一共要注册哪些账号
  • 开通与接入的通用流程:实名认证 → 开通服务 → RAM 子用户 → AccessKey → 配置落地
  • 费用与免费额度:哪些按条、哪些按量,怎么防止意外扣费
  • AccessKey 安全规范:为什么必须用 RAM 子账号、密钥该放哪、泄露后怎么办
  • 工程实读:mf-autoconfig 的 pom 依赖与自动装配骨架
  • 与后续章节的衔接映射
  • 常见误解澄清

为什么项目要用云服务

先说结论:短信、对象存储(OSS)、内容审核、人脸识别这四类能力,自建的成本高到不现实。

能力 自建需要付出什么 用云服务的代价
短信 申请运营商通道、企业资质备案、签名与模板报备,个人几乎不可能拿到 按条付费,调一个 API 就发出去了
对象存储 买磁盘、维护分布式文件系统、做冗余和扩容、处理 CDN 回源 存多少算多少,按存储量和流量计费
内容审核 自建模型团队或采购算法,还要持续迭代模型对抗绕过 把文字/图片丢给 API,返回是否合规
人脸识别 同上,且涉及生物特征合规问题 上传图片拿比对分数

交友项目是学习型项目,重点在业务逻辑与架构(Dubbo 拆分、MongoDB 地理位置、Redis 缓存、Spark 推荐)。把时间花在搭短信网关或自研审核模型上,等于跑偏。云服务提供的是开箱即用 + 按量付费,这正是学习项目最需要的形态。

短信验证码这条链路最能说明问题------服务端不直接对接运营商,中间隔着第三方云服务:
运营商 阿里云短信 Java 服务端 手机端 运营商 阿里云短信 Java 服务端 手机端 #mermaid-svg-Bd2KCvVVsEeuHUQ7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .error-icon{fill:#552222;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .marker.cross{stroke:#333333;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 p{margin:0;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .sequenceNumber{fill:white;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 #sequencenumber{fill:#333;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .messageText{fill:#333;stroke:none;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .labelText,#mermaid-svg-Bd2KCvVVsEeuHUQ7 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .loopText,#mermaid-svg-Bd2KCvVVsEeuHUQ7 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .noteText,#mermaid-svg-Bd2KCvVVsEeuHUQ7 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .actorPopupMenu{position:absolute;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 .actor-man circle,#mermaid-svg-Bd2KCvVVsEeuHUQ7 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Bd2KCvVVsEeuHUQ7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 请求发送验证码(手机号) 调用 SendSms API(AK 鉴权) 提交短信内容 回执 返回 Code/Message 下发短信 提交验证码校验

阿里云简介

阿里云是国内市场占有率领先的云厂商,产品线覆盖计算(ECS 云服务器)、存储(OSS 对象存储)、数据库(RDS)、中间件(消息队列、注册中心)、AI 能力(内容审核、人脸人体)和通信能力(短信服务)。

这里有个常见误解要先破掉:阿里云不等于"租服务器"。项目项目一台 ECS 都没买,用的是其中的 PaaS 与 API 类服务------SDK 引入依赖、填上密钥,服务端直接调接口。计算资源仍然跑在本地/自己的机器上。

本项目实际用到的阿里云服务

以工程实读为准。mf-autoconfig 的 pom 里出现的阿里云依赖,就是项目真正会用的服务:

服务名 用途 用在哪个功能 是否必须
短信服务 Dysmsapi(dysmsapi20170525) 下发手机验证码 注册、登录的短信验证码 必须,第一章就要用
对象存储 OSS(aliyun-sdk-oss) 存用户头像、动态图片、小视频封面 完善用户信息、发布动态/视频 必须
内容审核 Green(aliyun-java-sdk-green) 动态文字与图片的合规审核 后台管理系统的审核功能 后续章节用到
核心 SDK(aliyun-java-sdk-core) 上面若干 SDK 的公共依赖 全局 传递依赖
人脸人体 Facebody(facebody20191230) 人脸检测(备用能力) 见下方说明 可选

注意别搞混 :项目的人脸识别功能走的是百度 AI (com.baidu.aip:java-sdk),不是阿里云。pom 里那两个依赖都躺着,容易让人以为"人脸也是阿里云"。实际业务用的是百度人脸识别的解决方案,讲义 1.9 节写得很明确。至于 facebody20191230 这行,属于随大流引入的备用依赖。

把项目的第三方服务拉成一张全景表,注册账号前先看清楚要办哪几张:

服务 厂商 用途 对应章节
短信服务 阿里云 登录/注册验证码 短信验证码
对象存储 OSS 阿里云 头像、动态图片存储 完善用户信息
内容审核 阿里云 动态文字/图片审核 后台系统
人脸识别 百度 AI 人脸检测与比对 用户信息/动态
即时通讯 IM 环信 聊天消息 消息模块

开通与接入的通用流程

不管接哪个云服务,步骤都是同一套骨架。以阿里云短信为例:
#mermaid-svg-KA8v7Bm9Xn0H6WGh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .error-icon{fill:#552222;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .marker.cross{stroke:#333333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KA8v7Bm9Xn0H6WGh p{margin:0;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .cluster-label text{fill:#333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .cluster-label span{color:#333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .cluster-label span p{background-color:transparent;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .label text,#mermaid-svg-KA8v7Bm9Xn0H6WGh span{fill:#333;color:#333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .node rect,#mermaid-svg-KA8v7Bm9Xn0H6WGh .node circle,#mermaid-svg-KA8v7Bm9Xn0H6WGh .node ellipse,#mermaid-svg-KA8v7Bm9Xn0H6WGh .node polygon,#mermaid-svg-KA8v7Bm9Xn0H6WGh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .rough-node .label text,#mermaid-svg-KA8v7Bm9Xn0H6WGh .node .label text,#mermaid-svg-KA8v7Bm9Xn0H6WGh .image-shape .label,#mermaid-svg-KA8v7Bm9Xn0H6WGh .icon-shape .label{text-anchor:middle;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .rough-node .label,#mermaid-svg-KA8v7Bm9Xn0H6WGh .node .label,#mermaid-svg-KA8v7Bm9Xn0H6WGh .image-shape .label,#mermaid-svg-KA8v7Bm9Xn0H6WGh .icon-shape .label{text-align:center;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .node.clickable{cursor:pointer;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .arrowheadPath{fill:#333333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KA8v7Bm9Xn0H6WGh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KA8v7Bm9Xn0H6WGh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KA8v7Bm9Xn0H6WGh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .cluster text{fill:#333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .cluster span{color:#333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KA8v7Bm9Xn0H6WGh rect.text{fill:none;stroke-width:0;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .icon-shape,#mermaid-svg-KA8v7Bm9Xn0H6WGh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .icon-shape p,#mermaid-svg-KA8v7Bm9Xn0H6WGh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .icon-shape .label rect,#mermaid-svg-KA8v7Bm9Xn0H6WGh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KA8v7Bm9Xn0H6WGh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KA8v7Bm9Xn0H6WGh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KA8v7Bm9Xn0H6WGh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 注册阿里云账号
实名认证 - 个人认证即可
控制台搜索服务名并开通
申请签名与模板 - 短信服务人工审核
创建 RAM 子用户
只授予该服务权限
创建 AccessKeyId / AccessKeySecret
写入应用配置 - 环境变量 / yml / 配置中心
用官方示例代码测试连通性

各环节的关键动作与常见坑:

开通环节 关键动作 常见坑
注册与实名 用支付宝/手机号注册,完成个人实名认证 以为必须企业认证;个人认证可用,只是部分服务受限
开通服务 控制台顶部搜索框搜服务名 → 进入产品页 → 开通 开通了但没买短信包,依然能按条计费,别以为没开通
申请签名 短信 → 国内消息 → 签名管理 → 添加签名 签名要审核,测试可直接用官方提供的示例签名
申请模板 模板管理 → 添加模板,验证码类模板内容形如 您的验证码为${code} 模板里的 ${code} 就是占位符,参数名必须与代码里的 JSON key 一致
创建 RAM 子用户 访问控制 RAM → 用户 → 创建用户 不要用主账号 AccessKey,权限过大且无法收窄
获取 AccessKey RAM 用户详情 → 创建 AccessKey AK Secret 只在创建时展示一次,没存下来只能删掉重建
配置落地 写入 yml / 环境变量 / 配置中心 直接硬编码进代码或提交到仓库

签名与模板两个环节最容易被忽略------很多同学以为开通服务就能发短信,实际代码跑起来报 isv.SMS_SIGNATURE_ILLEGAL 或 isv.SMS_TEMPLATE_ILLEGAL,就是签名/模板没通过或名字写错。

费用与免费额度

项目 计费方式 学习项目的量级
短信 按条计费,通知/验证码类单价较低 几十到几百条级别,成本可忽略(具体单价以官方定价为准)
OSS 按存储容量 + 外网下行流量 + 请求次数 几张头像、几段小视频,几毛钱量级
内容审核 按调用次数计费 测试调用次数极少
人脸识别(百度) 按调用次数,有免费额度 同样可控

新用户通常能拿到一定的免费额度或体验包。即便如此,也建议在费用中心设置余额预警和消费预警------不是防大额扣费,而是防"忘了自己开通过什么",尤其是绑了自动续费或者被脚本刷接口的情况。

AccessKey 安全规范

这是本篇最值得记住的一节。AccessKey 是一对身份凭证,谁拿到谁就能以你的身份调用阿里云 API,能开机器、能删数据、能发短信。主账号的 AK 权限等于全部权限。

必须用 RAM 子账号,理由有三个:

  • 最小权限:只给这个子用户短信服务的权限,就算泄露也没法碰 OSS 和 ECS
  • 可单独吊销:出事禁用子用户即可,不影响主账号
  • 可审计:每个子用户的操作在日志里分得清

密钥放哪,优先级从上到下:

text 复制代码
环境变量(CI/CD 注入)  >  外部配置文件(不进仓库)  >  配置中心  >>  代码里硬编码

硬编码是最差的做法。讲义里为了方便演示,直接把 AK 写进了 yml:

yaml 复制代码
mf:
  sms:
    signName: 物流云商
    templateCode: SMS_106590012
    accessKey: <你的 AccessKeyId>
    secret: <你的 AccessKeySecret>

这段在教学环境没问题,但绝对不能原样提交到 Git 仓库。正确做法是本地 yml 不纳入版本控制,或改用环境变量占位:

yaml 复制代码
mf:
  sms:
    signName: ${SMS_SIGN_NAME}
    templateCode: ${SMS_TEMPLATE_CODE}
    accessKey: ${ALIYUN_ACCESS_KEY_ID}
    secret: ${ALIYUN_ACCESS_KEY_SECRET}

泄露后的应急处置顺序:先在 RAM 控制台禁用该 AK(或直接禁用子用户)→ 生成新的 AK → 更新应用配置 → 到操作审计里排查是否已被调用过、调了什么。别先改代码,先断掉凭证,否则改代码的速度赶不上对方刷接口的速度。

团队协作时不要几个人共用一个 AK。出了事不知道是谁干的,也没法单独吊销某个人。一人一个 RAM 子用户,成本几乎为零。

工程实读:mf-autoconfig

项目没有在每个模块里重复写短信调用逻辑,而是把云服务的调用封装成一个可复用的自动装配模块 mf-autoconfig。目录结构如下:

text 复制代码
mf-autoconfig
├── pom.xml                                  # 阿里云短信/OSS/内容审核、百度人脸、环信 SDK
└── src/main
    ├── java/com/mf/autoconfig
    │   ├── mfAutoConfiguration.java     # 自动装配入口,注册各类 Template 到容器
    │   ├── properties
    │   │   ├── SmsProperties.java           # @ConfigurationProperties(prefix = "mf.sms")
    │   │   ├── OssProperties.java
    │   │   └── GreenProperties.java
    │   └── template
    │       ├── SmsTemplate.java             # 封装短信发送
    │       ├── OssTemplate.java
    │       └── GreenTemplate.java
    └── resources/META-INF
        └── spring.factories                 # 声明 mfAutoConfiguration

spring.factories 是这套机制的关键,它让其他模块只要引入依赖就自动获得这些能力:

text 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mf.autoconfig.mfAutoConfiguration

第一章只落了短信一个 Template,骨架是这样:

java 复制代码
package com.mf.autoconfig;

import com.mf.autoconfig.properties.SmsProperties;
import com.mf.autoconfig.template.SmsTemplate;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

@EnableConfigurationProperties({
        SmsProperties.class
})
public class mfAutoConfiguration {

    @Bean
    public SmsTemplate smsTemplate(SmsProperties properties) {
        return new SmsTemplate(properties);
    }
}

属性类把 yml 里的密钥、签名、模板号绑成对象:

java 复制代码
package com.mf.autoconfig.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "mf.sms")
public class SmsProperties {
    private String signName;
    private String templateCode;
    private String accessKey;
    private String secret;
}

短信模板类里真正干活的是两件事:用 AccessKey 构造阿里云客户端,然后拼请求参数发出去:

java 复制代码
package com.mf.autoconfig.template;

import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.aliyun.teaopenapi.models.Config;
import com.mf.autoconfig.properties.SmsProperties;

public class SmsTemplate {

    private SmsProperties properties;

    public SmsTemplate(SmsProperties properties) {
        this.properties = properties;
    }

    public void sendSms(String mobile, String code) {
        try {
            Config config = new Config()
                    .setAccessKeyId(properties.getAccessKey())
                    .setAccessKeySecret(properties.getSecret());
            // 短信服务的接入域名
            config.endpoint = "dysmsapi.aliyuncs.com";

            com.aliyun.dysmsapi20170525.Client client =
                    new com.aliyun.dysmsapi20170525.Client(config);

            SendSmsRequest sendSmsRequest = new SendSmsRequest()
                    .setPhoneNumbers(mobile)
                    .setSignName(properties.getSignName())
                    .setTemplateCode(properties.getTemplateCode())
                    .setTemplateParam("{\"code\":\"" + code + "\"}");

            SendSmsResponse response = client.sendSms(sendSmsRequest);
            SendSmsResponseBody body = response.getBody();
            System.out.println(body.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

两个实读细节值得留意:一是讲义里写的是包名 com.mf.autoconfig.templates.SmsTemplate(复数),工程里实际是 template(单数),照抄讲义会编译不过;二是 templateParam 传的是 JSON 字符串,key 必须与模板里 ${code} 的占位名一致,否则短信能发出去但内容是空的。

与后续章节的衔接

云服务 在哪一章落地
阿里云短信 下一篇「阿里云短信入门案例」先跑通调用,再到「封装短信服务组件」抽成 SmsTemplate
阿里云 OSS 完善用户信息章节,上传头像
内容审核 Green 后台系统章节,动态文字与图片审核
百度人脸识别 用户信息相关章节

常见误解澄清

  • "用阿里云就得买服务器":不对。本项目用的全是 API/PaaS 类服务,不需要 ECS。
  • "主账号 AccessKey 更方便":方便一秒,风险无限。主账号 AK 泄露等于账号被接管,一律用 RAM 子用户。
  • "开通服务就能发短信":还差签名和模板,两个都要审核通过。
  • "第三方能力都是阿里云的":人脸识别是百度的,即时通讯是环信的。
  • "不买短信包就发不了":可以,按条计费;买套餐包只是更便宜。

官方文档

总结

交友项目用云服务,不是赶时髦,而是因为短信资质、分布式存储、审核算法这些能力自建不划算。项目实际接了三样阿里云能力------短信、OSS、内容审核,人脸识别是百度的,即时通讯是环信的,别记混。接入动作本身很简单,真正的门槛在开通流程(实名、签名、模板审核)和密钥管理(RAM 子用户 + 不硬编码)。把 mf-autoconfig 这个模块理解透,后面所有第三方能力都是同一套自动装配的套路。

相关推荐
2601_962071002 小时前
Kimi K3 vs DeepSeek V4-Pro实测对比:2026年同一入口十道题,耗时与token消耗差在哪
android·java·数据库
用户3721574261353 小时前
如何使用 Java 提取 PPT 中的文字:整份文档、指定幻灯片与表格内容
java
ManageEngineITSM3 小时前
工单优先级怎么定?影响×紧急度矩阵的设计与落地方法
java·大数据·运维·前端·数据库·变更管理
\光辉岁月/3 小时前
15.JavaSE-网络
java·开发语言·网络
const_qiu3 小时前
第二章 2.4:搭建 Monorepo 骨架 + 共享包 @autix/contracts
java·人工智能·arcgis
wangchunyu1143 小时前
JDK8新特性实战(Lambda、Stream、Optional)
java·开发语言
JosieBook4 小时前
【多线程】两台机器同时抢一个字典:一次并发 Bug 的排查
java·网络·bug
牛战士coding4 小时前
LLM 选错工具怎么办?提示词之外还需要确定性规则兜底
java·人工智能