修改权限控制
This commit is contained in:
@@ -12,7 +12,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 功能权限校验切面
|
||||
* <p>拦截 @FuncPermission 注解,校验权限并扣减库存后放行</p>
|
||||
* <p>拦截 @FuncPermission 注解,校验权限并扣减库存后放行,业务异常时自动回退</p>
|
||||
*
|
||||
* @author zk
|
||||
*/
|
||||
@@ -32,14 +32,15 @@ public class FuncPermissionAspect {
|
||||
|
||||
log.info("功能权限校验 userId:{} funcCode:{}", userId, funcCode);
|
||||
|
||||
// 校验权限 + 扣减库存
|
||||
funcPermissionServer.checkAndDeduct(userId, funcCode);
|
||||
// 校验权限 + 扣减库存,返回使用记录ID
|
||||
Long logId = funcPermissionServer.checkAndDeduct(userId, funcCode);
|
||||
|
||||
// 放行,业务异常时回退库存
|
||||
// 放行,业务异常时回退使用记录和库存
|
||||
try {
|
||||
return joinPoint.proceed();
|
||||
} catch (Exception e) {
|
||||
funcPermissionServer.rollbackCount(userId, funcCode);
|
||||
log.warn("业务异常,回退使用记录 logId:{} userId:{} funcCode:{}", logId, userId, funcCode);
|
||||
funcPermissionServer.rollbackUsage(logId, userId, funcCode);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,21 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jiayunet.exception.BusinessException;
|
||||
import org.jiayunet.exception.BusinessExpCodeEnum;
|
||||
import org.jiayunet.mapper.FuncPermissionMapper;
|
||||
import org.jiayunet.mapper.UserFuncPermissionStockMapper;
|
||||
import org.jiayunet.mapper.UserFuncUsageLogMapper;
|
||||
import org.jiayunet.pojo.po.FuncPermission;
|
||||
import org.jiayunet.pojo.po.UserFuncPermissionStock;
|
||||
import org.jiayunet.pojo.po.UserFuncUsageLog;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
|
||||
/**
|
||||
* 功能权限服务(校验、扣减、查询、添加库存)
|
||||
* 功能权限服务(校验、扣减、查询、添加库存、回退)
|
||||
*
|
||||
* @author zk
|
||||
*/
|
||||
@@ -21,39 +27,72 @@ import java.time.Instant;
|
||||
@Slf4j
|
||||
public class FuncPermissionServer {
|
||||
|
||||
@Autowired
|
||||
private FuncPermissionMapper funcPermissionMapper;
|
||||
|
||||
@Autowired
|
||||
private UserFuncPermissionStockMapper userFuncPermissionStockMapper;
|
||||
|
||||
@Autowired
|
||||
private UserFuncUsageLogMapper userFuncUsageLogMapper;
|
||||
|
||||
/**
|
||||
* 校验用户功能权限并扣减库存
|
||||
* <p>优先使用每日免费额度,免费额度用完后走付费库存</p>
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param funcCode 功能权限编码
|
||||
* @return 使用记录ID(用于异常回退)
|
||||
*/
|
||||
public void checkAndDeduct(Long userId, String funcCode) {
|
||||
// 查询用户功能权限库存
|
||||
public Long checkAndDeduct(Long userId, String funcCode) {
|
||||
// 1. 查功能权限定义
|
||||
FuncPermission funcPermission = funcPermissionMapper.selectOne(
|
||||
new LambdaQueryWrapper<FuncPermission>()
|
||||
.eq(FuncPermission::getFuncCode, funcCode)
|
||||
.eq(FuncPermission::getStatus, 1)
|
||||
);
|
||||
if (funcPermission == null) {
|
||||
throw new BusinessException(BusinessExpCodeEnum.PERMISSION_DENIED, "功能不存在或未启用");
|
||||
}
|
||||
|
||||
// 2. 判断每日免费额度
|
||||
int dailyFreeCount = funcPermission.getDailyFreeCount() == null ? 0 : funcPermission.getDailyFreeCount();
|
||||
if (dailyFreeCount > 0) {
|
||||
Instant todayStart = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant();
|
||||
Long todayUsed = userFuncUsageLogMapper.selectCount(
|
||||
new LambdaQueryWrapper<UserFuncUsageLog>()
|
||||
.eq(UserFuncUsageLog::getUserId, userId)
|
||||
.eq(UserFuncUsageLog::getFuncCode, funcCode)
|
||||
.ge(UserFuncUsageLog::getCreateTime, todayStart)
|
||||
);
|
||||
if (todayUsed < dailyFreeCount) {
|
||||
// 免费额度未用完,插入使用记录,直接放行
|
||||
return insertUsageLog(userId, funcCode);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 免费额度用完或无免费额度,查付费库存
|
||||
UserFuncPermissionStock stock = userFuncPermissionStockMapper.selectOne(
|
||||
new LambdaQueryWrapper<UserFuncPermissionStock>()
|
||||
.eq(UserFuncPermissionStock::getUserId, userId)
|
||||
.eq(UserFuncPermissionStock::getFuncCode, funcCode)
|
||||
);
|
||||
|
||||
// 无记录,无权限
|
||||
if (stock == null) {
|
||||
throw new BusinessException(BusinessExpCodeEnum.PERMISSION_DENIED, "无该功能权限");
|
||||
}
|
||||
|
||||
// 时间维度校验
|
||||
// 4. 时间维度校验
|
||||
if (stock.getTimeLimit() == 1 && stock.getExpireTime() != null && stock.getExpireTime().isBefore(Instant.now())) {
|
||||
throw new BusinessException(BusinessExpCodeEnum.PERMISSION_DENIED, "功能权限已过期");
|
||||
}
|
||||
|
||||
// 不限次,直接放行
|
||||
// 5. 次数维度校验
|
||||
if (stock.getCountLimit() == 0) {
|
||||
return;
|
||||
// 不限次,直接放行
|
||||
return insertUsageLog(userId, funcCode);
|
||||
}
|
||||
|
||||
// 限次,扣减库存(乐观锁,SQL原子扣减)
|
||||
// 限次,SQL原子扣减
|
||||
int rows = userFuncPermissionStockMapper.update(null,
|
||||
new LambdaUpdateWrapper<UserFuncPermissionStock>()
|
||||
.setSql("remain_count = remain_count - 1")
|
||||
@@ -61,10 +100,48 @@ public class FuncPermissionServer {
|
||||
.eq(UserFuncPermissionStock::getFuncCode, funcCode)
|
||||
.gt(UserFuncPermissionStock::getRemainCount, 0)
|
||||
);
|
||||
|
||||
if (rows == 0) {
|
||||
throw new BusinessException(BusinessExpCodeEnum.PERMISSION_DENIED, "功能使用次数已用完");
|
||||
}
|
||||
|
||||
return insertUsageLog(userId, funcCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入使用记录
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param funcCode 功能编码
|
||||
* @return 记录ID
|
||||
*/
|
||||
private Long insertUsageLog(Long userId, String funcCode) {
|
||||
UserFuncUsageLog usageLog = new UserFuncUsageLog();
|
||||
usageLog.setUserId(userId);
|
||||
usageLog.setFuncCode(funcCode);
|
||||
userFuncUsageLogMapper.insert(usageLog);
|
||||
return usageLog.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 回退使用记录(业务异常时调用)
|
||||
* <p>删除使用记录,并尝试回退付费库存次数(SQL条件自动过滤)</p>
|
||||
*
|
||||
* @param logId 使用记录ID
|
||||
* @param userId 用户ID
|
||||
* @param funcCode 功能编码
|
||||
*/
|
||||
public void rollbackUsage(Long logId, Long userId, String funcCode) {
|
||||
// 删除使用记录
|
||||
userFuncUsageLogMapper.deleteById(logId);
|
||||
|
||||
// 尝试回退库存次数(count_limit=1才会匹配,其他情况update 0行无影响)
|
||||
userFuncPermissionStockMapper.update(null,
|
||||
new LambdaUpdateWrapper<UserFuncPermissionStock>()
|
||||
.setSql("remain_count = remain_count + 1")
|
||||
.eq(UserFuncPermissionStock::getUserId, userId)
|
||||
.eq(UserFuncPermissionStock::getFuncCode, funcCode)
|
||||
.eq(UserFuncPermissionStock::getCountLimit, 1)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +171,6 @@ public class FuncPermissionServer {
|
||||
UserFuncPermissionStock existing = query(userId, funcCode);
|
||||
|
||||
if (existing == null) {
|
||||
// 无记录,新增
|
||||
UserFuncPermissionStock stock = new UserFuncPermissionStock();
|
||||
stock.setUserId(userId);
|
||||
stock.setFuncCode(funcCode);
|
||||
@@ -138,7 +214,6 @@ public class FuncPermissionServer {
|
||||
UserFuncPermissionStock existing = query(userId, funcCode);
|
||||
|
||||
if (existing == null) {
|
||||
// 无记录,新增
|
||||
UserFuncPermissionStock stock = new UserFuncPermissionStock();
|
||||
stock.setUserId(userId);
|
||||
stock.setFuncCode(funcCode);
|
||||
@@ -168,21 +243,4 @@ public class FuncPermissionServer {
|
||||
|
||||
userFuncPermissionStockMapper.update(null, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回退次数库存(业务异常时调用,仅限次维度有效)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param funcCode 功能权限编码
|
||||
*/
|
||||
public void rollbackCount(Long userId, String funcCode) {
|
||||
userFuncPermissionStockMapper.update(null,
|
||||
new LambdaUpdateWrapper<UserFuncPermissionStock>()
|
||||
.setSql("remain_count = remain_count + 1")
|
||||
.eq(UserFuncPermissionStock::getUserId, userId)
|
||||
.eq(UserFuncPermissionStock::getFuncCode, funcCode)
|
||||
.eq(UserFuncPermissionStock::getCountLimit, 1)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user