.net mvc 站点自带简易SSL加密传输

 

因项目需要,传输数据需要加密,因此有了一些经验,现简易抽出来分享!

 

请求:
前端cryptojs用rsa/aes 或 rsa/des加密,后端.net 解密
返回
后端.net用rsa/aes 或 rsa/des加密,前端cryptojs解密

 

图示:

数据发送加密:

返回数据加密:

开源代码分享:https://github.com/guandy/NetSSL 

现只是简易抽出,如果后续需求量大可考虑做成组件

 

 

 

 

 

Word报告自动生成(例如 导出数据库结构)

 

        将很早之前写的一个小组件重新整理优化一下,做成一个通用的功能。适用于导出数据库的结构(表、字段等)到Word或将体检数据自动生成Word版的体检报告等。代码:Github

一、主要需要完成功能:

1. 灵活的配置规则及word样式设置(文本、表格、图表、颜色等).

2. 支持表格.

3. 支持图表.

4. 支持章节内容循环生成.

5. 支持目录.

6.支持文档结构图

7.更新指定位置的文字

8.支持pdf导出.

 

最后结果如下:

                                                                            图一

                                    图二

                                         图三

二、需求分析与实现方式

   功能主要涉及3个比较重要的部分:数据源、Word样式、配置规则。 

     为了简单,数据源决定采用一个存储过程返回Dataset的方式, 整张报告的数据来源于此Dataset的多个Datatable.

  样式与配置:首先想到的是写一个config文件,所有配置都放到一个文件里,然后将数据按照这个规则生成word。但无疑这样的配置项太多了,关键是“样式”问题,比如字体、颜色、表格宽度.....想想就头大。而且没有“所见即所得”的效果,配置完都不知道啥样。

后来决定采取修改的方式, 先以一个word文件作为模板,在模板中定义好上面提到的“样式”,然后在模板中做一个个标记,然后将数据按照规则更新到对应的标记。

                                                       图四

    而这个标记我们用到了word的一个叫【书签】的功能,打开word按ctrl+shift+F5, 打开书签功能,如下图:

                                 图五

这样将【规则】通过一系列规则的【书签】定义到word模板中。

三、规则配置

  思路确定了,那就开始设计如何通过【书签】将规则定义到word模板中去,这里决定将所有规则都通过【书签】实现,而放弃config文件的方式,这个更统一而且直观一些。

A.循环

      以图四为例,数据库有多少张表是不固定的,我们在制作模板的时候不可能先画好N(N为表的总数)个表格等待数据填充, 这里就会需要遍历数据源中提供的所有表结构数据,然后逐一形成表格。这里就需要将图四中的表格循环一下,自动复制生成多个这样的表格。当然,这只是一种情况,还有可能会出现循环嵌套循环的情况,那么我将这个循环定义成一个书签的时候按照这样的格式:

      loop_级别_表序号_filter_名称

含义如下:

     loop:代表这是一个循环。

     级别:默认文档级别为0,出现的第一层循环为1,其内部若再次嵌套循环则级别为2,依次类推。

     表序号:取Dataset中的第几张表(从1开始)

     filter:循环的时候可能会用到对datatable的查找过滤,在此写出,多个字段用XX隔开(因为此处不允许有下划线外其他特殊字符, 就用这个XX吧 )

     名称:loop名称,方便与其他 loop区别

 B.更新指定位置的文字

    如图四中的【服务器名】、【表总数】等,只需要替换对应的文字即可:

    label_级别_名称

含义如下:

     label:代表这是一个label。

     级别:默认文档级别为0,出现的第一层循环为1,其内部若再次嵌套循环则级别为2,依次类推。

     名称:label名称

     注意这里省略了表序号,当级别为0的时候 ,自动取最后一个datatable中的数据,因为这个label经常会用到其他表汇总的数据,可能会用到之前几张表的数据,所以放在其他表都处理好后。当级别为1的时候,自然取该级别循环的行数据。

C.表格

     表格的配置原本也想对表格添加书签,后来发现有个表格属性, 觉得写在这里更好一些。

 如上图所示,【标题】格式为:table_级别_取Dataset中的第几张表(从1开始)_filter字段多个用XX隔开(此处不允许有下划线外其他特殊字符, 就用这个XX吧 )_名称

【说明】为可选项,若需要合计行, 则需要标识, summary或缩写s: [合计]行是模板中表格的第几行   summaryfilter或缩写sf:数据集进一步filter到summary行的条件(因为一个表格只取一个Datatable,通过一个标识指定了哪些datarow是用来作为合计的)

D.图表

同样为了方便将配置写在了【标题】,图表生成后会将名称修改过来。

配置格式为:chart_级别_取Dataset中的第几张表(从1开始)_filter字段多个用XX隔开(此处不允许有下划线外其他特殊字符, 就用这个XX吧 )_chart名称_是否将Datatable的columnName作为第一行_从datatable第几列开始(列起始为1)_截止列,

如下图所示配置即可。

 

E.目录

无需标识, 模板中添加目录, 当内容处理完成之后, 会根据处理后的结果动态更新目录.

 

四、主要代码

