当前位置: 首页 > news >正文

使用 Spring Boot 快速构建企业微信 JS-SDK 权限签名后端服务

使用 Spring Boot 快速构建企业微信 JS-SDK 权限签名后端服务

本篇文章将介绍如何使用 Spring Boot 快速构建一个用于支持企业微信 JS-SDK 权限校验的后端接口,并提供一个简单的 HTML 页面进行功能测试。适用于需要在企业微信网页端使用扫一扫、定位、录音等接口的场景。


一、项目目标

我们希望实现一个包含以下功能的服务:

  • 提供获取企业微信 access_token 的接口
  • 提供获取部门成员信息的接口(需要带 token)
  • 提供 JS-SDK 前端初始化所需签名参数的接口(wx.config() 配置)
  • 提供一个前端页面用于测试扫码、定位、数据表格展示等功能

二、开发环境与依赖

  • JDK 17
  • IDEA
  • Spring Boot 3.2.5
  • Maven 3.x

三、项目结构

DemoAPI
├── pom.xml                       		  // 项目依赖配置
├── src
│   └── main
│       ├── java
│       │   └── org.example
│       │       ├── Main.java             // 项目启动类
│       │       ├── WeComController.java  // 控制器:处理请求
│       │       └── WeComService.java     // 服务类:处理逻辑
│       └── resources
│           └── static
│               └── index.html            // 测试前端页面

说明: 本项目未配置 application.yml,Spring Boot 默认即可运行。


四、完整功能实现

第一步:修改 pom.xml,添加 Spring Boot 配置

pom.xml 中我们引入了:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope></dependency>
</dependencies>

可能遇到的问题:

  • 依赖下载失败,可通过加速器优化下载速度。
  • 注意 Spring Boot 3.x 要使用 JDK 17+。

第二步:刷新依赖

你可以点击 IntelliJ 右侧 “Maven” 工具窗口的刷新按钮(🔄),或者右键 pom.xml → Add as Maven Project,IDE 会自动下载 Spring Boot 依赖。

第三步:修改你的 Main.java,变成 Spring Boot 启动类

package org.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}
}

问题回顾: 如果你忘记添加 @SpringBootApplication,将导致 ApplicationContext 启动失败,同时控制台可能提示找不到 Web 容器类(如 Tomcat)或无法创建 Controller Bean。解决办法:确保注解已加。

第四步:创建一个服务类 WeComService.java

提供 access_token 缓存获取、jsapi_ticket 缓存、JS-SDK 签名生成逻辑:

String raw = String.format("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s",jsapiTicket, nonceStr, timestamp, url);MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(raw.getBytes(StandardCharsets.UTF_8));

注意:

  • 签名计算必须严格按参数顺序和格式
  • access_tokenjsapi_ticket 建议缓存,避免频繁请求
  • 返回格式需包括 appIdtimestampnonceStrsignature

JS-SDK 参数生成

  • 参数组成:jsapi_ticketnonceStrtimestampurl
  • 算法:SHA-1(raw字符串) 生成签名
  • 返回结构:包含 appIdtimestampnonceStrsignature

第五步:控制器类 WeComController.java

提供如下接口:

接口地址请求方法功能描述
/wecom/tokenGET获取 access_token
/wecom/department/usersGET获取指定部门的成员列表
/wecom/js-sdk-configGET获取 JS-SDK 初始化配置信息

常见问题:

  • 若自动注入失败,请确认 @Service@RestController 注解是否添加
  • 如果依赖注入失败,控制台会提示 UnsatisfiedDependencyException

第六步:创建前端测试页面 index.html

功能:

  • 获取 Token 并展示
  • 获取部门成员并展示表格(含滚动条)
  • 初始化 JS SDK,支持扫码、定位等测试按钮
wx.config({appId: config.appId,timestamp: config.timestamp,nonceStr: config.nonceStr,signature: config.signature,jsApiList: ["scanQRCode", "getLocation"]
});wx.ready(function() {alert("✅ 企业微信 JS SDK 初始化成功");
});

失败处理:

wx.error(function (err) {alert("❌ SDK 初始化失败: " + JSON.stringify(err));
});

页面结构清晰,所有逻辑通过 window.onload 初始化即可。

第七步:运行你的 Spring Boot 应用

在 IntelliJ 中右键 Main.java → Run ‘Main’,或点击绿色的 ▶ 按钮。

看到类似:

Tomcat started on port(s): 8080
Started Main in x.xxx seconds

