Преглед на файлове

feat(app): 实现微信小程序用户登录功能

- 新增用户模型、映射器和服务实现类- 添加微信登录相关接口和逻辑
- 创建用户视图和登录用户视图类
- 更新公共常量和密码工具类
SheepHy преди 3 седмици
родител
ревизия
30697f622a
променени са 11 файла, в които са добавени 380 реда и са изтрити 4 реда
  1. 1 0
      national-motion-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
  2. 4 2
      national-motion-base-core/src/main/java/org/jeecg/common/util/PasswordUtil.java
  3. 21 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/AppUserController.java
  4. 41 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/UserWechatRegisterDTO.java
  5. 1 2
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/entity/AppBanner.java
  6. 91 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/entity/User.java
  7. 9 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/mapper/UserMapper.java
  8. 19 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IUserService.java
  9. 103 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/UserServiceImpl.java
  10. 50 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/LoginUserVO.java
  11. 40 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/UserVO.java

+ 1 - 0
national-motion-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java

@@ -99,6 +99,7 @@ public interface CommonConstant {
     String  LOGIN_QRCODE  = "LQ:";
     /** 登录二维码token */
     String  LOGIN_QRCODE_TOKEN  = "LQT:";
+    String  USER_LOGIN_STATE  = "user_login:";
 
 
     /**

+ 4 - 2
national-motion-base-core/src/main/java/org/jeecg/common/util/PasswordUtil.java

@@ -1,12 +1,12 @@
 package org.jeecg.common.util;
 
-import java.security.Key;
-import java.security.SecureRandom;
 import javax.crypto.Cipher;
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.PBEParameterSpec;
+import java.security.Key;
+import java.security.SecureRandom;
 
 /**
  * @Description: 密码工具类
@@ -31,6 +31,8 @@ public class PasswordUtil {
      */
 	public static final String SALT = "63293188";
 
+	public static final String SALTA_APP = "zswl2025";
+
 	/**
 	 * 定义迭代次数为1000次
 	 */

+ 21 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/AppUserController.java

@@ -2,12 +2,33 @@ package org.jeecg.modules.app.controller;
 
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.app.dto.UserWechatRegisterDTO;
+import org.jeecg.modules.app.service.IUserService;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
 @Slf4j
 @Tag(name = "App用户相关接口")
 @RestController
 @RequestMapping("/app/user")
 public class AppUserController {
+    @Resource
+    private IUserService userService;
+    /**
+     * 微信小程序获取用户信息接口
+     *
+     * @param request               请求
+     * @param userWechatRegisterDTO {@link UserWechatRegisterDTO}
+     * @return {@link Result}<{@link ?}>
+     */
+    @PostMapping("/wechatRegister")
+    public Result<?> wechatInfo(@RequestBody UserWechatRegisterDTO userWechatRegisterDTO, HttpServletRequest request){
+        return Result.ok(userService.wechatInfo(userWechatRegisterDTO, request));
+    }
 }

+ 41 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/UserWechatRegisterDTO.java

@@ -0,0 +1,41 @@
+package org.jeecg.modules.app.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * null
+ *
+ * @author user
+ * @date 2024/12/16
+ */
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="微信用户注册入参DTO")
+public class UserWechatRegisterDTO {
+
+    private  String code;
+
+    /**
+     * 用户昵称
+     */
+    @Schema(description="用户昵称")
+    private String userName;
+
+    /**
+     * 用户头像
+     */
+    @Schema(description="用户头像")
+    private String userAvatar;
+
+    /**
+     * 性别  0-女、1-男
+     */
+    @Schema(description="性别  0-女、1-男")
+    private String gender;
+
+}

+ 1 - 2
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/entity/AppBanner.java

@@ -20,10 +20,9 @@ import java.io.Serializable;
  * @Version: V1.0
  */
 @Data
-@TableName("hm_app_banner")
+@TableName("nm_app_banner")
 @Accessors(chain = true)
 @EqualsAndHashCode(callSuper = false)
