Question List in May, 2021
🐦 The birds singing in the morning, everything is ready to get up in this summer.
“在为卖而买的过程中,开端和终结是一样的,都是货币,都是交换价值,单是由于这一点,这种运动就已经是没有止境的了。…因此,每一次为卖而买所完成的循环的终结,自然成为新循环的开始。…作为资本的货币的流通本身就是目的,因为只是在这个不断更新的运动中才有价值的增殖。因此,资本的运动是没有限度的。…为卖而买,或者说的完整些,为了贵买而买,即 G-W-G’…事实上是直接在流通领域内表现出来的资本的总公式。”摘自马克思《资本论》。
注:\(G-W-G'\) 是指 “货币—商品—货币” 的流通形式,这里的 \(G'=G+\Delta G\),是原有商品价值附加了剩余价值后所完成的价值的增殖。
Q1、能源集团大屏三维系统
【重大发现】html5tricks 网站资源的解压密码为``RJ4587``!望牢记。
大屏三维展示系统共五个需求:三维节点参数显示、负荷区域显示、参数云图、参数指标对比以及缺陷管理等。上月已基本搭建完成相关内容的雏形,现对某些细节执行下一步的完善:
1.1 三维节点参数显示
三维节点参数显示对左侧树功能进行完善,执行了以下三个步骤:首先,利用 jQuery 搭建抽屉式导航菜单布局;其次,修改 CSS 代码定制科技风样式;最后,修改相应 js 逻辑代码触发 ztree 双击跳转事件。
jQuery 导航抽屉
上个月本打算使用 Layui 进行抽屉插件的设计和应用,但后来发现 Layui
所提供的抽屉折叠效果是非平滑的,不符合项目需求,且由于没有别的用处而会为项目引入冗余包
layui。通过调查发现,jQuery 库本身拥有非常强大的平滑功能,该功能由函数
slideToggle() 实现,故而直接使用如下 js 代码控制菜单折叠显示:
// 控制菜单的折叠展开以及菜单项的点击样式
$(document).ready(function() {
$("#nav-pane .menu-body:eq(0)").show();
$("#nav-pane h3.menu-head").click(function() {
$(this).addClass("current").next("div.menu-body").slideToggle(300).siblings("div.menu-body").slideUp("slow");
$(this).siblings().removeClass("current");
});
$("#nav-pane a").click(function() {
$(this).addClass("ding");
$("#nav-pane *").not(this).removeClass("ding");
// 触发跳转事件
let name = this.innerText;
clickItemByName(name);
});
});
其中 html 中的主框架布局如下所示:
<!-- 集团组织机构图层控制菜单 -->
<div id="TechBox" class="TechBox">
<div class="horn">
<div class="lt"></div>
<div class="rt"></div>
<div class="rb"></div>
<div class="lb"></div>
</div>
<div id="tech-tree">
<div id="tech-tree-title">集团</div>
<div style="clear:both"></div>
<div id="title-line"></div>
<div id="nav-pane" class="menu-list"></div>
</div>
</div>
由此基本实现了抽屉式导航抽屉的逻辑层构建。而为了使系统具备更加美观的效果,我们还需要为框架引入相关的测试数据并定制 CSS 科技框样式,本文的科技框样式已放入 CodePen 中。
数据与样式设计
这里涉及到 JS 代码读取本地 JSON 数据的相关策略,即:首先在 data 文件夹中创建一个 js 文件,里面用一个函数体包裹相应的 JSON 数据,如下:
initTree({
"L1":[
{"id":"G01","name":"滨海热电"},
{"id":"G02","name":"城安热电"},
]
})//示例 JSON 数据文件
然后在 HTML 中通过相关代码进行数据读入:
<script type="text/javascript" src="data/company.js?callback=initTree"></script>
这里要注意的是,函数处理在回调函数 initTree()
中执行;利用这种机制可以实现本地 JSON 的直接读取,而无需使用 jQuery
的服务器式网络读取,从而避免了读取本地配置文件时跨域问题的产生。关于数据框的样式,这里可以使用
div 组件与 CSS 的协同控制来实现,实现可以参照参考文献[2]中的实例。
Ajax 数据更新
关于 HTTP 超文本传输协议以及 URL 统一资源定位器的研究是展开网络端相关工作的基础,虽然这两个东西已经查询过很多遍了,但还是容易忘记,这里对其作个简单记录。
引用别人对这两个重要概念的论述:
HTTP 超文本传输协议(Hypertext transfer protoco)
即超文本传输协议,其规定了浏览器与互联网的沟通规则,实现了用户从互联网接收超文本文档的功能特性,其是用于从服务器传输超文本到本地的一种高效的无状态传送应用层协议,它是无状态、无连接的。HTTP 是 TCP/IP 的应用层协议,其默认的端口号为 80。
关于 URL 资源定位器:
URL 统一资源定位器(Uniform Resource Locator)
因特网上的可用资源可以用简单字符串来表示,该文档就是描述了这种字符串的语法和语义。而这些字符串则被称为:统一资源定位器 URL。进一步理解是,在 WWW 上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫 URL,它是 WWW 的统一资源定位标志,就是指网络地址。
1.2 参数热力图与直方图
上月基本完成了热力图的示例功能,本月还需完成直方图功能的设计以及参数展示功能的进一步完善,主要需要实现的内容是根据参数层级、参数指标来动态绘制热力图与直方图。在热力图设计时,发现用于展现热力图信息的地理坐标在一定程度上有所偏移,故而使用大地测量学的知识来将模糊计算进一步精确。
子午圈弧长、平行圈弧长公式
在 Cesium 系统框架中使用的参考椭球是 WGS84 椭球,为了便于日后计算相关参数,这里列举一些常用的大地测量学参考椭球如下表所示:
代入 WGS84 椭球参数,可得到子午圈弧长计算公式如下:
代入 WGS84 椭球参数,可得到纬度 B 处的平行圈弧长计算公式如下:
其中,\(\rho\) 为测绘工程中常用的由秒转换为弧度的转换常数,其数值为 206265。由此即可计算 WGS84 坐标系下大范围经纬度坐标与实际地面距离之间的转换关系了。
热力图绘制原理
百度百科中对热力图的定义是以特殊高亮的形式显示访客热衷的页面区域和访客所在的地理区域的图示,这一概念是由软件设计师 Cormac Kinney 于 1991 年提出并创造的。一般实现热力图的参数主要有两个:二维坐标和当前坐标点的数据值,合起来构成一个三维的数据向量:
其中,\((x,y)\) 构成二维平面的坐标点,\(v\) 表达坐标点 \((x,y)\) 的特定参数值。令 \(\mathbb X^2=\{x,y\ |\ x,y\in\mathbb R\}\),为便于理解和书写代码也可将 \(\mathbf H\) 写成集合的形式如 \(\mathbb H^3=\{\mathbb x,v\ |\mathbb x\in \mathbb X^2,v\in\mathbb R\}\) 。则热力图旨在对集合 \(\mathbb H^3\) 进行密度分析和图像绘制。
需要注意的是热点图与热力图的区分。热点图是根据高值或低值进行聚类形成聚类区域的,而热力图则是根据空间位置上的密集程度进行聚类区域的划分的;也就是说热点图是值 \(v\) 强相关的,而热力图是空间 \(\mathbb x\) 强相关的。所以在某种意义上也可以将热力图称之为核密度分析图。
(1)核密度分析图
ArcGIS 中对点要素的核密度分析是指用于计算每个栅格像元周围的点要素的密度。
概念上,每个点上方均覆盖着一个平滑曲面。在点所在位置处表面值最高,随着与点的距离的增大表面值逐渐减小,在与点的距离等于搜索半径的位置处表面值为零。仅允许使用圆形邻域。曲面与下方的平面所围成的空间的体积等于此点的 Population 字段值,如果将此字段值指定为 NONE 则体积为 1。每个输出栅格像元的密度均为叠加在栅格像元中心的所有核表面的值之和。核函数以 Silverman 的著作(1986 年版,第 76 页,equation 4.5)中描述的四次核函数为基础。
由于核密度分析的中心思想是用概率密度函数估计样本数据周围邻域的数据情况,而核密度估计所做的工作就是估测所给样本数据的概率密度函数。即令概率密度函数为 \(f(x)\),则其累积分布函数为:
由微分思想可反知某一点 \(x\) 的概率密度函数:
引入累积分布函数的经验分布函数并进行相应的公式推导可得到 \(f(x)\) 的表达式为:
式中,\(h\) 是核密度估计中的带宽,也就是 ArcGIS 中所说的搜索半径。对于 ArcMap 的核密度分析工具而言,通常采用的四次核函数呈现如下形式:
延续上文的公式,进一步得到的概率密度估测函数为:
式中:
(2)heatmap.js 绘制机制
由此,即可知晓核密度分布函数的理论依据。当然在 heatmap.js 中使用前端 Canvas 渲染策略所渲染的热力图中并没有采用像 ArcGIS 理论这样复杂和精准的理论公式计算,而是采用了一种点模板和透明度叠加策略的前端热力图渲染策略,以此减少图像生成时间并提供实时新增热力点位予以生成热力图的功能。
注意到在 EarthSDK 中利用 heatmap.js
创建热力图时,其使用的数据要转化成整数格式,即使用 >>0
来将二维平面坐标点 \((x,y)\) 转换为栅格整数形式。另外这里的
heatmap.js 仍保有核密度分析中的 radius
这一概念。关于其源码和设计机制的解读可以参考参考文献[26]。
▇ 点模板点模板对应热力图数据点;它是一个圆点,根据可配置的模糊因子(blurFactor,默认.85)借助
Canvas 的 createRadialGradient() 函数使圆点带有模糊效果。
▇ 透明度叠加 透明度叠加是热力图的灵魂,在 RGB 通道之外的 A 通道施加近似线性的透明度叠加策略;该策略源自于透明度叠加算法 Alpha Blending Algorithm,该算法中的 Alpha 通道由 1970 年代末期的 Alvy Ray Smith 提出并在 1984年由 Thomas Porter 和 Tom Duff 进行了全面开发。混合算法包含 over、in、out、atop 以及 xor 等合成代数所指代的颜色混合。如对图像 A 和图像 B 的 Alpha 通道的 over 混合策略是:
在 heatmap.js 中对透明度叠加的策略是在上面策略基础上的进一步拓展,是一种综合考虑所有数据点存在混合可能性的一种近似混合策略,当前点的全局透明度计算公式为:
由此,对全局透明度施加一个叠加策略,可以在不同程度上叠加 \(\mathbb x\) 点处的透明度,\(\alpha_g\) 越大,该点越不透明。
▇ 线性色谱 线性色谱 Palette 是通过 Canvas 的
createLineGradient()
函数使使用者能够自主定制的热力图色谱,其具体热力图颜色的配置可以通过
config.gradient 色谱配置文件进行配置。此后,将透明度的叠加值
\(\alpha_g\) 映射到线性色谱,并取线性色谱中的颜色为 Canvas
上色即可得到最终的热力图了。
参数控制面板设计
关于参数面板的相关内容,我们暂且先梳理一下组织机构、调用策略和具体的参数。根据 5-25 会议做出的要求,热力图的展示方式是以各大服务中心所下辖机构的点位、相关参数值为基础绘制的一个小区域范围内的离散热力图构造模式,前文的热力图绘制原理已将克里金插值算法下的热力图绘制调整为 heatmap.js 热力图,故而进一步需要做的是就是根据会议布置的各个参数设计相关的热力参数选择面板。
该项设计已于近日完成设计部署,设计的参数控制面板作为左侧树子项的同级目录,随着子项的点击事件而弹出,弹出窗口包含简单的两个控件,一个标题控件,以及一个
<select>
控件用于提供候选参数,设计在复选框进行切换时自动切换参数云图或者说热力图的显示参数。目前的代码保存在
Project_03 工程中,后续工作留待下个月再予以展开,下个月的主要工作事项是
3DTiles 的转换。
IIS 中的 Cesium JSON 读取问题
上个月简单认识了下 JSONP 的概念以及这个概念是为跨域问题所设计的,接下来本文将进一步对 JSONP 的设计机制以及网络的跨域问题进行相关的研究。
JSONP,JSON with Padding,是 JSON 的一种数据使用模式,可用于解决主流浏览器的跨域数据访问问题。为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作 JSONP,该协议的一个要点就是允许用户传递一个 Callback 参数给服务端,然后服务端返回数据时会将这个 Callback 参数作为函数名来包裹住 JSON 数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
Cesium 中有一个专门用于解析 JSON 数据的工具叫
Cesium.Resource(options),其中有个 fectch()
方法及其衍生负责根据 URL
实现数据解析的相关功能。遇到的问题是,当本地写好的 ../data/data.json
路径被放到 IIS 服务器中运行时,这个相对路径没有被 js
代码所承认,于是数据就没有被读取。目前的解决方案是:
将
../data/data.json文件放到服务器中,形成路径http://xxxx/data/data.jsonURL即可。
Ajax + JSONP 解决跨域问题
Asynchronous JavaScript and XML 是 Web 2.0 的关键技术。Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索。使用 XMLHttpRequest 函数获取数据,它是一种允许客户端 JavaScript 通过 HTTP 连接到远程服务器的 API。不过,由于受到浏览器的限制,该方法不允许跨域通信。如果尝试从不同的域请求数据,会出现安全错误。
所有的浏览器都遵守同源策略,这个策略能够保证一个源的动态脚本不能读取或操作其他源的 HTTP 响应和 Cookie,这就使浏览器隔离了来自不同源的内容,防止它们互相操作。而跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果。其具体策略可参见参考文献[9]。
1.3 缺陷管理
CSS 雪碧图
Sprite 即雪碧的注册商标,所以在一般使用时会将 CSS Sprite 直译为 CSS 雪碧图。CSS Sprite 也有人叫它 CSS 精灵,是一种 CSS 图像合并技术,该方法是将小图标和背景图像合并到一张图片上,然后利用 CSS 的背景定位来显示需要显示的图片部分。使用雪碧图的优点有两点:一是将多张图片合并到一张图片中可以减小图片的总大小;二是将多张图片合并成一张图片后,下载全部所需的资源只需一次请求,可以减小建立连接的消耗。Sprite 这个单词的本意为“精灵”,是在游戏编程中常用的一个概念,是游戏发展早期为有条不紊的管理复杂游戏逻辑、随时间流逝均匀可控的运作、同时又要尽量优化性能所抽象出的一个概念,即如知乎 invalid s 的回答:
“精灵”抽象:游戏里一切能感知时间流逝、具有坐标位置的,都是精灵。至于为什么叫“精灵”,大概是因为它只是能“感知”有位置,却未必有实体吧——在西方传说里,“精灵sprite”本来就是有魔力的、介于虚实之间的幻想角色,如火之精灵、光之精灵之类。
针对可缩放矢量图形 Scalable Vector Graphics, SVG
图片来说,其使用方式既可以参考栅格图形的设计,同样也可以使用
<symbol> + <use> 这种语法改变 SVG 图片的内部组织方式并在 CSS
中进行调用。
参考文献
Q5. jQuery垂直折叠效果[EB/OL].
Ashijero. Technology blue box[EB/OL].
HTML5 Tricks. 纯CSS3实现的无限级垂直手风琴菜单[EB/OL].
jQuery之家. 手风琴菜单特效[EB/OL].
invalid s. 请问游戏编程中的精灵是什么意思呢?[EB/OL].
博客园. SVG Sprite 入门,SVG图标解决方案[EB/OL].
CSDN博客. 雪碧图/精灵图使用教程[EB/OL].
Cesium. Resource[EB/OL].
该死的Hero. JSONP跨域问题的解决方法[EB/OL].
简书. JSONP原理及实现[EB/OL].
CSDN博客. URL中的#、?、&解释[EB/OL].
墨颜丶.彻底理解Cookie/Sessin/Token[EB/OL].
简书. 常见的鉴权方式,你真的不想知道吗[EB/OL].
简书. JWT[EB/OL].
知乎. 五分钟带你了解啥是JWT[EB/OL].
吃代码的兔子窝.网页热力图绘制原理[EB/OL].
CSDN博客.(GIS可视化)热力图[EB/OL].
TheDataSchool.Heat maps, heat-maps and heatmaps[EB/OL].
Patrick Wied.heatmap.js[EB/OL].
Alexandre P, et al. Large Interactive Visualization of Density Functions on Big Data Infrastructure[J].
ArcMap.How kernel density works[EB/OL].
Silverman, B. W. Density Estimation for Statistics and Data Analysis.New York: Chapman and Hall, 1986.
CSDN博客.核密度估计(KDE)原理及实现[EB/OL].
CSDN博客.GIS 核密度分析工具[EB/OL].
乌合之众. RGBA alpha 透明度混合算法实现和测试[EB/OL].
小番茄. heatmap.js 热力图源码解读[EB/OL].
知乎.数据可视化:浅谈热力图如何在前端实现[EB/OL].
Q2、PP工具 2.0 版本
根据上级要求,进一步完善实景模型顶层金字塔创建工作,其中包括原有设计功能的实现、模型视距调整功能的进一步完善等等;而关于程序的自动运行,可以用 Qt 自己调度,也可以直接双击 exe 手动运行。
2.1 配置挂接到哪层实景模型
原始程序默认挂接到倒数第一层或倒数第 2 层文件上,现在需要手动指定挂接到哪层文件上,譬如 L15 层或是倒数第 2 层文件上,这个指定方式首选应该是选择第几层;当选择错误时默认选择倒数第一层,一般来说,模型文件命名都会以 L 开头设计金字塔层级,本文也采用这种方式好了。相关功能已于 5-17 日进行测试。
配置文件新增标签:Link
2.2 金字塔层级生成的控制
在配置文件中添加参数,指定是否生成最顶层文件;根据手动选择的几层文件,指定生成金字塔的哪几层文件。C++
提供了一个 stack 堆栈类型,引用头文件为
#include <stack>,其实现了一个先进后出(FILO)的数据结构。相关功能已于
5-17 日进行测试。
配置文件新增标签:Top、Level
此部分需要与主系统计算功能集成,保持默认状态下的层级选择符合要求;另外,生成层级不能随意选择,需要按照默认规则予以调整;若小于 4,则四层均可生成,若大于 4,则除 1,2 外逢偶数生成。
2.3 视距调整功能集成
视距调整功能需要作为工具提供给用户,此部分功能倒不是非常紧急。主要的设想是,根据用户需要,提供修改批量修改模型视距的功能,给定相关介绍。此外,还需修正关于修改视距后 DatabasePath 固定的问题。
目前设想,将 [视距调整功能]、[osgb 转 osg 功能] 作为常用工具,以 DockWidget 的形式展示在 Qt 主界面上。
2.4 Qt 链接到 exe 程序
调用 CMD 程序
主要技术点有:Qt 链接命令行窗口,相对路径转化,以及命令行窗口参数的设置。参照参考文献 [1] 可知 Qt 调用外部程序有以下三种策略:
system() 函数;QProcess::startDetached() 函数;QProcess::start() 函数。其中,策略 1 会在弹出黑色命令提示符窗口后弹出主程序窗口,且主程序窗口不响应任何事件,且命令提示符窗口随着主程序窗口的关闭而关闭;策略 2 中调用程序不会随着主程序的退出而退出;策略 3 中调用程序会随着主程序的退出而退出。
经过测试,不含配置文件的普通程序是可以在 Qt 程序内自主运行的,但加了具有相对路径的配置文件后某些程序就跑不起来了;为了使程序具有更好的适用性,我们来给这个程序加个命令行参数。
CMD 实时回显
实时回显可以通过 Qt 的信号槽来实现,但需要注意将 QProgress 声明为指针并主动控制销毁这一内存空间,因为在回显时该程序是一直在使用的,若非指针则会随着函数的结束而自动销毁,这样一来就会造成主程序还在运行但调用程序异常销毁的错误。
实时回显时,CMD 会返回一些头尾带 \r\n 的字符串,在 Qt 的 TextEdit
中进行显示时需要予以剔除,参照参考文献 [2-3] 提供的方法,可使用
QString::trimed() 函数来移除字符两端的空白。
命令行参数解析
以 C++ 的 main()
函数作为入口时,通常省略了两个形参[8],而这两个形参恰恰是本文完成的关键。其原型为:
int main(int argc, char* argv)
argc 是提供给主函数的参数个数,argv
是参数的字符串数组的指针。Qt
调用外部程序时,很难进行目录跳转,从而使得配置文件无法生效。而通过命令行参数的方式,可以在调用时直接指定配置文件路径,这样一来就解决了关于调用程序自动运行的问题,而且改造后的程序在不知道设计理念的情况下是无法通过命令行来控制的。
getopt()
#include <unistd.h>
int getopt(
int argc, /* The argc parameter of main() function.*/
char* const argv[], /* The argv parameter of main() function.*/
const char* optstring /* 格式控制符.*/
);
//格式控制符示例:如“ab:c:d”代表“-b”和“-c”后面必须跟一个参数,而“-a”和“-d”不需要参数
extern char* optarg; /* 参数具体内容.*/
extern int optind; /* 下一个将被处理参数在argv中的下标.*/
getopt_long()
#include <getopt.h>
int getopt_long(
int argc, /* Same as getopt(). */
char* const argv[], /* Same as getopt(). */
const char* optstring, /* Same as getopt(). */
const struct option *longopts, /* 长参数组. */
int* longindex /* 长参数组下标值. */
);
//长参数组:由option结构体构成的数组,数组元素指定长参如“--name”的名称和性质
//长参数组下标值:非空时指向的变量将记录当前找到参数符合longopts里的第几个元素的描述
struct option{
const char* name; /*长参数名称*/
int has_arg; /*是否带参数值*/
int* flag; /*指定第四个参数的返回策略*/
int val; /*找到该选项时的返回值,可以理解为长参数名称的缩写*/
}
//是否带参数值
//no_argument (即0),表明这个长参数不带参数(即不带数值,如:--name)
//required_argument(即1),表明这个长参数必须带参数(即必须带数值,如:--name Bob)
//optional_argument(即2),表明这个长参数后面带的参数是可选的,(即:--name和--name Bob)
哈哈哈,新版本 2.0 发布!如下图。
由此,关于 PP 工具的开发终于可以告一段落了。下文过一一一一一一一段时间再说。
参考文献
程序员大本营. 总结Qt5调用windows本地程序的三个方法以及异同[EB/OL].
CSDN博客. QT QString中去除收尾空白换行[EB/OL].
博客园. Qt 中QString 字符串操作:连接、组合、替换、去掉空白字符][EB/OL].
博客园. Qt编程之QString 处理换行,以行分割[EB/OL].
CSDN博客. QT QProcess: Destroyed while process (“apple.exe“) is still running[EB/OL].
CSDN博客. QT QProcess执行终端命令并实时输出回显[EB/OL].
CSDN博客. QT–信号槽与Lambda表达式[EB/OL].
CSDN博客. C++ 命令行参数解析[EB/OL].
Q3、矢量查询
参考二维矢量查询的相关功能为三维矢量做一个查询功能,这些查询可能包括属性查询和空间查询两种。为了便于查询,提供两种思路:其一,数据库方案,即使用 Spatialite 数据库,也即 SQLite 对空间的扩展数据库来进行矢量数据的保存,并通过其 C++ 类库来实现相关数据的查询;其二,矢量类库方案,即使用 GDAL 类库提供的相关二维矢量数据查询方法提供三维数据的联动查询。
3.1 Spatialite
SQLite 号称全世界最小的数据库,在几乎绝大多数数据库都具有空间数据的存储和查询功能后,SQLite 目前也有了空间数据支持的扩展,利用这个扩展,可以按照 OGC 的 Simple Feature Access 标准存取空间数据。这个项目名叫 SpatiaLite,与其一同分发的还有一个 VirtualShape。前者为 SQLite 增加空间数据支持,后者可以把一个Shapefile 作为 SQLite 的数据库。
3.2 GDAL
GDAL,Geospatial Data Abstraction Library 是一个在 X/MIT 许可协议下的开源栅格空间数据转换库。它利用抽象数据模型来表达所支持的各种文件格式,还提供一系列命令行工具来进行数据转换和处理。OGR 是 GDAL 项目的一个分支,功能与 GDAL 类似,只不过它提供对矢量数据的支持。有很多著名的 GIS 类产品都使用了该库,包括 ESRI 的 ARCGIS 9.3,Google Earth 和跨平台的 GRASS GIS 系统。利用 GDAL/OGR 库,可以使基于 Linux 的地理空间数据管理系统提供对矢量和栅格文件数据的支持。
3.3 注册器模式
构造通用接口,以 3.2 GDAL 的开发类为基础,实现查询的相关功能。
Q4、Mybatis 学习
在进一步学习之前,有必要了解下在若依框架中如何动态输出程序创建的 SQL 语句;由于若依框架采用 Nacos 对服务文件进行统一配置,故而只需要在 Nacos 中对应找到 ruoyi-system-dev.yml 进行编辑:
# mybatis 配置
mybatis:
# 搜索指定包名
typeAliasesPackage: com.ruoyi.system
# 打开 SQL 输出面板
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
由此,即可在 Idea 命令输出栏动态看到每次接口调用时生成的 SQL 语句了。
4.1 #{} 与 ${} 的区别
#{} 与 ${} 是 Mybatis
中动态传递参数的两种方式。一般地,#{} 在 Mybatis
中表示占位符,会在进行 SQL 解析时首先执行预编译,也就是说字符串
zhangsan 会被预编译为 ‘zhangsan’ 的形式;而 ${}
则表示拼接符,会直接将字符串 zhangsan 不加引号地写入 SQL
语句中,故而后者会引发 SQL
注入问题,而前者则不会。对于某些特殊需求,比如同时要求 ID 和
其他字段的联合查询时,使用 foreach 难免困难,故而采用 String
传参可能会更加轻松一些。
4.2 标签 foreach 用法
Foreach 元素的属性主要有 item,index,collection,open,separator,close。
- item:集合中元素迭代时的别名,该参数为必选。index:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。open:foreach代码的开始符号,一般是(和close=”)”合用。常用在in(),values()时。该参数可选。separator:元素之间的分隔符,例如在in()的时候,separator=”,”会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。close: foreach代码的关闭符号,一般是)和open=”(“合用。常用在in(),values()时。该参数可选。collection: 要做foreach的对象,作为入参时,List对象默认用”list”代替作为键,数组对象有”array”代替作为键,Map对象没有默认的键。当然在作为入参时可以使用@Param(“keyName”)来设置键,设置keyName后,list,array将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:如果User有属性List ids。入参是User对象,那么这个collection = “ids”.如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = “ids.id”。
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
- 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list .如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key.
传入多参数时的一个使用示例是,注意这里的 parameterType 不是 Tabel 而是 String 类型:
<!--Mapper.xml-->
<delete id="deleteByIDs" parameterType="String">
delete from table where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
对应的 Controller、Service 和 Mapper 应该这样写:
// Controller
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVarirable Long[] ids){
return toAjax(service.deleteByIDs(ids));
}
// Service
public int deleteByIDs(Long[] ids){
return mapper.deleteByIDs(ids);
}
// Mapper
public int deleteByIDs(Long[] ids);
参考文献
CSDN博客. MyBatis中#{}和${}的区别[EB/OL].
知乎. Mybatis中 #{}和${}的区别[EB/OL].
博客园. mybatis之foreach用法[EB/OL].