说明服务已成功启动。

第八步:界面展示

http://localhost:8080/index.html

在这里插入图片描述

运行 & 测试(可选)

启动 Spring Boot 项目后,浏览器访问可访问下面的接口:

http://localhost:8080/wecom/token
http://localhost:8080/wecom/department/users?id=1


六、常见问题总结

问题说明解决办法
SDK 初始化失败签名无效、时间戳不一致等保证 URL 不带 #,参数顺序正确
Bean 注入失败启动报错找不到 Controller Bean检查是否缺少 @SpringBootApplication@Service 注解
依赖无法拉取Maven 仓库连接慢配置阿里云镜像源,提高稳定性
HTML 无法访问资源路径未设置正确放到 resources/static/ 下由 Spring Boot 自动映射

❌ 错误核心提示:

APPLICATION FAILED TO STARTWeb application could not be started as there was no
org.springframework.boot.web.servlet.server.ServletWebServerFactory bean defined in the context.

原因解释:Spring Boot 应用是一个 Web 项目,但 缺少内嵌 Servlet 容器(比如 Tomcat)依赖,也就是没有 ServletWebServerFactory,Spring Boot 启动 Web 服务失败。

最常见的原因:

  • pom.xml 中 缺失或拼错了 spring-boot-starter-web 依赖
  • Maven 没有下载成功依赖(网络或仓库问题)
  • 没有添加 @SpringBootApplication

七、后续可扩展方向

  • 接入企业微信身份认证(OAuth2)
  • 支持更多 JS API(如录音、语音识别、打开地图)
  • 使用 Redis 缓存 token,提升性能与健壮性
  • 前后端分离,使用 Vue、React 等框架

八、结语

通过本项目我们实现了从零搭建一个企业微信 JS-SDK 权限校验服务,具备了完整的后端支持和前端测试页面。如果想正常使用企业微信的扫描等功能需要在企业微信内部访问,那么就需要设置 IP 白名单、域名、网页授权及JS-SDK、企业微信授权登录和应用主页等。


九、推荐

Maven Central(Maven 中央仓库 Web 版)

这是最常用、几乎所有 Java 开发者都会用的网站 —— 一个图形化的 Maven 中央仓库检索平台:

👉 网站地址:
🌐 https://mvnrepository.com

使用 Spring Initializr 官网 创建项目(图形化窗口版)

这个网站会自动帮你生成一个可运行的 Spring Boot 项目,并打包成一个 zip 文件。解压 zip,然后用 IDEA 打开即可。

👉 地址:
🌐 https://start.spring.io


附录:完整文件(可自行补全代码)

pom.xml ✅

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>DemoAPI</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><!-- Spring Boot 父项目 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.5</version><relativePath/></parent><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- Spring Boot Web 模块(包含内嵌 Tomcat) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 开发工具(自动重启,非必须) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

