美食社交APP项目--用户注册
写在开局 : 本篇文章 和 美食社交的认证授权中心同步, 实现简单功能:
[用户登录与注册], 同时附上认证授权的文章地址:认证授权文章链接
1. 发送验证码
1.2 Redis 配置类
package com.itkaka.diners.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisTemplateConfiguration {/*** redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类** @param redisConnectionFactory* @return*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用Jackson2JsonRedisSerialize 替换默认序列化Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 设置key和value的序列化规则redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}}
1.3 公共枚举类
package com.itkaka.commons.constant;import lombok.Getter;@Getter
public enum RedisKeyConstant {verify_code("verify_code:", "验证码"),private String key;private String desc;RedisKeyConstant(String key, String desc) {this.key = key;this.desc = desc;}}
1.4 Service业务层代码
package com.itkaka.diners.service;import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.itkaka.commons.constant.RedisKeyConstant;
import com.itkaka.commons.utils.AssertUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;/*** 发送验证码业务逻辑层*/
@Service
public class SendVerifyCodeService {@Resourceprivate RedisTemplate<String, String> redisTemplate;/*** 发送验证码** @param phone*/public void send(String phone) {// 检查非空AssertUtil.isNotEmpty(phone, "手机号不能为空");// 根据手机号查询是否已生成验证码,已生成直接返回if (!checkCodeIsExpired(phone)) {return;}// 生成 6 位验证码String code = RandomUtil.randomNumbers(6);// 调用短信服务发送短信(忽略)// 发送成功,将 code 保存到 Redis,失效时间 60sString key = RedisKeyConstant.verify_code.getKey() + phone;redisTemplate.opsForValue().set(key, code, 60, TimeUnit.SECONDS);}/*** 根据手机号查询是否已生成验证码** @param phone* @return*/private boolean checkCodeIsExpired(String phone) {String key = RedisKeyConstant.verify_code.getKey() + phone;String code = redisTemplate.opsForValue().get(key);return StrUtil.isBlank(code) ? true : false;}/*** 根据手机号获取验证码** @param phone* @return*/public String getCodeByPhone(String phone) {String key = RedisKeyConstant.verify_code.getKey() + phone;return redisTemplate.opsForValue().get(key);}}
1.5 Controller控制层代码
package com.itkaka.diners.controller;import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.utils.ResultInfoUtil;
import com.itkaka.diners.service.SendVerifyCodeService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;/*** 发送验证码控制层*/
@RestController
public class SendVerifyCodeController {@Resourceprivate HttpServletRequest request;@Resourceprivate SendVerifyCodeService sendVerifyCodeService;/*** 发送验证码** @param phone* @return*/@GetMapping("send")public ResultInfo<String> send(String phone) {sendVerifyCodeService.send(phone);return ResultInfoUtil.buildSuccess("发送成功", request.getServletPath());}}
1.6 网关设置
白名单放行发送验证码接口
server:port: 80 # 端口spring:application:name: fs_gateway # 应用名cloud:gateway:discovery:locator:enabled: true # 开启配置注册中心进行路由功能lower-case-service-id: true # 将服务名称转小写routes:- id: fs_dinersuri: lb://fs_dinerspredicates:- Path=/diners/**filters:- StripPrefix=1- id: fs_oauthuri: lb://fs_oauthpredicates:- Path=/auth/**filters:- StripPrefix=1secure:ignore:urls: # 配置白名单路径- /actuator/**- /auth/oauth/**- /diners/signin- /diners/send# 配置 Eureka Server 注册中心
eureka:instance:# 开启 ip 注册prefer-ip-address: trueinstance-id: ${spring.cloud.client.ip-address}:${server.port}client:service-url:defaultZone: http://localhost:8090/eureka/# 配置日志
logging:pattern:console: '%d{2100-01-01 13:14:00.666} [%thread] %-5level %logger{50} - %msg%n'
1.7 测试
访问:http://localhost/diners/send?phone=12311112222
返回结果:
{"code": 1,"message": "Successful.","path": "发送成功","data": "/send"
}
2. 注册
2.1 是否已注册
2.1.1 Mapper持久层
package com.itkaka.diners.mapper;import com.itkaka.commons.model.dto.DinersDTO;
import com.itkaka.commons.model.pojo.Diners;
import com.itkaka.commons.model.vo.ShortDinerInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;import java.util.List;/*** 食客 Mapper*/
public interface DinersMapper {/*** 根据手机号查询食客信息** @param phone* @return*/@Select("select id, username, phone, email, is_valid " +" from t_diners where phone = #{phone}")Diners selectByPhone(@Param("phone") String phone);/*** 根据用户名查询食客信息** @param username* @return*/@Select("select id, username, phone, email, is_valid " +" from t_diners where username = #{username}")Diners selectByUsername(@Param("username") String username);/*** 新增食客信息** @param dinersDTO* @return*/@Insert("insert into " +" t_diners (username, password, phone, roles, is_valid, create_date, update_date) " +" values (#{username}, #{password}, #{phone}, \"ROLE_USER\", 1, now(), now())")int save(DinersDTO dinersDTO);/*** 根据 ID 集合查询食客信息** @param ids* @return*/@Select("<script> " +" select id, nickname, avatar_url from t_diners " +" where is_valid = 1 and id in " +" <foreach item='id' collection='ids' open='(' separator=',' close=')'> " +" #{id} " +" </foreach> " +" </script>")List<ShortDinerInfo> findByIds(@Param("ids") String[] ids);}
2.1.2 Service
package com.itkaka.diners.service;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.itkaka.commons.constant.ApiConstant;
import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.model.dto.DinersDTO;
import com.itkaka.commons.model.pojo.Diners;
import com.itkaka.commons.model.vo.ShortDinerInfo;
import com.itkaka.commons.utils.AssertUtil;
import com.itkaka.commons.utils.ResultInfoUtil;
import com.itkaka.diners.config.OAuthClientConfiguration;
import com.itkaka.diners.config.OAuthClientConfiguration;
import com.itkaka.diners.mapper.DinersMapper;
import com.itkaka.diners.model.domain.OAuthDinerInfo;
import com.itkaka.diners.model.vo.LoginDinerInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;/*** 食客服务业务逻辑层*/
@Service
public class DinersService {@Resourceprivate RestTemplate restTemplate;@Value("${service.name.fs_oauth-server}")private String oauthServerName;@Resourceprivate OAuthClientConfiguration oAuthClientConfiguration;@Resourceprivate DinersMapper dinersMapper;@Resourceprivate com.itkaka.diners.service.SendVerifyCodeService sendVerifyCodeService;/*** 登录** @param account 账号信息:用户名或手机或邮箱* @param password 密码* @param path 请求路径* @return*/public ResultInfo signIn(String account, String password, String path) {// 参数校验AssertUtil.isNotEmpty(account, "请输入登录账户");AssertUtil.isNotEmpty(password, "请输入登录密码");// 构建请求头HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);// 构建请求体MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();body.add("username", account);body.add("password", password);body.setAll(BeanUtil.beanToMap(oAuthClientConfiguration));// 设置AuthorizationHttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);// 设置BasicAuthorizationrestTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(oAuthClientConfiguration.getClientId(),oAuthClientConfiguration.getSecret()));// 发送请求ResponseEntity<ResultInfo> result = restTemplate.postForEntity(oauthServerName + "oauth/token",entity, ResultInfo.class);// 处理返回结果AssertUtil.isTrue(result.getStatusCode() != HttpStatus.OK, "登录失败!");ResultInfo resultInfo = result.getBody();if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {// 登录失败resultInfo.setData(resultInfo.getMessage());return resultInfo;}OAuthDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),new OAuthDinerInfo(), false);LoginDinerInfo loginDinerInfo = new LoginDinerInfo();loginDinerInfo.setToken(dinerInfo.getAccessToken());loginDinerInfo.setNickname(dinerInfo.getNickname());loginDinerInfo.setAvatarUrl(dinerInfo.getAvatarUrl());return ResultInfoUtil.buildSuccess(path, loginDinerInfo);}/*** 校验手机号是否已注册** @param phone*/public void checkPhoneIsRegistered(String phone) {AssertUtil.isNotEmpty(phone, "手机号不能为空");Diners diners = dinersMapper.selectByPhone(phone);AssertUtil.isTrue(diners == null, "该手机号未注册");AssertUtil.isTrue(diners.getIsValid() == 0, "该用户已锁定,请先解锁");}/*** 用户注册** @param dinersDTO* @param path* @return*/public ResultInfo register(DinersDTO dinersDTO, String path) {// 参数非空校验String username = dinersDTO.getUsername();AssertUtil.isNotEmpty(username, "请输入用户名");String password = dinersDTO.getPassword();AssertUtil.isNotEmpty(username, "请输入密码");String phone = dinersDTO.getPhone();AssertUtil.isNotEmpty(username, "请输入手机号");String verifyCode = dinersDTO.getVerifyCode();AssertUtil.isNotEmpty(username, "请输入验证码");// 获取验证码String code = sendVerifyCodeService.getCodeByPhone(phone);// 验证码是否已过期AssertUtil.isNotEmpty(code, "验证码已过期,请重新发送");// 校验验证码一致性AssertUtil.isTrue(!dinersDTO.getVerifyCode().equals(code),"验证码不一致,请重新输入");// 验证用户名是否已注册Diners diners = dinersMapper.selectByUsername(username.trim());AssertUtil.isTrue(diners != null, "用户名已存在,请重新输入");// 注册// 密码加密dinersDTO.setPassword(DigestUtil.md5Hex(password.trim()));dinersMapper.save(dinersDTO);// 自动登录return signIn(username.trim(), password.trim(), path);}/*** 根据食客 ID 集合查询食客信息** @param ids 主键 id 集合,多个以逗号分隔,逗号之间不用空格* @return*/public List<ShortDinerInfo> findByIds(String ids) {AssertUtil.isNotEmpty(ids);String[] idArr = ids.split(",");List<ShortDinerInfo> dinerInfos = dinersMapper.findByIds(idArr);return dinerInfos;}}
2.1.3 Controller
package com.itkaka.diners.controller;import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.model.dto.DinersDTO;
import com.itkaka.commons.model.vo.ShortDinerInfo;
import com.itkaka.commons.utils.ResultInfoUtil;
import com.itkaka.diners.service.DinersService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;/*** 食客服务控制层*/
@RestController
@Api(tags = "食客相关接口")
public class DinersController {@Resourceprivate DinersService dinersService;@Resourceprivate HttpServletRequest request;/*** 登录** @param account* @param password* @return*/@GetMapping("signin")public ResultInfo signIn(String account, String password) {return dinersService.signIn(account, password, request.getServletPath());}/*** 校验手机号是否已注册** @param phone* @return*/@GetMapping("checkPhone")public ResultInfo checkPhone(String phone) {dinersService.checkPhoneIsRegistered(phone);return ResultInfoUtil.buildSuccess(request.getServletPath());}/*** 用户注册** @param dinersDTO* @return*/@PostMapping("register")public ResultInfo register(@RequestBody DinersDTO dinersDTO) {return dinersService.register(dinersDTO, request.getServletPath());}/*** 根据食客 ID 集合查询食客信息** @param ids 主键 id 集合,多个以逗号分隔,逗号之间不用空格* @return*/@GetMapping("findByIds")public ResultInfo<List<ShortDinerInfo>> findByIds(String ids) {List<ShortDinerInfo> dinerInfos = dinersService.findByIds(ids);return ResultInfoUtil.buildSuccess(request.getServletPath(), dinerInfos);}}
2.1.4 网关配置
放行校验手机号接口
secure:
ignore:urls: # 配置白名单路径- /actuator/**- /auth/oauth/**- /diners/signin- /diners/send- /diners/checkPhone
测试
访问:http://localhost/diners/checkPhone?phone=12311112222
返回结果(已注册):
{"code": 1,"message": "Successful.","path": "/checkPhone","data": null
}
返回结果 (未注册)
{"timestamp": "2020-11-15T10:16:23.815+00:00","status": 500,"error": "Internal Server Error","message": "","path": "/checkPhone"
}
2.2 全局异常处理
package com.itkaka.diners.handler;import com.itkaka.commons.exception.ParameterException;
import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.utils.ResultInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;@RestControllerAdvice // 将输出的内容写入 ResponseBody 中
@Slf4j
public class GlobalExceptionHandler {@Resourceprivate HttpServletRequest request;@ExceptionHandler(ParameterException.class)public ResultInfo<Map<String, String>> handlerParameterException(ParameterException ex) {String path = request.getRequestURI();ResultInfo<Map<String, String>> resultInfo =ResultInfoUtil.buildError(ex.getErrorCode(), ex.getMessage(), path);return resultInfo;}@ExceptionHandler(Exception.class)public ResultInfo<Map<String, String>> handlerException(Exception ex) {log.info("未知异常:{}", ex);String path = request.getRequestURI();ResultInfo<Map<String, String>> resultInfo = ResultInfoUtil.buildError(path);return resultInfo;}}
测试
{"code": 0,"message": "该手机号未注册","path": "/checkPhone","data": null
}
2.3 完成注册
2.3.1 DTO (数据传输对象)
package com.itkaka.commons.model.dto;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;import java.io.Serializable;@Getter
@Setter
@ApiModel(description = "注册用户信息")
public class DinersDTO implements Serializable {@ApiModelProperty("用户名")private String username;@ApiModelProperty("密码")private String password;@ApiModelProperty("手机号")private String phone;@ApiModelProperty("验证码")private String verifyCode;}
2.3.2 Mapper
/*** 根据用户名查询食客信息*/@Select("select id, username, phone, email, is_valid " +" from t_diners where username = #{username}")Diners selectByUsername(@Param("username") String username);/*** 新增食客信息*/@Insert("insert into " +" t_diners (username, password, phone, roles, is_valid, create_date, update_date) " +" values (#{username}, #{password}, #{phone}, \"ROLE_USER\", 1, now(), now())")int save(DinersDTO dinersDTO);
2.3.3 Service
SendVerifyCodeService.java
package com.itkaka.diners.service;import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.itkaka.commons.constant.RedisKeyConstant;
import com.itkaka.commons.utils.AssertUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;/*** 发送验证码业务逻辑层*/
@Service
public class SendVerifyCodeService {@Resourceprivate RedisTemplate<String, String> redisTemplate;/*** 发送验证码** @param phone*/public void send(String phone) {// 检查非空AssertUtil.isNotEmpty(phone, "手机号不能为空");// 根据手机号查询是否已生成验证码,已生成直接返回if (!checkCodeIsExpired(phone)) {return;}// 生成 6 位验证码String code = RandomUtil.randomNumbers(6);// 调用短信服务发送短信(忽略)// 发送成功,将 code 保存到 Redis,失效时间 60sString key = RedisKeyConstant.verify_code.getKey() + phone;redisTemplate.opsForValue().set(key, code, 60, TimeUnit.SECONDS);}/*** 根据手机号查询是否已生成验证码** @param phone* @return*/private boolean checkCodeIsExpired(String phone) {String key = RedisKeyConstant.verify_code.getKey() + phone;String code = redisTemplate.opsForValue().get(key);return StrUtil.isBlank(code) ? true : false;}/*** 根据手机号获取验证码** @param phone* @return*/public String getCodeByPhone(String phone) {String key = RedisKeyConstant.verify_code.getKey() + phone;return redisTemplate.opsForValue().get(key);}}
DinersService.java
package com.itkaka.diners.service;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.itkaka.commons.constant.ApiConstant;
import com.itkaka.commons.model.domain.ResultInfo;
import com.itkaka.commons.model.dto.DinersDTO;
import com.itkaka.commons.model.pojo.Diners;
import com.itkaka.commons.model.vo.ShortDinerInfo;
import com.itkaka.commons.utils.AssertUtil;
import com.itkaka.commons.utils.ResultInfoUtil;
import com.itkaka.diners.config.OAuthClientConfiguration;
import com.itkaka.diners.config.OAuthClientConfiguration;
import com.itkaka.diners.mapper.DinersMapper;
import com.itkaka.diners.model.domain.OAuthDinerInfo;
import com.itkaka.diners.model.vo.LoginDinerInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;/*** 食客服务业务逻辑层*/
@Service
public class DinersService {@Resourceprivate RestTemplate restTemplate;@Value("${service.name.fs_oauth-server}")private String oauthServerName;@Resourceprivate OAuthClientConfiguration oAuthClientConfiguration;@Resourceprivate DinersMapper dinersMapper;@Resourceprivate com.itkaka.diners.service.SendVerifyCodeService sendVerifyCodeService;/*** 登录** @param account 账号信息:用户名或手机或邮箱* @param password 密码* @param path 请求路径* @return*/public ResultInfo signIn(String account, String password, String path) {// 参数校验AssertUtil.isNotEmpty(account, "请输入登录账户");AssertUtil.isNotEmpty(password, "请输入登录密码");// 构建请求头HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);// 构建请求体MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();body.add("username", account);body.add("password", password);body.setAll(BeanUtil.beanToMap(oAuthClientConfiguration));// 设置AuthorizationHttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);// 设置BasicAuthorizationrestTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(oAuthClientConfiguration.getClientId(),oAuthClientConfiguration.getSecret()));// 发送请求ResponseEntity<ResultInfo> result = restTemplate.postForEntity(oauthServerName + "oauth/token",entity, ResultInfo.class);// 处理返回结果AssertUtil.isTrue(result.getStatusCode() != HttpStatus.OK, "登录失败!");ResultInfo resultInfo = result.getBody();if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {// 登录失败resultInfo.setData(resultInfo.getMessage());return resultInfo;}OAuthDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),new OAuthDinerInfo(), false);LoginDinerInfo loginDinerInfo = new LoginDinerInfo();loginDinerInfo.setToken(dinerInfo.getAccessToken());loginDinerInfo.setNickname(dinerInfo.getNickname());loginDinerInfo.setAvatarUrl(dinerInfo.getAvatarUrl());return ResultInfoUtil.buildSuccess(path, loginDinerInfo);}/*** 校验手机号是否已注册** @param phone*/public void checkPhoneIsRegistered(String phone) {AssertUtil.isNotEmpty(phone, "手机号不能为空");Diners diners = dinersMapper.selectByPhone(phone);AssertUtil.isTrue(diners == null, "该手机号未注册");AssertUtil.isTrue(diners.getIsValid() == 0, "该用户已锁定,请先解锁");}/*** 用户注册** @param dinersDTO* @param path* @return*/public ResultInfo register(DinersDTO dinersDTO, String path) {// 参数非空校验String username = dinersDTO.getUsername();AssertUtil.isNotEmpty(username, "请输入用户名");String password = dinersDTO.getPassword();AssertUtil.isNotEmpty(username, "请输入密码");String phone = dinersDTO.getPhone();AssertUtil.isNotEmpty(username, "请输入手机号");String verifyCode = dinersDTO.getVerifyCode();AssertUtil.isNotEmpty(username, "请输入验证码");// 获取验证码String code = sendVerifyCodeService.getCodeByPhone(phone);// 验证码是否已过期AssertUtil.isNotEmpty(code, "验证码已过期,请重新发送");// 校验验证码一致性AssertUtil.isTrue(!dinersDTO.getVerifyCode().equals(code),"验证码不一致,请重新输入");// 验证用户名是否已注册Diners diners = dinersMapper.selectByUsername(username.trim());AssertUtil.isTrue(diners != null, "用户名已存在,请重新输入");// 注册// 密码加密dinersDTO.setPassword(DigestUtil.md5Hex(password.trim()));dinersMapper.save(dinersDTO);// 自动登录return signIn(username.trim(), password.trim(), path);}/*** 根据食客 ID 集合查询食客信息** @param ids 主键 id 集合,多个以逗号分隔,逗号之间不用空格* @return*/public List<ShortDinerInfo> findByIds(String ids) {AssertUtil.isNotEmpty(ids);String[] idArr = ids.split(",");List<ShortDinerInfo> dinerInfos = dinersMapper.findByIds(idArr);return dinerInfos;}}
2.3.4 Controller
/*** 用户注册** @param dinersDTO* @return*/@PostMapping("register")public ResultInfo register(@RequestBody DinersDTO dinersDTO) {return dinersService.register(dinersDTO, request.getServletPath());}
2.3.5 网关配置
放行注册接口
secure:
ignore:urls: # 配置白名单路径- /actuator/**- /auth/oauth/**- /diners/signin- /diners/send- /diners/checkPhone- /diners/register
2.3.6 测试
先访问:http://localhost/diners/checkPhone?phone=12311113333
返回结果:
{"code": 0,"message": "该手机号未注册","path": "/checkPhone","data": null}
再访问:http://localhost/diners/send?phone=12311113333
返回结果(Redis 查看验证码):
{"code": 1,"message": "Successful.","path": "发送成功","data": "/send"
}
再访问:http://localhost/diners/register
请求参数:
{"username": "zhangsan","password": "123456","phone": "12311113333","verifyCode": "833275"
}
返回结果:
{"code": 1,"message": "Successful.","path": "/register","data": {"nickname": null,"token": "4323c187-5ffa-4e45-a3a3-e7cdff32145d","avatarUrl": null}
}
这是用户登录注册流程图,该图借鉴来源: 哈喽沃德先生的主页 -->哈喽沃德先生主页 ,可以在CSDN,知乎等平台搜索即可;
美食社交APP项目--用户注册相关推荐
- android app 的后台代码,包括后台的Android美食APP项目开源代码
项目简介 小食光定位为一款集美食,社交,LBS服务于一体的美食推荐APP.为你发现周边美食的同时提供一个吃货分享的平台. APP截图 功能模块 美食推荐 :提供基础的美食信息查询: 商家推荐 : 基于 ...
- 魔方APP项目-04-用户模块API接口、Marshmallow,基本构造器(Schema),Schema数据序列化、Schema数据反序列化、反序列化对数据验证、模型构造器(ModelSchema)
用户模块 当前开发的项目属于社交类型项目,所以关于用户的信息和功能直接贯穿了整个项目.所以此处实现用户模块功能,我们先把用户基本信息构建起来,并通过基本信息实现用户注册登录相关功能,后面遇到业务再继续 ...
- 让HR眼前一亮:30个APP项目软件测试经验,点燃你的简历
在求职过程中,我们都希望自己的简历能够吸引面试官的眼球,从而获得更多的面试机会.作为一名软件测试人员,丰富的实战经验是让自己脱颖而出的关键之一. 在我多年从事APP项目软件测试的工作中,我积累了大量的 ...
- 社交app如何做好验证码防护不被刷
社交是时代的主题.大众的生活需求正在改变.各种垂直社交APP接连不断.陌生社交的成功使社交网络服务APP燃烧,面对庞大的网络市场,社交产品几乎成为所有网民日常生活中不可缺少的应用程序. 网站或者APP ...
- JAVA社交平台项目第三天 即时通讯和接口加密
第3章 - 即时通讯和接口加密 学习目标: 了解即时通讯业务场景和需求: 了解短连接和长连接 了解websocket协议 使用环信im云实现十次方即时通讯功能 了解接口加密业务需求 掌握常用加密算法和 ...
- App项目实战之路(二):API篇
原创文章,转载请注明:转载自Keegan小钢 并标明原文链接:http://keeganlee.me/post/practice/20160812 微信订阅号:keeganlee_me 写于2016- ...
- 软件开发规范和标准_社交APP,社交直播软件开发怎样才可靠了?
在网络飞速发展的今天,开发社交直播APP软件已经成为商家发展的必然,他们都需要社交直播APP或者小程序软件来拓展业务.那么社交APP,社交直播软件开发怎样才可靠了? 首先,甄别网络虚假宣传. 目前,傍 ...
- 轻量社交APP系统ThinkSNS 简 权威发布 限时惠购
2019独角兽企业重金招聘Python工程师标准>>> 伴随国内外创业风潮.AI.区块链等互联网软件科技领域的高速发展,2019年,ThinkSNS软件品牌迎来十周年后的新纪元.作为 ...
- 某社交 App 涉黄被下架,真相令人窒息
最近见识了一个令人窒息的事情. 某社交 App,为了让另一个竞品 App 下架,跑去竞品 App 平台下发布涉黄信息,自己进行截图举报. 其中,一个是 Soul,另一个是 Uki,双方都主打匿名声音社 ...
最新文章
- 程序猿,凭什么让你拿二十万
- 浅谈进程同步和互斥的概念
- 笔记 - AliCloud CDN 分发网络简介
- layui时间日期控件使用
- 阿里巴巴AI智能专场:整理分享
- Leetcode-MySQL-180. 连续出现的数字
- 如何安装oracle数据库
- mybatis map里面传对象_关于 MyBatis,我死磕了 10 种超好用的写法
- 报告显示:数据屏蔽降低业务安全风险
- 什么是servlet?servlet有什么用?
- 打造前端 Deepin Linux 工作环境——安装 nodejs 环境,git 版本管理
- 1357:车厢调度(train)
- python情绪识别_使用百度对话情绪识别api分析文本
- matlab gram schmidt,如何在 MATLAB 中用 行代码实现 Gram-Schmidt 正交化
- unity 转向和角度
- 敲简单前端小游戏——贪吃蛇
- 【ShaderToy】基础篇之谈谈点、线的绘制
- Alextnet网络
- linux实训项目——飞鸽(一)
- Git的基本概念和SourceTree的使用