【开发指南】HTML和JS编写多用户VR应用程序的框架

1.概述

Networked-Aframe 的工作原理是将实体及其组件同步到连接的用户。要连接到房间,您需要将networked-scene组件添加到a-scene元素。对于要同步的实体,请向其添加networked组件。默认情况下,positionrotation组件是同步的,但如果您想同步其他组件或子组件,则需要定义架构。有关网络消息的更高级控制,请参阅广播自定义消息和选项部分。

2.场景组件

A-Frame<a-scene>上的组件。

<a-scene networked-scene="serverURL: /;app: <appId>;room: <roomName>;connectOnLoad: true;onConnect: onConnect;adapter: wseasyrtc;audio: false;video: false;debug: false;
">...
</a-scene>

属性

描述

默认值

serverURL

选择 WebSocket/信令服务器所在的位置。

/

app

唯一的应用程序名称。不允许有空格。

default

room

独特的房间名称。每个应用程序可以有多个。不允许有空格。每个应用程序可以有多个房间,客户端只能连接到同一应用程序和房间中的客户端。

default

connectOnLoad

网页加载后立即连接到服务器。

true

onConnect

当客户端成功连接到服务器时调用的函数。

onConnect

adapter

您要使用的网络服务,请参阅适配器。

wseasyrtc

audio

打开/关闭您的应用程序的麦克风音频流。仅当所选适配器支持时才有效。

false

video

打开/关闭您的应用程序的视频流。仅当所选适配器支持时才有效。

false

debug

打开/关闭 Networked-Aframe 调试日志。

false

3.连接

默认情况下,networked-scene将自动连接到您的服务器。为了防止这种情况发生并控制何时连接,请在networked-scene中将connectOnLoad设置为 false。当您准备好连接时,会在a-scene元素上发出connect事件。

AFRAME.scenes[0].emit('connect');

4.断开连接

要断开连接,只需从a-scene元素中删除networked-scene组件即可。

AFRAME.scenes[0].removeAttribute('networked-scene');

从页面中完全删除a-scene也可以彻底断开连接。

5.创建网络实体

<a-assets><template id="my-template"><a-entity><a-sphere color="#f00"></a-sphere></a-entity></template>
</a-assets><!-- Attach local template by default -->
<a-entity networked="template: #my-template">
</a-entity><!-- Do not attach local template -->
<a-entity networked="template:#my-template;attachTemplateToLocal:false">
</a-entity>

创建要在客户端之间同步的模板实例。默认情况下,位置和旋转将同步。buffered-interpolation库用于允许更少的网络更新,同时保持平滑的运动。

模板只能有一个根元素。当attachTemplateToLocal设置为true时,该元素上的属性将被复制到本地实体,并且子元素将被附加到本地实体。远程实例化的实体将是模板根元素的副本,并添加了networked组件。

(1)attachTemplateToLocal=true示例

<a-entity wasd-controls networked="template:#my-template">
</a-entity><!-- Locally instantiated as: -->
<a-entity wasd-controls networked="template:#my-template"><a-sphere color="#f00"></a-sphere>
</a-entity><!-- Remotely instantiated as: -->
<a-entity networked="template:#my-template;networkId:123;"><a-sphere color="#f00"></a-sphere>
</a-entity>

(2)attachTemplateToLocal=false示例

<a-entity wasd-controls networked="template:#my-template;attachTemplateToLocal:false;">
</a-entity><!-- No changes to local entity on instantiation --><!-- Remotely instantiated as: -->
<a-entity networked="template:#my-template;networkId:123;"><a-sphere color="#f00"></a-sphere>
</a-entity>
 

属性

描述

默认值

template

存储在<a-assets>中的模板标签的 css 选择器

''”

attachTemplateToLocal

设置为 false 时,不附加本地用户的模板。当本地和远程存在不同行为时,这非常有用。

true

persistent