复制代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Data;
  4 using System.Diagnostics;
  5 using System.IO;
  6 using System.Linq;
  7 using System.Reflection;
  8 using Excel = Microsoft.Office.Interop.Excel;
  9 using Word = Microsoft.Office.Interop.Word;
 10 
 11 namespace FlyLolo.WordReport.Demo
 12 {
 13     public class WordReportHelper
 14     {
 15         private Word.Application wordApp = null;
 16         private Word.Document wordDoc = null;
 17         private DataSet dataSource = null;
 18         private object line = Word.WdUnits.wdLine;
 19         private string errorMsg = "";
 20 
 21         /// <summary>
 22         /// 根据模板文件,创建数据报告
 23         /// </summary>
 24         /// <param name="templateFile">模板文件名(含路径)</param>
 25         /// <param name="newFilePath">新文件路径)</param>
 26         /// <param name="dataSource">数据源,包含多个datatable</param>
 27         /// <param name="saveFormat">新文件格式:</param>
 28         public bool CreateReport(string templateFile, DataSet dataSource, out string errorMsg, string newFilePath, ref string newFileName, int saveFormat = 16)
 29         {
 30             this.dataSource = dataSource;
 31             errorMsg = this.errorMsg;
 32             bool rtn = OpenTemplate(templateFile)
 33                 && SetContent(new WordElement(wordDoc.Range(), dataRow: dataSource.Tables[dataSource.Tables.Count - 1].Rows[0]))
 34                 && UpdateTablesOfContents()
 35                 && SaveFile(newFilePath, ref newFileName, saveFormat);
 36 
 37             CloseAndClear();
 38             return rtn;
 39         }
 40 
 41         /// <summary>
 42         /// 打开模板文件
 43         /// </summary>
 44         /// <param name="templateFile"></param>
 45         /// <returns></returns>
 46         private bool OpenTemplate(string templateFile)
 47         {
 48             if (!File.Exists(templateFile))
 49             {
 50                 return false;
 51             }
 52 
 53             wordApp = new Word.Application();
 54             wordApp.Visible = true;//使文档可见,调试用
 55             wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
 56             object file = templateFile;
 57             wordDoc = wordApp.Documents.Open(ref file, ReadOnly: false);
 58             return true;
 59         }
 60 
 61         /// <summary>
 62         /// 为指定区域写入数据
 63         /// </summary>
 64         /// <param name="element"></param>
 65         /// <returns></returns>
 66         private bool SetContent(WordElement element)
 67         {
 68             string currBookMarkName = string.Empty;
 69             string startWith = "loop_" + (element.Level + 1).ToString() + "_";
 70             foreach (Word.Bookmark item in element.Range.Bookmarks)
 71             {
 72                 currBookMarkName = item.Name;
 73 
 74                 if (currBookMarkName.StartsWith(startWith) && (!currBookMarkName.Equals(element.ElementName)))
 75                 {
 76                     SetLoop(new WordElement(item.Range, currBookMarkName, element.DataRow, element.GroupBy));
 77                 }
 78 
 79             }
 80 
 81             SetLabel(element);
 82 
 83             SetTable(element);
 84 
 85             SetChart(element);
 86 
 87             return true;
 88         }
 89 
 90         /// <summary>
 91         /// 处理循环
 92         /// </summary>
 93         /// <param name="element"></param>
 94         /// <returns></returns>
 95         private bool SetLoop(WordElement element)
 96         {
 97             DataRow[] dataRows = dataSource.Tables[element.TableIndex].Select(element.GroupByString);
 98             int count = dataRows.Count();
 99             element.Range.Select();
100 
101             //第0行作为模板  先从1开始  循环后处理0行;
102             for (int i = 0; i < count; i++)
103             {
104 
105                 element.Range.Copy();  //模板loop复制
106                 wordApp.Selection.InsertParagraphAfter();//换行 不会清除选中的内容,TypeParagraph 等同于回车,若当前有选中内容会被清除. TypeParagraph 会跳到下一行,InsertParagraphAfter不会, 所以movedown一下.
107                 wordApp.Selection.MoveDown(ref line, Missing.Value, Missing.Value);
108                 wordApp.Selection.Paste(); //换行后粘贴复制内容
109                 int offset = wordApp.Selection.Range.End - element.Range.End; //计算偏移量
110 
111                 //复制书签,书签名 = 模板书签名 + 复制次数
112                 foreach (Word.Bookmark subBook in element.Range.Bookmarks)
113                 {
114                     if (subBook.Name.Equals(element.ElementName))
115                     {
116                         continue;
117                     }
118 
119                     wordApp.Selection.Bookmarks.Add(subBook.Name + "_" + i.ToString(), wordDoc.Range(subBook.Start + offset, subBook.End + offset));
120                 }
121 
122                 SetContent(new WordElement(wordDoc.Range(wordApp.Selection.Range.End - (element.Range.End - element.Range.Start), wordApp.Selection.Range.End), element.ElementName + "_" + i.ToString(), dataRows[i], element.GroupBy));
123             }
124 
125             element.Range.Delete();
126 
127             return true;
128         }
129 
130         /// <summary>
131         /// 处理简单Label
132         /// </summary>
133         /// <param name="element"></param>
134         /// <returns></returns>
135         private bool SetLabel(WordElement element)
136         {
137             if (element.Range.Bookmarks != null && element.Range.Bookmarks.Count > 0)
138             {
139                 string startWith = "label_" + element.Level.ToString() + "_";
140                 string bookMarkName = string.Empty;
141                 foreach (Word.Bookmark item in element.Range.Bookmarks)
142                 {
143                     bookMarkName = item.Name;
144 
145                     if (bookMarkName.StartsWith(startWith))
146                     {
147                         bookMarkName = WordElement.GetName(bookMarkName);
148 
149                         item.Range.Text = element.DataRow[bookMarkName].ToString();
150                     }
151                 }
152             }
153 
154             return true;
155         }
156 
157         /// <summary>
158         /// 填充Table
159         /// </summary>
160         /// <param name="element"></param>
161         /// <returns></returns>
162         private bool SetTable(WordElement element)
163         {
164             if (element.Range.Tables != null && element.Range.Tables.Count > 0)
165             {
166                 string startWith = "table_" + element.Level.ToString() + "_";
167                 foreach (Word.Table table in element.Range.Tables)
168                 {
169                     if (!string.IsNullOrEmpty(table.Title) && table.Title.StartsWith(startWith))
170                     {
171                         WordElement tableElement = new WordElement(null, table.Title, element.DataRow);
172 
173                         TableConfig config = new TableConfig(table.Descr);
174 
175                         object dataRowTemplate = table.Rows[config.DataRow];
176                         Word.Row SummaryRow = null;
177                         DataRow SummaryDataRow = null;
178                         DataTable dt = dataSource.Tables[tableElement.TableIndex];
179                         DataRow[] dataRows = dataSource.Tables[tableElement.TableIndex].Select(tableElement.GroupByString); ;
180 
181                         if (config.SummaryRow > 0)
182                         {
183                             SummaryRow = table.Rows[config.SummaryRow];
184                             SummaryDataRow = dt.Select(string.IsNullOrEmpty(tableElement.GroupByString) ? config.SummaryFilter : tableElement.GroupByString + " and  " + config.SummaryFilter).FirstOrDefault();
185                         }
186 
187                         foreach (DataRow row in dataRows)
188                         {
189                             if (row == SummaryDataRow)
190                             {
191                                 continue;
192                             }
193 
194                             Word.Row newRow = table.Rows.Add(ref dataRowTemplate);
195                             for (int j = 0; j < table.Columns.Count; j++)
196                             {
197                                 newRow.Cells[j + 1].Range.Text = row[j].ToString(); ;
198                             }
199 
200                         }
201 
202                         ((Word.Row)dataRowTemplate).Delete();
203 
204                         if (config.SummaryRow > 0 && SummaryDataRow != null)
205                         {
206                             for (int j = 0; j < SummaryRow.Cells.Count; j++)
207                             {
208                                 string temp = SummaryRow.Cells[j + 1].Range.Text.Trim().Replace("\r\a", "");
209 
210                                 if (!string.IsNullOrEmpty(temp) && temp.Length > 2 && dt.Columns.Contains(temp.Substring(1, temp.Length - 2)))
211                                 {
212                                     SummaryRow.Cells[j + 1].Range.Text = SummaryDataRow[temp.Substring(1, temp.Length - 2)].ToString();
213                                 }
214                             }
215                         }
216 
217                         table.Title = tableElement.Name;
218                     }
219 
220 
221                 }
222             }
223 
224             return true;
225         }
226 
227         /// <summary>
228         /// 处理图表
229         /// </summary>
230         /// <param name="element"></param>
231         /// <returns></returns>
232         private bool SetChart(WordElement element)
233         {
234             if (element.Range.InlineShapes != null && element.Range.InlineShapes.Count > 0)
235             {
236                 List<Word.InlineShape> chartList = element.Range.InlineShapes.Cast<Word.InlineShape>().Where(m => m.Type == Word.WdInlineShapeType.wdInlineShapeChart).ToList();
237                 string startWith = "chart_" + element.Level.ToString() + "_";
238                 foreach (Word.InlineShape item in chartList)
239                 {
240                     Word.Chart chart = item.Chart;
241                     if (!string.IsNullOrEmpty(chart.ChartTitle.Text) && chart.ChartTitle.Text.StartsWith(startWith))
242                     {
243                         WordElement chartElement = new WordElement(null, chart.ChartTitle.Text, element.DataRow);
244 
245                         DataTable dataTable = dataSource.Tables[chartElement.TableIndex];
246                         DataRow[] dataRows = dataTable.Select(chartElement.GroupByString);
247 
248                         int columnCount = dataTable.Columns.Count;
249                         List<int> columns = new List<int>();
250 
251                         foreach (var dr in dataRows)
252                         {
253                             for (int i = chartElement.ColumnStart == -1 ? 0 : chartElement.ColumnStart - 1; i < (chartElement.ColumnEnd == -1 ? columnCount : chartElement.ColumnEnd); i++)
254                             {
255                                 if (columns.Contains(i) || dr[i] == null || string.IsNullOrEmpty(dr[i].ToString()))
256                                 {
257 
258                                 }
259                                 else
260                                 {
261                                     columns.Add(i);
262                                 }
263                             }
264                         }
265                         columns.Sort();
266                         columnCount = columns.Count;
267                         int rowsCount = dataRows.Length;
268 
269                         Word.ChartData chartData = chart.ChartData;
270 
271                         //chartData.Activate();
272                         //此处有个比较疑惑的问题, 不执行此条,生成的报告中的图表无法再次右键编辑数据. 执行后可以, 但有两个问题就是第一会弹出Excel框, 处理完后会自动关闭. 第二部分chart的数据range设置总不对
273                         //不知道是不是版本的问题, 谁解决了分享一下,谢谢
274 
275                         Excel.Workbook dataWorkbook = (Excel.Workbook)chartData.Workbook;
276                         dataWorkbook.Application.Visible = false;
277 
278                         Excel.Worksheet dataSheet = (Excel.Worksheet)dataWorkbook.Worksheets[1];
279                         //设定范围  
280                         string a = (chartElement.ColumnNameForHead ? rowsCount + 1 : rowsCount) + "|" + columnCount;
281                         Console.WriteLine(a);
282 
283                         Excel.Range tRange = dataSheet.Range["A1", dataSheet.Cells[(chartElement.ColumnNameForHead ? rowsCount + 1 : rowsCount), columnCount]];
284                         Excel.ListObject tbl1 = dataSheet.ListObjects[1];
285                         //dataSheet.ListObjects[1].Delete(); //想过重新删除再添加  这样 原有数据清掉了, 但觉得性能应该会有所下降
286                         //Excel.ListObject tbl1 = dataSheet.ListObjects.AddEx();
287                         tbl1.Resize(tRange);
288                         for (int j = 0; j < rowsCount; j++)
289                         {
290                             DataRow row = dataRows[j];
291                             for (int k = 0; k < columnCount; k++)
292                             {
293                                 dataSheet.Cells[j + 2, k + 1].FormulaR1C1 = row[columns[k]];
294                             }
295                         }
296 
297                         if (chartElement.ColumnNameForHead)
298                         {
299                             for (int k = 0; k < columns.Count; k++)
300                             {
301                                 dataSheet.Cells[1, k + 1].FormulaR1C1 = dataTable.Columns[columns[k]].ColumnName;
302                             }
303                         }
304                         chart.ChartTitle.Text = chartElement.Name;
305                         //dataSheet.Application.Quit();
306                     }
307                 }
308             }
309 
310             return true;
311         }
312 
313         /// <summary>
314         /// 更新目录
315         /// </summary>
316         /// <returns></returns>
317         private bool UpdateTablesOfContents()
318         {
319             foreach (Word.TableOfContents item in wordDoc.TablesOfContents)
320             {
321                 item.Update();
322             }
323 
324             return true;
325         }
326 
327         /// <summary>
328         /// 保存文件
329         /// </summary>
330         /// <param name="newFilePath"></param>
331         /// <param name="newFileName"></param>
332         /// <param name="saveFormat"></param>
333         /// <returns></returns>
334         private bool SaveFile(string newFilePath, ref string newFileName, int saveFormat = 16)
335         {
336             if (string.IsNullOrEmpty(newFileName))
337             {
338                 newFileName = DateTime.Now.ToString("yyyyMMddHHmmss");
339 
340                 switch (saveFormat)
341                 {
342                     case 0:// Word.WdSaveFormat.wdFormatDocument
343                         newFileName += ".doc";
344                         break;
345                     case 16:// Word.WdSaveFormat.wdFormatDocumentDefault
346                         newFileName += ".docx";
347                         break;
348                     case 17:// Word.WdSaveFormat.wdFormatPDF
349                         newFileName += ".pdf";
350                         break;
351                     default:
352                         break;
353                 }
354             }
355 
356             object newfile = Path.Combine(newFilePath, newFileName);
357             object wdSaveFormat = saveFormat;
358             wordDoc.SaveAs(ref newfile, ref wdSaveFormat);
359             return true;
360         }
361 
362         /// <summary>
363         /// 清理
364         /// </summary>
365         private void CloseAndClear()
366         {
367             if (wordApp == null)
368             {
369                 return;
370             }
371             wordDoc.Close(Word.WdSaveOptions.wdDoNotSaveChanges);
372             wordApp.Quit(Word.WdSaveOptions.wdDoNotSaveChanges);
373             System.Runtime.InteropServices.Marshal.ReleaseComObject(wordDoc);
374             System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApp);
375             wordDoc = null;
376             wordApp = null;
377             GC.Collect();
378             KillProcess("Excel", "WINWORD");
379         }
380 
381         /// <summary>
382         /// 杀进程..
383         /// </summary>
384         /// <param name="processNames"></param>
385         private void KillProcess(params string[] processNames)
386         {
387             //Process myproc = new Process();
388             //得到所有打开的进程  
389             try
390             {
391                 foreach (string name in processNames)
392                 {
393                     foreach (Process thisproc in Process.GetProcessesByName(name))
394                     {
395                         if (!thisproc.CloseMainWindow())
396                         {
397                             if (thisproc != null)
398                                 thisproc.Kill();
399                         }
400                     }
401                 }
402             }
403             catch (Exception)
404             {
405                 //throw Exc;
406                 // msg.Text+=  "杀死"  +  processName  +  "失败!";  
407             }
408         }
409     }
410 
411     /// <summary>
412     /// 封装的Word元素
413     /// </summary>
414     public class WordElement
415     {
416         public WordElement(Word.Range range, string elementName = "", DataRow dataRow = null, Dictionary<string, string> groupBy = null, int tableIndex = 0)
417         {
418             this.Range = range;
419             this.ElementName = elementName;
420             this.GroupBy = groupBy;
421             this.DataRow = dataRow;
422             if (string.IsNullOrEmpty(elementName))
423             {
424                 this.Level = 0;
425                 this.TableIndex = tableIndex;
426                 this.Name = string.Empty;
427                 this.ColumnNameForHead = false;
428             }
429             else
430             {
431                 string[] element = elementName.Split('_');
432                 this.Level = int.Parse(element[1]);
433                 this.ColumnNameForHead = false;
434                 this.ColumnStart = -1;
435                 this.ColumnEnd = -1;
436 
437                 if (element[0].Equals("label"))
438                 {
439                     this.Name = element[2];
440                     this.TableIndex = 0;
441                 }
442                 else
443                 {
444                     this.Name = element[4];
445                     this.TableIndex = int.Parse(element[2]) - 1;
446 
447                     if (!string.IsNullOrEmpty(element[3]))
448                     {
449                         string[] filters = element[3].Split(new string[] { "XX" }, StringSplitOptions.RemoveEmptyEntries);
450                         if (this.GroupBy == null)
451                         {
452                             this.GroupBy = new Dictionary<string, string>();
453                         }
454                         foreach (string item in filters)
455                         {
456                             if (!this.GroupBy.Keys.Contains(item))
457                             {
458                                 this.GroupBy.Add(item, dataRow[item].ToString());
459                             }
460 
461                         }
462                     }
463 
464                     if (element[0].Equals("chart") && element.Count() > 5)
465                     {
466                         this.ColumnNameForHead = element[5].Equals("1");
467                         this.ColumnStart = string.IsNullOrEmpty(element[6]) ? -1 : int.Parse(element[6]);
468                         this.ColumnEnd = string.IsNullOrEmpty(element[7]) ? -1 : int.Parse(element[7]);
469                     }
470                 }
471             }
472         }
473 
474         public Word.Range Range { get; set; }
475         public int Level { get; set; }
476         public int TableIndex { get; set; }
477         public string ElementName { get; set; }
478 
479         public DataRow DataRow { get; set; }
480         public Dictionary<string, string> GroupBy { get; set; }
481 
482         public string Name { get; set; }
483 
484         public bool ColumnNameForHead { get; set; }
485         public int ColumnStart { get; set; }
486         public int ColumnEnd { get; set; }
487 
488         public string GroupByString
489         {
490             get
491             {
492                 if (GroupBy == null || GroupBy.Count == 0)
493                 {
494                     return string.Empty;
495                 }
496 
497                 string rtn = string.Empty;
498                 foreach (string key in this.GroupBy.Keys)
499                 {
500                     rtn += "and " + key + " = '" + GroupBy[key] + "' ";
501                 }
502                 return rtn.Substring(3);
503             }
504         }
505 
506         public static string GetName(string elementName)
507         {
508             string[] element = elementName.Split('_');
509 
510 
511             if (element[0].Equals("label"))
512             {
513                 return element[2];
514             }
515             else
516             {
517                 return element[4];
518             }
519         }
520     }
521 
522     /// <summary>
523     /// Table配置项
524     /// </summary>
525     public class TableConfig
526     {
527         public TableConfig(string tableDescr = "")
528         {
529             this.DataRow = 2;
530             this.SummaryRow = -1;
531 
532             if (!string.IsNullOrEmpty(tableDescr))
533             {
534                 string[] element = tableDescr.Split(',');
535                 foreach (string item in element)
536                 {
537                     if (!string.IsNullOrEmpty(item))
538                     {
539                         string[] configs = item.Split(':');
540                         if (configs.Length == 2)
541                         {
542                             switch (configs[0].ToLower())
543                             {
544                                 case "data":
545                                 case "d":
546                                     this.DataRow = int.Parse(configs[1]);
547                                     break;
548                                 case "summary":
549                                 case "s":
550                                     this.SummaryRow = int.Parse(configs[1]);
551                                     break;
552                                 case "summaryfilter":
553                                 case "sf":
554                                     this.SummaryFilter = configs[1];
555                                     break;
556                                 default:
557                                     break;
558                             }
559                         }
560                     }
561                 }
562             }
563 
564         }
565         public int DataRow { get; set; }
566         public int SummaryRow { get; set; }
567         public string SummaryFilter { get; set; }
568     }
569 }
复制代码

 

 