index.html ✅

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>企业微信接口测试</title><style>body {font-family: "微软雅黑", sans-serif;margin: 20px;}table {border-collapse: collapse;width: 100%;margin-top: 10px;}th, td {border: 1px solid #ccc;padding: 6px 12px;text-align: center;}th {background-color: #f5f5f5;}pre {background-color: #eee;padding: 10px;}.scroll-box {max-height: 160px;overflow-y: auto;border: 1px solid #ccc;}</style><!-- 引入企业微信 JS SDK --><script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script><script>// 初始化企业微信 JS SDKasync function initWeComJsSdk() {const url = window.location.href.split('#')[0];const res = await fetch('/wecom/js-sdk-config?url=' + encodeURIComponent(url));const config = await res.json();wx.config({beta: true,debug: false,appId: config.appId,timestamp: config.timestamp,nonceStr: config.nonceStr,signature: config.signature,jsApiList: ["scanQRCode", "getLocation"]});wx.ready(function () {console.log("企业微信 JS SDK 就绪");alert("✅ 企业微信 JS SDK 初始化成功!");document.getElementById('scanBtn').onclick = function () {wx.scanQRCode({needResult: 1,scanType: ["qrCode", "barCode"],success: function (res) {alert("扫码结果:" + res.resultStr);}});};document.getElementById('locBtn').onclick = function () {wx.getLocation({type: 'wgs84',success: function (res) {alert("当前位置:经度 " + res.longitude + ",纬度 " + res.latitude);}});};});wx.error(function (err) {console.error("JS SDK 初始化失败:", err);alert("❌ 企业微信 JS SDK 初始化失败!\n" + JSON.stringify(err));});}async function getToken() {const res = await fetch('/wecom/token');const token = await res.text();document.getElementById('token').innerText = token;}async function getUsers() {const deptId = document.getElementById('dept').value || '1';const res = await fetch(`/wecom/department/users?id=${deptId}`);const json = await res.json();document.getElementById('result').innerText = JSON.stringify(json, null, 2);if (json.userlist) {renderTable(json.userlist);} else {document.getElementById('userTableBody').innerHTML = "<tr><td colspan='6'>无成员数据</td></tr>";}}function renderTable(users) {const tbody = document.getElementById("userTableBody");tbody.innerHTML = "";users.forEach(user => {const row = document.createElement("tr");row.innerHTML = `<td>${user.name}</td><td>${user.userid}</td><td>${(user.department || []).join(',')}</td><td>${user.isleader === 1 ? '是' : '否'}</td><td>${translateStatus(user.status)}</td><td>${user.telephone || ''}</td>`;tbody.appendChild(row);});}function translateStatus(status) {switch (status) {case 1: return "正常";case 2: return "已禁用";case 4: return "未激活";default: return "未知";}}window.onload = function () {initWeComJsSdk();};</script>
</head>
<body><h1>企业微信接口测试</h1><!-- 获取 Token -->
<button onclick="getToken()">获取 Token</button>
<p>Token:<code id="token">(点击上面按钮)</code></p><!-- 获取部门成员 -->
<hr>
<label>部门 ID:</label>
<input type="text" id="dept" value="1">
<button onclick="getUsers()">获取部门成员</button><!-- 显示返回数据 -->
<h3>接口返回数据:</h3>
<pre id="result">(点击按钮查看 JSON)</pre><!-- 成员列表表格 -->
<h3>成员列表表格:</h3>
<div class="scroll-box"><table><thead><tr><th>姓名</th><th>用户ID</th><th>部门</th><th>是否领导</th><th>状态</th><th>座机</th></tr></thead><tbody id="userTableBody"></tbody></table>
</div><!-- 企业微信 JS API 按钮 -->
<h3>企业微信功能测试:</h3>
<button id="scanBtn">扫一扫</button>
<button id="locBtn">获取当前位置</button></body>
</html>

Main.java ✅

package org.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** ==================================================* This class ${NAME} is responsible for [功能描述].** @author Darker* @version 1.0* ==================================================*/@SpringBootApplication
public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}
}

WeComService.java ✅

package org.example;import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.http.ResponseEntity;import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;import java.time.Instant;/*** ==================================================* This class WeComService is responsible for [功能描述].** @author Darker* @version 1.0* ==================================================*/@Service
public class WeComService {private static final String CORP_ID = "你的企业微信ID";private static final String SECRET = "你的自建应用的Secret";private static final String TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";private String accessToken;private long expireTime = 0;// jsapi_ticket(缓存 2 小时)private String jsapiTicket;private long ticketExpire = 0;public String getAccessToken() {long now = Instant.now().getEpochSecond();if (accessToken != null && now < expireTime) {return accessToken;}// 请求新的 tokenRestTemplate restTemplate = new RestTemplate();UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(TOKEN_URL).queryParam("corpid", CORP_ID).queryParam("corpsecret", SECRET);ResponseEntity<WeComTokenResponse> response = restTemplate.getForEntity(builder.toUriString(), WeComTokenResponse.class);WeComTokenResponse body = response.getBody();if (body != null && body.getAccess_token() != null) {this.accessToken = body.getAccess_token();this.expireTime = now + body.getExpires_in() - 60; // 提前60秒过期return accessToken;}throw new RuntimeException("无法获取 access_token");}public Map<String, Object> getJsSdkConfig(String url) {String jsapiTicket = getJsApiTicket(); // 用下面方法实现String nonceStr = UUID.randomUUID().toString().replace("-", "");long timestamp = System.currentTimeMillis() / 1000;String raw = String.format("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s",jsapiTicket, nonceStr, timestamp, url);String signature;try {MessageDigest md = MessageDigest.getInstance("SHA-1");md.update(raw.getBytes(StandardCharsets.UTF_8));signature = bytesToHex(md.digest());} catch (Exception e) {throw new RuntimeException("签名失败", e);}Map<String, Object> result = new HashMap<>();result.put("appId", CORP_ID);result.put("timestamp", timestamp);result.put("nonceStr", nonceStr);result.put("signature", signature);return result;}private String bytesToHex(byte[] bytes) {Formatter formatter = new Formatter();for (byte b : bytes) {formatter.format("%02x", b);}String result = formatter.toString();formatter.close();return result;}public String getJsApiTicket() {long now = System.currentTimeMillis() / 1000;if (jsapiTicket != null && now < ticketExpire) {return jsapiTicket;}String token = getAccessToken();String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=" + token;RestTemplate restTemplate = new RestTemplate();Map<String, Object> res = restTemplate.getForObject(url, Map.class);if (res != null && res.get("ticket") != null) {jsapiTicket = (String) res.get("ticket");ticketExpire = now + ((Integer) res.get("expires_in")) - 60;return jsapiTicket;}throw new RuntimeException("获取 jsapi_ticket 失败");}// 内部类用于接收 JSON 响应public static class WeComTokenResponse {private String access_token;private int expires_in;public String getAccess_token() {return access_token;}public void setAccess_token(String access_token) {this.access_token = access_token;}public int getExpires_in() {return expires_in;}public void setExpires_in(int expires_in) {this.expires_in = expires_in;}}
}