在远程创建者(而非所有者)断开连接时,尝试获取持久实体的所有权而不是删除它们

false

6.删除网络实体

目前只有网络实体的创建者可以删除它。要删除,只需使用常规 DOM API 从 HTML 中删除元素,Networked-Aframe 将自动处理同步。

7.同步自定义组件

默认情况下,根实体上的positionrotation组件是同步的。

要同步其他组件和子实体的组件,您需要为每个模板定义一个架构。以下是定义和添加架构的方法:

NAF.schemas.add({template: '#avatar-template',components: ['position','rotation','scale',{selector: '.hairs',component: 'show-child'},{selector: '.head',component: 'material',property: 'color'},]
});

根实体的组件可以用组件的名称来定义。子实体的组件可以使用具有selector字段和component字段的对象来定义,该字段使用document.querySelector使用的标准 CSS 选择器它指定组件的名称。要仅同步多属性组件的一个属性,请添加带有属性名称的property字段。

定义架构后,通过调用NAF.schemas.add(YOUR_SCHEMA)将其添加到架构列表中。

组件数据由 A-Frame 组件data属性检索。在网络更新期间,每个组件的数据都会根据其之前的同步值进行检查;如果数据对象发生了任何变化,它将通过网络同步。

8.同步组件优化

对于每个组件,您可以定义一个requiresNetworkUpdate函数,该函数采用当前值,如果当前值较之前值发生更改,则返回 true。如果当前值和先前值足够接近,您可以返回 false,以免将此更改发送给其他参与者。

默认情况下,当您未定义它时,它始终使用defaultRequiresUpdate函数(在networked.js顶部定义),该函数使用通用deepEqual函数来将当前值与前一个值进行比较,当两个值不同时使用cachedData = AFRAME.utils.clone(newData);以保留前一个值以供下次比较。AFRAME.utils.clone实现正做JSON.parse(JSON.stringify(obj)),可以与任何类型一起使用,但这可能不是 Vector3 类型(如位置、旋转、缩放)的最佳性能实现。

只是为了让你知道这是在做什么:

> const v = new THREE.Vector3(1,2,3);
Vector3 {x: 1, y: 2, z: 3}
> JSON.parse(JSON.stringify(v))
{x: 1, y: 2, z: 3}

因此,如果值发生变化,每次同步过程完成时都会在内存中创建一个新对象,这些对象会在某一时刻被垃圾收集。如果场景很重,垃圾收集通常可能需要 1 毫秒或更长的时间,结果可能是浏览器丢掉一些帧,因此没有一致的 fps。您可以使用 Chrome 分析器来确认这一点。对于移动的头像来说,这一点几乎不会被注意到,但如果用户拥有大量连续移动的对象,这对于您的用例可能很重要。

此外,使用当前的 aframewasd-controls实现以及位置平滑方式,在用户停止按键后 2 秒,玩家位置的变化仍然低于毫米精度,因此通过网络发送大量 NAF 消息视觉上不易察觉的位置变化。 NAF 已经包含位置插值来平滑接收到的位置变化,因此通过网络发送所有这些位置变化甚至是多余的。

您可以使用专用函数来比较给定精度的两个 Vector3,通过避免创建新对象,通过网络和内存发送更少的消息来实现更好的性能:

const vectorRequiresUpdate = epsilon => {return () => {let prev = null;return curr => {if (prev === null) {prev = new THREE.Vector3(curr.x, curr.y, curr.z);return true;} else if (!NAF.utils.almostEqualVec3(prev, curr, epsilon)) {prev.copy(curr);return true;}return false;};};
};

这个函数实际上是在NAF.utils.vectorRequiresUpdate中定义的,供你使用。

要在网络模式中使用它以获得 1 毫米的位置精度和 0.5 度的旋转精度,请按如下方式使用:

{template: '#avatar-template',components: [{component: 'position',requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.001)},{component: 'rotation',requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.5)}]
}