微信小程序:动画(Animation)

 

简单总结一下微信动画的实现及执行步骤。

一、实现方式

官方文档是这样说的:①创建一个动画实例 animation。②调用实例的方法来描述动画。③最后通过动画实例的 export 方法导出动画数据传递给组件的 animation 属性。

因为小程序是数据驱动的,给这句话加上数字标注分为三步:

前两步是定义一个动画并设置都要干什么,然后把这个设置好的“规则”扔给界面上的某个元素,让它按照这个规则执行。

当然如果有多个元素的animation="{{ani}}",也都会执行这个动画规则。

二、用例子说话

新建一个小程序,把没用的删掉修改一下,做个简单例子,上图

代码如下:

index.wxml,一个helloworld,一个按钮
复制代码
<view class="container">
  <view class="usermotto" animation="{{ani}}">
    <text class="user-motto">{{motto}}</text>
  </view>
  <button bindtap='start'>动画</button>
</view>
复制代码
index.wxss, 为了看着方便加了个边框
.usermotto {
  margin-top: 100px;
  border: solid;
}

index.js

复制代码
Page({
  data: {
    motto: 'Hello World',
  },
  start:function(){
    var animation = wx.createAnimation({
      duration: 4000,
      timingFunction: 'ease',
      delay: 1000
    });
    animation.opacity(0.2).translate(100, -100).step()
    this.setData({
      ani:  animation.export()
    })
  }
})
复制代码

 三、相关参数及方法

