美食社交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
     */
    @Bean
    public 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 {

    @Resource
    private 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,失效时间 60s
        String 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 {

    @Resource
    private HttpServletRequest request;

    @Resource
    private 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_diners
          uri: lb://fs_diners
          predicates:
            - Path=/diners/**
          filters:
            - StripPrefix=1

        - id: fs_oauth
          uri: lb://fs_oauth
          predicates:
            - Path=/auth/**
          filters:
            - StripPrefix=1



secure:
  ignore:
    urls: # 配置白名单路径
      - /actuator/**
      - /auth/oauth/**
      - /diners/signin
      - /diners/send

# 配置 Eureka Server 注册中心
eureka:
  instance:
    # 开启 ip 注册
    prefer-ip-address: true
    instance-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"
}

image.png

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 {

    @Resource
    private RestTemplate restTemplate;

    @Value("${service.name.fs_oauth-server}")
    private String oauthServerName;

    @Resource
    private OAuthClientConfiguration oAuthClientConfiguration;

    @Resource
    private DinersMapper dinersMapper;

    @Resource
    private 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));
        // 设置Authorization
        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
        // 设置BasicAuthorization
        restTemplate.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 {

    @Resource
    private DinersService dinersService;

    @Resource
    private 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 {

    @Resource
    private 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 {

    @Resource
    private 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,失效时间 60s
        String 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 {

    @Resource
    private RestTemplate restTemplate;

    @Value("${service.name.fs_oauth-server}")
    private String oauthServerName;

    @Resource
    private OAuthClientConfiguration oAuthClientConfiguration;

    @Resource
    private DinersMapper dinersMapper;

    @Resource
    private 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));
        // 设置Authorization
        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
        // 设置BasicAuthorization
        restTemplate.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
 }
}

image.png
在这里插入图片描述
这是用户登录注册流程图,该图借鉴来源: 哈喽沃德先生的主页 -->哈喽沃德先生主页 ,可以在CSDN,知乎等平台搜索即可;

👉 💕美好的一天,从现在开始,大家一起努力!后续更新持续更新,码字不易,麻烦大家小手一点 , 点赞或关注 , 感谢大家的支持!! 🌙

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值