-@Schema(description="首页轮播图管理")
 public class AppBanner implements Serializable {
     private static final long serialVersionUID = 1L;
 

+ 91 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/entity/User.java

@@ -0,0 +1,91 @@
+package org.jeecg.modules.app.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 用户
+ *
+ */
+@Data
+@TableName("nm_user")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+public class User implements Serializable {
+
+    /**
+     * id
+     */
+    @TableId(type = IdType.ASSIGN_ID)
+    private String id;
+
+    /**
+     * 用户账号
+     */
+    private String userAccount;
+
+    /**
+     * 用户密码
+     */
+    private String userPassword;
+
+    /**
+     * 小程序openId
+     */
+    private String openid;
+
+    /**
+     * 用户昵称
+     */
+    private String userName;
+
+    /**
+     * 用户头像
+     */
+    private String userAvatar;
+
+    /**
+     * 用户简介
+     */
+    private String userProfile;
+
+    /**
+     * 电话
+     */
+    private String phone;
+
+    /**
+     * 性别  0-女、1-男
+     */
+    private String gender;
+
+    /**
+     * 用户角色:user/admin/ban
+     */
+    private String userRole;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    /**
+     * 是否删除
+     */
+    @Schema(description = "删除状态(0-正常,1-已删除)")
+    @TableLogic
+    private Integer delFlag;
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}

+ 9 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/mapper/UserMapper.java

@@ -0,0 +1,9 @@
+package org.jeecg.modules.app.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.app.entity.User;
+
+@Mapper
+public interface UserMapper extends BaseMapper<User> {
+}

+ 19 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IUserService.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.app.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.app.dto.UserWechatRegisterDTO;
+import org.jeecg.modules.app.entity.User;
+import org.jeecg.modules.app.vo.LoginUserVO;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface IUserService extends IService<User> {
+    LoginUserVO wechatInfo(UserWechatRegisterDTO userWechatRegisterDTO, HttpServletRequest request);
+
+    /**
+     * 获取脱敏的已登录用户信息
+     *
+     * @return
+     */
+    LoginUserVO getLoginUserVO(User user);
+}

+ 103 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/UserServiceImpl.java

@@ -0,0 +1,103 @@
+package org.jeecg.modules.app.service.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.exception.JeecgBootException;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.modules.app.dto.UserWechatRegisterDTO;
+import org.jeecg.modules.app.entity.User;
+import org.jeecg.modules.app.mapper.UserMapper;
+import org.jeecg.modules.app.service.IUserService;
+import org.jeecg.modules.app.vo.LoginUserVO;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.DigestUtils;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+import static org.jeecg.common.constant.CommonConstant.*;
+import static org.jeecg.common.util.PasswordUtil.SALTA_APP;
+
+@Service
+public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
+    @Resource
+    private WxMaService wxMaService;
+    @Autowired
+    private RedisUtil redisUtil;
+
+    @Override
+    public LoginUserVO wechatInfo(UserWechatRegisterDTO userWechatRegisterDTO, HttpServletRequest request) {
+        try {
+            if (userWechatRegisterDTO == null) {
+                throw new JeecgBootException("参数不能为空",SC_JEECG_NO_AUTHZ);
+            }
+            String code = userWechatRegisterDTO.getCode();
+            String userName = userWechatRegisterDTO.getUserName();
+            String userAvatar = userWechatRegisterDTO.getUserAvatar();
+            String gender = userWechatRegisterDTO.getGender();
+            if (StringUtils.isAnyBlank(code, userName, userAvatar,gender)) {
+                throw new JeecgBootException("参数不能为空",SC_JEECG_NO_AUTHZ);
+            }
+            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
+            String openid = session.getOpenid();
+            String sessionKey = session.getSessionKey();
+            // 单机锁
+            synchronized (openid.intern()) {
+                // 查询用户是否已存在
+                User user = this.getOne(Wrappers.<User>lambdaQuery().eq(User::getOpenid, openid).eq(User::getDelFlag,0));
+                // 用户不存在则创建
+                if (user == null) {
+                    user = new User();
+                    user.setOpenid(openid);
+                    user.setUserAccount(IdUtil.getSnowflakeNextIdStr());
+                    String encryptPassword = DigestUtils.md5DigestAsHex((SALTA_APP).getBytes());
+                    user.setUserPassword(encryptPassword);
+                    user.setUserAvatar(userAvatar);
+                    user.setUserName(userName);
+                    user.setGender(gender);
+                    boolean result = this.save(user);
+                    if (!result) {
+                        throw new JeecgBootException("登录失败",SC_INTERNAL_SERVER_ERROR_500);
+                    }
+                }
+                // 记录用户的登录态
+                request.getSession().setAttribute(USER_LOGIN_STATE, user);
+                LoginUserVO loginUserVO = this.getLoginUserVO(user);
+                String userAccount = user.getUserAccount();
+                String userPassword = user.getUserPassword();
+                //1.生成token
+                String token = JwtUtil.sign(userAccount, userPassword);
+                // 设置token缓存有效时间
+                redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
+                redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
+                loginUserVO.setToken(token);
+                return loginUserVO;
+            }
+        } catch (WxErrorException e) {
+            log.error(e.getMessage(), e);
+            throw new JeecgBootException("小程序登录失败:" + e,SC_INTERNAL_SERVER_ERROR_500);
+        } finally {
+            WxMaConfigHolder.remove();//清理ThreadLocal
+        }
+    }
+
+    @Override
+    public LoginUserVO getLoginUserVO(User user) {
+        if (user == null) {
+            return null;
+        }
+        LoginUserVO loginUserVO = new LoginUserVO();
+        BeanUtils.copyProperties(user, loginUserVO);
+        return loginUserVO;
+    }
+}

+ 50 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/LoginUserVO.java

@@ -0,0 +1,50 @@
+package org.jeecg.modules.app.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 已登录用户视图(脱敏)
+ *
+ **/
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="已登录用户视图")
+public class LoginUserVO implements Serializable {
+
+    /**
+     * 用户 id
+     */
+    @Schema(description = "用户 id")
+    private String id;
+
+    /**
+     * 用户昵称
+     */
+    @Schema(description = "用户昵称")
+    private String userName;
+
+    /**
+     * 用户头像
+     */
+    @Schema(description = "用户头像")
+    private String userAvatar;
+
+    /**
+     * 用户简介
+     */
+    @Schema(description = "用户简介")
+    private String userProfile;
+
+    /**
+     * token
+     */
+    @Schema(description = "token")
+    private String token;
+
+}

+ 40 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/UserVO.java

@@ -0,0 +1,40 @@
+package org.jeecg.modules.app.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 用户视图(脱敏)
+ *
+ */
+@Data
+public class UserVO implements Serializable {
+
+    /**
+     * id
+     */
+    @Schema(description = "用户 id")
+    private String id;
+
+    /**
+     * 用户昵称
+     */
+    @Schema(description = "用户昵称")
+    private String userName;
+
+    /**
+     * 用户头像
+     */
+    @Schema(description = "用户头像")
+    private String userAvatar;
+
+    /**
+     * 用户简介
+     */
+    @Schema(description = "用户简介")
+    private String userProfile;
+
+
+}