从0.11.0版本开始,同步位置和旋转的默认模式使用上述优化。

9.同步嵌套模板 - 例如:手

要同步嵌套模板,请像这样设置 HTML 节点:

<a-entity id="player" networked="template:#player-template;attachTemplateToLocal:false;" wasd-controls><a-entity camera look-controls networked="template:#head-template;attachTemplateToLocal:false;"></a-entity><a-entity hand-controls="hand:left" networked="template:#left-hand-template"></a-entity><a-entity hand-controls="hand:right" networked="template:#right-hand-template"></a-entity>
</a-entity>

在此示例中,头部/摄像头、控制器的左手和右手将生成自己的模板,这些模板将独立于根玩家进行联网。注意:这与当前不支持的手部追踪无关。这种父子关系仅在一个级别之间有效,即。子实体的直接父实体必须具有networked组件。

您需要自己定义左手和右手模板,以便向其他用户显示手部模型。只有位置和旋转会同步给其他用户。要同步手势,请参阅下面的networked-hand-controls组件。

10.带同步手势的跟踪控制器

这是比上述更简单的替代方案。 NAF 允许轻松添加其他人可见的手部模型,这些模型显示与触摸的按钮相匹配的模拟手势(不是手部跟踪),这样您就可以向房间里的其他人指向并竖起大拇指或握拳。

您所要做的就是使用内置的networked-hand-controls组件,将这两个实体添加为相机装备的子级:

<a-entityid="my-tracked-left-hand"networked-hand-controls="hand:left"networked="template:#left-hand-default-template"
></a-entity>
<a-entityid="my-tracked-right-hand"networked-hand-controls="hand:right"networked="template:#right-hand-default-template"
></a-entity

您可以设置的公共架构属性有:

属性

描述

默认值

取值范围

color

将被设置为材质颜色

white

hand

指定实体是用于左手还是右手

left

left, right

handModelStyle

A-Frame中可用的内置模型

highPoly

highPoly, lowPoly, toon, controller

customHandModelURL

可选的自定义手模型网址

请注意“控制器”选项——它将使用控制器本身的模型,根据您的平台自动正确设置——它还将广播模型支持的按钮网格更新。 (不幸的是,Quest 2 模型按钮网格目前存在一个错误,因此不会显示任何更新。)

networked-hand-controls正在完全替换hand-controls,不要同时使用两者。如果您使用如上所述的网络组件,则无需为每只手定义模板和网络架构。默认模板和网络模式已定义如下:

<template id="left-hand-default-template"><a-entity networked-hand-controls="hand:left"></a-entity>
</template>
<template id="right-hand-default-template"><a-entity networked-hand-controls="hand:right"></a-entity>
</template>
NAF.schemas.add({template: '#left-hand-default-template',components: [{component: 'position',requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.001)},{component: 'rotation',requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.5)},'networked-hand-controls']
});
NAF.schemas.add({template: '#right-hand-default-template',components: [{component: 'position',requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.001)},{component: 'rotation',requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.5)},'networked-hand-controls']
});

11.发送自定义消息

NAF.connection.subscribeToDataChannel(dataType, callback)
NAF.connection.unsubscribeToDataChannel(dataType)NAF.connection.broadcastData(dataType, data)
NAF.connection.broadcastDataGuaranteed(dataType, data)NAF.connection.sendData(clientId, dataType, data)
NAF.connection.sendDataGuaranteed(clientId, dataType, data)

订阅和取消订阅dataType指定的网络消息的回调。使用broadcastData功能向房间内的所有客户端广播数据。要仅发送到特定客户端,请改用sendData函数。

参数

描述

clientId

将此数据发送到的 ClientId

dataType

用于标识网络消息的字符串。u(更新)、um(UpdateMulti)和r(删除)是保留数据类型,请不要使用它们

callback

