马上过牛年了,先祝大家新年好,身体好,心情好!!!

年前最后写一篇之前项目开发的一个功能,自己根据系统业务,想到的一个解决办法,效率还是不错的,废话不多说,开整!!!

需求:企业填报自己的企业信息到系统中,最后需要将数据以给定word模板形式导出,功能简单,就是要开发快,赶及

分析:主要费时间的工作是设计企业填报表单设计实现,以及根据提供的word模板导出数据这块儿,因为涉及到的表单比较多,一个表单最少也有差不多150多个字段,一个一个对,头发也得一把一把的掉

想到的解决法案:在导出word这个功能模块儿,写一些通用的方法,减少一些工作量。

        word数据导出功能,思路就是在word模板中每一个需要填数据的地方命名一个标签,代码中找到对应命名的标签,插入数值

传统做法,第一步:在word模板中填写标签  第二步:程序中每个插入字段数据和word模板标签对应,最后插值,这样做有一个问题就是比较耗时间,而且很容易出错

        我的做法,第一步:给数据字段一个自定义特性,在自定定义特性中写上对应的标签地址,应用反射的方法将数据最终插入到word模板中。这样就省去了第一步在word中写标签这样繁杂的操作。这样做的问题就是性能比较差,但是可以忽略不计

大体思路就这样,我就单独写一个demo供大家参考,之后能用就用,重在思路和想法的分享和讨论

开写:

新建一个项目:ExportWordModel

最终项目简易结构:

将没用的东西全部去掉,修改Index.cshtml页面成这样:

  1. 1 @{
  2. 2 ViewBag.Title = "Home Page";
  3. 3 }
  4. 4 <div class="jumbotron" style="text-align: center">
  5. 5 @*<h1>ASP.NET</h1>*@
  6. 6 <input type="button" value="导出" onclick="location.href = '@Url.Action("GetExport","Home")'" />
  7. 7 </div>

在 HomeController 中创建:GetExport

创建一个类ExportFileOperator(所有的word操作),此类需要继承Controller,因为有返回File操作方法

1、 在GetExport中首先命名一个导出word标题就叫:测试导出Word文件

  1. string title = "测试导出Word文件";

创建doc:

  1. var doc = ExportFileOperator.CreateBuilder("GroupForm.doc");
  1. 2CreateBuilder方法实现为(此处操作需要Aspose.Word组件,是操作word的,这个需要大家自己去找一下,或者网上找个破解的):
  1. 1 private static string _tempPath = AppDomain.CurrentDomain.BaseDirectory;
  2. 2 public static (Document doc, DocumentBuilder builder) CreateBuilder(string tempFileName)
  3. 3 {
  4. 4 string tempPath = $"{_tempPath}{tempFileName}";
  5. 5 Document doc = new Document(tempPath);
  6. 6 return (doc, new DocumentBuilder(doc));
  7. 7 }

3、插入标题(需要在word中写一个标签,作为标题插入的地址):

最终可以显示结果为这样:

方法:

ExportFileOperator.InsertTitle(ref doc.Item2, title);//插入标题

  1. public static void InsertTitle(ref DocumentBuilder builder, string fileName, string tempBookMarkName = "title")
  2. {
  3. builder.MoveToBookmark(tempBookMarkName);
  4. builder.Write(fileName);
  5. }

4、根据业务实体,将实体数据写入到word中,也是核心所在

