Spring Boot教程之十: 使用 Spring Boot 实现从数据库动态下拉列表
使用 Spring Boot 实现从数据库动态下拉列表
动态下拉列表(或依赖下拉列表)的概念令人兴奋,但编写起来却颇具挑战性。动态下拉列表意味着一个下拉列表中的值依赖于前一个下拉列表中选择的值。一个简单的例子是三个下拉框,分别显示地区、塔卢克和村庄的名称,其中塔卢克中的值取决于地区中选择的值,村庄中的值取决于塔卢克下拉列表中选择的值。动态下拉列表可以使用以下技术实现:
- 任何数据库都可用于加载下拉列表中要填充的地区、塔卢克和村庄的详细信息。在本例中,我们将使用 PostgreSQL。
- 可以使用Java和Spring Boot实现连接数据库的服务类。
- HTML、CSS、JavaScript、jQuery 和 AJAX 可用于实现下拉列表。
本教程的最佳方法是先创建和填充数据库,然后编写 Java 服务类,然后继续设计和编写网页中的下拉列表。在继续进行之前,可视化本教程的大致输出也会有所帮助。

DISTRICT SELECTED

TALUK SELECTED

VILLAGE SELECTED
现在输出已经可视化了,是时候缩小执行本教程目标的细节了。建议单独创建 Spring Boot 项目,并在另一个项目中单独创建网页。
服务方法项目 1:
以下教程介绍了创建 Spring Boot 项目的过程:Spring Boot – 用于显示响应代码和自定义错误代码的服务类示例。数据库部分由每个表的一个 CREATE 命令和每个表的一些 INSERT 命令组成。表的创建命令和相应的插入命令如下所列:
CREATE TABLE district (id int SERIAL PRIMARY KEY,name varchar(50),distcode varchar(4));
insert into district (name,distcode) values('Chennai','1');
insert into district (name,distcode) values('Coimbatore','2'); CREATE TABLE taluk (id int SERIAL PRIMARY KEY,name varchar(50),distcode varchar(4),talukcode varchar(4));
insert into taluk (name,distcode,talukcode) values('Avadi','1','12');
insert into taluk (name,distcode,talukcode) values('Sulur','2','3'); CREATE TABLE village (id int SERIAL PRIMARY KEY,name varchar(50),distcode varchar(4),talukcode varchar(4),villagecode varchar(4));
insert into village (name,distcode,talukcode,villagecode) values('Pothur','1','12','15');
insert into village (name,distcode,talukcode,villagecode) values('Arasur','2','10','9'); 各个数据库的图像如下所示:

DISTRICT DATABASE

TALUK DATABASE

