SpringBoot+react/umi实现手机短信验证登陆功能

点击上方 java项目开发选择 设为星标javascript

优质文章,及时送达前端

--

案例功能效果图

前端初始页面vue

点击获取验证码交互效果页面java


手机获取短信验证码成功页面mysql



登陆成功页面react


登陆成功能够直接设置跳转任何页面
git


环境介绍

前端:umijsgithub

后端:springbootweb

jdk:1.8及以上redis

数据库:mysql


完整源码获取方式



源码获取方式

扫码关注回复【duanxin】获取完整源码


若是你在运行这个代码的过程当中有遇到问题,请加小编微信xxf960513,我拉你进对应微信学习群!!帮助你快速掌握这个功能代码!




核心代码介绍



pom.xml


      <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-access</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.3</version> </dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.25</version> <scope>compile</scope> </dependency>
<!-- swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> <version>1.5.21</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.3</version> </dependency>
<!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version>        </dependency> <!--短信功能须要的jar包依赖--> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>3.2.8</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-dysmsapi</artifactId> <version>1.1.0</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency>    </dependencies></project>

application.properties


server.port=8002#server.servlet.context-path=/spring.datasource.url=jdbc:mysql://xxxxx:3306/xxxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaispring.datasource.username=xxxxxxxxxspring.datasource.password=xxxxxxxxxspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver#开启驼峰命名mybatis.configuration.map-underscore-to-camel-case=true#设置超时时间-可自行调整sms.default.connect.timeout=sun.net.client.defaultConnectTimeoutsms.default.read.timeout=sun.net.client.defaultReadTimeoutsms.timeout=10000#初始化ascClient须要的几个参数#短信API产品名称(短信产品名固定,无需修改)sms.product=Dysmsapi#短信API产品域名(接口地址固定,无需修改)sms.domain=dysmsapi.aliyuncs.com#替换成你的AK (产品密)#你的accessKeyId,填你本身的 上文配置所得 自行配置sms.access.key.id=xxxxxxx#你的accessKeyId,填你本身的 上文配置所得 自行配置sms.access.key.secret=xxxxxxxxx#阿里云配置你本身的短信模板填入sms.template.code=xxxxxxxx提示:以上是xxxxxxxxx的代码都得修改为你本身对应的参数

MessageUtils.java

