一、项目背景与需求分析

1.1 项目背景

1.2 需求分析

  • 用户身份验证:确保用户身份合法,防止非法操作。
  • 金额校验:验证转账金额的合法性,避免超额转账。
  • 微信接口对接:与微信支付系统进行无缝对接,实现资金流转。
  • 事务管理:确保转账操作的原子性,防止数据不一致。
  • 日志记录:详细记录每笔转账的操作日志,便于后续审计。

二、技术选型与架构设计

2.1 技术选型

  • 编程语言:Java
  • 框架:Spring Boot、Spring Cloud
  • 数据库:MySQL
  • 消息队列:RabbitMQ
  • 接口对接:微信支付API

2.2 架构设计

采用经典的微服务架构,主要包括以下服务模块:

  • 用户服务:负责用户身份验证和信息管理。
  • 账户服务:管理用户账户信息,进行金额校验。
  • 转账服务:核心服务,负责转账逻辑的实现。
  • 日志服务:记录操作日志,提供审计功能。
  • 微信对接服务:与微信支付系统进行交互。

三、核心功能实现

3.1 用户身份验证

使用JWT(JSON Web Token)进行用户身份验证,确保每次请求的合法性。

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public class JwtUtil {
    private static final String SECRET_KEY = "your_secret_key";

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 3600000))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    public static Claims extractClaims(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }

    public static boolean validateToken(String token) {
        try {
            extractClaims(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

3.2 金额校验

在账户服务中,对用户的转账金额进行校验,确保不超过账户余额。

public class AccountService {

    @Autowired
    private AccountRepository accountRepository;

    public boolean validateAmount(Long userId, BigDecimal amount) {
        Account account = accountRepository.findById(userId).orElseThrow(() -> new RuntimeException("Account not found"));
        return account.getBalance().compareTo(amount) >= 0;
    }
}

3.3 微信接口对接

import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

public class WeChatPayService {

    private static final String API_URL = "https://api.mch.weixin.qq.com/v3/pay/transfer";
    private static final String MCH_ID = "your_mch_id";
    private static final String API_KEY = "your_api_key";

    public void transfer(BigDecimal amount, String openid) throws Exception {
        String requestJson = buildRequestJson(amount, openid);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(API_URL);
        httpPost.setHeader("Content-Type", "application/json");
        httpPost.setEntity(new StringEntity(requestJson));

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            if (response.getStatusLine().getStatusCode() == 200) {
                // 处理响应结果
            } else {
                throw new RuntimeException("Transfer failed");
            }
        }
    }

    private String buildRequestJson(BigDecimal amount, String openid) throws Exception {
        JSONObject json = new JSONObject();
        json.put("mchid", MCH_ID);
        json.put("appid", "your_appid");
        json.put("openid", openid);
        json.put("amount", amount.multiply(new BigDecimal(100)).intValue());
        json.put("desc", "Transfer description");
        json.put("spbill_create_ip", "your_ip_address");

        AesUtil aesUtil = new AesUtil(API_KEY.length());
        String encryptedData = aesUtil.encryptToString(json.toString(), API_KEY);
        return encryptedData;
    }
}

3.4 事务管理

使用Spring的声明式事务管理,确保转账操作的原子性。

import org.springframework.transaction.annotation.Transactional;

@Service
public class TransferService {

    @Autowired
    private AccountService accountService;

    @Autowired
    private WeChatPayService weChatPayService;

    @Transactional
    public void transfer(Long fromUserId, Long toUserId, BigDecimal amount) {
        if (!accountService.validateAmount(fromUserId, amount)) {
            throw new RuntimeException("Insufficient balance");
        }

        // 扣减余额
        accountService.deductBalance(fromUserId, amount);

        // 调用微信转账接口
        weChatPayService.transfer(amount, toUserId.toString());

        // 记录日志
        logService.recordLog(fromUserId, toUserId, amount);
    }
}

3.5 日志记录

使用AOP(面向切面编程)进行日志记录,提高代码的解耦性。

@Aspect
@Component
public class LogAspect {

    @Autowired
    private LogService logService;

    @Pointcut("execution(* com.example.transfer.TransferService.transfer(..))")
    public void transferPointcut() {}

    @AfterReturning("transferPointcut()")
    public void logTransfer(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        Long fromUserId = (Long) args[0];
        Long toUserId = (Long) args[1];
        BigDecimal amount = (BigDecimal) args[2];
        logService.recordLog(fromUserId, toUserId, amount);
    }
}

四、测试与部署

4.1 单元测试

使用JUnit和Mockito进行单元测试,确保每个服务模块的功能正确。

@SpringBootTest
public class TransferServiceTest {

    @Autowired
    private TransferService transferService;

    @MockBean
    private AccountService accountService;

    @MockBean
    private WeChatPayService weChatPayService;

    @Test
    public void testTransfer() {
        Long fromUserId = 1L;
        Long toUserId = 2L;
        BigDecimal amount = new BigDecimal("100");

        when(accountService.validateAmount(fromUserId, amount)).thenReturn(true);

        transferService.transfer(fromUserId, toUserId, amount);

        verify(accountService).deductBalance(fromUserId, amount);
        verify(weChatPayService).transfer(amount, toUserId.toString());
    }
}

4.2 部署

使用Docker进行容器化部署,确保服务的可移植性和高可用性。

version: '3'
services:
  user-service:
    image: user-service:latest
    ports:
      - "8081:8080"
    depends_on:
      - mysql

  account-service:
    image: account-service:latest
    ports:
      - "8082:8080"
    depends_on:
      - mysql

  transfer-service:
    image: transfer-service:latest
    ports:
      - "8083:8080"
    depends_on:
      - user-service
      - account-service

  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: bankdb

五、总结与展望

未来,我们将继续探索更多金融科技的应用场景,进一步提升农行的服务质量和客户体验。期待与更多技术同仁共同交流、进步,共同推动金融科技的发展。

参考文献

  1. 《Spring Boot实战》
  2. 《微服务架构设计 patterns》
  3. 微信支付官方文档

希望本文能为您的项目开发提供有价值的参考和帮助。如果有任何问题或建议,欢迎随时交流。