Flowable-SpringBoot项目集成

在前面的介绍中,虽然实现了绘制流程图,然后将流程图存储到数据库中,然后从数据库中获取流程信息,并部署和启动流程,但是部署的流程绘制器是在tomcat中部署的,可能在部分的项目中,需要我们将流程设计器,设置到自己的项目中,这样部署项目就相当于部署了流程设计器,下面对SpringBoot项目集成flowable流程设计器进行简单介绍。

一、项目整合

在前面部署flowable-ui后可以看到,ui界面分为了任务应用程序、建模器应用程序、管理员应用程序和身份管理应用程序。

在这几个应用中,最重要的就是建模器应用程序(flowable-modeler),它主要是用来绘制流程图和流程定义信息,因此,在这里我们是在项目中集成了建模器应用程序,实现在自己的项目中使用flowable-ui官方的建模器具绘制流程图,并将其保存到mysql数据库中。

环境:flowable版本:6.7.2 MySQL版本:5.7

  1. 下载源码

在这里下载对应版本的flowable-ui的源码。

Release Flowable 6.7.2 release · flowable/flowable-engine · GitHub

6.7.2版本的源码:

flowable-engine-flowable-6.7.2.zip

  1. flowable引擎基础配置

由于是 spring-boot 项目,因此直接选择 flowable-spring-boot-starter,里面提供了齐全的 REST API

<!--Flowable的核心依赖-->
<dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter-process</artifactId><version>${flowable.version}</version>
</dependency>
<dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>${flowable.version}</version>
</dependency>
<dependency><groupId>org.flowable</groupId><artifactId>flowable-json-converter</artifactId><version>${flowable.version}</version>
</dependency>
<dependency><groupId>org.flowable</groupId><artifactId>flowable-bpmn-layout</artifactId><version>${flowable.version}</version>
</dependency>

添加yml配置:

# flowable config
flowable:# 关闭定时任务JOBasync-executor-activate: true# 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。database-schema-update: truecheck-process-definitions: falsedb-history-used: truehistory-level: full

日志配置:

注意:Flowable 使用 SLF4J 作为内部日志框架,所以我们使用 log4j 作为 SLF4J 的实现

添加依赖:

<!--日志-->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version>
</dependency>

resource 目录下新建文件 log4j.properties

log4j.rootLogger=DEBUG, CAlog4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
  1. 集成 flowable-modeler 前端

这里为了方便我们开发,将官方的flowable-modeler前端项目直接集成到了后端中。

从刚刚下载的源码中获取flowable-modeler的statci文件,6.7.2版本的目录在:

flowable-engine-flowable-6.7.2\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources

复制包中 resources\static 下所有前端代码文件,复制到我们自己的项目static 文件夹下,项目没有static就在resource目录下新建static文件夹。

添加依赖:

<!--通过下方的配置,加上官方源码中的静态文件,就可以将建模器应用程序集成到项目中-->
<dependency><groupId>org.flowable</groupId><artifactId>flowable-ui-modeler-rest</artifactId><version>${flowable.version}</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>org.flowable</groupId><artifactId>flowable-ui-modeler-conf</artifactId><version>${flowable.version}</version>
</dependency>
<dependency><groupId>org.flowable</groupId><artifactId>flowable-ui-modeler-logic</artifactId><version>${flowable.version}</version>
</dependency><dependency><groupId>org.liquibase</groupId><artifactId>liquibase-core</artifactId><version>4.4.0</version>
</dependency>

配置文件:

在新版本的flowable-modeler中,需要配置idm,身份认证的相关配置,因此,在配置文件中添加:

# flowable config
flowable:# 关闭定时任务JOBasync-executor-activate: true# 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。database-schema-update: truecheck-process-definitions: falsedb-history-used: truehistory-level: fullcommon:app:idm-url: http://localhost:8099/flowable-idmidm-admin:user: adminpassword: admin

自定义配置类:

DatabaseAutoConfiguration.java

Flowable 是基于 liquibase 进行数据库自动管理与追踪的,因此需要加一个 liquibase 的配置类(可以把org.flowable.ui.modeler.conf.DatabaseConfiguration下的复制下来改一改)

