|
@@ -0,0 +1,194 @@
|
|
|
+package com.zhentao.user.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.zhentao.user.domain.User;
|
|
|
+import com.zhentao.user.service.UserService;
|
|
|
+import com.zhentao.user.mapper.UserMapper;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.zhentao.user.dto.LoginResponseDTO;
|
|
|
+import com.zhentao.user.dto.WechatLoginDTO;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.util.LinkedMultiValueMap;
|
|
|
+import org.springframework.util.MultiValueMap;
|
|
|
+import org.springframework.web.client.RestTemplate;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.UUID;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+* @author ASUS
|
|
|
+* @description 针对表【user(用户基本信息表)】的数据库操作Service实现
|
|
|
+* @createDate 2025-05-20 09:53:17
|
|
|
+*/
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class UserServiceImpl extends ServiceImpl<UserMapper, User>
|
|
|
+ implements UserService{
|
|
|
+ @Value("${wx.appid}")
|
|
|
+ private String appId;
|
|
|
+
|
|
|
+ @Value("${wx.secret}")
|
|
|
+ private String appSecret;
|
|
|
+
|
|
|
+ @Value("${wx.login-url}")
|
|
|
+ private String loginUrl;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisTemplate<String, Object> redisTemplate;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RestTemplate restTemplate;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public LoginResponseDTO wechatLogin(WechatLoginDTO dto) {
|
|
|
+ try {
|
|
|
+ // 1. 向微信服务器换取session_key和openid
|
|
|
+ Map<String, String> wxResult = getWxSession(dto.getCode());
|
|
|
+ String openid = wxResult.get("openid");
|
|
|
+ String sessionKey = wxResult.get("session_key");
|
|
|
+
|
|
|
+ if (openid == null || sessionKey == null) {
|
|
|
+ log.error("微信登录失败:获取openid或session_key失败,返回结果: {}", wxResult);
|
|
|
+ throw new RuntimeException("微信登录失败:获取openid或session_key失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询或创建用户
|
|
|
+ User user = getUserByOpenid(openid);
|
|
|
+ boolean isNewUser = false;
|
|
|
+
|
|
|
+ if (user == null) {
|
|
|
+ // 创建新用户
|
|
|
+ user = createWechatUser(openid, sessionKey, dto);
|
|
|
+ isNewUser = true;
|
|
|
+ } else {
|
|
|
+ // 更新用户信息和session_key
|
|
|
+ updateUserInfo(user, sessionKey, dto);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 生成JWT Token并缓存到Redis
|
|
|
+ String token = generateToken(user.getUserId());
|
|
|
+ cacheUserToken(user.getUserId(), token);
|
|
|
+
|
|
|
+ // 4. 构建响应
|
|
|
+ LoginResponseDTO response = new LoginResponseDTO();
|
|
|
+ response.setUserId(user.getUserId());
|
|
|
+ response.setToken(token);
|
|
|
+ response.setLoginType(user.getLoginType());
|
|
|
+ response.setWxNickname(user.getWxNickname());
|
|
|
+ response.setWxAvatarUrl(user.getWxAvatarUrl());
|
|
|
+ response.setIsNewUser(isNewUser);
|
|
|
+
|
|
|
+ return response;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("微信登录服务出错,请求参数: {}", dto, e);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, String> getWxSession(String code) {
|
|
|
+ MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
|
|
+ params.add("appid", appId);
|
|
|
+ params.add("secret", appSecret);
|
|
|
+ params.add("js_code", code);
|
|
|
+ params.add("grant_type", "authorization_code");
|
|
|
+
|
|
|
+ String result = restTemplate.postForObject(loginUrl, params, String.class);
|
|
|
+
|
|
|
+ try {
|
|
|
+ ObjectMapper mapper = new ObjectMapper();
|
|
|
+ Map<String, Object> resultMap = mapper.readValue(result, Map.class);
|
|
|
+
|
|
|
+ if (resultMap.containsKey("errcode")) {
|
|
|
+ log.error("微信登录失败,错误码:{},错误信息:{}",
|
|
|
+ resultMap.get("errcode"),
|
|
|
+ resultMap.get("errmsg"));
|
|
|
+ return new HashMap<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, String> sessionInfo = new HashMap<>();
|
|
|
+ sessionInfo.put("openid", (String) resultMap.get("openid"));
|
|
|
+ sessionInfo.put("session_key", (String) resultMap.get("session_key"));
|
|
|
+ return sessionInfo;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("解析微信登录结果失败", e);
|
|
|
+ return new HashMap<>();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private User getUserByOpenid(String openid) {
|
|
|
+ return this.getOne(new LambdaQueryWrapper<User>()
|
|
|
+ .eq(User::getWxOpenid, openid));
|
|
|
+ }
|
|
|
+
|
|
|
+ private User createWechatUser(String openid, String sessionKey, WechatLoginDTO dto) {
|
|
|
+ User user = new User();
|
|
|
+ user.setWxOpenid(openid);
|
|
|
+ user.setWxSessionKey(sessionKey);
|
|
|
+ user.setLoginType(1); // 1=微信登录
|
|
|
+
|
|
|
+ // 如果有用户信息,填充到实体
|
|
|
+ if (dto.getRawData() != null) {
|
|
|
+ try {
|
|
|
+ ObjectMapper mapper = new ObjectMapper();
|
|
|
+ Map<String, Object> userInfo = mapper.readValue(dto.getRawData(), Map.class);
|
|
|
+ user.setWxNickname((String) userInfo.get("nickName"));
|
|
|
+ user.setGender(Integer.parseInt(userInfo.get("gender").toString()));
|
|
|
+ user.setWxAvatarUrl((String) userInfo.get("avatarUrl"));
|
|
|
+ log.info("成功解析用户信息,昵称: {}, 头像: {}", user.getWxNickname(), user.getWxAvatarUrl()); // 添加日志输出
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("解析微信用户信息失败", e); // 修改为 error 级别日志
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.save(user);
|
|
|
+ return user;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void updateUserInfo(User user, String sessionKey, WechatLoginDTO dto) {
|
|
|
+ user.setWxSessionKey(sessionKey);
|
|
|
+ user.setWxLastLoginTime(new java.util.Date());
|
|
|
+
|
|
|
+ // 如果有新的用户信息,更新
|
|
|
+ if (dto.getRawData() != null) {
|
|
|
+ try {
|
|
|
+ ObjectMapper mapper = new ObjectMapper();
|
|
|
+ Map<String, Object> userInfo = mapper.readValue(dto.getRawData(), Map.class);
|
|
|
+ user.setWxNickname((String) userInfo.get("nickName"));
|
|
|
+ user.setGender(Integer.parseInt(userInfo.get("gender").toString()));
|
|
|
+ user.setWxAvatarUrl((String) userInfo.get("avatarUrl"));
|
|
|
+ log.info("成功更新用户信息,昵称: {}, 头像: {}", user.getWxNickname(), user.getWxAvatarUrl()); // 添加日志输出
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("解析微信用户信息失败", e); // 修改为 error 级别日志
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.updateById(user);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String generateToken(Integer userId) {
|
|
|
+ // 生成唯一Token
|
|
|
+ return UUID.randomUUID().toString().replace("-", "");
|
|
|
+ }
|
|
|
+
|
|
|
+ private void cacheUserToken(Integer userId, String token) {
|
|
|
+ // 将Token缓存到Redis,有效期24小时
|
|
|
+ redisTemplate.opsForValue().set(
|
|
|
+ "user_token:" + userId,
|
|
|
+ token,
|
|
|
+ 24,
|
|
|
+ TimeUnit.HOURS
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|