手摸手系列之SpringBoot+Vue2项目整合高德地图实现车辆实时定位功能

前言

最近在做一个物流内陆运输的项目,其中的一个关键功能是根据车辆的GPS数据在页面上实时显示车辆位置信息。由于我们已经获得了第三方提供的GPS数据,所以接下来的任务是将这些数据整合到我们的系统中,并利用高德地图API来展示车辆的实时位置。接下来,来看看怎么样来一步步实现吧。

一、后端工作:将第三方提供的GPS数据进一步整合优化后,再返回给前端
1. 第三方提供的接口文档

image.png
image.png
第三方的返回数据示例:

{"status": 1001,"result": {"firstVcl": {"lat": "22088888","lon": "96332278","adr": "山东省济南市历城区中电四齐鲁安替制药临建区,西南方向,159.0米","utc": "1703843972000","spd": "0.0","drc": "278","province": "山东省","city": "济南市","country": "历城区","mil": "488206.2","vno": "鲁AL8560","status": "1001","offlineState": false,"offlineTime": "","runDistance": "","remainDistance": "","estimateArriveTime": ""},"others": []}
}
2. 后端主要代码

需要先将第三方提供的SDK包整合进项目里。在resources下新建目录sdk,然后将sdk.jar拷贝进去:
image.png
然后在pom.xml中加入依赖:

<dependency><groupId>com.openapi.sdk</groupId><artifactId>openapi-sdk</artifactId><version>6.0</version><scope>system</scope><systemPath>${project.basedir}/src/main/resources/sdk/openapi-sdk-6.0.jar</systemPath>
</dependency>

最后重要的一步,在spring-boot-maven-plugin插件设置加上includeSystemScope
image.png

  • includeSystemScope:scope为system的maven默认是不打包进去的,所以导致上面说的,项目打包完成后,对应的lib目录下并没有外部提供的xxx-api-sdk。使用该配置,将指定maven把scope为system的依赖 同样打到jar包中去。

然后就可以直接使用SDK中的postHttps(url, map)等方法了。
下面是主要的Java代码:

/*** 厂外物流-在途监控类服务** 运输节点服务** @param vnos 车牌号_车牌颜色,多* 个车辆以英文逗号分* 隔(最多 100 台车,* 颜色:1 蓝色、2 黄* 色、3 黄绿)京 A78601_1,京* A78602_2, 京 A78603_3* @return 陆运单列表*/
@ApiOperation(value = "运输节点服务", notes = "运输节点服务")
@RequestMapping(value = "/getDataV2")
public Result<?> getDataV2(@RequestParam("vnos") String vnos,@RequestParam(value = "timeNearby", required = false) String timeNearby) {return dispatchTransportService.getDataV2(vnos, timeNearby);
}
/*** 厂外物流-在途监控类服务* <p>* 运输节点服务** @param vnos       车牌号_车牌颜色,多*                   个车辆以英文逗号分*                   隔(最多 100 台车,*                   颜色:1 蓝色、2 黄*                   色、3 黄绿)京 A78601_1,京*                   A78602_2, 京 A78603_3* @param timeNearby* @return 陆运单列表*/
@Override
public Result<?> getDataV2(String vnos, String timeNearby) {try {Map<String, String> map = new HashMap<>();map.put("cid", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");map.put("srt", "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"); // 私钥用于 SDK 生成签名,不会在请求中传输map.put("vnos", vnos);if (isNotBlank(timeNearby)) {map.put("timeNearby", timeNearby);}String url = "https://aaaaaaaaa.99999.com/bbbbb/ccccc/getDataV2";DataExchangeService des = new DataExchangeService(5000, 8000);log.info("请求地址:" + url);// 通过 https 方式调用,此方法内部会使用私钥生成签名参数 sign,私钥不会发送String res = des.postHttps(url, map);log.info("返回:" + res);JSONObject returnJson = new JSONObject();if (isNotBlank(res)) {JSONObject jsonObject = JSONObject.parseObject(res);if (jsonObject.containsKey("status")) {String code = jsonObject.getString("status");if (code.equals("1001")) {String data = jsonObject.getString("result");returnJson = JSONObject.parseObject(data);} else {return Result.error("未获取到车辆" + (vnos.substring(0, vnos.indexOf("_"))) + "位置信息!");}}}return Result.ok(returnJson);} catch (Exception e) {log.error("e:" + e.getMessage());return Result.error("获取车辆定位出现异常:" + e.getMessage());}
}

返回前端的数据格式如下:

{"status": 1001,"result": {"firstVcl": {"lat": "2968514","lon": "85692278","adr": "山东省济南市历城区中电四齐鲁安替制药临建区,西南方向,159.0米","utc": "1703843972000","spd": "0.0","drc": "278","province": "山东省","city": "济南市","country": "历城区","mil": "488206.2","vno": "鲁AX9999","status": "1001","offlineState": false,"offlineTime": "","runDistance": "","remainDistance": "","estimateArriveTime": ""},"others": []}
}
二、前端工作:接收后端返回数据,整合高德地图展示数据
1. 先去高德开放平台申请key

image.png
image.png
image.png
👉高德的地图JS API 2.0非常详细,只需要看文档就可以完成各种需要的功能,不需要再看其他人的博客了,以免被误导。

2. 新建地图组件MapContainer.vue
<template><div><div id="container"></div><div class="info"><h3>{{ firstVcl.vno }} <a-switch style='margin-left: 80px' size="small" checked-children="开" un-checked-children="关" default-checked @change='isRealtime'/>实时刷新<a-tooltip slot="suffix" title="开启后默认每15秒获取最新位置信息!"><a-icon type="question-circle" theme="twoTone"/></a-tooltip></h3><hr><p style='margin-top: 3px'><span style='font-weight: bold'>定位时间:</span>{{ this.formatDate(firstVcl.utc?Number(firstVcl.utc):new Date().getTime(), 'yyyy-MM-dd hh:mm:ss') }}</p><p><span style='font-weight: bold'>最后定位经度:</span>{{ firstVcl.lon.toFixed(6) }}</p><p><span style='font-weight: bold'>最后定位纬度:</span>{{ firstVcl.lat.toFixed(6) }}</p><p><span style='font-weight: bold'>地理位置名称:</span>{{ firstVcl.adr }}</p><p><span style='font-weight: bold'>方向:</span>{{ getDrc() }}</p><p><span style='font-weight: bold'>里程:</span>{{ firstVcl.mil ? firstVcl.mil : 0 }} km</p><p><span style='font-weight: bold'>速度:</span>{{ firstVcl.spd ? firstVcl.spd : 0 }} km/h</p><!--			<p><span style='font-weight: bold'>已行驶距离:</span>{{ firstVcl.runDistance ? firstVcl.runDistance : 0 }} km</p>--><!--			<p><span style='font-weight: bold'>剩余运距:</span>{{ firstVcl.remainDistance ? firstVcl.remainDistance : 0 }} km</p>--><!--			<p><span style='font-weight: bold'>预计到达时间:</span>{{ firstVcl.estimateArriveTime ? this.formatDate(Number(firstVcl.estimateArriveTime), 'yyyy-MM-dd hh:mm:ss') : '' }}</p>--><p><span style='font-weight: bold'>离线状态:</span>{{ getOfflineState() }}</p><p><span style='font-weight: bold'>离线时长:</span>{{ firstVcl.offlineTime }}</p></div></div>
</template>
<script>import AMapLoader from "@amap/amap-jsapi-loader";import { getAction } from '@/api/manage'import BigNumber from 'bignumber.js'// 设置安全密钥window._AMapSecurityConfig = {securityJsCode: 'xxxxxxxxxxxxxxxxxxxx0704b5080',}export default {name: "MapContainer",props: {carModel: {type: Object,default: {}}},data() {return {firstVcl: {},map : null,marker : null,overlays : [],myTimer : null,placeSearch : null,stopTimer: false,url: {getDataV2: '/business/dispatch/getDataV2'}}},mounted() {this.initAMap()// 通过 $once 来监听定时器,在 beforeDestroy 钩子可以被清除。this.$once('hook:beforeDestroy', () => {clearInterval(this.myTimer)})},unmounted() {this.stopTimer = truethis.map.destroy()},beforeDestroy() {this.stopTimer = truethis.map.destroy()},methods: {isRealtime(value) {if (value === true) {this.stopTimer = falsethis.realtimeRefresh(this.firstVcl.vno)} else if (value === false) {this.stopTimer = true}},/*** 实时刷新*/realtimeRefresh(carNum) {this.myTimer = setInterval(() => {// 停止定时器if (this.stopTimer === true) {console.log('停止实时刷新!!!')clearInterval(this.myTimer)return}const carType = '2' // 默认黄牌车let params = {vnos: carNum + '_' + carType,timeNearby: '30'}getAction(this.url.getDataV2, params).then((res) => {if (res.success) {console.log(res.result.records || res.result)let data = res.result.records || res.resultthis.firstVcl = data.firstVclif (data.firstVcl && data.firstVcl.lon) {this.firstVcl.lon = new BigNumber(data.firstVcl.lon).div(600000.0).toNumber()}if (data.firstVcl && data.firstVcl.lat) {this.firstVcl.lat = new BigNumber(data.firstVcl.lat).div(600000.0).toNumber()}var position = new AMap.LngLat(this.firstVcl.lon, this.firstVcl.lat) //传入经纬度this.map.setCenter(position) //设置地图中心点if (this.marker) {this.marker.setPosition([this.firstVcl.lon, this.firstVcl.lat]); //更新点标记位置}} else {// 失败this.$message.warning(res.message || res)}}).finally(() => {})},15000)},initAMap() {this.firstVcl = Object.assign({}, this.carModel.firstVcl)this.realtimeRefresh(this.firstVcl.vno)AMapLoader.load({key: "yyyyyyyyyyyyyyyyyybe1b7dae4", // 申请好的Web端开发者Key,首次调用 load 时必填version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15plugins: ['AMap.ToolBar', 'AMap.Scale', 'AMap.MapType'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等}).then((AMap) => {this.map = new AMap.Map("container", {mapStyle: "amap://styles/fresh", // 设置地图的显示样式// 设置地图容器idviewMode: "3D", // 是否为3D地图模式zoom: 13, // 初始化地图级别center: [this.firstVcl.lon, this.firstVcl.lat], // 初始化地图中心点位置resizeEnable: true});this.map.addControl(new AMap.ToolBar()); // 缩略地图控件this.map.addControl(new AMap.Scale()); // 比例尺this.map.addControl(new AMap.MapType()); // 图层切换// 创建一个 Iconvar startIcon = new AMap.Icon({// 图标尺寸size: new AMap.Size(32, 32),// 图标的取图地址image: require("../../../assets/汽车1.png"),// 图标所用图片大小imageSize: new AMap.Size(32, 32),// 图标取图偏移量// imageOffset: new AMap.Pixel(-9, -3)});// 将 Icon 实例添加到 marker 上:this.marker = new AMap.Marker({position: [this.firstVcl.lon, this.firstVcl.lat], //点标记的位置offset: new AMap.Pixel(0, 0), //设置点标记偏移量anchor: "bottom-center", //设置锚点方位icon: startIcon, //添加 Icon 实例zooms: [2, 18], //点标记显示的层级范围,超过范围不显示});// 设置鼠标划过点标记显示的文字提示this.marker.setTitle(this.firstVcl.vno);// 设置label标签// label默认蓝框白底左上角显示,样式className为:amap-marker-labelthis.marker.setLabel({direction:'top',offset: new AMap.Pixel(0, 0),  //设置文本标注偏移量content: `<div>${this.firstVcl.vno}</div>`, //设置文本标注内容});// 加入到map对象中绘制this.map.add(this.marker);}).catch((e) => {console.log(e);});},/*** 正北,大于 0 且小于 90:东北,* 等于 90:正东,大于 90 且小于* 180:东南,等于 180:正南,大于* 180 且小于 270:西南,*  * 等于 270:正西,大于 270* 且小于等于 359:西北,其他:未* 知* @returns {string}*/getDrc() {if (this.firstVcl.drc) {let drc = Number(this.firstVcl.drc);if (drc > 0 && drc < 90) {return '东北'} else if (drc === 90) {return '正东'} else if (drc > 90 && drc < 180) {return '东南'} else if (drc === 180) {return '正南'} else if (drc > 180 && drc < 270) {return '西南'} else if (drc === 270) {return '正西'} else if (drc > 270 && drc <= 359) {return '西北'}}return '未知'},getOfflineState() {if (this.firstVcl.offlineState) {return '离线'} else {return '在线'}},/*** 时间格式化* @param value* @param fmt* @returns {*}*/formatDate (value, fmt) {let regPos = /^\d+(\.\d+)?$/if (regPos.test(value)) {//如果是数字let getDate = new Date(value)let o = {'M+': getDate.getMonth() + 1,'d+': getDate.getDate(),'h+': getDate.getHours(),'m+': getDate.getMinutes(),'s+': getDate.getSeconds(),'q+': Math.floor((getDate.getMonth() + 3) / 3),'S': getDate.getMilliseconds()}if (/(y+)/.test(fmt)) {fmt = fmt.replace(RegExp.$1, (getDate.getFullYear() + '').substr(4 - RegExp.$1.length))}for (let k in o) {if (new RegExp('(' + k + ')').test(fmt)) {fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))}}return fmt} else {//TODOvalue = value.trim()return value.substr(0, fmt.length)}}}
};
</script>
<style scoped>
#container {width: 100%;height: 800px;
}
.info {position: absolute;width: 300px;top: 75px;left: 20px;z-index: 1000; /* 为确保 info 在地图上方 */padding: 10px;background-color: rgba(255, 255, 255, 0.9); /* 设置一个半透明的背景色 */
}
.info p {margin: 2px;
}
</style>
3. 在父组件VehicleLocationAndTrackingModal中引入地图组件
<template><z-c-modal:title="'陆运单 ' + title":width="width":visible="visible"@cancel="handleCancel"switchFullscreen:destroyOnClose="true"cancelText="关闭"><template slot='footer'><a-button type="primary" @click="handleCancel">关闭</a-button></template><a-card :body-style='{padding: 0}' :bordered='false'><a-tabs v-model='activeKey' default-active-key='1' @change='callbacktab'><a-tab-pane key='1' :forceRender='true' tab='车辆定位'><map-container ref='carLocationRef' :car-model='transport.carModel'/></a-tab-pane><a-tab-pane key='2' :forceRender='true' tab='轨迹回放'>
<!--					<aexg-list ref='aexgList' />--></a-tab-pane></a-tabs></a-card></z-c-modal>
</template>
<script>
import CarLocationMap from '@/views/dispatchManage/component/CarLocationMap.vue'
import ZCModal from '@/components/jeecg/ZCModal/index.vue'
import MapContainer from '@/views/dispatchManage/component/MapContainer.vue'
import BigNumber from 'bignumber.js'
export default {name: 'VehicleLocationAndTrackingModal',components: { ZCModal, CarLocationMap, MapContainer },data() {return {activeKey: '1',transport: {},title: '',width: 1180,visible: false,confirmLoading: false,disableSubmit: false}},methods: {add(record) {this.transport = Object.assign({}, record)if (this.transport.carModel) {let lon = 116.397428if (this.transport.carModel.firstVcl && this.transport.carModel.firstVcl.lon) {lon = new BigNumber(this.transport.carModel.firstVcl.lon).div(600000.0).toNumber();}this.transport.carModel.firstVcl.lon = lonlet lat = 39.90923if (this.transport.carModel.firstVcl && this.transport.carModel.firstVcl.lat) {lat = new BigNumber(this.transport.carModel.firstVcl.lat).div(600000.0).toNumber();}this.transport.carModel.firstVcl.lat = lat}this.visible = true},callbacktab(key) {console.log(key)},close() {this.visible = false},handleCancel () {this.close()}}
}
</script><style scoped lang='less'>
@import '~@assets/less/common.less';
/deep/ .ant-modal-body {padding:0 12px !important;
}
/deep/ .ant-tabs-nav-wrap {margin-top: -5px;
}
</style>
三、最终的展示效果:

image.png

总结

Vue整合高德地图总的来说还是非常简单的,下一篇我们继续来介绍如何实现展示车辆的某段时间的运行轨迹。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

如何修复msvcp140_1.dll丢失问题,分享多种实测可靠的修复方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp140_1.dll丢失”的错误。msvcp140_1.dll是Microsoft Visual C 2015 Redistributable的一个组件&#xff0c;它是运行某些程序所必需的动态链接库文件。动态链接库&#xff08;DLL&…

【Linux】Linux

Linux 文章目录 Linux1. 简介2. 目录结构3. vi/vim 的使用4. 网络配置4.1 配置网络ip地址4.2 配置主机名或ip映射4.3 远程登陆及上传下载 5. 系统管理5.1 service 服务管理&#xff08;CentOS 6 版本&#xff09;5.2 systemctl 服务管理&#xff08;CentOS 7 版本&#xff09;5…

Flask笔记

一&#xff1a;模板渲染 一般的话都序列化成字符串 二&#xff1a;项目拆分 2.1 项目拆分 app.py init.py views.py models.py 模型数据 2.2 蓝图 三&#xff1a;路由参数 3.1 String 重点 3.2 int 3.3 path 3.4 UUID 3.5 any 四&#xff1a;请求方式 五&#xff1a;Requ…

