當(dāng)前位置:首頁 > IT技術(shù) > Windows編程 > 正文

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比
2021-10-18 17:40:52


BIMFACE二次開發(fā)系列目錄???? ?【已更新最新開發(fā)文章,點(diǎn)擊查 看詳細(xì)】


?


在我的前一篇博客??《??C#開發(fā)BIMFACE系列41 服務(wù)端API之模型對比??》??中詳細(xì)介紹了BIMFACE服務(wù)端接口模型對比的功能。 BIMFACE官方文檔提供的三維模型對比接口同樣也適用于二維CAD圖紙對比。下圖中是官方提供的對比示例程序。

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_c#開發(fā)

其中新增的圖元使用綠色標(biāo)記、修改的圖元使用黃色標(biāo)記、刪除的圖元使用紅色標(biāo)記。

下面介紹BIMFACE圖紙對比功能的原理與實(shí)現(xiàn)。

圖紙對比可以對兩個圖紙文件進(jìn)行差異性分析,確定兩個圖紙文件之間構(gòu)件的幾何和屬性差異,包括增加的圖元構(gòu)件、刪除的圖元和修改的圖元。

特別說明:圖紙對比是在BIMFACE云端進(jìn)行的,通常需要5~10分鐘。當(dāng)模型對比完成后,BIMFACE能通知對比結(jié)果。


前置條件



  • 您需要將修改前和修改后的圖紙上傳到云端并轉(zhuǎn)換成功以后才能發(fā)起圖紙對比;
  • 目前支持.dwg、.dwf單文件的圖紙對比。


基本步驟



  1. 通過服務(wù)端API發(fā)起圖紙對比(對比前后模型文件的fileId);
  2. 等待云端對比任務(wù)執(zhí)行;
  3. 對比完成后,在網(wǎng)頁端通過調(diào)用JavaScript API實(shí)現(xiàn)差異圖紙的顯示;
  4. 除了顯示差異圖紙,還需要調(diào)用服務(wù)端API獲取對比結(jié)果(包括新增、刪除、修改的圖元列表)。


對比流程


  圖紙文件經(jīng)過云端轉(zhuǎn)換后,生成了BIMFACE定義的數(shù)據(jù)包。因此,要對比兩個圖紙文件,實(shí)際上需要對比兩個文件的數(shù)據(jù)包。如下圖所示,文件B是文件A修改后的版本,對比完成之后,其結(jié)果包括兩個部分:


  • 幾何差異;
  • 變更構(gòu)件及屬性。

?C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_json_02

BIMFACE提供了服務(wù)端API,用于發(fā)起對比,獲取對比狀態(tài)、獲取對比結(jié)果。請參考我的博客:


??C#開發(fā)BIMFACE系列30 服務(wù)端API之模型對比1:發(fā)起模型對比??


??C#開發(fā)BIMFACE系列31 服務(wù)端API之模型對比2:獲取模型對比狀態(tài)??


??C#開發(fā)BIMFACE系列32 服務(wù)端API之模型對比3:批量獲取模型對比狀態(tài)??


??C#開發(fā)BIMFACE系列33 服務(wù)端API之模型對比4:獲取模型對比結(jié)果??


??C#開發(fā)BIMFACE系列34 服務(wù)端API之模型對比5:獲取模型構(gòu)建對比差異??


測試程序


C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_json_03

發(fā)起圖紙對比

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_BIM  BIMFACE_04

調(diào)用服務(wù)器端的API獲取對比結(jié)果

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_服務(wù)端_05

對比差異分為三類:新增、修改、刪除。由于CAD圖紙的展示類型包含 Model 與 Layer 兩種形式,

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_BIM  BIMFACE_06

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_BIM  BIMFACE_07

差異結(jié)果中也是包含兩種展示類型的對比信息,所以可能有重復(fù)的圖元ID,需要手動過濾。

返回結(jié)果對應(yīng)的實(shí)體類如下



