基于Leaflet的自助标绘源码解析-其它对象解析

目录

前言

一、整体类图介绍

1、整体类图

二、进攻方向类对象标绘实现

1、基础配置

2、各组成部分的绘制

三、集结地对象的标绘实现

1、对象图形绘制

四、钳击对象的标绘实现 

1、基础配置

2、各部分标绘

五、总结


前言

        在之前的自助标绘相关博文中,我们对一些战斗对象的标绘有了进一步的介绍和说明。原来的博文列表如下表,感兴趣的朋友可以点击看一下:

序号博客列表
1基于Leaflet和天地图的直箭头标绘实战-源码分析
2基于Leaflet和天地图的细直箭头和突击方向标绘实战

        在之前的这两篇博客中,我们已经对直箭头、细直箭头和突击方向这三种对象的绘制进行了详细的介绍。通过这些系列博客,对其主要的类图、源码以及绘制的原理进行深入的剖析,在一些警用或者历史类战斗还原时,除了之前提到过的三种对象,其实还有一些常见的其它对象,比如战斗队形,带尾部的战斗队形,钳击箭头以及聚集地。具体的效果如下所示:

         在上图中的示例应用中就将一些基本的标绘对象进行了展示。本文将继续围绕着自助标绘场景来进行深度讲解,首先介绍剩余对象的类继承关系,然后针对不同的对象分别介绍具体对象的绘制方法,最后给出整体的自助标绘的实例成果。如果看博客的您对自助标绘感兴趣的话,不妨来这里看看,欢迎大家评论区留言交流。

一、整体类图介绍

        在进行相关的标绘方法的介绍之前,首先我们来梳理一下标绘对象的继承关系。通过梳理标绘对象,大家会发现。这些对象之间其实是有内在的关联的,不同的是加入了一些单独的处理。通过继承等父子关系,可以理顺这些类的逻辑关系。通过个性化的自定义代码讲解,让大家对独立性的标绘对象有了更深入的认识。

1、整体类图

        关于标绘对象的整体类图,除了之前介绍的标绘对象不再单独设置,感兴趣的朋友可以翻阅之前的相关博文。这里分享根据源码整理出来的类图,如下所示:

        通过上图可以看到, 除了聚居地和钳击箭头是独立的标绘对象外,其它的进攻箭头(带尾)、分队战斗箭头(箭尾和平尾)这三类箭头其实都是进攻方向这个对象的子类。因此这里着重讲解其父类即进攻方向、聚集地、钳击箭头这三种对象。针对进攻方向,只要掌握了其中一种,剩下的掌握起来也是比较简单的。

二、进攻方向类对象标绘实现

        在了解了整体的类图设计之后,我们来分别对进攻方向以及其子类标绘对象的实现进行说明。让大家掌握进攻类标绘对象的绘制防范。 进攻方向跟之前介绍的箭头类对象相比,生成的方法较为复杂。

1、基础配置

        进攻方向的基础配置参数不少,主要是包含以下的基本参数:

headHeightFactor: 0.18,//头部高度系数
headWidthFactor: 0.3,//头部宽度系数
neckHeightFactor: 0.85,//颈部高度系数
neckWidthFactor: 0.15,//颈部宽度系数
headTailFactor: 0.8

        绘制进攻方向在地图上标绘时,至少需要三个点才能确定。而标绘对象由三部分组成,分别是:箭头、箭尾和箭身。通过分别计算三个部分的信息,然后将所有的关键点连接起来,整合成我们的目标进攻方向对象。因此对箭头、箭尾和箭身的计算,之前其它的对象绘制的时候均不要这么复杂。而有一些带尾部效果的对象还需要进行尾部的处理。因此显得更加复杂。

2、各组成部分的绘制

        这里将重点介绍如何对进攻方向的箭头、箭身、箭尾来进行介绍。可以在源码中找到generate的方法。而与generate平级都生成三个组成部分的计算方法。下面我们来一一解答。最先进行计算的是箭尾,计算箭尾需要先确定坐标点的方向,可以通过PlotUtils中的isClockWise判断,关键代码如下:

var pnts = this._proPoints;
// 计算箭尾
var tailLeft = pnts[0];
var tailRight = pnts[1];
if (L.PlotUtils.isClockWise(pnts[0], pnts[1], pnts[2])) {
    tailLeft = pnts[1];
    tailRight = pnts[0];
}

        通过传入的点来判断箭尾的顺序是顺时针还是逆时针。如果是顺时针,就需要对坐标点进行互换,互换后对tailLeft和tailRight进行赋值。:得到这两个值之后,再来计算中间点。如下所示,计算两个点的终点的方法也在下面实例代码当中:

 var midTail = L.PlotUtils.mid(tailLeft, tailRight);
 var bonePnts = [midTail].concat(pnts.slice(2));

//计算中点
L.PlotUtils.mid = function (pnt1, pnt2) {
  return [(pnt1[0] + pnt2[0]) / 2, (pnt1[1] + pnt2[1]) / 2];
};

        接下来就是计算箭头的坐标,计算箭头的坐标跟之前计算直线箭头的方式有点类似,通过坐标点和旋转的方向还有相关的系数其实就可以明确箭头相关的点。

 //获取箭头部分的点
getArrowHeadPoints: function (points, tailLeft, tailRight) {
   var len = L.PlotUtils.getBaseLength(points);
   var headHeight = len * this.options.headHeightFactor;
   var headPnt = points[points.length - 1];
   len = L.PlotUtils.distance(headPnt, points[points.length - 2]);
   var tailWidth = L.PlotUtils.distance(tailLeft, tailRight);
   if (headHeight > tailWidth * this.options.headTailFactor) {
        headHeight = tailWidth * this.options.headTailFactor;
   }
   var headWidth = headHeight * this.options.headWidthFactor;
   var neckWidth = headHeight * this.options.neckWidthFactor;
   headHeight = headHeight > len ? len : headHeight;
   var neckHeight = headHeight * this.options.neckHeightFactor;
   var headEndPnt = L.PlotUtils.getThirdPoint(points[points.length - 2], headPnt, 0, headHeight, true);
   //L.marker(L.PlotUtils.unProPoint(headEndPnt)).bindPopup("headEndPnt").addTo(map)
   var neckEndPnt = L.PlotUtils.getThirdPoint(points[points.length - 2], headPnt, 0, neckHeight, true);
   //L.marker(L.PlotUtils.unProPoint(neckEndPnt)).bindPopup("neckEndPnt").addTo(map)

   var headLeft = L.PlotUtils.getThirdPoint(headPnt, headEndPnt, L.PlotConstants.HALF_PI, headWidth, false);
   var headRight = L.PlotUtils.getThirdPoint(headPnt, headEndPnt, L.PlotConstants.HALF_PI, headWidth, true);
   var neckLeft = L.PlotUtils.getThirdPoint(headPnt, neckEndPnt, L.PlotConstants.HALF_PI, neckWidth, false);
   var neckRight = L.PlotUtils.getThirdPoint(headPnt, neckEndPnt, L.PlotConstants.HALF_PI, neckWidth, true);
   return [neckLeft, headLeft, headPnt, headRight, neckRight];
}

        通过偏转方向和相应的距离和角度系数,最终可以获取箭头各坐标点的坐标。从而组成箭头这个对象相应的坐标。最后来计算箭身,箭身的计算过程是复杂一点,比如tailWidthFactor需要根据箭头的坐标和长度信息来进行动态生成,而不是像前面的常数配置参数一样。

// 计算箭头
var headPnts = this.getArrowHeadPoints(bonePnts, tailLeft, tailRight);
var neckLeft = headPnts[0];
var neckRight = headPnts[4];
var tailWidthFactor = L.PlotUtils.distance(tailLeft, tailRight) / L.PlotUtils.getBaseLength(bonePnts);

        通过两个距离的求解来计算相应的系数。最后需要将这些系数传入到箭身的计算方法当中。关键代码如下所示:

 