package com.example.demo.utils;import com.aliyuncs.DefaultAcsClient;import com.aliyuncs.IAcsClient;import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;import com.aliyuncs.exceptions.ClientException;import com.aliyuncs.http.MethodType;import com.aliyuncs.profile.DefaultProfile;import com.aliyuncs.profile.IClientProfile;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Component;import org.springframework.web.client.RestTemplate;import java.util.HashMap;import java.util.Map;
@Componentpublic class MessageUtils { @Autowired RestTemplate restTemplate;
@Value("${sms.default.connect.timeout}") private String DEFAULT_CONNECT_TIMEOUT;
@Value("${sms.default.read.timeout}") private String DEFAULT_READ_TIMEOUT;
@Value("${sms.timeout}") private String SMS_TIMEOUT;
@Value("${sms.product}") private String SMS_PRODUCT;
@Value("${sms.domain}") private String SMS_DOMAIN;
@Value("${sms.access.key.id}") private String SMS_ACCESSKEYID;
@Value("${sms.access.key.secret}") private String SMS_ACCESSKEYSECRET;
@Value("${sms.template.code}") private String TEMPLATE_CODE;
private static String code;//code对应你短信目标里面的参数
public Map getPhoneMsg(String phone) { if (phone == null || phone == "") { System.out.println("手机号为空"); return null; } // 设置超时时间-可自行调整 System.setProperty(DEFAULT_CONNECT_TIMEOUT, SMS_TIMEOUT); System.setProperty(DEFAULT_READ_TIMEOUT, SMS_TIMEOUT); // 初始化ascClient须要的几个参数 final String product = SMS_PRODUCT; final String domain = SMS_DOMAIN; // 替换成你的AK final String accessKeyId = SMS_ACCESSKEYID; final String accessKeySecret = SMS_ACCESSKEYSECRET; // 初始化ascClient,暂时不支持多region IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
Map map = new HashMap(); try { DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
//获取验证码 code = vcode(); IAcsClient acsClient = new DefaultAcsClient(profile); // 组装请求对象 SendSmsRequest request = new SendSmsRequest(); // 使用post提交 request.setMethod(MethodType.POST); // 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式 request.setPhoneNumbers(phone); // 必填:短信签名-可在短信控制台中找到 request.setSignName("java学习"); // 必填:短信模板-可在短信控制台中找到 request.setTemplateCode(TEMPLATE_CODE); // 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 // 友情提示:若是JSON中须要带换行符,请参照标准的JSON协议对换行符的要求,好比短信内容中包含\r\n的状况在JSON中须要表示成\\r\\n,不然会致使JSON在服务端解析失败 request.setTemplateParam("{ \"code\":\"" + code + "\"}"); // 可选-上行短信扩展码(无特殊需求用户请忽略此字段) // request.setSmsUpExtendCode("90997"); // 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者 request.setOutId("yourOutId"); // 请求失败这里会抛ClientException异常 SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); map.put("status", sendSmsResponse.getCode()); if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) { // 请求成功 map.put("msg", code); } else { //若是验证码出错,会输出错误码告诉你具体缘由 map.put("msg", sendSmsResponse.getMessage()); } } catch (Exception e) { e.printStackTrace(); map.put("status", "FAIL"); map.put("msg", "获取短信验证码失败"); } return map;    } /** * 生成6位随机数验证码 * * @return */ public static String vcode() { String vcode = ""; for (int i = 0; i < 6; i++) { vcode = vcode + (int) (Math.random() * 9); } return vcode;    }}

MessageController.java

package com.example.demo.controller;import com.alibaba.fastjson.JSON;import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;import com.example.demo.service.MessageService;import com.example.demo.utils.MessageUtils;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;import java.util.Map;
@Api(description = "短信接口")@RequestMapping("/smsLogin")@RestControllerpublic class MessageController { @Autowired public MessageService messageService;
@Autowired public MessageUtils messageUtils;
@ApiOperation(value = "获取短信验证码接口", notes = "获取短信验证码接口") @GetMapping("/sendMessage") public Map<String, Object> getSMSMessage(String phone) { Map<String, Object> map = new HashMap<>(); if (phone == null || phone == "") { map.put("code", "FAIL"); map.put("msg", "手机号为空"); return map; } Map smsMap = messageUtils.getPhoneMsg(phone); if("OK".equals(smsMap.get("status"))){ Map data = messageService.selectSMSDataByPhone(phone); map.put("phone", phone); map.put("smsCode", smsMap.get("msg")); // 将验证码存入数据库 也能够考虑用redis等方式 这里就用数据库作例子 if (data != null) { messageService.updateSMSDataByPhone(map); } else { messageService.insert(map); } smsMap.put("msg", "成功"); } return smsMap; }
@ApiOperation(value = "短信校验登陆接口", notes = "短信校验登陆接口") @GetMapping("/login") public Map<String, Object> login(String phone, String smsCode) { Map<String, Object> map = new HashMap<>(); if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(smsCode)) { map.put("code", "FAIL"); map.put("msg", "请检查数据"); return map; } // 取出对应的验证码进行比较便可 Map smsMap = messageService.selectSMSDataByPhone(phone); if (smsMap == null) { map.put("code", "FAIL"); map.put("msg", "该手机号未发送验证码"); return map; } String code = (String) smsMap.get("sms_code"); if (!smsCode.equals(code)) { map.put("code", "FAIL"); map.put("msg", "验证码不正确"); return map; } map.put("code", "OK"); map.put("msg", "success"); return map; }}

MessageMapper.java

package com.example.demo.mapper;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Select;import org.apache.ibatis.annotations.Update;import java.util.Map;
@Mapperpublic interface MessageMapper { @Select("select * from SMS_MESSAGE where PHONE=#{phone}") Map selectSMSDataByPhone(String phone);
@Update("update SMS_MESSAGE set SMS_CODE = #{smsCode} where phone=#{phone}") int updateSMSDataByPhone(Map smsMap);
@Insert("insert into SMS_MESSAGE (PHONE,SMS_CODE) values (#{phone},#{smsCode})") int insert(Map smsMap);}

MessageService.java

package com.example.demo.service;import com.example.demo.mapper.MessageMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;
import java.util.Map;
@Servicepublic class MessageService { @Autowired public MessageMapper messageMapper;
public Map selectSMSDataByPhone(String phone) { return messageMapper.selectSMSDataByPhone(phone); }
public int updateSMSDataByPhone(Map smsMap) { return messageMapper.updateSMSDataByPhone(smsMap); }
public int insert(Map smsMap) { return messageMapper.insert(smsMap); }}

index.js

import { MailTwoTone, MobileTwoTone } from '@ant-design/icons';import { Alert, message } from 'antd';import React, { useState } from 'react';import ProForm, { ProFormCaptcha, ProFormText } from '@ant-design/pro-form';
import { getFakeCaptcha, phoneLogin } from '@/service/login';
import styles from './index.less';
export default function({ history }) { const [loading, setLoading] = useState(false);
const handleSubmit = async values => { setLoading(true); let params = { phone: values.mobile, smsCode: values.captcha, };
const result = await phoneLogin(params); if (result.code === 'OK') { message.success(result.msg);
history.push('/home'); } else { message.error(result.msg); } }; return ( <div className={styles.main}> <ProForm initialValues={{ autoLogin: true, }} submitter={{ render: (_, dom) => dom.pop(), submitButtonProps: { loading: loading, size: 'large', style: { width: '100%', }, }, }} onFinish={async values => { handleSubmit(values); }} > <div> <ProFormText fieldProps={{ size: 'large', prefix: <MobileTwoTone className={styles.prefixIcon} />, }} name="mobile" placeholder="手机号" rules={[ { required: true, message: '请输入手机号!', }, { pattern: /^1\d{10}$/, message: '手机号格式错误!', }, ]} /> <ProFormCaptcha fieldProps={{ size: 'large', prefix: <MailTwoTone className={styles.prefixIcon} />, }} captchaProps={{ size: 'large', }} placeholder="请输入验证码" captchaTextRender={(timing, count) => (timing ? `${count} 获取验证码` : '获取验证码')} name="captcha" rules={[ { required: true, message: '请输入验证码!', }, ]} onGetCaptcha={async mobile => { console.log(mobile, 'phone'); const result = await getFakeCaptcha(mobile);
message.success('获取验证码成功!请查看手机'); }} /> </div> </ProForm> </div> );}

login.js

import request from '@/utils/request';
export async function phoneLogin({ phone, smsCode }) { return request(`http://xxxxx:8002/smsLogin/login?phone=${phone}&smsCode=${smsCode}`);}
export async function getFakeCaptcha(mobile) { return request(`http://xxxxx:8002/smsLogin/sendMessage?phone=${mobile}`);}

test.sql

CREATE TABLE `SMS_MESSAGE` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `phone` varchar(11) NOT NULL, `sms_code` varchar(6) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;--每次生成的验证码都会存进数据库,登陆的时候进行查询判断

--完--

推荐案例

温暖提示

为了方便你们更好的学习,本公众号常常分享一些 完整的单个功能案例代码给你们去练习, 若是本公众号没有你要学习的功能案例,你能够联系小编(微信:xxf960513)提供你的小需求给我,我安排咱们这边的开发团队免费帮你完成你的案例。
注意:只能提单个功能的需求不能要求功能太多,好比要求用什么技术,有几个页面,页面要求怎么样?


请长按识别二维码

想学习更多的java功能案例请关注

Java项目开发

若是你以为这个案例以及咱们的分享思路不错,对你有帮助,请分享给身边更多须要学习的朋友。别忘了《留言+点在看》给做者一个鼓励哦!

本文分享自微信公众号 - web项目开发(javawebkaifa)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。