收到类型dataType的消息时调用的函数。参数:function(senderId, dataType, data, targetObj)使用 easyrtc 适配器,targetObj在广播消息时可以是{targetRoom: 'roomId'},或者在向特定参与者发送消息时可以是{targetEasyrtcid: 'targetId'}。对于 janus 适配器,senderId 始终为 null,并且targetObj更多的是source参数,通常等于“janus-event”。

data

要发送给所有其他客户端的对象

12.转让实体所有权

实体的所有者负责同步其组件数据。当用户想要修改另一个用户的实体时,他们必须首先获得该实体的所有权。所有权转移示例和切换所有权组件展示了如何获取实体的所有权并更新它。

NAF.utils.takeOwnership(entityEl)

取得实体的所有权。

NAF.utils.isMine(entityEl)

检查您是否拥有指定实体。

13.事件

当 NAF 中发生某些事情时,事件就会被触发。要订阅这些事件,请遵循以下模式:

document.body.addEventListener('clientConnected', function (evt) {console.error('clientConnected event. clientId =', evt.detail.clientId);
});

创建document.body元素后需要订阅事件。这可以通过等待document.bodyonLoad方法或使用 NAF 的onConnect函数来实现。使用 NAF 活动演示作为示例。

事件列表:

事件

描述

取值范围

clientConnected

当另一个客户端连接到您时触发

evt.detail.clientId- 连接客户端的ClientId

clientDisconnected

当另一个客户端与您断开连接时触发

evt.detail.clientId- 断开连接的客户端的ClientId

entityCreated

创建网络实体时触发

evt.detail.el- 新实体

entityRemoved

删除网络实体时触发

evt.detail.networkId- 已删除实体的网络ID

以下事件在networked组件上触发。有关示例,请参阅切换所有权组件。

所有权转让事件列表:

事件

描述

参数范围

ownership-gained

当网络实体的所有权被夺取时触发

evt.detail.el- 获得所有权的实体

evt.detail.oldOwner- 前任所有者的 clientId

ownership-lost

当网络实体的所有权丢失时触发

evt.detail.el- 失去所有权的实体

evt.detail.newOwner- 新所有者的 clientId

ownership-changed

当网络实体的所有权更改时触发

evt.detail.el- 失去所有权的实体

evt.detail.oldOwner- 前任所有者的 clientId

evt.detail.newOwner- 新所有者的 clientId

14.适配器

NAF 可与多个网络库和服务一起使用。适配器是一个向 NAF 添加对库的支持的类。如果您只是在开发一个小项目或概念验证,那么您可能会使用默认配置,并且可以跳过本节。评估不同适配器时应考虑的因素包括:

  • 一间房间需要支持多少个并发用户?

  • 您想托管自己的服务器吗?或者像 Firebase 这样的“无服务器”解决方案可以完成这项工作吗?

  • 您需要音频(麦克风)流吗?

  • 您需要自定义服务器端逻辑吗?

  • 您想要 WebSocket(客户端-服务器)网络架构还是 WebRTC(点对点)网络架构?

默认情况下使用wseasyrtc适配器,它不支持音频并使用 TCP 连接。这对于生产部署来说并不理想,但是由于 WebRTC 固有的连接问题,我们将其设置为默认值。要通过 WebRTC 支持音频,请确保服务器使用 https 并将适配器更改为easyrtc(这使用 UDP)。

支持的适配器列表:

适配器

描述

音频/视频支持情况

基于WebSocket 或 WebRTC

如何启动

wseasyrtc

默认 - 使用 open-easyrtc 库

No

WebSocket

npm run dev

easyrtc

使用 open-easyrtc 库

音频和视频(相机和屏幕共享)

WebRTC

npm run dev

janus

使用 Janus WebRTC 服务器和 janus-plugin-sfu

音频和视频(相机或屏幕共享)

WebRTC

参阅 naf-janus-adapter

socketio

无需外部库的 SocketIO 实现(服务器支持房间实例化)

No

WebSocket

npm run dev-socketio

webrtc

