这里有ddd说明,可以先看面向领域编程DDD二它,然后再往后看
public class PaymentController{
private PayService payService;
public Result pay(String merchantAccount,BigDecimal amount){
Long userId = (Long) session.getAttribute("userId");
return payService.pay(userId, merchantAccount, amount);
}
}
public class PayServiceImpl extends PayService{
private AccountDao accountDao;//操作数据库
private KafkaTemplate<String, String> kafkaTemplate;//操作kafka
private RiskCheckService riskCheckService;//风控微服务接口
public Result pay(Long userId,String merchantAccount,BigDecimal amount){
// 1. 从数据库读取数据
AccountDO clientDO = accountDAO.selectByUserId(userId);
AccountDO merchantDO =
accountDAO.selectByAccountNumber(merchantAccount);
// 2. 业务参数校验
if (amount>(clientDO.getAvailable()) {
throw new NoMoneyException();
}
// 3. 调用风控微服务
RiskCode riskCode = riskCheckService.checkPayment(...);
// 4. 检查交易合法性
if("0000"!= riskCode){
throw new InvalideOperException();
}
// 5. 计算新值,并且更新字段
BigDecimal newSource = clientDO.getAvailable().subtract(amount);
BigDecimal newTarget = merchantDO.getAvailable().add(amount);
clientDO.setAvailable(newSource);
merchantDO.setAvailable(newTarget);
// 6. 更新到数据库
accountDAO.update(clientDO);
accountDAO.update(merchantDO);
// 7. 发送审计消息
String message = sourceUserId + "," + targetAccountNumber + "," + targetAmount;
kafkaTemplate.send(TOPIC_AUDIT_LOG, message);
return Result.SUCCESS;
}
}`
上面的代码是一个简单的mvc代码这样的代码 就会有一个问题 第一版本可以会很成功但是 如果在这基础上编写二期三期。。那么这里就会变的很庞大 也不敢删维护起来很麻烦 测试也不好测比如专门测试风控微服务 这样就会要把其他的逻辑都测一遍 如果单独开一个接口也会有很多问题比如两个方法的数据不一样 上面的代码还是一个很简单的代码 要是现实的业务代码会更加复杂 短期项目这样写也是没问题主要就是长期的项目 然后就有人提出的ddd的架构模式 ddd称为面向领域编程
ddd设计模式 仓库模式
public interface AccountRepository {
.......
}
public class AccountRepositoryImpl implements AccountRepository {
@Autowired
private AccountDao accountDAO;
@Autowired
private AccountBuilder accountBuilder;
@Override
public Account find(Long id) {
AccountDO accountDO = accountDAO.selectById(id);
return accountBuilder.toAccount(accountDO);
}
@Override
public Account find(Long accountNumber) {
AccountDO accountDO = accountDAO.selectByAccountNumber(accountNumber);
return accountBuilder.toAccount(accountDO);
}
@Override
public Account save(Account account) {
AccountDO accountDO = accountBuilder.fromAccount(account);
if (accountDO.getId() == null) {
accountDAO.insert(accountDO);
} else {
accountDAO.update(accountDO);
}
return accountBuilder.toAccount(accountDO);
}
public class Account{
private Long id;
private Long accountNumber;
private BigDecimal available;
public void withdraw(BigDecimal money){
//转入操作
available = available + money;
}
public void deposit(BigDecimal money){
//转出操作
if(available < money){
throws new InsufficientMoneyException();
}
available = available - money;
}
}
之前都是定义一个跟数据库的字段名相同的一个类作为实体类 现在不提供get set方法写一个仓库 在仓库里把实体类拼接起来
防腐层 隔离外部服务
public interface BusiSafeService{
.......
}
public class BusiSafeServiceImpl implements BusiSafeService{
@Autowired
private RiskChkService riskChkService;
public Result checkBusi(Long userId,Long mechantAccount,BigDecimal money){
//参数封装
RiskCode riskCode = riskCheckService.checkPayment(...);
if("0000".equals(reskCode.getCode()){
return Result.SUCCESS;
}
return Result.REJECT;
}
}
隔离外部服务就是封装一个返回类型 如果你换了返回类型实现接口重写方法即可不会影响业务
防腐层 隔离第三方组件
public class AuditMessage{
private Long UserId;
private Long clientAccount;
private Long merchantAccount;
private BigDecimal money;
private Date data;
.....
}
public interface AuditMessageProducer{
....
}
public class AuditMessageProducerImpl implements AuditMessageProducer{
private KafkaTemplate<String,String> kafkaTemplate;
public SendResult send(AuditMessage message){
String messageBody = message.getBody();
kafkaTemplate.send("some topic",messageBody);
return SendResult.SUCCESS;
}
}
就是如果你换了中间件 继承接口实现它的方法 不用更改业务代码