Springboot2.7集成websocket及相关问题
1、集成websocket完整代码
导入maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
服务端代码
(1)注入bean
@Configuration
@EnableWebSocket
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
(2)服务端开放的服务及其业务逻辑
@Slf4j
@Component
@ServerEndpoint("/testcase/page/{clientId}")
//@Lazy
public class WsMessageService {//与某个客户端的连接会话private Session session;//存放每个客户端对应的WebSocket对象。private static Map<String, WsMessageService> webSocketsBeanMap = new ConcurrentHashMap<>();//每次连接都是一个新的会话对象,线程安全的String userId;//注入业务类。要注意setTestcaseService()的名称不能错,set后的字符串要和要注入的变量名一致。private static TestcaseService testcaseService;@Autowiredpublic void setTestcaseService(TestcaseService testcaseService) {WsMessageService.testcaseService= testcaseService;}//private TestcaseService testcaseService = SpringContextUtil.getBean(TestcaseService.class);@OnOpenpublic void onOpen(Session session, @PathParam(value = "clientId") String userId) {this.session = session;this.userId = userId;webSocketsBeanMap.put(userId, this);log.info("OnOpen连接成功,userId:{},当前在线人数:{}", userId, this.getOnLineCount());}@OnMessagepublic void onMessage(String message) throws IOException {Session session = webSocketsBeanMap.get(this.userId).session;if (session==null || !session.isOpen()) {return;}log.info("收到客户端的消息:" + message);//start业务Integer pageNum = null;Integer pageSize = null;String pid = null;String vid = null;if (session.getRequestParameterMap().get("pageNum")!= null) {pageNum = Integer.valueOf(session.getRequestParameterMap().get("pageNum").get(0));}if (session.getRequestParameterMap().get("pageNum")!= null) {pageSize = Integer.valueOf(session.getRequestParameterMap().get("pageSize").get(0));}if (session.getRequestParameterMap().get("pid")!= null) {pid = session.getRequestParameterMap().get("pid").get(0);}if (session.getRequestParameterMap().get("vid")!= null) {vid = session.getRequestParameterMap().get("vid").get(0);}PageInfo<TestcasePageVO> pageInfo = testcaseService.findTestcaseByMultiCondition(pageNum, pageSize, pid, vid);//end业务try {JSONObject object = new JSONObject();object.put("data", pageInfo);object.put("code", 200);object.put("message", "SUCCESS");this.session.getBasicRemote().sendText(String.valueOf(object.toString()));} catch (IOException e) {throw new RuntimeException(e);}}@OnClosepublic void onClose() throws IOException {log.info("会话关闭,关闭会话的用户Id为:{}", this.userId);webSocketsBeanMap.remove(this.userId);log.info("当前在线人数:{}", this.getOnLineCount());}@OnErrorpublic void onError(Session session, Throwable error) {log.error("连接错误:" + error.getMessage());error.printStackTrace();}private int getOnLineCount() {return webSocketsBeanMap.size();}
}
测试服务端的可用性。在浏览器的控制台输入以下代码可以测试。
function initWebSocket(wsUri) {var websocket = new WebSocket(wsUri);websocket.onopen = function(evt) {console.log('连接建立中... '+wsUri);};websocket.onclose = function(evt) {console.log('连接关闭中...', evt);};websocket.onmessage = function(evt) {console.log('收到来自服务端的消息:', evt.data);};websocket.onerror = function(evt) {console.log('发生错误...', evt);};return websocket;}var websocket = initWebSocket("ws://ip:port/testcase/page/123?pid=5922cc3d03f74012a7112c931c8497d7&vid=fc2d7a6049ff4c7bafc40bf659b4e903");var msg, i = 0;var loop = setInterval(function(){msg = "Hello " +(i++);if(websocket.readyState == WebSocket.OPEN) {websocket.send(msg);console.log('已发送消息:' +msg);} else{clearInterval(loop);console.log('连接已关闭');}}, 10000);
2、集成websocket另一种方法(用控制台测试时返回的数据会乱码)
代码找不到了。但那种方法有一个特征就是使用的注解比当前的方法少。
3、解决业务类注入不进去的问题(两种方法,推荐第一种)
(1)第一种:就是当前使用的注入方法。注意命名,否则不会注入成功
//注入业务类。要注意setTestcaseService()的名称不能错,set后的字符串要和要注入的变量名一致。private static TestcaseService testcaseService;@Autowiredpublic void setTestcaseService(TestcaseService testcaseService) {WsMessageService.testcaseService= testcaseService;}
(2)第二种:自己写一个SpringContextUtil工具类,协助注入
package cn.xxxxx.tmMaster.utils;import lombok.extern.slf4j.Slf4j;
import org.mybatis.logging.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import java.util.logging.Logger;@Slf4j
@Component
public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringContextUtil.applicationContext = applicationContext;}/*** 获取 applicationContext*/public static ApplicationContext getApplicationContext() {return applicationContext;}/*** 通过 name 获取 bean 对象*/public static Object getBean(String name) {return getApplicationContext().getBean(name);}/*** 通过 class 获取 bean 对象*/public static <T> T getBean(Class<T> clazz) {return getApplicationContext().getBean(clazz);}/*** 通过 name,clazz 获取指定的 bean 对象*/public static <T> T getBean(String name, Class<T> clazz) {return getApplicationContext().getBean(name, clazz);}
}
在WsMessageService中使用如下代码注入进去,但在类上必须要@Lazy进行懒加载,否则会报错
@Lazy
public class WsMessageService {
……private TestcaseService testcaseService = SpringContextUtil.getBean(TestcaseService.class);
……
}
不加@Lazy报错如下:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wsMessageService' defined in file [D:\javaworkspace\test-xxxx\tm-master\target\classes\cn\xxxxx\tmMaster\service\testcase\WsMessageService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.xxxxx.tmMaster.service.testcase.WsMessageService]: Constructor threw exception; nested exception is java.lang.NullPointerException
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wsMessageService' defined in file [D:\javaworkspace\test-xxxx\tm-master\target\classes\cn\xxxxx\tmMaster\service\testcase\WsMessageService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.xxxxx.tmMaster.service.testcase.WsMessageService]: Constructor threw exception; nested exception is java.lang.NullPointerExceptionat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1334) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:921) ~[spring-context-5.3.29.jar:5.3.29]at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.29.jar:5.3.29]at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) [spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) [spring-boot-2.7.14.jar:2.7.14]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) [spring-boot-2.7.14.jar:2.7.14]at cn.xxxxx.tmMaster.MasterApplication.main(MasterApplication.java:17) [classes/:na]at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_382]at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_382]at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_382]at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_382]at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) [spring-boot-devtools-2.7.14.jar:2.7.14]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.xxxxx.tmMaster.service.testcase.WsMessageService]: Constructor threw exception; nested exception is java.lang.NullPointerExceptionat org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:224) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.3.29.jar:5.3.29]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1326) ~[spring-beans-5.3.29.jar:5.3.29]... 22 common frames omitted
Caused by: java.lang.NullPointerException: nullat cn.xxxxx.tmMaster.utils.SpringContextUtil.getBean(SpringContextUtil.java:55) ~[classes/:na]at cn.xxxxx.tmMaster.service.testcase.WsMessageService.<init>(WsMessageService.java:48) ~[classes/:na]at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_382]at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_382]at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_382]at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_382]at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:211) ~[spring-beans-5.3.29.jar:5.3.29]... 24 common frames omitted
参考资料:
SpringBoot集成WebSocket实现客户端与服务端长连接通信_springboot实现websocket客户端_拄杖忙学轻声码的博客-CSDN博客 SpringBoot集成WebSocket实现客户端与服务端长连接通信
快速搭建springboot websocket客户端_springboot实现websocket客户端_wcybaonier的博客-CSDN博客 快速搭建springboot websocket客户端
相关文章:
Springboot2.7集成websocket及相关问题
1、集成websocket完整代码 导入maven依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency> 服务端代码 (1)注入bean Configur…...
MES管理系统和ERP系统在生产制造管理中的应用
MES生产管理系统通过过程管理、质量管理、设备管理、产品跟踪和溯源、性能分析和物料管理等方面来管理生产制造,旨在建立规范的生产管理信息平台,提高企业核心竞争力。ERP系统则通过制定生产计划、细分物料需求计划、车间订单下达和生产回报等步骤进行生…...
Netty Channel 详解
优质博文:IT-BLOG-CN 一、Netty 服务端启动过程 【1】创建服务端Channel; 【2】初始化服务端Channel; 【3】注册Selector; 【4】端口绑定:我们分析源码的入口从端口绑定开始,ServerBootstrap的bind(int in…...
技师学院物联网实训室建建设方案
一、概述 1.1专业背景 物联网(Internet of Things)被称为继计算机、互联网之后世界信息产业第三次浪潮,它并非一个全新的技术领域,而是现代信息技术发展到一定阶段后出现的一种聚合性应用与技术提升,是随着传感网、通…...
SpringBoot项目--电脑商城【增加/减少购物车商品数量】
1.持久层[Mapper] 1.1规划需要执行的SQL语句 1.更新该商品的数量.此SQL语句无需重复开发 update t_cart set num?,modified_user?,modified_time? where cid? 2.首先进行查询需要操作的购物车数据信息【查看该条数据是否存在】 SELECT * FROM t_cart WHERE cid?2.接口…...
CSS元素浮动
概述 浮动简介 在最初,浮动是用来实现文字环绕图片效果的,现在浮动是主流的页面布局方式之一。 元素浮动后的特点 脱离文档流。不管浮动前是什么元素,浮动后,默认宽与高都是被内容撑开的(尽可能小)&am…...
MATLAB中islocalmin函数用法
目录 语法 说明 示例 向量中的局部最小值 矩阵行中的最小值 相隔最小值 最小值平台区 突出最小值 islocalmin函数的功能是计算局部最小值。 语法 TF islocalmin(A) TF islocalmin(A,dim) TF islocalmin(___,Name,Value) [TF,P] islocalmin(___) 说明 当在 A 的…...
Python+Requests+Pytest+YAML+Allure实现接口自动化
本项目实现接口自动化的技术选型:PythonRequestsPytestYAMLAllure ,主要是针对之前开发的一个接口项目来进行学习,通过 PythonRequests 来发送和处理HTTP协议的请求接口,使用 Pytest 作为测试执行器,使用 YAML 来管理测…...
双视觉Transformer(Dual Vision Transformer)
摘要 已经提出了几种策略来减轻具有高分辨率输入的自注意机制的计算:比如将图像补丁上的全局自注意过程分解成区域和局部特征提取过程,每个过程都招致较小的计算复杂度。尽管效率良好,这些方法很少探索所有补丁之间的整体交互,因…...
MES系统成为工业4.0首选,制造业真正数字化车间你看过吗?
在日益激烈的市场竞争中,MES管理系统已经成为企业提升生产效率、降低成本、提高竞争力的关键。通过MES管理系统实现数据集成和分析,能够对产品制造过程的各个环节进行可视化控制,从设计、制造、质量、物流等环节全面掌控信息,实现…...
Vuex有几种属性以及它们的意义
有五种,分别是 State、 Getter、Mutation 、Action、 Module。 一、State Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实…...
PRBP20P-10/250C-EB、PRDP6G-10/30-CB电液比例直动式先导减压阀放大板
PRDP6P-10/30-CB、PRDP6R-10/50-DC、PRDP6G-10/30-CC、PRDP6P-10/50-CB、PRDP6R-10/30-CC、PRDP6G-10/30-CB电液比例直动式先导减压阀 PRBP10P-10/50C-EB、PRBP20P-10/100C-EC、PRBP30P-10/150C-EB、PRBP20P-10/250C-EB、PRBP10P-10/315C-EC、PRBP30P-10/350C-EB电液比例柱塞平…...
GDB之常见缩写命令(十九)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
MarkText快捷键(随时补充中)
MarkText快捷键 ctrl1:一号标题 (需要手动在【左上角】-【file】-【preferences】-【Key Bindings】-【 Transform into Heading 1】手动调整,先将【Switch tab to the 1st】占用快捷键删除才能在下面添加) ctrlg:添加…...
每日一题 1601最多可达成的换楼请求数目(子集模版)
题目 1601 我们有 n 栋楼,编号从 0 到 n - 1 。每栋楼有若干员工。由于现在是换楼的季节,部分员工想要换一栋楼居住。 给你一个数组 requests ,其中 requests[i] [fromi, toi] ,表示一个员工请求从编号为 fromi 的楼搬到编号为…...
排序算法-归并排序
属性 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序&#…...
vue3 整合 springboot 打完整jar包
前端 .env.developmen VITE_APP_BASE_URL/api.env.production VITE_APP_BASE_URL/axios 配置 axios.defaults.baseURL import.meta.env.VITE_APP_BASE_URLpackage.json "scripts": {"dev": "vite --mode development","build": &…...
依赖倒转原则是什么?
依赖倒转原则(Dependency Inversion Principle)是面向对象设计中的另一个基本原则,它是由Robert C. Martin提出的,它的中心思想是面向接口编程,该原则指出高层模块不应该依赖于低层模块,两者都应该依赖于抽…...
什么是GPT与MBR
GPT(GUID Partition Table)和MBR(Master Boot Record)是两种不同的磁盘分区表格式。 MBR是一种较早的磁盘分区表格式,它使用512字节的扇区作为存储空间。MBR分区表可以定义最多4个主分区,每个主分区都可以…...
前后端开发接口联调对接参数
前言 一个完整的互联网系统项目,需要前后端配合,进行上线,针对前端开发者,现在互联网主流的项目都是前后端分离 也就是后端负责提供数据接口,前端负责UI界面数据渲染 凡是在前台数据展示与用户交互的,都是由前端来实现的,而数据来源是由后台服务提供的 在浏览器c端能够发送后端…...
定时任务框架-xxljob
1.定时任务 spring传统的定时任务Scheduled,但是这样存在这一些问题 : 做集群任务的重复执行问题 cron表达式定义在代码之中,修改不方便 定时任务失败了,无法重试也没有统计 如果任务量过大,不能有效的分片执行 …...
idea项目配置三大步
场景: 使用 idea 打开一个新项目的时候,想让项目迅速跑起来, 其实只需要下面简单三步: 1. 首先,配maven 2. 其次,配置 jdk 这里配置 project 就行了,不用管Modules中的配置。 3. 最后&#…...
学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量
目录 一、简介 ( 1 ) 是什么 ( 2 ) 分类 ( 3 ) 作用 二、自定义注解 ( 1 ) 如何自定义注解 ( 2 ) 场景演示 场景一(获取类与方法上的注解值) 场景二( 获取类属性上的注解属性值 ) 场景三( 获取参数修…...
步态识别常见模块解读及代码实现:基于OpenGait框架
步态识别常见模块解读及代码实现:基于OpenGait框架 最近在看步态识别相关论文,但是因为记忆力下降的原因,老是忘记一些内容。因此记录下来方便以后查阅,仅供自己学习参考,没有背景知识和论文介绍。 目录 步态识别常见…...
前端八股文之“闭包”
一、定义 一句话概括闭包:能够访问函数内部变量的函数与这个变量的组合构成了闭包结构。如下代码 function fuc1(){let num 999return function fuc2(){console.log(num)}}fuc1()(); 如代码所示,fuc2和父级变量num构成了一个闭包环境。 二、原理 子…...
数据可视化:掌握数据领域的万金油技能
⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据开发、数据分析等。 🐴欢迎小伙伴们点赞👍🏻、收藏⭐️、…...
Apache Kafka 基于 S3 的数据导出、导入、备份、还原、迁移方案
在系统升级或迁移时,用户常常需要将一个 Kafka 集群中的数据导出(备份),然后在新集群或另一个集群中再将数据导入(还原)。通常,Kafka集群间的数据复制和同步多采用 Kafka MirrorMaker࿰…...
事务管理AOP
事务管理 事务回顾 概念:事务是一组操作的集合,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败 操作: 开启事务:一组操作开始前,开启事务-start transaction/be…...
Java从Tif中抽取最大的那张图进行裁剪成x*y份
之前我有一篇帖子《kfb格式文件转jpg格式》讲述到 kfb > tif > jpg,但是针对于超大tif中的大图是无法顺利提取的,就算是能顺利提取,试想一下,2G的tif文件,如果能提取处理最大的那张图,并且在不压缩的…...
人工智能AI界的龙头企业,炸裂的“英伟达”时代能走多远
原创 | 文 BFT机器人 1、AI芯片的竞争格局已趋白热化 尽管各类具有不同功能和定位的AI芯片在一定程度上可实现互补,但同时也在机遇与挑战并存中持续调整定位。在AI训练端,英伟达的GPU凭着高算力的门槛,一直都是训练端的首选。 只有少数芯片能…...
深圳培训公司网站建设/网站在线客服系统免费
Java远程方法调用(RMI)机制和公用对象请求代理体系(CORBA)是最重要 和使用最广泛的两种分布式对象系统。每个系统都有其特点和短处。它们在行 业中被用于从电子交易到保健医疗的各个领域。一个项目如果要从这两种分布式 机制中选用…...
电子商务网站项目建设阶段的划分/百度网页版登录
2019独角兽企业重金招聘Python工程师标准>>> 这两天研究了FFmpeg获取DirectShow设备数据的方法,在此简单记录一下以作备忘。本文所述的方法主要是对应Windows平台的。 1. 列设备 ffmpeg -list_devices true -f dshow -i dummy 命令执行后输出的结果…...
精品课程网站开发的创新点/安卓优化大师app
当一个循环较长,我们想实现一个进度条的时候,tqdm是一个非常好的选择。 安装 tqdm的安装非常简单,用pip就可以了。 pip install tqdm 使用 在tqdm包中,我们一般使用的两个函数是tqdm和trange两个。建议大家自己尝试一下&…...
wordpress 主题调试/ui设计公司
一、问题 假设山洞中有N种宝物,每种宝物有一定的重量w和相应的价值v,大盗的运载能力有限,只能随身携带重量M的宝物,一种宝物只能拿一样,宝物可以分割。那么怎么才能一次带走宝物的价值最大呢? 二、分析 …...
南通做网站多少钱/专业黑帽seo推广
布局布线Place&Route1布局我们前面做的那些设计流程得到的LUT门级网表就好比一个购物清单,即LUT门级网表。网表里提供的仅仅是从逻辑关系上一些LUT结构的连接。我们需要将这些LUT结构配置到FPGA具体的哪个位置。需要说明的是,FPGA里任何硬件结构都是…...
php做网站开发有什么框架/电商运营培训班
项目协作与工作流程规范 俗话说磨刀不负砍柴功,如果不知道为什么这么做,能有什么好处,则即使指定的规范也不会良好的落地实施。下面就讨论规范及规范解决了哪些问题,和解决方法是什么: 1、项目之间能够互相调用&#x…...