WeComController.java ✅

package org.example;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.util.UriComponentsBuilder;/*** ==================================================* This class WeComController is responsible for [功能描述].** @author Darker* @version 1.0* ==================================================*/@RestController
@RequestMapping("/wecom")
public class WeComController {@Autowiredprivate WeComService weComService;// GET 接口:/wecom/token@GetMapping("/token")public String getToken() {return weComService.getAccessToken();}@GetMapping("/department/users")public Object getDepartmentUsers(@RequestParam("id") String departmentId) {String token = weComService.getAccessToken();String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list";UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParam("access_token", token).queryParam("department_id", departmentId);RestTemplate restTemplate = new RestTemplate();ResponseEntity<Object> response = restTemplate.getForEntity(builder.toUriString(), Object.class);return response.getBody();}// GET 接口:/wecom/js-sdk-config?url=xxx@GetMapping("/js-sdk-config")public Object getJsSdkConfig(@RequestParam("url") String url) {return weComService.getJsSdkConfig(url);}
}

相关文章:

使用 Spring Boot 快速构建企业微信 JS-SDK 权限签名后端服务

使用 Spring Boot 快速构建企业微信 JS-SDK 权限签名后端服务 本篇文章将介绍如何使用 Spring Boot 快速构建一个用于支持企业微信 JS-SDK 权限校验的后端接口&#xff0c;并提供一个简单的 HTML 页面进行功能测试。适用于需要在企业微信网页端使用扫一扫、定位、录音等接口的…...

【软考-架构】13.2、软件层次风格

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 2、层次架构风格两层C/S架构三层C/S架构三层B/S架构富互联网应用RIAMVC架构MVP架构MVVM架构 ✨3、面向服务的架构风格SOASOA中应用的关键技术WEB Service企业服务总线ESB …...

Java 进阶-全面解析

目录 异常处理​ 集合框架​ List 集合​ Set 集合​ Map 集合​ 文件与字符集​ IO 流​ 多线程​ 通过继承Thread类创建线程 通过实现Runnable接口创建线程 线程同步示例​ 线程通信示例 网络编程 Java 高级技术 反射机制 动态代理 注解 异常处理​ 在 Java …...

mongodb 创建keyfile

在 MongoDB 中&#xff0c;keyFile 是用于副本集成员间内部认证的密钥文件。它是一个包含随机字符串的文件&#xff0c;所有副本集成员必须使用相同的 keyFile 进行通信。以下是创建和配置 keyFile 的详细步骤。 创建 KeyFile 的步骤 1. 生成随机字符串 使用以下命令生成一个…...

工业4.0时代,RK3562工控机为何成为智慧工位首选?

在制造业数字化转型的浪潮中&#xff0c;智慧车间已成为提升生产效率、降低运营成本的关键战场。作为智慧车间的"神经末梢"&#xff0c;工位机的智能化程度直接影响着整个生产线的运行效率。RK3562工控机凭借其强大的计算性能、稳定的运行表现和丰富的接口配置&#…...

WPF 资源加载问题:真是 XAML 的锅吗?

你的观察很敏锐&#xff01;确实&#xff0c;在 WPF 项目中&#xff0c;.cs 文件主要负责逻辑实现&#xff0c;而资源加载的问题通常跟 XAML&#xff08;以及它背后的 .csproj 配置&#xff09;关系更大。我会围绕这个观点&#xff0c;用 CSDN 博客风格详细解释一下 .cs、XAML …...

