【工作流Activiti7】7、Activiti7+SpringBoot

news2024/11/25 13:12:33

1. 版本问题

1.1. Activiti版本

7.1.0-M6是最后一个支持JDK1.8的版本,此后的版本都要求JDK11以上

目前,Activiti最新版本是7.6.0,它是用JDK11编译的,因此要想使用最新版7.6.0必须升级JDK版本,不能再用1.8

同时,7.6.0依赖的SpringBoot版本是2.7.5

1.2. SpringBoot版本

最新的SpringBoot版本是3.0.0,这个版本不支持JDK1.8,对JDK的最小版本是17

目前可用比较多的Java版本是Java 17 和 Java 19

综合来看,我们采用Java 17+SpringBoot 2.7.5+Activiti 7.6.1

补充:52 = Java 8  55 = Java 11

2. Maven仓库设置

首先要添加Activiti组件的仓库,不然找不到jar包,可用配置在全局的settings.xml文件中,也可以配置在项目pom.xml中

<repositories>
    <repository>
        <id>activiti-releases</id>
        <url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases</url>
    </repository>
</repositories>

如果settings.xml中有镜像,并且所有镜像都使用一个仓库的话(即,morrorOf配置的是*),要注意将新加的这个仓库排除

Maven – Guide to Mirror Settings

举个例子:

3. 依赖管理

Activiti依赖管理

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-dependencies</artifactId>
            <version>7.6.1</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

Dubbo依赖管理

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-bom</artifactId>
            <version>3.1.3</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

完整的父POM如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <!--<version>3.0.0</version>-->
        <version>2.7.5</version>
        <relativePath/>
    </parent>
    <groupId>com.cjs.example</groupId>
    <artifactId>activiti7-sample</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <name>activiti7-sample</name>

    <modules>
        <module>activiti7-sample-provider-api</module>
        <module>activiti7-sample-provider</module>
    </modules>

    <properties>
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <!--
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-spring-boot-starter</artifactId>
                <version>7.1.0.M6</version>
            </dependency>
            -->
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-dependencies</artifactId>
                <version>7.6.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-bom</artifactId>
                <version>3.1.3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.5.2</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <repositories>
        <repository>
            <id>activiti-releases</id>
            <url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases</url>
        </repository>
    </repositories>
</project>

4. Activiti  API使用

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cjs.example</groupId>
        <artifactId>activiti7-sample</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.cjs.example</groupId>
    <artifactId>activiti7-sample-provider</artifactId>
    <version>${parent.version}</version>

    <name>activiti7-sample-provider</name>

    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.cjs.example</groupId>
            <artifactId>activiti7-sample-provider-api</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-registry-nacos</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.yml

server:
  port: 8080
  servlet:
    context-path: /activiti7
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/activiti7?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&nullCatalogMeansCurrent=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  activiti:
    check-process-definitions: false
    database-schema-update: "false" # 第一次运行时设置为true,待表生成完以后改成false,以后就不用再更新表结构了
    db-history-used: true
    history-level: full
    deployment-mode: "never-fail" # org.activiti.spring.autodeployment.AbstractAutoDeploymentStrategy
dubbo:
  application:
    name: activiti7-sample-provider
  protocol:
    name: dubbo
    port: -1
  registry:
    address: nacos://127.0.0.1:8848
  config-center:
    address: nacos://127.0.0.1:8848
  metadata-report:
    address: nacos://127.0.0.1:8848

启动项目后,生成的表结构如图:

也可以自己执行SQL脚本,脚本在源码包activiti-engine-7.6.1.jar里面

由于Activit7集成了SpringSecurity,它用SpringSecurity来做权限管理,因此它需要一个UserDetailsService,不配做的话启动会报错。当然网上也有一种解决办法就是排除SpringSecurity相关的某些类,没试过,应该也是可以的吧。

按照Spring Security 5.7以后的新写法,我们来配置一下WebSecurity

Java Configuration :: Spring Security

https://github.com/spring-projects/spring-security-samples/tree/6.0.x/servlet/spring-boot/java/oauth2

package com.cjs.example.provider.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