首先命名一个数据类:

  1. public class EnterpriseEntity
  2. {
  3. #region 实体成员
  4. /// <summary>
  5. /// id
  6. /// </summary>
  7. public string id { get; set; }
  8. /// <summary>
  9. /// 团队名
  10. /// </summary>
  11. [Description("企业名称")]
  12. public string v1 { get; set; }
  13. /// <summary>
  14. /// 统一社会信用代码
  15. /// </summary>
  16. [Description("统一社会信用代码")]
  17. public string v3 { get; set; }
  18. /// <summary>
  19. /// 成立日期
  20. /// </summary>
  21. [Description("成立日期")]
  22. public string v4 { get; set; }
  23.  
  24. /// <summary>
  25. /// 参赛行业领域
  26. /// </summary>
  27. [Description("参赛行业领域")]
  28. public string v5 { get; set; }
  29. /// <summary>
  30. /// 行政区域
  31. /// </summary>
  32. [Description("行政区域")]
  33. public string v6 { get; set; }
  34. /// <summary>
  35. /// 是否属于国家高新区内的企业
  36. /// </summary>
  37. [Description("属于国家高新区内的企业")]
  38. public string v7 { get; set; }
  39. /// <summary>
  40. /// 是否属于国家级经济开发区内的企业
  41. /// </summary>
  42. [Description("属于国家级经济开发区内的企业")]
  43. public string v9 { get; set; }
  44. /// <summary>
  45. /// 是否属于国家级科技企业孵化器内的企业
  46. /// </summary>
  47. [Description("属于国家级科技企业孵化器内的企业")]
  48. public string v11 { get; set; }
  49. /// <summary>
  50. /// 是否属于国家大学科技园内的企业
  51. /// </summary>
  52. [Description("属于国家大学")]
  53. public string v13 { get; set; }
  54. /// <summary>
  55. /// 是否国家备案的众创空间内的企业
  56. /// </summary>
  57. [Description("国家备案的众创空间内的企业")]
  58. public string v20 { get; set; }
  59. /// <summary>
  60. /// 企业注册类型
  61. /// </summary>
  62. [Description("企业注册类型")]
  63. public string v22 { get; set; }
  64. /// <summary>
  65. /// 注册资本
  66. /// </summary>
  67. [Description("注册资本")]
  68. public string v24 { get; set; }
  69. /// <summary>
  70. /// 实收资本(万元人民币)
  71. /// </summary>
  72. [Description("实收资本")]
  73. public string v25 { get; set; }
  74. /// <summary>
  75. /// 企业注册地址
  76. /// </summary>
  77. [Description("企业注册地址")]
  78. public string v26 { get; set; }
  79. /// <summary>
  80. /// 邮政编码
  81. /// </summary>
  82. [Description("注册地邮政编码")]
  83. public string v27 { get; set; }
  84. /// <summary>
  85. /// 通信地址
  86. /// </summary>
  87. [Description("通信地址")]
  88. public string v28 { get; set; }
  89. /// <summary>
  90. /// 邮政编码
  91. /// </summary>
  92. [Description("通讯地邮政编码")]
  93. public string v29 { get; set; }
  94. /// <summary>
  95. /// 企业网址
  96. /// </summary>
  97. [Description("企业网址")]
  98. public string v30 { get; set; }
  99. /// <summary>
  100. /// 企业官方微信
  101. /// </summary>
  102. [Description("企业官方微信")]
  103. public string v31 { get; set; }
  104. /// <summary>
  105. /// 职工总数
  106. /// </summary>
  107. [Description("职工总数")]
  108. public string v32 { get; set; }
  109. /// <summary>
  110. /// 博 士人数
  111. /// </summary>
  112. [Description("博 士")]
  113. public string v33 { get; set; }
  114. /// <summary>
  115. /// 硕 士人数
  116. /// </summary>
  117. [Description("硕 士")]
  118. public string v34 { get; set; }
  119. /// <summary>
  120. /// 本 科人数
  121. /// </summary>
  122. [Description("本 科")]
  123. public string v35 { get; set; }
  124. /// <summary>
  125. /// 大专及以下人数
  126. /// </summary>
  127. [Description("大专及以下")]
  128. public string v36 { get; set; }
  129. /// <summary>
  130. /// 高级职称人数
  131. /// </summary>
  132. [Description("高级职称")]
  133. public string v37 { get; set; }
  134. /// <summary>
  135. /// 中级职称人数
  136. /// </summary>
  137. [Description("中级职称")]
  138. public string v38 { get; set; }
  139. /// <summary>
  140. /// 初级职称人数
  141. /// </summary>
  142. [Description("初级职称")]
  143. public string v39 { get; set; }
  144. /// <summary>
  145. /// 高级技工人数
  146. /// </summary>
  147. [Description("高级技工")]
  148. public string v40 { get; set; }
  149. /// <summary>
  150. /// 上市公司控股企业是否
  151. /// </summary>
  152. [Description("上市公司控股企业")]
  153. public string v41 { get; set; }
  154. /// <summary>
  155. /// 新三板企业是否
  156. /// </summary>
  157. [Description("新三板企业")]
  158. public string v42 { get; set; }
  159. /// <summary>
  160. /// 高新技术企业是否
  161. /// </summary>
  162. [Description("高新技术企业")]
  163. public string v43 { get; set; }
  164. /// <summary>
  165. /// 获得时间
  166. /// </summary>
  167. [Description("获得时间")]
  168. public string v44 { get; set; }
  169. /// <summary>
  170. /// 登记入库的科技型中小企业是否
  171. /// </summary>
  172. [Description("登记入库的科技型中小企业")]
  173. public string v45 { get; set; }
  174. /// <summary>
  175. /// 企业概要(不超1000字)
  176. /// </summary>
  177. [Description("企业概要")]
  178. public string v46 { get; set; }
  179. /// <summary>
  180. /// 关 键 词
  181. /// </summary>
  182. [Description("关 键 词")]
  183. public string v47 { get; set; }
  184. /// <summary>
  185. /// 现融资阶段
  186. /// </summary>
  187. [Description("现融资阶段")]
  188. public string v48 { get; set; }
  189. /// <summary>
  190. /// 参赛项目产品图片
  191. /// </summary>
  192. public string v49 { get; set; }
  193. /// <summary>
  194. /// 参赛项目收入占去年企业营业收入比例
  195. /// </summary>
  196. [Description("参赛项目收入占去年企业营业收入比例")]
  197. public string v50 { get; set; }
  198. /// <summary>
  199. /// 参赛项目介绍(1000字以内)
  200. /// </summary>
  201. [Description("参赛项目介绍(1000字以内)")]
  202. public string v51 { get; set; }
  203. /// <summary>
  204. /// 当前五大客户
  205. /// </summary>
  206. [Description("当前五大客户")]
  207. public string v52 { get; set; }
  208. /// <summary>
  209. /// 当前五大供应商
  210. /// </summary>
  211. [Description("当前五大供应商")]
  212. public string v53 { get; set; }
  213. /// <summary>
  214. /// 国内市场地位排名
  215. /// </summary>
  216. [Description("国内市场地位排名")]
  217. public string v54 { get; set; }
  218. /// <summary>
  219. /// 商业模式及业务拓展计划
  220. /// </summary>
  221. [Description("商业模式及业务拓展计划")]
  222. public string v56 { get; set; }
  223. /// <summary>
  224. /// 经营风险与对策
  225. /// </summary>
  226. [Description("经营风险与对策")]
  227. public string v57 { get; set; }
  228. /// <summary>
  229. /// 企业管理模式
  230. /// </summary>
  231. [Description("企业管理模式")]
  232. public string v58 { get; set; }
  233. /// <summary>
  234. /// 公司对管理层及关键人员是否已采取激励措施是否
  235. /// </summary>
  236. [Description("公司对管理层及关键人员是否已采取激励措施")]
  237. public string v59 { get; set; }
  238. /// <summary>
  239. /// 公司是否考虑员工持股问题?是否
  240. /// </summary>
  241. [Description("公司是否考虑员工持股问题")]
  242. public string v60 { get; set; }
  243. /// <summary>
  244. /// 企业其他技术、产品及服务(1000字以内)
  245. /// </summary>
  246. [Description("企业其他技术、产品及服务(1000字以内)")]
  247. public string v61 { get; set; }
  248. /// <summary>
  249. /// 参赛目的
  250. /// </summary>
  251. [Description("参赛目的")]
  252. public string v62 { get; set; }
  253. /// <summary>
  254. /// 并购需求
  255. /// </summary>
  256. [Description("并购需求")]
  257. public string v63 { get; set; }
  258. /// <summary>
  259. /// 申请大赛组织的大企业对接活动是否
  260. /// </summary>
  261. [Description("申请大赛组织的大企业对接活动")]
  262. public string v64 { get; set; }
  263. /// <summary>
  264. /// 资金使用计划
  265. /// </summary>
  266. [Description("债权融资资金使用计划")]
  267. public string v65 { get; set; }
  268. /// <summary>
  269. /// 股权融资需求是否
  270. /// </summary>
  271. [Description("直接从事研发科技人员数")]
  272. public string v66 { get; set; }
  273. /// <summary>
  274. /// 融资金额(万元¥)
  275. /// </summary>
  276. [Description("上年度吸纳高校应届毕业生人数")]
  277. public string v67 { get; set; }
  278. /// <summary>
  279. /// 拟出让股权比例
  280. /// </summary>
  281. [Description("参赛项目名称")]
  282. public string v68 { get; set; }
  283. /// <summary>
  284. /// 融资时间
  285. /// </summary>
  286. [Description("产品市场分析及竞争优势")]
  287. public string v69 { get; set; }
  288. /// <summary>
  289. /// 资金使用计划
  290. /// </summary>
  291. [Description("股权融资资金使用计划")]
  292. public string v70 { get; set; }
  293. /// <summary>
  294. /// 申请大赛推荐投资机构是否 (修改 申请大赛推荐信贷机构)
  295. /// </summary>
  296. [Description("申请大赛推荐信贷机构")]
  297. public string v71 { get; set; }
  298. /// <summary>
  299. /// 申请大赛组织的融资路演是否 (修改 申请大赛推荐投资机构)
  300. /// </summary>
  301. [Description("申请大赛推荐投资机构")]
  302. public string v72 { get; set; }
  303. /// <summary>
  304. /// 申请国家科技成果转化引导基金设立的子基金推荐 (修改 申请大赛组织的融资路演)
  305. /// </summary>
  306. [Description("申请大赛组织的融资路演")]
  307. public string v73 { get; set; }
  308. #endregion
  309.  
  310. public List<string> GetThisDescriptionName()
  311. {
  312. var result = new List<string>();
  313. GetType().GetProperties().ToList().ForEach(f =>
  314. {
  315. var descriptionObj = (DescriptionAttribute[])f.GetCustomAttributes(typeof(DescriptionAttribute), false);
  316. if (descriptionObj.Length > 0 && !string.IsNullOrWhiteSpace(descriptionObj[0].Description))
  317. {
  318. result.Add(descriptionObj[0].Description);
  319. }
  320. });
  321. return result;
  322. }
  323. }

