目录
[1. 异步处理优势](#1. 异步处理优势)
[2. 异步管理器实现](#2. 异步管理器实现)
[1. @Log注解使用](#1. @Log注解使用)
[2. AOP切面实现](#2. AOP切面实现)
[1. Quartz核心配置](#1. Quartz核心配置)
[2. 定时任务工具类](#2. 定时任务工具类)
[3. 集群模式配置](#3. 集群模式配置)
[1. 数据权限类型](#1. 数据权限类型)
[2. @DataScope注解使用](#2. @DataScope注解使用)
[3. MyBatis SQL拼接](#3. MyBatis SQL拼接)
[4. 数据权限切面实现](#4. 数据权限切面实现)
本文介绍了企业级应用中的四个核心功能实现方案:
1.异步任务管理器通过线程池实现非阻塞任务处理,提升系统性能;
2.操作日志自动化记录利用AOP切面和自定义注解实现方法级日志采集;
3.定时任务管理基于Quartz框架实现分布式任务调度,支持集群部署;
4.数据权限控制通过注解和SQL拼接实现多维度数据访问控制。这些方案通过注解驱动、AOP切面等技术手段,实现了业务逻辑与技术实现的解耦,提高了系统的可维护性和扩展性。
一、异步任务管理器
1. 异步处理优势
-
性能提升:将非核心业务异步执行,减少主线程等待时间
-
故障隔离:异步任务失败不影响主业务事务
-
提高响应速度:用户无需等待所有任务完成
2. 异步管理器实现
java
// 异步管理器单例
public class AsyncManager {
private static AsyncManager instance = new AsyncManager();
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
public static AsyncManager me() {
return instance;
}
public void execute(TimerTask task) {
executor.schedule(task, 10, TimeUnit.MILLISECONDS);
}
}
// 异步工厂
public class AsyncFactory {
public static TimerTask recordLoginLog(String username, String status, String message) {
return new TimerTask() {
@Override
public void run() {
// 构建日志对象
SysLogininfor logininfor = new SysLogininfor();
logininfor.setUserName(username);
logininfor.setStatus(status);
logininfor.setMsg(message);
logininfor.setLoginTime(new Date());
// 异步保存日志
SpringUtils.getBean(ISysLogininforService.class)
.insertLogininfor(logininfor);
}
};
}
}
// 使用示例
AsyncManager.me().execute(AsyncFactory.recordLoginLog(
username,
Constants.LOGIN_SUCCESS,
"登录成功"
));
二、操作日志自动化记录
1. @Log注解使用
java
@Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody SysUser user) {
return toAjax(userService.insertUser(user));
}
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody SysUser user) {
return toAjax(userService.updateUser(user));
}
@Log(title = "用户管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{userIds}")
public AjaxResult remove(@PathVariable Long[] userIds) {
return toAjax(userService.deleteUserByIds(userIds));
}
2. AOP切面实现
java
@Aspect
@Component
public class LogAspect {
@Around("@annotation(controllerLog)")
public Object around(ProceedingJoinPoint joinPoint, Log controllerLog) throws Throwable {
// 执行前记录开始时间
long beginTime = System.currentTimeMillis();
// 执行方法
Object result = joinPoint.proceed();
// 执行后记录日志
long time = System.currentTimeMillis() - beginTime;
recordLog(joinPoint, controllerLog, result, time);
return result;
}
private void recordLog(ProceedingJoinPoint joinPoint, Log log, Object result, long time) {
// 异步记录操作日志
AsyncManager.me().execute(AsyncFactory.recordOper(
log.title(),
log.businessType(),
joinPoint.getArgs(),
result,
time
));
}
}
三、定时任务管理
1. Quartz核心配置
java
@Configuration
public class ScheduleConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
Properties prop = new Properties();
// 集群配置
prop.put("org.quartz.jobStore.isClustered", "true");
prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
factory.setQuartzProperties(prop);
factory.setSchedulerName("FrameworkScheduler");
factory.setStartupDelay(1);
factory.setOverwriteExistingJobs(true);
factory.setAutoStartup(true);
return factory;
}
}
2. 定时任务工具类
java
public class ScheduleUtils {
// 创建定时任务
public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException {
Class<? extends Job> jobClass = getQuartzJobClass(job);
// 构建JobDetail
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(getJobKey(job.getJobId()))
.build();
// 构建触发器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
.cronSchedule(job.getCronExpression());
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(job.getJobId()))
.withSchedule(cronScheduleBuilder)
.build();
// 将任务参数传入JobDataMap
jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
scheduler.scheduleJob(jobDetail, trigger);
// 暂停任务
if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
pauseJob(scheduler, job.getJobId());
}
}
}
3. 集群模式配置
-
导入Quartz集群表
-
修改配置开启集群
-
多节点部署实现负载均衡
集群优势:
-
高可用性:单点故障不影响服务
-
负载均衡:任务分散执行
-
数据持久化:任务状态不丢失
四、数据权限控制
1. 数据权限类型
java
public class DataScopeConstants {
// 全部数据权限
public static final String DATA_SCOPE_ALL = "1";
// 自定义数据权限
public static final String DATA_SCOPE_CUSTOM = "2";
// 部门数据权限
public static final String DATA_SCOPE_DEPT = "3";
// 部门及以下数据权限
public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
// 仅本人数据权限
public static final String DATA_SCOPE_SELF = "5";
}
2. @DataScope注解使用
java
@Service
public class SysLogininforServiceImpl implements ISysLogininforService {
@DataScope(deptAlias = "d", userAlias = "u")
@Override
public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor) {
return logininforMapper.selectLogininforList(logininfor);
}
}
3. MyBatis SQL拼接
XML
<select id="selectLogininforList" parameterType="SysLogininfor" resultMap="SysLogininforResult">
select * from sys_logininfor l
left join sys_dept d on l.dept_id = d.dept_id
left join sys_user u on l.user_id = u.user_id
<where>
<!-- 查询条件 -->
<if test="userName != null and userName != ''">
AND l.user_name like concat('%', #{userName}, '%')
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
</where>
</select>
4. 数据权限切面实现
java
@Aspect
@Component
public class DataScopeAspect {
@Before("@annotation(controllerDataScope)")
public void doBefore(JoinPoint point, DataScope controllerDataScope) {
clearDataScope(point);
handleDataScope(point, controllerDataScope);
}
protected void handleDataScope(JoinPoint joinPoint, DataScope controllerDataScope) {
// 获取当前用户
LoginUser loginUser = SecurityUtils.getLoginUser();
SysUser currentUser = loginUser.getUser();
if (!currentUser.isAdmin()) {
// 构建数据范围SQL
String dataScopeSql = buildDataScopeSql(currentUser,
controllerDataScope.deptAlias(),
controllerDataScope.userAlias());
// 设置到参数中
Object params = joinPoint.getArgs()[0];
if (params instanceof BaseEntity) {
((BaseEntity) params).getParams()
.put("dataScope", " AND (" + dataScopeSql + ")");
}
}
}
private String buildDataScopeSql(SysUser user, String deptAlias, String userAlias) {
StringBuilder sql = new StringBuilder();
for (SysRole role : user.getRoles()) {
String dataScope = role.getDataScope();
switch (dataScope) {
case DataScopeConstants.DATA_SCOPE_CUSTOM:
sql.append(String.format(
" OR %s.dept_id IN (SELECT dept_id FROM sys_role_dept WHERE role_id = %d) ",
deptAlias, role.getRoleId()));
break;
case DataScopeConstants.DATA_SCOPE_DEPT:
sql.append(String.format(" OR %s.dept_id = %d ", deptAlias, user.getDeptId()));
break;
case DataScopeConstants.DATA_SCOPE_DEPT_AND_CHILD:
sql.append(String.format(
" OR %s.dept_id IN (SELECT dept_id FROM sys_dept WHERE dept_id = %d or find_in_set(%d, ancestors))",
deptAlias, user.getDeptId(), user.getDeptId()));
break;
case DataScopeConstants.DATA_SCOPE_SELF:
if (StringUtils.isNotBlank(userAlias)) {
sql.append(String.format(" OR %s.user_id = %d ", userAlias, user.getUserId()));
}
break;
}
}
return sql.length() > 0 ? sql.substring(4) : "1=0";
}
}