5. 深度剖析:Spring AI项目架构与分层体系全解读

1、前言 前面我们已经可以通过简单的方式集成Spring AI进行快速开发了。授人以鱼不如授人以渔&#xff0c;我们还是需要了解Spring AI的项目结构&#xff0c;以及他的一些核心概念。 2、项目结构 我们将Spring AI代码直接fork到我们自己的仓库中。fork的目的是方便我们为了学…...

2025最新数字化转型国家标准《数字化转型管理参考架构》 正式发布

当前&#xff0c;数字化转型是数字时代企业生存和发展的必答题&#xff0c;其根本任务是价值体系优化、创新和重构。数字生产力的飞速发展不仅引发了生产方式的转变&#xff0c;也深刻改变了企业的业务体系和价值模式。 为进一步引导企业明确数字化转型的主要任务和关键着力点…...

蓝桥杯备赛 Day 20 树基础

![[树的基础概念.png]] 树的遍历 二叉树遍历分类 DFS前序遍历 根节点-左儿子-右儿子 DFS中序遍历 左儿子-根节点-右儿子 DFS后序遍历 左儿子-右儿子-根节点 BFS层序遍历![[树的遍历.png]] 代码: #include <bits/stdc.h>using namespace std; const int N20; i…...

清晰易懂的Jfrog Artifactory 安装与核心使用教程

JFrog Artifactory 是企业级二进制仓库管理工具&#xff0c;支持 Maven、Docker、npm 等 30 包格式。本教程将手把手教你完成 安装、配置、核心操作&#xff0c;并指出企业级部署的避坑要点&#xff0c;助你快速搭建私有仓库&#xff01; 一、安装 JFrog Artifactory&#xff0…...

苍穹外卖总结

苍穹外卖学习知识点 整体概括: 学到目前(day10),总体最核心的部分就是CURD各种数据,因为一些接口,前端页面都已经设计好,在实际开发中也应该是这样,重点是在每个不同的业务板块区别出细微不同的业务逻辑 Swagger注解 swagger是一种自动生成接口文档的插件 使用注解,就可以…...

python学智能算法(九)|决策树深入理解

【1】引言 前序学习进程中&#xff0c;初步理解了决策树的各个组成部分&#xff0c;此时将对决策树做整体解读&#xff0c;以期实现深入理解。 各个部分的解读文章链接为&#xff1a; python学智能算法&#xff08;八&#xff09;|决策树-CSDN博客 【2】代码 【2.1】完整代…...

HTTP代理:内容分发战场上的「隐形指挥官」

目录 一、技术本质&#xff1a;流量博弈中的「规则改写者」 二、战略价值&#xff1a;内容分发的「四维升级」 三、实战案例&#xff1a;代理技术的「降维打击」 四、未来进化&#xff1a;代理技术的「认知升级」 五、结语&#xff1a;代理技术的「战略觉醒」 在数字内容爆…...

学习笔记(C++篇)--- Day2

1.类的定义 1.1 类的格式 ①class为类的关键字 ②在类的内容中还可以写函数&#xff0c;具体格式请看示例。 ③为了区分成员变量&#xff0c;一般习惯上成员变量会加一个特殊标识&#xff08;如成员变量前面或者后面加_ 或者 m开头&#xff0c;注意C中这个并不是强制的&#x…...

下载firefox.tar.xz后如何将其加入到Gnome启动器

起因&#xff1a;近期&#xff08;2025-04-07&#xff09;发现firefox公布了130.0 版本&#xff0c;可以对pdf文档进行签名了&#xff0c;想试一下&#xff0c;所以卸载了我的Debian12上的firefox-esr,直接下载了新版本的tar.xz 包。 经过一番摸索&#xff0c;实现了将其加入Gn…...

VSCode英文翻译插件:变量命名、翻单词、翻句子

目录 【var-translate】 【Google Translate】 【code-translator】 【其他插件】 【var-translate】 非常推荐&#xff0c;可以提供小驼峰、大驼峰、下划线、中划线、常量等翻译&#xff0c;Windows下快捷键为Ctrl Shift v 可以整句英文翻译&#xff0c;并且支持多个免费…...

快速高效的MCP Severs