//获取箭身部分的点
getArrowBodyPoints: function (points, neckLeft, neckRight, tailWidthFactor) {
   var allLen = L.PlotUtils.wholeDistance(points);
   var len = L.PlotUtils.getBaseLength(points);
   var tailWidth = len * tailWidthFactor;
   var neckWidth = L.PlotUtils.distance(neckLeft, neckRight);
   var widthDif = (tailWidth - neckWidth) / 2;
   var tempLen = 0, leftBodyPnts = [], rightBodyPnts = [];
   for (var i = 1; i < points.length - 1; i++) {
        var angle = L.PlotUtils.getAngleOfThreePoints(points[i - 1], points[i], points[i + 1]) / 2;
        tempLen += L.PlotUtils.distance(points[i - 1], points[i]);
        var w = (tailWidth / 2 - tempLen / allLen * widthDif) / Math.sin(angle);
        var left = L.PlotUtils.getThirdPoint(points[i - 1], points[i], Math.PI - angle, w, true);
        //L.marker(L.PlotUtils.unProPoint(left)).bindPopup("left").addTo(map)
        var right = L.PlotUtils.getThirdPoint(points[i - 1], points[i], angle, w, false);
        //L.marker(L.PlotUtils.unProPoint(right)).bindPopup("right").addTo(map)

        leftBodyPnts.push(left);
        rightBodyPnts.push(right);
     }
  return leftBodyPnts.concat(rightBodyPnts);
}

        来看具体坐标点的生成然后从下标为1的点开始循环至倒数第二个点,每次循环计算当前点和前一个点和后一个点组成的角度的一半angle,以及当前的位置相较于tailWidth和neckWidth的宽度w,然后根据当前点的位置、angle和w计算出一组left和right。在生成坐标点,为了保持对象的平滑,这里采用贝塞尔曲线的方式来生成。贝塞尔曲线的生成方法如下:

//获取二次贝塞尔曲线点
L.PlotUtils.getQBSplinePoints = function (points) {
  if (points.length <= 2)
      return points;

  var n = 2;

  var bSplinePoints = [];
  var m = points.length - n - 1;
  bSplinePoints.push(points[0]);
  for (var i = 0; i <= m; i++) {
      for (var t = 0; t <= 1; t += 0.05) {
          var x = y = 0;
          for (var k = 0; k <= n; k++) {
              var factor = L.PlotUtils.getQuadricBSplineFactor(k, t);
              x += factor * points[i + k][0];
              y += factor * points[i + k][1];
          }
          bSplinePoints.push([x, y]);
      }
  }
  bSplinePoints.push(points[points.length - 1]);
  return bSplinePoints;
};

        通过以上的计算后,我们将所有的坐标点连起来,就可以形成一个进攻方向。在地图上绘制后如下图所示:

        注意,带了尾部效果的计算与之前的进攻方向不一样的是,带尾的计算过程与平尾的有所区别。其关键的区别在于以下的代码:

var len = allLen * this.options.tailWidthFactor * this.options.swallowTailFactor;
this.swallowTailPnt = L.PlotUtils.getThirdPoint(bonePnts[1], bonePnts[0], 0, len, true);
var factor = tailWidth / allLen;

三、集结地对象的标绘实现

        说完了进攻方向,接下来介绍一下集结地对象的介绍。集结地是单独的对象,直接集成自Polot对象。

1、对象图形绘制

        集结地对象的基础配置比较简单,这是一个由很多个点组成的蚕豆形状的多边形,只需要三个点就可以计算得出一个聚集地图形。在进行计算时,如果传入的点的长度等于2的话,会重新计算坐标。