Docker单点部署Seata(2.0.0) + Nacos(v2.3.0) + Mysql(5.7)

文章目录 一、部署Nacos二、部署Mysql三、Seata准备工作1. 记住nacos、mysql、宿主机的ip2. 建立数据库3. Nacos远程配置文件 四、部署Seata五、初步检验Seata部署情况六、微服务使用Seata1.引入依赖2. application.yml配置 七、遇到的坑1. Nacos显示Seata服务的ip为容器内网ip…

听GPT 讲Rust源代码--src/tools(38)

File: rust/src/tools/clippy/clippy_dev/src/lib.rs rust/src/tools/clippy/clippy_dev/src/lib.rs文件是Clippy开发工具的入口文件&#xff0c;其作用是提供Clippy开发过程中所需的功能和工具。Clippy是一个Rust代码的静态分析工具&#xff0c;用于提供各种有用的代码规范、编…

ARCGIS PRO SDK 访问Geometry对象

一、Geometry常用对象 二、主要类 1、ReadOnlyPartCollection&#xff1a;Polyline 和 Polygon 使用的 ReadOnlySegmentCollection 部件的只读集合&#xff0c;属性成员&#xff1a;​ 名字描述Count获取 ICollection 中包含的元素数。TIEM获取位于指定索引处的元素。Spatial…