通用AI Agent的瓶颈 最近一直在用MCP协议开发通用智能体。 虽然大模型本身请求比较慢&#xff0c;但是还可以接受。 而最让人沮丧的是&#xff0c;工具效率也不高 比如社区的filesystem&#xff0c;每次只能创建一个目录&#xff0c;生成文件时&#xff0c;如果目录不存在&…...

原子化 CSS 的常见实现框架

原子化 CSS 是一种 CSS 架构方法&#xff0c;其核心思想是将样式拆分为最小粒度的单一功能类&#xff0c;每个类仅对应一个具体的样式属性&#xff08;如颜色、边距、字体大小等&#xff09;&#xff0c;通过组合这些类来构建复杂的界面。这种方式强调代码复用性、维护性和灵活…...

技术速递|使用 GitHub Copilot Agent Mode 进行编程

作者&#xff1a;卢建晖 - 微软高级云技术布道师 翻译/排版&#xff1a;Alan Wang GitHub Copilot 持续发展&#xff0c;从最初的代码补全、生成、优化功能&#xff0c;到通过对话交互提升 AI 代码质量的 GitHub Copilot Chat&#xff0c;再到能够基于项目中多个文件的关联进行…...

Linux系统(Ubuntu和树莓派)的远程操作练习

目录 实验准备一、Ubuntu 下的远程操作二、树莓派下的远程操作三、思考 实验准备 ​ 1.双方应保证处于同一个局域网内 ​ 2.关闭防火墙 (否则别人将不能 ping 通自己,具体说明请参考&#xff1a;windows-关闭防火墙&#xff09; ​ 3.配置虚拟机 ​ a.网桥模式配置 ​ 查询…...

电脑屏保壁纸怎么设置 桌面壁纸设置方法详解

电脑桌面壁纸作为我们每天面对的第一视觉元素&#xff0c;不仅能够彰显个人品味&#xff0c;还能营造舒适的工作或娱乐氛围。电脑桌面壁纸怎么设置呢&#xff1f;下面本文将为大家介绍Windows和macOS两大主流操作系统中设置电脑桌面壁纸的方法&#xff0c;帮助大家快速设置个性…...

为什么选择Redis?解析核心使用场景与性能优化技巧

解析核心使用场景与性能优化技巧 redis只能能操作字符串&#xff0c;要把Java对象存入redis非关系型数据库&#xff0c;需要用序列化变成字符串&#xff0c;再反序列化成Java对象 not only sql NoSQL非关系型数据库&#xff1a;缓存数据库&#xff0c;只能读取数据&#xff0…...

Docker中Redis修改密码失效

docker容器中&#xff0c;我们通过docker run命令运行某一容器 这里&#xff0c;我们通过以下命令来进行运行【注意&#xff0c;这里有两个关键点&#xff1a;-d 和--requirepass】 docker run \ --restartalways \ --log-opt max-size100m \ --log-opt max-file2 \ -p 6379:6…...

质数质数筛

1.试除法判定质数–O(sqrt(N)) bool is_prime(int x) {if (x < 2) return false;for (int i 2; i < x / i; i )if (x % i 0)return false;return true; }2.试除法分解质因数–O(logN)~O(sqrt(N)) void divide(int x) {for (int i 2; i < x / i; i )if (x % i …...

VGA接口设计

1.VGA简介 VGA(Video Graphics Array)视频图形阵列接口是一种模拟信号视频传输标准,用于连接计算机主机和显示设备,如显示器、投影仪等。 VGA接口能够传输红、绿、蓝三原色的模拟信号以及同步信号(数字信号),实现计算机图形和视频信号的输出和显示。 尽管数字化显示接口…...

clickhouse注入手法总结

clickhouse 遇到一题clickhouse注入相关的&#xff0c;没有见过&#xff0c;于是来学习clickhouse的使用&#xff0c;并总结相关注入手法。 环境搭建 直接在docker运行 docker pull clickhouse/clickhouse-server docker run -d --name some-clickhouse-server --ulimit n…...

VsCode保存时删除无用的引用

打开设置文件 教程&#xff1a;打开VsCode设置设置里添加 {"editor.codeActionsOnSave": {"source.organizeImports": false, // 禁用默认的整理导入"source.removeUnusedImports": true // 仅删除未使用的导入} }...

轻松Linux-4.进程概念

屋漏偏逢连夜雨&#xff0c;今天就学Linux 话不多说&#xff0c;展示军火 1.认识冯诺依曼体系 冯诺依曼体系其实并不是什么稀罕的东西&#xff0c;我们生活中的笔记本、服务器、计算机等等大多都遵守冯诺依曼体系 非常经典的一张图 我们所认识的计算机&#xff0c;是由一个个…...

畅游Diffusion数字人(21):基于Wan2.1的音频驱动数字人FantasyTalking

畅游Diffusion数字人(0)&#xff1a;专栏文章导航 前言&#xff1a;AI数字人是目前视觉AIGC最有希望大规模落地的场景之一。现阶段的商业工具&#xff0c;如字节的OminiHuman-1(即梦大师版)、快手的可灵对口型&#xff0c;虽然效果不错&#xff0c;但是收费昂贵。而开源解决方案…...

CentOS禁用nouveau驱动

1、验证 nouveau 是否在运行 lsmod | grep nouveau如果命令返回结果&#xff0c;说明 nouveau 驱动正在运行。 2、编辑黑名单文件 通过编辑黑名单配置文件来禁用 nouveau 驱动&#xff0c;这样在系统启动时不会加载它。 vi /etc/modprobe.d/blacklist-nouveau.conf修改以下…...

《Operating System Concepts》阅读笔记:p587-p596

《Operating System Concepts》学习第 52 天&#xff0c;p587-p596 总结&#xff0c;总计 10 页。 一、技术总结 1.Recovery (1)consistency checking consistency checking 工具&#xff1a;fsck。 (2)log-structure file system (3)WAFL file system 2.Veritas (1)Ve…...

k8s 1.24.17版本部署(使用Flannel插件)

1.k8s集群环境准备 推荐阅读: https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/ 1.1 环境准备 环境准备:硬件配置: 2core 4GB磁盘: 50GB操作系统: Ubuntu 22.04.04 LTSIP和主机名:10.0.0.231 master23110.0.0.232 worker23210.0…...

通信协议详解(十):PSI5 —— 汽车安全传感器的“抗干扰狙击手”

一、PSI5是什么&#xff1f; 一句话秒懂 PSI5就像传感器界的“防弹信使”&#xff1a;在汽车安全系统&#xff08;如气囊&#xff09;中&#xff0c;用两根线同时完成供电数据传输&#xff0c;即便车祸时线路受损&#xff0c;仍能确保关键信号准确送达&#xff01; 基础概念…...

Kafka生产者和消费者:数据管道的核心引擎与智能终端

在分布式系统中&#xff0c;数据的高效流动如同人体的血液循环&#xff0c;而Kafka的生产者&#xff08;Producer&#xff09;与消费者&#xff08;Consumer&#xff09;正是驱动这一循环的核心组件。它们不仅是Kafka客户端的基本形态&#xff0c;更是构建实时数据生态的基石。…...

特权FPGA之按键消抖

完整代码如下所示&#xff1a; timescale 1ns / 1ps// Company: // Engineer: 特权 // // Create Date: // Design Name: // Module Name: // Project Name: // Target Device: // Tool versions: // Description: // // Dependencies: // // Revision: // …...

实时比分更新系统的搭建

搭建一个实时比分更新系统需要考虑多个技术环节&#xff0c;以下是一个完整的实现方案&#xff1a; 一、系统架构 1.数据获取层 比分数据API接入&#xff08;如熊猫比分、API-Football等&#xff09; 网络爬虫&#xff08;作为备用数据源&#xff09; 2.数据处理层 …...

【Linux】线程的概念与控制

目录 1. 整体学习思维导图 2. 线程的概念 2.1 基础概念 2.2 Linux下的线程 初步理解&#xff1a; 2. 分页式存储 3.1 页表 3.1.1 页框/页 3.1.2 页表机制 3.1.3 从虚拟地址到物理地址的转换 总结&#xff1a; 3.2 TLB快表 3.3 缺页异常&#xff08;Page Fault&am…...

K8s 老鸟的配置管理避雷手册

Yining, China 引言 对于这种案例&#xff0c;你们的处理思路是怎么样的呢&#xff0c;是否真正的处理过&#xff0c;如果遇到&#xff0c;你们应该怎么处理。 最后有相关的学习群&#xff0c;有兴趣可以加入。 开始 一、血泪教训&#xff1a;环境变量引发的真实灾难 1.1 …...

飞速(FS)解决方案验证实验室搬迁升级,赋能客户技术服务

飞速&#xff08;FS&#xff09;解决方案验证实验室近日顺利完成搬迁升级&#xff0c;标志着飞速&#xff08;FS&#xff09;在解决方案可行性验证、质量保障以及定制化需求支持方面迈上新台阶&#xff0c;进一步提升了产品竞争力和客户信任度。 全新升级的实验室定位为技术验证…...

柔性关节双臂机器人奇异摄动鲁棒自适应PD控制

1 双臂机器人动力学模型 对于一个具有多个关节的机器人来说&#xff0c;机器人端动力学子方程及关节驱动电机端动力学子方程为&#xff1a; 以上为推导过程&#xff0c;MATLAB程序已完成&#xff0c;若需要可找我。...

遵循IEC62304YY/T0664:确保医疗器械软件生命周期合规性

一、EC 62304与YY/T 0664的核心定位与关系 IEC 62304&#xff08;IEC 62304&#xff09;是国际通用的医疗器械软件生命周期管理标准&#xff0c;适用于所有包含软件的医疗器械&#xff08;如嵌入式软件、独立软件、移动应用等&#xff09;&#xff0c;其核心目标是确保软件的安…...

Kafka和RocketMQ相比有什么区别?那个更好用?

Kafka和RocketMQ相比有什么区别?那个更好用? Kafka 和 RocketMQ 都是广泛使用的消息队列系统&#xff0c;它们有很多相似之处&#xff0c;但也有一些关键的区别。具体选择哪个更好用&#xff0c;要根据你的应用场景和需求来决定。以下是它们之间的主要区别&#xff1a; 1. …...

空对象模式(Null Object Pattern)在C#中的实现详解

一 、什么是空对象模式 空对象模模是靠”空对孔象式是书丯一种引施丼文行为,行凌,凌万成,个默疤"空象象象象来飞䛿引用用用用电从延盈盈甘仙丿引用用用职从延务在仅代砷易行行 」这种燕式亲如要目的片片 也说媚平父如如 核心思烟 定义一个人 派一个 &#xfffd; 创建…...

【Windows】Win2008服务器SQL服务监控重启脚本

以下是一个用于监控并自动重启 SQL Server 服务的批处理脚本&#xff0c;适用于 Windows Server 2008 和 SQL Server 2012&#xff08;默认实例&#xff09;&#xff1a; echo off setlocal enabledelayedexpansion:: 配置参数 set SERVICE_NAMEMSSQLSERVER set LOG_FILEC:\SQ…...

Spring MVC 操作会话属性详解(@SessionAttributes 与 @SessionAttribute)

Spring MVC 操作会话属性详解&#xff08;SessionAttributes 与 SessionAttribute&#xff09; 1. 核心注解对比 注解作用范围功能SessionAttributes类级别声明控制器中需要持久化的模型属性&#xff08;存入 HttpSession&#xff09;SessionAttribute方法参数/返回值显式绑定…...

416. 分割等和子集

416. 分割等和子集 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割成 [1, 5, 5] 和…...

Composer安装Laravel步骤

Composer安装Laravel步骤 要使用 Composer 安装 Laravel&#xff0c;请按照以下步骤操作&#xff1a; 确保已经安装了 Composer。如果还没有安装&#xff0c;请访问 https://getcomposer.org/download/ 下载并安装。 打开命令行或终端。 使用 cd 命令导航到你的项目目录&…...

游戏引擎学习第209天

调整椅子α 昨天&#xff0c;我们实现了将数据输出到调试流中的功能&#xff0c;之前的调试流大多只包含性能分析数据&#xff0c;而现在我们可以将任意数据放入调试流中。 完成这个功能后&#xff0c;我们接下来要做的是收集这些数据并显示出来&#xff0c;这样我们就能有一…...

更新vscode后链接远程服务器出现了报错‘无法建立连接:远程主机不满足运行vscode服务器的先决条件’20250408

更新了vscode之后再链接远程服务器出现了报错&#xff0c;如下&#xff1a; 1. 确认服务器上的库版本 1.1 检查 glibc 版本 在服务器终端运行&#xff1a; ldd --version 最低要求&#xff1a;VS Code 远程开发需要 glibc ≥ 2.28。 1.2 检查 libstdc 版本 在服务器终端运…...

电磁兼容特种测试

并非所有的检测都能在实验室的标准场地中完成。今天&#xff0c;就带大家走进电磁兼容特种测试中需要现场测试的情况&#xff0c;看看哪些场合和设备有着特殊的测试需求。 哪种场合需要现场测试&#xff1f; 大型设备由于物理尺寸或供电功率上的限制&#xff0c;无法在一般…...