import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.flowable.ui.common.service.exception.InternalServerErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;@Configuration
public class DatabaseAutoConfiguration {private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseAutoConfiguration.class);protected static final String LIQUIBASE_CHANGELOG_PREFIX = "ACT_DE_";@Beanpublic Liquibase liquibase(DataSource dataSource) {LOGGER.info("Configuring Liquibase");Liquibase liquibase = null;try {DatabaseConnection connection = new JdbcConnection(dataSource.getConnection());Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);database.setDatabaseChangeLogTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogTableName());database.setDatabaseChangeLogLockTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogLockTableName());liquibase = new Liquibase("META-INF/liquibase/flowable-modeler-app-db-changelog.xml", new ClassLoaderResourceAccessor(), database);liquibase.update("flowable");return liquibase;} catch (Exception e) {throw new InternalServerErrorException("Error creating liquibase database", e);} finally {closeDatabase(liquibase);}}private void closeDatabase(Liquibase liquibase) {if (liquibase != null) {Database database = liquibase.getDatabase();if (database != null) {try {database.close();} catch (DatabaseException e) {LOGGER.warn("Error closing database", e);}}}}
}

之后还需要添加mybatis-plus的相关配置:需要配置扫描 classpath:/META-INF/modeler-mybatis-mappings/*.xml

mybatis-plus:mapper-locations: classpath:/mapper/*Mapper.xml, classpath:/META-INF/modeler-mybatis-mappings/*.xmlconfiguration:map-underscore-to-camel-case: truejdbc-type-for-null: null# 参数配置configuration-properties:# 配置流程引擎参数,详情可见 DatabaseConfigurationblobType: BLOBboolValue: TRUE# 不要设置库名,否则会出现双库名 bugprefix: ''

汉化配置:

StencilSetResource.java

在源码中找到这俩文件:

在resource下新建stencilset文件夹,将源码中的两个汉化文件放入该文件夹中。

添加类配置,在这里新建类的时候,名称不能为StencilSetResource,会与官方的jar包中的bean冲突,因此,我们新建FlowableStencilSetResource.java。

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.flowable.ui.common.service.exception.InternalServerErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;/*** 汉化 配置*/
@RestController
@RequestMapping("/app")
public class FlowableStencilSetResource {private static final Logger LOGGER = LoggerFactory.getLogger(FlowableStencilSetResource.class);@Autowiredprotected ObjectMapper objectMapper;@RequestMapping(value = "/rest/stencil-sets/editor", method = RequestMethod.GET, produces = "application/json")public JsonNode getStencilSetForEditor() {try {JsonNode stencilNode = objectMapper.readTree(this.getClass().getClassLoader().getResourceAsStream("stencilset/stencilset_bpmn.json"));return stencilNode;} catch (Exception e) {LOGGER.error("Error reading bpmn stencil set json", e);throw new InternalServerErrorException("Error reading bpmn stencil set json");}}@RequestMapping(value = "/rest/stencil-sets/cmmneditor", method = RequestMethod.GET, produces = "application/json")public JsonNode getCmmnStencilSetForEditor() {try {JsonNode stencilNode = objectMapper.readTree(this.getClass().getClassLoader().getResourceAsStream("stencilset/stencilset_cmmn.json"));return stencilNode;} catch (Exception e) {LOGGER.error("Error reading bpmn stencil set json", e);throw new InternalServerErrorException("Error reading bpmn stencil set json");}}
}

SecurityUtils配置

注意因为源码中引用了这个类,因此我们在配置的时候,路径需要与源码中的路径保持一致,也就是:org.flowable.ui.common.security 这样在 Jar 中的方法在调用时会覆盖原 Jar 里的工具类

下方的类为6.7.2版本的配置,如果是低版本的配置,可能不同,在旧版本中,flowable使用了FlowableAppUser,但是在新版本的依赖中,转而是:SecurityScope,因此这个配置需要根据自己的flowable版本配置。

