首页 文章 精选 留言 我的

精选列表

搜索[响应],共10003篇文章
优秀的个人博客,低调大师

JeecgBoot 2.x 版本 SQL 漏洞补丁发布,响应零日漏洞修复计划

漏洞编码:HW21-0499 产品名字:JeecgBoot低代码平台 问题: JEECG系统存在SQL注入0day漏洞 处理情况: 已经处理 处理方案: 针对存在SQL漏洞注入风险的接口,采用加签名认证的方式进行安全验证。 加签规则逻辑: 接口参数 + 自定义密钥串(正式发布自行修改)+ 年月日时分秒时间戳。 补丁包下载:https://pan.baidu.com/s/1xXlPYYQET80z-XqkFG-sGQ提取码:fnxb JeecgBoot 是一款基于代码生成器的低代码平台!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue,Mybatis-plus,Shiro,JWT 支持微服务。强大的代码生成器让前后端代码一键生成! JeecgBoot引领低代码开发模式(OnlineCoding-> 代码生成-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省成本,同时又不失灵活性!

优秀的个人博客,低调大师

APIJSON 4.6.0 发布 腾讯项目百万数据 6s 响应(2.3KW 大表)

在 2.3KW 记录大表中查询 LIMIT 1000000(100W) ---------- | ---------- | ---------- | ---------- | ------------- Total | Received | Time Total | Time Spent | Current Speed 72.5M | 72.5M | 0:00:05 | 0:00:05 | 20.0M /get >> http请求结束:5624 APIJSON 4.6.0 更新内容 解决 bug 解决 "toId%": "0,10" 等连续范围报错 value 类型不合法; 解决 "id{}@": "[]/Moment/praiseUserIdList" 等引用赋值的值有时类型为 List 时报错; 解决 "key<>": "a" 这种包含字符串的格式报错,从原来要用 "" 包装简化成直接写即可; 增强安全 对 MySQL 的 DELETE 和 PUT 强制加 LIMIT,限制一次操作记录的数量; 提升性能 通过缓存及复用数组主表 ObjectParser 来大幅提升大量数据的数组内主表的查询性能; 通过减少不必要的 newSQLConfig 及 getSQL 等步骤来大幅提升大量数据的数组内主表的查询性能; 对比 4.5.2 在 Log.DEBUG = true(开启日志)的情况下 TestRecord[] 耗时降低至原来 24%,性能提升 300% 至原来 4 倍; Moment[] 耗时降低至原来 33%,性能提升 200% 至原来 3 倍; 朋友圈列表耗时降低至原来 77%,性能提升 23% 至原来 1.2 倍。 其中每个数组都按 100 条来测试,如果每页数量更大或每项数据量更大,则提升会更加明显。 腾讯 CSIG 某项目线上生产环境实测 Log.DEBUG = false 时2.3KW 大表查询 LIMIT 100 相比原来从 2s 降到 164ms 提升 11 倍; LIMIT 1000 相比原来从 30s 降到 197ms 提升 151 倍; LIMIT 10000(一次 /get 1W 条记录) 整个网络请求耗时仅 633ms; LIMIT 1000000(一次 /get 100W 条记录共 72.5M 数据) 整个网络请求耗时仅 5.624s。 具体见Release 发布版本。 APIJSON 简介 APIJSON 是一种专为 API 而生的 JSON 网络传输协议 以及 基于这套协议实现的 ORM 库。 为 简单的增删改查、复杂的查询、简单的事务操作 提供了完全自动化的万能 API。 能大幅降低开发和沟通成本,简化开发流程,缩短开发周期。 适合中小型前后端分离的项目,尤其是 BaaS、Serverless、互联网创业项目和企业自用项目。 为什么选择 APIJSON? 解决十大痛点(APIJSON 大幅提振开发效率、强力杜绝联调扯皮、巧妙规避文档缺陷、非常节省流量带宽 等) 开发提速巨大(CRUD 零代码热更新自动化,APIJSONBoot 对比 SSM、SSH 等保守估计可提速 20 倍以上) 腾讯官方开源(使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告) 社区影响力大(GitHub 9.9K Star 在 350WJava 项目中排名前 150,远超 FLAG, BAT 等国内外绝大部分开源项目) 各项荣誉成就(腾讯开源五个第一、腾讯首个 GVP 获奖项目、腾讯后端项目 Star 第一、GitHub Java 周榜第一 等) 多样用户案例(腾讯内部用户包含 互娱、音乐、云与智慧,外部用户包含 500 强上市公司、数千亿资本国企 等) 适用场景广泛(社交聊天、阅读资讯、影音视频、办公学习 等各种 App、网站、公众号、小程序 等非金融类项目) 周边生态丰富(Android, iOS, Web 等各种 Demo、继承 JSON 的海量生态、零代码 接口测试 和 单元测试 工具等) 文档视频齐全(项目介绍、快速上手、安装部署 等后端、前端、客户端的 图文解说、视频教程、代码注释 等) 功能丰富强大(增删改查、分页排序、分组聚合、各种 JOIN、各种子查询、跨库跨表、性能分析等零代码实现) 使用安全简单(自动增删改查、自动生成文档、自动管理版本、自动控制权限、自动校验参数、自动防SQL注入等) 灵活定制业务(在后端编写 远程函数,可以拿到 session、version、当前 JSON 对象 等,然后自定义处理) 高质可靠代码(代码严谨规范,商业分析软件源伞 Pinpoint 代码扫描报告平均每行代码 Bug 率低至 0.15%) 兼容各种项目(对各类 Web 框架集成友好且提供 SpringBoot, JFinal 的 Demo,协议不限 HTTP,与其它库无冲突) 工程轻量小巧(仅依赖 fastjson,Jar 仅 280KB,Java 文件仅 59 个共 13719 行代码,例如 APIJSONORM 4.3.1) 多年持续迭代(自 2016 年开源至今已连续维护 4 年,累计 2000+ Commits、70+ Releases,不断更新迭代中...) APIJSON 生态项目 APIAuto敏捷开发最强大易用的 HTTP 接口工具,机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释 UnitAuto机器学习单元测试平台,零代码、全方位、自动化 测试 方法/函数 的正确性和可用性 APIJSON.NETC# 版 APIJSON ,支持 MySQL, PostgreSQL, SQL Server, Oracle, SQLite apijson-phpPHP 版 APIJSON,基于 ThinkPHP,支持 MySQL, PostgreSQL, SQL Server, Oracle 等 apijson-nodeNode.ts 版 APIJSON,提供 nestjs 和 typeorm 的 Demo,支持 MySQL, PostgreSQL, SQL Server, Oracle uliweb-apijsonPython 版 APIJSON,支持 MySQL, PostgreSQL, SQL Server, Oracle, SQLite 等 APIJSONParser第三方 APIJSON 解析器,将 JSON 动态解析成 SQL ApiJsonByJFinal整合 APIJSON 和 JFinal 的 Demo SpringServer1.2-APIJSON智慧党建服务器端,提供 上传 和 下载 文件的接口 apijson-builder一个方便为 APIJSON 构建 RESTful 请求的 JavaScript 库 感谢热心的作者们的贡献,点 ⭐Star 鼓励他们继续完善吧^_^ 腾讯 APIJSON - 零代码接口与文档 ORM 库 https://gitee.com/Tencent/APIJSON