无需外部库的原生 WebRTC 实现(正在进行中,目前没有维护者)

音频

WebRTC

npm run dev-socketio

Firebase

用于 WebRTC 信号传输的 Firebase(目前没有维护者)

No

WebRTC

参阅 naf-firebase-adapter

uWS

uWebSockets 的实现(目前没有维护者)

No

WebSocket

参阅 naf-uws-adapter

表中的 WebRTC 表示组件更新使用 WebRTC 数据通道 (UDP),而不是 WebSocket (TCP)。您仍然有一个用于信令部分的 WebSocket。

更为详细比较,请参阅文档 NAF 适配器比较。

15.音频

audio: true添加到networked-scene组件(并使用支持它的适配器)后,默认情况下您将听不到任何音频。尽管音频将进行流式传输,但在创建具有networked-audio-source的实体之前,它是听不到的。来自该实体所有者的音频将从该实体的位置在 3D 空间中发出。networked-audio-source组件必须与networked组件一起添加到实体(或实体的子实体)。

要使麦克风静音/取消静音,您可以使用以下 API(easyrtc 和 janus 适配器):

NAF.connection.adapter.enableMicrophone(enabled)

其中enabledtruefalse

16.视频

video: true(janus 适配器不需要)添加到networked-scene组件(并使用支持它的适配器)后,默认情况下您将看不到任何视频。尽管视频将进行流式传输,但在创建使用带有networked-video-source的网格(例如<a-plane>)的实体之前,它是不可见的。来自该实体所有者的视频将在 3D 空间中从该实体的位置可见。networked-video-source组件必须添加到具有networked组件的实体的<a-plane>子实体中。

目前,这仅适用于支持getMediaStream(clientId, type="video")API 的 easyrtc 和 janus 适配器。

请参阅,该示例显示了没有音频的用户摄像头。

要禁用/重新启用相机,您可以使用以下 API(仅限 easyrtc 适配器):

NAF.connection.adapter.enableCamera(enabled)

其中enabledtruefalse

使用 easyrtc 适配器,您可以使用addLocalMediaStreamremoveLocalMediaStreamAPI 添加额外的视频轨道,例如屏幕共享:

navigator.mediaDevices.getDisplayMedia().then((stream) => {NAF.connection.adapter.addLocalMediaStream(stream, "screen");
});NAF.connection.adapter.removeLocalMediaStream("screen");

请参阅多流示例,该示例使用带有networked-video-source="streamName: screen"的第二个平面向其他参与者显示屏幕共享。请务必查看此示例 html 文件末尾的注释以了解已知问题。

17.杂项

NAF.connection.isConnected()

如果已与信令服务器建立连接,则返回 true。

NAF.connection.getConnectedClients()

返回当前连接的客户端列表。

18.选项

NAF.options.updateRate

每秒调用网络组件sync函数的频率。对于大多数社交 VR 应用程序来说,10-20 是正常的。默认为15

NAF.options.useLerp

默认情况下,当创建实体时,buffered-interpolation库用于平滑位置、旋转和缩放网络更新。如果您不希望在创建时使用此功能,请将其设置为 false。

19.离线使用

NAF 已经包含 easyrtc,因此运行npm run dev将提供完全有效的解决方案,而无需访问外部服务器。不过,这些示例确实依赖于 AFrame 和其他未与 NAF 打包的依赖项。因此,必须首先使 AFrame 适应离线工作,然后对所有其他组件执行相同的操作。这基本上可以归结为下载所使用的脚本及其内容,例如 3D 模型、字体等资产。建议在网络控制台打开时加载页面并识别哪些请求来自主机外部。

对于 VR,您还需要 https,因为浏览器需要它才能实现沉浸式模式。server/easyrtc-server.js文件中提供了说明。也就是说,您必须生成密钥和证书,将它们添加到本地 CA,然后通过 NAF 提供的 Express 服务器加载它们。确保在server/easyrtc-server.js顶部正确配置,并按照说明通过https.createServer进一步向下启用 https 本身。一旦您连接到 VR 中的 NAF 服务器,浏览器仍然会抱怨证书未知。您可以单击高级并继续。

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

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

