From f5d14f3b3f5b4888308f1da8e92f1db040b9f791 Mon Sep 17 00:00:00 2001
From: Helius <wangdoubleone@gmail.com>
Date: Thu, 16 Sep 2021 17:08:44 +0800
Subject: [PATCH] add login interface

---
 src/main/java/cc/mrbird/febs/mall/controller/ApiLoginController.java         |   15 +
 src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java               |    5 
 src/main/java/cc/mrbird/febs/mall/service/ICommonService.java                |    9 +
 src/main/resources/mapper/modules/MallMemberMapper.xml                       |   11 +
 src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java         |   14 ++
 src/main/java/cc/mrbird/febs/mall/dto/RegisterDto.java                       |    2 
 src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java |  155 ++++++++++++++++++++++
 src/main/java/cc/mrbird/febs/mall/dto/LoginDto.java                          |   24 +++
 src/main/java/cc/mrbird/febs/mall/entity/MallMember.java                     |   19 ++
 src/main/java/cc/mrbird/febs/common/utils/AppContants.java                   |   18 --
 src/main/java/cc/mrbird/febs/mall/service/impl/CommonService.java            |    6 
 src/main/java/cc/mrbird/febs/common/entity/BaseEntity.java                   |    4 
 src/main/java/cc/mrbird/febs/common/utils/ShareCodeUtil.java                 |  110 +++++++++++++++
 13 files changed, 364 insertions(+), 28 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/common/entity/BaseEntity.java b/src/main/java/cc/mrbird/febs/common/entity/BaseEntity.java
index 4a7e64a..fa87659 100644
--- a/src/main/java/cc/mrbird/febs/common/entity/BaseEntity.java
+++ b/src/main/java/cc/mrbird/febs/common/entity/BaseEntity.java
@@ -21,9 +21,9 @@
 
     private String updatedBy = "system";
 
-    private Date createdTime;
+    private Date createdTime = new Date();
 
-    private Date updatedTime;
+    private Date updatedTime = new Date();
 
     @TableId(value = "id",type = IdType.AUTO)
     private Long id;
diff --git a/src/main/java/cc/mrbird/febs/common/utils/AppContants.java b/src/main/java/cc/mrbird/febs/common/utils/AppContants.java
index 4ac326b..4d0dd5b 100644
--- a/src/main/java/cc/mrbird/febs/common/utils/AppContants.java
+++ b/src/main/java/cc/mrbird/febs/common/utils/AppContants.java
@@ -45,23 +45,6 @@
      */
     public static final String SYSTEM_REFERER = "rxadr3";
 
