网络创始人 网站建设,黄埔区网站建设,网站建设简述,中信建设有限责任公司在朝阳区哪个街道在Java开发中#xff0c;发送手机验证码时需要考虑以下几个问题#xff1a;
验证码的有效期#xff1a;验证码应该有一定的有效期#xff0c;一般设置为几分钟或者十几分钟。过期的验证码应该被认为是无效的#xff0c;不能用于验证用户身份。手机号码格式的校验#xf…在Java开发中发送手机验证码时需要考虑以下几个问题
验证码的有效期验证码应该有一定的有效期一般设置为几分钟或者十几分钟。过期的验证码应该被认为是无效的不能用于验证用户身份。手机号码格式的校验应该对用户输入的手机号码进行格式校验确保其符合手机号码的格式要求。例如手机号码应该是11位数字以1开头不含其他字符。验证码的重复使用应该限制验证码的重复使用即同一个验证码不能被多次使用。否则可能导致用户的账号被恶意攻击者盗用。手机号码的安全性应该注意保护用户的手机号码安全不要将用户的手机号码保存在明文格式避免泄露用户的个人信息。验证码的加密传输在发送验证码过程中应该使用加密传输方式避免验证码被拦截或者窃取。发送短信的限制应该限制发送短信的频率和数量避免过度发送短信给用户影响用户体验。发送短信的成本需要考虑发送短信的成本避免浪费资源。可以通过采用短信通道和短信模板的方式降低短信发送的成本。
腾讯云的短信服务满足需求5和7
1.进入腾讯云然后登录 2.腾讯云好像改布局了不能直接在云产品那边搜索需要进入自己的控制台然后搜索短信
3.完成创建短信签名、创建短信正文模板和创建应用每一项右边都会出现详细说明 可以使用标准模板
4.需要记住以下几组数据 签名管理的签名内容 正文模板中的id 左侧应用管理-应用列表的 SDKAppId 最重要的一步CAM 密钥查询链接
pom文件添加 !--腾讯手机验证码--dependencygroupIdcom.tencentcloudapi/groupIdartifactIdtencentcloud-sdk-java/artifactId!-- go to https://search.maven.org/search?qtencentcloud-sdk-java and get the latest version. --!-- 请到https://search.maven.org/search?qtencentcloud-sdk-java查询所有版本最新版本如下 --version3.1.703/version/dependency!--redis依赖--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency!--lombok--dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency!--mp--dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.3/version/dependency!--druid--dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.23/version/dependency配置redis的序列化规则(可读性)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**** author: zpy* Description: rdeis序列化规则* date 2023/2/28*/
Configuration
public class RedisConfiguration {Beanpublic RedisTemplateString,Object redisTemplate(RedisConnectionFactory redisConnectionFactory){RedisTemplateString,Object redisTemplate new RedisTemplate();redisTemplate.setConnectionFactory(redisConnectionFactory);//创建一个json序列化对象GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer new GenericJackson2JsonRedisSerializer();//设置value的序列化方式jsonredisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);//设置key序列化为StringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置hash key序列化方式为StringredisTemplate.setHashKeySerializer(new StringRedisSerializer());//设置hash key序列化方式为jsonredisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}
}application.yml配置
spring:#redisredis:database: 0host: #你的ipport: 6379password: #你的密码timeout: 3000
#开启mp的日志输出到控制台
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#逻辑删除字面值global-config:db-config:logic-delete-field: isDeletedlogic-not-delete-value: 0logic-delete-value: 1#短信验证参数
tencent:msm:id: AKIDfAUcAUcYMyOchw0ueBYlmvtgJm24uX0J#同上, 这个是secretkeysecret: 密码#短信控制台页面-左侧应用管理-应用列表的 SDKAppIdappId: 1400798952#短信控制台页面-左侧国内短信-签名管理 签名内容signName: 个人学习网页成果#短信控制台页面-左侧国内短信-正文模板管理 IdtemplateId: 1715747配置个统一返回的类R这个随便写的不标准测试方便用可以用自己的
import lombok.Data;
import java.util.HashMap;
import java.util.Map;/*** 通用返回结果服务端响应的数据最终都会封装成此对象* param T*/
Data
public class RT {private Integer code; //编码1成功0和其它数字为失败private String msg; //提示信息private T data; //数据private Map map new HashMap(); //动态数据private boolean flag;//标记符public R() {}public R(Integer code, String msg, T data, Map map, boolean flag) {this.code code;this.msg msg;this.data data;this.map map;this.flag flag;}public static T RT success(T object) {RT r new RT();r.data object;r.code 200;return r;}public static T RT success(String msg) {RT r new RT();r.code 200;r.msg msg;r.flag true;return r;}public static T RT error(String msg) {R r new R();r.msg msg;r.code 300;r.flag false;return r;}public RT add(String key, Object value) {this.map.put(key, value);return this;}}实体类
因为我需要把注册信息存到数据库如果你只是来学习发送验证码可以忽略
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;/*** author: zpy* date: 2023/2/28 17:58*/
Data
TableName(student)
public class StudentEntity implements Serializable {/*** 序列化ID*/private static final long serialVersionUID 1L;/*** 学生id,自增*/TableId(type IdType.AUTO)private Long id;/*** 学校名称*/private String school;/*** 专业班级*/private String subject;/*** 学生姓名*/private String name;/*** 电话号*/private String phone;/*** 密码*/private String password;/*** 逻辑删除0是默认1是删除*/private Integer isDeleted;/*** 创建时间*/private String gmtCreate;/*** 修改时间*/private String gmtModified;TableField(existfalse)/*** 验证码*/private String code;}随机数工具类网上随便找的
import java.util.List;
import java.util.Random;public class RandomUtil {private static final Random random new Random();private static final DecimalFormat fourdf new DecimalFormat(0000);private static final DecimalFormat sixdf new DecimalFormat(000000);public static String getFourBitRandom() {return fourdf.format(random.nextInt(10000));}public static String getSixBitRandom() {return sixdf.format(random.nextInt(1000000));}/*** 给定数组抽取n个数据* param list* param n*/public static ArrayList getRandom(List list, int n) {Random random new Random();HashMapObject, Object hashMap new HashMapObject, Object();// 生成随机数字并存入HashMapfor (int i 0; i list.size(); i) {int number random.nextInt(100) 1;hashMap.put(number, i);}// 从HashMap导入数组Object[] robjs hashMap.values().toArray();ArrayList r new ArrayList();// 遍历数组并打印数据for (int i 0; i n; i) {r.add(list.get((int) robjs[i]));System.out.print(list.get((int) robjs[i]) \t);}System.out.print(\n);return r;}
}controller
这边有一个前端按钮按一次就能发送验证码和注册信息录入前端页面自我想象即可
/*** author: 赵鹏宇* date: 2023/3/6 19:05* 注册*/
RestController
RequestMapping(logon)
public class LogonController {Autowiredprivate RedisTemplateString,String redisTemplate;Autowiredprivate LogonService logonService;Resourceprivate StudentDao studentDao;/*** 发送验证码按钮*/PostMapping({phoneNum})public RString sendVerificationCode(PathVariable String phoneNum){//从redis获取取不到再腾讯云发送String code redisTemplate.opsForValue().get(phoneNum);if (!Strings.isEmpty(code)){return R.success(已发送请在手机查看验证码);}//生成随机数code RandomUtil.getSixBitRandom();System.out.println(手机号phoneNum----验证码code);RString send logonService.send(phoneNum, code);if (send.isFlag()){//发送成功就把验证码放在redis中,并设置时间5分钟redisTemplate.opsForValue().set(phoneNum,code,5, TimeUnit.MINUTES);return send;}return send;}/*** 注册按钮* 1.判断输入是否是空* 2.判断手机号是否重复* 3.验证码审核* 4.完成注册*/PostMapping()public R register(RequestBody StudentEntity studentEntity){RString register logonService.register(studentEntity);return register;}}mapper
import com.ace.qiyexuni.domain.StudentEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;/**** author: 赵鹏宇* Description: 学生接口* date 2023/2/28*/
Mapper
public interface StudentDao extends BaseMapperStudentEntity {
}
service层
public interface LogonService {/*** 发送验证码* param phone* param code* return*/RString send(String phone, String code);/*** 注册按钮* param studentEntity*/RString register(StudentEntity studentEntity);
}serviceImpl层满足需求136
正常书写的话短信验证码存储的key应该是“YZM156****4804”这种value对应的随机验证码由于我这个只是demo写的并不规则且这个并没有判断手机号每天可以发送几次由于腾讯云默认同一个手机号30秒内不超过一条1小时不超过5条1天不超过10条这边可以给个思路redis存入一个key为”DAY156****4804“value默认为0做一个计数器手机号每发送成功一次就加1次当达到你所规定的上限就不能发送了
/**** author: 赵鹏宇* Description: 短信发送逻辑* date 2023/2/28*/
Service
Slf4j
public class LogonServiceImpl implements LogonService {Resourceprivate StudentDao studentDao;Autowiredprivate RedisTemplateString,String redisTemplate;Override/*** 发送验证码*/public R send(String phone, String code) {//判断手机是否为nullif (Strings.isEmpty(phone)){return R.error(手机号为空);}//判断手机号是否存在LambdaQueryWrapperStudentEntity lambdaQueryWrapper new LambdaQueryWrapperStudentEntity();lambdaQueryWrapper.eq(phone!null,StudentEntity::getPhone,phone);Integer count studentDao.selectCount(lambdaQueryWrapper);if (count1){return R.error(手机号已存在是否去登录);}try {/* 必要步骤* 实例化一个认证对象入参需要传入腾讯云账户密钥对 secretId 和 secretKey* 本示例采用从环境变量读取的方式需要预先在环境变量中设置这两个值* 您也可以直接在代码中写入密钥对但需谨防泄露不要将代码复制、上传或者分享给他人* CAM 密钥查询https://console.cloud.tencent.com/cam/capi*/Credential cred new Credential(MsmConstantUtil.SECRET_ID, MsmConstantUtil.SECRET_KEY);// 实例化一个http选项可选的没有特殊需求可以跳过HttpProfile httpProfile new HttpProfile();httpProfile.setEndpoint(sms.tencentcloudapi.com);// 实例化一个client选项可选的没有特殊需求可以跳过ClientProfile clientProfile new ClientProfile();clientProfile.setHttpProfile(httpProfile);// 实例化要请求产品的client对象,clientProfile是可选的SmsClient client new SmsClient(cred, ap-beijing, clientProfile);// 实例化一个请求对象,每个接口都会对应一个request对象SendSmsRequest req new SendSmsRequest();String[] phoneNumberSet1 {phone};req.setPhoneNumberSet(phoneNumberSet1);req.setSmsSdkAppId(MsmConstantUtil.APP_ID);req.setSignName(MsmConstantUtil.SIGN_NAME);req.setTemplateId(MsmConstantUtil.TEMPLATE_ID);String[] templateParamSet1 {code, 5};req.setTemplateParamSet(templateParamSet1);// 返回的resp是一个SendSmsResponse的实例与请求对象对应SendSmsResponse resp client.SendSms(req);// 输出 JSON 格式的字符串回包System.out.println(SendSmsResponse.toJsonString(resp));return R.success(发送成功,有效期5分钟);} catch (TencentCloudSDKException e) {e.printStackTrace();}return R.error(发送失败);}/*** 注册按钮* 1.判断手机号是否重复* 2.验证码审核* 3.完成注册*/Overridepublic R register(StudentEntity studentEntity) {//当前时间String now DateUtil.now();studentEntity.setGmtCreate(now);studentEntity.setGmtModified(now);//判断验证码是否正确验证码的key值String key studentEntity.getPhone();boolean isKey keyIsExists(key);if (!isKey){return R.error(请先发送验证码);}//key对应的value值String code redisTemplate.boundValueOps(key).get();if (code.equals(null)){return R.error(未发送验证码);}if(studentEntity.getCode().equals(code)){R.success(验证码正确);}else {return R.error(验证码错误);}//添加到数据库表中int insert studentDao.insert(studentEntity);System.out.println(insert);//删除redis的验证码boolean delete deleteKey(key);System.out.println(是否删除成功delete);return R.success(注册成功);}/*** 判断key是否存在*/public boolean keyIsExists(String key) {return redisTemplate.hasKey(key);}/*** 删除key* param key*/public boolean deleteKey(String key) {return redisTemplate.delete(key);}}现在没满足2和4
满足2让前端判断输入是否符合规则或者你自己后端写 满足4给手机号加密一下md5我个人感觉不太需要密码加密一下可以本demo密码没有加密加密可以自己加一下
接口测试
发送验证码测试 5分钟内再次发送验证码测试 数据库存在手机号 这种的逻辑自己去写即可根据需求文档开发即可就不一一展示了
注册按钮测试