TimescaleDB安装部署

安装cmake 解压压缩包 tar xvf cmake-3.28.1-linux-x86_64.tar 将cmake 添加到profile中 vi ~/.bash_profile export PATH/home/postgres/app/cmake-3.28.1-linux-x86_64/bin:$PATH 保存&#xff0c;执行 source ~/.bash_profile 安装TimescaleDB 下载timescaledb安装包并解压…

【Matlab】基于遗传算法优化BP神经网络 (GA-BP)的数据时序预测

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88682033 一&#xff0c;概述 基于遗传算法优化BP神经网络 (GA-BP) 的数据时序预测是一种常用的机器学习方法&#xff0c;用于预测时间序列数据的趋势和未来值。 在使用这种方法之前&#xff0c;需要将时间序…

JVM工作原理与实战(二):字节码编辑器jclasslib

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、字节码编辑器jclasslib介绍和安装 1.介绍 2.安装 3.IntelliJ IDEA 插件安装 二、字节码编辑器jclasslib的使用 1.使用jclasslib bytecode viewer打开字节码文件 2.使用Intell…

Redis经典五大类型源码及底层实现(二)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术&#x1f525;如果感觉博主的文章还不错的…

Screenshot-to-code开源项目mac上实践

github上的开源项目&#xff0c;看介绍可以将设计ui图片转换为 HTML 和 CSS 源码地址&#xff1a; GitCode - 开发者的代码家园 我的mac安装了2.7和3.11&#xff0c;就用3吧直接上代码 安装 pip3 install keras tensorflow pillow h5py jupyter 报错 ERROR: Could not in…

