深入解析CustomerInfoServiceImpl和CustomerServiceImpl:微信小程序登录功能的实现


在现代移动应用开发中,微信小程序已经成为了许多企业的重要选择。为了支持小程序的用户登录功能,我们需要与微信的认证服务进行集成。这篇文章将带大家深入解析两个关键的服务实现类: CustomerInfoServiceImplCustomerServiceImpl,它们是如何共同工作来实现微信小程序登录功能的。

一、CustomerInfoServiceImpl类详解

CustomerInfoServiceImpl类主要负责处理用户信息的管理和登录日志的记录。它继承了ServiceImpl,并实现了CustomerInfoService接口。下面我们来详细了解它的核心逻辑。

package com.atguigu.daijia.customer.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.atguigu.daijia.customer.mapper.CustomerInfoMapper;
import com.atguigu.daijia.customer.mapper.CustomerLoginLogMapper;
import com.atguigu.daijia.customer.service.CustomerInfoService;
import com.atguigu.daijia.model.entity.customer.CustomerInfo;
import com.atguigu.daijia.model.entity.customer.CustomerLoginLog;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
@RequiredArgsConstructor
public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, CustomerInfo> implements
        CustomerInfoService {

    private final WxMaService wxMaService;
    private final CustomerInfoMapper customerInfoMapper;
    private final CustomerLoginLogMapper customerLoginLogMapper;

    // 微信小程序登录接口
    @Override
    public Long login(String code) {
        // 1.获取code值,使用微信工具包对象,获取微信唯一标识openid
        String openid = null;
        try {
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
            openid = sessionInfo.getOpenid();
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        // 2.根据openid查询数据库表,判断是否第一次登录
        // 如果不存返回null,如果存在返回一条记录
        LambdaQueryWrapper<CustomerInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CustomerInfo::getWxOpenId, openid);
        CustomerInfo customerInfo = customerInfoMapper.selectOne(wrapper);
        // 3.如果是第一次登录,将用户信息插入数据库表
        if (customerInfo == null) {
            customerInfo = new CustomerInfo();
            customerInfo.setNickname(String.valueOf(System.currentTimeMillis()));
            customerInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
            customerInfo.setWxOpenId(openid);
            customerInfoMapper.insert(customerInfo);
        }
        // 4.记录登录日志
        CustomerLoginLog customerLoginLog = new CustomerLoginLog();
        customerLoginLog.setCustomerId(customerInfo.getId());
        customerLoginLog.setMsg("小程序登录");
        customerLoginLogMapper.insert(customerLoginLog);

        // 5.返回用户id
        return customerInfo.getId();
    }
}
  1. 获取微信用户的openid

    在微信小程序中,code是通过调用wx.login接口获取的,作为登录的凭证。我们通过wxMaService来获取openid,这是每个微信用户的唯一标识。

    WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
    String openid = sessionInfo.getOpenid();
    
  2. 检查用户是否是第一次登录

    通过openid在数据库中查询用户信息。如果没有找到对应的用户信息,则说明这是用户的首次登录。在这种情况下,我们会创建一条新的用户记录。

    LambdaQueryWrapper<CustomerInfo> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(CustomerInfo::getWxOpenId, openid);
    CustomerInfo customerInfo = customerInfoMapper.selectOne(wrapper);
    
    if (customerInfo == null) {
        customerInfo = new CustomerInfo();
        customerInfo.setNickname(String.valueOf(System.currentTimeMillis()));
        customerInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
        customerInfo.setWxOpenId(openid);
        customerInfoMapper.insert(customerInfo);
    }
    
  3. 记录登录日志

    每次用户登录,我们都会记录一条登录日志,以便后续分析和追踪。

    CustomerLoginLog customerLoginLog = new CustomerLoginLog();
    customerLoginLog.setCustomerId(customerInfo.getId());
    customerLoginLog.setMsg("小程序登录");
    customerLoginLogMapper.insert(customerLoginLog);
    
  4. 返回用户ID

    最后,我们将用户的ID返回,供后续使用。

    return customerInfo.getId();
    
二、CustomerServiceImpl类详解

CustomerServiceImpl类则主要负责与其他微服务的交互以及处理登录后的Token管理。它通过调用远程的用户服务,获取用户的登录信息,并将登录状态存储在Redis中。

package com.atguigu.daijia.customer.service.impl;

import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.Result;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.customer.client.CustomerInfoFeignClient;
import com.atguigu.daijia.customer.service.CustomerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
@RequiredArgsConstructor
public class CustomerServiceImpl implements CustomerService {