相关文章

【BUG】已解决:AttributeError: ‘NoneType‘ object has no attribute ‘split‘

已解决&#xff1a;AttributeError: ‘NoneType‘ object has no attribute ‘split‘ 英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;…

Android:将自定义视图设为互动式

一、简介 点击查看将自定义视图设为互动式官网文档 绘制界面只是创建自定义视图的一个部分。您还需要让视图以非常类似于您模仿的真实操作的方式响应用户输入。 让应用中的对象的行为方式与真实对象相似。例如&#xff0c;不要让应用中的图片消失后重新出现在其他位置&#x…

防洪墙的安全内容检测+http请求头

1、华为的IAE引擎&#xff1a;内部工作过程 IAE引擎主要是针对2-7层进行一个数据内容的检测 --1、深度检测技术 (DPI和DPF是所有内容检测都必须要用到的技术) ---1、DPI--深度包检测&#xff0c;针对完整的数据包&#xff0c;进行内容的识别和检测 1、基于特征子的检…

使用Django框架实现音频上传功能

数据库设计&#xff08;models.py&#xff09; class Music(models.Model):""" 音乐 """name models.CharField(verbose_name"音乐名字", max_length32)singer models.CharField(verbose_name"歌手", max_length32)# 本质…

「51媒体」广东展览展会媒体宣传,媒体邀约名单

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 广州作为最具经济活力的省份之一&#xff0c;每年大大小小的展会吸引着全球的客商&#xff0c;在展览展会期间能邀请哪些媒体来报道宣传呢&#xff1f; 广东展览展会媒体宣传的媒体邀约名…

sourcrinlight 4.0 的使用技巧:如何在文件名后省略路径名

如图&#xff1a; 如果路径名很长&#xff0c;将显示不了几个文件名的&#xff0c;会造成一些不便。如何隐藏文件的路径名呢&#xff1f; 选中或取消这个按钮&#xff1a; 就可以了。要想再查看文件路径&#xff0c;鼠标放上去&#xff0c;就会显示了&#xff1a; 谢谢

2024最新Cloudways主机使用教程(含最新Cloudways折扣码)

Cloudways是一家提供云托管服务的公司&#xff0c;可以帮助你轻松管理和运行你的网站。本教程是Cloudways主机注册和使用教程。Cloudways界面简洁&#xff0c;使用方便&#xff0c;不需要复杂的设置&#xff0c;就能快速搭建一个WordPress网站。它的主机功能包括高级缓存和Bree…

Electron案例解析-获取 Chrome、Node.js和Electron版本号的应用案例

实现效果 目录结构 index.html <!DOCTYPE html> <html> <head><meta charset"UTF-8" /><!-- 内容安全策略--><metahttp-equiv"Content-Security-Policy"content"default-src self; script-src self"/><…

微信公众平台无限回调系统 /user/ajax.php SQL注入漏洞复现

0x01 产品简介 微信公众平台无限回调系统是一种旨在提升企业客户服务体验和运营效率的工具。该系统通过一系列智能化和自动化的功能,帮助企业与用户之间建立更加便捷、高效的沟通桥梁。 0x02 漏洞概述 微信公众平台无限回调系统 /user/ajax.php 接口存在SQL注入漏洞,未经身…

live555 rtsp服务器实战之doGetNextFrame

live555关于RTSP协议交互流程 live555的核心数据结构值之闭环双向链表 live555 rtsp服务器实战之createNewStreamSource live555 rtsp服务器实战之doGetNextFrame 注意&#xff1a;该篇文章可能有些绕&#xff0c;最好跟着文章追踪下源码&#xff0c;不了解源码可能就是天书…

windows docker nvidia wsl2

