Flowable 與 Spring Boot 深度集成:從環境搭建到平臺構建

在前三篇文章中,我們依次認識了 Flowable 的基礎概念、用 Modeler 設計流程,以及通過 API 控制流程運行。但在實際項目中,我們更需要將 Flowable 與 Spring Boot 深度融合,構建完整的工作流平臺。本文將從環境配置、設計器集成、權限控制等方面,分享 Flowable 與 Spring Boot 集成的實戰經驗。

一、Flowable 與 Spring Boot 的無縫對接

1.1 基礎環境配置

Spring Boot 對 Flowable 提供了自動配置支持,只需引入相關依賴即可快速集成:

<dependencies><!-- Flowable核心依賴 --><dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.8.0</version></dependency><!-- Web依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</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-security</artifactId></dependency>
</dependencies>

在application.yml中配置數據庫和 Flowable 參數:

spring:datasource:url: jdbc:mysql://localhost:3306/flowable_boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTCusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driverflowable:# 數據庫表結構更新策略database-schema-update: true# 異步執行器配置async-executor-activate: true# 歷史記錄級別history-level: full# 流程部署路徑process-definition-location-prefix: classpath:/processes/

1.2 自定義 Flowable 配置

通過ProcessEngineConfigurationConfigurer可自定義流程引擎配置:

@Configuration
public class FlowableConfig implements ProcessEngineConfigurationConfigurer {@Overridepublic void configure(SpringProcessEngineConfiguration configuration) {// 配置郵件服務器(用于任務通知)configuration.setMailServerHost("smtp.example.com");configuration.setMailServerPort(587);configuration.setMailServerUsername("notifications@example.com");configuration.setMailServerPassword("password");// 配置自定義表單類型List<AbstractFormType> customFormTypes = new ArrayList<>();customFormTypes.add(new PhoneFormType()); // 自定義手機號表單類型customFormTypes.add(new IdCardFormType()); // 自定義身份證表單類型configuration.setCustomFormTypes(customFormTypes);// 配置流程自動部署器configuration.setDeploymentName("spring-boot-deployment");}
}

二、Flowable Modeler 與業務系統集成

將 Flowable Modeler 嵌入業務系統,實現流程設計與業務的無縫銜接。

2.1 部署獨立的 Modeler 服務