    // 注入远程调用接口
    private final CustomerInfoFeignClient client;
    private final RedisTemplate redisTemplate;

    @Override
    public String login(String code) {
        // 1.远程调用,返回用户id
        Result<Long> loginResult = client.login(code);

        // 2.判断如果返回失败,返回错误提示
        Integer codeResult = loginResult.getCode();
        if (codeResult != 200) {
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
        // 3.获取远程调用返回的用户id
        Long customerId = loginResult.getData();
        // 4.判断返回用户id是否为空,如果为空,返回错误提示
        if (customerId == null) {
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
        // 5.生成token字符串
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        // 6.把用户id放到Redis,设置过期时间
        // key:token value:customerId
        redisTemplate.opsForValue().set(RedisConstant.USER_LOGIN_KEY_PREFIX + token,
                                        customerId.toString(),
                                        RedisConstant.USER_LOGIN_KEY_TIMEOUT,
                                        TimeUnit.SECONDS);
        // 7.返回token字符串
        return token;
    }
}
  1. 远程调用获取用户ID

    CustomerServiceImpl通过Feign客户端远程调用CustomerInfoServicelogin方法,获取用户ID。

    Result<Long> loginResult = client.login(code);
    
  2. 错误处理

    在调用远程服务后,首先要检查返回的结果状态码,如果状态码不为200,说明请求失败,抛出自定义异常。

    if (loginResult.getCode() != 200) {
        throw new GuiguException(ResultCodeEnum.DATA_ERROR);
    }
    
  3. 生成Token并存储到Redis

    为了管理用户的会话状态,我们生成了一个唯一的Token,并将其与用户ID绑定存储到Redis中,这样可以在后续的请求中验证用户身份。

    String token = UUID.randomUUID().toString().replaceAll("-", "");
    redisTemplate.opsForValue().set(RedisConstant.USER_LOGIN_KEY_PREFIX + token,
                                    customerId.toString(),
                                    RedisConstant.USER_LOGIN_KEY_TIMEOUT,
                                    TimeUnit.SECONDS);
    
  4. 返回Token

    最终,将生成的Token返回给前端,前端会在后续的请求中使用这个Token来进行身份验证。

    return token;
    
三、总结

CustomerInfoServiceImplCustomerServiceImpl这两个类的协作,完整实现了微信小程序的用户登录功能。前者负责处理微信用户信息的管理,后者则负责会话状态的管理与安全。这种设计使得代码清晰且职责明确,便于维护和扩展。

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,我们需要选择一个适合的Java微服务框架。在市面上,比较流行的微服务框架有Spring Cloud、Dubbo、ServiceComb等。我们选用Spring Cloud作为我们的微服务框架。 接下来,我们需要设计并实现新增批量修改客户信息的功能。客户信息包含证件类型和证件号码两个关键字段。我们可以定义一个客户信息实体类,包含对应的字段属性,例如: ```java public class Customer { private Long id; private String name; private String idType; private String idNumber; // getter and setter } ``` 接着,我们需要设计对应的RESTful API接口,用于新增、批量修改客户信息。例如: ```java @RestController @RequestMapping("/api/customers") public class CustomerController { @Autowired private CustomerService customerService; @PostMapping public Customer createCustomer(@RequestBody Customer customer) { return customerService.createCustomer(customer); } @PutMapping public List<Customer> updateCustomers(@RequestBody List<Customer> customers) { return customerService.updateCustomers(customers); } } ``` 在上述代码中,我们定义了两个接口,一个用于新增单个客户信息,一个用于批量修改客户信息。我们需要在对应的Service层中实现具体的业务逻辑。 ```java @Service public class CustomerServiceImpl implements CustomerService { @Autowired private CustomerRepository customerRepository; @Override public Customer createCustomer(Customer customer) { return customerRepository.save(customer); } @Override public List<Customer> updateCustomers(List<Customer> customers) { List<Customer> updatedCustomers = new ArrayList<>(); for (Customer customer : customers) { Customer updatedCustomer = customerRepository.save(customer); updatedCustomers.add(updatedCustomer); } return updatedCustomers; } } ``` 在上述代码中,我们定义了一个CustomerService接口,并在实现类中实现了具体的业务逻辑。我们将客户信息存储在一个CustomerRepository中,可以使用JPA或者其他ORM框架来实现数据持久化。 最后,我们需要编写详细的开发文档手册,包括项目框架选择、代码结构设计、API接口设计、数据模型设计、业务逻辑实现等内容。文档需要清晰明了,让其他团队成员容易理解和使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值