• [技术干货] javascript中将xml转为json的方法
    这篇文章将为大家详细讲解有关javascript中将xml转为json的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。javascript中将xml转换为json字符串的方法:首先通过XML字符串或请求XML文件来获取XML的DOM对象;然后通过遍历和递归来获取子元素的nodeValue值;最后拼接出JSON字符串即可。利用JavaScript将XML转换为JSON首先通过XML字符串来生成XML的DOM对象:/**  * 通过传入xml的内容字符串来解析xml  * @param xmlString xml字符串  * @returns xml的Document对象  */ function getXmlDocumentByXmlString(xmlString) {     var xmlDoc = null;     if (window.DOMParser) {         var parser = new DOMParser();         xmlDoc = parser.parseFromString(xmlString, "text/xml");     } else {         //IE         xmlDoc = new ActiveXObject("Microsoft.XMLDOM");         xmlDoc.async = "false";         xmlDoc.loadXML(xmlString);     }     return xmlDoc; }或者通过请求XML文件来获取XML的DOM对象:/**  * 通过传入xml文件路径来解析xml文档  * @param xmlFilePath xml文档路径,如:files/test.xml  * @returns xml的Document对象  */ function getXmlDocumentByFilePath(xmlFilePath) {     //xmlDocument对象     var xmlDoc = null;     //xmlhttp对象     var xmlhttp = null;     if (window.XMLHttpRequest) {         //IE7+, FireFox, Chrome, Opera, Safari         xmlhttp = new XMLHttpRequest();     } else {         //IE6, IE5         xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");     }     xmlhttp.open("GET", xmlFilePath, false);     xmlhttp.send();     xmlDoc = xmlhttp.responseXML;     return xmlDoc; }接下来就是重点的部分了,通过遍历和递归获取子元素的nodeValue,来拼接出JSON字符串,实现将XML转换成JSON字符串:/**  * 将XML的Document对象转换为JSON字符串  * @param xmlDoc xml的Document对象  * @return string  */ function convertToJSON(xmlDoc) {     //准备JSON字符串和缓存(提升性能)     var jsonStr = "";     var buffer = new Array();     buffer.push("{");     //获取xml文档的所有子节点     var nodeList = xmlDoc.childNodes;     generate(nodeList);     /**      * 中间函数,用于递归解析xml文档对象,并附加到json字符串中      * @param node_list xml文档的的nodeList      */     function generate(node_list) {         for (var i = 0; i < node_list.length; i++) {             var curr_node = node_list[i];             //忽略子节点中的换行和空格             if (curr_node.nodeType == 3) {                 continue;             }             //如果子节点还包括子节点,则继续进行遍历             if (curr_node.childNodes.length > 1) {                 buffer.push("\"" + curr_node.nodeName + "\": {");                 generate(curr_node.childNodes);             } else {                 var firstChild = curr_node.childNodes[0];                 if (firstChild != null) {                     //nodeValue不为null                     buffer.push("\"" + curr_node.nodeName + "\":\"" + firstChild.nodeValue + "\"");                 } else {                     //nodeValue为null                     buffer.push("\"" + curr_node.nodeName + "\":\"\"");                 }             }             if (i < (node_list.length - 2)) {                 buffer.push(",");             } else {                 break;             }         }         //添加末尾的"}"         buffer.push("}");     }     jsonStr = buffer.join("");     return jsonStr; }使用方式:通过getXmLDocumentByFilePath(xmlFilePath)或者getXmlDocumentByXmlString(xmlString)获取XML的Document对象,然后通过调用convertToJSON(xmlDocument)传入xml的Ducument对象即可得到转换后的JSON字符串。适用范围:不含有attribute的任意XML文档。关于“javascript中将xml转为json的方法”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。原文链接:https://m.yisu.com/zixun/446969.html
  • [技术干货] vue中async和await异步编程
    async&await是Promise的语法糖,使用他的目的就是用同步的写法,写异步的操作。async 是“异步”的简写, async 用于申明一个异步的 function,await 可以认为是 async wait 的简写,await 用于等待一个异步方法执行完成。当我们函数中需要返回值是promise对象时通常用async和await简化。          async作为一个关键字放到函数之前,表示函数是异步的函数,异步函数也就意味着该函数的执行不会阻塞后面代码的执行,等async 函数返回一个promise 对象。  1.async async可以作用在任何方法前, 返回值是一个Promise对象  async function a(){  } console.log(a());   var b = (async () => {       }) console.log(b()); async函数内部return的返回值, 会成为then回调函数的参数  async function a() {     return 123 } a().then(res=>{     console.log(res); }) async作用的方法,如果内部出现报错,可以被promise的catch方法捕获  async function a() {     console.log(a);     let a = 123; } a().catch(err=>{     console.log(err); }) 2. await await只能作用在async修饰的方法中,不能单独使用,如果使用报错、  function a(){     await //报错:await is not defined     console.log(123); } a() 正常情况 await后面跟着一个Promise对象,返回的是Promise对象的成功后结果  async function a(){     var b = await new Promise((resolve,reject)=>{         resolve('123')     })     return b } a().then(res=>{     console.log(res); }) ———————————————— 原文链接:https://blog.csdn.net/qq_44858608/article/details/124332167 
  • [技术干货] async和await用法介绍
     一;async 1.函数前面加上 async 关键字,则该函数会返回一个结果为 promise 的对象。 2. async 函数返回 promise 对象的状态。 2.1:如果返回的是一个非 Promise 类型的数据, 则async 函数返回 promise 的状态 为 fulfilled 成功。 2.2:如果返回的是一个 Promise对象,则 async 函数返回 promise 的状态由返回的Promise对象的状态决定。 2.3:如果 throw Errow 抛出异常,则 async 函数返回 promise 的状态为 rejected 失败。 二;await 1.await 右侧的表达式一般为 promise 对象。 2.await 是在等一个表达式的结果,等一个返回值(回调成功的内容) 3.如果 await 右侧是一个 promise 对象,则 await 返回的是 promise 成功的值。 注意: 1.await 必须写在 async 函数中,但 async 函数中可以没有 await。 2.如果 await 的 promise 失败了,就会抛出异常,该异常需要通过 try catch 捕获处理。 3.如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。  三;async 和 await 结合发送 ajax   1.封装一个 发送GET请求的 promise  function sendAjax(url) {             return new Promise((resolve, reject) => {                 const xhr = new XMLHttpRequest()                 xhr.open('GET', url)                 xhr.send()                 // 处理返回结果                 xhr.onreadystatechange = function () {                     if (xhr.readyState == 4) {                         // 判断状态码                         if (xhr.readyState >= 200 && xhr.readyState < 300) {                             resolve(xhr.response)                         }else {                             reject(xhr.status)                         }                     }                 }             })         } 2.async和await结合发送ajax请求  // 触发点击事件发送ajax请求         let btn = document.querySelector('#btn')         btn.addEventListener('click', async function () {             try {                 let res = await sendAjax('get请求地址')                 console.log(res);             } catch (error) {                 console.log(error);             }         }) ———————————————— 原文链接:https://blog.csdn.net/Allurewuhui/article/details/123434870 
  • [技术干货] JavaScript开发小技巧
    1、使用var声明变量如果给一个没有声明的变量赋值,默认会作为一个全局变量(即使在函数内赋值)。要尽量避免不必要的全局变量。2、行尾使用分号虽然JavaScript允许省略行尾的分号,但是有时不注意的省略,会导致不必要的错误。建议在可用可不用行尾分号的地方加上分号。3、获取指定范围内的随机数var getRandom = function(max, min) {min = arguments[1] || 0;return Math.floor(Math.random() * (max - min + 1) + min);};上面的函数接受一个你希望的随机最大数和一个你希望的随机最小数。4、打乱数字数组的顺序var sortArray = array.sort(function(){ return Math.random() - 0.5;});5、取出数组中的随机项var ran = array[Math.floor(Math.random() * array.length)];6、去除字符串的首尾空格var s = string.trim();7、类数组对象转为数组比如:类数组对象遍历:Array.prototype.forEach.call(argumens,function(value){})DOM的NodeList和HTMLCollection也是类数组对象8、获取数组中的最大值和最小值var max = Math.max.apply(Math, array);var min = Math.min.apply(Math, array);9、清空数组array.length = 0;array = [];10、保留指定小数位var num = num.toFixed(2);返回字符串,保留两位小数11、使用for-in循环来遍历对象的属性for(var key in object) { // object[key]}不要用for-in来遍历数据12、获取某月天数function getMonthDay(date){ date = date || new Date(); if(typeof date === 'string') { date = new Date(date); }; date.setDate(32); return 32 - date.getDate();}传入date参数,可以是字符串、日期对象实例;为空表示当月天数13、浮点数问题0.1 + 0.2 = 0.30000000000000004 != 0.3JavaScript的数字都遵循IEEE 754标准构建,在内部都是64位浮点小数表示14、JSON序列化和反序列化使用JSON.stringify()来将JavaScript对象序列化为有效的字符串。使用JSON.parse()来将有效的字符串转换为JavaScript对象。在AJAX传输数据时很有用15、使用“===”替换“==”相等运算符(==)在比较时会将操作数进行相应的类型转换,而全等运算符(===)不会进行类型转换。16、避免使用with()使用with()可以把变量加入到全局作用域中,因此,如果有其它的同名变量,一来容易混淆,二来值也会被覆盖。17、不要使用eval()或函数构造器eval()和函数构造器(Function consturctor)的开销较大,每次调用,JavaScript引擎都要将源代码转换为可执行的代码。18、简化if语句if (condition) { fn();}可替换成:condition && fn();19、给可能省略的参数赋默认值function test(a, b){ a = a || '1';}20、给数组循环中缓存length的值如果你确定循环中数组的长度不会变化,那么你可以这样:var length = array.length;for(var i = 0; i < length; i++) {}可以避免在每次迭代都将会重新计算数组的大小,提高效率21、合并数组对于小数组,我们可以这样:var arr1 = [1,2,3];var arr2 = [4,5,6];var arr3 = arr1.concat(arr2); // [1,2,3,4,5,6]不过,concat()这个函数并不适合用来合并两个大型的数组,因为其将消耗大量的内存来存储新创建的数组。在这种情况之个,可以使用Array.prototype.push.apply(arr1,arr2)来替代创建一个新数组。这种方法不是用来创建一个新的数组,其只是将第一个第二个数组合并在一起,同时减少内存的使用:Array.prototype.push.apply(arr1, arr2); console.log(arr1); // [1,2,3,4,5,6]22 枚举对象“自身”的属性for...in除了枚举对象“自身”的属性外,还会枚举出继承过来的属性。var hasOwn = Object.prototype.hasOwnProperty;var obj = {name: 'tg', age: 24};for(var name in obj) { if (hasOwn.call(obj, name)) { console.log(name + ':' + obj[name]); }}// name:tg// age:24转载自http://bbs.jeecms.com/java/83762.jhtml
  • [技术干货] 基于Java+SpringBoot+vue等疫情期间在线网课管理系统详细设计实现-转载
     一、前言介绍: 1.1 背景及意义         疫情网课也都将通过计算机进行整体智能化操作,对于疫情网课管理系统所牵扯的管理及数据保存都是非常多的,例如管理员;首页、个人中心、学生管理、教师管理、班级管理、课程分类管理、课程表管理、课程信息管理、作业信息管理、请假信息管理、上课签到管理、论坛交流、系统管理,学生;首页、个人中心、课程表管理、课程信息管理、作业信息管理、请假信息管理、上课签到管理,教师;首页、个人中心、学生管理、班级管理、课程分类管理、课程表管理、课程信息管理、作业信息管理、请假信息管理、上课签到管理、系统管理,前台首页;首页、课程表、论坛交流、学校公告、个人中心、后台管理、师生聊天等功能,这给管理者的工作带来了巨大的挑战,面对大量的信息,传统的管理系统,都是通过笔记的方式进行详细信息的统计,后来出现电脑,通过电脑输入软件将纸质的信息统计到电脑上,这种方式比较传统,而且想要统计数据信息比较麻烦,还受时间和空间的影响,所以为此开发了疫情网课管理系统;为学生提供了方便管理平台,方便管理员查看及维护,并且可以通过需求进行内容的编辑及维护等;对于学生和教师而言,可以随时进行查询所需信息,管理员可以足不出户就可以获取到系统的数据信息等,而且还能节省学生和教师很多时间,所以开发疫情网课管理系统给管理者带来了很大的方便,同时也方便管理员对学生及教师信息进行处理。          本论文疫情网课管理系统主要牵扯到的程序,数据库与计算机技术等。覆盖知识面大,可以大大的提高系统人员工作效率。  1.2 系统运行环境  开发系统:Windows10  架构模式:MVC/前后端分离  JDK版本:Java JDK1.8  开发工具:IDEA  数据库版本: mysql5.7  数据库可视化工具: navicat for mysql  服务器:SpringBoot自带 apache tomcat  主要技术:Java,Springboot,mybatis,mysql,jquery,html,vue,elementui等  二、系统设计: 2.1 系统架构设计 ​  2.2 角色功能图 ​  2.3 登录时序图设计 ​  三、功能截图:  3.1 登录注册: 管理员通过用户名和密码、验证码、角色填写完成后进行登录  ​  学生注册,在学生注册页面可以填写学号、密码、学生、年龄、手机、邮箱等信息进行注册   ​  3.2 前台首页: 学生点击进入到系统操作界面可以查看首页、个人中心、课程表管理、课程信息管理、作业信息管理、请假信息管理、上课签到管理等功能模块,个人信息:通过列表可以获取学号、学生、性别、年龄、手机、邮箱、班级、照片等信息并进行修改操作。  ​   ​   课程表信息:  ​  可以下载和收藏操作   ​ 论讨交流,可以发布论讨文章和进行评论交流等  ​  学校公告:  ​  个人中心:  ​ 师生聊天:  ​   用户后端:  ​  3.3 后台管理:  管理员登录成功后进入到系统操作界面,可以对首页、个人中心、学生管理、教师管理、班级管理、课程分类管理、课程表管理、课程信息管理、作业信息管理、请假信息管理、上课签到管理、论坛交流、系统管理等功能模块进行相对应操作。  学生管理:  ​   课程表管理:  ​  作业信息管理:  ​ 学校公告:  ​  四、数据设计: 每个数据库的应用它们都是和区分开的,当运行到一定的程序当中,它就会与自己相关的协议与客户端进行通讯。那么这个系统就会对使这些数据进行连接。当我们选择哪个桥段的时候,接下来就会简单的叙述这个数据库是如何来创建的。当点击完成按钮的时候就会自动在对话框内弹出数据源的名称,在进行点击下一步即可,直接在输入相对应的身份验证和登录密码。   ​  五、代码实现: /**  * 登录相关  */ @RequestMapping("users") @RestController public class UserController{          @Autowired     private UserService userService;          @Autowired     private TokenService tokenService;       /**      * 登录      */     @IgnoreAuth     @PostMapping(value = "/login")     public R login(String username, String password, String captcha, HttpServletRequest request) {         UserEntity user = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", username));         if(user==null || !user.getPassword().equals(password)) {             return R.error("账号或密码不正确");         }         String token = tokenService.generateToken(user.getId(),username, "users", user.getRole());         return R.ok().put("token", token);     }          /**      * 注册      */     @IgnoreAuth     @PostMapping(value = "/register")     public R register(@RequestBody UserEntity user){ //        ValidatorUtils.validateEntity(user);         if(userService.selectOne(new EntityWrapper<UserEntity>().eq("username", user.getUsername())) !=null) {             return R.error("用户已存在");         }         userService.insert(user);         return R.ok();     }       /**      * 退出      */     @GetMapping(value = "logout")     public R logout(HttpServletRequest request) {         request.getSession().invalidate();         return R.ok("退出成功");     }          /**      * 密码重置      */     @IgnoreAuth     @RequestMapping(value = "/resetPass")     public R resetPass(String username, HttpServletRequest request){         UserEntity user = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", username));         if(user==null) {             return R.error("账号不存在");         }         user.setPassword("123456");         userService.update(user,null);         return R.ok("密码已重置为:123456");     }          /**      * 列表      */     @RequestMapping("/page")     public R page(@RequestParam Map<String, Object> params,UserEntity user){         EntityWrapper<UserEntity> ew = new EntityWrapper<UserEntity>();         PageUtils page = userService.queryPage(params, MPUtil.sort(MPUtil.between(MPUtil.allLike(ew, user), params), params));         return R.ok().put("data", page);     }       /**      * 列表      */     @RequestMapping("/list")     public R list( UserEntity user){            EntityWrapper<UserEntity> ew = new EntityWrapper<UserEntity>();           ew.allEq(MPUtil.allEQMapPre( user, "user"));          return R.ok().put("data", userService.selectListView(ew));     }     /**      * 信息      */     @RequestMapping("/info/{id}")     public R info(@PathVariable("id") String id){         UserEntity user = userService.selectById(id);         return R.ok().put("data", user);     }          /**      * 获取用户的session用户信息      */     @RequestMapping("/session")     public R getCurrUser(HttpServletRequest request){         Long id = (Long)request.getSession().getAttribute("userId");         UserEntity user = userService.selectById(id);         return R.ok().put("data", user);     }     /**      * 保存      */     @PostMapping("/save")     public R save(@RequestBody UserEntity user){         if(userService.selectOne(new EntityWrapper<UserEntity>().eq("username", user.getUsername())) !=null) {             return R.error("用户已存在");         }         userService.insert(user);         return R.ok();     }       /**      * 修改      */     @RequestMapping("/update")     public R update(@RequestBody UserEntity user){         UserEntity u = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", user.getUsername()));         if(u!=null && u.getId()!=user.getId() && u.getUsername().equals(user.getUsername())) {             return R.error("用户名已存在。");         }         userService.updateById(user);//全部更新         return R.ok();     }       /**      * 删除      */     @RequestMapping("/delete")     public R delete(@RequestBody Long[] ids){         userService.deleteBatchIds(Arrays.asList(ids));         return R.ok();     } }  ———————————————— 版权声明:本文为CSDN博主「java李杨勇」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_39709134/article/details/128438852 
  • [技术干货] 基于Java+Springboot+Vue+elememt社区疫情返乡管控系统设计实现-转载
    前言介绍:          随着国内经济形势的不断发展,中国互联网进入了一个难得的高峰发展时期,这使得中外资本家纷纷转向互联网市场。然而,许多管理领域的不合理结构,人员不足以及市场管理需求的增加使得更多的人具备了互联网管理的意识。在当今高度发达的信息中,信息管理改革已成为一种更加广泛和全面的趋势。“社区疫情返乡人员防控管理平台系统”是基于Mysql5.7版本数据库,在Springboot程序设计的基础上实现的。                  该系统具有首页、个人中心、用户管理、物资捐赠管理。物资申请管理、物资捐赠审核、反人员管理、外出报备管理、投诉信息管理、体温上报管理、商品代买管理、商品配送管理、社区论坛、系统管理等功能。通过用户模块来管理自己的信息。用户注册登陆本社区疫情后,可以进入个人后台来管理首页、个人中心、返乡报备管理、外出报备管理、投诉信息管理、体温上报管理、商品代买管理、商品配送管理等功能。最后在主页页面,增加了推送功能,使用户可以直接快速接触到最丰富的内容、通过对此项目的练习、设计、学习、代码编写、让自己熟练的运用Java主流相关的一系列技术、比如、系统前期的调研、数据库的反复设计和修改、字段长度的控制、类型的掌控、编码的设计、以及代码规范、接口调试、前端页面样式代码编写、前端后端对接、以及跨域问题和其他权限问题的解决。为以为从事Java开发或相关工作打下巩固基础。  此社区疫情基本上实现了整个社区疫情返乡人员防控管理平台信息管理的过程,向大众提供了一个安全、动态、高效的社区疫情防控管理平台系统。  二、系统设计: 系统整体架构: ​​  主要研究方法: 本系统采用基于Java语言B/S架构模式实现的,即Java启动运行的客户端与服务器的结构,基于 J2EE的基本标准,Tomcat7.0及以上作为运行服务器支持,基于、java、springboot、vue等主要技术设计,idea作为开发环境,数据库采用Mysql 5.0以上。  (1)项目调查法:参考基于java社区疫情返乡人员防控管理平台系统相关的系统设计和实现、结合这次毕业设计的自己的系统需求调研,设计出本系统的主要功能设计和架构。  (2)文献参考法:通过查阅阅读最近三年基于java社区疫情返乡人员防控管理平台有关的优质文献参考和相关书籍、了解基于java社区疫情返乡人员防控管理平台的现状和涉及的技术情况  (3)经验总结法:经过网络搜索查看、老师的指导、自己的学习开发经验结合、对系统开发整理、具体情况,进行归纳、分析总结,满足系统的各项可行性分析,使系统设计和实现的合理化、标准化。  (4)实证测试法:通过自己对前面资料的查询、阅读、以及利用自己所学习的计算机相关技术来完成编码实现、进行系统功能测试、代码编写、完成功能模块开发。最后进行测试  登录模块设计: ​  三、功能截图:  登录注册: 用户后台登录:  ​  系统首页: 社区疫情防控管理平台系统,用户输入进入到系统首页可以查看首页、社区论坛、社区公告、个人中心、后台管理等内容进行操作。    物资申请: 物资申请列表,这里的物资是用户捐赠的一些疫情防疫物资等、点击查看详情和申请操作。   申请详情: 比如常用的口罩信息等。  ​​  公告列表 点击可以查看公告详情,这里的数据是后台管理员编辑上传就行。    公告详情  社区论坛: 点击查看社区论坛列表和详情,用户登录后可以添加社区论坛信息,可以进行论坛信息进行评论等操作。   点击查看详情,用户登录后可以进行评论操作。    后台管理: 管理员登录进入社区疫情防控管理平台系统可以查看首页、个人中心、用户管理、物资捐赠管理,物资申请管理,返乡报备管理、外出报备管理、投诉信息管理、体温上报管理、商品代买管理、商品配送管理、社区论坛、系统管理等内容进行详细操作   捐赠物资管理:  返乡报备管理 : 在返乡报备管理页面可以对出发地点、返乡时间、体温、身体状态、近15天轨迹、核酸报告、经过疫区、报备时间、用户姓名、姓名、用户手机、详细住址、审核回复、审核状态、审核等信息进行详情,修改或删除等操作。   外出申请管理: 在外出报备管理页面可以对外出事由、外出地点、经过疫区、外出时间、返回时间、外出报备出行方式、随行人员、用户姓名、姓名、用户手机、详细住址、审核回复、审核状态、审核等信息进行详情,修改或删除等操作。   投诉信息管理:  核酸检测管理: 在核酸检测管理页面可以对用户姓名、姓名、性别、年龄、体温、健康码、是否咳嗽、是否腹泻、是否乏力、是否就医、其他情况、上报时间等信息进行详情,修改或删除等操作   商品代买管理: 在商品代买管理页面可以对用户姓名、姓名、用户手机、详细住址、申请时间、备注、审核回复、审核状态、审核等信息进行详情,修改或删除等操作。   商品配送管理:  社区论坛管理:  返乡公告管理:  四、数据设计: 主要数据库表字段设计: 用户信息:主键id、用户id、用户姓名、表名、角色、密码、新增时间、过期时间  物资捐赠:物资名称,物资介绍,物资图片,捐赠地址,捐赠数量,捐赠对象,发布时间,捐赠内容。审核状态,审核回复,备注等。  物资申请:物资名称,物资信息,申请人,申请时间,申请数量,用户账号,审核状态,审核回复  疫情社区论坛信息:主键id、创建日期、帖子标题名称、帖子内容、父节点id、用户id、用户姓名、状态  返乡报备:主键id、创建日期、出发地点、返乡时间、体温、身体状态、近15天轨迹、核酸报告、经过疫区、报备时间、用户姓名、姓名、用户手机、详细住址、是否审核、审核回复  用户信息:主键id、创建日期、用户姓名、密码、姓名、头像、性别、年龄、详细住址、用户手机、邮箱、身份证  外出报备:主键id、创建日期、外出事由、外出地点、经过疫区、外出时间、返回时间、外出报备出行方式、随行人员、用户姓名、姓名、用户手机、详细住址、是否审核、审核回复  投诉信息:(主键id、创建日期、标题名称、名称、类型、图片信息、投诉内容、投诉日期、用户姓名、姓名、用户手机、详细住址、是否审核、审核回复  体温上报信息:主键id、创建日期、用户姓名、姓名、性别、年龄、体温、健康码、是否咳嗽、是否腹泻、是否乏力、是否就医、其他情况、上报时间  商品配送信息:主键id、创建日期、用户姓名、姓名、用户手机、详细住址、商品金额、配送状态、更新时间、是否支付  社区疫情公告信息:主键id、创建日期、标题名称、简介、图片信息内容  数据库实体设计: 用户管理结构图: ​  投诉信息管理实体: ​体温上报管理实体: ​  五、代码实现: 用户登录: <div id="app" class="login">         <form id="loginForm" class="layui-form login-form" :style='{"padding":"20px","boxShadow":"0 0 0px rgba(255,0,0,.8)","borderColor":"rgba(0, 112, 126, 1)","backgroundColor":"rgba(255, 255, 255, 1)","borderRadius":"20px","borderWidth":"2px","width":"400px","borderStyle":"solid","justifyContent":"center","height":"auto"}'>             <h1 class="logo" v-if="false" :style='{"padding":"5px 0","boxShadow":"0 0 6px rgba(255,0,0,.8)","borderColor":"rgba(0,0,0,.3)","backgroundColor":"#fff","borderRadius":"6px","borderWidth":"0","borderStyle":"solid"}'><img :style='{"boxShadow":"0 0 6px rgba(255,0,0,.8)","margin":"0 auto","borderColor":"rgba(0,0,0,.3)","borderRadius":"100%","borderWidth":"1px","width":"44px","borderStyle":"solid","height":"44px"}' src="$template2.front.login.logo.backgroundImage"></h1>                          <div class="msg-warn hide title" v-if="true" :style='{"padding":"0 10px","boxShadow":"0 0 6px rgba(255,0,0,.8)","margin":"10px auto","borderColor":"rgba(0,0,0,1)","backgroundColor":"#f7f7f7","color":"red","isshow":true,"borderRadius":"8px","borderWidth":"0","width":"auto","lineHeight":"32px","fontSize":"12px","borderStyle":"solid"}'>公共场所不建议自动登录,以防账号丢失</div>             <div :style='{"padding":"0","boxShadow":"0 0 6px rgba(255,0,0,0)","margin":"0 auto","borderColor":"rgba(0, 112, 126, 1)","backgroundColor":"rgba(213, 195, 195, 0.49)","borderRadius":"20px","borderWidth":"0 0 0px 0","width":"80%","borderStyle":"solid","height":"64px"}' class="form-item">                 <label v-if="false" :style='{"padding":"0 10px","boxShadow":"0 0 6px rgba(255,0,0,0)","borderColor":"rgba(0,0,0,0)","backgroundColor":"transparent","color":"#333","borderRadius":"0","textAlign":"right","borderWidth":"0","width":"84px","fontSize":"16px","borderStyle":"solid"}' class="form-label">账号</label>                 <input :style='{"padding":"0 10px","boxShadow":"0 0 6px rgba(0,0,0,.5)","borderColor":"rgba(0, 112, 126, 1)","backgroundColor":"#fff","color":"#333","borderRadius":"8px","textAlign":"left","borderWidth":"1px","width":"100%","fontSize":"14px","borderStyle":"solid","height":"44px"}' type="text" name="username" required lay-verify="required" placeholder="请输入账号" autocomplete="off" class="layui-input">             </div>             <div :style='{"padding":"0","boxShadow":"0 0 6px rgba(255,0,0,0)","margin":"0 auto","borderColor":"rgba(0, 112, 126, 1)","backgroundColor":"rgba(213, 195, 195, 0.49)","borderRadius":"20px","borderWidth":"0 0 0px 0","width":"80%","borderStyle":"solid","height":"64px"}' class="form-item">                 <label v-if="false" :style='{"padding":"0 10px","boxShadow":"0 0 6px rgba(255,0,0,0)","borderColor":"rgba(0,0,0,0)","backgroundColor":"transparent","color":"#333","borderRadius":"0","textAlign":"right","borderWidth":"0","width":"84px","fontSize":"16px","borderStyle":"solid"}' class="form-label">密码</label>                 <input :style='{"padding":"0 10px","boxShadow":"0 0 6px rgba(0,0,0,.5)","borderColor":"rgba(0, 112, 126, 1)","backgroundColor":"#fff","color":"#333","borderRadius":"8px","textAlign":"left","borderWidth":"1px","width":"100%","fontSize":"14px","borderStyle":"solid","height":"44px"}' type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">             </div>                 <div class="form-item codes" :style='{"padding":"0","boxShadow":"0 0 6px rgba(255,0,0,0)","margin":"0 auto","borderColor":"rgba(0, 112, 126, 1)","backgroundColor":"rgba(213, 195, 195, 0.49)","borderRadius":"20px","borderWidth":"0 0 0px 0","width":"80%","borderStyle":"solid","height":"64px"}'>                   <input style="flex: 1;" type="text" id="code" placeholder="请输入验证码">                   <div class="nums" id="nums" style="display: flex;justify-content: center;align-items: center;">                                        </div>                 </div>               <div :style='{"padding":"0","boxShadow":"0 0 6px rgba(255,0,0,0)","margin":"0 auto","borderColor":"rgba(0, 112, 126, 1)","backgroundColor":"#fff","borderRadius":"0","borderWidth":"0 0 1px 0","width":"80%","borderStyle":"solid","height":"44px"}' class="form-item l-redio">                 <input v-if="item.hasFrontLogin=='是'" v-for="(item,index) in menu" v-bind:key="index" type="radio" name="role" id="role" :value="item.tableName" :title="item.roleName">             </div>             <button :style='{"padding":"0 10px","boxShadow":"0 0px 0px rgba(255, 0, 0, 1)","margin":"10px auto","borderColor":"rgba(0, 112, 126, 1)","backgroundColor":"rgba(38, 155, 158, 1)","color":"#fff","borderRadius":"8px","borderWidth":"0","width":"60%","fontSize":"14px","borderStyle":"solid","height":"44px"}' class="layui-btn layui-btn-fluid layui-btn-danger btn-submit" lay-submit lay-filter="login">登录</button>             <p :style='{"color":"rgba(255, 0, 0, 1)","textAlign":"left","fontSize":"12px"}' class="txt"><a style="color: inherit;font-size: inherit;" v-if="item.hasFrontRegister=='是'" v-for="(item,index) in menu" v-bind:key="index" :href="'javascript:registerClick(\''+item.tableName+'\')'">注册{{item.roleName.replace('注册','')}}</a></p>         </form>     </div>  物资申请:     /**  * 申请物资  * 后端接口  * @author   * @email   * @date 2021210-11 19:15:03  */ @RestController @RequestMapping("/juanzengdingdan") public class JuanzengdingdanController {     @Autowired     private JuanzengdingdanService juanzengdingdanService;          /**      * 后端列表      */     @RequestMapping("/page")     public R page(@RequestParam Map<String, Object> params,JuanzengdingdanEntity juanzengdingdan,         HttpServletRequest request){         String tableName = request.getSession().getAttribute("tableName").toString();         String username = (String)request.getSession().getAttribute("username");         EntityWrapper<JuanzengdingdanEntity> ew = new EntityWrapper<JuanzengdingdanEntity>();         if(tableName.equals("jigou")) {             juanzengdingdan.setJigouzhanghao((String)request.getSession().getAttribute("username"));         }         if(tableName.equals("yonghu")) {             juanzengdingdan.setYonghuzhanghao((String)request.getSession().getAttribute("username"));         }         PageUtils page = juanzengdingdanService.queryPage(params, MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, juanzengdingdan), params), params));           return R.ok().put("data", page);     }             /**      * 列表      */     @RequestMapping("/lists")     public R list( JuanzengdingdanEntity juanzengdingdan){            EntityWrapper<JuanzengdingdanEntity> ew = new EntityWrapper<JuanzengdingdanEntity>();           ew.allEq(MPUtil.allEQMapPre( juanzengdingdan, "juanzengdingdan"));          return R.ok().put("data", juanzengdingdanService.selectListView(ew));     }        /**      * 查询      */     @RequestMapping("/query")     public R query(JuanzengdingdanEntity juanzengdingdan){         EntityWrapper< JuanzengdingdanEntity> ew = new EntityWrapper< JuanzengdingdanEntity>();          ew.allEq(MPUtil.allEQMapPre( juanzengdingdan, "juanzengdingdan"));          JuanzengdingdanView juanzengdingdanView =  juanzengdingdanService.selectView(ew);         return R.ok("查询申请物资成功").put("data", juanzengdingdanView);     }             /**      * 前端详情      */     @RequestMapping("/detail/{id}")     public R detail(@PathVariable("id") Long id){         JuanzengdingdanEntity juanzengdingdan = juanzengdingdanService.selectById(id);         return R.ok().put("data", juanzengdingdan);     }              /**      * 前端保存      */     @RequestMapping("/add")     public R add(@RequestBody JuanzengdingdanEntity juanzengdingdan, HttpServletRequest request){         juanzengdingdan.setId(new Date().getTime()+new Double(Math.floor(Math.random()*1000)).longValue());         juanzengdingdan.setJuanzengshijian(new Date());         juanzengdingdanService.insert(juanzengdingdan);         return R.ok();     }       /**      * 修改      */     @RequestMapping("/update")     public R update(@RequestBody JuanzengdingdanEntity juanzengdingdan, HttpServletRequest request){         //ValidatorUtils.validateEntity(juanzengdingdan);         juanzengdingdanService.updateById(juanzengdingdan);//全部更新         return R.ok();     }          /**      * 删除      */     @RequestMapping("/delete")     public R delete(@RequestBody Long[] ids){         juanzengdingdanService.deleteBatchIds(Arrays.asList(ids));         return R.ok();     }         }  配置拦截:    @Configuration public class InterceptorConfig extends WebMvcConfigurationSupport{          @Bean     public AuthorizationInterceptor getAuthorizationInterceptor() {         return new AuthorizationInterceptor();     }          @Override     public void addInterceptors(InterceptorRegistry registry) {         registry.addInterceptor(getAuthorizationInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**");         super.addInterceptors(registry);     }          /**      * springboot 2.0配置WebMvcConfigurationSupport之后,会导致默认配置被覆盖,要访问静态资源需要重写addResourceHandlers方法      */     @Override     public void addResourceHandlers(ResourceHandlerRegistry registry) {         registry.addResourceHandler("/**")         .addResourceLocations("classpath:/resources/")         .addResourceLocations("classpath:/static/")         .addResourceLocations("classpath:/admin/")         .addResourceLocations("classpath:/front/")         .addResourceLocations("classpath:/public/");         registry.addResourceHandler("/upload/**").addResourceLocations("file:D:/work/");         super.addResourceHandlers(registry);     } }  ———————————————— 版权声明:本文为CSDN博主「java李杨勇」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_39709134/article/details/128124580 
  • [技术干货] Spring注解开发-转载
     1、Spring注解开发 1 注解开发定义Bean对象【重点】 目的:xml配置Bean对象有些繁琐,使用注解简化Bean对象的定义  问题导入 问题1:使用什么标签进行Spring注解包扫描?  问题2:@Component注解和@Controller、@Service、@Repository三个衍生注解有什么区别?  1.1 基本使用 【第一步】在applicationContext.xml中开启Spring注解包扫描  <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:context="http://www.springframework.org/schema/context"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xsi:schemaLocation="         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">      <!--扫描com.itheima包及其子包下的类中注解-->     <context:component-scan base-package="com.lfs"/> </beans> 【第二步】在类上使用@Component注解定义Bean。  //@Component定义bean @Component("bookDao") public class BookDaoImpl implements BookDao {     public void save() {         System.out.println("book dao save ...");     } } @Component public class BookServiceImpl implements BookService {     private BookDao bookDao;      public void setBookDao(BookDao bookDao) {         this.bookDao = bookDao;     }      public void save() {         System.out.println("book service save ...");         bookDao.save();     } } 补充说明:如果@Component注解没有使用参数指定Bean的名称,那么类名首字母小写就是Bean在IOC容器中的默认名称。例如:BookServiceImpl对象在IOC容器中的名称是bookServiceImpl。  【第三步】在测试类中获取Bean对象  public class AppForAnnotation {     public static void main(String[] args) {         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");         BookDao bookDao = (BookDao) ctx.getBean("bookDao");         System.out.println(bookDao);         //按类型获取bean         BookService bookService = ctx.getBean(BookService.class);         System.out.println(bookService);     } } 注意:在测试类中不要调用bookService的save方法,因为还没有给BookServiceImpl中的bookDao赋值,调用bookService的save方法会出现空指针异常。  1.2 @Component三个衍生注解 说明:加粗的注解为常用注解  Spring提供**@Component**注解的三个衍生注解 @Controller:用于表现层bean定义 @Service:用于业务层bean定义 @Repository:用于数据层bean定义 @Repository("bookDao") public class BookDaoImpl implements BookDao { }  @Service public class BookServiceImpl implements BookService { } 2 纯注解开发模式【重点】 问题导入 问题1:配置类上使用什么注解表示该类是一个配置类?  问题2:配置类上使用什么注解进行Spring注解包扫描?  2.1 纯注解开发模式介绍 Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道 Java类代替Spring核心配置文件 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cGOu29Re-1670647827838)(assets/image-20210803192052811.png)]  @Configuration注解用于设定当前类为配置类 @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式 @ComponentScan({com.itheima.service","com.lfs.dao"}) 1 读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象 //加载配置文件初始化容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //加载配置类初始化容器 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); 2.2 代码演示 【第一步】定义配置类代替配置文件  //声明当前类为Spring配置类 @Configuration //Spring注解扫描,相当于<context:component-scan base-package="com.itheima"/> @ComponentScan("com.itheima") //设置bean扫描路径,多个路径书写为字符串数组格式 //@ComponentScan({"com.itheima.service","com.lfs.dao"}) public class SpringConfig { } 【第二步】在测试类中加载配置类,获取Bean对象并使用  public class AppForAnnotation {     public static void main(String[] args) {         //AnnotationConfigApplicationContext加载Spring配置类初始化Spring容器         ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);         BookDao bookDao = (BookDao) ctx.getBean("bookDao");         System.out.println(bookDao);         //按类型获取bean         BookService bookService = ctx.getBean(BookService.class);         System.out.println(bookService);     } } 3 注解开发Bean作用范围和生命周期管理 问题导入 在类上使用什么注解定义Bean的作用范围?  3.1 bean作用范围注解配置 使用@Scope定义bean作用范围 @Repository @Scope("singleton") public class BookDaoImpl implements BookDao { } 3.2 bean生命周期注解配置 使用@PostConstruct、@PreDestroy定义bean生命周期 @Repository @Scope("singleton") public class BookDaoImpl implements BookDao {     public BookDaoImpl() {         System.out.println("book dao constructor ...");     }     @PostConstruct     public void init(){         System.out.println("book init ...");     }     @PreDestroy     public void destroy(){         System.out.println("book destory ...");     } } 注意:@PostConstruct和@PreDestroy注解是jdk中提供的注解,从jdk9开始,jdk中的javax.annotation包被移除了,也就是说这两个注解就用不了了,可以额外导入一下依赖解决这个问题。  <dependency>   <groupId>javax.annotation</groupId>   <artifactId>javax.annotation-api</artifactId>   <version>1.3.2</version> </dependency> 4 注解开发依赖注入【重点】 问题导入 问题1:请描述@Autowired注解是如何进行自动装配的?  问题2:请描述@Qualifier注解的作用  4.1 使用@Autowired注解开启自动装配模式(按类型) @Service public class BookServiceImpl implements BookService {     //@Autowired:注入引用类型,自动装配模式,默认按类型装配     @Autowired     private BookDao bookDao;      public void save() {         System.out.println("book service save ...");         bookDao.save();     } } 说明:不管是使用配置文件还是配置类,都必须进行对应的Spring注解包扫描才可以使用。@Autowired默认按照类型自动装配,如果IOC容器中同类的Bean有多个,那么默认按照变量名和Bean的名称匹配,建议使用@Qualifier注解指定要装配的bean名称  注意:自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法。  4.2 使用@Qualifier注解指定要装配的bean名称 目的:解决IOC容器中同类型Bean有多个装配哪一个的问题  @Service public class BookServiceImpl implements BookService {     //@Autowired:注入引用类型,自动装配模式,默认按类型装配     @Autowired     //@Qualifier:自动装配bean时按bean名称装配     @Qualifier("bookDao")     private BookDao bookDao;      public void save() {         System.out.println("book service save ...");         bookDao.save();     } } 注意:@Qualifier注解无法单独使用,必须配合@Autowired注解使用  4.3 使用@Value实现简单类型注入 @Repository("bookDao") public class BookDaoImpl implements BookDao {     //@Value:注入简单类型(无需提供set方法)     @Value("${name}")     private String name;      public void save() {         System.out.println("book dao save ..." + name);     } } 以上@Value注解中使用${name}从属性文件中读取name值,那么就需要在配置类或者配置文件中加载属性文件。  @Configuration @ComponentScan("com.itheima") //@PropertySource加载properties配置文件 @PropertySource({"classpath:jdbc.properties"}) //{}可以省略不写 public class SpringConfig { } 注意:@PropertySource()中加载多文件请使用数组格式配置,不允许使用通配符*  5 注解开发管理第三方Bean【重点】 问题导入 导入自己定义的配置类有几种方式?  【第一步】单独定义配置类 public class JdbcConfig {     //@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中     @Bean     public DataSource dataSource(){         DruidDataSource ds = new DruidDataSource();         ds.setDriverClassName("com.mysql.jdbc.Driver");         ds.setUrl("jdbc:mysql://localhost:3306/spring_db");         ds.setUsername("root");         ds.setPassword("root");         return ds;     } } 【第二步】将独立的配置类加入核心配置 方式1:@Import注解导入式 @Configuration @ComponentScan("com.itheima") //@Import:导入配置信息 @Import({JdbcConfig.class}) public class SpringConfig { } 方式2:@ComponentScan扫描式 @Configuration @ComponentScan({"com.itheima.config","com.itheima.service","com.itheima.dao"})  //只要com.itheima.config包扫到了就行,三个包可以合并写成com.itheima public class SpringConfig { } 6 注解开发为第三方Bean注入资源【重点】 问题导入 配置类中如何注入简单类型数据,如何注入引用类型数据?  6.1 简单类型依赖注入 public class JdbcConfig {     //1.定义一个方法获得要管理的对象     @Value("com.mysql.jdbc.Driver")     private String driver;     @Value("jdbc:mysql://localhost:3306/spring_db")     private String url;     @Value("root")     private String userName;     @Value("root")     private String password;     //2.@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中     @Bean     public DataSource dataSource(){         DruidDataSource ds = new DruidDataSource();         ds.setDriverClassName(driver);         ds.setUrl(url);         ds.setUsername(userName);         ds.setPassword(password);         return ds;     } } 说明:如果@Value()中使用了EL表达式读取properties属性文件中的内容,那么就需要加载properties属性文件。  6.2 引用类型依赖注入 //Spring会自动从IOC容器中找到BookDao对象赋值给参数bookDao变量,如果没有就会报错。 @Bean  public DataSource dataSource(BookDao bookDao){     System.out.println(bookDao);     DruidDataSource ds = new DruidDataSource();     ds.setDriverClassName(driver);     ds.setUrl(url);     ds.setUsername(userName);     ds.setPassword(password);     return ds; } 说明:引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象 ———————————————— 版权声明:本文为CSDN博主「楠慧」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_64071654/article/details/128263980 
  • [技术干货] 执行js代码(executeScript)命令使用技巧
    Js中定位操作元素1.使用控制台定位1.右击需要定位的元素,选择Copy选项,再选择Copy JS path的子选项复制上元素定位路径。 2.切换到Console面板,粘贴上前面复制的信息,即可在第二行预览定位元素的情况。 3.这里使用的是CSS的定位方式,如果觉得控制台生成的定位路径不好用,那么可以修改上图中红色字体的定位信息 2.使用XPATH方式定位xpath的通常格式是:document.evaluate('......', document).iterateNext()其中的......表示的是xpath语句xpath语句可以右击操作元素,选择Copy选项,再选择Copy XPath的子选项复制上元素定位路径。 也可以手动书写相关xpath语句,不过最好在Elements面板中通过Ctrl+f组合键唤出搜索栏(下图中红色部分),然后写上自己的xpath语句进行验证,确保定位的元素是唯一的(下图中绿色部分)。使用场景1.执行点击动作先定位操作元素,再执行click方法上图中使用了JS path2.获取元素数量1.通过querySelectorAll方法获取元素数量......使用的是CSS语法return document.querySelectorAll(".......").length在Studio中获取js的返回值需要使用return关键词 2.通过evaluate方法获取元素数量......使用的是XPATH语法return document.evaluate('......', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE).snapshotLength同理在Studio中获取js的返回值需要使用return关键词3.获取元素文本先定位操作元素,再执行获取方法,相关的方法较多,可以逐一尝试// 方法1 document.querySelector("span#content").value // 方法2 document.querySelector("span#content").innerHTML // 方法3 document.querySelector("span#content").innerText // 方法4 document.querySelector("span#content").textContent // 方法5 document.querySelector("span#content").nodeValue对于一个元素,不一定每种方法都可以获取到文本值,选择一个可用的就行 同理在Studio中获取js的返回值需要使用return关键词 更多使用场景欢迎在下面补充注意事项1.iframe框架的选取在拾取的时候,如果js操作的目标元素不在iframe中,那么可以拾取整个页面,但是如果目标元素位于某层iframe中,那么就需要具体拾取到那一层iframe元素上。
  • [技术干货] top.location.href和localtion.href有什么不同
    window.location.href、location.href是本页面跳转 parent.location.href是上一层页面跳转 top.location.href是最外层的页面跳转 top.location.href=”url” 在顶层页面打开url(跳出框架)   self.location.href=”url” 仅在本页面打开url地址   parent.location.href=”url”   在父窗口打开Url地址    this.location.href=”url”    用法和self的用法一致 if (top.location == self.location) 判断当前location 是否为顶层来 禁止frame引用  如果页面当中有自定义的frame的话, 也可以将parent self top换为自定义frame的名称 效果就是在自定义frame窗口打开url地址实际中可能这样使用        if(top !== self){             top.location.href = location.href;         }   禁止frame引用 以下是从网上找到的一个例子,不是很直观, 我加了上面那三行代码, 可以先去掉, 再加上, 看一下效果,就很清楚了 以下是top.htm 代码
  • [问题求助] GDE中js脚本里怎么设置disabled属性啊
    disabled在脚本里怎么写才规范啊,无论怎么写都是报错呢,试了几种方法需求是点击提交按钮后,将该按钮设为禁用状态,待请求发送成功后,再解除按钮限制
  • 剑指 Offer 49. 丑数 && 264. 丑数 II ●●-转载
     描述 只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。  通常 1 为第一个丑数,求按从小到大的顺序的第 n 个丑数。  示例 输入:n = 10 输出:12 解释:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是由前 10 个丑数组成的序列。  题解 1. 小顶堆 要得到从小到大的第 n 个丑数,可以使用最小堆实现。  初始时堆为空。首先将最小的丑数 1 加入堆。  每次取出堆顶元素 x,即堆中最小的丑数,由于 2x, 3x, 5x 也是丑数,因此将 2x, 3x, 5x 加入堆。  上述做法会导致堆中出现重复元素的情况。为了避免重复元素,可以使用哈希集合去重,避免相同元素多次加入堆。  在排除重复元素的情况下,第 n 次从最小堆中取出的元素即为第 n 个丑数。  时间复杂度:O ( n log ⁡ n ) O(n \log n)O(nlogn)。得到第 n 个丑数需要进行 n 次循环,每次循环都要从最小堆中取出 1 个元素以及向最小堆中加入最多 3 个元素,因此每次循环的时间复杂度是 O ( log ⁡ ( 3 n ) + 3 log ⁡ ( 3 n ) ) O(\log (3n) + 3 \log (3n))O(log(3n)+3log(3n)),总时间复杂度是 O ( n log ⁡ n ) O(n \log n)O(nlogn)。 空间复杂度:O ( n ) O(n)O(n)。空间复杂度主要取决于最小堆和哈希集合的大小,最小堆和哈希集合的大小都不会超过 3n。 class Solution { public:     int nthUglyNumber(int n) {         vector factors = {2, 3, 5};        // 因子         unordered_set hash;                // 哈希         priority_queue, greater> heap;    // 小顶堆         hash.insert(1L);         heap.push(1L);         int uglyn = 1;                                     for(int i = 1; i <= n; ++i){             long top = heap.top();             heap.pop();             uglyn = (int)top;                    // 第n个丑数             for(int factor : factors){            // 堆中最小的丑数 * 因子2/3/5                 long next = top * factor;                 if(hash.count(next) == 0){                     hash.insert(next);                     heap.push(next);                 }             }         }         return uglyn;     } }; 2. 动态规划 方法一使用最小堆,会预先存储较多的丑数,维护最小堆的过程也导致时间复杂度较高。 可以使用动态规划的方法进行优化。  定义数组 uglys,其中 uglys[i-1] 表示第 i 个丑数。 uglys[0] = 1;  如何得到其余的丑数呢? 每个丑数都有一次与 2/3/5 相乘的机会,定义三个指针 p2、p3、p5,表示下一个丑数是三个指针指向的丑数乘以对应的质因数得到的最小值。初始时,三个指针的值都是 0,每轮将对应指针执行 +1 即可。  uglys[i] = min(min(num2, num3), num5); 在进行指针判断移动操作时,对每个指针得到的结果都进行一次对比,去除重复操作,比如 5*2 与 2*5,那么 p2 和 p5 都右移。  时间复杂度:O(n)。需要计算数组中的 n 个元素,每个元素的计算都可以在 O(1) 的时间内完成。 空间复杂度:O(n) class Solution { public:     int nthUglyNumber(int n) {         vector uglys(n, 1);         int p2 = 0, p3 = 0, p5 = 0;         for(int i = 1; i < n; ++i){             int num2 = uglys[p2]*2, num3 = uglys[p3]*3, num5 = uglys[p5]*5;             uglys[i] = min(min(num2, num3), num5);             if(uglys[i] == num2) ++p2;             if(uglys[i] == num3) ++p3;             if(uglys[i] == num5) ++p5;      // 不用else,去重,2*5 跟 5*2的情况,p2与p5++         }         return uglys[n-1];     } }; ———————————————— 版权声明:本文为CSDN博主「keep_fan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_19887221/article/details/126689247 
  • [技术干货] js中数组reduce方法的使用和实现【转载】
    reduce方法定义reduce() 方法对数组中的每个元素执行一个传入的callback回调函数(升序执行,空值和已删除的除外),将其结果汇总为单个返回值。reduce方法语法arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])reduce方法参数callback自己传入的为数组中每个值 (如果没有传入 initialValue则第一个值除外)执行的函数,包含四个参数:(1)accumulator累计器累计回调的返回值; 它是上一次调用callback回调时返回的值,或初始化时initialValue的值(见于下方)。(2)currentValue数组中当前正在处理的元素。(3)index 可选数组中当前正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。(4)selfArray可选调用reduce()的源数组自身。initialValue可选作为第一次调用 callback函数时的第一个参数的值。 如果没有传入初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。reduce方法返回值函数累计处理的结果(可以是任意值,取决于自己需要什么)。reduce方法详细描述reduce为数组中的每一个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:1、accumulator 累计器2、currentValue 当前值3、currentIndex 当前值的索引4、selfArray数组本身回调函数第一次执行时,accumulator 和currentValue的取值有两种情况:如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。特别注意:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。如果调用reduce函数的数组为空且没有提供initialValue,会抛出TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。reduce方法使用示例参数累加 // 不传入initialValue参数 let arr1 = [1,3, , ,5] let newArr = arr1.reduce((acc, cur, index, selfArr) => { console.log({acc, cur, index}) return acc + cur }) console.log(newArr) // {acc: 1, cur: 3, index: 1} // {acc: 4, cur: 5, index: 4} // 9 // 传入initialValue参数 let newArr1 = arr1.reduce((acc, cur, index) => { console.log({acc, cur, index}) return acc + cur }, 0) console.log(newArr1) // {acc: 0, cur: 1, index: 0} // {acc: 1, cur: 3, index: 1} // {acc: 4, cur: 5, index: 4} // 9上述代码的最终结果都是返回数组中每个元素相加的和,区别就是第一组代码没有传入initialValue 参数,第二组传入了initialValue 参数。根据打印结果可以看出,第一组没有传入initialValue参数的代码从arr1数组中索引为1的元素开始执行callback函数,一共执行了两次,并且acc初始值为数组的第一个元素。第二组传入initialValue 参数的代码,从arr1原数组中索引值为0的元素开始执行并且acc初始值为传入的initialValue的值。两组代码都没有为arr1原数组中的空值执行callback函数。数组对象结构的参数累加 let arr2 = [ { num: 1, }, { num: 5, }, { num: 7, } ] const newArr2 = arr2.reduce((acc, cur, index) => { return acc + cur.num }, 0) console.log(newArr2) // 13上述代码是循环原数组arr2中每一项,并将每一项里面num的值进行相加,并且返回最后相加的结果。数组去重 let arr3 = [1,2,1,1,3,5,2] const newArr3 = arr3.reduce((acc, cur) => { if (!acc.includes(cur)) acc.push(cur) return acc }, []) console.log(newArr3) // [1, 2, 3, 5]上述代码 执行时初始参数传入一个空数组,然后开始从原数组arr3的第一个元素开始执行callback函数,每次都会利用数组的includes方法判断当前元素是否已经存在传入的数组里面,最后返回传入的数组赋值给acc参数。最后的结果就是已经去重好的新数组newArr3。对象分类 let arr4 = [ { name: '小红', age: 21 }, { name: '小绿', age: 20 }, { name: '小蓝', age: 20 }, { name: '大白', age: 19 } ]; const newArr4 = arr4.reduce((acc, cur, index) => { if (!acc[cur.age]) acc[cur.age] = [] acc[cur.age].push(cur) return acc }, {}) console.log(newArr4) // { // 19: [{ name: '大白', age: 19 }], // 20: [{name: "小绿", age: 20}, {name: "小蓝", age: 20}], // 21: [{name: "小红", age: 21}] // }上述代码将数据列表根据age进行分类,同样age的数据合并组成key:value形式展示出来。计算数组中元素出现的次数 let arr5 = [1,2,3,1,2,1] const newArr5 = arr5.reduce((acc, cur) => { acc[cur]? acc[cur] ++: acc[cur] = 1 return acc }, {}) console.log(newArr5) // {1: 3, 2: 2, 3: 1}上述代码利用对象中key – value数据形式来计算得出数组中每个元素出现的次数。最后在来看下空数组和数组只有一个参数时的值: // 数组为空,传入initialValue初始值时和只有一个参数没有传入初始值时 console.log([].reduce((acc, cur) => { console.log(acc, cur) return cur }, 0)) // 0 console.log([1].reduce((acc, cur) => { console.log(acc, cur) return 10 })) // 1下面根据上述描述和使用来模拟实现我们自己的reduce方法。步骤思路1、 将方法添加到Array的原型上2、 传入回调函数形参和初始值形参3、 判断initialValue 初始值是否传入4、 判断原数组的元素是不是空值,来调用callback函数5、 将每次执行的callback函数的返回值赋值给accumulator6、 返回accumulator实现代码 Array.prototype.myReduce = function(callback, initialValue) { let accumulator,initIndex, length = this.length // 判断initialValue初始参数有没有传入 if (initialValue || initialValue === 0) { // 空数组时直接返回传入的初始参数 if (length === 0) return initialValue initIndex = 0 accumulator = initialValue } else { // 空数组时报错 if (length === 0) throw new TypeError('xxxxxxxxx') // 原数组只有一个元素时,返回此元素 if (length === 1) return this[0] initIndex = 1 accumulator = this[0] } for (let index = initIndex; index < length; index++) { // 通过hasOwnProperty方法剔除空值,然后将传入的callback函数的值赋值给accumulator累计参数 if(this.hasOwnProperty(index)) accumulator = callback(accumulator, this[index], index, this) } return accumulator }测试验证 Array.prototype.myReduce = function(callback, initialValue) { let accumulator,initIndex, length = this.length // 判断initialValue初始参数有没有传入 if (initialValue || initialValue === 0) { // 空数组时直接返回传入的初始参数 if (length === 0) return initialValue initIndex = 0 accumulator = initialValue } else { // 空数组时报错 if (length === 0) throw new TypeError('xxxxxxxxx') // 原数组只有一个元素时,返回此元素 if (length === 1) return this[0] initIndex = 1 accumulator = this[0] } for (let index = initIndex; index < length; index++) { // 通过hasOwnProperty方法剔除空值,然后将传入的callback函数的值赋值给accumulator累计参数 if(this.hasOwnProperty(index)) accumulator = callback(accumulator, this[index], index, this) } return accumulator } // 不传入initialValue参数 let arr1 = [1,3, , ,5] let newArr = arr1.myReduce((acc, cur, index, selfArr) => { console.log({acc, cur, index}) return acc + cur }) console.log(newArr) // {acc: 1, cur: 3, index: 1} // {acc: 4, cur: 5, index: 4} // 9 // 传入initialValue参数 let newArr1 = arr1.myReduce((acc, cur, index) => { console.log({acc, cur, index}) return acc + cur }, 0) console.log(newArr1) // {acc: 0, cur: 1, index: 0} // {acc: 1, cur: 3, index: 1} // {acc: 4, cur: 5, index: 4} // 9 let arr2 = [ { num: 1, }, { num: 5, }, { num: 7, } ] const newArr2 = arr2.myReduce((acc, cur, index) => { return acc + cur.num }, 0) console.log(newArr2) // 13 let arr3 = [1,2,1,1,3,5,2] const newArr3 = arr3.myReduce((acc, cur) => { if (!acc.includes(cur)) acc.push(cur) return acc }, []) console.log(newArr3) // [1, 2, 3, 5] let arr4 = [ { name: '小红', age: 21 }, { name: '小绿', age: 20 }, { name: '小蓝', age: 20 }, { name: '大白', age: 19 } ]; const newArr4 = arr4.myReduce((acc, cur, index) => { if (!acc[cur.age]) acc[cur.age] = [] acc[cur.age].push(cur) return acc }, {}) console.log(newArr4) // { // 19: [{ name: '大白', age: 19 }], // 20: [{name: "小绿", age: 20}, {name: "小蓝", age: 20}], // 21: [{name: "小红", age: 21}] // } let arr5 = [1,2,3,1,2,1] const newArr5 = arr5.myReduce((acc, cur) => { acc[cur]? acc[cur] ++: acc[cur] = 1 return acc }, {}) console.log(newArr5) // {1: 3, 2: 2, 3: 1} // 数组为空,传入initialValue初始值时和只有一个参数没有传入初始值时 console.log([].myReduce((acc, cur) => { console.log(acc, cur) return cur }, 0)) // 0 console.log([1].myReduce((acc, cur) => { console.log(acc, cur) return 10 })) // 1使用自己模拟实现的方法打印结果和原方法一致。作者:绿芽链接:https://www.jianshu.com/p/a31f43462007
  • [技术干货] “结构体名”和“结构体名是个指针”的区别-转载
     经常看见下面这样的定义:  typedef struct {       int a;       double b;   }emp_i, *pemp_i;    //typedef 了两个新的数据类型(结构体),其中一个是指针方式的名字   int main(void)   {           char i = 'y';       emp_i  a1;    //emp_i 声明的a1是一个实体,声明了就已经有存储空间了       pemp_i  b1 = &a1;  //pemp_i 声明的b1是一个指针(但这里不用加*号,因为pemp_i已经被指定为指针),它可以指向一个struct a 的实体。        a1.a++;      //a1的元素访问方式  实体方式        b1->a++;   //b1的访问方式  指针方式   }  也就是说,用结构体名字去定义声明的变量是一个真正的变量,他在内存中分配有自己的存储空间;而是用指针去形式定义的变量是一个指针,使用的时候给他赋予一个结构体变量的地址。  访问方式不一样:结构体变量直接访问使用实体方式,用点;结构体变量使用指针方式,如上面例子所示。 ———————————————— 版权声明:本文为CSDN博主「微电子学与固体电子学-俞驰」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/appleyuchi/article/details/126641509 
  • [技术干货] UserAgent的使用方法
    1、UserAgent的简介      User Agent即用户代理,简称为UA,是一种特殊的字符串头,会使得服务器能够识别客户使用的操作系统、版本、CPU 类型、浏览器版本、浏览器渲染引擎、浏览器语言、浏览器插件等等,是不感觉很厉害的样子,通过这个串头,我们就可以进行获得很多的信息,从而进行相关业务的处理。      在server抓包的时候,会经常碰到直接使用wget或者curl被服务器拒绝的状况,这时候只需要通过增加一个user-agent串头进行模拟就可以通过了。2、查看User Agent的方法2.1 通过js获取      在浏览器地址栏中输入以下代码navigator.userAgent      或者window.navigator.userAgent      进行获取相关信息,获取后的信息会是这个样子的:'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/xxx (KHTML, like Gecko) Chrome/xxx Safari/xxx'2.2 通过Chrome开发者模式获取      打开chrome开发者模式(快捷键是F12),或者在网页上右键选择检查(快捷键是Ctrl+Shift+I),在Network栏中找到需要查询的请求,在Headers的最后可以看到User-Agent的相关信息了。这种方法可以通过模拟机型,在选择模拟的设备机型后,找到相应的请求就可以找到这类机型所对应的User-Agent信息了。3、User-Agent的应用3.1 User-Agent在js中的应用      其中判断是否是微信环境,通常我们会通过window.navigator.userAgent获取User-Agent串头后进行转小写,然后通过正则匹配/MicroMessenger/i是否为'micromessenger'来判断是否是微信内部浏览器从而判断是否是微信环境,这里如果不加window的话Android机可能会判断不了是否是微信,所以还是加上比较保险。function isWX() { var ua = window.navigator.userAgent.toLowerCase(); if (ua.match(/MicroMessenger/i) == 'micromessenger') { return true; } else { return false; }} 3.2 User-Agent在java中的应用       通常我们会通过reques请求中获取header中的user-Agent元素,然后进行转小写,在获取到信息之后,我们就可以通过这个User-Agent串头信息来进行环境判断了,其中包含micromessenger则为微信内部浏览器标识,即微信内部环境,在微信内部环境又包括小程序和企微,我们通过判断User-Agent串头信息是否包含wxwork元素来判断是否为企微环境,通过判断User-Agent串头信息是否包含miniprogram来判断是否为小程序环境下。String userAgent = request.getHeader("user-agent").toLowerCase();if (userAgent.indexOf("micromessenger") < 0) {// 非微信 return true;} else{ if (userAgent.indexOf("wxwork") > 0) { // 企业微信客户端 return true; }else if(userAgent.indexOf("miniprogram") > 0){//小程序下 return true; }}以上就是User-Agent的相关应用和总结。
  • [技术干货] 初识Webpack
    1. 摘要Webpack是一种前端资源构建工具,一个静态模块打包器。在Webpack看来,前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理,当Webpack处理应用程序时,它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源。Webpack打包流程图如图1-1所示。图1-1 Webpack打包流程图2. Webpack五个核心概念2.1 Entry入口(Entry)指示Webpack以哪个文件作为入口起点分析构建内部依赖图并进行打包。2.2 Output输出(Output)指示Webpack打包后的资源bundles输出到哪里去,以及如何命名。2.3 LoaderLoader让Webpack能够去处理那些非JavaScript语言的文件,Webpack本身只能理解JavaScript。2.4 Plugins插件(Plugins)可以用于执行范围更广的任务,插件的范围包括从打包和压缩,一直到重新定义环境中的变量等。2.5 Mode模式(Mode)指示Webpack使用相应模式的配置。分为development和production两种模式,下面分别进行简述。development: 开发模式,能让代码本地运行的环境,会将process.env.NODE_ENV的值设为development,同时启用NamedChunksPlugin和NamedModulesPlugin插件;production: 生产模式,能让代码优化运行的环境,会将process.env.NODE_ENV的值设为production,同时启用FlagDependencyUsagePlugin、FlagIncludedChunksPlugin、ModuleConcatenationPlugin、NoEmitOnErrorsPlugin、OccurrenceOrderPlugin、SideEffectsFlagPlugin和UglifyJsPlugin插件。3. Wbepack配置3.1 webpack.config.js文件webpack.config.js是webpack的配置文件,用来指示webpack工作,运行webpack指令时,会加载里面的配置,所有构建工具都是基于nodejs平台运行的,默认采用commonjs模块化。webpack.config.js基础配置如图3-1所示。图3-1 webpack.config.js基础配置3.2 devServer配置开发服务器(devServer)用来实现自动化(自动编译、自动打开浏览器、自动刷新浏览器),只会在内存中编译打包,不会有任何文件输出,本地安装webpack-dev-server后,通过npx webpack-dev-server命令启动devServer,核心代码如图3-2所示。图3-2 devServer配置核心代码3.3 打包html/样式/图片/其它资源打包不同的资源会使用不同的loader和插件,打包html/样式/图片/其它资源的流程如下所述。3.3.1 打包html资源1.下载html-webpack-plugin插件;2.引入html-webpack-plugin插件;3.使用html-webpack-plugin插件,并进行相应配置。3.3.2 打包样式资源不同的样式文件需要配置不同的loader1.下载loader;2.配置loader,css样式文件使用css-loader和style-loader,less文件使用less-loader、css-loader和style-loader。其中css-loader的作用是将css文件变成commonjs模块加载到js文件中,style-loader的作用是创建style标签,将js中的样式资源插入进去,添加到head中生效。3.3.3 打包图片资源1.下载url-loader,file-loader2.配置loader3.3.4 打包其它资源1.下载file-loader2. 配置loader,配置该loader作用于不为html/css/less/js的其他文件3.4 提取css成单独文件/css兼容性处理/压缩css3.4.1  提取css成单独文件样式文件打包后会默认和js文件一起输出,可以通过插件将打包后的css文件单独输出,流程如下所述。1.下载mini-css-extract-plugin插件2.引用该插件3.配置3.4.2 css兼容性处理1.下载postcss-loader和postcss-preset-env2.在package.json中browsetslist属性中分别对开发环境和生产环境进行兼容性配置,设置支持样式的浏览器版本3.通过postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式。3.4.3 压缩css1.下载optimize-css-assets-webpack-plugin插件2.引用该插件3.使用该插件3.5 js语法检查eslint/js兼容性处理/js压缩3.5.1 js语法检查eslint1.下载eslint-loader和eslint2.在package.json中的eslintConfig中进行配置3.配置eslint-loader,其中只需检测js文件并要排除第三方库,只检测自己写的源代码,同时可在options配置中设置fix:true,自动修复eslint的错误。3.5.2 js兼容性处理    1.下载babel-loader、@babel/core、@babel/preset-env,通过@babel/preset-env做基本的js兼容性处理,然后通过corejs做前面无法实现的兼容性处理,并实现按需加载    2. 配置loaderjs兼容性处理核心代码如图3-3所示图3-3 js兼容性处理核心代码3.5.3 js压缩mode设置为production生产环境时会自动压缩js代码。4. webpack性能优化可以从开发环境和生产环境分别对webpack进行性能优化。其中开发环境主要考虑从打包构建速度和代码调试两个方面进行优化,生产环境主要考虑从打包构建速度和代码运行性能这两个方面进行优化。下面简单介绍下开发环境上通过HMR提升构建速度。4.1 HMR    HMR(热模块替换),作用是一个模块发生变化后,只会更新打包这一个模块而不是所有模块,通过在devServer中设置hot:true属性启动HMR功能。其中对于样式文件,可以使用HMR功能,因为style-loader内部实现了;对于js文件,默认不能使用HMR功能,解决方法:修改入口文件js代码,添加支持HMR功能的代码,另外HMR只能处理非入口js文件的其他文件,对入口文件并不能生效,因为一旦入口文件更新,入口文件引入的其他文件一定会被重新加载;对于html文件,默认不能使用HMR功能,同时会导致html文件不能热更新,解决方法:修改entry入口文件,将html文件引入,只能解决html文件不能热更新的问题。js文件支持HMR功能的核心代码如图4-1所示。图4-1 js文件支持HMR功能核心代码4.2  HMR效果在入口index.js文件中引入print.js文件,运行npx webpack-devserver后,页面如图4-2所示。4-2 初始页面修改print.js文件后,只会重新加载print.js文件,而不会重新加载index.js文件,HMR效果如图4-3所示。4-3 HMR效果图
总条数:85 到第
上滑加载中