其中重要的地方是:需要给每个字段一个Description,这里面的值对应的就是word模板中的名称,如下:

这里因为数据是保密的,我就将一些字段删除了,包括word模板中的一些也删除了,就拿出一部分。

和数据库交互的部分我也没写,就将查出来的数据先命名一个_enterpriseStr,最后用Newtonsoft转换成实体这样操作了哈:

EnterpriseEntity enterprise = JsonConvert.DeserializeObject<EnterpriseEntity>(_enterpriseStr);

5、将查出来的数据,插入到word中,完成最终的导出:

  1. 1 ExportFileOperator.InsertFormData(enterprise, ref doc.Item1);//实体数据插入
  2. 2 return new ExportFileOperator().FileResult(title, doc.Item1);

其中最重要的方法就是InsertFormData这个,他的实现如下:

  1. 1 public static void InsertFormData<T>(T objFormData, ref Document document)
  2. 2 {
  3. 3 NodeCollection allTables = document.GetChildNodes(NodeType.Table, true);
  4. 4 List<string> headDescribeNameList = GetObjectHeadDescription<T>();//获取实体中每个Description中的值
  5. 5 foreach (Table tableFirst in allTables)
  6. 6 {
  7. 7 for (int headIndex = 0; headIndex < headDescribeNameList.Count; headIndex++)//循环实体中的每个DescribeName
  8. 8 {
  9. 9 for (int rowIndex = 0; rowIndex < tableFirst.Rows.Count; rowIndex++)//遍历word模板中所有的table
  10. 10 {
  11. 11 for (int cellIndex = 0; cellIndex < tableFirst.Rows[rowIndex].Cells.Count; cellIndex++)//遍历模板中所有的table每行的列数
  12. 12 {
  13. 13 if (tableFirst.Rows[rowIndex].Cells[cellIndex].GetText() != null && tableFirst.Rows[rowIndex].Cells[cellIndex].GetText().Contains(headDescribeNameList[headIndex]) &&
  14. 14 ((tableFirst.Rows[rowIndex].Cells.Count > cellIndex && tableFirst.Rows[rowIndex].Cells[cellIndex + 1] != null && tableFirst.Rows[rowIndex].Cells[cellIndex + 1].GetText().Equals("\a")) || (tableFirst.Rows.Count > rowIndex && tableFirst.Rows[rowIndex + 1] != null && tableFirst.Rows[rowIndex + 1].Cells[cellIndex] != null && tableFirst.Rows[rowIndex + 1].Cells[cellIndex].GetText().Equals("\a"))))//如果遍历的cell不为空、其中的值能和DescribeName匹配上,并且这个单元的右边的cell或者下边cell有占位,而且是空,就在此处插入值
  15. 15 {
  16. 16 var objValue = GetObjectValueByPropName(objFormData, headDescribeNameList[headIndex]);//根据DescribeName获取对应的值
  17. 17 if (tableFirst.Rows[rowIndex].Cells.Count > cellIndex && tableFirst.Rows[rowIndex].Cells[cellIndex + 1] != null && tableFirst.Rows[rowIndex].Cells[cellIndex + 1].GetText().Equals("\a"))
  18. 18 {
  19. 19 InsertCell(objValue, document, tableFirst.Rows[rowIndex].Cells[cellIndex + 1]);//优先在右变空位插入值
  20. 20 break;
  21. 21 }
  22. 22 InsertCell(objValue, document, tableFirst.Rows[rowIndex + 1].Cells[cellIndex]);//右侧如果没有就在下边空位插入值
  23. 23 break;
  24. 24 }
  25. 25 }
  26. 26 }
  27. 27 }
  28. 28 }
  29. 29 }
  1. 1 public static List<string> GetObjectHeadDescription<T>()
  2. 2 {
  3. 3 var obj = Activator.CreateInstance<T>();
  4. 4 MethodInfo method = obj.GetType().GetMethod("GetThisDescriptionName", new Type[] { });//每个实体需要有GetThisDescriptionName这个方法
  5. 5 return (List<string>)(method?.Invoke(obj, null));
  6. 6 }

