如何进行页面前端监控

article/2025/6/8 15:06:46

🧑‍💻 写在开头
点赞 + 收藏 === 学会🤣🤣🤣

前端监控主要分三个方向

前端性能(用户体验优化)
异常监控
业务指标跟

下面我来分别介绍三类指标如何获取

1)前端性能指标:

一、用户体验相关的:

页面加载时间(Page Load Time) :

定义:从用户请求页面到页面完全加载的时间。
测量方法:使用Performance API中的performance.timing对象。

首次内容绘制(First Contentful Paint, FCP) :

定义:浏览器从DOM中渲染出第一个内容的时间点。
测量方法:使用PerformanceObserver来监听paint条目。

最大内容绘制(Largest Contentful Paint, LCP) :

定义:页面加载过程中最大可见内容的绘制时间。
测量方法:使用PerformanceObserver来监听largest-contentful-paint条目。

首次输入延迟(First Input Delay, FID) :

定义:用户首次与页面交互(如点击按钮)到浏览器开始响应交互的时间。
测量方法:使用EventListeners结合PerformanceObserver。

累积布局偏移(Cumulative Layout Shift, CLS) :

定义:页面布局在加载过程中发生的意外变化的累积得分。
测量方法:使用PerformanceObserver来监听layout-shift条目。

总阻塞时间(Total Blocking Time, TBT):

定义: TBT 是一个网页性能指标,用于衡量从首次内容绘制(First Contentful Paint, FCP)到可交互时间(Time to Interactive, TTI)之间,所有超过 50 毫秒的长任务阻塞主线程的时间总和。TBT 反映了页面在加载过程中用户交互的延迟情况。
测量方法: 使用PerformanceObserver来监听longtask条目。通过这种方式,可以捕获并计算页面在加载过程中所有长任务的阻塞时间。

交互时间(Time to Interactive, TTI) :

定义:页面从开始加载到完全可交互的时间。
测量方法:通常通过分析资源加载和长任务来估算。虽然没有直接的API,但可以结合Long Tasks API和其他指标来推测。

示例代码
以下是一个简单的示例代码,展示如何使用Performance API和PerformanceObserver来测量这些指标:

// 页面加载时间
window.addEventListener('load', () => {const timing = performance.timing;const pageLoadTime = timing.loadEventEnd - timing.navigationStart;console.log(`Page Load Time: ${pageLoadTime} ms`);
});// 首次内容绘制和最大内容绘制
const observer = new PerformanceObserver((list) => {const entries = list.getEntries();entries.forEach((entry) => {if (entry.name === 'first-contentful-paint') {console.log(`First Contentful Paint: ${entry.startTime} ms`);}if (entry.entryType === 'largest-contentful-paint') {console.log(`Largest Contentful Paint: ${entry.startTime} ms`);}});
});
observer.observe({ type: 'paint', buffered: true });
observer.observe({ type: 'largest-contentful-paint', buffered: true });// 首次输入延迟
let firstInputDelay = 0;
const fidObserver = new PerformanceObserver((list) => {const entries = list.getEntries();for (const entry of entries) {firstInputDelay = entry.processingStart - entry.startTime;console.log(`First Input Delay: ${firstInputDelay} ms`);}
});
fidObserver.observe({ type: 'first-input', buffered: true });// 累积布局偏移
let cumulativeLayoutShiftScore = 0;
const clsObserver = new PerformanceObserver((list) => {for (const entry of list.getEntries()) {if (!entry.hadRecentInput) {cumulativeLayoutShiftScore += entry.value;console.log(`Cumulative Layout Shift: ${cumulativeLayoutShiftScore}`);}}
});
clsObserver.observe({ type: 'layout-shift', buffered: true });// 长任务
const ttiObserver = new PerformanceObserver((entryList) => {const entries = entryList.getEntries();entries.forEach(entry => {console.log(`Long Task detected: ${entry.startTime} ms, duration: ${entry.duration} ms`);});
});ttiObserver.observe({ entryTypes: ['longtask'] });