下载驱动(GeForce Experience里的也可以)https://www.nvidia.cn/Download/index.aspx 安装wsl2https://blog.csdn.net/qq_39942341/article/details/121512900?ops_request_misc%257B%2522request%255Fid%2522%253A%2522172122816816800227436617%2522%252C%2522scm%2522%253A…

mac M1 创建Mysql8.0容器

MySLQ8.0 拉取m1镜像 docker pull mysql:8.0创建挂载文件夹并且赋予权限 sudo chmod 777 /Users/zhao/software/dockerLocalData/mysql 创建容器并且挂载 docker run --name mysql_8 \-e MYSQL_ROOT_PASSWORDadmin \-v /Users/zhao/software/dockerLocalData/mysql/:/var/l…

CSS3实现提示工具的渐入渐出效果及CSS3动画简介

上一篇文章用CSS3实现了一个提示工具&#xff0c;本文介绍如何利用CSS3实现提示工具以渐入的方式呈现&#xff0c;以渐出的方式消失。 CSS3主要可以通过两个样式来实现动画效果&#xff1a;animation和transition。 其中&#xff0c;animation需要自己定义一组关键帧从而实现…

第十届能源材料与电力工程国际学术会议(ICEMEE 2024)

第十届能源材料与电力工程国际学术会议&#xff08;ICEMEE 2024) 2024 10th International Conference on Energy Materials and Electrical Engineering 重要信息 ICEMEE 2024已通过SPIE - The International Society for Optical Engineering (ISSN: 0277-786X)单独出版…

修改了mybatis的xml中的sql不重启服务器如何动态加载更新

目录 一、背景 二、注意 三、代码 四、使用示例 五、其他参考博客 一、背景 开发一个报表功能&#xff0c;好几百行sql&#xff0c;每次修改完想自测下都要重启服务器&#xff0c;启动一次服务器就要3分钟&#xff0c;重启10次就要半小时&#xff0c;耗不起时间呀。于是在…

Spring Security之安全异常处理

前言 在我们的安全框架中&#xff0c;不管是什么框架&#xff08;包括通过过滤器自定义&#xff09;都需要处理涉及安全相关的异常&#xff0c;例如&#xff1a;登录失败要跳转到登录页&#xff0c;访问权限不足要返回页面亦或是json。接下来&#xff0c;我们就看看Spring Sec…

公司政务办理流程分享(北京)

社保增减员&#xff1a; 参保登记——增减员业务这么办_北京市人力资源和社会保障局_社会保险 https://rsj.beijing.gov.cn/yltc/202310/t20231025_3287007.html 公积金增减员&#xff1a; https://dwwsyw.gjj.beijing.gov.cn/

CentOS 7 初始化环境配置详细

推荐使用xshell远程连接&#xff0c;如链接不上 请查看 CentOS 7 网络配置 修改主机名 hostname hostnamectl set-hostname xxx bash 关闭 SElinux 重启之后生效 配置yum源&#xff08;阿里&#xff09; 先备份CentOS-Base.repo&#xff0c;然后再下载 mv /etc/yum.repos…

ROS参数服务器理论模型

ROS参数服务器理论模型 参数服务器角色实现参数服务器流程参数可以使用的类型 参数服务器角色 参数服务器实现是最为简单的&#xff0c;该模型如下图所示,该模型中涉及到三个角色: ROS Master (管理者)Talker (参数设置者)Listener (参数调用者) 实现参数服务器流程 整个流…

Ubuntu 24.04安装Jellyfin媒体服务器图解教程

使用 Jellyfin 等开源软件创建媒体服务器肯定能帮助您管理和跨各种设备传输媒体集合。当你有一个封闭社区时&#xff0c;这尤其有用。 什么是 Jellyfin 媒体服务器&#xff1f; Jellyfin 媒体服务器&#xff0c;顾名思义&#xff0c;是一款开源软件&#xff0c;允许用户使用本…