/**
 * https://docs.spring.io/spring-security/reference/servlet/configuration/java.html
 * https://github.com/spring-projects/spring-security-samples/tree/6.0.x/servlet/spring-boot/java/oauth2
 *
 * @Author: ChengJianSheng
 * @Date:   2022/12/5
 */
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests(authorize -> authorize.anyRequest().authenticated())
                .formLogin(Customizer.withDefaults());
        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
                // Spring Security should completely ignore URLs starting with /resources/
                .antMatchers("/resources/**");
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails admin = User.withUsername("tom")
                .password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
                .roles("ACTIVITI_USER", "ACTIVITI_ADMIN", "APPLICATION_MANAGER")
                .build();
        UserDetails user = User.withUsername("jerry")
                .password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
                .roles("ACTIVITI_USER", "GROUP_BUSINESS_MANAGER")
                .build();
        UserDetails zhangsan = User.withUsername("zhangsan")
                .password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
                .roles("ACTIVITI_USER")
                .build();
        UserDetails lisi = User.withUsername("lisi")
                .password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
                .roles("ACTIVITI_USER")
                .build();
        return new InMemoryUserDetailsManager(admin, user, zhangsan, lisi);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    public static void main(String[] args) {
        System.out.println(new BCryptPasswordEncoder().encode("123456"));
    }
}

在activiti-spring-boot-starter中新提供了ProcessRuntime 和 TaskRuntime用于流程和任务处理的API,调用它们需要当前操作的用户具有ACTIVITI_USER权限

因此,在使用这两个类之前要保证当前登录用户有这个权限。为了模拟登录,我们来写个登录方法。

package com.cjs.example.provider.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 * @Author: ChengJianSheng
 * @Date: 2022/12/6
 */
@Component
public class SecurityUtil {

    @Autowired
    private UserDetailsService userDetailsService;

    public void logInAs(String username) {
        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (null == user) {
            throw new IllegalStateException(String.format("用户【%s】不存在", username));
        }
        SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                return user.getAuthorities();
            }

            @Override
            public Object getCredentials() {
                return user.getPassword();
            }

            @Override
            public Object getDetails() {
                return user;
            }

            @Override
            public Object getPrincipal() {
                return user;
            }

            @Override
            public boolean isAuthenticated() {
                return true;
            }

            @Override
            public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {

            }

            @Override
            public String getName() {
                return user.getUsername();
            }
        }));
        org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
    }
}

现在可以开始调用API操作流程了

package com.cjs.example.provider.service;

import com.cjs.example.provider.api.WorkflowService;
import com.cjs.example.provider.util.SecurityUtil;
import org.activiti.api.process.model.ProcessInstance;
import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
import org.activiti.api.process.model.payloads.GetProcessInstancesPayload;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.query.Order;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

/**
 * @Author: ChengJianSheng
 * @Date: 2022/12/6
 */
@DubboService
public class WorkflowServiceImpl implements WorkflowService {

    @Autowired
    private ProcessRuntime processRuntime;

    @Autowired
    private TaskRuntime taskRuntime;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private SecurityUtil securityUtil;


    @Override
    public void deploy() {
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("processes/leave.bpmn20.xml")
                .name("请假")
                .key("leave")
                .category("AAA")
                .tenantId("QingJia")
                .deploy();
    }

    @Override
    public void start() {
        securityUtil.logInAs("tom");
        ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder.start()
                .withProcessDefinitionKey("leave")
                .withVariable("hello", "world")
                .withVariable("apple", "orange")
                .withBusinessKey("1")
                .build());
    }

    @Override
    public void startProcessInstance(String processDefinitionKey, String businessKey, Map<String, Object> variables, String tenantId) {
        runtimeService.startProcessInstanceByKeyAndTenantId(processDefinitionKey, businessKey, variables, tenantId);
    }

    @Override
    public void processInstancePage(int pageNo, int pageSize) {
        securityUtil.logInAs("tom");
        GetProcessInstancesPayload payload = new GetProcessInstancesPayload();
        payload.setActiveOnly(true);
        Page<ProcessInstance> page = processRuntime.processInstances(Pageable.of(pageNo-1, pageSize, Order.by("start_time_", Order.Direction.DESC)), payload);
        for (ProcessInstance ps : page.getContent()) {
            System.out.println(ps);
        }
    }

    @Override
    public void taskList() {
        securityUtil.logInAs("zhangsan");
        Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0, 10));
        System.out.println(taskPage.getTotalItems());

        securityUtil.logInAs("lisi");
        taskPage = taskRuntime.tasks(Pageable.of(0, 10));
        System.out.println(taskPage.getTotalItems());
    }

    @Override
    public void claimTask() {
        securityUtil.logInAs("zhangsan");
        String taskId = "429ad159-754c-11ed-aaf8-84a9386654d8";
        Task task = taskRuntime.task(taskId);
        taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(taskId).build());
    }

    @Override
    public void completeTask() {
        securityUtil.logInAs("zhangsan");
        String taskId = "429ad159-754c-11ed-aaf8-84a9386654d8";
        taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskId).build());
    }
}

注意:可以把tenantId看成是某个业务,businessKey当做业务ID,比如:放款流程001。或者建一张中间表用于关联流程ID和业务ID。