其中GetThisDescriptionName方法需求在每个实体类中有实现:

根据descriptionName获取实体中的值:

  1. 1 private static string GetObjectValueByPropName<T>(T objFormData, string descriptionName)
  2. 2 {
  3. 3 try
  4. 4 {
  5. 5 var properties = objFormData.GetType().GetProperties();
  6. 6 foreach (var propertyInfo in properties)
  7. 7 {
  8. 8 var descriptionAttributes = (DescriptionAttribute[])propertyInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
  9. 9 if (descriptionAttributes.Length > 0 && !string.IsNullOrWhiteSpace(descriptionAttributes[0].Description) && descriptionAttributes[0].Description.Equals(descriptionName))
  10. 10 {
  11. 11 return propertyInfo.GetValue(objFormData) == null ? "无" : propertyInfo.GetValue(objFormData).ToString();
  12. 12 }
  13. 13 }
  14. 14 return "无";
  15. 15 }
  16. 16 catch (Exception e)
  17. 17 {
  18. 18 Console.WriteLine(e);
  19. 19 throw;
  20. 20 }
  21. 21 }

在cell中插入值:

  1. 1 private static void InsertCell(string value, Document doc, Cell cell)
  2. 2 {
  3. 3 Cell insertCell = cell;
  4. 4 insertCell.FirstParagraph.Remove();
  5. 5 Paragraph p = new Paragraph(doc);
  6. 6 p.AppendChild(new Run(doc, (value == null ? "" : value)));
  7. 7 p.ParagraphFormat.Alignment = ParagraphAlignment.Center;
  8. 8 insertCell.CellFormat.VerticalAlignment = CellVerticalAlignment.Center;
  9. 9 insertCell.AppendChild(p);
  10. 10 }