DFS BFS

用DFS和BFS分别实现 //这边给出DFS的模版 void dfs(int x,int y) {//判断是否到达终点&#xff08;只有给出结束点的时候需要&#xff09; if (x ex && y ey) {if (min_steps > step) {min_steps step;}return;}//给出移动方向int move[4][2] {{0, 1}, {0, -1}…

uniapp中uview组件库的丰富Upload 上传上午用法

目录 基础用法 #上传视频 #文件预览 #隐藏上传按钮 #限制上传数量 #自定义上传样式 API #Props #Methods #Slot #Events 基础用法 可以通过设置fileList参数(数组&#xff0c;元素为对象)&#xff0c;显示预置的图片。其中元素的url属性为图片路径 <template>…

音频播放软件Foobar2000 mac特点介绍

Foobar2000 mac是一款高度可定制的音频播放器&#xff0c;适用于Windows平台。它支持各种音频格式&#xff0c;包括MP3、FLAC、AAC、WMA等&#xff0c;同时也支持各种音频插件和效果器&#xff0c;可以提供更好的音质和用户体验。 Foobar2000 mac软件特点 1. 高度可定制&#…

69内网安全-域横向CobaltStrikeSPNRDP

这节课主要讲spn和rdp协议&#xff0c; 案例一域横向移动RDP传递-Mimikatz rdp是什么&#xff0c;rdp是一个远程的链接协议&#xff0c;在linux上面就是ssh协议&#xff0c; 我们在前期信息收集的时候&#xff0c;得到一些hash值和明文密码可以进行一些相关协议的链接的&am…

【Proteus仿真】【Arduino单片机】汽车尾灯控制设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用按键、LED模块等。 主要功能&#xff1a; 系统运行后&#xff0c;系统运行后&#xff0c;系统开始运行&#xff0c;K1键控制左转向灯&#x…

【UE 游戏模板】 游戏分类(RPG、RST等)

目录 0 引言1 游戏分类1.1 角色扮演游戏&#xff08;RPG&#xff09;1.2 第一人称射击游戏&#xff08;FPS&#xff09;1.3 即时策略游戏&#xff08;RTS&#xff09;1.4 VR游戏1.5 集换式卡牌游戏&#xff08;TCG&#xff09;1.5 塔防游戏&#xff08;Tower Defense Games&…

据报道,微软的下一代 Surface 笔记本电脑将是其首款真正的“人工智能 PC”

明年&#xff0c;微软计划推出 Surface Laptop 6和 Surface Pro 10&#xff0c;这两款设备将提供 Arm 和 Intel 两种处理器选项。不愿意透露姓名的不透露姓名人士透露&#xff0c;这些新设备将引入先进的人工智能功能&#xff0c;包括配备下一代神经处理单元 (NPU)。据悉&#…

Spring Data Redis对象缓存序列化问题

相信在项目中&#xff0c;你一定是经常使用 Redis &#xff0c;那么&#xff0c;你是怎么使用的呢&#xff1f;在使用时&#xff0c;有没有遇到同我一样&#xff0c;对象缓存序列化问题的呢&#xff1f;那么&#xff0c;你又是如何解决的呢&#xff1f; Redis 使用示例 添加依…

听GPT 讲Rust源代码--src/tools(37)

File: rust/src/tools/clippy/clippy_lints/src/explicit_write.rs 在Rust源代码中&#xff0c;explicit_write.rs这个文件是Clippy的一个lint插件&#xff0c;其作用是检查代码中的write!、writeln!宏使用时的不当或繁琐的情况&#xff0c;并给出相关的警告或建议。 具体来说&…