简单介绍一下例子中的几个参数和方法(其他的详见官方文档):

      duration: 动画持续多少毫秒
      timingFunction: “运动”的方式,例子中的 'ease'代表动画以低速开始,然后加快,在结束前变慢  
      delay: 多久后动画开始运行

      opacity(0.2) 慢慢变透明

      translate(100, -100) 向X轴移动100的同时向Y轴移动-100

      step(): 一组动画完成,例如想让上例中的HelloWorld向右上方移动并变透明后,再次向左移动50可以继续写 animation.translateX( -50).step() , 作用就是向右上方移动和变透明是同时进行, 这两种变化完成之后才会进行向左运行的一步。

 

例子:Github

 
 

SignalR 设计理念(一)

实现客户端和服务器端的实时通讯.
问题阐述
  1. 客户端提供的方法不确定!
  2. 客户端的方法参数不确定!
  3. 不同的名称和参数要分别调用指定的方法!
  4. 调用客户端方法时,不忽略大小写!

例如:

public void Send(string message) { Clients.All.Write(message); // Clients.All.write(message); 也可以。 }

针对以上问题,你会如何设计服务器架构?

SignalR 选用 dynamic 动态数据类型作为客户端通讯的基类。

问:

  1. 动态数据类型是如何解决客户端方法不确定的? 1
  2. 动态数据类型是如何解决客户端方法参数不确定的? 2
  3. 动态数据类型是如何区分要调用的客户端方法的? 3
举一反三:
  1. 为什么服务器端调用客户端要忽略大小写?

核心代码:

public class ClientProxy : DynamicObject
{
   [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Binder is passed in by the DLR")] public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { result = Invoke(binder.Name, args); return true; } /// <summary> /// 这里处理业务逻辑 /// </summary> /// <param name="method">方法名称</param> /// <param name="args">参数</param> /// <returns></returns> public Task Invoke(string method, params object[] args) { return Task.Factory.StartNew(() => { //这里处理业务逻辑。 }); } }
解析:

  1. 通过binder.Name 确定客户端方法名称。

  2. 通过args 确定客户端方法参数。

  3. 通过 [^1] 和 [^2] 两点确定客户端的指定方法。

  4.  

 
 
 
 
 

ASP.NET -- WebForm -- ViewState

ASP.NET -- WebForm --  ViewState

1. ViewState的作用

当 ASP .NET 中的表单被提交时,表单会随所有表单值一同重新出现。这是由于 ASP .NET 维持了您的 ViewState。

ViewState 会在页面被提交到服务器时指示其状态。通过在每张页面中的一个 <form runat="server"> 控件中放置一个隐藏域,我们就可以定义页面的状态了。

新建一个Test.aspx:

复制代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test"  %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>my Test Aspx</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </div>
    </form>
</body>
</html>
复制代码

 

在浏览器--开发者工具可看到ViewState隐藏域的存在:

 

 

2. ViewState的开启和关闭

维持 ViewState 是 ASP.NET Web 表单的默认设置。

如果您不希望维持 ViewState,请在 .aspx 页面的顶部包含指令: <%@ Page EnableViewState="false" %>,或为任意控件添加属性:EnableViewState="false"。

整个页面关闭ViewState:

单个控件关闭ViewState:

 

 

把EnableViewState="false",在浏览器--开发者工具,还是可以看见隐藏域__ViewState的。

如果想彻底去掉隐藏域__ViewState,必须将runat="server"去掉,换成action  (但是这样做,会导致工具箱的控件不能用), 如下图:

复制代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>my Test Aspx</title>
</head>
<body>
    <form action="Test.aspx" method="post">
    <div>
        <input type="text" name="txtName"/>
    </div>
    </form>
</body>
</html>
复制代码

浏览器开发者工具中可清楚看见,隐藏域__ViewState被去掉了

 

 

ASP.NET -- 一般处理程序ashx

ASP.NET  --   一般处理程序ashx

如果在一个html页面向服务器端请求数据,可用ashx作为后台页面处理数据。ashx适合用作数据后台处理,相当于WebForm中的aspx.cs文件或aspx.vb文件。

入门案例:html页面向ashx页面请求数据,ashx作为后台页面返回数据。

前端html页面:

复制代码
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>My Test ashx</title>
    <script type="text/javascript" src="./js/jquery-2.0.3.min.js" ></script>
    <script type="text/javascript" >
        $(function() {
            $("#btn_Test").click(function() {
                $.ajax({
                    type: "post",
                    url: "Test.ashx",
                    datatype: "text",
                    data: { "TestAction":"getBaiduUrl"},
                    success: function(data) {
                       $("#myDiv1").html(data);
                    }
                });
            });
        });
    </script>
</head>
<body>
    <button type="button" id="btn_Test">Test</button>
    <div id="myDiv1" style="width:300px;height:30px;padding: 10px;border:2px solid blue;">
    </div>   
</body>
</html>
复制代码

 

后台Test.ashx页面:

复制代码
<%@ WebHandler Language="C#" Class="Test" %>

using System;
using System.Web;

public class Test : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain";
        if (context.Request["TestAction"] == "getBaiduUrl")
        {
            context.Response.Write("百度的地址是: https://www.baidu.com");
        }
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }

}
复制代码

 

运行结果:

   

 

 

 

常用到的一些js方法,记录一下

 

  获取字符串长度

function GetStringLength(str) {
    return str.replace(/[^\x00-\xff]/g, "00").length;
}

 

  通过js对html转义和反转义

复制代码
function HTMLEncode(html) {
    var temp = document.createElement("div");
    (temp.textContent != null) ? (temp.textContent = html) : (temp.innerText = html);
    var output = temp.innerHTML;
    temp = null;
    return output;
}

function HTMLDecode(text) { 
    var temp = document.createElement("div"); 
    temp.innerHTML = text; 
    var output = temp.innerText || temp.textContent; 
    temp = null; 
    return output; 
} 
复制代码

 一些公用的js

复制代码
  1 var com = com || {};
  2 (function ($, com) {
  3     /**
  4     * 截取字符串
  5     * @param str:要截取的字符串
  6     * @param len:保留多少字符
  7     * @param symbol:超过之后字符串末端要添加的字符
  8     */
  9     com.cutStr = function (str, len, symbol) {
 10         str = str || "";
 11         if (symbol == null || symbol == undefined)
 12             symbol = "...";
 13 
 14         var count = 0;
 15         var strTemp = "";
 16         for (var i = 0; i < str.length; i++) {
 17             if (/[^\x00-\xff]/g.test(str.substr(i, 1))) {
 18                 count += 2;
 19             }
 20             else {
 21                 count += 1;
 22             }
 23             if (count <= len) {
 24                 strTemp += str.substr(i, 1);
 25             }
 26             else {
 27                 return strTemp + symbol;
 28             }
 29         }
 30         return str;
 31     },
 32     /*
 33     * 将日期字符串转化为Date
 34     * (如:将"2016-12-24 20:13:14"转化为Date格式)
 35     * @param d:待转化字符串(传入的时间不能有毫秒)
 36     */
 37     com.getDate = function (d) {
 38         //部分浏览器(IE)不支持日期格式“yyyy-MM-dd hh:mm:ss”,必须将“-”转化为“/”
 39         var date = new Date(Date.parse(d.replace(/-/g, "/")));
 40         return date;
 41     },
 42     /*
 43     * 获取html代码的纯文本
 44     * @param html
 45     */
 46     com.removeHTMLTag = function (html) {
 47         html = html.replace(/<\/?[^>]*>/g, ''); //去除HTML tag
 48         html = html.replace(/[ | ]*\n/g, '\n'); //去除行尾空白
 49         //html = html.replace(/\n[\s| | ]*\r/g,'\n'); //去除多余空行
 50         html = html.replace(/&nbsp;/ig, '');//去掉&nbsp;
 51         html = html.replace(/\s/g, ''); //将空格去掉
 52         return html;
 53     },
 54     /*
 55     * 获取地址栏参数
 56     * @param 参数名
 57     */
 58     com.getQueryString = function (name) {
 59         var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
 60         var r = window.location.search.substr(1).match(reg);
 61         if (r != null) return (r[2]); return null;
 62     },
 63 
 64     /**************************************************************
 65     *将金额转化为大写
 66     *   str:需要转化的金额
 67     ****************************************************************/
 68     com.convertMoney = function (n) {
 69         var fraction = ['角', '分', '毫', '厘'];
 70         var digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
 71         var unit = [['元', '万', '亿'], ['', '拾', '佰', '仟']];
 72         var cnInteger = "整"; //整数金额时后面跟的字符
 73         var cnIntLast = "元"; //整型完以后的单位
 74         var maxNum = 9999999999999.9999;
 75         var head = n < 0 ? '负' : '';
 76         //取绝对值
 77         n = Math.abs(n);
 78         if (n >= maxNum) {
 79             console.error("金额转化超出最大处理数字");
 80             return "";
 81         }
 82 
 83         var IntegerNum; //金额整数部分  
 84         var DecimalNum; //金额小数部分
 85         var money = n.toString();
 86         if (money.indexOf(".") == -1) {
 87             IntegerNum = money;
 88             DecimalNum = '';
 89         } else {
 90             var parts = money.split(".");
 91             IntegerNum = parts[0];
 92             DecimalNum = parts[1].substr(0, 4);
 93         }
 94 
 95         var ChineseStr = "";
 96 
 97         //小数部分
 98         if (DecimalNum != '') {
 99             for (i = 0; i < DecimalNum.length; i++) {
100                 var m = DecimalNum.substr(i, 1);
101                 if (m != '0') {
102                     ChineseStr += digit[Number(m)] + fraction[i];
103                 }
104             }
105         }
106 
107         IntegerNum = IntegerNum * 1;
108 
109         //整数部分
110         for (var i = 0; i < unit[0].length && IntegerNum > 0; i++) {
111             var p = '';
112             for (var j = 0; j < unit[1].length && IntegerNum > 0; j++) {
113                 p = digit[IntegerNum % 10] + unit[1][j] + p;
114                 IntegerNum = Math.floor(IntegerNum / 10);
115             }
116             ChineseStr = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + ChineseStr;
117         }
118 
119         if (ChineseStr == '') {
120             ChineseStr += digit[0] + cnIntLast + cnInteger;
121         } else if (DecimalNum == '') {
122             ChineseStr += cnInteger;
123         }
124         ChineseStr = head + ChineseStr;
125         return ChineseStr;
126     },
127 
128     /**
129     * 获取字符串长度(一个汉字占两个字符)
130     * @param str:字符串
131     */
132     com.getStringLength = function (str) {
133         return str.replace(/[^\x00-\xff]/g, "00").length;
134     }
135 
136 })(jQuery, com);
复制代码

 

 

CryptoJS与C#AES加解密互转

 

CryptoJS下载地址:

https://code.google.com/archive/p/crypto-js/downloads

http://download.csdn.net/detail/wz122889488/9851085

页面js引用:

    <script type="text/javascript" src="/content/plugin/CryptoJSv3.1.2/components/core-min.js"></script>
    <script type="text/javascript" src="/content/plugin/CryptoJSv3.1.2/rollups/aes.js"></script>

 

JS端AES加密解密:

复制代码
 1     com.str = {
 2         _KEY: "12345678900000001234567890000000",//32位
 3         _IV: "1234567890000000",//16位
 4         /**************************************************************
 5         *字符串加密
 6         *   str:需要加密的字符串
 7         ****************************************************************/
 8         Encrypt: function (str) {
 9             var key = CryptoJS.enc.Utf8.parse(this._KEY); 
10             var iv = CryptoJS.enc.Utf8.parse(this._IV);
11 
12             var encrypted = '';
13 
14             var srcs = CryptoJS.enc.Utf8.parse(str);
15             encrypted = CryptoJS.AES.encrypt(srcs, key, {
16                 iv: iv,
17                 mode: CryptoJS.mode.CBC,
18                 padding: CryptoJS.pad.Pkcs7
19             });
20 
21             return encrypted.ciphertext.toString();
22         },
23 
24         /**************************************************************
25         *字符串解密
26         *   str:需要解密的字符串
27         ****************************************************************/
28         Decrypt: function (str) {
29             var key = CryptoJS.enc.Utf8.parse(this._KEY);
30             var iv = CryptoJS.enc.Utf8.parse(this._IV);
31             var encryptedHexStr = CryptoJS.enc.Hex.parse(str);
32             var srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
33             var decrypt = CryptoJS.AES.decrypt(srcs, key, {
34                 iv: iv,
35                 mode: CryptoJS.mode.CBC,
36                 padding: CryptoJS.pad.Pkcs7
37             });
38             var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
39             return decryptedStr.toString();
40         }
41     }
复制代码

C# AES加密解密:

复制代码
const string AES_IV = "1234567890000000";//16位    

/// <summary> /// AES加密算法 /// </summary> /// <param name="input">明文字符串</param> /// <param name="key">密钥(32位)</param> /// <returns>字符串</returns> public static string EncryptByAES(string input, string key) { byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 32)); using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider()) { aesAlg.Key = keyBytes; aesAlg.IV = Encoding.UTF8.GetBytes(AES_IV.Substring(0, 16)); ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { swEncrypt.Write(input); } byte[] bytes = msEncrypt.ToArray(); return ByteArrayToHexString(bytes); } } } } /// <summary> /// AES解密 /// </summary> /// <param name="input">密文字节数组</param> /// <param name="key">密钥(32位)</param> /// <returns>返回解密后的字符串</returns> public static string DecryptByAES(string input, string key) { byte[] inputBytes = HexStringToByteArray(input); byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 32)); using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider()) { aesAlg.Key = keyBytes; aesAlg.IV = Encoding.UTF8.GetBytes(AES_IV.Substring(0, 16)); ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); using (MemoryStream msEncrypt = new MemoryStream(inputBytes)) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srEncrypt = new StreamReader(csEncrypt)) { return srEncrypt.ReadToEnd(); } } } } } /// <summary> /// 将指定的16进制字符串转换为byte数组 /// </summary> /// <param name="s">16进制字符串(如:“7F 2C 4A”或“7F2C4A”都可以)</param> /// <returns>16进制字符串对应的byte数组</returns> public static byte[] HexStringToByteArray(string s) { s = s.Replace(" ", ""); byte[] buffer = new byte[s.Length / 2]; for (int i = 0; i < s.Length; i += 2) buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16); return buffer; } /// <summary> /// 将一个byte数组转换成一个格式化的16进制字符串 /// </summary> /// <param name="data">byte数组</param> /// <returns>格式化的16进制字符串</returns> public static string ByteArrayToHexString(byte[] data) { StringBuilder sb = new StringBuilder(data.Length * 3); foreach (byte b in data) { //16进制数字 sb.Append(Convert.ToString(b, 16).PadLeft(2, '0')); //16进制数字之间以空格隔开 //sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' ')); } return sb.ToString().ToUpper(); }
复制代码

 

用法:

com.str.Encrypt("2017-05")//结果:68f4a7903a9fe6085d2301ac68cc039c
com.str.Decrypt("68f4a7903a9fe6085d2301ac68cc039c")//结果:2017-05
//加密
string str1 = Encrypt.EncryptByAES("2017-05", "12345678900000001234567890000000");
//解密
string str2 = Encrypt.DecryptByAES("68f4a7903a9fe6085d2301ac68cc039c", "12345678900000001234567890000000");

 注:前后台的加密Key必须一致。

转载于:https://www.cnblogs.com/cjm123/p/9970193.html

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