2023-01-16 阿里SMS短信接口使用
用户注册—使用阿里短信接口和Redis
文章目录
- 用户注册—使用阿里短信接口和Redis
- 步骤
- 1.导入依赖
- 2.redis属性配置文件
- 3.spring集成redis配置文件
- 4.短信接口属性配置文件
- 5.短信接口核心配置类
- 6.对应的Service层
- 7.对应的Controller层
步骤
1.用户注册时,在注册页填写手机号进行手机验证码的获取
2.后台收到验证码请求后,首先校验手机号是否已存在
3.若手机号存在,则提醒用户。
4.若不存在,生成验证码,调用短信接口进行验证码发送
5.判断验证码发送是否成功,成功后将用户手机号作为key,验证码作为value存到redis中,并设置redis的key的有效时间为15分钟。来使验证码只有15分钟内有效
6.成功后用户输入信息,判断用户名是否重复。
7.校验完成后提交表单,使用表单数据与redis中手机号对应的数值判断验证码是否正确,进行注册。
1.导入依赖
短信依赖
<!-- 阿里短信 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.0.6</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.1.0</version>
</dependency>
redis依赖
<!-- redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.1.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
2.redis属性配置文件
#redis\u4E2D\u5FC3
#\u7ED1\u5B9A\u7684\u4E3B\u673A\u5730\u5740
redis.host=192.168.25.100
#\u6307\u5B9ARedis\u76D1\u542C\u7AEF\u53E3\uFF0C\u9ED8\u8BA4\u7AEF\u53E3\u4E3A6379
redis.port=6379
#\u6388\u6743\u5BC6\u7801\uFF08\u53EF\u4EE5\u4E0D\u4F7F\u7528\uFF09
#redis.password=bjtu
#\u6700\u5927\u7A7A\u95F2\u6570\uFF1A\u7A7A\u95F2\u94FE\u63A5\u6570\u5927\u4E8EmaxIdle\u65F6\uFF0C\u5C06\u8FDB\u884C\u56DE\u6536
redis.maxIdle=100
#\u6700\u5927\u8FDE\u63A5\u6570\uFF1A\u80FD\u591F\u540C\u65F6\u5EFA\u7ACB\u7684\u201C\u6700\u5927\u94FE\u63A5\u4E2A\u6570\u201D
redis.maxTotal=200
#\u6700\u5927\u7B49\u5F85\u65F6\u95F4\uFF1A\u5355\u4F4Dms
redis.maxWait=1000
#\u4F7F\u7528\u8FDE\u63A5\u65F6\uFF0C\u68C0\u6D4B\u8FDE\u63A5\u662F\u5426\u6210\u529F
redis.testOnBorrow=false
#\u5F53\u5BA2\u6237\u7AEF\u95F2\u7F6E\u591A\u957F\u65F6\u95F4\u540E\u5173\u95ED\u8FDE\u63A5\uFF0C\u5982\u679C\u6307\u5B9A\u4E3A0\uFF0C\u8868\u793A\u5173\u95ED\u8BE5\u529F\u80FD
redis.timeout=10000
redis.prefix=redis:cache:
3.spring集成redis配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xmlns:redis="http://www.springframework.org/schema/redis"
xsi:schemaLocation="http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis-1.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
<context:component-scan base-package="com.li">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:property-placeholder location="classpath:redis.properties,classpath:db.properties" ignore-resource-not-found="true" ignore-unresolvable="true"/>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
<property name="maxTotal" value="${redis.maxTotal}" />
<property name="blockWhenExhausted" value="true" />
</bean>
<!-- jedis连接工程的配置 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="poolConfig" ref="jedisPoolConfig" />
<!-- <property name="password" value="${redis.password}" /> -->
<property name="usePool" value="true"/>
<property name="timeout" value="${redis.timeout}"></property>
</bean>
<!-- redisTemplate配置 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialPoolSize" value="${connection_pools.initial_pool_size}" />
<property name="minPoolSize" value="${connection_pools.min_pool_size}" />
<property name="maxPoolSize" value="${connection_pools.max_pool_size}" />
<property name="maxIdleTime" value="${connection_pools.max_idle_time}" />
<property name="acquireIncrement" value="${connection_pools.acquire_increment}" />
<property name="checkoutTimeout" value="${connection_pools.checkout_timeout}" />
</bean>
<!-- 配置MyBatis的sqlSession -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- <property name="configLocation" value="classpath:mybatis.xml"></property> -->
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
</bean>
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- xml aop事物方式 -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut expression="execution (* com.li.service.*.*(..))" id="serviceMethodAOP"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethodAOP"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 方法名称 以 add加入事物处理 addGoods updateGoods-->
<tx:method name="insert*" propagation="REQUIRED" rollback-for="RunTimeException"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="RunTimeException"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="RunTimeException"/>
<tx:method name="get*" propagation="NOT_SUPPORTED" rollback-for="RunTimeException" read-only="true"/>
<tx:method name="select*" propagation="NOT_SUPPORTED" rollback-for="RunTimeException" read-only="true"/>
<tx:method name="find*" propagation="NOT_SUPPORTED" rollback-for="RunTimeException" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 映射Mapper目录 -->
<!-- Mapper接口所在包名,Spring会自动查找其下的Mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.li.mapper" />
</bean>
<!-- <bean id="sessionUtils" class="com.oracle.utils.SessionUtils"></bean> -->
</beans>
4.短信接口属性配置文件
sms.product =Dysmsapi
sms.domain =dysmsapi.aliyuncs.com
sms.accessKeyId =xxx
sms.accessKeySecret =xxx
sms.templateCode =SMS_xxx
5.短信接口核心配置类
/**
* Created on 17/6/7.
* 短信API产品的DEMO程序,工程中包含了一个SmsDemo类,直接通过
* 执行main函数即可体验短信产品API功能(只需要将AK替换成开通了云通信-短信产品功能的AK即可)
* 工程依赖了2个jar包(存放在工程的libs目录下)
* 1:aliyun-java-sdk-core.jar
* 2:aliyun-java-sdk-dysmsapi.jar
*
* 备注:Demo工程编码采用UTF-8
* 国际短信发送请勿参照此DEMO
*/
@Configuration
@PropertySource("classpath:sms.properties")
public class SmsConfig {
@Value("${sms.product}")
private String product;
@Value("${sms.domain}")
private String domain;
@Value("${sms.accessKeyId}")
private String accessKeyId;
@Value("${sms.accessKeySecret}")
private String accessKeySecret;
@Value("${sms.templateCode}")
private String templateCode;
@Value("Poseidon管理中心")
private String signName;
public SendSmsResponse sendSms(String phone,String randomCode) throws ClientException {
try {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(phone);
//必填:短信签名-可在短信控制台中找到
request.setSignName(signName);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(templateCode);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam("{\"code\":"+randomCode+"}");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
return sendSmsResponse;
} catch (ClientException e) {
throw e;
}
}
public QuerySendDetailsResponse querySendDetails(String bizId) throws ClientException {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象
QuerySendDetailsRequest request = new QuerySendDetailsRequest();
//必填-号码
request.setPhoneNumber("138xxxxxxxx");
//可选-流水号
request.setBizId(bizId);
//必填-发送日期 支持30天内记录查询,格式yyyyMMdd
SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
request.setSendDate(ft.format(new Date()));
//必填-页大小
request.setPageSize(10L);
//必填-当前页码从1开始计数
request.setCurrentPage(1L);
//hint 此处可能会抛出异常,注意catch
QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);
return querySendDetailsResponse;
}
public static void main(String[] args) throws ClientException, InterruptedException {
SmsConfig smsConfig = new SmsConfig();
//发短信
SendSmsResponse response = smsConfig.sendSms("xxxxxx","xxx");
System.out.println("短信接口返回的数据----------------");
System.out.println("Code=" + response.getCode());
System.out.println("Message=" + response.getMessage());
System.out.println("RequestId=" + response.getRequestId());
System.out.println("BizId=" + response.getBizId());
Thread.sleep(3000L);
//查明细
if(response.getCode() != null && response.getCode().equals("OK")) {
QuerySendDetailsResponse querySendDetailsResponse = smsConfig.querySendDetails(response.getBizId());
System.out.println("短信明细查询接口返回数据----------------");
System.out.println("Code=" + querySendDetailsResponse.getCode());
System.out.println("Message=" + querySendDetailsResponse.getMessage());
int i = 0;
for(QuerySendDetailsResponse.SmsSendDetailDTO smsSendDetailDTO : querySendDetailsResponse.getSmsSendDetailDTOs())
{
System.out.println("SmsSendDetailDTO["+i+"]:");
System.out.println("Content=" + smsSendDetailDTO.getContent());
System.out.println("ErrCode=" + smsSendDetailDTO.getErrCode());
System.out.println("OutId=" + smsSendDetailDTO.getOutId());
System.out.println("PhoneNum=" + smsSendDetailDTO.getPhoneNum());
System.out.println("ReceiveDate=" + smsSendDetailDTO.getReceiveDate());
System.out.println("SendDate=" + smsSendDetailDTO.getSendDate());
System.out.println("SendStatus=" + smsSendDetailDTO.getSendStatus());
System.out.println("Template=" + smsSendDetailDTO.getTemplateCode());
}
System.out.println("TotalCount=" + querySendDetailsResponse.getTotalCount());
System.out.println("RequestId=" + querySendDetailsResponse.getRequestId());
}
}
}
6.对应的Service层
@Service
public class MemberService {
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Autowired
private MemberMapper memberMapper;
@Value("${redis.prefix}")
private String redisCache;
/**
* 校验手机号是否重复
* @return
*/
public boolean checkPhone(String phone){
MemberExample memberExample = new MemberExample();
MemberExample.Criteria criteria = memberExample.createCriteria();
criteria.andPhoneEqualTo(phone);
int count = memberMapper.countByExample(memberExample);
return count==0;
}
/**
* 存验证码到redis
* @return
*/
public void cachePhone(String phone,String randomCode){
String redisKey = redisCache+"reg:member:"+phone;
//存redis
redisTemplate.boundValueOps(redisKey).set(randomCode,2, TimeUnit.MINUTES);
}
/**
* 校验短信验证码
* @return
*/
public boolean checkSmsCode(String smsCode,String phone){
String redisKey = redisCache+"reg:member:"+phone;
String code = redisTemplate.boundValueOps(redisKey).get();
if(code==null||!code.equals(smsCode)){
return false;
}
return true;
}
/**
* 注册
*/
public void memberReg(Member memberVo){
memberVo.setStatus(200);
memberMapper.insertSelective(memberVo);
}
/**
* 校验用户名
*/
public boolean checkUsername(String username){
MemberExample memberExample = new MemberExample();
MemberExample.Criteria criteria = memberExample.createCriteria();
criteria.andUsernameEqualTo(username);
int count = memberMapper.countByExample(memberExample);
return count==0;
}
}
7.对应的Controller层
@Slf4j
@Controller
@RequestMapping("member")
public class MemberController {
@Autowired
private MemberService memberService;
@Autowired
private SmsConfig smsConfig;
@RequestMapping("/getMobileCode")
@ResponseBody
public R getMobilePhone(String phone) throws ClientException {
log.info("获取手机验证码开始,手机号:{0}",phone);
boolean flag = memberService.checkPhone(phone);
if(flag){
//验证码
String code = RandomCodeUtils.createRegisterCode().toString();
SendSmsResponse response = null;
try {
//发送短信验证码
response = smsConfig.sendSms(phone, code);
if(response.getCode() != null && response.getCode().equals("OK")) {
//存redis
memberService.cachePhone(phone,code);
return new R(200,"验证码已发送",null);
}
} catch (Exception e) {
QuerySendDetailsResponse querySendDetailsResponse = smsConfig.querySendDetails(response.getBizId());
System.out.println("短信明细查询接口返回数据----------------");
System.out.println("Code=" + querySendDetailsResponse.getCode());
System.out.println("Message=" + querySendDetailsResponse.getMessage());
e.printStackTrace();
return new R(400, querySendDetailsResponse.getMessage(), null);
}
}
return new R(400,"手机号已存在",null);
}
/**
* 用户注册
* @param smsCode
* @return
*/
@RequestMapping("/register")
public String memberReg(Member memberVo, String smsCode, Model model){
//校验短信验证码是否正确
boolean flag = memberService.checkSmsCode(smsCode, memberVo.getPhone());
if(flag){
//验证成功,进行注册
memberService.memberReg(memberVo);
return "reg_success";
}
model.addAttribute("info","手机验证码错误,注册失败");
return "reg";
}
@RequestMapping("/checkUsername")
@ResponseBody
public R checkUsername(String username){
boolean flag = memberService.checkUsername(username);
if(flag){
return new R(200,"用户名可用",null);
}
return new R(400,"用户名已存在",null);
}
}