架构流程

# 短信的架构 # 手机验证码 ## 1. 申请 >阿里云个人是无法申请手机验证码的, 因此, 我们采取下面的方式弄一个测试手机, 用测试收集收验证码 > 加入短信权限 ![image.png](https://cos.easydoc.net/13568421/files/llc4dikj.png) ![image.png](https://cos.easydoc.net/13568421/files/llc4el2p.png) ![image.png](https://cos.easydoc.net/13568421/files/llc4fgym.png) ## 2. 环境构建 ![image.png](https://cos.easydoc.net/13568421/files/llc5dx31.png) > 点击SDK信息获取依赖版本号 ## 逆天大坑 ### 发送请求, 总是显示accessKey不存在 > 因为仔细看官方给的SDK, 里面有一段注解, 中文意思是在环境变量里面获取, 对应着getEnv()这个方法, 设置环境变量没有用的话, 把他删了, 直接注入 ### 方法异步执行, 先于controller执行 > 这是因为有@ConfigurationProperties注解, 导致异步执行, 即声明的这个组件会执行里面所有的方法, 不管是否@Bean, 因此异步 ## 代码 ```java package com.junjie.bitmall.thirdpart.component; import com.aliyun.auth.credentials.Credential; import com.aliyun.auth.credentials.provider.StaticCredentialProvider; import com.aliyun.sdk.service.dysmsapi20170525.AsyncClient; import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsRequest; import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsResponse; import com.google.gson.Gson; import darabonba.core.client.ClientOverrideConfiguration; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * @className: com.junjie.bitmall.thirdpart.component.SMSComponent * @description: * @author: 江骏杰 * @create: 2023-08-15 17:56 */ @Component public class SMSComponent { @Value("${spring.cloud.alicloud.access-key}") private String accessId; @Value("${spring.cloud.alicloud.secret-key}") private String accessKey; public void sendPhoneCode(String phone, String code) throws ExecutionException, InterruptedException { // HttpClient Configuration /*HttpClient httpClient = new ApacheAsyncHttpClientBuilder() .connectionTimeout(Duration.ofSeconds(10)) // Set the connection timeout time, the default is 10 seconds .responseTimeout(Duration.ofSeconds(10)) // Set the response timeout time, the default is 20 seconds .maxConnections(128) // Set the connection pool size .maxIdleTimeOut(Duration.ofSeconds(50)) // Set the connection pool timeout, the default is 30 seconds // Configure the proxy .proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("<your-proxy-hostname>", 9001)) .setCredentials("<your-proxy-username>", "<your-proxy-password>")) // If it is an https connection, you need to configure the certificate, or ignore the certificate(.ignoreSSL(true)) .x509TrustManagers(new X509TrustManager[]{}) .keyManagers(new KeyManager[]{}) .ignoreSSL(false) .build();*/ // Configure Credentials authentication information, including ak, secret, token StaticCredentialProvider provider = StaticCredentialProvider.create(Credential.builder() // Please ensure that the environment variables ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET are set. .accessKeyId(accessId) // 这里有大坑, 默认从环境变量里面获取, 实测无效, 因此改成这样 .accessKeySecret(accessKey) //.securityToken(System.getenv("ALIBABA_CLOUD_SECURITY_TOKEN")) // use STS token .build()); // Configure the Client AsyncClient client = AsyncClient.builder() .region("cn-hangzhou") // Region ID //.httpClient(httpClient) // Use the configured HttpClient, otherwise use the default HttpClient (Apache HttpClient) .credentialsProvider(provider) //.serviceConfiguration(Configuration.create()) // Service-level configuration // Client-level configuration rewrite, can set Endpoint, Http request parameters, etc. .overrideConfiguration( ClientOverrideConfiguration.create() // Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi .setEndpointOverride("dysmsapi.aliyuncs.com") //.setConnectTimeout(Duration.ofSeconds(30)) ) .build(); // Parameter settings for API request SendSmsRequest sendSmsRequest = SendSmsRequest.builder() .signName("阿里云短信测试") .templateCode("SMS_154950909") .phoneNumbers("15570790850") .templateParam("{\"code\":\""+code+"\"}") // 验证码 // Request-level configuration rewrite, can set Http request parameters, etc. // .requestConfiguration(RequestConfiguration.create().setHttpHeaders(new HttpHeaders())) .build(); // Asynchronously get the return value of the API request CompletableFuture<SendSmsResponse> response = client.sendSms(sendSmsRequest); // Synchronously get the return value of the API request SendSmsResponse resp = null; resp = response.get(); System.out.println(new Gson().toJson(resp)); // Asynchronous processing of return values // response.thenAccept(resp -> // System.out.println(new Gson().toJson(resp)) // ).exceptionally(throwable -> { // Handling exceptions // System.out.println(throwable.getMessage()); // return null; // }); // Finally, close the client client.close(); } } ``` # 邮箱验证码 ## 架构 ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> ``` ```yml mail: host: smtp.126.com username: jiangjunjie_db@126.com password: XWFXSGJZJDVXONSG port: 465 #XWFXSGJZJDVXONSG protocol: smtp default-encoding: UTF-8 properties: mail.smtp.auth: true mail.smtp.starttls.enable: true mail.smtp.starttls.required: true mail.smtp.socketFactory.port: 465 mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory mail.smtp.socketFactory.fallback: false ``` ```java /** * * @param to 收件人邮箱 * @param emailTitle 邮件标题 * @param code 验证码 */ public void sendEmailCode(String to, String emailTitle, String code) { // 封装视图, 并渲染视图, 最终获取对应的字符串 Context context = new Context(); context.setVariable("verifyCode", Arrays.asList(code.split(""))); String emailContent = templateEngine.process("mail", context); // 自定义消息 MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = null; try { helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(emailTitle); helper.setText(emailContent, true); } catch (MessagingException e) { e.printStackTrace(); } mailSender.send(message); } ``` ```html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>邮箱验证码</title> <style> table { width: 700px; margin: 0 auto; } #top { width: 700px; border-bottom: 1px solid #ccc; margin: 0 auto 30px; } #top table { font: 12px Tahoma, Arial, 宋体; height: 40px; } #content { width: 680px; padding: 0 10px; margin: 0 auto; } #content_top { line-height: 1.5; font-size: 14px; margin-bottom: 25px; color: #4d4d4d; } #content_top strong { display: block; margin-bottom: 15px; } #content_top strong span { color: #f60; font-size: 16px; } #verificationCode { color: #f60; font-size: 24px; } #content_bottom { margin-bottom: 30px; } #content_bottom small { display: block; margin-bottom: 20px; font-size: 12px; color: #747474; } #bottom { width: 700px; margin: 0 auto; } #bottom div { padding: 10px 10px 0; border-top: 1px solid #ccc; color: #747474; margin-bottom: 20px; line-height: 1.3em; font-size: 12px; } #content_top strong span { font-size: 18px; color: #FE4F70; } #sign { text-align: right; font-size: 18px; color: #FE4F70; font-weight: bold; } #verificationCode { height: 100px; width: 680px; text-align: center; margin: 30px 0; } #verificationCode div { height: 100px; width: 680px; } .button { color: #FE4F70; margin-left: 10px; height: 80px; width: 80px; resize: none; font-size: 42px; border: none; outline: none; padding: 10px 15px; background: #ededed; text-align: center; border-radius: 17px; box-shadow: 6px 6px 12px #cccccc, -6px -6px 12px #ffffff; } .button:hover { box-shadow: inset 6px 6px 4px #d1d1d1, inset -6px -6px 4px #ffffff; } </style> </head> <body> <table> <tbody> <tr> <td> <div id="top"> <table> <tbody><tr><td></td></tr></tbody> </table> </div> <div id="content"> <div id="content_top"> <strong>尊敬的用户:您好!</strong> <strong> 您正在进行<span>注册账号</span>操作,请在验证码中输入以下验证码完成操作: </strong> <div id="verificationCode"> <button class="button" th:each="a:${verifyCode}">[[${a}]]</button> </div> </div> <div id="content_bottom"> <small> 注意:此操作可能会修改您的密码、登录邮箱或绑定手机。如非本人操作,请及时登录并修改密码以保证账号安全 <br>(工作人员不会向你索取此验证码,请勿泄漏!) </small> </div> </div> <div id="bottom"> <div> <p>此为系统邮件,请勿回复<br> 请保管好您的邮箱,避免账号被他人盗用 </p> <p id="sign">——JUNJIE_SEND</p> </div> </div> </td> </tr> </tbody> </table> </body> ```