总结:上面的指标performance.timing主要是采集一些基础的时间,目前都是前后端分离的项目参考意义已经不大,除非是ssr和服务端的项目这部分指标有一些参考价值。像最大内容绘制largest-contentful-paint 是一个持续变动的指标,最后计算出最大时间,位移数据也是如此,长任务也是如此持续监听过程。

二、页面资源相关

在前端监控中资源监控方面,通常使用的是浏览器提供的Performance API。这个 API 提供了一组接口,对于资源监控,具体来说,可以使用以下接口:

PerformanceResourceTiming:

这个接口提供了关于每个资源加载的详细计时信息。通过它,你可以获取到资源加载的各个阶段的时间,例如 DNS 查询时间、TCP 连接时间、请求时间、响应时间等。

PerformanceObserver:

这是一个更为通用的接口,可以用来监听各种性能条目(performance entry)。通过PerformanceObserver,你可以监听到资源加载事件(resource类型),并在资源加载完成时获取到相应的PerformanceResourceTiming对象。

以下是一个简单的示例,展示如何使用PerformanceObserver来监控资源加载:

if ('PerformanceObserver' in window) {const observer = new PerformanceObserver((list) => {const entries = list.getEntriesByType('resource');entries.forEach((entry) => {console.log(`Resource: ${entry.name}`);console.log(`Start Time: ${entry.startTime}`);console.log(`Duration: ${entry.duration}`);console.log(`Initiator Type: ${entry.initiatorType}`);});});observer.observe({ type: 'resource', buffered: true });
}

总结:他可以对页面所有的资源加载进行监控,比如 js,css,图片还能够对xmlhttprequest和fetch监控。也就是说他能够对接口进行监控,当我们的页面有一些超长的请求可以单独识别出来进行报警。

下面是对请求接口的监控:

if ('PerformanceObserver' in window) {const observer = new PerformanceObserver((list) => {const entries = list.getEntriesByType('resource');entries.forEach((entry) => {if (entry.initiatorType === 'xmlhttprequest' || entry.initiatorType === 'fetch') {console.log(`API Request: ${entry.name}`);console.log(`Start Time: ${entry.startTime}`);console.log(`Duration: ${entry.duration}`);console.log(`Fetch Start: ${entry.fetchStart}`);console.log(`Response End: ${entry.responseEnd}`);console.log(`Transfer Size: ${entry.transferSize}`);}});});observer.observe({ type: 'resource', buffered: true });
}

三、其他一些不太重要的监控(不细讲)

navigator.getBattery() : 电池监控
Performance Memory API: 内存监控

2)异常监控

一、监听形式

监听形式主要是通过捕获全局错误事件来实现。这种方式可以捕获大部分未处理的异常,并可以将其记录或发送到服务器进行分析。

1. 使用window.onerror

window.onerror是最传统的异常捕获方法,可以捕获运行时的 JavaScript 错误。

window.onerror = function(message, source, lineno, colno, error) {console.error('Error caught:', message, source, lineno, colno, error);// 可以在这里将错误信息发送到服务器sendErrorToServer({message,source,lineno,colno,error: error ? error.stack : null});
};function sendErrorToServer(errorInfo) {fetch('/log-error', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(errorInfo)});
}

2. 使用window.addEventListener(‘error’)

这种方法可以捕获资源加载错误(如图片、脚本加载失败)。

window.addEventListener('error', function(event) {console.error('Resource Error:', event);// 处理资源加载错误if (event.target instanceof HTMLImageElement) {console.error('Image failed to load:', event.target.src);}// 可以在这里将错误信息发送到服务器sendErrorToServer({message: event.message,source: event.filename,lineno: event.lineno,colno: event.colno,error: event.error ? event.error.stack : null});
}, true);

3. 使用window.addEventListener(‘unhandledrejection’)