最后,配置流程监听器

package com.cjs.example.provider.config;

import lombok.extern.slf4j.Slf4j;
import org.activiti.api.process.runtime.events.ProcessCompletedEvent;
import org.activiti.api.process.runtime.events.listener.ProcessRuntimeEventListener;
import org.activiti.api.task.runtime.events.TaskAssignedEvent;
import org.activiti.api.task.runtime.events.TaskCompletedEvent;
import org.activiti.api.task.runtime.events.listener.TaskRuntimeEventListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: ChengJianSheng
 * @Date: 2022/12/6
 */
@Slf4j
@Configuration
public class ListenerConfig {

    @Bean
    public ProcessRuntimeEventListener<ProcessCompletedEvent> processCompletedListener() {
        return processCompleted -> log.info(">>> Process Completed: '"
                + processCompleted.getEntity().getName() +
                "' We can send a notification to the initiator: " + processCompleted.getEntity().getInitiator());
    }

    @Bean
    public TaskRuntimeEventListener<TaskAssignedEvent> taskAssignedListener() {
        return taskAssigned -> log.info(">>> Task Assigned: '"
                + taskAssigned.getEntity().getName() +
                "' We can send a notification to the assginee: " + taskAssigned.getEntity().getAssignee());
    }

    @Bean
    public TaskRuntimeEventListener<TaskCompletedEvent> taskCompletedListener() {
        return taskCompleted -> log.info(">>> Task Completed: '"
                + taskCompleted.getEntity().getName() +
                "' We can send a notification to the owner: " + taskCompleted.getEntity().getOwner());
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/114423.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数组中数字出现的次数-有限状态自动机】

数组中数字出现的次数一&#xff0c;有限状态自动机解法二&#xff0c;一般解法想必大家对数组中数字出现的次数的这种题并不少见&#xff0c; 主要有三种&#xff1a; 1&#xff0c;找出数组中只出现一次的数字&#xff08;其他数字出现两次&#xff09; 2&#xff0c;找出数组…

渗透测试指操作系统漏洞发现与防御概述

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是渗透测试指操作系统漏洞发现与防御概述。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#x…

Android四大组件之Service

文章目录Android四大组件之默默劳动的Service什么是ServiceAndroid多线程编程线程的基本用法在子线程中更新UI解析异步消息处理机制MessageHandlerMessageQueueLooper异步消息的整个流程使用AsyncTaskService的基本用法定义一个Service启动和停止ServiceActivity和Service进行通…

【4】axi协议学习

1、axi背景介绍: Advanced extensible Interface(AXI)是为了满足高性能系统设计而定义的一套独立通道协议,首次是在2003年发布的AMBA3标准中出现,经历AMBA4,目前已经到达AMBA5版本。 2、axi 特性: AXI满足如下的特性: 适合于高带宽,低延迟的设计 不需要通过复杂的桥…

去耦电容和旁路的概念说明与应用说明

回想当初第一眼看觉得&#xff0c;这啥玩意自己又菜了&#xff01; 电容&#xff1a;本质就是充放电&#xff0c;实际应该我们围着这个来转 一、解释 旁路电容从英文角度看&#xff0c;就是抄小路的意思&#xff0c;意思当有一个干扰来临时候&#xff0c;可以通过这个电容抄…

LeetCode 1739. 放置盒子:数学 思维

【LetMeFly】1739.放置盒子 力扣题目链接&#xff1a;https://leetcode.cn/problems/building-boxes/ 有一个立方体房间&#xff0c;其长度、宽度和高度都等于 n 个单位。请你在房间里放置 n 个盒子&#xff0c;每个盒子都是一个单位边长的立方体。放置规则如下&#xff1a; …

世界杯竞猜项目Dapp-第五章(合约升级)

目前主流有三种合约升级方法 transparent 方式&#xff1b;(通用&#xff0c;业务逻辑和代理逻辑解耦合&#xff0c;比较贵&#xff09;uups 方式&#xff1b;&#xff08;代理逻辑集成到了业务逻辑&#xff0c;通过继承来实现&#xff0c;便宜&#xff09;beacon 方式&#x…

408 考研《操作系统》第三章第二节:基本分页存储管理、两级页表、基本分段存储管理方式、段页式管理方式

文章目录教程1. 基本分页存储管理的基本概念1.1 连续分配方式的缺点1.2 把“固定分区分配”改造为“非连续分配版本”1.3 什么是分页存储1.4 如何实现地址的转换&#xff1f;1.5 逻辑地址结构1.6 重要的数据结构——页表1.7 知识回顾与重要考点2. 基本地址变换机构2.1 例题2.2 …

node.js+uni计算机毕设项目购物小程序(程序+小程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等…

不写一行代码(一):实现安卓基于GPIO的LED设备驱动

文章目录系列文章一、前言二、准备工作2.1 内核版本2.2 内核文档&#xff1a;bindings->leds2.3 文档解析&#xff1a; leds-gpio.txt三、编写DTS3.1 查原理图&#xff0c;挑选GPIO3.2 编写DTS文件四、编译测试4.1 编译dt.img4.2 烧录dt.img五、基于fs的测试5.1 测试命令5.2…

第二十五章 数论——约数

第二十五章 数论——约数一、什么是约数二、约数的求解——试除法1、问题2、思路分析3、代码实现三、约数个数1、问题描述2、算法思路3、代码实现四、约数之和1、问题描述2、算法思路3、代码实现五、最大公约数——欧几里德算法1、问题描述2、算法思路&#xff08;1&#xff09…

前端实现文件上传(点击+拖拽)

一、简介 之前在Vue项目中使用过element的上传组件&#xff0c;实现了点击上传拖拽上传的两种上传功能。然后我就在想是否可以通过原生的htmljs来实现文件的点击上传和拖拽上传&#xff0c;说干就干。 首先是点击获取上传文件自然没的说&#xff0c;只需要借助input标签即可&a…

Java面试题(六)RabbitMQ常见面试题

RabbitMQ常见面试题RabbitMQ架构设计RabbitMQ有哪些优点RabbitMQ事物机制RabbitMQ持久化机制持久化和非持久化什么时候需要持久化&#xff1f;落盘过程文件删除RabbitMQ如何保证消息不丢失RabbitMQ如何保证消息不被重复消费RabbitMQ死信队列&#xff0c;延时队列死信队列延时队…

如何使用 ChatGPT 进行教学,教师可以利用 ChatGPT 的 5 种方式

我们听说过很多关于学生如何使用 ChatGPT 撰写论文和布置家庭作业的信息。 我们一直在讨论围绕这个问题的担忧,并争先恐后地为 ChatGPT 寻找 AI 检测工具,据传 OpenAI 也在致力于此。 但是关于教师如何将 ChatGPT 用于他们自己的工作的讨论并不多。 在从教师的角度对 Chat…

20221222 Coppeliasim的视频导出功能

Video exporter CoppeliaSim的视频记录器可以对the page, scene hierarchy and model browser areas进行录屏&#xff0c;保存成视频文件。Dialogs, menu bar, toolbars and popup menus &#xff08;对话框、菜单栏、工具栏和弹出菜单&#xff09;不会被录进去. 默认情况下&am…

【C++11】包装器

目录 1.function包装器 1.1什么是函数包装器(function)&#xff1f; 1.2为啥使用函数包装器(function)&#xff1f; 2.bind包装器 2.1绑定普通函数和调整传参顺序 2.2绑定类成员函数 1.function包装器 头文件#include<functional> 1.1什么是函数包装器(function)&a…

2022年终总结

不知不觉就到了年末&#xff0c;感叹时间过的真快。 我自己坚持写了七年多的博客&#xff0c;但这其实是我第一次去写年终总结。也不知道怎么写&#xff0c;就简单聊聊。 写博客的初衷就是个人收获&#xff0c;学习的记录&#xff0c;分享出来如果能帮到别人那就更好了。毕竟…

(一)LTspice简介2

文章目录前言一、LTspice的仿真过程二、spice的模型三、LTspice的工具栏和快捷键四、LTspice中的数量级前言 上一节我们学习了LTspice的安装&#xff0c;很简单&#xff0c;无脑安装 &#xff08;一&#xff09;LTspice安装 这一节我们继续学习LTspice的简介&#xff0c;主要包…

题:A-B 数对(二分)

A-B 数对 - 洛谷 题目背景 出题是一件痛苦的事情&#xff01; 相同的题目看多了也会有审美疲劳&#xff0c;于是我舍弃了大家所熟悉的 AB Problem&#xff0c;改用 A-B 了哈哈&#xff01; 题目描述 给出一串正整数数列以及一个正整数 CC&#xff0c;要求计算出所有满足 A…

通过Wireshark分析Apache服务器的SSL协议工作过程

文章目录一、实验环境二、为Apache服务器启用SSL1.获取SSL证书2.修改httpd.conf配置文件3.修改httpd-ssl.conf配置文件4.启动Apache服务三、SSL/TLS工作过程分析一、实验环境 操作系统&#xff1a;macOS Ventura 13.0.1 Apache&#xff1a;Apache/2.4.54 (Unix)&#xff0c;此…