优秀的个人博客,低调大师

vue.js响应式原理解析与实现—实现v-model与{{}}指令

上次我们已经分析了vue.js是通过Object.defineProperty以及发布订阅模式来进行数据劫持和监听,并且实现了一个简单的demo。今天,我们就基于上一节的代码,来实现一个MVVM类,将其与html结合在一起,并且实现v-model以及{{}}语法。 tips:本节新增代码(去除注释)在一百行左右。使用的Observer和Watcher都是延用上一节的代码,没有修改。 接下来,让我们一步步来,实现一个MVVM类。 构造函数 首先,一个MVVM的构造函数如下(和vue.js的构造函数一样): class MVVM { constructor({ data, el }) { this.data = data; this.el = el; this.init(); this.initDom(); } } 和vue.js一样,有它的data属性以及el元素。 初始化操作 vue.js可以通过this.xxx的方法来直接访问this.data.xxx的属性,这一点是怎么做到的呢?其实答案很简单,它是通过Object.defineProperty来做手脚,当你访问this.xxx的时候,它返回的其实是this.data.xxx。当你修改this.xxx值的时候,其实修改的是this.data.xxx的值。具体可以看如下代码: class MVVM { constructor({ data, el }) { this.data = data; this.el = el; this.init(); this.initDom(); } // 初始化 init() { // 对this.data进行数据劫持 new Observer(this.data); // 传入的el可以是selector,也可以是元素,因此我们要在这里做一层处理,保证this.$el的值是一个元素节点 this.$el = this.isElementNode(this.el) ? this.el : document.querySelector(this.el); // 将this.data的属性都绑定到this上,这样用户就可以直接通过this.xxx来访问this.data.xxx的值 for (let key in this.data) { this.defineReactive(key); } } defineReactive(key) { Object.defineProperty(this, key, { get() { return this.data[key]; }, set(newVal) { this.data[key] = newVal; } //前端全栈学习交流圈:866109386 })//面向1-3年前端开发人员 }//帮助突破技术瓶颈,提升思维能力。 // 是否是属性节点 isElementNode(node) { return node.nodeType === 1; } } 在完成初始化操作后,我们需要对this.$el的节点进行编译。目前我们要实现的语法有v-model和{{}}语法,v-model这个属性只可能会出现在元素节点的attributes里,而{{}}语法则是出现在文本节点里。 fragment 在对节点进行编译之前,我们先考虑一个现实问题:如果我们在编译过程中直接操作DOM节点的话,每一次修改DOM都会导致DOM的回流或重绘,而这一部分性能损耗是很没有必要的。因此,我们可以利用fragment,将节点转化为fragment,然后在fragment里编译完成后,再将其放回到页面上。 class MVVM { constructor({ data, el }) { this.data = data; this.el = el;//前端全栈交流学习圈:866109386 this.init();//针对1-3年前端开发人员 this.initDom();//帮助突破技术瓶颈,提升思维能力。 } initDom() { const fragment = this.node2Fragment(); this.compile(fragment); // 将fragment返回到页面中 document.body.appendChild(fragment); } // 将节点转为fragment,通过fragment来操作DOM,可以获得更高的效率 // 因为如果直接操作DOM节点的话,每次修改DOM都会导致DOM的回流或重绘,而将其放在fragment里,修改fragment不会导致DOM回流和重绘 // 当在fragment一次性修改完后,在直接放回到DOM节点中 node2Fragment() { const fragment = document.createDocumentFragment(); let firstChild; while(firstChild = this.$el.firstChild) { fragment.appendChild(firstChild); } return fragment; } } 实现v-model 在将node节点转为fragment后,我们来对其中的v-model语法进行编译。 由于v-model语句只可能会出现在元素节点的attributes里,因此,我们先判断该节点是否为元素节点,若为元素节点,则判断其是否是directive(目前只有v-model),若都满足的话,则调用CompileUtils.compileModelAttr来编译该节点。 编译含有v-model的节点主要有两步: 为元素节点注册input事件,在input事件触发的时候,更新vm(this.data)上对应的属性值。 对v-model依赖的属性注册一个Watcher函数,当依赖的属性发生变化,则更新元素节点的value。 class MVVM { constructor({ data, el }) { this.data = data; this.el = el; this.init(); this.initDom(); } initDom() { const fragment = this.node2Fragment(); this.compile(fragment); // 将fragment返回到页面中 document.body.appendChild(fragment); } compile(node) { if (this.isElementNode(node)) { // 若是元素节点,则遍历它的属性,编译其中的指令 const attrs = node.attributes; Array.prototype.forEach.call(attrs, (attr) => { if (this.isDirective(attr)) { CompileUtils.compileModelAttr(this.data, node, attr) } }) } // 若节点有子节点的话,则对子节点进行编译 if (node.childNodes && node.childNodes.length > 0) { Array.prototype.forEach.call(node.childNodes, (child) => { this.compile(child); }) } } // 是否是属性节点 isElementNode(node) { return node.nodeType === 1; } // 检测属性是否是指令(vue的指令是v-开头) isDirective(attr) { return attr.nodeName.indexOf('v-') >= 0; } } const CompileUtils = { // 编译v-model属性,为元素节点注册input事件,在input事件触发的时候,更新vm对应的值。 // 同时也注册一个Watcher函数,当所依赖的值发生变化的时候,更新节点的值 compileModelAttr(vm, node, attr) { const { value: keys, nodeName } = attr; node.value = this.getModelValue(vm, keys); // 将v-model属性值从元素节点上去掉 node.removeAttribute(nodeName); node.addEventListener('input', (e) => { this.setModelValue(vm, keys, e.target.value); }); new Watcher(vm, keys, (oldVal, newVal) => { node.value = newVal; }); }, /* 解析keys,比如,用户可以传入 * <input v-model="obj.name" /> * 这个时候,我们在取值的时候,需要将"obj.name"解析为data[obj][name]的形式来获取目标值 */ parse(vm, keys) { keys = keys.split('.'); let value = vm; keys.forEach(_key => { value = value[_key]; }); return value; }, // 根据vm和keys,返回v-model对应属性的值 getModelValue(vm, keys) { return this.parse(vm, keys); }, // 修改v-model对应属性的值 setModelValue(vm, keys, val) { keys = keys.split('.'); let value = vm; for(let i = 0; i < keys.length - 1; i++) { value = value[keys[i]]; } value[keys[keys.length - 1]] = val; }, } 实现{{}}语法 {{}}语法只可能会出现在文本节点中,因此,我们只需要对文本节点做处理。如果文本节点中出现{{key}}这种语句的话,我们则对该节点进行编译。在这里,我们可以通过下面这个正则表达式来对文本节点进行处理,判断其是否含有{{}}语法。 const textReg = /\{\{\s*\w+\s*\}\}/gi; // 检测{{name}}语法 console.log(textReg.test('sss')); console.log(textReg.test('aaa{{ name }}')); console.log(textReg.test('aaa{{ name }} {{ text }}')); 若含有{{}}语法,我们则可以对其处理,由于一个文本节点可能出现多个{{}}语法,因此编译含有{{}}语法的文本节点主要有以下两步: 找出该文本节点中所有依赖的属性,并且保留原始文本信息,根据原始文本信息还有属性值,生成最终的文本信息。比如说,原始文本信息是"test {{test}} {{name}}",那么该文本信息依赖的属性有this.data.test和this.data.name,那么我们可以根据原本信息和属性值,生成最终的文本。 为该文本节点所有依赖的属性注册Watcher函数,当依赖的属性发生变化的时候,则更新文本节点的内容。 class MVVM { constructor({ data, el }) { this.data = data; this.el = el; this.init(); this.initDom(); } initDom() { const fragment = this.node2Fragment(); this.compile(fragment); // 将fragment返回到页面中 document.body.appendChild(fragment); } compile(node) { const textReg = /\{\{\s*\w+\s*\}\}/gi; // 检测{{name}}语法 if (this.isTextNode(node)) { // 若是文本节点,则判断是否有{{}}语法,如果有的话,则编译{{}}语法 let textContent = node.textContent; if (textReg.test(textContent)) { // 对于 "test{{test}} {{name}}"这种文本,可能在一个文本节点会出现多个匹配符,因此得对他们统一进行处理 // 使用 textReg来对文本节点进行匹配,可以得到["{{test}}", "{{name}}"]两个匹配值 const matchs = textContent.match(textReg); CompileUtils.compileTextNode(this.data, node, matchs); } } // 若节点有子节点的话,则对子节点进行编译 if (node.childNodes && node.childNodes.length > 0) { Array.prototype.forEach.call(node.childNodes, (child) => { this.compile(child); }) } } // 是否是文本节点 isTextNode(node) { return node.nodeType === 3; } } const CompileUtils = { reg: /\{\{\s*(\w+)\s*\}\}/, // 匹配 {{ key }}中的key // 编译文本节点,并注册Watcher函数,当文本节点依赖的属性发生变化的时候,更新文本节点 compileTextNode(vm, node, matchs) { // 原始文本信息 const rawTextContent = node.textContent; matchs.forEach((match) => { const keys = match.match(this.reg)[1]; console.log(rawTextContent); new Watcher(vm, keys, () => this.updateTextNode(vm, node, matchs, rawTextContent)); }); this.updateTextNode(vm, node, matchs, rawTextContent); }, // 更新文本节点信息 updateTextNode(vm, node, matchs, rawTextContent) { let newTextContent = rawTextContent; matchs.forEach((match) => { const keys = match.match(this.reg)[1]; const val = this.getModelValue(vm, keys); newTextContent = newTextContent.replace(match, val); }) node.textContent = newTextContent; } } 结语 这样,一个具有v-model和{{}}功能的MVVM类就已经完成了 这里也有一个简单的样例(忽略样式)。 接下来的话,可能会继续实现computed属性,v-bind方法,以及支持在{{}}里面放表达式。如果觉得这个文章对你有帮助的话,麻烦点个赞,嘻嘻。 最后,贴上所有的代码: class Observer { constructor(data) { // 如果不是对象,则返回 if (!data || typeof data !== 'object') { return; } this.data = data; this.walk(); } // 对传入的数据进行数据劫持 walk() { for (let key in this.data) { this.defineReactive(this.data, key, this.data[key]); } } // 创建当前属性的一个发布实例,使用Object.defineProperty来对当前属性进行数据劫持。 defineReactive(obj, key, val) { // 创建当前属性的发布者 const dep = new Dep(); /* * 递归对子属性的值进行数据劫持,比如说对以下数据 * let data = { * name: 'cjg', * obj: { * name: 'zht', * age: 22, * obj: { * name: 'cjg', * age: 22, * } * }, * }; * 我们先对data最外层的name和obj进行数据劫持,之后再对obj对象的子属性obj.name,obj.age, obj.obj进行数据劫持,层层递归下去,直到所有的数据都完成了数据劫持工作。 */ new Observer(val); Object.defineProperty(obj, key, { get() { // 若当前有对该属性的依赖项,则将其加入到发布者的订阅者队列里 if (Dep.target) { dep.addSub(Dep.target); } return val; }, set(newVal) { if (val === newVal) { return; } val = newVal; new Observer(newVal); dep.notify(); } }) } } // 发布者,将依赖该属性的watcher都加入subs数组,当该属性改变的时候,则调用所有依赖该属性的watcher的更新函数,触发更新。 class Dep { constructor() { this.subs = []; } addSub(sub) { if (this.subs.indexOf(sub) < 0) { this.subs.push(sub); } } notify() { this.subs.forEach((sub) => { sub.update(); }) } } Dep.target = null; // 观察者 class Watcher { /** *Creates an instance of Watcher. * @param {*} vm * @param {*} keys * @param {*} updateCb * @memberof Watcher */ constructor(vm, keys, updateCb) { this.vm = vm; this.keys = keys; this.updateCb = updateCb; this.value = null; this.get(); } // 根据vm和keys获取到最新的观察值 get() { // 将Dep的依赖项设置为当前的watcher,并且根据传入的keys遍历获取到最新值。 // 在这个过程中,由于会调用observer对象属性的getter方法,因此在遍历过程中这些对象属性的发布者就将watcher添加到订阅者队列里。 // 因此,当这一过程中的某一对象属性发生变化的时候,则会触发watcher的update方法 Dep.target = this; this.value = CompileUtils.parse(this.vm, this.keys); Dep.target = null; return this.value; } update() { const oldValue = this.value; const newValue = this.get(); if (oldValue !== newValue) { this.updateCb(oldValue, newValue); } } } class MVVM { constructor({ data, el }) { this.data = data; this.el = el; this.init(); this.initDom(); } // 初始化 init() { // 对this.data进行数据劫持 new Observer(this.data); // 传入的el可以是selector,也可以是元素,因此我们要在这里做一层处理,保证this.$el的值是一个元素节点 this.$el = this.isElementNode(this.el) ? this.el : document.querySelector(this.el); // 将this.data的属性都绑定到this上,这样用户就可以直接通过this.xxx来访问this.data.xxx的值 for (let key in this.data) { this.defineReactive(key); } } initDom() { const fragment = this.node2Fragment(); this.compile(fragment); document.body.appendChild(fragment); } // 将节点转为fragment,通过fragment来操作DOM,可以获得更高的效率 // 因为如果直接操作DOM节点的话,每次修改DOM都会导致DOM的回流或重绘,而将其放在fragment里,修改fragment不会导致DOM回流和重绘 // 当在fragment一次性修改完后,在直接放回到DOM节点中 node2Fragment() { const fragment = document.createDocumentFragment(); let firstChild; while(firstChild = this.$el.firstChild) { fragment.appendChild(firstChild); } return fragment; } defineReactive(key) { Object.defineProperty(this, key, { get() { return this.data[key]; }, set(newVal) { this.data[key] = newVal; } }) } compile(node) { const textReg = /\{\{\s*\w+\s*\}\}/gi; // 检测{{name}}语法 if (this.isElementNode(node)) { // 若是元素节点,则遍历它的属性,编译其中的指令 const attrs = node.attributes; Array.prototype.forEach.call(attrs, (attr) => { if (this.isDirective(attr)) { CompileUtils.compileModelAttr(this.data, node, attr) } }) } else if (this.isTextNode(node)) { // 若是文本节点,则判断是否有{{}}语法,如果有的话,则编译{{}}语法 let textContent = node.textContent; if (textReg.test(textContent)) { // 对于 "test{{test}} {{name}}"这种文本,可能在一个文本节点会出现多个匹配符,因此得对他们统一进行处理 // 使用 textReg来对文本节点进行匹配,可以得到["{{test}}", "{{name}}"]两个匹配值 const matchs = textContent.match(textReg); CompileUtils.compileTextNode(this.data, node, matchs); } } // 若节点有子节点的话,则对子节点进行编译。 if (node.childNodes && node.childNodes.length > 0) { Array.prototype.forEach.call(node.childNodes, (child) => { this.compile(child); }) } } // 是否是属性节点 isElementNode(node) { return node.nodeType === 1; } // 是否是文本节点 isTextNode(node) { return node.nodeType === 3; } isAttrs(node) { return node.nodeType === 2; } // 检测属性是否是指令(vue的指令是v-开头) isDirective(attr) { return attr.nodeName.indexOf('v-') >= 0; } } const CompileUtils = { reg: /\{\{\s*(\w+)\s*\}\}/, // 匹配 {{ key }}中的key // 编译文本节点,并注册Watcher函数,当文本节点依赖的属性发生变化的时候,更新文本节点 compileTextNode(vm, node, matchs) { // 原始文本信息 const rawTextContent = node.textContent; matchs.forEach((match) => { const keys = match.match(this.reg)[1]; console.log(rawTextContent); new Watcher(vm, keys, () => this.updateTextNode(vm, node, matchs, rawTextContent)); }); this.updateTextNode(vm, node, matchs, rawTextContent); }, // 更新文本节点信息 updateTextNode(vm, node, matchs, rawTextContent) { let newTextContent = rawTextContent; matchs.forEach((match) => { const keys = match.match(this.reg)[1]; const val = this.getModelValue(vm, keys); newTextContent = newTextContent.replace(match, val); }) node.textContent = newTextContent; }, // 编译v-model属性,为元素节点注册input事件,在input事件触发的时候,更新vm对应的值。 // 同时也注册一个Watcher函数,当所依赖的值发生变化的时候,更新节点的值 compileModelAttr(vm, node, attr) { const { value: keys, nodeName } = attr; node.value = this.getModelValue(vm, keys); // 将v-model属性值从元素节点上去掉 node.removeAttribute(nodeName); new Watcher(vm, keys, (oldVal, newVal) => { node.value = newVal; }); node.addEventListener('input', (e) => { this.setModelValue(vm, keys, e.target.value); }); }, /* 解析keys,比如,用户可以传入 * let data = { * name: 'cjg', * obj: { * name: 'zht', * }, * }; * new Watcher(data, 'obj.name', (oldValue, newValue) => { * console.log(oldValue, newValue); * }) * 这个时候,我们需要将keys解析为data[obj][name]的形式来获取目标值 */ parse(vm, keys) { keys = keys.split('.'); let value = vm; keys.forEach(_key => { value = value[_key]; }); return value; }, // 根据vm和keys,返回v-model对应属性的值 getModelValue(vm, keys) { return this.parse(vm, keys); }, // 修改v-model对应属性的值 setModelValue(vm, keys, val) { keys = keys.split('.'); let value = vm; for(let i = 0; i < keys.length - 1; i++) { value = value[keys[i]]; } value[keys[keys.length - 1]] = val; }, }

优秀的个人博客,低调大师

SpringBoot2.0响应式编程系列(二)-函数式编程和lambda表达式

函数接口 方法引用 package lambda; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.IntUnaryOperator; class Dog { private String name = "哮天犬"; /** * 默认10斤狗粮 */ private int food = 10; public Dog() { } /** * 带参数的构造函数 * * @param name */ public Dog(String name) { this.name = name; } /** * 狗叫,静态方法 * * @param dog */ public static void bark(Dog dog) { System.out.println(dog + "叫了"); } /** * 吃狗粮 JDK * * 默认会把当前实例传入到非静态方法,参数名为this,位置是第一个; * * @param num * @return 还剩下多少斤 */ public int eat(int num) { System.out.println("吃了" + num + "斤狗粮"); this.food -= num; return this.food; } @Override public String toString() { return this.name; } } /** * @author shishusheng */ public class MethodRefrenceDemo { public static void main(String[] args) { Dog dog = new Dog(); dog.eat(3); // 方法引用 Consumer<String> consumer = System.out::println; consumer.accept("接受的数据"); // 静态方法的方法引用 Consumer<Dog> consumer2 = Dog::bark; consumer2.accept(dog); // 非静态方法,使用对象实例的方法引用 // Function<Integer, Integer> function = dog::eat; // UnaryOperator<Integer> function = dog::eat; IntUnaryOperator function = dog::eat; // dog置空,不影响下面的函数执行,因为java 参数是传值 dog = null; System.out.println("还剩下" + function.applyAsInt(2) + "斤"); // // // 使用类名来方法引用 // BiFunction<Dog, Integer, Integer> eatFunction = Dog::eat; // System.out.println("还剩下" + eatFunction.apply(dog, 2) + "斤"); // // // 构造函数的方法引用 // Supplier<Dog> supplier = Dog::new; // System.out.println("创建了新对象:" + supplier.get()); // // // 带参数的构造函数的方法引用 // Function<String, Dog> function2 = Dog::new; // System.out.println("创建了新对象:" + function2.apply("旺财")); // 测试java变量是传值还是穿引用 List<String> list = new ArrayList<>(); test(list); System.err.println(list); } private static void test(List<String> list) { list = null; } } 类型推断 image.png

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Oracle

Oracle

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

JDK

JDK

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。