手摸手系列之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 = true
      this.map.destroy()
    },
    beforeDestroy() {
      this.stopTimer = true
      this.map.destroy()
    },
    methods: {
      isRealtime(value) {
        if (value === true) {
          this.stopTimer = false
          this.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.result
							this.firstVcl = data.firstVcl
							if (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.15
        plugins: ['AMap.ToolBar', 'AMap.Scale', 'AMap.MapType'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
      })
        .then((AMap) => {
          this.map = new AMap.Map("container", {
						mapStyle: "amap://styles/fresh", // 设置地图的显示样式
            // 设置地图容器id
            viewMode: "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()); // 图层切换

					// 创建一个 Icon
					var 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-label
					this.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 {
				//TODO
				value = 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.397428
				if (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 = lon
				let lat = 39.90923
				if (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整合高德地图总的来说还是非常简单的,下一篇我们继续来介绍如何实现展示车辆的某段时间的运行轨迹。

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

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

相关文章

【数据结构】栈【详解】

目录 栈的定义&#xff1a; 栈的声明与定义&#xff1a; 头文件的包含&#xff1a; 对栈的基本操作&#xff1a; 栈的初始化&#xff1a; 摧毁栈: 入栈&#xff1a; ​编辑 出栈&#xff1a; ​编辑 输出栈顶位置&#xff1a; 输出栈的当前大小&#xff1a; 判空操…

小兔鲜儿 uniapp - 购物车模块

目录 加入购物车​ 接口相关​ 购物车列表​ 静态结构​ 登录状态​ 列表渲染​ 删除购物车 接口相关​ 参考代码 修改商品信息​ 接口相关​ ​修改商品数量​ 修改商品选中/全选​ 底部结算信息​ 计算总钱数(总金额)​ 带返回按钮的购物车​ 完成加入购物车…

读书笔记1-C++ Primer Plus

C是在C语言基础上开发的一种集面向对象编程&#xff08;OOP&#xff09;、通用编程和传统的过程化编程于一体的编程语言。本书是根据2003年的ISO/ANSI C标准编写的&#xff0c;通过大量短小精悍的程序详细而全面地阐述了C的基本概念和技术。 全书分17章和10个附录&#xff0c;分…

UE5.1_Gameplay Debugger启用

UE5.1_Gameplay Debugger启用 重点问题&#xff1a; Gamplay Debugger启用不知道&#xff1f; Apostrophe、Tilde键不知道是哪个&#xff1f; Gameplay调试程序 | 虚幻引擎文档 (unrealengine.com) Gameplay Debugger

2023下半年的总结

我从八月下旬开始写的&#xff0c;到现在差不多有半年了&#xff0c;总结一下吧&#xff01; 1.计算机视觉 在计算机视觉方面&#xff0c;想必两个有名的深度学习框架&#xff08;TensorFlow和PyTorch&#xff09;大家都很清楚吧&#xff0c;以及OpenCV库。对于人脸识别&…

王道考研计算机网络——应用层

如何为用户提供服务&#xff1f; CS/P2P 提高域名解析的速度&#xff1a;local name server高速缓存&#xff1a;直接地址映射/低级的域名服务器的地址 本机也有告诉缓存&#xff1a;本机开机的时候从本地域名服务器当中下载域名和地址的对应数据库&#xff0c;放到本地的高…

cargo设置国内源 windows+linux

cargo默认的源比pip的源好多了&#xff0c;但是有时候速度还是很慢 一、部分国内源&#xff08;排名不分先后&#xff09; 这些源的格式用在具体的配置文件中 中国科学技术大学 [source.crates-io] replace-with ustc[source.ustc] registry "git://mirrors.ustc.ed…

用LCD循环右移显示“Welcome to China“

#include<reg51.h> //包含单片机寄存器的头文件 #include<intrins.h> //包含_nop_()函数定义的头文件 sbit RSP2^0; //寄存器选择位&#xff0c;将RS位定义为P2.0引脚 sbit RWP2^1; //读写选择位&#xff0c;将RW位定义为P2.1引脚 sbit EP2^2; //使能…

【形式语言与自动机/编译原理】CFG-->Greibach-->NPDA(2)

本文将详细讲解《形式语言与自动机》&#xff08;研究生课程&#xff09;或《编译原理》&#xff08;本科生课程&#xff09;中的上下文无关文法&#xff08;CFG&#xff09;转换成Greibach范式&#xff0c;再转成下推自动机&#xff08;NPDA&#xff09;识别语言是否可以被接受…

内侧APP分发平台:移动应用开发的加速器

在数字化时代&#xff0c;移动应用已成为企业触达用户的重要渠道。为了迅速占领市场&#xff0c;开发者需要一种能够快速发布和测试移动应用的解决方案。内侧APP分发平台应运而生&#xff0c;它通过简化应用的封装、测试和分发流程&#xff0c;极大地提升了移动应用的上市速度。…

WPF+Halcon 培训项目实战(13):HS 鼠标绘制图形

文章目录 前言相关链接项目专栏运行环境匹配图片矩形鼠标绘制Halcon添加右键事件Task封装运行结果个人引用问题原因推测 圆形鼠标绘制代码运行结果 后面安排 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想换个工作。相关的教学视频来源于下方…

《深入理解JAVA虚拟机笔记》对象的创建和访问、对象头

对象的创建 当 Java 虚拟机遇到一条字节码 new 指令时&#xff0c;首先将去检查这个指令的参数是否能做常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有&#xff0c;那必须先执行相应的类加载过程。 在类加载…

2021-03-17 51单片机设计洗衣机

缘由51单片机设计洗衣机_其他-CSDN问答 通过控制两个继电器循环工作状态&#xff0c;模拟洗衣机间歇正反转。设定正转3s&#xff0c;停止2s&#xff0c;然后反转3s&#xff0c;停止2s&#xff0c;循环上述动作。求代码和proteus仿真图。 #include "reg52.h" sbit L…

金融帝国实验室(Capitalism Lab)官方正版游戏『2024新年特卖优惠』

「金融帝国实验室」&#xff08;Capitalism Lab&#xff09;Enlight 官方正版游戏「2024新年特卖」 ■优惠时限&#xff1a;2024.01.01&#xff5e;01.31 ■游戏开发商&#xff1a;Enlight Software Ltd. 请您认准以下官方正版游戏购买链接&#xff1a;支持“支付宝&am…

08 通信协议之UART

引言&#xff1a; 从本文开始&#xff0c; 本个专题之后的几篇文章都是讲解嵌入式开发中几种常见的通信协议的&#xff0c; 比如UART, I2C&#xff0c;SPI&#xff0c; CAN总线这些我就不讲了&#xff0c; 没用到过&#xff0c; 学是学不完的&#xff0c; 等用到的时候再去学习…

如何开发一个google插件(二)

前言 在上一篇文章如何开发一个google插件(一)里主要介绍了google插件的基本结构。 在这篇文章中主要结合reactwebpack进行一个代码演示&#xff0c;源码地址&#xff1a;源码地址 下载源码后打开浏览器的扩展程序管理->加载已解压的扩展程序&#xff0c;即可调试插件 此…

2024年安全员-B证证模拟考试题库及安全员-B证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年安全员-B证证模拟考试题库及安全员-B证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;安全员-B证证模拟考试题库是根据安全员-B证最新版教材&#xff0c;安全员-B证大纲整理而成&#xff08;含2024年…

java struts2教务管理系统Myeclipse开发mysql数据库struts2结构java编程计算机网页项目

一、源码特点 java struts2 教务管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助 struts2 框架开发&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库…

7.12全排列②(LC47-M)

算法&#xff1a; 这道题目和46.全排列 (opens new window)的区别在与给定一个可包含重复数字的序列&#xff0c;要返回所有不重复的全排列。 所以就是多了个去重操作。 还是一样的套路&#xff1a; 先排序&#xff1a; Arrays.sort(nums); 再去重&#xff1a; // used[…

C语言课程设计参考题目

一、工资管理系统 需求分析 工资信息存放在文件中&#xff0c;提供文件的输入、输出等操作&#xff1b;要实现浏览功能&#xff0c;提供显示、排序操作&#xff1b;而查询功能要求实现查找操作&#xff1b;另外还应该提供键盘式选择菜单以实现功能选择。 2、总体设计 整个系统可…