VILLAGE DATABASE
DBController.java
- Java
package com.springboot.springbootdemo; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.websocket.server.PathParam; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController @CrossOrigin public class DBController { PreparedStatement ps; Connection con; String sql; @GetMapping("/dist") @CrossOrigin public String saylistDistrict() throws SQLException { PreparedStatement ps; ResultSet myRs; JSONArray districtlist = new JSONArray(); try { Class.forName("org.postgresql.Driver"); con = DriverManager.getConnection( "jdbc:postgresql://localhost:5432/test?allowPublicKeyRetrieval=true", "postgres", "password"); sql = "SELECT distcode, name FROM district"; ps = con.prepareStatement(sql); myRs = ps.executeQuery(); while (myRs.next()) { JSONObject jsonobj = new JSONObject(); jsonobj.put("districtcode", myRs.getString("distcode") .toString() .trim()); jsonobj.put("districtname", myRs.getString("name") .toString() .trim()); districtlist.add(jsonobj); } System.out.println("districtlist" + districtlist.size()); close(con, ps, myRs); } catch (Exception e) { System.out.println("getservice Exception==>" + e); } return (districtlist.toString()); } @RequestMapping(value = "/taluk", method = RequestMethod.GET) @ResponseBody @CrossOrigin public String ListTaluk(@RequestParam String Discode) throws ParseException { String districtcode = Discode; JSONArray taluklist = new JSONArray(); try { Class.forName("org.postgresql.Driver"); con = DriverManager.getConnection( "jdbc:postgresql://localhost:5432/test?allowPublicKeyRetrieval=true", "postgres", "password"); sql = " select * from taluk where distcode=?"; ps = con.prepareStatement(sql); ps.setString(1, districtcode); ResultSet res = ps.executeQuery(); while (res.next()) { JSONObject jsontaluk = new JSONObject(); jsontaluk.put("districtcode", res.getString("distcode") .toString() .trim()); jsontaluk.put("talukcode", res.getString("talukcode") .toString() .trim()); jsontaluk.put("talukname", res.getString("name") .toString() .trim()); taluklist.add(jsontaluk); } System.out.println("taluklist" + taluklist.size()); close(con, ps, res); } catch (Exception e) { System.out.println( "getservice Edistid1xception==>" + e); } return (taluklist.toString()); } @RequestMapping(value = "/village", method = RequestMethod.GET) @ResponseBody @CrossOrigin public String Listvillage(@RequestParam String Discode, @RequestParam String Talukcode) throws ParseException { String districtcode = Discode; String talukcode = Talukcode; JSONArray villagelist = new JSONArray(); try { Class.forName("org.postgresql.Driver"); con = DriverManager.getConnection( "jdbc:postgresql://localhost:5432/test?allowPublicKeyRetrieval=true", "postgres", "password"); sql = "select * from village where distcode=? and talukcode=?"; ps = con.prepareStatement(sql); ps.setString(1, districtcode); ps.setString(2, talukcode); ResultSet resl = ps.executeQuery(); while (resl.next()) { JSONObject jsonvillage = new JSONObject(); jsonvillage.put("districtcode", resl.getString("distcode") .toString() .trim()); jsonvillage.put("talukcode", resl.getString("talukcode") .toString() .trim()); jsonvillage.put( "villagecode", resl.getString("villagecode") .toString() .trim()); jsonvillage.put("villagename", resl.getString("name") .toString() .trim()); villagelist.add(jsonvillage); } System.out.println("villagelist" + villagelist.size()); close(con, ps, resl); } catch (Exception e) { System.out.println("getservice Exception==>" + e); } return (villagelist.toString()); } private static void close(Connection myConn, Statement myStmt, ResultSet myRs) { try { if (myRs != null) { myRs.close(); } if (myStmt != null) { myStmt.close(); } if (myConn != null) { myConn.close(); } } catch (Exception exc) { exc.printStackTrace(); } } } |
对以上代码的解释:
- 需要@RestController注释来标识Java服务类,并且建议仅在授权发送请求的URL时使用@CrossOrigin注释。
- @GetMapping(“/dist”) 注释用在 saylistDistrict() 函数之前,这样每当调用包含“/dist”的 URL 时就会调用该函数。
- 函数 saylistDistrict() 从数据库中检索数据,处理并以 JSON 格式返回数据,该格式在以下子要点中解释:
- 建立数据库连接并调用相应的选择查询来检索区域详细信息及其各自的代码。
- “SELECT distcode, name FROM district” 查询检索地区名称以及地区代码,然后将其存储在结果集“myRs”中。然后迭代结果集,并将地区数据存储在 JSON 对象“jsonobj”中。
- 迭代完每个区域后,将生成的 JSONObject 添加到主 JSONArray“districtlist”中。使用 close(Connection myConn, Statement myStmt, ResultSet myRs) 方法关闭数据库连接,其中 Connection、ResultSet 和 Statement 均已关闭。
注意:在 Web 应用程序中,每次使用后关闭数据库连接非常重要。如果不这样做,当用户从数据库服务器请求数据库连接时,可能会导致内存泄漏、性能下降、连接不足。
- “return(districtlist.toString());”命令将 JSONArray 转换为字符串,然后将其返回给调用 Java 方法的实体。
- 现在该介绍 ListTaluk() 函数了。此函数也使用与 saylistDistrict() 函数相同的注释,但附加注释 '@RequestMapping(value = “/taluk”, method = RequestMethod.GET)'
- @RequestMapping(value = “/taluk”, method = RequestMethod.GET) 注释简化了使用 @RequestParam 注释的 URL 参数映射。
- 当 URL 包含 @RequestMapping 注释的 value 参数中提到的值时,将调用此方法。 method 参数提到请求方法,在本例中为 GET 方法。 RequestMethod 是为此目的编写的内置 Java 类,它用在方法名称之前,以点 (.) 分隔。
- @RequestParam 注释从 URL 中读取 distid1 值并将该值存储在“String Discode”变量中。然后将 Discode 值存储到字符串变量“discode”中。
- 后续操作和命令与之前的方法类似,只是过程中有一些细微的变化,下面给出的子要点将对此进行解释:
- 检索 taluk 名称以及相应的地区代码和 taluk 代码的查询是“select * from taluk where distcode=?”,其中 ? 表示地区代码的值。
- ps.setString(1,districtcode) 设置查询中的区域代码的值。
- 使用命令“ResultSet res = ps.executeQuery();”执行查询并将其存储在 ResultSet 中。
- “jsontaluk” 是用于存储每次迭代中的 taluk 名称的 JSONObject。例如,“jsontaluk.put(“districtcode”, res.getString(“distcode”).toString().trim());” 是将地区值存储在 JSONObject 中的命令。
- 类似地,在接下来的三行中,taluk 代码和 taluk 名称也存储在 JSONObject 中,并且该对象存储在 JSONArray “taluklist” 中
- 使用“return(taluklist.toString());”命令转换为字符串后返回 JSONArray。
- Listvillage() 方法中使用的所有注释与 ListTaluk() 注释中使用的注释相同。
- 与 Listvillage() 方法中的操作方式类似,使用查询检索村庄名称、地区代码、taluk 代码和村庄代码。检索到的数据存储在 JSONArray 中,并在方法结束时以字符串格式返回。
项目 2 网页和前端
下拉列表.jsp
- HTML
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <script type="text/javascript" src="jquery-3.6.0.min.js"></script> <script type="text/javascript" src="Ajaxcall.js"></script> <!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>Insert title here</title> </head> <body> <table border="1" cellpadding="10px" cellspacing="5px"> <tr> <td>District: </td> <td> <select id="districtlist" name="districtlist" required> <option disabled selected>Select District</option> </select> </td> </tr> <tr> <td>Taluk: </td> <td> <select id="taluklist" name="taluklist" required> <option disabled>Select Taluk</option> </select> </td> </tr> <tr> <td>Village: </td> <td> <select id="villagelist" name="villagelist" required> <option disabled>Select Village</option> </select> </td> </tr> </table> </body> </html> |
插件 jquery-3.6.0.min.js 需要导入到 HTML 项目中,当插件部署到本地项目并导入时,效果最佳。网页很简单,只有基本布局,没有太多 CSS,因为本教程的范围只是解释基于数据库的动态下拉列表。现在已经编写了下拉列表的网页布局,是时候编写 AJAX 调用了。名为 Ajaxcall.js 的 JavaScript 文件用于填充下拉列表。它也是调用链接到 Java 服务方法的 URL 的地方。
Ajax调用
- JavaScript
var dis; var tal; var vill; $(document).ready(function () { $.ajax({ type: "GET", url: "http://localhost:8075/dist", data: "json", contentType: "application/json", success: function (data) { let obj = $.parseJSON(data); $.each(obj, function (key, value) { $('#districtlist').append('<option value="' + value.districtcode + '">' + value.districtcode + '--' + value.districtname + '</option>'); }); }, error: function (data) { $('#districtlist').append('<option>District Unavailable</option>'); }, }); /*$('#districtlist').trigger("change");*/ $('#districtlist').change(function () { $('#taluklist').find('option').remove(); $('#taluklist').append('<option>Select taluk</option>'); $('#villagelist').find('option').remove(); $('#villagelist').append('<option>Select village</option>'); var distid1 = $('#districtlist').val(); var inputValObj = {}; alert(distid1); inputValObj.Discode = distid1; var inputVal = JSON.stringify(inputValObj); alert(inputVal); var data = inputVal.toString(); alert(data); $.ajax({ type: "GET", url: "http://localhost:8075/taluk?Discode=" + distid1, /*data: 1,*/ contentType: "application/json", success: function (data) { let obj = $.parseJSON(data); $.each(obj, function (key, value) { $('#taluklist' ).append( '<option value="' + value.talukcode + '">' + value.talukcode + '--' + value.talukname + '</option>'); }); }, error: function (data) { $('#taluklist' ).append('<option>Taluk Unavailable</option>'); }, }); }); $('#taluklist' ).change( function () { $('#villagelist' ).find('option').remove(); $('#villagelist' ).append('<option>Select village</option>'); var distid1 = $('#districtlist').val(); var talukid = $('#taluklist').val(); alert(distid1); alert(talukid); var inputValObj = {}; inputValObj.Discode = distid1; inputValObj.talucode = talukid; var inputVal = JSON.stringify(inputValObj); var data = inputVal.toString(); $.ajax({ type: "GET", //POST url: "http://localhost:8075/village?Discode=" + distid1 + "&" + "Talukcode=" + talukid, contentType: "application/json", success: function (data) { let obj = $.parseJSON(data); $.each(obj, function (key, value) { $('#villagelist' ).append( '<option value="' + value.villagecode + '">' + value.villagecode + '--' + value.villagename + '</option>'); }); }, error: function (data) { $('#villagelist').appe nd('<option>village Unavailable</option>'); }, }); }); }); |
当文档准备就绪时,使用“http://localhost:8075/dist”URL 在第一个 AJAX 调用中调用 saylistDistrict() 函数,提取的数据进入成功函数。现在,数据被解析并存储到变量“obj”中,然后使用 jQuery 中的 $.each 进行迭代。然后使用“$('#districtlist').append('<option value=”' + value.districtcode+ '”>' + value.districtcode + '–' + value.districtname+ '</option>');' 命令将迭代中的每个条目附加到区域下拉列表中。
注意:'districtlist' 是区域下拉菜单的 ID。
当地区下拉菜单发生变化时,jQuery '$('#districtlist').change(function () {}); 被调用,url “http://localhost:8075/taluk?Discode=”+distid1 调用 Java 函数 ListTaluk()。然后使用 ' $('#taluklist').append('<option value=”' + value.talukcode + '”>' + value.talukcode + '–' + value.talukname+ '</option>');' 命令将返回的数据填充到 taluk 下拉菜单中。
当 taluk 下拉列表值发生更改时,将调用 jQuery '$('#taluklist').change(function () {});'。url“http://localhost:8075/village?Discode=”+distid1+”&”+”Talukcode=”+talukid 调用 Java 函数 Listvillage()。然后使用 '$('#villagelist').append('<option value=”' + value.villagecode + '”>' + value.villagecode + '–' + value.villagename+ '</option>')' 命令将返回的数据填充到 'villagelist' 下拉列表中。
此外,每当修改下拉菜单时,依赖于修改的下拉菜单的其他下拉菜单值都会被删除,并插入“选择”占位符。使用 .remove() 函数删除下拉菜单值(如上例所示),并使用以下模板中的命令插入“选择”占位符“$('#taluklist').append('<option>Select taluk</option>');”。
在任何 Spring Boot 项目中,都会有一个带有 @SpringBootApplication 注释的 Java 类,必须使用右键单击并选择 Run As _> Java 应用程序来运行该类。第一个项目必须以这种方式运行。第二个项目必须在服务器上运行,方法是使用右键单击 - Run as -> Run on the server。使用以下方法运行 dropdown.jsp 后,可以观察到本教程的输出。
相关文章:
Spring Boot教程之十: 使用 Spring Boot 实现从数据库动态下拉列表
使用 Spring Boot 实现从数据库动态下拉列表 动态下拉列表(或依赖下拉列表)的概念令人兴奋,但编写起来却颇具挑战性。动态下拉列表意味着一个下拉列表中的值依赖于前一个下拉列表中选择的值。一个简单的例子是三个下拉框,分别显示…...
基于混合ABC和A*算法复现
基于混合ABC和A*算法复现 一、背景介绍二、算法原理(一)A*算法原理(二)人工蜂群算法原理(三)混合ABC和A*算法策略 三、代码实现(一)数据准备(二)关键函数实现…...
狂野飙车8+(Asphalt 8+) for Mac 赛车竞速游戏 安装教程
Mac分享吧 文章目录 狂野飙车8(Asphalt 8) for Mac 赛车竞速游戏软件 效果图展示一、狂野飙车8(Asphalt 8) 赛车竞速游戏 Mac电脑版——v2.1.11️⃣:下载软件2️⃣:安装软件2.1 左侧安装包拖入右侧文件夹中,等待安装完成,运行软件…...
网络技术-VRRP(虚拟路由冗余协议)部署介绍
一、VRRP的含义 VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)是一种高度可靠的路由器备用协议,用于在局域网内部提供路由器冗余。 其部署方式主要是通过多个路由器组成一个虚拟路由器组,通过协议选…...
C语言解决空瓶换水问题:高效算法与实现
标题:C语言解决空瓶换水问题:高效算法与实现 一、问题描述 在一个饮料促销活动中,你可以通过空瓶换水的方式免费获得更多的水:3个空瓶可以换1瓶水。喝完这瓶水后,空瓶会再次变为空瓶。假设你最初拥有一定数量的空瓶&a…...
day2全局注册
全局注册代码: //文件核心作用:导入App.vue,基于App.vue创建结构渲染index.htmlimport Vue from vue import App from ./App.vue //编写导入的代码,往代码的顶部编写(规范) import HmButton from ./components/Hm-But…...
鸿蒙多线程应用-taskPool
并发模型 并发模型是用来实现不同应用场景中并发任务的编程模型,常见的并发模型分为基于内存共享的并发模型和基于消息通信的并发模型。 Actor并发模型作为基于消息通信并发模型的典型代表,不需要开发者去面对锁带来的一系列复杂偶发的问题,同…...
【失败经验】将算法模型封装为安卓应用
背景:不懂安卓开发,希望能使用大模型编码完成安卓应用生成,调用算法模型进行预测。 模型准备: pip方案安装pcnn; 然后需要将pytorch训练完成的算法模型保存为torchscript模型,然后使用pcnn转换为ncnn的模…...
ABAP OOALV模板
自用模板,可能存在问题 一、主程序 *&---------------------------------------------------------------------* *& Report ZVIA_OO_ALV *&---------------------------------------------------------------------* REPORT ZVIA_OO_ALV.INCLUDE ZVI…...
YOLOv8-ultralytics-8.2.103部分代码阅读笔记-autobatch.py
autobatch.py ultralytics\utils\autobatch.py 目录 autobatch.py 1.所需的库和模块 2.def check_train_batch_size(model, imgsz640, ampTrue, batch-1): 3.def autobatch(model, imgsz640, fraction0.60, batch_sizeDEFAULT_CFG.batch): 1.所需的库和模块 # Ultraly…...
SycoTec 4060 ER-S德国高精密主轴电机如何支持模具的自动化加工?
SycoTec 4060 ER-S高速电主轴在模具自动化加工中的支持体现在以下几个关键方面: 1.高精度与稳定性:SycoTec 4060 ER-S锥面跳动小于1微米,确保了加工过程中的极高精度,这对于模具的复杂几何形状和严格公差要求至关重要。高精度加工…...
部署 DeepSpeed以推理 defog/sqlcoder-70b-alpha 模型
部署 DeepSpeed 以推理 defog/sqlcoder-70b-alpha 这样的 70B 模型是一个复杂的过程,涉及多个关键步骤。下面是详细的步骤,涵盖了从模型加载、内存优化到加速推理的全过程。 1. 准备环境 确保你的环境配置正确,以便能够顺利部署 defog/sqlc…...
Python网络爬虫基础
Python网络爬虫是一种自动化工具,用于从互联网上抓取信息。它通过模拟人类浏览网页的行为,自动地访问网站并提取所需的数据。网络爬虫在数据挖掘、搜索引擎优化、市场研究等多个领域都有广泛的应用。以下是Python网络爬虫的一些基本概念: 1.…...
每天五分钟机器学习:支持向量机数学基础之超平面分离定理
本文重点 超平面分离定理(Separating Hyperplane Theorem)是数学和机器学习领域中的一个重要概念,特别是在凸集理论和最优化理论中有着广泛的应用。该定理表明,在特定的条件下,两个不相交的凸集总可以用一个超平面进行分离。 定义与表述 超平面分离定理(Separating Hy…...
TCP/IP网络协议栈
TCP/IP网络协议栈是一个分层的网络模型,用于在互联网和其他网络中传输数据。它由几个关键的协议层组成,每一层负责特定的功能。以下是对TCP/IP协议栈的简要介绍: TCP/IP协议模型的分层 1. 应用层(Application Layer)…...
利用编程思维做题之最小堆选出最大的前10个整数
1. 理解问题 我们需要设计一个程序,读取 80,000 个无序的整数,并将它们存储在顺序表(数组)中。然后从这些整数中选出最大的前 10 个整数,并打印它们。要求我们使用时间复杂度最低的算法。 由于数据量很大,直…...
详解MVC架构与三层架构以及DO、VO、DTO、BO、PO | SpringBoot基础概念
🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 今天毛毛张分享的是SpeingBoot框架学习中的一些基础概念性的东西:MVC结构、三层架构、POJO、Entity、PO、VO、DO、BO、DTO、DAO 文章目录 1.架构1.1 基本…...
Unity C# 影响性能的坑点
c用的时间长了怕unity的坑忘了,记录一下。 GetComponent最好使用GetComponent<T>()的形式, 继承自Monobehaviour的函数要避免空的Awake()、Start()、Update()、FixedUpdate().这些空回调会造成性能浪费 GetComponent方法最好避免在Update当中使用…...
工作学习:切换git账号
概括 最近工作用的git账号下发下来了,需要切换一下使用的账号。因为是第一次弄,不熟悉,现在记录一下。 打开设置 路径–git—git remotes,我这里选择项是Manage Remotes,点进去就可以了。 之后会出现一个输入框&am…...
量化交易系统开发-实时行情自动化交易-8.量化交易服务平台(一)
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来会对于收集整理的33个量化交易服…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