1 /// <summary>
2 /// 模型對比差異類
3 /// </summary>
4 public class ModelCompareDiff
5 {
6 /// <summary>
7 /// 對比差異構(gòu)件所屬類別ID。樣例 : "-2001320"
8 /// </summary>
9 [JsonProperty("categoryId", NullValueHandling = NullValueHandling.Ignore)]
10 public string CategoryId { get; set; }
11
12 /// <summary>
13 /// 對比差異構(gòu)件所屬類別名稱。樣例 : "framework"
14 /// </summary>
15 [JsonProperty("categoryName", NullValueHandling = NullValueHandling.Ignore)]
16 public string CategoryName { get; set; }
17
18 /// <summary>
19 /// 對比構(gòu)件差異類型:NEW、DELETE、CHANGE
20 /// </summary>
21 [JsonProperty("diffType", NullValueHandling = NullValueHandling.Ignore)]
22 public string DiffType { get; set; }
23
24 /// <summary>
25 /// 對比差異構(gòu)件ID。樣例 : "296524"
26 /// </summary>
27 [JsonProperty("elementId", NullValueHandling = NullValueHandling.Ignore)]
28 public string ElementId { get; set; }
29
30 /// <summary>
31 /// 對比差異構(gòu)件名稱
32 /// </summary>
33 [JsonProperty("elementName", NullValueHandling = NullValueHandling.Ignore)]
34 public string ElementName { get; set; }
35
36 /// <summary>
37 /// 對比差異構(gòu)件的族名稱。樣例 : "framework 1"
38 /// </summary>
39 [JsonProperty("family", NullValueHandling = NullValueHandling.Ignore)]
40 public string Family { get; set; }
41
42 /// <summary>
43 /// 對比差異構(gòu)件來源構(gòu)件ID。樣例 : "0213154515478"
44 /// </summary>
45 [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
46 public string Id { get; set; }
47
48 /// <summary>
49 /// 對比差異構(gòu)件變更文件ID,即(當(dāng)前)變更后的文件ID。樣例 : "1136893002033344"
50 /// </summary>
51 [JsonProperty("followingFileId", NullValueHandling = NullValueHandling.Ignore)]
52 public string FollowingFileId { get; set; }
53
54 /// <summary>
55 /// 對比差異構(gòu)件來源文件ID,即 (歷史)變更前的文件ID。樣例 : "0213154515478"
56 /// </summary>
57 [JsonProperty("previousFileId", NullValueHandling = NullValueHandling.Ignore)]
58 public string PreviousFileId { get; set; }
59
60 /// <summary>
61 /// 對比差異構(gòu)件所屬專業(yè)。樣例 : "civil"
62 /// </summary>
63 [JsonProperty("specialty", NullValueHandling = NullValueHandling.Ignore)]
64 public string Specialty { get; set; }
65 }


對比結(jié)果如下



1 {
2 "code": "success",
3 "message": null,
4 "data": {
5 "data": [{
6 "diffType": "NEW",
7 "id": "1946876",
8 "layer": "D1",
9 "sheetId": "0",
10 "sheetName": "Model",
11 "type": "Model"
12 }, {
13 "diffType": "NEW",
14 "id": "1946877",
15 "layer": "D1",
16 "sheetId": "0",
17 "sheetName": "Model",
18 "type": "Model"
19 }, {
20 "diffType": "NEW",
21 "id": "1946878",
22 "layer": "D1",
23 "sheetId": "0",
24 "sheetName": "Model",
25 "type": "Model"
26 }, {
27 "diffType": "CHANGE",
28 "id": "40539",
29 "layer": "0",
30 "sheetId": "0",
31 "sheetName": "Model",
32 "type": "Model"
33 }, {
34 "diffType": "CHANGE",
35 "id": "40541",
36 "layer": "0",
37 "sheetId": "0",
38 "sheetName": "Model",
39 "type": "Model"
40 }, {
41 "diffType": "CHANGE",
42 "id": "40542",
43 "layer": "0",
44 "sheetId": "0",
45 "sheetName": "Model",
46 "type": "Model"
47 }, {
48 "diffType": "CHANGE",
49 "id": "22243",
50 "layer": "AXIS",
51 "sheetId": "0",
52 "sheetName": "Model",
53 "type": "Model"
54 }
55 ],
56 "page": 1,
57 "total": 7
58 }
59 }


網(wǎng)頁中使用JS來實(shí)現(xiàn)圖紙展示與差異對比效果,以及點(diǎn)擊異動圖元后自動定位到構(gòu)件所在的視角。官網(wǎng)示例請參考?https://bimface.com/developer-jsdemo#988

官網(wǎng)的對比展示效果是將2張圖紙進(jìn)行疊加對比顯示的,下面介紹另一種對比展示方式,2張圖紙分別展示,左側(cè)展示當(dāng)前版本圖紙,右側(cè)展示歷史版本圖紙。

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_c#開發(fā)_08

點(diǎn)擊新增圖元項(xiàng),自動定位(綠色標(biāo)記)

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_服務(wù)端_09

點(diǎn)擊修改圖元項(xiàng),自動定位(黃色標(biāo)記)

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_c#開發(fā)_10

點(diǎn)擊刪除圖元項(xiàng),自動定位(紅色標(biāo)記)

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_c#開發(fā)_11

?

布局如下



<body>
<div class="nav"><a class="lg"><b>xxxx圖紙.dwg</b></a></div>
<div id="container">
<div class='latest'>
<!--<div class='title'>
<span>當(dāng)前輪次(<b>當(dāng)前版本</b>)</span>
</div>-->
</div>

<div class='prev'>
<!--<div class='title'>
<span>上一輪次(<b>歷史版本</b>)</span>
</div>-->
</div>

<div class="list">
<h3>差異列表(<span>0</span>)</h3>
<div class="detail">
<ul class="bf-collapse add">
<span class="bf-icon"></span>
<span>新增圖元(<b>0</b>)</span>
<div class="items"></div>
</ul>

<ul class="bf-collapse edit">
<span class="bf-icon"></span>
<span>修改圖元(<b>0</b>)</span>
<div class="items"></div>
</ul>

<ul class="bf-collapse deletes">
<span class="bf-icon"></span>
<span>刪除圖元(<b>0</b>)</span>
<div class="items"></div>
</ul>
</div>
</div>
</div>
</body>


腳本實(shí)現(xiàn)圖紙加載展示



1  $(document).ready(function () {
2 document.querySelector('.nav .lg b').innerHTML = sclc_desc + "【" + tzFileName1 + "】" + " 對比 【" + tzFileName2 + "】";
3
4 var success = getViewTokens(compareId);
5 if (!success) {
6 return;
7 }
8
9 prev = previousFileViewToken;
10 latest = followingFileViewToken;
11 compare = compareViewToken;
12
13 var bimfaceLoaderConfig = new BimfaceSDKLoaderConfig();
14 bimfaceLoaderConfig.viewToken = latest;
15 BimfaceSDKLoader.load(bimfaceLoaderConfig, onSDKLoadSucceeded, onSDKLoadFailed);
16 });
17
18 function onSDKLoadSucceeded(viewMetaData) {
19 if (viewMetaData.viewType == "drawingView") {
20 // 加載修改后圖紙
21 var webAppConfig = new Glodon.Bimface.Application.WebApplicationDrawingConfig();
22 webAppConfig.domElement = document.querySelector('.latest');
23 latest = new Glodon.Bimface.Application.WebApplicationDrawing(webAppConfig);
24 latest.load(viewMetaData.viewToken);
25
26 // 加載修改前圖紙
27 latest.getViewer().getViewMetaData(prev,
28 function (viewMetaData) {
29 var webAppConfig = new Glodon.Bimface.Application.WebApplicationDrawingConfig();
30 webAppConfig.domElement = document.querySelector('.prev');
31 prev = new Glodon.Bimface.Viewer.ViewerDrawing(webAppConfig);
32 prev.load(viewMetaData.viewToken);
33 prev.addEventListener('Loaded', correspond);
34 });
35
36 $.ajax({
37 url: "Handlers/GetBIMCompareResultFromDBHandler.ashx",
38 data: { compareId: compareId, modelType: '2D' },
39 dataType: "json",
40 type: "GET",
41 async: false, //同步。函數(shù)有返回值,必修設(shè)置為同步執(zhí)行
42 success: function (data) {
43 if (data.code == true) {
44 var add = '', edit = '', deletes = '';
45 if (data.news) {
46 data.news.map((item, i) => {
47 add += `<li class='add-item'>${item.elementId}</li>`;
48 });
49 document.querySelector('.add .items').innerHTML = add;
50 document.querySelector('.add b').innerHTML = data.news.length;
51 }
52 if (data.changes) {
53 data.changes.map((item, i) => {
54 edit += `<li class='modify-item'>${item.elementId}</li>`;
55 });
56 document.querySelector('.edit .items').innerHTML = edit;
57 document.querySelector('.edit b').innerHTML = data.changes.length;
58 }
59 if (data.deletes) {
60 data.deletes.map((item, i) => {
61 deletes += `<li class='delete-item'>${item.elementId}</li>`;
62 });
63 document.querySelector('.deletes .items').innerHTML = deletes;
64 document.querySelector('.deletes b').innerHTML = data.deletes.length;
65 }
66 document.querySelector('.list h3 span').innerHTML =
67 (data.deletes ? data.deletes.length * 1 : 0) +
68 (data.changes ? data.changes.length * 1 : 0) +
69 (data.news ? data.news.length * 1 : 0);
70 } else {
71 $.messager.alert('提示', data.message, 'warning');
72 }
73 },
74 error: function (e) {
75 $.messager.alert('提示', e, 'error');
76 }
77 });
78 } else {
79 $.messager.alert('提示', '對比的文件不是二維圖紙。', 'warning');
80 }
81 };
82
83 function onSDKLoadFailed(error) {
84 alert("圖紙加載失敗。");
85 };


腳本實(shí)現(xiàn)差異項(xiàng)點(diǎn)擊事件



1 // 同步新舊圖紙的平移和旋轉(zhuǎn)操作
2 function correspond() {
3 prevViewer = prev.getViewer();
4 latestViewer = latest.getViewer();
5 var state;
6 bindEvent();
7 (latestViewer.getViewer()).onViewChanges = function () {
8 if (latestViewer.getCurrentState() == state) {
9 return;
10 }
11 state = latestViewer.getCurrentState();
12 prev.setState(state);
13 }
14
15 setTimeout(function () {
16 prevViewer.onViewChanges = function () {
17 if (prev.getCurrentState() == state) {
18 return;
19 }
20 state = prev.getCurrentState();
21 latestViewer.getViewer().setState(state);
22 }
23 },
24 10);
25
26 // 同步新舊圖紙的HOVER事件和CLICK事件
27 //let ViewerEvent = Glodon.Bimface.Viewer.ViewerDrawingEvent;
28 var ViewerEvent = Glodon.Bimface.Viewer.ViewerDrawingEvent;
29
30 latestViewer.addEventListener(ViewerEvent.ComponentsSelectionChanged,
31 function (data) {
32 prev.clearSelection();
33 prev.selectByIds(data);
34 });
35
36 prev.addEventListener(ViewerEvent.ComponentsSelectionChanged,
37 function (data) {
38 latestViewer.getViewer().clearSelection();
39 latestViewer.selectByIds(data);
40 });
41
42 latestViewer.addEventListener(ViewerEvent.Hover,
43 function (data) {
44 prev.clearHighlight();
45 data.objectId && prev.highlightById(data.objectId);
46 console.log(data.objectId);
47 });
48
49 prev.addEventListener(ViewerEvent.Hover,
50 function (data) {
51 latestViewer.getViewer().clearHighlight();
52 data.objectId && latestViewer.getViewer().highlightById(data.objectId);
53 });
54 }
55
56 function bindEvent() {
57 var red = new Glodon.Web.Graphics.Color("#FF0000", 0.8);
58 var yellow = new Glodon.Web.Graphics.Color("#FFF68F", 0.8);
59 var blue = new Glodon.Web.Graphics.Color("#32CD99", 0.8);
60 // 設(shè)置差異列表的交互
61 // 獲取文檔中 class="detail" 的第一個元素: 差異列表內(nèi)容的div
62 var dom = document.querySelector('.detail');
63
64 // 差異列表的點(diǎn)擊事件
65 // e 為MouseEvent事件,其target為點(diǎn)擊到的html元素
66 dom.addEventListener('click',
67 function (e) {
68 console.log(e);
69 var target = e.target;
70 tagName = target.tagName;
71 // 通過點(diǎn)擊對象的種類,決定交互
72 if (tagName == 'SPAN') {
73 // 如果是span,則展開/收起列表
74 target.parentElement.toggleClass('bf-collapse');
75 } else if (tagName == 'LI') {
76 // 如果是li,則繪制矩形框
77 // 獲取點(diǎn)擊的數(shù)值,對應(yīng)圖元的id
78 var id = target.innerText;
79
80 // 清除上一步的選中效果和boundingBox
81 latest.getViewer().clearSelection();
82 latest.getViewer().clearElementBox();
83 prev.clearElementBox();
84 prev.clearSelection();
85
86 switch (target.className) {
87 // 新增圖元
88 case "add-item":
89 // 設(shè)置矩形框的樣式-藍(lán)色&云線
90 prev.setElementBoxColor(blue);
91 prev.setElementBoxStyle("CloudRect");
92 latest.getViewer().setElementBoxColor(blue);
93 latest.getViewer().setElementBoxStyle("CloudRect");
94
95 // 定位
96 latest.getViewer().zoomToObject(id);
97
98 // 繪制矩形框
99 var BBox = latest.getViewer().getObjectBoundingBox(parseInt(id));
100 prev.showElementBoxByBBox(BBox, 1);
101 console.log(BBox);
102 latest.getViewer().showElementBoxByBBox(BBox, 1);
103 break;
104
105 // 被修改圖元
106 case "modify-item":
107 // 設(shè)置矩形框的樣式-黃色&云線
108 prev.setElementBoxColor(yellow);
109 prev.setElementBoxStyle("CloudRect");
110 latest.getViewer().setElementBoxColor(yellow);
111 latest.getViewer().setElementBoxStyle("CloudRect");
112
113 // 定位
114 prev.zoomToObject(id);
115
116 // 繪制矩形框
117 var BBox = prev.getViewer().getObjectBoundingBox(parseInt(id));
118 prev.showElementBoxByBBox(BBox, 1);
119 latest.getViewer().showElementBoxByBBox(BBox, 1);
120 break;
121
122 // 被刪除圖元
123 case "delete-item":
124 // 設(shè)置矩形框的樣式-紅色&云線
125 prev.setElementBoxColor(red);
126 prev.setElementBoxStyle("CloudRect");
127 latest.getViewer().setElementBoxColor(red);
128 latest.getViewer().setElementBoxStyle("CloudRect");
129
130 // 定位
131 prev.zoomToObject(id);
132
133 // 繪制矩形框
134 var BBox = prev.getViewer().getObjectBoundingBox(parseInt(id));
135 prev.showElementBoxByBBox(BBox, 1);
136 latest.getViewer().showElementBoxByBBox(BBox, 1);
137 }
138 }
139 });
140
141 // 設(shè)置layout切換同步
142 var layout = document.querySelector('.bf-family .bf-sub-toolbar');
143 layout.addEventListener('click',
144 function (e) {
145 var target = e.target, tagName = target.tagName, name, views;
146 if (tagName == 'SPAN') {
147 name = target.innerText;
148 } else if (tagName == 'DIV') {
149 name = target.getAttribute('title');
150 }
151 views = prev.getViews();
152 views.map((item, i) => {
153 if (item.name == name) {
154 prev.showViewById(item.id);
155 }
156 });
157 });
158
159 // 顯示效果同步
160 var state = { showLineWidth: true, mode: '普通模式', layout: 'model' }
161 setInterval(() => {
162 var lineWidth = latest.getViewer().getViewer().viewer.ShowLineWidth;
163 var container = document.querySelectorAll('.bf-drawing-container ');
164 if (lineWidth != state.showLineWidth) {
165 state.showLineWidth = !state.showLineWidth;
166 prev.showLineWidth(state.showLineWidth);
167 }
168 if (document.querySelector('input[mode=普通模式]') &&
169 document.querySelector('input[mode=普通模式]').checked &&
170 (state.mode != '普通模式')) {
171 state.mode = '普通模式';
172
173 prev.setPrintMode('Normal');
174 container[1].style.background = 'rgb(50,50,55)';
175
176 } else if (document.querySelector('input[mode=白底模式]') &&
177 document.querySelector('input[mode=白底模式]').checked &&
178 (state.mode != '白底模式')) {
179 state.mode = '白底模式';
180 prev.setPrintMode('White');
181 container[1].style.background = 'rgb(255,255,255)';
182 } else if (document.querySelector('input[mode=黑白模式]') &&
183 document.querySelector('input[mode=黑白模式]').checked &&
184 (state.mode != '黑白模式')) {
185 state.mode = '黑白模式';
186 prev.setPrintMode('Black');
187 container[1].style.background = 'rgb(255,255,255)';
188 }
189 },
190 1000);
191
192 // 圖層列表顯示同步
193 var watch = function () {
194 var layers = document.querySelector('.layers-panel');
195 if (layers) {
196 layers.addEventListener('click',
197 function (e) {
198 var data = latest.getViewer().getViewer().getLayers(),
199 obj = {},
200 arr = [],
201 prevState = prev.getLayers();
202 data.map(function (item, index) {
203 obj[item.id] = item;
204 });
205 prevState.map(function (item, index) {
206 if (obj[item.id]) {
207 arr.push(obj[item.id]);
208 } else {
209 arr.push(item);
210 }
211 });
212 prev.getViewer().changeLayers(arr);
213 prev.getViewer().update();
214 });
215 } else {
216 setTimeout(watch, 1000);
217 }
218 }
219 watch();
220 }


問題思考 ???


官方提供的示例中,對比的2個.dwg文件中,每個文件中僅包含一張圖紙,即一個圖框。在常規(guī)業(yè)務(wù)場景下,一個.dwg文件中包含多個圖框,如下圖

C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_json_12

當(dāng)前版本與歷史版本對比完成后,通過上述測試程序,在Web網(wǎng)頁中點(diǎn)擊差異項(xiàng)可以自動定位到圖元變化所在位置。是否可以知道差異項(xiàng)來自哪個圖框呢?

答案是肯定的,實(shí)現(xiàn)方案參考下面兩篇博客《C#開發(fā)BIMFACE系列43 服務(wù)端API之圖紙拆分》、《C#開發(fā)BIMFACE系列44 服務(wù)端API之計(jì)算圖紙對比差異項(xiàng)來源自哪個圖框》。

?

上述測試程序使用了 《BIMFace.SDK.CSharp》開源SDK。歡迎大家下載使用。

?


BIMFACE二次開發(fā)系列目錄???? ?【已更新最新開發(fā)文章,點(diǎn)擊查看詳細(xì)】



?


?C#開發(fā)BIMFACE系列42 服務(wù)端API之圖紙對比_html_13技術(shù)棧

? ?

?1、Visual Studio、.C#/.NET、.NET Core、MVC、Web API、RESTful API、gRPC、SignalR、Python

?2、jQuery、Vue.js、Bootstrap

?3、數(shù)據(jù)庫:SQLServer、MySQL、PostgreSQL、Oracle、SQLite、Redis、MongoDB、ElasticSearch、TiDB、達(dá)夢DM、人大金倉、 神通、南大通用 GBase、華為 GaussDB 、騰訊 TDSQL 、阿里 PolarDB、螞蟻金服 OceanBase、東軟 OpenBASE、浪潮云溪數(shù)據(jù)庫 ZNBase

?4、ORM:Dapper、Entity Framework、FreeSql、SqlSugar、分庫分表、讀寫分離

?5、架構(gòu):領(lǐng)域驅(qū)動設(shè)計(jì) DDD、ABP

?6、環(huán)境:跨平臺、Windows、Linux(CentOS、麒麟、統(tǒng)信UOS、深度Linux)、maxOS、IIS、Nginx、Apach

?7、移動App:Android、IOS、HarmonyOS、微信、小程序、快應(yīng)用、Xamarin、uni-app、MUI、Flutter、Framework7、Cordova、Ionic、React Native、Taro、NutUI、Smobiler

? ?

?云原生、微服務(wù)、Docker、CI/CD、DevOps、K8S;

?Dapr、RabbitMQ、Kafka、分布式、大數(shù)據(jù)、高并發(fā)、負(fù)載均衡、中間件、RPC、ELK;

?.NET + Docker + jenkins + Github + Harbor + K8S;


?

作者:張傳寧 ??微軟MCP、系統(tǒng)架構(gòu)設(shè)計(jì)師、系統(tǒng)集成項(xiàng)目管理工程師、科技部創(chuàng)新工程師。

??????????專注于微軟.NET技術(shù)(.NET Core、Web、MVC、WinForm、WPF)、通用權(quán)限管理系統(tǒng)、工作流引擎、自動化項(xiàng)目(代碼)生成器、SOA 、DDD、 云原生(Docker、微服務(wù)、DevOps、CI/CD);PDF、CAD、BIM 審圖等研究與應(yīng)用。

??????????多次參與電子政務(wù)、圖書教育、生產(chǎn)制造等企業(yè)級大型項(xiàng)目研發(fā)與管理工作。

??????????熟悉中小企業(yè)軟件開發(fā)過程:需求分析、架構(gòu)設(shè)計(jì)、編碼測試、實(shí)施部署、項(xiàng)目管理。通過技術(shù)與管理幫助中小企業(yè)快速化實(shí)現(xiàn)互聯(lián)網(wǎng)技術(shù)全流程解決方案。

?????????



? ?

本文摘自 :https://blog.51cto.com/u

開通會員,享受整站包年服務(wù)立即開通 >