一、项目背景与需求分析
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
五、总结与展望
未来,我们将继续探索更多金融科技的应用场景,进一步提升农行的服务质量和客户体验。期待与更多技术同仁共同交流、进步,共同推动金融科技的发展。
参考文献
- 《Spring Boot实战》
- 《微服务架构设计 patterns》
- 微信支付官方文档
希望本文能为您的项目开发提供有价值的参考和帮助。如果有任何问题或建议,欢迎随时交流。