import java.util.ArrayList;
import java.util.List;
import org.flowable.common.engine.api.FlowableIllegalStateException;
import org.flowable.idm.api.User;
import org.flowable.ui.common.model.RemoteUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;/*** 重构流程编辑器获取用户信息*/
public class SecurityUtils {private static User assumeUser;private static SecurityScopeProvider securityScopeProvider = new FlowableSecurityScopeProvider();private SecurityUtils() {}/*** Get the login of the current user.*/public static String getCurrentUserId() {User user = getCurrentUserObject();if (user != null) {return user.getId();}return null;}/*** @return the {@link User} object associated with the current logged in user.*/public static User getCurrentUserObject() {if (assumeUser != null) {return assumeUser;}RemoteUser user = new RemoteUser();user.setId("admin");user.setDisplayName("admin");user.setFirstName("admin");user.setLastName("admin");user.setEmail("admin@flowable.com");user.setPassword("123456");List<String> pris = new ArrayList<>();pris.add(DefaultPrivileges.ACCESS_MODELER);pris.add(DefaultPrivileges.ACCESS_IDM);pris.add(DefaultPrivileges.ACCESS_ADMIN);pris.add(DefaultPrivileges.ACCESS_TASK);pris.add(DefaultPrivileges.ACCESS_REST_API);user.setPrivileges(pris);return user;}public static void setSecurityScopeProvider(SecurityScopeProvider securityScopeProvider) {SecurityUtils.securityScopeProvider = securityScopeProvider;}public static SecurityScope getCurrentSecurityScope() {SecurityContext securityContext = SecurityContextHolder.getContext();if (securityContext != null && securityContext.getAuthentication() != null) {return getSecurityScope(securityContext.getAuthentication());}return null;}public static SecurityScope getSecurityScope(Authentication authentication) {return securityScopeProvider.getSecurityScope(authentication);}public static SecurityScope getAuthenticatedSecurityScope() {SecurityScope currentSecurityScope = getCurrentSecurityScope();if (currentSecurityScope != null) {return currentSecurityScope;}throw new FlowableIllegalStateException("User is not authenticated");}public static void assumeUser(User user) {assumeUser = user;}public static void clearAssumeUser() {assumeUser = null;}
}

认证请求配置

前端 url-config.js 修改

路径:resource\static\scripts\configuration\url-conf.js

将 getAccountUrl 的路径改为上面自己的 getAccount 接口的路径,我们让他使用我们自己的认证

后端添加Controller

添加一个登录认证的FlowModelerController


/*** flowable-modeler获取默认的管理员信息** @Author: yichangqiao* @Date: 2024/4/19 16:11*/
@Slf4j
@RestController
public class FlowModelerController {/*** 获取默认的管理员信息* @return*/@RequestMapping(value = "/flow/rest/account", method = RequestMethod.GET, produces = "application/json")public UserRepresentation getAccount() {UserRepresentation userRepresentation = new UserRepresentation();userRepresentation.setId("admin");userRepresentation.setEmail("admin@flowable.org");userRepresentation.setFullName("Administrator");userRepresentation.setLastName("Administrator");userRepresentation.setFirstName("Administrator");List<String> privileges = new ArrayList<>();privileges.add(DefaultPrivileges.ACCESS_MODELER);privileges.add(DefaultPrivileges.ACCESS_IDM);privileges.add(DefaultPrivileges.ACCESS_ADMIN);privileges.add(DefaultPrivileges.ACCESS_TASK);privileges.add(DefaultPrivileges.ACCESS_REST_API);userRepresentation.setPrivileges(privileges);log.info("login init success ..... ");return userRepresentation;}
}

mybatis-plus配置

因为flowable自己使用了一个sqlsessionfactory创建SQL会话,但是我们自己的项目中又需要使用mybatis-plus的sqlsessionfactory,在mybatis-plus加载sqlsessionfactory默认是单例的,因此我们需要配置默认的回话连接:

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan(basePackages = {"com.flowable.mapper"},sqlSessionFactoryRef = "sqlSessionFactory",sqlSessionTemplateRef = "sqlSessionTemplate")
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}

配置security

这里我们需要跳过flowable的权限校验,而是使用我们自己的认证框架,因此,需要在项目中配置:

import org.flowable.ui.common.security.SecurityConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@Configuration
public class SecurityConfiguration {@Configuration(proxyBeanMethods = false)//所以这个地方-1让该配置项在FlowableUiSecurityAutoConfiguration中对应配置项前加载,以跳过授权@Order(SecurityConstants.FORM_LOGIN_SECURITY_ORDER - 1)public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http//必须要将csrf设置为disable,不然后面发送POST请求时会报403错误.csrf().disable()//为了简单起见,简单粗暴方式直接放行modeler下面所有请求.authorizeRequests().antMatchers("/**").permitAll();}}}

修改Application启动类配置

让spring加载我们自定义的配置bean:FlowableStencilSetResource.class、DatabaseAutoConfiguration.class

import com.yichangqiao.flowable.config.DatabaseAutoConfiguration;
import com.yichangqiao.flowable.config.FlowableStencilSetResource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.ui.common.security.ApiHttpSecurityCustomizer;
import org.flowable.ui.common.security.FlowableUiSecurityAutoConfiguration;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import java.time.LocalDateTime;@Slf4j
//启用全局异常拦截器
@Import(value = {FlowableStencilSetResource.class,// 引入 DatabaseConfiguration 表更新转换,DatabaseAutoConfiguration.class
})
@ComponentScan(basePackages = {"com.flowable.*"})
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class MasterYiFlowableApplication {public static void main(String[] args) {SpringApplication.run(MasterYiFlowableApplication.class, args);log.info("flowable模块加载成功 ================> {}", LocalDateTime.now());}}

启动项目

启动项目后,访问项目地址:127.0.0.1:端口,就可以访问到我们本地项目中的flowable-modeler了。

三、结语

实际整合过程中,可能存在版本、环境、依赖等影响,导致出现报错,但是大体的思路如上,可以参考整合。

下一节:flowable-整合系统角色人员 Flowable-整合系统角色人员-CSDN博客

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

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

相关文章

<数据集>pcb板缺陷检测数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;693张 标注数量(xml文件个数)&#xff1a;693 标注数量(txt文件个数)&#xff1a;693 标注类别数&#xff1a;6 标注类别名称&#xff1a;[missing_hole, mouse_bite, open_circuit, short, spurious_copper, spur…

git 提交的进阶操作

cherry-pick cherry-pick 是 Git 中的一种操作,允许你从一个分支中选择特定的 commit,并将其应用到另一个分支。它的主要用途是将特定的更改引入到其他分支,而无需合并整个分支历史。这在修复 bug 或者移植某些功能时特别有用。 cherry-pick 的使用场景 Bug 修复: 例如,你…

Python面试宝典第16题:跳跃游戏

题目 给你一个非负整数数组 nums &#xff0c;你最初位于数组的第一个下标 &#xff0c;数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true。否则&#xff0c;返回 false。 示例 1&#xff1a; 输…

detection_segmentation

目标检测和实例分割(OBJECT_DETECTION AND INSTANCE SEGMENTATION) 文章目录 目标检测和实例分割(OBJECT_DETECTION AND INSTANCE SEGMENTATION)一. 计算机视觉(AI VISION)1. 图像分类2. 目标检测与定位3. 语义分割和实例分割目标检测算法可以分为两大类&#xff1a; R-CNN生成…

Linux系统:揭开它神秘面纱的科普之旅

在这个数字化时代&#xff0c;电脑和手机成了我们生活中不可或缺的一部分。而提到这些设备的操作系统&#xff0c;大家可能首先想到的是Windows、macOS或是Android。 但你知道吗&#xff0c;在技术的海洋里&#xff0c;还有一个强大而灵活的操作系统家族&#xff0c;它就是Lin…

python-多任务编程

2. 多任务编程 2.1 多任务概述 多任务 即操作系统中可以同时运行多个任务。比如我们可以同时挂着qq&#xff0c;听音乐&#xff0c;同时上网浏览网页。这是我们看得到的任务&#xff0c;在系统中还有很多系统任务在执行,现在的操作系统基本都是多任务操作系统&#xff0c;具备…

JVM--HostSpot算法细节实现

1.根节点枚举 定义&#xff1a; 我们以可达性分析算法中从GC Roots 集合找引用链这个操作作为介绍虚拟机高效实现的第一个例 子。固定可作为GC Roots 的节点主要在全局性的引用&#xff08;例如常量或类静态属性&#xff09;与执行上下文&#xff08;例如 栈帧中的本地变量表&a…

时间序列预测方法概述

这里写目录标题 时间序列预测方法概述1.统计方法1.1 ARIMA (AutoRegressive Integrated Moving Average)1.2 State Space Models1.3 Exponential Smoothing 2.机器学习方法2.1 SVM (Support Vector Machines)2.2 RF (Random Forest)2.3 KNN (K-Nearest Neighbors) 3. 深度学习方…

latex \left{ \right} 环境不能自动换行

latex \left{ \right} 环境不能自动换行 1. 问题描述2.解决方法 1. 问题描述 可以看到 V { v 1 , v 2 , . . . , v g } V\left\{v_1, v_2, ..., v_g \right\} V{v1​,v2​,...,vg​}没有自动换行。 2.解决方法 在合适换行的位置加入\right.\\ \left.&#xff0c;手动换行。…

连锁收银系统一定需要具备会员营销功能

连锁收银系统不只是一个收银工具&#xff0c;它需要具备会员营销功能&#xff0c;这取决于连锁店的经营策略和目标群体。会员营销功能通常用于吸引和留住忠实客户&#xff0c;通过积分、折扣、专属优惠等方式提升客户的消费频率和金额。连锁店的经营模式侧重于会员制度或者目标…

Golang | Leetcode Golang题解之第257题二叉树的所有路径

题目&#xff1a; 题解&#xff1a; func binaryTreePaths(root *TreeNode) []string {paths : []string{}if root nil {return paths}nodeQueue : []*TreeNode{}pathQueue : []string{}nodeQueue append(nodeQueue, root)pathQueue append(pathQueue, strconv.Itoa(root.V…

PDF文件压缩怎么弄?这3个方法轻松解决

PDF文件压缩怎么弄&#xff1f;PDF文件压缩在日常办公和学习中扮演着至关重要的角色&#xff0c;它不仅仅是减少文件占用的磁盘空间那么简单&#xff0c;更是提升了文件在云存储、电子邮件发送以及跨设备传输时的效率与便捷性。通过压缩&#xff0c;我们能够更快地共享大型文档…

【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析

初阶数据结构相关知识点可以通过点击以下链接进行学习一起加油&#xff01;时间与空间复杂度的深度剖析深入解析顺序表:探索底层逻辑深入解析单链表:探索底层逻辑深入解析带头双向循环链表:探索底层逻辑深入解析栈:探索底层逻辑深入解析队列:探索底层逻辑深入解析循环队列:探索…

【Django+Vue3 线上教育平台项目实战】Celery赋能:优化订单超时处理与自动化定时任务调度

文章目录 前言⭐✨&#x1f4ab;&#x1f525;&#x1f4d6;一、Celery⭐1.基本概念及介绍:✨2.使用步骤&#x1f4ab; 二、订单超时 取消订单&#xff08;Celery&#xff09;&#x1f525;具体实现流程&#x1f4d6; 前言⭐✨&#x1f4ab;&#x1f525;&#x1f4d6; 在构建复…

GIT命令学习 二

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 ☁️运维工程师的职责&#xff1a;监…

开源智能助手平台Dify是什么?

1.背景 对于国内小公司&#xff0c;怎样通过Ai 将内部流程、产品重新做一次&#xff0c;从而提高人效、给客户带来价值&#xff0c;这是老板们在考虑的问题 &#xff1f; 当前市面上的你大模型例如&#xff1a;通义千问、文心一言、kimi、智谱清言、盘古 等&#xff0c;底层能…

JavaWeb服务器-Tomcat(Tomcat概述、Tomcat的下载、安装与卸载、启动与关闭、常见的问题)

Tomcat概述 Tomcat服务器软件是一个免费的开源的web应用服务器。是Apache软件基金会的一个核心项目。由Apache&#xff0c;Sun和其他一些公司及个人共同开发而成。 由于Tomcat只支持Servlet/JSP少量JavaEE规范&#xff0c;所以是一个开源免费的轻量级Web服务器。 JavaEE规范&…

python-网络并发模型

3. 网络并发模型 3.1 网络并发模型概述 什么是网络并发 在实际工作中&#xff0c;一个服务端程序往往要应对多个客户端同时发起访问的情况。如果让服务端程序能够更好的同时满足更多客户端网络请求的情形&#xff0c;这就是并发网络模型。 循环网络模型问题 循环网络模型只能…

逻辑回归损失函数

文章目录 1.基础简析交叉熵损失函数&#xff08;Cross-Entropy Loss&#xff09;对数似然损失函数&#xff08;Log-Likelihood Loss&#xff09; 2.关键步骤3.案例 1.基础简析 逻辑回归&#xff08;Logistic Regression&#xff09;是一种广泛应用于分类问题的统计模型&#x…

C++进阶 继承

目录 继承的概念及定义 继承概念 继承定义 定义格式 继承关系和访问限定符 继承基类成员访问方式的变化 基类和派生类对象赋值转换 继承中的作用域 派生类的默认成员函数 构造函数 拷贝构造函数 赋值运算符重载 析构函数 总结 继承与友元 继承与静态成员 浅谈复杂…