最后一个方法FileResult:

  1. 1 public FileResult FileResult(string fileName, Document doc)
  2. 2 {
  3. 3 var filePathName = $"{fileName}.doc";
  4. 4 doc.Save(Path.Combine(_tempPath, "temp", filePathName), SaveFormat.Doc); //保存word
  5. 5 filePathName = Path.Combine(_tempPath, "temp", filePathName);
  6. 6 return File(filePathName, "application/doc", $"{fileName}.Doc");
  7. 7 }

最终效果:

最后说一下,其中有一些细节的地方还是需要做一些处理,暂时没时间写,后期有时间补,先就这样了

大家有什么好的想法或者更好的实现方式,尽管提出来,共同进步

git地址:https://github.com/Binzm/ExportWorkdModel.git

C#中word导出功能骚操作的更多相关文章

  1. Guava中这些Map的骚操作,让我的代码量减少了50%

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. Guava是google公司开发的一款Java类库扩展工具包,内含了丰富的API,涵盖了集合.缓存.并发.I/O等多个方面.使用这些API一方面 ...

  2. 论减少代码中return语句的骚操作

    一.写作背景 最近组内在推行checkstyle代码规范的检测,关于checkstyle的介绍可以参考:https://checkstyle.sourceforge.io, 在按照checkstyle ...

  3. Pandas中关于accessor的骚操作

    来自:Python那些事 pandas中accessor功能很强大,可以将它理解为一种属性接口,通过它获得额外的方法. 下面用代码和实例理解一下: import pandas as pd pd.Ser ...

  4. Java 动态实现word导出功能

    1.word模板:xx.ftl生成,ftl文件就是word的源代码,类似html一样是拥有标签和样式的代码. 把需要导出的doc文件模板用office版本的word工具打开. 把doc文件另存为xx. ...

  5. linux中dd相关命令骚操作

    一.dd如何快速将磁盘写满 方法一: dd if=/dev/zero of=/tmp/file bs=1G count=10 # 参数解释 1. if=文件名:输入文件名,缺省为标准输入.即指定源文件 ...

  6. Python中的”黑魔法“与”骚操作“

    本文主要介绍Python的高级特性:列表推导式.迭代器和生成器,是面试中经常会被问到的特性.因为生成器实现了迭代器协议,可由列表推导式来生成,所有,这三个概念作为一章来介绍,是最便于大家理解的,现在看 ...

  7. 【Python从入门到精通】(九)Python中字符串的各种骚操作你已经烂熟于心了么?

    您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦. 本文将重点介绍Python字符串的各种常用方法,字符串是实际开发中经常用到的,所有熟练的掌握它的各种用法显得尤为重要. 干货满满,建议收藏,欢迎大 ...

  8. vue开发中的一些简单骚操作

    在开发过程中,我们可以定义很多参数,这时需要通过不同的操作来改变不同的参数,这就比较复杂了, 虽然不难,但是代码多了也不好看,这时我们就可以通过简单的操作就行简化: 1.对象使用方括号 let obj ...

  9. 项目中常用的js骚操作

    //打开网址window.open("http://www.runoob.com"); //判断是否为url var url = $("#url").val() ...