-    /**
-     * 初始化金额
-     */
-    public static final BigDecimal INIT_MONEY = BigDecimal.ZERO;
-
-
-    public static final Integer INIT_SIMULATE_MONEY = 5000;
-
-    /**
-     * homeSymbols 接口状态值 币币
-     */
-    public static final int HOME_SYMBOLS_COIN = 1;
-
-    /**
-     * homeSymbols 接口状态值 合约
-     */
-    public static final int HOME_SYMBOLS_CONTRACT = 2;
 
     /**
      * 验证码前缀 手机
@@ -75,6 +58,5 @@
 
     public static final String TIME_OUT = "time_out";
 
-    public static final String CLOSING_ORDER_PREFIX = "closing_cnt_";
 
 }
diff --git a/src/main/java/cc/mrbird/febs/common/utils/ShareCodeUtil.java b/src/main/java/cc/mrbird/febs/common/utils/ShareCodeUtil.java
new file mode 100644
index 0000000..c00834c
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/common/utils/ShareCodeUtil.java
@@ -0,0 +1,110 @@
+package cc.mrbird.febs.common.utils;
+
+import java.util.Random;
+
+public class ShareCodeUtil {
+
+    /**
+     * 自定义进制(0,1没有加入,容易与o,l混淆)
+     */
+//    private static final char[] r=new char[]{'q', 'w', 'e', '8', 'a', 's', '2', 'd', 'z', 'x', '9', 'c', '7', 'p', '5', 'i', 'k', '3', 'm', 'j', 'u', 'f', 'r', '4', 'v', 'y', 'l', 't', 'n', '6', 'b', 'g', 'h'};
+    private static final char[] r = new char[]{'1', '2', '3', '4', '5', '6', '7', '8', '9'};
+
+    /**
+     * (不能与自定义进制有重复)
+     */
+    private static final char b = '0';
+
+    /**
+     * 进制长度
+     */
+    private static final int binLen = r.length;
+
+    /**
+     * 序列最小长度
+     */
+    private static final int s = 8;
+
+    /**
+     * 根据ID生成六位随机码
+     *
+     * @param id ID
+     * @return 随机码
+     */
+    public static String toSerialCode(long id) {
+        char[] buf = new char[32];
+        int charPos = 32;
+
+        while ((id / binLen) > 0) {
+            int ind = (int) (id % binLen);
+            buf[--charPos] = r[ind];
+            id /= binLen;
+        }
+        buf[--charPos] = r[(int) (id % binLen)];
+        String str = new String(buf, charPos, (32 - charPos));
+        // 不够长度的自动随机补全
+        if (str.length() < s) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(b);
+            Random rnd = new Random();
+            for (int i = 1; i < s - str.length(); i++) {
+                sb.append(r[rnd.nextInt(binLen)]);
+            }
+            str += sb.toString();
+        }
+        return str;
+    }
+
+    /**
+     * 根据ID生成六位随机码
+     *
+     * @param id ID
+     * @return 随机码
+     */
+    public static String toSerialNumberCode(long id) {
+        char[] buf = new char[32];
+        int charPos = 32;
+
+        while ((id / binLen) > 0) {
+            int ind = (int) (id % binLen);
+            buf[--charPos] = r[ind];
+            id /= binLen;
+        }
+        buf[--charPos] = r[(int) (id % binLen)];
+        String str = new String(buf, charPos, (32 - charPos));
+        // 不够长度的自动随机补全
+        if (str.length() < s) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(b);
+            Random rnd = new Random();
+            for (int i = 1; i < s - str.length(); i++) {
+                sb.append(r[rnd.nextInt(binLen)]);
+            }
+            str += sb.toString();
+        }
+        return str;
+    }
+
+    public static long codeToId(String code) {
+        char chs[] = code.toCharArray();
+        long res = 0L;
+        for (int i = 0; i < chs.length; i++) {
+            int ind = 0;
+            for (int j = 0; j < binLen; j++) {
+                if (chs[i] == r[j]) {
+                    ind = j;
+                    break;
+                }
+            }
+            if (chs[i] == b) {
+                break;
+            }
+            if (i > 0) {
+                res = res * binLen + ind;
+            } else {
+                res = ind;
+            }
+        }
+        return res;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/controller/ApiLoginController.java b/src/main/java/cc/mrbird/febs/mall/controller/ApiLoginController.java
index 496a308..3dc024f 100644
--- a/src/main/java/cc/mrbird/febs/mall/controller/ApiLoginController.java
+++ b/src/main/java/cc/mrbird/febs/mall/controller/ApiLoginController.java
@@ -1,8 +1,9 @@
 package cc.mrbird.febs.mall.controller;
 
 import cc.mrbird.febs.common.entity.FebsResponse;
+import cc.mrbird.febs.mall.dto.LoginDto;
 import cc.mrbird.febs.mall.dto.RegisterDto;
-import cc.mrbird.febs.mall.service.MallMemberService;
+import cc.mrbird.febs.mall.service.IApiMallMemberService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
@@ -23,15 +24,21 @@
 @Validated
 @RequiredArgsConstructor
 @RestController
-@RequestMapping(value = "/api/login/")
+@RequestMapping(value = "/api/login")
 @Api(value = "ApiLoginController", tags = "登录注册类")
 public class ApiLoginController {
 
-    private final MallMemberService memberService;
+    private final IApiMallMemberService memberService;
 
-    @ApiOperation(value = "app注册接口", notes = "app注册接口,验证码必须输入可默认为123456")
+    @ApiOperation(value = "app注册接口", notes = "app注册接口")
     @PostMapping(value = "/register")
     public FebsResponse register(@RequestBody RegisterDto registerDto) {
         return memberService.register(registerDto);
     }
+
+    @ApiOperation(value = "账号密码登录接口", notes = "账号密码登录接口")
+    @PostMapping(value = "/toLogin")
+    public FebsResponse login(@RequestBody LoginDto loginDto) {
+        return memberService.toLogin(loginDto);
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/dto/LoginDto.java b/src/main/java/cc/mrbird/febs/mall/dto/LoginDto.java
new file mode 100644
index 0000000..2870467
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/dto/LoginDto.java
@@ -0,0 +1,24 @@
+package cc.mrbird.febs.mall.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author wzy
+ * @date 2021-09-16
+ **/
+@Data
+@ApiModel(value = "LoginDto", description = "登录接口参数接收类")
+public class LoginDto {
+
+    @NotBlank(message = "账号不能为空")
+    @ApiModelProperty(value = "账号", example = "15773001234")
+    private String account;
+
+    @NotBlank(message = "密码不能为空")
+    @ApiModelProperty(value = "密码", example = "123456")
+    private String password;
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/dto/RegisterDto.java b/src/main/java/cc/mrbird/febs/mall/dto/RegisterDto.java
index 69a49f7..a8ef6af 100644
--- a/src/main/java/cc/mrbird/febs/mall/dto/RegisterDto.java
+++ b/src/main/java/cc/mrbird/febs/mall/dto/RegisterDto.java
@@ -23,7 +23,7 @@
     private String password;
 
     @ApiModelProperty(value = "类型 1-手机号 2-邮箱", example = "1")
-    private Integer type = 1;
+    private String type = "1";
 
     @NotBlank(message = "验证码不能为空")
     @ApiModelProperty(value = "验证码", example = "123456")
diff --git a/src/main/java/cc/mrbird/febs/mall/entity/MallMember.java b/src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
index af98c35..14f5a20 100644
--- a/src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
+++ b/src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
@@ -1,6 +1,7 @@
 package cc.mrbird.febs.mall.entity;
 
 import cc.mrbird.febs.common.controller.BaseController;
+import cc.mrbird.febs.common.entity.BaseEntity;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 
@@ -10,7 +11,7 @@
  **/
 @Data
 @TableName("mall_member")
-public class MallMember extends BaseController {
+public class MallMember extends BaseEntity {
 
     private String name;
 
@@ -31,7 +32,23 @@
     private String level;
 
     private Integer accountStatus;
+    /**
+     * 启用
+     */
+    public static final Integer ACCOUNT_STATUS_ENABLE = 1;
+    /**
+     * 禁用
+     */
+    public static final Integer ACCOUNT_STATUS_DISABLED = 2;
 
     private Integer accountType;
 
+    /**
+     * 正常账号
+     */
+    public static final Integer ACCOUNT_TYPE_NORMAL = 1;
+    /**
+     * 测试账号
+     */
+    public static final Integer ACCOUNT_TYPE_TEST = 2;
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java b/src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java
index 4245646..490fe89 100644
--- a/src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java
+++ b/src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java
@@ -12,6 +12,11 @@
  **/
 public interface MallMemberMapper extends BaseMapper<MallMember> {
 
+    MallMember selectInfoByAccount(@Param("account") String account);
+
     IPage<MallMember> selectMallMemberListInPage(Page<MallMember> page, @Param("record")MallMember mallMember);
 
+    MallMember selectInfoByInviteId(@Param("inviteId") String inviteId);
+
+    MallMember selectInfoByAccountAndPwd(@Param("account") String account, @Param("password") String password);
 }
diff --git a/src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java b/src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java
new file mode 100644
index 0000000..f0d3815
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java
@@ -0,0 +1,14 @@
+package cc.mrbird.febs.mall.service;
+
+import cc.mrbird.febs.common.entity.FebsResponse;
+import cc.mrbird.febs.mall.dto.LoginDto;
+import cc.mrbird.febs.mall.dto.RegisterDto;
+import cc.mrbird.febs.mall.entity.MallMember;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+public interface IApiMallMemberService extends IService<MallMember> {
+    FebsResponse register(RegisterDto registerDto);
+
+    FebsResponse toLogin(LoginDto loginDto);
+
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/service/ICommonService.java b/src/main/java/cc/mrbird/febs/mall/service/ICommonService.java
new file mode 100644
index 0000000..6508cb3
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/service/ICommonService.java
@@ -0,0 +1,9 @@
+package cc.mrbird.febs.mall.service;
+
+/**
+ * @author wzy
+ * @date 2021-09-16
+ **/
+public interface ICommonService {
+    boolean verifyCode(String account, String code);
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java
new file mode 100644
index 0000000..8b3273e
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java
@@ -0,0 +1,155 @@
+package cc.mrbird.febs.mall.service.impl;
+
+import cc.mrbird.febs.common.entity.FebsResponse;
+import cc.mrbird.febs.common.exception.FebsException;
+import cc.mrbird.febs.common.utils.AppContants;
+import cc.mrbird.febs.common.utils.RedisUtils;
+import cc.mrbird.febs.common.utils.ShareCodeUtil;
+import cc.mrbird.febs.mall.dto.LoginDto;
+import cc.mrbird.febs.mall.dto.RegisterDto;
+import cc.mrbird.febs.mall.entity.MallMember;
+import cc.mrbird.febs.mall.mapper.MallMemberMapper;
+import cc.mrbird.febs.mall.service.IApiMallMemberService;
+import cc.mrbird.febs.mall.service.ICommonService;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author wzy
+ * @date 2021-09-16
+ **/
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class ApiMallMemberServiceImpl extends ServiceImpl<MallMemberMapper, MallMember> implements IApiMallMemberService {
+
+    private final ICommonService commonService;
+    private final RedisUtils redisUtils;
+
+    @Value("${spring.profiles.active}")
+    private String active;
+
+    @Override
+    public FebsResponse register(RegisterDto registerDto) {
+        MallMember mallMember = this.baseMapper.selectInfoByAccount(registerDto.getAccount());
+        if (mallMember != null) {
+            throw new FebsException("该手机号/邮箱已被占用");
+        }
+
+        String account = registerDto.getAccount();
+        String code = registerDto.getCode();
+        boolean flags = commonService.verifyCode(account, code);
+        if(!flags) {
+            throw new FebsException("验证码错误");
+        }
+
+        mallMember = new MallMember();
+        mallMember.setPassword(SecureUtil.md5(registerDto.getPassword()));
+
+        // 判断账号类型
+        if (AppContants.ACCOUNT_TYPE_MOBILE.equals(registerDto.getType())) {
+            mallMember.setPhone(registerDto.getAccount());
+        } else {
+            mallMember.setEmail(registerDto.getAccount());
+        }
+
+        Integer count = this.baseMapper.selectCount(null);
+        if (count != null && count != 0) {
+            MallMember inviteMember = this.baseMapper.selectInfoByInviteId(registerDto.getInviteId());
+            if (inviteMember == null) {
+                throw new FebsException("邀请码不存在");
+            }
+
+            mallMember.setReferrerId(registerDto.getInviteId());
+
+        }
+        mallMember.setName(registerDto.getAccount());
+        mallMember.setAccountStatus(MallMember.ACCOUNT_STATUS_ENABLE);
+        mallMember.setAccountType(MallMember.ACCOUNT_TYPE_NORMAL);
+        mallMember.setLevel("1");
+        mallMember.setSex("男");
+
+        this.baseMapper.insert(mallMember);
+
+        String inviteId = ShareCodeUtil.toSerialCode(mallMember.getId());
+        mallMember.setInviteId(inviteId);
+
+        //推荐人和推荐人链
+        boolean flag = false;
+        String parentId = mallMember.getReferrerId();
+        String ids = "";
+        while (!flag) {
+            if (StrUtil.isBlank(ids)) {
+                ids += parentId;
+            } else {
+                ids += ("," + parentId);
+            }
+            MallMember parentMember = this.baseMapper.selectInfoByInviteId(parentId);
+            if (parentMember == null) {
+                break;
+            }
+            parentId = parentMember.getReferrerId();
+            if (parentMember.getReferrerId().equals(parentMember.getInviteId())) {
+                flag = true;
+            }
+        }
+
+        if (StrUtil.isNotBlank(ids)) {
+            mallMember.setReferrerIds(ids);
+        }
+        this.baseMapper.updateById(mallMember);
+        return new FebsResponse().success().message("注册成功");
+    }
+
+    @Override
+    public FebsResponse toLogin(LoginDto loginDto) {
+        String md5Pwd = SecureUtil.md5(loginDto.getPassword());
+
+        MallMember mallMember = this.baseMapper.selectInfoByAccountAndPwd(loginDto.getAccount(), md5Pwd);
+        if (mallMember == null) {
+            throw new FebsException("用户不存在或账号密码错误");
+        }
+
+        if (MallMember.ACCOUNT_STATUS_DISABLED.equals(mallMember.getAccountStatus())) {
+            throw new FebsException("该账号存在异常, 暂限制登录");
+        }
+
+        String redisKey = AppContants.APP_LOGIN_PREFIX + mallMember.getId();
+        String existToken = redisUtils.getString(redisKey);
+        if (StrUtil.isNotBlank(existToken)) {
+            Object o = redisUtils.get(existToken);
+            if (ObjectUtil.isNotEmpty(o)) {
+                redisUtils.del(existToken);
+            }
+        }
+
+        String token = IdUtil.simpleUUID();
+        redisUtils.set(token, JSONObject.toJSONString(mallMember), 360000);
+        redisUtils.set(redisKey, token, 360000);
+        Map<String, Object> authInfo = new HashMap<>();
+        authInfo.put("token", token);
+        if ("dev".equals(active)) {
+            authInfo.put("rasToken", generateAsaToken(token));
+        }
+        return new FebsResponse().success().data(authInfo);
+    }
+
+    public String generateAsaToken(String token) {
+        RSA rsa = new RSA(null, AppContants.PUBLIC_KEY);
+        return rsa.encryptBase64(token + "_" + System.currentTimeMillis(), KeyType.PublicKey);
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/service/CommonService.java b/src/main/java/cc/mrbird/febs/mall/service/impl/CommonService.java
similarity index 83%
rename from src/main/java/cc/mrbird/febs/mall/service/CommonService.java
rename to src/main/java/cc/mrbird/febs/mall/service/impl/CommonService.java
index 06e129d..443f40f 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/CommonService.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/CommonService.java
@@ -1,7 +1,8 @@
-package cc.mrbird.febs.mall.service;
+package cc.mrbird.febs.mall.service.impl;
 
 import cc.mrbird.febs.common.utils.AppContants;
 import cc.mrbird.febs.common.utils.RedisUtils;
+import cc.mrbird.febs.mall.service.ICommonService;
 import cn.hutool.core.util.StrUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -14,9 +15,10 @@
 @Slf4j
 @Service
 @RequiredArgsConstructor
-public class CommonService {
+public class CommonService implements ICommonService {
     private final RedisUtils redisUtils;
 
+    @Override
     public boolean verifyCode(String account, String code) {
         String cacheCode = redisUtils.getString(AppContants.VERIFY_CODE_PREFIX + account);
         if (StrUtil.isBlank(cacheCode)) {
diff --git a/src/main/resources/mapper/modules/MallMemberMapper.xml b/src/main/resources/mapper/modules/MallMemberMapper.xml
index 3d724fb..f5cfcb7 100644
--- a/src/main/resources/mapper/modules/MallMemberMapper.xml
+++ b/src/main/resources/mapper/modules/MallMemberMapper.xml
@@ -23,4 +23,15 @@
         order by m.CREATED_TIME desc
     </select>
 
+    <select id="selectInfoByAccount" resultType="cc.mrbird.febs.mall.entity.MallMember">
+        select * from mall_member where phone=#{account} or email=#{account}
+    </select>
+
+    <select id="selectInfoByInviteId" resultType="cc.mrbird.febs.mall.entity.MallMember">
+        select * from mall_member where invite_id=#{inviteId}
+    </select>
+
+    <select id="selectInfoByAccountAndPwd" resultType="cc.mrbird.febs.mall.entity.MallMember">
+        select * from mall_member where (phone=#{account} or email=#{account}) and password=#{password}
+    </select>
 </mapper>
\ No newline at end of file

--
Gitblit v1.9.1