if (this.getPointCount() == 2) {
    var mid = L.PlotUtils.mid(pnts[0], pnts[1]);
    var d = L.PlotUtils.distance(pnts[0], mid) / 0.9;
    var pnt = L.PlotUtils.getThirdPoint(pnts[0], mid, L.PlotConstants.HALF_PI, d, true);
    pnts = [pnts[0], pnt, pnts[1]];
}

        在绘制集结地图形过程当中,需要基于前面计算出来的三个点来求解相应的法线,同一个for循环来进行循环生成。

 var mid = L.PlotUtils.mid(pnts[0], pnts[2]);
 pnts.push(mid, pnts[0], pnts[1]);
 var normals = [];
 for (var i = 0; i < pnts.length - 2; i++) {
     var pnt1 = pnts[i];
     var pnt2 = pnts[i + 1];
     var pnt3 = pnts[i + 2];
     var normalPoints = L.PlotUtils.getBisectorNormals(this.options.t, pnt1, pnt2, pnt3);
     normals = normals.concat(normalPoints);
}

        求解法线的方法如下:

//获取平分线的法线(pnt1 pnt2 pnt3顺次连接组成的以pnt2为原点的夹角的角平分线的垂线)
L.PlotUtils.getBisectorNormals = function (t, pnt1, pnt2, pnt3) {
  var normal = L.PlotUtils.getNormal(pnt1, pnt2, pnt3);
  // L.marker(L.PlotUtils.unProPoint(normal)).addTo(tempGuidelinesLy)
  var dist = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1]);
  var uX = normal[0] / dist;
  var uY = normal[1] / dist;
  var d1 = L.PlotUtils.distance(pnt1, pnt2);
  var d2 = L.PlotUtils.distance(pnt2, pnt3);
  if (dist > L.PlotConstants.ZERO_TOLERANCE) {
      if (L.PlotUtils.isClockWise(pnt1, pnt2, pnt3)) {
          var dt = t * d1;
          var x = pnt2[0] - dt * uY;
          var y = pnt2[1] + dt * uX;
          var bisectorNormalRight = [x, y];
          dt = t * d2;
          x = pnt2[0] + dt * uY;
          y = pnt2[1] - dt * uX;
          var bisectorNormalLeft = [x, y];
      }
      else {
          dt = t * d1;
          x = pnt2[0] + dt * uY;
          y = pnt2[1] - dt * uX;
          bisectorNormalRight = [x, y];
          dt = t * d2;
          x = pnt2[0] - dt * uY;
          y = pnt2[1] + dt * uX;
          bisectorNormalLeft = [x, y];
      }
  }
  else {
      x = pnt2[0] + t * (pnt1[0] - pnt2[0]);
      y = pnt2[1] + t * (pnt1[1] - pnt2[1]);
      bisectorNormalRight = [x, y];
      x = pnt2[0] + t * (pnt3[0] - pnt2[0]);
      y = pnt2[1] + t * (pnt3[1] - pnt2[1]);
      bisectorNormalLeft = [x, y];
  }
  return [bisectorNormalRight, bisectorNormalLeft];
};

        最后需要求解三次贝塞尔曲线点坐标。在将这些点连接整合起来得到一个完成的集结地图形。

//获取三次贝塞尔曲线点的坐标
L.PlotUtils.getCubicValue = function (t, startPnt, cPnt1, cPnt2, endPnt) {
  t = Math.max(Math.min(t, 1), 0);
  var tp = 1 - t;
  var t2 = t * t;
  var t3 = t2 * t;
  var tp2 = tp * tp;
  var tp3 = tp2 * tp;
  var x = (tp3 * startPnt[0]) + (3 * tp2 * t * cPnt1[0]) + (3 * tp * t2 * cPnt2[0]) + (t3 * endPnt[0]);
  var y = (tp3 * startPnt[1]) + (3 * tp2 * t * cPnt1[1]) + (3 * tp * t2 * cPnt2[1]) + (t3 * endPnt[1]);
  return [x, y];
};

        绘制出来的集结地图形如下所示:

四、钳击对象的标绘实现 

        钳击对象一般用来表示同时发起攻击,因此有两个箭头。通过两个箭头来表示进攻的方向。绘制钳击对象需要使用四个点,分别是尾部的两点以及两个箭头的坐标。这里来详细介绍钳击箭头的属性和绘制过程。

1、基础配置

        与其它的标绘对象一致,钳击箭头的属性如下表所示:

headHeightFactor: 0.25,//头部高度倍数
headWidthFactor: 0.3,//头部宽度倍数
neckHeightFactor: 0.85,//颈部高度倍数
neckWidthFactor: 0.15,//颈部宽度倍数
fixPointCount: 4

        如前文所述,钳击箭头包含两个箭头,因此同样需要计算不同箭头的坐标点,以及定义箭头对象的高度和高度的倍数。

2、各部分标绘

        首先根据给出的坐标点计算顺序,计算方法是之前介绍过的判断点的顺时针和逆时针方向。以此来分别计算左右两个箭头。

var leftArrowPnts, rightArrowPnts;
if (L.PlotUtils.isClockWise(pnt1, pnt2, pnt3)) {
     leftArrowPnts = this.getArrowPoints(pnt1, this.connPoint, this.tempPoint4, false);
     rightArrowPnts = this.getArrowPoints(this.connPoint, pnt2, pnt3, true);
 } else {
     leftArrowPnts = this.getArrowPoints(pnt2, this.connPoint, pnt3, false);
     rightArrowPnts = this.getArrowPoints(this.connPoint, pnt1, this.tempPoint4, true);
}

        得到左右两边的钳击箭头的方法为:

getArrowPoints: function (pnt1, pnt2, pnt3, clockWise) {
        var midPnt = L.PlotUtils.mid(pnt1, pnt2);
        var len = L.PlotUtils.distance(midPnt, pnt3);
        var midPnt1 = L.PlotUtils.getThirdPoint(pnt3, midPnt, 0, len * 0.3, true);
        var midPnt2 = L.PlotUtils.getThirdPoint(pnt3, midPnt, 0, len * 0.5, true);
        //var midPnt3=PlotUtils.getThirdPoint(pnt3, midPnt, 0, len * 0.7, true);
        midPnt1 = L.PlotUtils.getThirdPoint(midPnt, midPnt1, L.PlotConstants.HALF_PI, len / 5, clockWise);
        midPnt2 = L.PlotUtils.getThirdPoint(midPnt, midPnt2, L.PlotConstants.HALF_PI, len / 4, clockWise);
        //midPnt3=PlotUtils.getThirdPoint(midPnt, midPnt3, Constants.HALF_PI, len / 5, clockWise);

        var points = [midPnt, midPnt1, midPnt2, pnt3];
        // 计算箭头部分
        var arrowPnts = this.getArrowHeadPoints(points, this.options.headHeightFactor, this.options.headWidthFactor, this.options.neckHeightFactor, this.options.neckWidthFactor);
        var neckLeftPoint = arrowPnts[0];
        var neckRightPoint = arrowPnts[4];
        // 计算箭身部分
        var tailWidthFactor = L.PlotUtils.distance(pnt1, pnt2) / L.PlotUtils.getBaseLength(points) / 2;
        var bodyPnts = this.getArrowBodyPoints(points, neckLeftPoint, neckRightPoint, tailWidthFactor);
        var n = bodyPnts.length;
        var lPoints = bodyPnts.slice(0, n / 2);
        var rPoints = bodyPnts.slice(n / 2, n);
        lPoints.push(neckLeftPoint);
        rPoints.push(neckRightPoint);
        lPoints = lPoints.reverse();
        lPoints.push(pnt2);
        rPoints = rPoints.reverse();
        rPoints.push(pnt1);
        return lPoints.reverse().concat(arrowPnts, rPoints);
    }

        其它的计算过程跟其它箭头类的计算相似,在此不再赘述。生成钳击箭头的实际效果如下所示:

        到此, 进攻方向机器扩展对象、集结地、钳击对象的基础配置以及具体的绘制过程说明就进行了具体的源码解析。最后将所有的对象在地图上进行标绘的可视化展示结果如下:

五、总结

        以上就是本文的主要内容,本文将继续围绕着自助标绘场景来进行深度讲解,首先介绍剩余对象的类继承关系,然后针对不同的对象分别介绍具体对象的绘制方法,最后给出整体的自助标绘的实例成果。自助标绘非常重要,掌握自助标绘对于以后进行战斗的还原,演习斗争的还原等具有非常重要的作用。为下一步进行动态标绘奠定绘制的基础。行文仓促,难免有许多不足支持,针对不足,还请各位专家博主朋友在评论区留下真知灼见,不胜感激。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/909269.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于机器学习的健身房会员健康风险分类及预测分析

1.项目背景 随着健康意识的提升和健身文化的普及&#xff0c;人们对科学健身和个性化训练的需求日益增长&#xff0c;健身房会员的锻炼模式和健康管理需求呈现出新的特点&#xff0c;本项目使用基于真实健身模式生成的973位会员数据进行深入分析&#xff0c;探索不同会员群体的…

如何在本地Linux服务器搭建WordPress网站结合内网穿透随时随地可访问

文章目录 前言1. 安装WordPress2. 创建WordPress数据库3. 安装相对URL插件4. 安装内网穿透发布网站4.1 命令行方式&#xff1a;4.2. 配置wordpress公网地址 5. 配置WordPress固定公网地址 前言 本文主要介绍如何在Linux Ubuntu系统上使用WordPress搭建一个本地网站&#xff0c…

30条勒索病毒处置原则

当前&#xff0c;勒索病毒在全球范围内肆虐&#xff0c;成为企业数据资产安全的头号威胁。这些狡猾的恶意软件&#xff0c;如同网络空间中的幽灵&#xff0c;不断寻找并利用系统的漏洞&#xff0c;通过加密数据或窃取敏感信息&#xff0c;向企业索取高额赎金。一旦感染&#xf…

【MongoDB】Windows/Docker 下载安装,MongoDB Compass的基本使用、NoSQL、MongoDB的基础概念及基础用法(超详细)

文章目录 Windows下载MongoDB Compass使用NoSQL的基本概念MongoDB常用术语MongoDB与RDBMS区别MongoDB的CRUD 更多相关内容可查看 Docker安装MongoDB可查看&#xff1a;Docker-安装MongoDB Windows下载 官网下载地址&#xff1a;https://www.mongodb.com/try/download/communi…

爬虫学习4

from threading import Thread#创建任务 def func(name):for i in range(100):print(name,i)if __name__ __main__:#创建线程t1 Thread(targetfunc,args("1"))t2 Thread(targetfunc, args("2"))t1.start()t2.start()print("我是诛仙剑")from …

springboot yml文件数据源出现警告/报黄/数据库配置警告问题

1、看一下数据源的依赖是不是都引入完整了 2、看一下数据源是否有拼写错误 上图就是数据源拼写错误

配置深度学习环境

先前已经配置好了 1在新建一个项目时 2.打开文件&#xff0c;找到设置 3.点开设置 如图1.2.3所示

MySQL初学之旅(1)配置与基础操作

目录 1.前言 2.正文 2.1数据库的发展历程 2.2数据库的基础操作 2.2.1启动服务 2.2.2创建与删除数据库 2.2.3数据类型 2.2.4创建表与删除表 2.3MySQL Workbench基础使用简介 3.小结 1.前言 哈喽大家好吖&#xff0c;今天博主正式开始为大家分享数据库的学习&#xff…

好用且免费的工具分享

在当今数字化时代&#xff0c;AI工具的普及极大地提升了我们的工作效率和生活品质。最近发现一个功能强大、免费好用的AI工具&#xff0c;叫做“灵办AI”。 无论是打工人还是学生党&#xff0c;用了它绝对能让你效率起飞&#xff01;它不同于市面上专注于特定领域的产品&#x…