随机推荐

  1. 在recover database时,如何决定该从哪一个SCN开始恢复

    使用备份恢复的方法搭建DG库,还原数据文件后,打开数据库时报错 SQL> ALTER DATABASE OPEN READ ONLY; ALTER DATABASE OPEN READ ONLY ...

  2. Java高并发与多线程(三)-----线程的基本属性和主要方法

    今天,我们开始Java高并发与多线程的第三篇,线程的基本属性和主要方法. [属性] 编号(ID) 类型long 用于标识不同的线程,编号唯一,只存在java虚拟机的一次运行 名称(Name) 类型St ...

  3. 小试牛刀ElasticSearch大数据聚合统计

    ElasticSearch相信有不少朋友都了解,即使没有了解过它那相信对ELK也有所认识E即是ElasticSearch.ElasticSearch最开始更多用于检索,作为一搜索的集群产品简单易用绝对 ...

  4. Ubuntu创建桌面图标

    以火狐为例 创建"~/.local/share/applications/firefox_dev.desktop"文件, 文件内容为: [Desktop Entry] Name=F ...

  5. loj10009钓鱼___vector的调试

    题目描述 在一条水平路边,有 n 个钓鱼湖,从左到右编号为1,2,...,n .佳佳有 h 个小时的空余时间,他希望利用这个时间钓到更多的鱼.他从1  出发,向右走,有选择的在一些湖边停留一定的时间( ...

  6. 内存屏障在CPU、JVM、JDK中的实现

    前言 内存屏障(英语:Memory barrier),也称内存栅栏,内存栅障,屏障指令等,是一类同步屏障指令,它使得 CPU 或编译器在对内存进行操作的时候, 严格按照一定的顺序来执行, 也就是说在内 ...

  7. 有趣的css—隐藏元素的7种思路

    css隐藏元素的7种思路 前言 display.visibility.opacity三个属性隐藏元素之间的异同点一直是前端面试面试的常考题. 属性 值 是否在页面上显示 注册点击事件是否有效 是否存在 ...

  8. Java中Socket的用法

    Socket分为ServerSocket和Socket两大类: 其中ServerSocket用于服务器端,可以通过accept方法监听请求,监听到请求后返回Socket: Socket用户具体完成数据 ...

  9. HaspMap源码分析(JDK 1.8)

    底层结构分析 上面这两张图分别画出了JDK 1.7.1.8底层数据结构,在JDK 1.7.1.8中都使用 了散列算法,但是在JDK 1.8中引入了红黑树,在链表的长度大于等于8并且hash桶的长度大于 ...

  10. trunk

    今天我们一起聊trunk(接vlan之后),一台switch我们用vlan就可以划分vlan(虚拟局域网),但是2台switch该怎么办呢? 实验环境搭建 switch0 : enable //切换到 ...