使用Spring Boot开发微信服务号推送短信验证码提示的完整指南
全面实现微信服务号与短信验证码功能的步骤解析
关键要点
- 配置微信服务号: 注册微信服务号并获取必要的认证信息。
- 整合Spring Boot与微信SDK: 构建后端服务以处理消息交互。
- 集成短信服务提供商: 选择并配置短信API以发送验证码。
一、配置微信服务号
1. 注册微信服务号
首先,您需要在微信公众平台上注册并创建一个服务号。注册完成后,您将获得以下重要信息:
- AppID
- AppSecret
- Token
- EncodingAESKey
2. 配置服务器URL
在微信公众平台后台,配置服务器URL以接收微信的消息推送。确保您的服务器具备公网可访问的地址,并能通过微信的验证。
示例配置
@RestController
@RequestMapping("/wechat")
public class WechatController {
private final String token = "yourToken";
private final String encodingAesKey = "yourEncodingAESKey";
private final String appId = "yourAppId";
private WxMpService wxMpService;
public WechatController() {
WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();
config.setToken(token);
config.setEncodingAesKey(encodingAesKey);
config.setAppId(appId);
this.wxMpService = new WxMpServiceImpl();
this.wxMpService.setWxMpConfigStorage(config);
}
@GetMapping(produces = "text/plain;charset=utf-8")
public String authGet(@RequestParam String signature,
@RequestParam String timestamp,
@RequestParam String nonce,
@RequestParam String echostr) {
if (wxMpService.checkSignature(timestamp, nonce, signature)) {
return echostr;
}
return "非法请求";
}
@PostMapping(produces = "application/xml; charset=UTF-8")
public String post(@RequestBody String requestBody,
@RequestParam String signature,
@RequestParam String timestamp,
@RequestParam String nonce,
@RequestParam(required = false) String encrypt_type,
@RequestParam(required = false) String msg_signature) {
try {
WxMpXmlMessage inMessage;
if ("aes".equals(encrypt_type)) {
inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(), timestamp, nonce, msg_signature);
} else {
inMessage = WxMpXmlMessage.fromXml(requestBody);
}
WxMpXmlOutMessage outMessage = this.route(inMessage);
if ("aes".equals(encrypt_type)) {
return outMessage.toEncryptedXml(wxMpService.getWxMpConfigStorage());
} else {
return outMessage.toXml();
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
private WxMpXmlOutMessage route(WxMpXmlMessage inMessage) {
if ("验证码".equals(inMessage.getContent())) {
// 触发短信验证码发送逻辑
return WxMpXmlOutMessage.TEXT()
.content("短信验证码已发送,请查收!")
.fromUser(inMessage.getToUser())
.toUser(inMessage.getFromUser())
.build();
}
return WxMpXmlOutMessage.TEXT()
.content("您好,请发送“验证码”来获取短信验证码。")
.fromUser(inMessage.getToUser())
.toUser(inMessage.getFromUser())
.build();
}
}
二、Spring Boot项目配置
1. 创建Spring Boot项目
使用Spring Initializr创建一个新的Spring Boot项目,并添加以下依赖:
-
spring-boot-starter-web
-
spring-boot-starter-security
-
spring-boot-starter-data-jpa(如果需要数据库交互)
-
weixin-java-mp(微信SDK)
2. 配置application.yml
wechat:
mp:
app-id: yourAppId
app-secret: yourAppSecret
token: yourToken
encoding-aes-key: yourEncodingAESKey
template-id: yourTemplateId
sms:
provider: aliyun
access-key: yourAccessKey
secret-key: yourSecretKey
sign-name: yourSignName
template-code: yourTemplateCode
3. 集成微信SDK
@Configuration
public class WechatMpConfig {
@Value("${wechat.mp.app-id}")
private String appId;
@Value("${wechat.mp.app-secret}")
private String appSecret;
@Value("${wechat.mp.token}")
private String token;
@Value("${wechat.mp.encoding-aes-key}")
private String encodingAesKey;
@Bean
public WxMpService wxMpService() {
WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();
config.setAppId(appId);
config.setSecret(appSecret);
config.setToken(token);
config.setAesKey(encodingAesKey);
WxMpService service = new WxMpServiceImpl();
service.setWxMpConfigStorage(config);
return service;
}
}
三、集成短信服务
1. 选择短信服务提供商
常见的短信服务提供商包括阿里云、腾讯云等。根据需求选择合适的提供商,并获取API密钥。
2. 配置短信服务
以下是集成阿里云短信服务的示例:
Maven依赖
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0.0</version>
</dependency>
短信服务配置类
@Service
public class SmsService {
@Value("${sms.access-key}")
private String accessKey;
@Value("${sms.secret-key}")
private String secretKey;
@Value("${sms.sign-name}")
private String signName;
@Value("${sms.template-code}")
private String templateCode;
public boolean sendSmsCode(String phoneNumber, String code) {
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKey, secretKey);
IAcsClient client = new DefaultAcsClient(profile);
SendSmsRequest request = new SendSmsRequest();
request.setPhoneNumbers(phoneNumber);
request.setSignName(signName);
request.setTemplateCode(templateCode);
request.setTemplateParam("{\"code\":\"" + code + "\"}");
try {
SendSmsResponse response = client.getAcsResponse(request);
return "OK".equals(response.getCode());
} catch (ClientException e) {
e.printStackTrace();
return false;
}
}
}
四、实现短信验证码发送逻辑
1. 生成验证码
验证码通常为6位数字,可以通过以下工具类实现:
public class VerificationCodeUtils {
public static String generateCode(int length) {
Random random = new Random();
StringBuilder sb = new StringBuilder();
for(int i=0; i<length; i++) {
sb.append(random.nextInt(10));
}
return sb.toString();
}
}
2. 存储验证码
为了验证用户输入,需将验证码临时存储在服务器端,如Redis:
@Service
public class VerificationService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void storeCode(String phoneNumber, String code) {
redisTemplate.opsForValue().set("sms:code:" + phoneNumber, code, 5, TimeUnit.MINUTES);
}
public boolean verifyCode(String phoneNumber, String inputCode) {
String storedCode = redisTemplate.opsForValue().get("sms:code:" + phoneNumber);
return inputCode != null && inputCode.equals(storedCode);
}
}
3. 发送验证码并推送消息
@Service
public class WechatMessageService {
@Autowired
private WxMpService wxMpService;
@Autowired
private SmsService smsService;
@Autowired
private VerificationService verificationService;
public boolean sendVerificationCodeMessage(String openId, String phoneNumber) {
String code = VerificationCodeUtils.generateCode(6);
verificationService.storeCode(phoneNumber, code);
boolean smsSent = smsService.sendSmsCode(phoneNumber, code);
if(smsSent) {
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser(openId)
.templateId("yourTemplateId")
.data(Arrays.asList(
new WxMpTemplateData("code", code, "#FF0000")
))
.build();
try {
wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
return true;
} catch (WxErrorException e) {
e.printStackTrace();
}
}
return false;
}
}
五、安全性与优化
1. 限制验证码发送频率
避免用户频繁请求验证码,可以通过Redis设置发送间隔:
public boolean canSendCode(String phoneNumber) {
Boolean exists = redisTemplate.hasKey("sms:sent:" + phoneNumber);
if(Boolean.TRUE.equals(exists)) {
return false;
}
redisTemplate.opsForValue().set("sms:sent:" + phoneNumber, "sent", 1, TimeUnit.MINUTES);
return true;
}
2. 验证码输入限制
限制用户输入验证码的次数,防止暴力破解:
public boolean verifyCodeWithLimit(String phoneNumber, String inputCode) {
String key = "sms:attempts:" + phoneNumber;
Integer attempts = redisTemplate.opsForValue().get(key) != null ? Integer.parseInt(redisTemplate.opsForValue().get(key)) : 0;
if(attempts >= 5) {
return false;
}
boolean isValid = verifyCode(phoneNumber, inputCode);
if(!isValid) {
redisTemplate.opsForValue().increment(key, 1);
redisTemplate.expire(key, 10, TimeUnit.MINUTES);
}
return isValid;
}
3. 数据加密传输
确保所有敏感数据在传输过程中采用加密方式,使用HTTPS协议保护数据安全。
六、测试与部署
1. 本地测试
使用内网穿透工具如Ngrok,将本地服务暴露到公网,配置微信服务器URL进行测试。
2. 部署到服务器
选择可靠的云服务提供商,将Spring Boot应用部署到生产环境,确保高可用性和稳定性。
3. 监控与日志
设置日志监控,实时监控系统运行状态,及时发现并解决问题。
七、示例代码汇总
1. 完整控制器示例
@RestController
@RequestMapping("/wechat")
public class WechatController {
@Autowired
private WechatMessageService wechatMessageService;
@GetMapping(produces = "text/plain;charset=utf-8")
public String authGet(@RequestParam String signature,
@RequestParam String timestamp,
@RequestParam String nonce,
@RequestParam String echostr) {
// 微信验证逻辑
}
@PostMapping(produces = "application/xml; charset=UTF-8")
public String post(@RequestBody String requestBody,
@RequestParam String signature,
@RequestParam String timestamp,
@RequestParam String nonce,
@RequestParam(required = false) String encrypt_type,
@RequestParam(required = false) String msg_signature) {
// 消息处理逻辑
}
private WxMpXmlOutMessage route(WxMpXmlMessage inMessage) {
if ("验证码".equals(inMessage.getContent())) {
String phoneNumber = getPhoneNumberByOpenId(inMessage.getFromUser());
if(phoneNumber != null && wechatMessageService.sendVerificationCodeMessage(inMessage.getFromUser(), phoneNumber)) {
return WxMpXmlOutMessage.TEXT()
.content("短信验证码已发送,请查收!")
.fromUser(inMessage.getToUser())
.toUser(inMessage.getFromUser())
.build();
} else {
return WxMpXmlOutMessage.TEXT()
.content("验证码发送失败,请稍后再试。")
.fromUser(inMessage.getToUser())
.toUser(inMessage.getFromUser())
.build();
}
}
return WxMpXmlOutMessage.TEXT()
.content("您好,请发送“验证码”来获取短信验证码。")
.fromUser(inMessage.getToUser())
.toUser(inMessage.getFromUser())
.build();
}
}
2. 短信发送服务示例
@Service
public class SmsService {
@Value("${sms.access-key}")
private String accessKey;
@Value("${sms.secret-key}")
private String secretKey;
@Value("${sms.sign-name}")
private String signName;
@Value("${sms.template-code}")
private String templateCode;
public boolean sendSmsCode(String phoneNumber, String code) {
// 阿里云短信发送逻辑
}
}
3. 短信验证码生成与验证
@Service
public class VerificationService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void storeCode(String phoneNumber, String code) {
redisTemplate.opsForValue().set("sms:code:" + phoneNumber, code, 5, TimeUnit.MINUTES);
}
public boolean verifyCode(String phoneNumber, String inputCode) {
String code = redisTemplate.opsForValue().get("sms:code:" + phoneNumber);
return inputCode != null && inputCode.equals(code);
}
}
八、功能概览表
| 功能模块 | 描述 | 技术/工具 |
|---|---|---|
| 微信服务号配置 | 注册并配置微信服务号,获取认证信息 | 微信公众平台 |
| Spring Boot集成 | 建立后端服务处理微信消息 | Spring Boot, weixin-java-mp |
| 短信服务集成 | 发送短信验证码给用户 | 阿里云短信API |
| 验证码管理 | 生成、存储和验证短信验证码 | Redis |
| 安全性措施 | 限制发送频率和输入次数,确保安全 | Spring Security, Redis |
| 部署与监控 | 将应用部署到生产环境并进行监控 | 云服务器, 日志监控工具 |
九、结论
通过以上步骤,您可以成功使用Spring Boot开发一个微信服务号,实现向用户推送短信验证码的功能。关键在于正确配置微信服务号、整合短信服务提供商以及确保系统的安全性和稳定性。完善的验证码管理和安全措施将有效提升用户体验并保障系统安全。
参考资料
Last updated February 8, 2025