首页
归档
留言
友链
广告合作
壁纸
更多
美女主播
Search
1
博瑞GE车机升级/降级
5,579 阅读
2
Mac打印机设置黑白打印
4,890 阅读
3
修改elementUI中el-table树形结构图标
4,866 阅读
4
Mac客户端添加腾讯企业邮箱方法
4,649 阅读
5
intelliJ Idea 2022.2.X破解
4,323 阅读
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
登录
/
注册
Search
标签搜索
Spring Boot
Java
Vue
Spring Cloud
Mac
MyBatis
WordPress
asp.net
Element UI
Nacos
MacOS
.Net
Spring Cloud Alibaba
Mybatis-Plus
Typecho
jQuery
MySQL
Java Script
微信小程序
Oracle
Laughing
累计撰写
609
篇文章
累计收到
1,417
条评论
首页
栏目
后端开发
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
页面
归档
留言
友链
广告合作
壁纸
美女主播
搜索到
609
篇与
的结果
2025-03-22
网站增加搜一下功能
搜一下功能通过提升用户体验、增加页面曝光、优化关键词等方式,对SEO有显著帮助。基于typecho及Joe主题,实现方式如下找到主题public下的batten.php文件,因为我本地主题进行过魔改,在大概第30行左右,插入如下代码,其他主题同理。<span class="text"> <a href="https://www.baidu.com/s?wd=<?php $this->title() ?>+site:lisen.cc" target="_blank">搜一下</a> </span> <span class="line">/</span>
2025年03月22日
100 阅读
0 评论
0 点赞
2025-03-21
Beszel:一款开源轻量级的服务器资源监控平台
{mtitle title="简介"/}Beszel是一款功能全面、轻量级且易于部署的服务器资源监控平台,特别适合Docker环境和小型项目使用。其丰富的功能模块和灵活的告警机制能够帮助用户及时发现问题并采取措施,确保服务器稳定运行。{mtitle title="功能特点"/}轻量级架构 :与其他监控方案对比,Beszel的资源消耗更低,占用空间小,适合硬件性能有限的设备使用。Docker深度支持 :Beszel能够实时监控Docker容器的CPU、内存使用情况,并记录历史数据,帮助用户优化容器配置。多用户管理 :支持团队协作,管理员可跨用户共享监控系统,每个用户都有自己的系统视图,系统具有极高的灵活性和可扩展性。灵活告警机制 :用户可根据CPU、内存、磁盘、带宽等多个指标设置告警阈值,当这些指标达到预设的阈值时,Beszel会通过邮件或Webhook等方式发送警报通知,帮助用户及时发现问题并采取措施。历史数据分析 :长期记录设备运行状态,便于回溯性能瓶颈。开源与可扩展性 :Beszel提供REST API,便于二次开发与数据整合,用户可以在自己的脚本和应用程序中使用这些API来获取和使用监控数据。OAuth/OIDC支持 :兼容Google、GitHub等身份提供商,增强了登录安全性,同时可禁用传统密码,进一步提升了系统安全性。自动备份 :支持从本地磁盘或S3兼容存储中自动备份和恢复数据,确保数据的可靠性和完整性。{mtitle title="技术架构"/}Beszel采用Hub-Agent分离式架构,兼顾灵活性与扩展性。Hub(服务端) :基于PocketBase构建,提供Web仪表盘,负责数据的汇总、展示和管理。用户通过浏览器访问指定IP和端口即可查看监控面板。Agent(客户端) :部署于被监控设备,通过轻量级SSH服务器采集系统指标并传输至Hub。Agent需访问Docker守护进程(/var/run/docker.sock)以获取容器数据。{mtitle title="应用场景"/}个人开发者和小型企业:资源占用少,非常适合中小型项目的服务器监控。服务器运维和管理:便于集中监控多台服务器的Docker容器,降低运维复杂度。需要多用户管理的环境:支持不同用户间的系统资源共享和权限分配,更适合团队合作。如需了解更多信息,可以访问其官方网站或查阅相关的技术文档。{card-describe title="GitHub地址"}https://github.com/henrygd/beszel?tab=readme-ov-file {/card-describe}{card-describe title="官方文档"}https://beszel.dev/guide/hub-installation#docker-or-podman {/card-describe}{card-describe title="官方网站"}https://beszel.dev/ {/card-describe}{mtitle title="安装教程"/}安装Dockersudo apt updatesudo apt install -y docker.io docker-compose编写配置文件编写配置文件docker-compose.yml,在同一台设备安装Hub和Agent。services: beszel: image: henrygd/beszel:latest container_name: beszel restart: unless-stopped ports: - 8090:8090 volumes: - ./beszel_data:/beszel_data - ./beszel_socket:/beszel_socket beszel-agent: image: henrygd/beszel-agent:latest container_name: beszel-agent restart: unless-stopped network_mode: host volumes: - ./beszel_socket:/beszel_socket - /var/run/docker.sock:/var/run/docker.sock:ro environment: LISTEN: /beszel_socket/beszel.sock KEY: 'bednarvkpj97'启动服务sudo docker-compose up -d服务启动后,在浏览器访问http://IP:8090即可。
2025年03月21日
89 阅读
0 评论
0 点赞
2025-03-21
Springboot中使用Undertow替换默认的Tomcat容器
{mtitle title="Undertow介绍"/}Undertow是由JBoss(现为Red Hat)开发的一款轻量级、高性能的Web服务器。它是WildFly应用服务器的默认Web容器,专注于高并发和低延迟的场景。Undertow基于NIO(非阻塞I/O)构建,支持HTTP/1.x、HTTP/2和WebSocket协议。{mtitle title="Undertow优势"/}Tomcat凭借其稳定性、易用性和社区支持成为Springboot默认的容器。虽然Tomcat表现足够优秀,但是Undertow也有其可圈可点的地方。高并发支持:Undertow基于NIO构建,能够高效处理大量并发请求,适合高负载场景。低延迟:由于其非阻塞的设计,Undertow在低延迟场景中表现优异。轻量级:Undertow的核心代码非常精简,启动速度快,资源占用低。在资源有限的情况下,尤其是内存和CPU资源紧张的情况下,Undertow是更好的选择。{mtitle title="Undertow替换Tomcat"/}上面介绍了Undertow的优点,那么我们如何在Springboot项目中使用Undertow作为默认容器呢。先来看一下,默认Tomcat容器,启动成功后控制台输出信息为了使用Undertow容器,我们需要修改项目的pom.xml文件,排除掉Tomcat。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency>然后添加Undertow的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>然后重启项目,查看控制台输出
2025年03月21日
92 阅读
0 评论
0 点赞
2025-03-21
AISeo:一款Typecho主题Joe借助AI生成SEO关键词和SEO描述语的插件
一个网页的keywords及description对于网站的SEO是非常重要的,因此,我们在发布文章时,需要针对文章设置一个合理的keywords及description。但是如果每个文章,我们都手工设置keywords及description,势必会浪费我们极大的精力,在这个全名疯狂的AI时代,不利用AI生成一下keywords及description感觉自己不属于这个时代似的。{mtitle title="实现原理"/}其实整个实现过程是非常简单的,在发布文章页面,增加一个按钮,按钮点击时,通过http的方式调用对应模型的接口,并要求模型返回对应的keywords及description,使用正则表达式对返回的内容进行拆分,获取keywords及description信息,赋值到对应的字段上。{mtitle title="环境介绍"/}本文实现是有条件的,当然你可以在本文的基础上自行修改,进行更多的适配。李森的博客使用的是轻量高效的开源博客程序-Typecho,主题使用的是Joe,因此本文所有介绍的内容都是基于这两个前提的,当然,我们后续的代码会进行说明,方便你在其他地方使用或者使用了Typecho但是不是使用的Joe主题时,也能顺畅的使用。{mtitle title="GPT-API-free介绍"/}本着免费的原则,本文使用的AI工具是GPT-API-free。GPT-API-free是一个提供免费ChatGPT API密钥的开源项目,支持多种模型并允许开发者低成本接入GPT服务。特点支持Models, Embedding, text-davinci(免费版不支持), GPT-3.5-Turbo, GPT-3.5-Turbo-16K(免费版不支持), GPT-4, DALLE(免费版不支持), Whisper(免费版不支持)。(免费版就可以支持AutoGPT, gpt_academic, langchain等)免费版支持gpt-4,一天3次;支持gpt-4o-mini,和gpt-3.5-turbo共享一天200次。与官方完全一致的接口标准,兼容各种软件/插件。支持流式响应。国内线路使用动态加速,体验远优于使用代理连接官方。无需科学上网,国内环境直接可用。个人完全免费使用。免费使用申请领取内测免费API Key,申请地址 https://api.chatanywhere.org/v1/oauth/free/renderHost: https://api.chatanywhere.tech (国内中转,延时更低){mtitle title="博客引入AI"/}{alert type="error"}本插件只适用于Typecho并且需要使用Joe插件,{/alert}下载插件我已经将需要使用的插件封装好,可以直接下载使用{cloud title="AISeo.zip" type="bd" url="https://pan.baidu.com/s/1Nuoce_U8vkI9IG-60MEFlw?pwd=ccdd" password="ccdd"/}下载插件后解压,得到AISeo文件夹,将文件夹整体上传到网站的/usr/plugins文件夹内启用并配置插件进入网站后台,找到并启用AISeo插件点击设置按钮,进入设置页面模型名:gpt-3.5-turboAPI KEY:通过申请领取内测免费API Key介绍的网址免费申请。注意:申请API Key需要Github授权。输入地址:https://api.chatanywhere.tech其他保持默认即可,然后保存插件设置。配置文章编辑页面到admin目录下,找到write-post.php文件。在标题下方插入一个按钮<button type="button" class="generate-seo" onclick="generateSeoKeywords()">生成SEO关键词和描述</button>然后在最后一个div标签后面,添加以下代码<script> function generateSeoKeywords() { // 获取标题和内容 const title = document.querySelector('input[name="title"]').value; const text = document.querySelector('textarea[name="text"]').value; // 获取插件设置 const apiUrl = "<?php echo rtrim(Typecho_Widget::widget('Widget_Options')->plugin('AISeo')->apiUrl, '/') . '/v1/chat/completions'; ?>"; const keyValue = "<?php echo Typecho_Widget::widget('Widget_Options')->plugin('AISeo')->keyValue; ?>"; const modelName = "<?php echo Typecho_Widget::widget('Widget_Options')->plugin('AISeo')->modelName; ?>"; const maxLength = "<?php echo Typecho_Widget::widget('Widget_Options')->plugin('AISeo')->maxLength; ?>"; // 获取UUID const uuid = "<?php echo AISeo_Plugin::getUuid(); ?>"; // 从插件中获取UUID // 发起 AJAX 请求 fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + keyValue, 'X-Request-ID': uuid // 添加UUID到请求头 }, body: JSON.stringify({ model: modelName, messages: [{ role: "system", content: "请你扮演一个文本SEO关键词和SEO描述生成器,下面是一篇关于 '" + title + "' 的文章,请你根据文章标题生成 " + maxLength + " 字左右的SEO关键词和SEO描述,格式使用SEO关键词:SEO描述:,关键词使用英文逗号分隔,除了你生成的内容,请不要输出其他任何无关内容" }, { role: "user", content: text }], temperature: 0 }) }) .then(response => response.json()) .then(data => { if (data.choices && data.choices.length > 0) { const content = data.choices[0].message.content; // 使用特定的分隔符进行分割 const keywordsMatch = content.match(/SEO关键词:(.*?)SEO描述:(.*)/s); if (keywordsMatch && keywordsMatch.length === 3) { const keywords = keywordsMatch[1].replace(/\s+/g, ''); // 关键词 const description = keywordsMatch[2].trim(); // 描述 const keywordField = document.querySelector('input[name="fields[keywords]"]'); const descriptionField = document.querySelector('textarea[name="fields[description]"]'); // 始终覆盖自定义字段 keywordField.value = keywords; descriptionField.value = description; // 使用 cocoMessage 显示成功提示 console.success('SEO关键词和描述生成成功!'); } else { // 使用 cocoMessage 显示失败提示 console.error('生成失败,请重试。'); } } else { // 使用 cocoMessage 显示失败提示 console.error('生成失败,请重试。'); } }) .catch(error => { // 捕获并处理错误 console.error('请求失败:' + error.message); }); } </script>配置按钮样式找到admin/css/style.css,在任意位置,增加以下样式.generate-seo { padding: 8px 10px; /* 缩小内边距,减少按钮高度 */ background-color: #4CAF50; /* 绿色背景 */ color: white; /* 字体颜色为白色 */ border: none; /* 去除边框 */ border-radius: 4px; /* 圆角边框 */ cursor: pointer; /* 鼠标悬停时显示为指针 */ font-size: 14px; /* 字体大小 */ transition: background-color 0.5s ease; /* 背景颜色渐变效果 */ margin-top: 0px; /* 仅调整此按钮的顶部外边距 */ } .generate-seo:hover { background-color: #45a049; /* 悬停时更深的绿色 */ }
2025年03月21日
72 阅读
0 评论
0 点赞
2025-03-21
Typecho主题Joe首页底部增加友情链接
Joe是typecho下一款非常优秀的主题,本站也是使用的Joe的主题,只不过进行了一些改动。{message type="warning" content="本文实现方式只只用于Joe主题,其他主题需要自己修改"/}增加首页友情链接文件在主题public文件夹下增加homefriend.php文件,文件内容如下<!-- * 博客底部-友情链接 * Joe主题在想要显示的地方直接引入即可,其他主题需根据主题自身情况修改。 * $this->need('public/homefriend.php'); * * @Author:李森的博客 * @site:https://lisen.cc --> <style> .ls_friend_home { border-radius: 5px; margin: 0 auto; overflow: hidden } .ls_sites { overflow: hidden; padding-top: 10px } .ls_sites li { width: 31%; float: left; text-align: center; border-radius: 5px; line-height: 35px; margin: 0 3px; margin-bottom: 10px; position: relative } .ls_sites li a { text-decoration: none; color: #fff; display: block; text-overflow: ellipsis; white-space: nowrap; overflow: hidden } .ls_sites li:before, .ls_sites li:after { content: ''; position: absolute; top: 0; right: 0; height: 3px; width: 0; background: #fff; transition: 400ms ease all } .ls_sites li:after { right: inherit; top: inherit; left: 0; bottom: 0 } .ls_sites li:hover:before, .ls_sites li:hover:after { width: 100%; transition: 800ms ease all } @media(min-width:576px) { .ls_friend_home { max-width: 540px } .ls_sites li { width: 30% } } @media(min-width:768px) { .ls_friend_home { max-width: 720px } .ls_sites li { width: 30% } } @media(min-width:992px) { .ls_friend_home { max-width: 960px } .ls_sites li { width: 16.6% } } @media(min-width:1200px) { .ls_friend_home { max-width: 1140px } .ls_sites li { width: 16.6% } } @media(min-width:1400px) { .ls_friend_home { max-width: 1320px } .ls_sites li { width: 16.6% } } </style> <?php /*获取友情链接【这里Joe主题可直接使用,其他主题需要自己重写,原理相同,获取到链接进行循环。】*/ $friends = []; $friends_color = ['#F8D800','#0396FF','#EA5455','#7367F0','#32CCBC','#F6416C','#28C76F','#9F44D3','#F55555','#736EFE','#E96D71','#DE4313','#D939CD','#4C83FF','#F072B6','#C346C2','#5961F9','#FD6585','#465EFB','#FFC600','#FA742B','#5151E5','#BB4E75','#FF52E5','#49C628','#00EAFF','#F067B4','#F067B4','#ff9a9e','#00f2fe','#4facfe','#f093fb','#6fa3ef','#bc99c4','#46c47c','#f9bb3c','#e8583d','#f68e5f']; $friends_text = $this->options->JFriends; if ($friends_text) { $friends_arr = explode("\r\n", $friends_text); if (count($friends_arr) > 0) { for ($i = 0; $i < count($friends_arr); $i++) { $name = explode("||", $friends_arr[$i])[0]; $url = explode("||", $friends_arr[$i])[1]; $avatar = explode("||", $friends_arr[$i])[2]; $desc = explode("||", $friends_arr[$i])[3]; $friends[] = array("name" => trim($name), "url" => trim($url), "avatar" => trim($avatar),"desc" => trim($desc)); }; } } ?> <?php if (sizeof($friends) > 0) : ?> <div class="ls_friend_home"> <ul class="ls_sites"> <?php foreach ($friends as $item) : ?> <li style="background: <?php echo $friends_color[mt_rand(0, count($friends_color) - 1)] ?>"> <a href="<?php echo $item['url']; ?>" target="_blank" rel="noopener noreferrer" title="<?php echo $item['desc']; ?>"> <img width="20" height="20" class="lazyload" style="border-radius: 50%;object-fit: cover;" src="<?php _getAvatarLazyload(); ?>" data-src="<?php echo $item['avatar']; ?>" alt="<?php echo $item['name']; ?>" /> <?php echo $item['name']; ?> </a> </li> <?php endforeach; ?> </ul> </div> <?php endif; ?>在需要展示的地方,引入友情链接文件如果你想全站显示,建议放到public/footer.php的合适位置。因为我只想在首页显示,所以我是在index.php文件引入的,位置的话,放到了最底部<!-- 友情链接 --> <?php $this->need('public/homefriend.php'); ?>
2025年03月21日
81 阅读
0 评论
0 点赞
2025-03-19
爱链网停业整顿暂停一切业务,是不是要凉凉?
爱链网是我之前博客的不多收入之一,爱链网也是国内比较大的链接交易平台,一切手续、流程也是比较正规的。从2025年2月8号整改开始,截止到今天(2025年3月19号)已经快一个半月了,目前没有任何恢复的迹象。记得3月初的时候,已经整站关闭了,后来网站恢复访问了,但是目前提现已经提不出来了。{timeline}{timeline-item color="#19be6b"}2025.3.24 爱链网官网再次无法访问。{/timeline-item}{timeline-item color="#19be6b"}2025.2.23 平台停业整顿,暂停一切中介业务。买卖双方提现会另行通知。{/timeline-item}{timeline-item color="#ed4014"}2025.2.8 爱链网暂停充值业务,买家需要提现的,请在网站后台留言{/timeline-item}{/timeline}如果想购买本站的友情链接、发布软文或者发布广告,可以通过51链购买,购买地址: https://www.51link.com/link-sell?uid=30403
2025年03月19日
51 阅读
0 评论
0 点赞
2025-03-19
云闪付登录逻辑:用户发短信?这是什么神仙操作?
云闪付是一种非现金收付款移动交易结算工具,是在中国人民银行的指导下,由中国银联携手各商业银行、支付机构等产业各方共同开发建设、共同维护运营的移动支付APP,于2017年12月11日正式发布。最近想购买扩展坞,用云闪付可以直接国补抵扣,在使用云闪付时发现它的手机号码登录逻辑简直让人哭笑不得。作为一个支付工具,安全性和便捷性本该是核心,但云闪付的登录流程却让我怀疑人生——竟然需要用户主动发短信才能登录!而且它还是给你发送一个短信,告诉你需要给它发送一个短信进行验证。。。这是什么神仙操作?今天就来吐槽一下这个让人摸不着头脑的设计。登录流程:用户发短信?认真的吗?正常的移动App通常的登录流程是:输入手机号 → 接收验证码 → 输入验证码 → 登录成功。简单直接,一气呵成。但云闪付的流程却是:输入手机号 → 系统给你发一条短信提示你发一条短信到指定号码 → 发完短信 → 等待系统验证 → 登录成功。What? 我不仅要输入手机号,还要自己发短信?这操作简直让人一脸懵。难道云闪付觉得用户的时间不值钱还是觉得用户发短信不需要钱,还是觉得发短信是一件很有趣的事情?用户体验:繁琐又反人类步骤繁琐: 本来一键接收验证码就能搞定的事情,非要让用户手动发短信。操作复杂: 尤其是对不太熟悉手机操作的中老年用户,发短信可能比接收验证码难多了。浪费时间: 发短信、等待验证,整个过程比普通登录多花了好几倍时间。浪费金钱: 用户想要注册或者登录你的产品,你还得要用户掏钱去认证?云闪付的产品经理是不是觉得用户都太闲了? 这种设计简直是把用户体验按在地上摩擦。安全性:真的更安全吗?可能有人会说,这种设计是为了安全。但仔细想想,发短信真的比接收验证码更安全吗?短信拦截风险:如果用户的手机被恶意软件控制,短信内容同样可能被截获。用户体验牺牲:为了所谓的安全,牺牲了用户体验,真的值得吗?对比其他App:差距明显看看支付宝、微信支付,甚至其他普通的App,哪个不是一键验证码登录?简单、快捷、安全,这才是用户需要的。而云闪付却偏偏要走一条“与众不同”的路,结果就是让用户感到困惑和不便。希望云闪付的产品团队能好好反思一下,用户需要的是便捷和安全,而不是折腾和困惑。如果下次登录还要我发短信,我可能真的要考虑卸载了。最后,灵魂一问:云闪付,你是认真的吗?还是说,这只是为了让我多花点短信费?(手动狗头)
2025年03月19日
51 阅读
0 评论
0 点赞
2025-03-19
Windows11查看系统密玥
通过命令查看这种方式只能查看OEM密玥,如果不是OEM激活的,这个密玥也没啥用。打开终端,输入以下命令 wmic path SoftwareLicensingService get OA3xOriginalProductKey通过注册表查看那么只要右键开始菜单,选择运行,其中输入regedit回车打开注册表。接依次定位到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform,如下图可以双击BackupProductKeyDefault,在弹出的界面可以复制密玥。
2025年03月19日
37 阅读
0 评论
0 点赞
2025-03-18
Java优雅判空技巧:瞧瞧别人家的判空,太香啦!
在 Java 开发中,空指针异常(NullPointerException,简称NPE) 是程序员最常遇到的错误之一。无论是新手还是资深开发者,几乎每个人都曾因为一个突如其来的 NullPointerException 而抓狂过。想象一下这样的场景:项目即将上线,整个团队正忙于最后的部署工作,突然系统抛出了一个堆栈错误。大家花费大量时间排查,最终发现竟然是因为某个变量未初始化。再一看代码,满屏的 if (xxx == null),层层嵌套,复杂到让人头晕目眩。这种低效且低级的判空方式,不仅降低了代码的可读性,还增加了维护成本。然而,判空的方式远不止传统的 if (xxx == null)!今天,我要向大家推荐‘别人家的代码’——那些优雅、高效的判空技巧,简直是代码的艺术品。接下来,我们将一起探讨Java 中如何优雅、高效地进行判空操作*,帮助你彻底告别繁琐的判空代码,提升代码的可读性和可维护性。一、传统判空的血泪史在我们之前的开发过程中,最常见的判空方式,可能就是这样了:if (user != null) { if (user.getAddress() != null) { if (user.getAddress().getStreet() != null) { // 做一些事情 } } }一层又一层的嵌套判空,简直是代码的噩梦!尤其是当这种判空逻辑遍布代码的多个地方时,整个程序的可读性急剧下降,维护成本也随之飙升。更糟糕的是,在调用外部数据接口时,稍有不慎就会引发大量的空指针异常(NPE)。而在高并发场景下,这种问题会被进一步放大,程序崩溃的概率成倍增加,给系统稳定性带来巨大威胁。那么,如何优化这种灾难级别的代码呢?接下来,我们将探讨如何通过现代化的判空技巧,彻底告别多层嵌套判空,提升代码的可读性与健壮性,同时有效避免高并发场景下的空指针异常。二、Java 8+ 时代的判空革命随着Java 8的到来,我们迎来了判空操作的一次革命性升级——Optional!这个神器彻底改变了传统的判空方式,让代码变得更加优雅、简洁。通过链式调用,Optional 不仅避免了繁琐的 if (xxx == null) 判断,还大大提升了代码的可读性和可维护性。无论是新手还是资深开发者,都对它爱不释手。接下来,我们将深入探讨 Optional 的使用技巧,包括基础用法、链式调用以及高级功能,帮助你彻底告别繁琐的判空代码,提升开发效率。1. Optional 黄金三板斧链式调用判空:使用 Optional.ofNullable()Optional 是一个容器对象,它能帮助我们避免空指针异常。通过 Optional.ofNullable(),我们可以优雅地处理可能为 null 的对象,而无需一层层地嵌套判断。让我们看个例子:Optional.ofNullable(user) .map(User::getAddress) .map(Address::getStreet) .ifPresent(street -> { // 在这里使用 street,避免了 NullPointerException });看!这段代码比那段嵌套的 if 优雅多了吧?简洁明了,能够有效避免 NullPointerException,而且还能链式调用,代码的可读性大大提升。高级用法:条件过滤与业务异常抛出Optional 还能用于更复杂的情况,比如在判空时抛出业务异常。比如我们有一个方法,接收一个可能为空的用户对象,并希望如果用户没有地址,就抛出一个自定义的异常:User user = getUser(); String street = Optional.ofNullable(user) .map(User::getAddress) .map(Address::getStreet) .orElseThrow(() -> new IllegalStateException("用户地址不能为空"));当 user 或者 address 为 null 时,代码会自动抛出 IllegalStateException,避免了不必要的 null 检查。2. 封装通用工具类你可能会想,写了这么多判空代码,我能不能封装一个工具类,让其他地方直接调用?当然可以。你可以封装一个 NullSafe 工具类,让判空变得更加简单。比如:public class NullSafe { public static <T> Optional<T> ofNullable(T value) { return Optional.ofNullable(value); } }然后直接调用:String street = NullSafe.ofNullable(user) .map(User::getAddress) .map(Address::getStreet) .orElse("默认街道");三、现代化框架的判空银弹1. Spring 实战技巧如果你在用 Spring 框架,那么 Spring 提供了一些非常好用的工具类来帮助我们判空,比如 CollectionUtils 和 StringUtils。if (CollectionUtils.isEmpty(userList)) { // 处理用户列表为空的情况 } if (StringUtils.isEmpty(user.getName())) { // 处理用户名为空的情况 }这些工具类能大大简化我们的代码,让判空更加直接和简洁。2. Lombok 保驾护航Lombok是我们项目中的老朋友了,@NonNull 注解简直是自动生成判空代码的神奇宝贝。通过它,我们可以在方法参数中标记某个参数不能为 null,如果为 null,Lombok 会自动抛出 NullPointerException,省去了手动检查的麻烦。public void setUserName(@NonNull String name) { this.name = name; }调用这个方法时,如果传入 null,Lombok 会帮我们自动抛出 NullPointerException,这样一来,代码简洁且异常处理得当。四、工程级解决方案在一些大型项目中,空指针检查可能变得尤为复杂,传统的判空方式已经不适用了,这时我们可以考虑采用一些工程级的方案。1. 空对象模式空对象模式是一种很巧妙的解决方案,它通过定义一个空对象来替代 null,避免了频繁的 null 检查。比如,我们可以定义一个 Notification 接口的空对象,实现一个空的 Notification 对象,从而避免频繁的 null 检查。public class EmptyNotification implements Notification { @Override public void notifyUser() { // 什么也不做 } }这样,当没有通知需要发送时,直接使用 EmptyNotification,不需要担心 null 的问题。2. Guava 的 Optional 增强Guava的 Optional 提供了一些更为强大的功能,比如 transform 和 or 方法,能够帮助我们进行更复杂的操作。比如:Optional<String> name = Optional.of("John"); String upperName = name.transform(String::toUpperCase).or("Default Name");这段代码用 Guava 的 Optional 实现了 String 大写转换,并且提供了一个默认值,简洁且优雅。五、防御式编程进阶在一些关键性业务中,我们还可以通过防御式编程来增强系统的健壮性,防止出现 null 值导致的问题。1. Assert 断言式拦截断言(assert)能够帮助我们验证某些关键参数在方法执行之前是有效的。如果某个参数为 null,程序会立即抛出异常。public void processData(@NonNull String data) { assert data != null : "数据不能为空"; // 处理数据 }这样我们就能确保传入的数据不会为 null,提高了代码的健壮性。2. 全局 AOP 拦截AOP 拦截可以帮助我们全局处理参数判空的逻辑,尤其是在接口调用时非常有用。通过自定义注解与 AOP 结合,我们可以在调用接口之前拦截请求,进行判空处理,避免了重复编写判空代码。@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface NotNullCheck { // 自定义判空注解 }然后通过 AOP 拦截:@Aspect @Component public class NullCheckAspect { @Before("@annotation(NotNullCheck)") public void checkParamsNotNull(JoinPoint joinPoint) { for (Object arg : joinPoint.getArgs()) { if (arg == null) { throw new IllegalArgumentException("参数不能为null"); } } } }六、总结在 Java 开发中,判空问题一直是程序员面临的挑战之一。从传统的多层 if (xxx == null) 判空,到 Java 8 引入的革命性工具 Optional,再到现代化框架提供的强大支持,判空操作已经经历了显著的进化。如今,程序员不再需要一遍遍地编写冗长的 if 判断,代码变得更加简洁、优雅,可读性也大幅提升。无论是通过 Optional 的链式调用,还是借助 Spring、Lombok 等现代化框架的工具类,Java 开发者都可以轻松实现高效、优雅的判空操作。接下来,我们将总结这些判空技巧,帮助你彻底告别繁琐的判空代码,提升开发效率与代码质量。
2025年03月18日
37 阅读
0 评论
0 点赞
2025-03-18
Spring 官宣接入 DeepSeek,太香了!
Spring AI已经支持DeepSeek。今天和大家聊聊如何在Spring Boot项目制使用DeepSeek,还是非常方便的!Spring AI介绍Spring AI是一个用于AI工程的应用程序框架,将Spring生态系统设计原则应用于AI领域。其核心是通过抽象化和模块化设计,简化AI功能的接入步骤,同时保持与Spring生态的无缝兼容。以下是其主要特点与功能:统一的抽象API:支持主流AI服务,如 OpenAI、DeepSeek、Google、和Ollama等,提供了提供标准化的接口。核心功能模块:模型交互、向量处理、检索增强生成(RAG)、函数调用。低代码集成:通过Spring Boot Starter依赖快速接入,在配置文件中配置好AI服务即可使用。结构化输出:将模型响应直接映射为Java对象,简化数据处理。流式响应:支持Flux流式输出,适用于实时聊天等场景。Spring AI集成DeepSeek申请Api Key首先我们需要去DeepSeek官网申请Api Key,地址:https://platform.deepseek.com/api_keys Spring Boot中集成DeepSeek首先在SpringBoot项目中添加Spring AI对应的依赖;<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency>然后在项目的application.yml配置文件中添加调用AI服务相关的配置;spring: ai: openai: # 调用AI接口时表明身份的API KEY api-key: <YOUR_API_KEY> # 调用AI接口时的基础路径,配置的是阿里云百炼的基础路径 base-url: https://api.deepseek.com chat: options: # 调用的模型,DeepSeek的话可以选择deepseek-r1或deepseek-v3 model: deepseek-chat # 用来控制文本生成的随机性(创造力),值越小越严谨 temperature: 0.8创建一个控制器类,用于处理与 DeepSeek 的交互,import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/chat") public class ChatController { @Autowired private DeepSeekClient deepSeekClient; @PostMapping public String chat(@RequestBody String message) { return deepSeekClient.chatCompletion(message).getOutput().getContent(); } @GetMapping(value = "/stream", produces = "text/event-stream") public Flux<String> chatStream(@RequestParam String message) { return deepSeekClient.chatFluxCompletion(message) .map(response -> response.getOutput().getContent()); } }
2025年03月18日
26 阅读
0 评论
0 点赞
2025-03-17
iPhone12~iPhone16E支持5GA网络IPCC文件
目前IOS 18.4 Beta2测试版本身已经支持,其他版本的如果想体验5GA可以通过更新IPCC的方式实现。目前5GA要求条件比较苛刻,如果想体验的,请先看一下是否满足一下条件:iPhone12以上机型,不区分普通版、Pro或者Plus或者Max,全系均可。IOS18.2及以上系统(IOS 18.4本身已经支持,无需更新IPCC)。环境要求较高,目前5GA覆盖不完善,基本只有大城市的核心区域才覆盖。下载ipcc文件我这里已经整理好了iPhone12~iPhone16E对应版本的IPCC文件,所有IPCC文件都是最新的63.0版本。如有需要的,可以选择自己对应的版本下载。{cloud title="ipcc下载" type="bd" url="https://pan.baidu.com/s/180I5qvR7cuC8YDysrvQSnQ" password="j6dg"/}注意,每个压缩包内都有对应移动、联通、电信、广电的IPCC文件,具体区分如下{card-describe title="IPCC说明"}中国广电 CBN_cn.ipcc 63.0中国电信 ChinaTelecom_USIM_cn.ipcc 63.0中国移动 CMCC_cn.ipcc 63.0中国联通 Unicom_cn.ipcc 63.0{/card-describe}使用爱思助手刷如ipcc打开爱思助手,切换到【工具箱】,点击【更新IPCC文件】如果是双卡手机,注意选择SIM卡对应的电信运营商,点击【选择本地IPCC】{message type="error" content="一定要正确选择对应运营商的IPCC文件"/}点击立即更新IPCC刷完后手机会立即重新搜索信号,我们可以到手机设置-通用-关于本机-下拉到底-看运营商后面的数字是不是你刷的IPCC版本号数字,比如你刷的是63.0 IPCC,刷完这里会变成63.0即成功。这个时候,如果你所在地区支持5GA网络,那么你的手机原来的5G就会变成5GA
2025年03月17日
64 阅读
0 评论
0 点赞
2025-03-16
HarmonyOS Next自带浏览器如何更换搜索引擎
之前买的Mate 60 Pro一直在吃灰,今天因为手机被孩子拿手了,临时用了一下,竟然发现了HarmonyOS Next自带的华为浏览器的无语的功能。HarmonyOS Next自带的华为浏览器默认搜索引擎竟然是360搜索,感觉哪怕默认个百度搜索我都不说啥了,百度搜索虽然说广告多、虚假内容多,但是起码内容比较全,360搜索,这不光广告多、虚假内容多,关键是搜索内容少呀。出自之外,华为浏览器想更换搜索引擎,对于普通人来说还是比较麻烦的。感觉这产品经理不是回扣吃的多就是个脑残瞅瞅下面这骚操作,这是给人用的东西吗,好像除了华为浏览器这个骚操作,别的浏览器还真没见过这样的,其他浏览器基本都能直接切换。{mtitle title="华为浏览器更换Bing搜索引擎"/}这里,推荐大家使用Bing搜索,搜索内容比较多,没有乱七八糟的广告或者虚假内容,具体更换方法如下:打开浏览器,切换到【我的】页签在【我的】页签,点击【设置】在【设置】页面点击【搜索引擎】点击下面那行小字【编辑自定义搜索引擎】第一行随便输入名称即可,我这里输入的Bing第二行很关键,输入https://cn.bing.com/search?q=%s点击右上角的[√]保存设置在返回的页面,勾选我们新添加的Bing搜索
2025年03月16日
38 阅读
0 评论
0 点赞
1
2
3
4
...
51