捕获未处理的 Promise 异常,此处主要用来捕获Promise没有被catch的异常,属于最后的兜底。

window.addEventListener('unhandledrejection', function(event) {console.error('Unhandled promise rejection:', event.reason);// 可以在这里将错误信息发送到服务器sendErrorToServer({message: event.reason ? event.reason.toString() : 'Unknown reason',error: event.reason && event.reason.stack ? event.reason.stack : null});
});

二、主动上报形式

主动上报形式是指在代码中手动捕获异常并上报。适用于需要在特定逻辑中捕获异常的场景。

1. 使用try…catch

在代码中使用try…catch来捕获异常,并在catch块中进行上报。

function riskyOperation() {try {// 执行可能抛出异常的代码let result = potentiallyFailingFunction();console.log('Operation successful:', result);} catch (error) {console.error('Caught an error:', error);// 在这里上报错误sendErrorToServer({message: error.message,error: error.stack});}
}function potentiallyFailingFunction() {// 模拟可能抛出异常的代码if (Math.random() > 0.5) {throw new Error('Random failure');}return 'Success';
}

2. 集成到应用框架

在现代前端框架(如 React、Vue)中,可以利用框架的错误边界或错误处理机制来捕获和上报异常。

React: 使用 Error Boundary

class ErrorBoundary extends React.Component {constructor(props) {super(props);this.state = { hasError: false };}static getDerivedStateFromError(error) {return { hasError: true };}componentDidCatch(error, errorInfo) {console.error('ErrorBoundary caught an error:', error, errorInfo);// 在这里上报错误sendErrorToServer({message: error.message,error: error.stack,componentStack: errorInfo.componentStack});}render() {if (this.state.hasError) {return <h1>Something went wrong.</h1>;}return this.props.children;}
}// 使用 ErrorBoundary 包裹组件
<ErrorBoundary><YourComponent />
</ErrorBoundary>

总结:我本人更加倾向于主动上报形式,因为在现在的开发形式里面,编译工具和开发工具能够帮我们避免绝大多数的异常情况,我们的监控往往因为业务逻辑和接口数据返回不对导致对业务的影响,所以主动上报能够更加准确和清晰的给出异常,这样利于我们去监控,往往比较多的异常问题不是错误导致更多就是接口不符合预期这样window.onerror形式不太全,最多只能当一个辅助使用。

3、业务指标跟踪

业务指标跟踪也是前端监控的一部分,主要用于收集和分析用户在应用中的行为数据,以帮助理解用户的使用模式、评估功能效果、优化用户体验等。常见的业务指标包括页面访问量、点击事件、用户停留时间、转化率等,很多公司都是单独做,我所在的公司就是这样,其实原理很简单就是调用一个接口把想要上报的数据给带过去就行。

let clickCount = 0;// 获取按钮元素
const button = document.getElementById('trackButton');// 为按钮添加点击事件监听器
button.addEventListener('click', () => {clickCount++;console.log('按钮点击次数:', clickCount);
});// 页面卸载时发送数据
window.addEventListener('beforeunload', () => {const data = JSON.stringify({ clickCount });// 使用 sendBeacon 发送数据,确保在页面卸载时也能发送成功if (navigator.sendBeacon) {navigator.sendBeacon('/track-clicks', data);} else {// 备用方案,使用 fetch 发送数据fetch('/track-clicks', {method: 'POST',headers: {'Content-Type': 'application/json'},body: data});}
});

有个问题,为什么用navigator.sendBeacon去发送数据 ?这就涉及到如何上报数据的问题,下面我具体讲下。

一、五种数据上报的形式

XMLHttpRequest:经典的 AJAX 请求方式,用于发送数据到服务器。可以配置为同步或异步请求,但在页面卸载时可能不可靠。
Fetch API:现代浏览器中推荐的方式,用于发送网络请求。相比XMLHttpRequest,它提供了更简洁的语法,但在页面卸载时仍可能会被中断。
Navigator.sendBeacon:专门用于在页面卸载时发送数据的 API。sendBeacon是非阻塞的,确保数据在页面关闭时也能可靠地发送。
Image Ping:通过动态创建图像对象并设置其src属性来发送 GET 请求。这种方法常用于简单的数据上报,不会受到跨域限制,但只能发送少量数据。
WebSocket:用于建立持久连接,实现双向通信。适合需要实时数据传输的场景,但对于简单的数据上报来说可能过于复杂。

一共有5种形式上报,我来分析下各有什么优劣势:
其中可以XMLHttpRequest和Fetch没有什么太大本质的区别属于一类,他们都是比较常规的上报形式,但是他有个致命问题可能会被中断,导致数据丢失,特别在页面跳出的情况,还有就是在请求里面优先级高,在页面加载的前期当有大量的上报的时候会阻塞页面的请求看下图:
在这里插入图片描述

Image Ping图片上报,在跨域和调用方式上比较好,但是有个致命的缺点数据量带不多。
WebSocket我见过的很少,可能在某些场景用的多,但是我很少见到
Navigator.sendBeacon专为页面卸载设计,确保数据在页面关闭时发送。非阻塞:不会影响页面卸载速度。在上图里面的优先级属于低,使用简单,但是有个问题,兼容性有点问题,可以配合fetch使用。他不会应为页面切换丢数据,调用起来非常方便。

二、上报时机

数据上报的形式可以从不同的角度来分类和理解。一般来说,数据上报主要有以下几种形式:

实时上报:
数据在产生后立即发送到服务器。这种方式确保数据的实时性,适用于需要即时分析和处理的场景。

批量上报:
数据在客户端累积到一定数量或满足特定条件后,再一次性发送到服务器。这种方式可以减少网络请求次数,适用于对时效性要求不高的场景。

定时上报:
客户端在固定的时间间隔内发送数据到服务器。这种方式可以平衡实时性和网络资源的消耗。

页面卸载上报: 在页面关闭或卸载时发送数据,通常使用sendBeaconAPI。这种方式确保在用户离开页面时也能可靠地将数据发送到服务器。

事件驱动上报:
基于特定事件触发数据上报,例如用户点击按钮、表单提交等。这种方式适用于需要对特定用户行为进行监控的场景。

一共有5种形式时机,我来分析下各有什么优劣势:

实时上报:
优点:
实时性:数据在产生后立即发送,适合需要即时分析的场景。
准确性:可以立即捕捉用户行为,减少数据丢失的风险。
缺点:
网络开销:频繁发送请求可能增加网络负担。
服务器压力:需要服务器能够处理高频率的数据请求。

批量上报:
优点:
减少请求次数:通过合并多条数据减少网络请求。
提高效率:降低网络和服务器的负担。
缺点:
时效性:数据不是实时发送,可能导致分析滞后。
数据丢失风险:如果客户端崩溃或断网,未发送的数据可能丢失。

定时上报:
优点:
平衡实时性和效率:通过定时发送,减少频繁请求。
可控性:可以根据需求调整上报频率。
缺点:
复杂性:需要实现定时器逻辑。
数据可能不够实时:与实时上报相比,数据可能有延迟。

页面卸载上报:
优点:
可靠性:利用sendBeacon确保数据在页面关闭时发送。
简单性:不需要复杂的逻辑,只需在页面卸载时触发。
缺点:
数据量限制:通常只能发送较小的数据量。
依赖浏览器支持:如果浏览器不支持sendBeacon,需要备用方案。

事件驱动上报:
优点:
精确性:针对特定用户行为进行上报,适合精准分析。
灵活性:可以根据业务需求定制上报逻辑。
缺点:
复杂性:需要为每个事件设置监听器和上报逻辑。
潜在的性能问题:过多的事件监听可能影响页面性能。

看你业务需要那种形式,去评估那种形式上报。

我来总结下我在公司遇到的几种情况:公司H5目前用的最多的就是第一种,但是在客户端里面是批量,我理解客户端的形式是最好的,H5的页面如果在端里面可以借助端的能力去实现批量上报。我们也可以在h5里面页面卸载的时候去上报,我自己测试过好像有一些兼容问题,最后还是放弃了用的实时上报。

三、最后来个小问题,如何对你的页面程序方法运行时间进行监控?

页面程序方法的运行时间进行监控是性能优化的重要一环,可以帮助识别性能瓶颈和优化点。以下是一些常用的方法来监控方法的运行时间:

使用console.time和console.timeEnd:
这是最简单的方法之一,适用于开发和调试阶段。
使用console.time(‘label’)开始计时,console.timeEnd(‘label’)结束计时,并在控制台输出运行时间。

console.time('myFunction');myFunction();console.timeEnd('myFunction');

使用performance.now() :
performance.now()提供高精度的时间戳,可以用于精确测量函数的执行时间。

const start = performance.now();myFunction();const end = performance.now();console.log(`myFunction took ${end - start} milliseconds`);

使用PerformanceAPI:
浏览器的PerformanceAPI 提供了更全面的性能测量工具,可以记录和分析多个时间点。
可以使用performance.mark()和performance.measure()来标记和测量代码片段。

performance.mark('start');myFunction();
performance.mark('end');
performance.measure('myFunction', 'start', 'end');const measures = performance.getEntriesByName('myFunction');console.log(measures[0].duration);

使用第三方库:

有一些第三方库可以帮助监控和分析性能,如stats.js或New Relic等。
这些工具通常提供更详细的性能分析和报告功能。

自定义监控工具:

如果需要更复杂的监控,可以编写自定义的监控工具,结合performance.now()和日志记录,将数据发送到服务器进行分析。

目前用的比较多的是performance.mark()因为他是用的比new date提供高精度的时间戳,具体的可以自己去查文档,我懒得讲performance.mark()是 Web Performance API 提供的一个方法,用于在浏览器的性能时间线上创建一个标记。这个标记可以帮助开发者测量特定代码段的执行时间,尤其是在需要精确测量性能的复杂应用中。

用法
创建标记: 使用performance.mark(name)来创建一个标记,其中name是一个字符串,用于标识这个标记。例如:

performance.mark('start');// 执行一些代码
performance.mark('end');

测量时间: 使用performance.measure(name, startMark, endMark)方法来测量两个标记之间的时间间隔。name是测量的名称,startMark和endMark是之前创建的标记。例如:

performance.measure('myMeasure', 'start', 'end');

获取测量结果: 使用performance.getEntriesByName(name)来获取测量结果。这个方法返回一个数组,其中包含所有与指定名称匹配的测量结果。例如:

const measures = performance.getEntriesByName('myMeasure');
measures.forEach((measure) => {console.log(`${measure.name}: ${measure.duration}ms`);
});

我以前用过一个蠢方法就是用mark形式对接口进行打点监控,其实前面见过用资源监控就能完成,后面我为了精准的监控页面真实的渲染时间,用过mack在页面渲染完成的时间点去打mark,后面发现有lcp后放弃,但是我认为在有些特殊场景还是能用上,特别在性能优化到后期实在找不到优化点的时候可以对具体的某些方法进行监控优化。

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
在这里插入图片描述


http://www.hkcw.cn/article/GROmdUKTIu.shtml

相关文章

【JAVA版】意象CRM客户关系管理系统+uniapp全开源

一.介绍 CRM意象客户关系管理系统&#xff0c;是一个综合性的客户管理平台&#xff0c;旨在帮助企业高效地管理客户信息、商机、合同以及员工业绩。系统通过首页、系统管理、工作流程、审批中心、线索管理、客户管理、商机管理、合同管理、CRM系统、数据统计和系统配置等模块&…

【Python连接数据库基础 04】Django ORM开发指南:模型设计与高效查询完全攻略

Django ORM开发指南&#xff1a;模型设计与高效查询完全攻略 关键词&#xff1a;Django ORM、模型设计、数据库查询优化、Model关系、QuerySet、数据库性能、Python Web开发、ORM最佳实践 摘要&#xff1a;深入解析Django ORM的核心概念和高级用法&#xff0c;从模型设计原则到…

项目计划缺乏风险评估和应对策略,如何完善

项目计划缺乏风险评估和应对策略可通过建立风险识别机制、实施风险定性与定量评估、制定具体应对措施、建立风险监控体系、加强风险意识培训来完善。 特别是实施风险定性与定量评估&#xff0c;这一环节直接决定了风险的处理优先级和资源分配。通过定性评估&#xff0c;我们能明…

java29

1.IO流续续集 序列化流&#xff1a; 上传javabean类后再修改它&#xff0c;会报错 自己定义版本号 方便生产版本号的设置&#xff1a; 版本号要在javabean写完再写 综合练习&#xff1a; 因为不知道写进去多少个对象&#xff0c;因此读的时候不确定读多少次&#xff08;读一次…

时代星光推出战狼W60智能运载无人机,主要性能超市场同类产品一倍!

在刚刚结束的第九届世界无人机大会上&#xff0c;时代星光科技发布了其全新产品战狼W60智能运载无人机&#xff0c;并展示了基于战狼W60无人机平台的多种应用场景解决方案。据了解&#xff0c;该产品作为一款多旋翼无人机&#xff0c;主要性能参数均远超市场同类产品&#xff0…

Gephi中的Isometric Layout 插件使用应该用什么数据格式

格式如下&#xff1a; 1.导入数据&#xff0c;运行布局算法Isometric Layout &#xff1b; 2.进入数据面板&#xff0c;选择节点页&#xff1b; 3.已经有一个新列“Computed Z-Level”出现了&#xff0c;但是此时还不是正确的列名&#xff0c;需要改名为[z]&#xff1b; 列…

Mac版本Android Studio配置LeetCode插件

第一步&#xff1a;Android Studio里面找到Settings&#xff0c;找到Plugins&#xff0c;在Marketplace里面搜索LeetCode Editor。 第二步&#xff1a;安装对应插件&#xff0c;并在Tools->LeetCode Plugin页面输入帐号和密码。 理论上&#xff0c;应该就可以使用了。但是&a…

大模型的分词器——算法及示例

文章目录 1. 分词的概述1.1 什么是分词&#xff1f;1.2 分词的重要性1.3 分词方法的演变1.4 分词器的选择 2. Byte-Pair Encoding (BPE)2.1 BPE的概述2.2 BPE的工作原理示例&#xff1a;BPE训练示例&#xff1a;BPE分词伪代码&#xff1a;BPE训练 2.3 BPE的优缺点2.4 BPE在模型…

用户管理页面(解决toggleRowSelection在dialog用不了的隐患,包含el-table的plus版本的组件)

新增/编辑/删除/分配角色&#xff0c;图片上传在此文章分类下另一个文章 1.重点分配角色&#xff1a; <template><!-- 客户资料 --><div class"pageBox"><elPlusTable :tableData"tableData" :tablePage"tablePage" onSi…

构建基于深度学习的人体姿态估计系统 数据预处理到模型训练、评估和部署 _如何利用人体姿态识别估计数据集_数据进行人体姿态估计研究的建议Human3.6M

构建基于深度学习的人体姿态估计系统 数据预处理到模型训练、评估和部署 如何利用人体姿态识别估计数据集_数据进行人体姿态估计研究的建议__ _人体姿态估计数据集:human3.6m w文章内容及代码仅供参考 By. subject: SubjectS1 : Videos Segments Features Depth Scanner Poses…

PyTorch——非线性激活(5)

非线性激活函数的作用是让神经网络能够理解更复杂的模式和规律。如果没有非线性激活函数&#xff0c;神经网络就只能进行简单的加法和乘法运算&#xff0c;没法处理复杂的问题。 非线性变化的目的就是给我们的网络当中引入一些非线性特征 Relu 激活函数 Relu处理图像 # 导入必…

极智项目 | 基于PyQT+Whisper实现的语音识别软件设计

这是一个基于OpenAI的Whisper模型的语音识别应用程序&#xff0c;使用PyQt5构建了简洁直观的用户界面。该应用支持多语言识别&#xff0c;特别优化了中文识别体验。 项目下载&#xff1a;链接 功能特点 简洁现代的深色主题界面支持多语言识别&#xff08;中文、英语、日语等…

【大模型:知识图谱】--1.py2neo连接图数据库neo4j

【图数据库】--Neo4j 安装_neo4j安装-CSDN博客 需要打开图数据库Neo4j&#xff0c; neo4j console 目录 1.图数据库--连接 2.图数据库--操作 2.1.创建节点 2.2.删除节点 2.3.增改属性 2.4.建立关系 2.5.查询节点 2.6.查询关系 3.图数据库--实例 1.图数据库--连接 fr…

关于线缆行业设备数据采集异构问题的解决

通信线缆制造设备 异构设备协议情况 设备具体型号和关键参数数据传输协议拉丝机LW-1-6/560 塑料扁丝拉丝机&#xff08;螺杆120mm&#xff09;进料直径6.5mm→出料2mm 线速245m/min&#xff0c;功率30kWModbus RTU&#xff08;RS485总线&#xff09;对绞机QC-500C 绞弓转速0-…

电力设备故障预测网关技术方案——基于EFISH-SCB-RK3588的国产化替代实践

一、国产化替代战略背景 行业痛点分析 传统x86方案&#xff08;赛扬N100/N150&#xff09;存在单线程性能瓶颈&#xff08;SPECint2006仅15.2分&#xff09;进口芯片供应链风险&#xff08;Intel产品生命周期通常仅3-5年&#xff09;工业现场总线支持不足&#xff08;需外扩CA…

基于SpringBoot的“嗨玩旅游”网站设计与实现(源码+定制+开发)嗨玩旅游平台开发:景点展示与个性化推荐系统(SpringBoot)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

网络安全问题及对策研究

摘 要 网络安全问题一直是近年来社会乃至全世界十分关注的重要性问题&#xff0c;网络关乎着我们的生活&#xff0c;政治&#xff0c;经济等多个方面&#xff0c;致力解决网络安全问题以及给出行之有效的安全策略是网络安全领域的一大目标。 本论文简述了课题的开发背景&…

Modbus转Ethernet IP网关助力罗克韦尔PLC数据交互

在工业自动化领域&#xff0c;Modbus协议是一种广泛应用的串行通信协议&#xff0c;它定义了主站和从站之间的通信规则和数据格式。罗克韦尔PLC是一种可编程的逻辑控制器&#xff0c;通过Modbus协议实现与其他设备之间的数据交互。然而&#xff0c;随着以太网技术的普及和发展&…

SpringBoot 数据库导入导出 Xlsx文件的导入与导出 全量导出 数据库导出表格 数据处理 外部数据

介绍 poi-ooxml 是 Apache POI 项目中的一个库&#xff0c;专门用于处理 Microsoft Office 2007 及以后版本的文件&#xff0c;特别是 Excel 文件&#xff08;.xlsx 格式&#xff09;和 Word 文件&#xff08;.docx 格式&#xff09;。 在管理系统中需要对数据库的数据进行导…

EagleTrader采访|在市场中修行的交易之道与实战反思

在交易世界的洪流中&#xff0c;真正让人敬佩的不是一时的高收益&#xff0c;而是对规则的敬畏与长期自我修正的能力。来自EagleTrader的交易员罗秋林&#xff0c;正是这样一位在实战中历练出的“老兵”。 七八年时间&#xff0c;他从爆仓阴影走出&#xff0c;如今选择通过Eag…