二阶温度补偿带隙基准电路版图设计

二阶温度补偿带隙基准电路 点击获取&#xff0c;188 电路版图设计&#xff0c;cadence电路版图&#xff0c;24h秒发&#xff0c;不答疑 参数&#xff1a; 电源电压&#xff1a;1.8V 输出电压&#xff1a;0.87V ppm&#xff1a;17 功耗&#xff1a;100uA PSRR&#xff1a;-62…

2.若依vue表格数据根据不同状态显示不同颜色style

例如国标显示蓝色&#xff0c;超标是红色 使用是蓝色&#xff0c;未使用是绿色 <el-table-column label"外卖配送是否完成评价" align"center" prop"isOverFlag"> <template slot-scope"scope"> …

Unity照片墙效果

Unity照片墙效果&#xff0c;如下效果展示 。 工程源码

简易CPU设计入门:译码模块(一)

项目代码下载 还是请大家首先准备好本项目所用的源代码。如果已经下载了&#xff0c;那就不用重复下载了。如果还没有下载&#xff0c;那么&#xff0c;请大家点击下方链接&#xff0c;来了解下载本项目的CPU源代码的方法。 下载本项目代码 准备好了项目源代码以后&#xff…

vue 使用docx-preview 预览替换文档内的特定变量

在开发合同管理中&#xff0c;需要使用到此功能&#xff0c;就是替换合同模板内的一些字符串&#xff0c;如&#xff1a;甲乙方名称&#xff0c;金额日期等&#xff0c;合同内容不变。效果如下&#xff1a; 使用docx-preview 好处是只预览不可编辑内容。 前端vue import { re…

[N-155]基于springboot,vue宿舍管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 项目采用前后端分离 前端技术&#xff1a;vue3element-plus 服务端技术&#xff1a;springbootmybatis-plus 本项目分为学生、宿舍管理…

json-server的使用(根据json数据一键生成接口)

一.使用目的 在前端开发初期&#xff0c;后端 API 可能还未完成&#xff0c;json-server 可以快速创建模拟的 RESTful API&#xff0c;帮助前端开发者进行开发和测试。 二.安装 npm install json-server //局部安装npm i json-server -g //全局安装 三.使用教程 1.准备一…

win11安装安卓apk原生应用,并设置网络代理

一、win11安装安卓apk原生应用&#xff0c;查看https://blog.csdn.net/qq_33704787/article/details/123658419https://blog.csdn.net/qq_33704787/article/details/123658419 主要是安装&#xff1a;Windows Subsystem for Android™ with Amazon Appstore 二、使用ABD工具设…

算法|牛客网华为机试21-30C++

牛客网华为机试 上篇&#xff1a;算法|牛客网华为机试10-20C 文章目录 HJ21 简单密码HJ22 汽水瓶HJ23 删除字符串中出现次数最少的字符HJ24 合唱队HJ25 数据分类处理HJ26 字符串排序HJ27 查找兄弟单词HJ28 素数伴侣HJ29 字符串加解密HJ30 字符串合并处理 HJ21 简单密码 题目描…

如何对数据库的表字段加密解密处理?

对于表格数据的加密处理&#xff0c;通常涉及到对数据库中存储的数据进行加密&#xff0c;以保护敏感信息。 Java示例&#xff08;使用AES算法加密数据库表数据&#xff09; 首先&#xff0c;你需要一个数据库连接&#xff0c;这里假设你使用的是JDBC连接MySQL数据库。以下是…

搭建你的私人云盘:使用File Browser与cpolar实现公网传输文件

文章目录 前言1.下载安装File Browser2.启动访问File Browser3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4.固定公网地址访问 前言 File Browser是一个开源的文件管理器和文件共享工具&#xff0c;它可以帮助用户轻…