  1. 下載 Flowable Modeler 的 WAR 包并部署到 Tomcat
  2. 配置跨域支持(flowable-modeler-app/WEB-INF/classes/flowable-modeler.properties):
flowable.modeler.app.cors.allowed-origins=http://localhost:8080flowable.modeler.app.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONSflowable.modeler.app.cors.allowed-headers=Content-Type,Authorization

?3.配置與業務系統相同的數據庫,實現數據共享

2.2 實現 Modeler 與業務系統的單點登錄

通過自定義過濾器實現 SSO 集成:

@Component
public class ModelerSsoFilter extends OncePerRequestFilter {@Autowiredprivate AuthenticationManager authenticationManager;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 從請求頭獲取令牌String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {try {// 驗證令牌并創建認證對象UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(token, token);Authentication authentication = authenticationManager.authenticate(authToken);// 設置安全上下文SecurityContextHolder.getContext().setAuthentication(authentication);} catch (AuthenticationException e) {SecurityContextHolder.clearContext();}}filterChain.doFilter(request, response);}
}

2.3 流程部署與版本管理

實現流程設計完成后自動部署到業務系統:

@Service
public class ProcessDeploymentService {@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate RestTemplate restTemplate;/*** 從Modeler獲取流程模型并部署*/public Deployment deployFromModeler(String modelId) {// 調用Modeler的API獲取流程模型JSONString modelUrl = "http://localhost:8080/flowable-modeler/app/rest/models/" + modelId + "/source";String bpmnXml = restTemplate.getForObject(modelUrl, String.class);// 部署流程定義return repositoryService.createDeployment().name("model-" + modelId).addString("process-" + modelId + ".bpmn20.xml", bpmnXml).deploy();}/*** 流程版本管理*/public List<ProcessDefinition> getProcessVersions(String processKey) {return repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey).orderByProcessDefinitionVersion().asc().list();}/*** 激活指定版本的流程*/public void activateProcessVersion(String processDefinitionId) {repositoryService.activateProcessDefinitionById(processDefinitionId);// 停用其他版本String processKey = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult().getKey();List<ProcessDefinition> otherVersions = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey).processDefinitionIdNotEquals(processDefinitionId).list();otherVersions.forEach(def -> repositoryService.suspendProcessDefinitionById(def.getId()));}
}

三、基于 Flowable 的工作流平臺搭建

構建包含待辦任務、流程監控、報表分析的完整工作流平臺。

3.1 待辦任務中心

實現個人待辦、已辦任務的統一管理:

@RestController
@RequestMapping("/workflow/task")
public class TaskController {@Autowiredprivate TaskService taskService;@Autowiredprivate IdentityService identityService;/*** 獲取當前用戶的待辦任務*/@GetMapping("/pending")public Page<TaskVO> getPendingTasks(@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size) {String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();// 查詢待辦任務(包含候選人任務)List<Task> tasks = taskService.createTaskQuery().taskCandidateOrAssigned(currentUser).orderByTaskCreateTime().desc().listPage(page * size, size);// 轉換為VO對象List<TaskVO> taskVOs = tasks.stream().map(this::convertToVO).collect(Collectors.toList());// 計算總條數long total = taskService.createTaskQuery().taskCandidateOrAssigned(currentUser).count();return new Page<>(taskVOs, page, size, total);}/*** 認領任務*/@PostMapping("/claim/{taskId}")public ResponseEntity<Void> claimTask(@PathVariable String taskId) {String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();// 驗證任務是否可認領Task task = taskService.createTaskQuery().taskId(taskId).taskCandidateUser(currentUser).singleResult();if (task == null) {return ResponseEntity.badRequest().build();}// 認領任務taskService.claim(taskId, currentUser);return ResponseEntity.ok().build();}/*** 完成任務*/@PostMapping("/complete/{taskId}")public ResponseEntity<Void> completeTask(@PathVariable String taskId,@RequestBody TaskCompleteRequest request) {String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();// 驗證任務歸屬Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee(currentUser).singleResult();if (task == null) {return ResponseEntity.badRequest().build();}// 完成任務taskService.complete(taskId, request.getVariables());return ResponseEntity.ok().build();}// 其他方法:獲取已辦任務、委托任務、轉辦任務等
}

3.2 流程監控與分析

實現流程運行狀態的實時監控和數據分析:

@RestController
@RequestMapping("/workflow/monitor")
public class MonitorController {@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate HistoryService historyService;@Autowiredprivate ManagementService managementService;/*** 流程運行狀態統計*/@GetMapping("/statistics")public WorkflowStatisticsVO getStatistics() {WorkflowStatisticsVO stats = new WorkflowStatisticsVO();// 運行中流程數量stats.setRunningProcessCount(runtimeService.createProcessInstanceQuery().active().count());// 已完成流程數量stats.setCompletedProcessCount(historyService.createHistoricProcessInstanceQuery().finished().count());// 平均流程完成時間HistoricProcessInstanceStatistics avgStats = historyService.createHistoricProcessInstanceStatisticsQuery(null).singleResult();if (avgStats != null) {stats.setAvgCompletionTime(avgStats.getAverageDurationInMillis());}// 各流程定義的運行數量List<ProcessDefinitionCountVO> definitionCounts = runtimeService.createProcessInstanceQuery().groupByProcessDefinitionKey().countByProcessDefinitionKey().entrySet().stream().map(entry -> {ProcessDefinitionCountVO vo = new ProcessDefinitionCountVO();vo.setProcessKey(entry.getKey());vo.setCount(entry.getValue());return vo;}).collect(Collectors.toList());stats.setProcessDefinitionCounts(definitionCounts);return stats;}/*** 流程實例跟蹤*/@GetMapping("/trace/{processInstanceId}")public ProcessTraceVO traceProcess(@PathVariable String processInstanceId) {// 獲取流程實例ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();// 獲取歷史活動實例List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();// 構建流程跟蹤VOProcessTraceVO traceVO = new ProcessTraceVO();traceVO.setProcessInstanceId(processInstanceId);traceVO.setProcessDefinitionId(instance.getProcessDefinitionId());traceVO.setStartTime(instance.getStartTime());traceVO.setStatus(instance.isEnded() ? "completed" : "running");// 轉換活動實例List<ActivityTraceVO> activityTraces = activities.stream().map(activity -> {ActivityTraceVO activityVO = new ActivityTraceVO();activityVO.setActivityId(activity.getActivityId());activityVO.setActivityName(activity.getActivityName());activityVO.setAssignee(activity.getAssignee());activityVO.setStartTime(activity.getStartTime());activityVO.setEndTime(activity.getEndTime());activityVO.setDuration(activity.getDurationInMillis());return activityVO;}).collect(Collectors.toList());traceVO.setActivities(activityTraces);return traceVO;}
}

3.3 流程報表與分析

通過報表分析流程瓶頸,優化業務流程:

@Service
public class WorkflowReportService {@Autowiredprivate HistoryService historyService;/*** 流程環節耗時分析*/public List<ActivityDurationVO> analyzeActivityDurations(String processKey) {// 查詢指定流程的所有歷史活動List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery().processDefinitionKey(processKey).activityTypeIn("userTask", "serviceTask").list();// 按活動ID分組計算平均耗時Map<String, List<Long>> durationMap = new HashMap<>();for (HistoricActivityInstance activity : activities) {String activityId = activity.getActivityId();long duration = activity.getDurationInMillis() == null ? 0 : activity.getDurationInMillis();durationMap.computeIfAbsent(activityId, k -> new ArrayList<>()).add(duration);}// 計算平均值并轉換為VOreturn durationMap.entrySet().stream().map(entry -> {ActivityDurationVO vo = new ActivityDurationVO();vo.setActivityId(entry.getKey());// 獲取活動名稱String activityName = activities.stream().filter(a -> a.getActivityId().equals(entry.getKey())).findFirst().map(HistoricActivityInstance::getActivityName).orElse(entry.getKey());vo.setActivityName(activityName);// 計算平均耗時List<Long> durations = entry.getValue();long avgDuration = durations.stream().mapToLong(Long::longValue).average().orElse(0);vo.setAvgDuration(avgDuration);vo.setCount(durations.size());return vo;}).sorted(Comparator.comparingLong(ActivityDurationVO::getAvgDuration).reversed()).collect(Collectors.toList());}
}

四、安全與權限控制

集成 Spring Security 實現流程操作的權限管控。

4.1 基于角色的權限控制

@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(auth -> auth// 公開接口.requestMatchers("/workflow/public/**", "/actuator/health").permitAll()// 管理員接口.requestMatchers("/workflow/admin/**", "/flowable-ui/**").hasRole("ADMIN")// 流程設計接口.requestMatchers("/workflow/model/**").hasAnyRole("ADMIN", "PROCESS_DESIGNER")// 其他接口需認證.anyRequest().authenticated()).oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))).csrf(csrf -> csrf.disable());return http.build();}/*** JWT認證轉換器(將JWT聲明轉換為Spring Security權限)*/private JwtAuthenticationConverter jwtAuthenticationConverter() {JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();grantedAuthoritiesConverter.setAuthoritiesClaimName("roles");grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");JwtAuthenticationConverter converter = new JwtAuthenticationConverter();converter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);return converter;}
}

4.2 流程權限的細粒度控制

通過AccessControlProvider控制流程實例的訪問權限:

@Component
public class CustomAccessControlProvider implements AccessControlProvider {@Autowiredprivate ProcessRepositoryService processRepositoryService;@Overridepublic boolean isAuthorized(UserDetails user, String processInstanceId) {String username = user.getUsername();// 管理員擁有所有權限if (user.getAuthorities().stream().anyMatch(auth -> auth.getAuthority().equals("ROLE_ADMIN"))) {return true;}// 流程發起人擁有權限ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();if (instance != null && username.equals(instance.getStartUserId())) {return true;}// 參與過流程的用戶擁有權限long participatedCount = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).taskAssignee(username).count();if (participatedCount > 0) {return true;}return false;}
}

五、實際項目中的架構設計與踩坑經驗

5.1 分布式環境下的 Flowable 部署

在微服務架構中,Flowable 的部署策略:

  1. 共享數據庫模式:所有服務共享 Flowable 數據庫,適合中小規模部署
  2. 獨立流程服務:將 Flowable 作為獨立微服務,提供 REST API 供其他服務調用
  3. 事件驅動架構:通過消息隊列(如 Kafka)實現流程事件的跨服務通知

5.2 性能優化實踐

  1. 歷史數據歸檔:定期將舊的歷史數據遷移到歸檔庫
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2點執行
public void archiveHistoricData() {// 歸檔30天前的歷史數據Date cutoffDate = new Date(System.currentTimeMillis() - 30L * 24 * 60 * 60 * 1000);historyService.createHistoricProcessInstanceQuery().finished().processInstanceEndTimeBefore(cutoffDate).list().forEach(instance -> {// 遷移到歸檔表archiveService.archiveInstance(instance.getId());// 刪除原表數據historyService.deleteHistoricProcessInstance(instance.getId());});
}

2.流程變量優化

  • 避免存儲大對象(超過 1KB)
  • 使用runtimeService.setVariableLocal設置局部變量
  • 敏感信息加密存儲

3.緩存策略:緩存流程定義和常用流程數據

@Bean
public CacheManager flowableCacheManager() {CaffeineCacheManager cacheManager = new CaffeineCacheManager();cacheManager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).maximumSize(1000));return cacheManager;
}

5.3 常見問題及解決方案

問題

解決方案

流程實例查詢性能差

1. 減少返回字段 2. 分頁查詢 3. 添加索引 4. 使用緩存

分布式環境下流程事件重復處理

1. 使用冪等設計 2. 事件去重 3. 分布式鎖控制

大并發下任務創建慢

1. 異步創建任務 2. 批量處理 3. 數據庫優化

流程版本升級困難

1. 設計兼容的流程變更 2. 流程實例遷移工具 3. 灰度發布策略

六、小結與下一篇預告

本文我們實現了 Flowable 與 Spring Boot 的深度集成,包括:

  • 環境搭建與自定義配置
  • Modeler 與業務系統的無縫對接
  • 工作流平臺核心功能(待辦任務、流程監控)
  • 安全權限控制與分布式部署策略

這些內容足以支撐企業級工作流平臺的構建。下一篇文章,我們將探討 Flowable 的高級特性與擴展,包括:

  • 動態流程生成(無需預先設計 BPMN 文件)
  • Flowable 與決策引擎 DMN 的集成
  • 復雜場景的流程設計模式(如子流程嵌套、事件子流程)
  • 自定義 Flowable 的核心組件(如自定義解析器、行為處理器)

如果在集成過程中遇到特殊場景或技術難題,歡迎在評論區留言討論!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92653.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92653.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92653.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Jenkins最新版本的安裝以及集成Allure生成測試報告

目錄 Jenkins的安裝 將上面的目錄添加到系統環境變量中 為Jenkins配置密碼 創建一個用戶&#xff0c;用于登錄jenkins 為Jenkins安裝Allure插件 幾個大坑 使用jenkins集成python測試項目 Jenkins的安裝 Jenkins官方網址 Jenkins 點擊download 點擊 past Release選擇你想要下載…

Vue3 面試題及詳細答案120道 (1-15 )

《前后端面試題》專欄集合了前后端各個知識模塊的面試題&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

基于 GitLab 實踐敏捷開發

在軟件開發中&#xff0c;**基于 GitLab 實踐敏捷開發**&#xff0c;并建立一套**規范的日常管理流程**&#xff0c;不僅可以提升團隊協作效率&#xff0c;還能確保平臺持續向好迭代、性能穩步提升。以下是一個完整的實踐方案&#xff0c;適用于中小型團隊或中大型項目&#xf…

黑馬點評使用Apifox導入接口測試合集(持續更新、詳細圖解)

目錄 一、前言 二、更新店鋪 三、添加秒殺券 四、秒殺下單和秒殺下單user2 一、前言 本博客將持續更新記錄黑馬點評所有接口測試的導入(學到哪更新到哪)&#xff0c;以此博客為完整導入接口測試的合集。第一次在黑馬點評項目使用Apifox進行接口測試直接先看我前面的博客&a…

MYOJ_10583:CSP初賽題單7:計算機常識綜合練習

更多初賽題單請參見題目整理CSP初賽題目整理題單&#xff0c;謝謝。 注&#xff1a;閱讀此題單時建議先看1~5&#xff0c;再試著自己做。 題目描述 1. [J-2010-6][S-2010-6]提出“存儲程序”的計算機工作原理的是&#xff08; &#xff09;。 A. 克勞德香農 B. 戈登摩爾 C.…

代碼隨想錄day22回溯算法1

文章目錄77. 組合216.組合總和III17. 電話號碼的字母組合77. 組合 題目鏈接 文章講解 class Solution { public:vector<vector<int>> res; // 存儲所有的組合vector<int> path; // 當前正在構建的組合// 回溯算法void solve(int n, int k, int st…

【Android】Popup menu:彈出式菜單

Popup menu&#xff1a;彈出式菜單 PopupMenu&#xff0c;彈出菜單&#xff0c;一個模態形式展示的彈出風格的菜單&#xff0c;綁在在某個View上&#xff0c;一般出現在被綁定的View的下方&#xff08;如果下方有空間&#xff09;。 注意&#xff1a;彈出菜單是在API 11和更高版…

20250724-day21

Main Memory Database System&#xff08;MMDB&#xff09;&#xff1a;基于內存的數據庫系統 File Database&#xff08;FDB&#xff09;&#xff1a;基于文件的數據庫 Netware Database&#xff08;NDB&#xff09;&#xff1a;基于網絡的數據庫 daemon&#xff1a;守護進程 …

API是什么,如何保障API安全?

API&#xff08;應用程序編程接口&#xff09;是什么&#xff1f; API&#xff08;Application Programming Interface&#xff09;是不同軟件系統之間通信的“橋梁”。它定義了應用程序如何請求服務、交換數據或調用功能&#xff0c;無需了解底層實現細節。例如&#xff0c;當…

深度分析Java多線程機制

Java 多線程是掌握高性能、高響應性應用程序開發的關鍵&#xff0c;它涉及到語言特性、JVM 實現、操作系統交互以及并發編程的核心概念。 核心目標&#xff1a; 充分利用現代多核 CPU 的計算能力&#xff0c;提高程序吞吐量&#xff08;單位時間內處理的任務量&#xff09;和響…

Android熱修復實現方案深度分析

熱修復的核心目標是在**不發布新版本、不重新安裝、不重啟應用&#xff08;或僅輕量級重啟&#xff09;**的情況下&#xff0c;修復線上應用的 Bug 或進行小范圍的功能更新&#xff0c;極大地提升用戶體驗和問題響應速度。 一、熱修復的核心原理 無論哪種方案&#xff0c;其核心…

HTML前端顏色漸變動畫完整指南

漸變動畫已經成為現代網頁設計中不可或缺的元素&#xff0c;它們不僅能為網站增添視覺吸引力&#xff0c;還能顯著提升用戶體驗。通過巧妙運用CSS漸變動畫&#xff0c;開發者可以創造出令人印象深刻的動態背景效果&#xff0c;而無需依賴圖片或復雜的腳本。 漸變動畫的魅力所在…

b-up:Enzo_mi:Transformer DETR系列

1.視頻1&#xff1a;self-Attention&#xff5c;自注意力機制 &#xff5c;位置編碼 &#xff5c; 理論 代碼 注意&#xff1a; q-查詢; k-商品標簽&#xff1b; v-值&#xff08;具體商品&#xff09; * 不是指乘法&#xff0c;類似概念 a1:相似度&#xff1b; b1:總分 若想…

算法題(179):單調棧

審題&#xff1a; 本題是單調棧的模板題 補充&#xff1a;單調棧 單調棧中的數據始終保持單調遞增或單調遞減 使用情景&#xff1a;給定一個數組&#xff0c;要求尋找 1.某個數左側&#xff0c;離他最近且值大于他的數 2.某個數左側&#xff0c;離他最近且值小于他的數 3.某個數…

CF每日5題(1500-1600)

545C 貪心 1500 題意&#xff1a;給 n 棵樹在一維數軸上的坐標 xix_ixi? &#xff0c;以及它們的長度 hih_ihi?。現在要你砍倒這些樹&#xff0c;樹可以向左倒也可以向右倒&#xff0c;砍倒的樹不能重合、當然也不能覆蓋其他的樹原來的位置&#xff0c;現在求最大可以砍倒的…

HW藍隊:天眼告警監測分析之Web攻擊

Web攻擊 信息泄露 敏感數據包括但不限于:口令、密鑰、證書、會話標識、License、隱私數據(如短消息的內容)、授權憑據、個人數據(如姓名、住址、電話等)等&#xff0c;在程序文件、配置文件、日志文件、備份文件及數據庫中都有可能包含敏感數據 信息收集方法 漏洞分類 備份文…

大騰智能國產3D CAD軟件正式上架華為云云商店

深圳市大騰信息技術有限公司&#xff08;以下簡稱“大騰智能”&#xff09;與華為云達成深度合作&#xff0c;大騰智能CAD軟件及配套服務通過了華為云在功能適配、安全可用、穩定高效等方面的嚴選商品認證&#xff0c;已正式上架華為云云商店&#xff0c;成為華為云云商店的聯營…

論文復現-windows電腦在pycharm中運行.sh文件

1.更改終端路徑&#xff08;前提&#xff1a;已下載git bash&#xff09;2.授權打開pycharm終端&#xff0c;輸入 chmod x 文件名3.根據當前位置&#xff0c;運行.sh文件

開關電源安全保護電路:浪涌保護、過流保護、過壓保護

開關電源安全保護電路:浪涌保護、過流保護、過壓保護 引言 對于開關電源而言, 安全、可靠性歷來被視為重要的性能之一. 開關電源在電氣技術指標滿足電子設備正常使用要求的條件下, 還要滿足外界或自身電路或負載電路出現故障的情況下也能安全可靠地工作. 為此, 須有多種保護措…

C語言(十)

一、函數概述函數是面向過程編程思想的具體體現&#xff0c;主要作用&#xff1a;降低程序之間的耦合性提高代碼的復用性和可維護性一個完整的 C 程序由**一個或多個程序模塊&#xff08;源文件&#xff09;**組成。為便于開發與調試&#xff0c;通常會將代碼拆分為多個源文件&…