总览:
在web模块下的service包,补充短信接口(SmsService):检查用户发送的验证码是否正确
package com.bjpowernode.front.service;public interface SmsService {/*** @param phone 手机号* @return true:发送成功,false 其他情况*/boolean sendSms(String phone);/*** @param phone 手机号* @param code 提交参数中的验证码* @return*/boolean checkSmsCode(String phone,String code);
}
实现这个接口还没有实现的方法,在SmsCodeRegisterImpl添加,验证客户端接受到短信验证码是否正确:
package com.bjpowernode.front.service.impl;import com.alibaba.fastjson.JSONObject;
import com.bjpowernode.common.constants.RedisKey;
import com.bjpowernode.front.config.JdwxSmsConfig;
import com.bjpowernode.front.service.SmsService;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;/*** 注册发送短信验证码*/@Service(value = "smsCodeRegisterImpl")
public class SmsCodeRegisterImpl implements SmsService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Resourceprivate JdwxSmsConfig smsConfig;@Overridepublic boolean sendSms(String phone) {boolean send = false;// 设置短信内容String random = RandomStringUtils.randomNumeric(4);System.out.println("注册验证码的随机数 random="+random);//更新content中的 %s 【大富科技】你的验证码是:%s,3分钟内有效,请勿泄露给他人String content = String.format(smsConfig.getContent(), random);//使用HttpClient发送 get 请求给第三方。CloseableHttpClient client = HttpClients.createDefault();//https://way.jd.com/chuangxin/dxjk?mobile=13568813957&content=//【创信】你的验证码是:5873,3分钟内有效!&appkey=您申请的APPKEYString url = smsConfig.getUrl()+"?mobile="+phone+"&content=" + content+"&appkey="+smsConfig.getAppkey();HttpGet get = new HttpGet(url);try{CloseableHttpResponse response = client.execute(get);if( response.getStatusLine().getStatusCode() == HttpStatus.SC_OK ){//得到返回的数据,jsonString text = EntityUtils.toString(response.getEntity());//解析jsonif(StringUtils.isNotBlank(text)){// fastjsonJSONObject jsonObject = JSONObject.parseObject(text);if("10000".equals(jsonObject.getString("code"))){ //第三方接口调用成功//读取result中的key:ReturnStatusif("Success".equalsIgnoreCase(jsonObject.getJSONObject("result").getString("ReturnStatus"))){//短信发送成功send = true;//把短信验证码,存到redisString key = RedisKey.KEY_SMS_CODE_REG + phone;stringRedisTemplate.boundValueOps(key).set(random,3 , TimeUnit.MINUTES);}}}}}catch (Exception e){e.printStackTrace();}return send;}@Overridepublic boolean checkSmsCode(String phone, String code) {String key = RedisKey.KEY_SMS_CODE_REG + phone;if( stringRedisTemplate.hasKey(key)){String querySmsCode = stringRedisTemplate.boundValueOps(key).get();if( code.equals(querySmsCode)){ // 输入的验证码和redis里相应的验证码是否相等return true;}}return false;}}
在api模块下的service包,补充用户接口(UserService):用户注册
package com.bjpowernode.api.service;import com.bjpowernode.api.model.User;
import com.bjpowernode.api.pojo.UserAccountInfo;public interface UserService {/*** 根据手机号查询数据*/User queryByPhone(String phone);/*用户注册*/int userRegister(String phone, String password);/*登录*/User userLogin(String phone, String pword);/*更新实名认证信息*/boolean modifyRealname(String phone, String name, String idCard);/*获取用户和资金信息*/UserAccountInfo queryUserAllInfo(Integer uid);/*查询用户*/User queryById(Integer uid);
}
实现这个接口方法,在dataservice模块service包下,补充UserServiceImpl,用户注册:
1、检查参数(电话是否标准,密码是否标准)
2、判断注册手机号是否已经注册过
3、md5密码加密
4、注册用户(向user数据表添加数据)
5、获取用户主键值(编写相应的mapper)
6、判断
package com.bjpowernode.dataservice.service;import com.bjpowernode.api.model.FinanceAccount;
import com.bjpowernode.api.model.User;
import com.bjpowernode.api.pojo.UserAccountInfo;
import com.bjpowernode.api.service.UserService;
import com.bjpowernode.common.util.CommonUtil;
import com.bjpowernode.dataservice.mapper.FinanceAccountMapper;
import com.bjpowernode.dataservice.mapper.UserMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;@DubboService(interfaceClass = UserService.class,version = "1.0")
public class UserServiceImpl implements UserService {@Resourceprivate UserMapper userMapper;@Resourceprivate FinanceAccountMapper financeAccountMapper;@Value("${ylb.config.password-salt}")private String passwordSalt;@Overridepublic User queryByPhone(String phone) {User user = null;if(CommonUtil.checkPhone(phone)){user = userMapper.selectByPhone(phone);}return user;}/*用户注册*/@Transactional(rollbackFor = Exception.class) // 开启事务@Overridepublic synchronized int userRegister(String phone, String password) { // synchronized:同步的方法,保证线程安全,该方法处理时,其他方法不能对其参数二次处理(phone和password)int result = 0;//默认参数不正确if( CommonUtil.checkPhone(phone)&& (password != null && password.length()==32)){//判断手机号在库中是否存在User queryUser = userMapper.selectByPhone(phone);if(queryUser == null){//注册密码的md5二次加密。 给原始的密码加盐(salt)String newPassword = DigestUtils.md5Hex( password + passwordSalt);//注册u_userUser user = new User();user.setPhone(phone);user.setLoginPassword(newPassword);user.setAddTime(new Date());userMapper.insertReturnPrimaryKey(user);//获取主键user.getId()FinanceAccount account = new FinanceAccount();account.setUid(user.getId());account.setAvailableMoney(new BigDecimal("0"));financeAccountMapper.insertSelective(account);//成功result = 1result = 1;} else {//手机号存在result = 2;}}return result;}/*登录*/@Transactional(rollbackFor = Exception.class)@Overridepublic User userLogin(String phone, String password) {User user = null;if( CommonUtil.checkPhone(phone) && (password != null && password.length() == 32)) {String newPassword = DigestUtils.md5Hex( password + passwordSalt);user = userMapper.selectLogin(phone,newPassword);//更新最后登录时间if( user != null){user.setLastLoginTime(new Date());userMapper.updateByPrimaryKeySelective(user);}}return user;}/*更新实名认证信息*/@Overridepublic boolean modifyRealname(String phone, String name, String idCard) {int rows = 0;if(!StringUtils.isAnyBlank(phone,name,idCard)){rows = userMapper.updateRealname(phone,name,idCard);}return rows > 0 ;}/*获取用户和资金信息*/@Overridepublic UserAccountInfo queryUserAllInfo(Integer uid) {UserAccountInfo info = null;if( uid != null && uid > 0 ) {info = userMapper.selectUserAccountById(uid);}return info ;}/*查询用户*/@Overridepublic User queryById(Integer uid) {User user = null;if( uid != null && uid > 0 ){user = userMapper.selectByPrimaryKey(uid);}return user;}
}
其中:
1、md5加密需要在dataservice模块下resources/application.yml,添加配置信息:
#密码的盐
ylb:config:password-salt: fiwsyhrf9wejroi2huio3y4234operw3
2、添加记录,获取主键值(需要在dataservice模块mapper包下的UserMapper接口添加方法,并在resources/mappers/UserMapper.xml编写SQL语句):
/*添加记录,获取主键值*/int insertReturnPrimaryKey(User user);
<!--添加记录,获取主键值--><insert id="insertReturnPrimaryKey">insert into u_user(phone, login_password,add_time)values(#{phone},#{loginPassword},#{addTime})<selectKey keyColumn="newId" keyProperty="id" resultType="int" order="AFTER">select LAST_INSERT_ID() as newId</selectKey></insert>
手机号注册属于“用户功能”,所以在web模块的usercontroller类下添加:
package com.bjpowernode.front.controller;import com.bjpowernode.api.model.User;
import com.bjpowernode.api.pojo.UserAccountInfo;
import com.bjpowernode.common.enums.RCode;
import com.bjpowernode.common.util.CommonUtil;
import com.bjpowernode.common.util.JwtUtil;
import com.bjpowernode.front.service.RealnameServiceImpl;
import com.bjpowernode.front.service.SmsService;
import com.bjpowernode.front.view.RespResult;
import com.bjpowernode.front.vo.RealnameVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.jute.compiler.generated.Rcc;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.management.relation.Relation;
import java.util.HashMap;
import java.util.Map;@Api(tags = "用户功能")
@RestController
@RequestMapping("/v1/user")
public class UserController extends BaseController {@Resource(name = "smsCodeRegisterImpl")private SmsService smsService;@Resource(name = "smsCodeLoginImpl")private SmsService loginSmsService;@Resourceprivate RealnameServiceImpl realnameService;@Resourceprivate JwtUtil jwtUtil;/**手机号注册用户*/@ApiOperation(value = "手机号注册用户")@PostMapping("/register")public RespResult userRegister(@RequestParam String phone,@RequestParam String pword,@RequestParam String scode){RespResult result = RespResult.fail();//1.检查参数if( CommonUtil.checkPhone(phone)){if(pword !=null && pword.length() == 32 ){//检查短信验证码if( smsService.checkSmsCode(phone,scode)){//可以注册int registerResult = userService.userRegister(phone,pword);if( registerResult == 1 ){result = RespResult.ok();} else if( registerResult == 2 ){result.setRCode(RCode.PHONE_EXISTS);} else {result.setRCode(RCode.REQUEST_PARAM_ERR);}} else {//短信验证码无效result.setRCode(RCode.SMS_CODE_INVALID);}} else {result.setRCode(RCode.REQUEST_PARAM_ERR);}} else {//手机号格式不正确result.setRCode(RCode.PHONE_FORMAT_ERR);}return result;}/** 手机号是否存在 */@ApiOperation(value = "手机号是否注册过",notes = "在注册功能中,判断手机号是否可以注册")@ApiImplicitParam(name = "phone",value = "手机号")@GetMapping("/phone/exists")public RespResult phoneExists(@RequestParam("phone") String phone){RespResult result = new RespResult();result.setRCode(RCode.PHONE_EXISTS);//1.检查请求参数是否符合要求if(CommonUtil.checkPhone(phone)){//可以执行逻辑 ,查询数据库,调用数据服务User user = userService.queryByPhone(phone);if( user == null ){//可以注册result = RespResult.ok();}//把查询到的手机号放入redis。 然后检查手机号是否存在,可以查询redis} else {result.setRCode(RCode.PHONE_FORMAT_ERR);}return result;}/** 登录,获取token-jwt*/@ApiOperation(value = "用户登录-获取访问token")@PostMapping("/login")public RespResult userLogin(@RequestParam String phone,@RequestParam String pword,@RequestParam String scode) throws Exception{RespResult result = RespResult.fail();if(CommonUtil.checkPhone(phone) && (pword != null && pword.length() == 32) ){if(loginSmsService.checkSmsCode(phone,scode)){//访问data-serviceUser user = userService.userLogin(phone,pword);if( user != null){//登录成功,生成tokenMap<String, Object> data = new HashMap<>();data.put("uid",user.getId());String jwtToken = jwtUtil.createJwt(data,120);result = RespResult.ok();result.setAccessToken(jwtToken);Map<String,Object> userInfo = new HashMap<>();userInfo.put("uid",user.getId());userInfo.put("phone",user.getPhone());userInfo.put("name",user.getName());result.setData(userInfo);} else {result.setRCode(RCode.PHONE_LOGIN_PASSWORD_INVALID);}} else {result.setRCode(RCode.SMS_CODE_INVALID);}} else {result.setRCode(RCode.REQUEST_PARAM_ERR);}return result;}/** 实名认证 vo: value object*/@ApiOperation(value = "实名认证",notes = "提供手机号和姓名,身份证号。 认证姓名和身份证号是否一致")@PostMapping("/realname")public RespResult userRealname(@RequestBody RealnameVO realnameVO){RespResult result = RespResult.fail();result.setRCode(RCode.REQUEST_PARAM_ERR);//1验证请求参数if( CommonUtil.checkPhone(realnameVO.getPhone())){if(StringUtils.isNotBlank(realnameVO.getName()) &&StringUtils.isNotBlank(realnameVO.getIdCard())){//判断用户已经做过User user = userService.queryByPhone(realnameVO.getPhone());if( user != null ){if( StringUtils.isNotBlank(user.getName())){result.setRCode(RCode.REALNAME_RETRY);} else {//有短信验证码,先不写//调用第三方接口,判断认证结果boolean realnameResult = realnameService.handleRealname(realnameVO.getPhone(),realnameVO.getName(),realnameVO.getIdCard());if( realnameResult == true ){result = RespResult.ok();} else {result.setRCode(RCode.REALNAME_FAIL);}}}}}return result;}/** 用户中心 */@ApiOperation(value = "用户中心")@GetMapping("/usercenter")public RespResult userCenter(@RequestHeader(value = "uid",required = false) Integer uid){RespResult result = RespResult.fail();if( uid != null && uid > 0 ){UserAccountInfo userAccountInfo = userService.queryUserAllInfo(uid);if( userAccountInfo != null ){result = RespResult.ok();Map<String,Object> data = new HashMap<>();data.put("name",userAccountInfo.getName());data.put("phone",userAccountInfo.getPhone());data.put("headerUrl",userAccountInfo.getHeaderImage());data.put("money",userAccountInfo.getAvailableMoney());if( userAccountInfo.getLastLoginTime() != null){data.put("loginTime", DateFormatUtils.format(userAccountInfo.getLastLoginTime(),"yyyy-MM-dd HH:mm:ss"));} else {data.put("loginTime","-");}result.setData(data);}}return result;}
}