如何利用spring自带的事件发布订阅实现各种异步操作

许久不见,小伙伴们!

最近工作确实非常忙碌,今天终于抽空整理了一篇关于如何在实际开发中利用Spring框架自带的事件机制实现异步操作的文章。希望这篇分享能够给大家带来一些启发。

首先,我写这个的原因是因为我实际开发中遇到这么一个开发场景:

我们的一个新项目登录相关的是用的keycloak,这也就说明 我们的用户是存在于keycloak中,我接到的需求是 批量导入用户功能,这也就意味着 我要找到keycloak的批量新增用户接口,但很不幸的时keycloak并没有批量新增用户的接口只有一个新增用户的接口

那我要批量新增怎么办,只能解析完excel数据UserList然后循环去调这个接口,这个涉及到调用第三方接口还是循环调就考虑异步去调接口了.

废话不多说,直接上代码!!

实现步骤

我先把controller和service代码贴一下 有头有尾看起来比较顺畅
Controller

java 复制代码
    @PostMapping("/action/import")
    @ApiOperation(value = "导入用户", notes = "导入用户")
    public void importFile(@RequestParam MultipartFile file) throws IOException {
        userService.importFile(file);
    }

service

java 复制代码
  @Autowired
    private CreatorUserPublisher creatorUserPublisher;

    public void importFile(MultipartFile file) throws IOException {
        ExcelUtils.importFile(file, UserImportDTO.class, new ImportHandler<>(list -> createAll(list)));
    }

 public void createAll(List<UserImportDTO> list) {
        String eventId = IdUtil.randomUUID();
        OperationLogUtil.setEventId(eventId);
        // 判断数据是否有重复
        dataHandle(list);
        // 组装用户数据
        List<UserParam> userParams = new ArrayList<>();
        for (UserImportDTO userImportDTO : list) {
            UserParam userParam = new UserParam();
            userParam.setUsername(userImportDTO.getUsername());
            userParam.setEmail(userImportDTO.getEmail());
            userParam.setEnabled(true);

            List<UserParam.CredentialsDTO> credentials = new ArrayList<>();
            UserParam.CredentialsDTO credentialsDTO = new UserParam.CredentialsDTO();
            credentialsDTO.setType("password");
            credentialsDTO.setValue(userImportDTO.getP6d());
            credentials.add(credentialsDTO);
            userParam.setCredentials(credentials);

            UserParam.AttributesDTO attributesDTO = new UserParam.AttributesDTO();
            attributesDTO.setProject(userImportDTO.getUsername());
            userParam.setAttributes(attributesDTO);
            userParams.add(userParam);
        }
        // 异步调用keycloak接口新增用户

        Map<String, Object> map = new HashMap<>();
        map.put("userParams", userParams);
        map.put("eventId", eventId);
        log.info("发布异步新增keycloak用户任务");
        creatorUserPublisher.creatorUserList(map);
    }

以上代码大部分都不重要

下面我来讲一下这个service里面注入了一个
@Autowired
private CreatorUserPublisher creatorUserPublisher;

这个东西的作用就是发布事件

接下来进入正题
1.创建事件类

java 复制代码
public class CreatorUserEvent extends ApplicationEvent {
    private static final long serialVersionUID = -1843750195817873742L;

    private Map<String, Object> map;

    public CreatorUserEvent(Object source) {
        super(source);
    }

    public CreatorUserEvent(Object source, Map<String, Object> map) {
        super(source);
        this.map = map;
    }

    public Map<String, Object> getMap() {
        return map;
    }
}

2.发布事件

这个就是我们在service里面注入之后发布的创建用户的事件

java 复制代码
@Service
@Slf4j
public class CreatorUserPublisher implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void creatorUserList(Map<String, Object> map) {
        applicationEventPublisher.publishEvent(new CreatorUserEvent(this, map));
    }
}

3.监听事件

这个就是处理我们之间在service里面发布的创建用户的事件

java 复制代码
@Service
@Slf4j
public class CreatorUserListener implements ApplicationListener<CreatorUserEvent> {

    @Autowired
    private UserService userService;

    @Override
    public void onApplicationEvent(CreatorUserEvent creatorUserEvent) {
        log.info("开始执行异步任务");
        Map<String, Object> map = creatorUserEvent.getMap();

        List<UserParam> userParams = (List<UserParam>) map.get("userParams");
        String eventId = (String) map.get("eventId");
        for (UserParam userParam : userParams) {
            if (!userService.addUser(userParam)) {
                log.error("新增用户失败:{}", userParam.getUsername());
                throw new SecurityResourceUnavailableException(UserError.ADD_USER_ERROR);
            }
        }
    }
}

到这就完活了 是不是很简单 就三步: 创建事件、发布事件、监听事件

只要service里面的方法执行完之后就会给前端返回响应消息了,后面的事件监听到之后处理的逻辑跟返回前端没关了也不会影响接口超时,如果监听事件处理的逻辑得结果有需要返回前端的话,建议用websocket去处理吧 主动向前端去发送处理结果

希望对你们有帮助。 开心写代码☺

相关推荐
吾日三省吾码1 小时前
JVM 性能调优
java
Estar.Lee1 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
弗拉唐2 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi773 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
2401_857610033 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
少说多做3433 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀3 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20204 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深4 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++