背景

使用springboot+mybatisPlus进行业务开发 为列表返回设置翻译值,由于需要翻译的字段较多考虑使用异步提升接口效率,但是由于使用了mybatisPlus的全局租户拦截,需要获取用户信息导致报错。

解决方案:

采用 Spring 的 TaskDecorator 方案来传播安全上下文

实现代码:

package com.minex.ams.infrastructure.config.thread;

import org.springframework.core.task.TaskDecorator;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

@Component
public class SecurityContextCopyingDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable runnable) {
        // 获取当前线程的安全上下文
        SecurityContext context = SecurityContextHolder.getContext();
        return () -> {
            try {
                // 设置新的安全上下文到当前线程
                SecurityContextHolder.setContext(context);
                // 执行实际的任务
                runnable.run();
            } finally {
                // 清理操作,确保不会意外地保留上下文
                SecurityContextHolder.clearContext();
            }
        };
    }
}

 

package com.minex.ams.infrastructure.config.thread;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class AsyncConfig {

    @Bean(name = "contextAwareExecutor")
    public ThreadPoolTaskExecutor taskExecutor(SecurityContextCopyingDecorator decorator) {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // 根据需要调整
        executor.setMaxPoolSize(10); // 根据需要调整
        executor.setQueueCapacity(25); // 根据需要调整
        executor.setTaskDecorator(decorator); // 设置 TaskDecorator
        executor.initialize();
        return executor;
    }
}

具体使用:

 
@Resource
private ThreadPoolTaskExecutor executor;

private
void handleNames(List<WireVO> records) { // 使用CompletableFuture并行加载不同种类的数据 CompletableFuture<Void> projectFuture = CompletableFuture.runAsync(() -> { List<Long> projectIds = records.stream().map(WireVO::getProjectId).collect(Collectors.toList()); if (!projectIds.isEmpty()) { List<Project> projects = projectRepository.lambdaQuery().in(Project::getId, projectIds).list(); records.forEach(t -> t.setProjectName(projects.stream() .filter(project -> project.getId().equals(t.getProjectId())) .findFirst().orElse(new Project()).getName())); } },executor); CompletableFuture<Void> departmentFuture = CompletableFuture.runAsync(() -> { List<Long> pmIds = records.stream().map(WireVO::getPmId).collect(Collectors.toList()); if (!pmIds.isEmpty()) { List<Department> departments = departmentRepository.lambdaQuery().in(Department::getId, pmIds).list(); records.forEach(t -> t.setManagementName(departments.stream() .filter(department -> department.getId().equals(t.getPmId())) .findFirst().orElse(new Department()).getName())); } },executor); CompletableFuture<Void> deviceModelFuture = CompletableFuture.runAsync(() -> { List<Long> deviceModelIds = records.stream().map(WireVO::getDeviceModelId).collect(Collectors.toList()); if (!deviceModelIds.isEmpty()) { List<DeviceModel> deviceModels = deviceModelRepository.lambdaQuery().in(DeviceModel::getId, deviceModelIds).list(); records.forEach(t -> t.setDeviceModelName(deviceModels.stream() .filter(deviceModel -> deviceModel.getId().equals(t.getDeviceModelId())) .findFirst().orElse(new DeviceModel()).getName())); } },executor); // 等待所有异步任务完成 CompletableFuture.allOf(projectFuture, departmentFuture, deviceModelFuture).join(); }

通过这种方式,你可以在异步任务中正确访问 SecurityContextHolder.getContext().getAuthentication(),因为安全上下文已经被适当地传播到了子线程中。

 

posted @ 2025-02-20 18:19 官萧何 阅读(20) 评论(0) 推荐(0) 编辑
摘要: 示例代码: @Override public IPage<DeviceAlarmSignalConfigVO> findPage(DeviceAlarmSignalConfigQueryRO query, CurrentUser user) { query.setFirmCode(user.getF 阅读全文
posted @ 2024-12-24 09:05 官萧何 阅读(167) 评论(0) 推荐(0) 编辑
摘要: 示例:把指定数据库minex-pms所有表中的project_depart_name字段 重庆项目部更改为渝北项目部,不存在project_depart_name字段的表排除掉,使用临时表和sql脚本的方式实现 sql脚本: -- 1. 创建实体表来存储需要更新的表名 CREATE TABLE IF 阅读全文
posted @ 2024-12-20 16:38 官萧何 阅读(28) 评论(0) 推荐(0) 编辑
摘要: 1.背景 在本地部署没有问题,但是通过docker-compose部署到docker环境中就出现以下异常: Caused by: java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11FontManager 或 c 阅读全文
posted @ 2024-12-11 14:50 官萧何 阅读(398) 评论(0) 推荐(0) 编辑
摘要: 1.需求:需要导出的EXCEL示例: 2.依赖: <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.1.5</version> </dependency> 3.工具类: 阅读全文
posted @ 2024-12-06 10:27 官萧何 阅读(110) 评论(1) 推荐(0) 编辑
点击右上角即可分享
微信分享提示