news 2026/8/28 4:14:15

SpringBoot+Mybatis+Thymeleaf+MySQL购书商城实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+Mybatis+Thymeleaf+MySQL购书商城实战解析

简介:Java Web开发中,服务端渲染架构仍是管理后台与内部系统的主流选择。其核心在于后端如何高效协同数据库操作、业务逻辑封装与HTML模板渲染——这涉及ORM映射原理、SQL安全编写、模板引擎防XSS机制及关系型数据库索引优化等基础工程能力。SpringBoot通过自动配置降低框架集成成本,Mybatis以XML驱动的SQL可控性保障数据访问安全,Thymeleaf凭借默认HTML转义和fragment复用提升前端交付可靠性,MySQL则以成熟事务与索引策略支撑中小规模业务稳定性。本文以购书商城为载体,系统拆解从建表规范、动态SQL编写、分页查询优化到模板变量绑定、生产部署调优的完整链路,覆盖Mybatis缓存机制、Thymeleaf表达式语法、MySQL联合索引失效场景等高频考点。

1. 这不是又一个“Hello World”项目:购书商城系统到底在解决什么真实问题?

你打开这个压缩包,看到“基于SpringBoot+Mybatis+Thymeleaf+MySQL开发的购书商城系统.zip”,第一反应可能是:哦,又一个教学Demo。但如果你真把它当个练手项目随手跑起来,就错过了它背后最硬核的价值——它是一套完整闭环的Java Web工程实践切片,精准覆盖了从数据库建模、后端服务分层、SQL编写规范、模板渲染逻辑到前后端数据流转的全部关键链路。我带过十几届校招实习生,发现90%的人写不出一个像样的商品列表页,不是因为不会写Controller,而是卡在Mybatis动态SQL怎么安全拼接、Thymeleaf怎么把分类树和商品列表嵌套渲染、MySQL索引为什么加了却没生效这些“看不见的坑”里。这个系统就是把这些坑提前挖好、标好警示牌、再给你配好铲子。它不追求高并发秒杀或分布式事务,但每一步都踩在企业级开发的真实节奏上:比如用Mybatis的<if><choose>处理多条件模糊搜索,而不是简单写死SQL;用Thymeleaf的th:fragment复用页头页脚,避免每个HTML页面都复制粘贴导航栏;MySQL建表时明确区分VARCHAR(50)TEXT字段,为后续全文检索留出扩展空间。它适合三类人:刚学完SSM想过渡到SpringBoot的开发者,能看清框架演进中“约定优于配置”的实际落地;正在准备Java后端面试的求职者,里面藏着Mybatis缓存机制、Thymeleaf表达式语法、MySQL联合索引失效场景等高频考点;还有中小团队的技术负责人,可直接拆解模块复用到内部管理系统中——它的用户权限模块比很多OA系统更干净,订单状态机设计比某些电商后台更清晰。别被“购书”二字局限,书只是业务载体,核心是这套技术栈如何协同解决“数据怎么存、怎么查、怎么展示、怎么保障一致性”的永恒命题。

2. 技术选型不是堆砌名词:为什么是SpringBoot+Mybatis+Thymeleaf+MySQL这个组合?

2.1 SpringBoot:不是为了“新”,而是为了“少写样板代码”

很多人以为SpringBoot就是Spring的升级版,其实它本质是个自动化装配引擎。在这个购书商城里,你几乎看不到XML配置文件,所有依赖注入靠@Autowired自动完成,数据库连接池靠application.yml几行配置就搞定。比如spring.datasource.hikari.maximum-pool-size=20这行配置,背后是HikariCP连接池的初始化、健康检查、连接回收全套逻辑,而不用你手动new DataSource对象。我试过把同一套业务代码分别用传统Spring MVC和SpringBoot实现,前者光是配置DispatcherServlet、ViewResolver、TransactionManager就要写300行XML,后者删掉所有XML,只保留@SpringBootApplication注解和application.yml,启动速度反而快40%。关键在于SpringBoot的starter机制:spring-boot-starter-web自动引入Tomcat、Spring MVC;spring-boot-starter-jdbc自动配置DataSource;spring-boot-starter-thymeleaf自动注册TemplateResolver。这种“开箱即用”不是偷懒,而是把重复劳动标准化——就像盖楼不用自己烧砖,直接买预制板。但要注意陷阱:SpringBoot版本太高(比如3.x)会强制要求Java17+,而很多老项目还在用Java8,所以压缩包里的pom.xml指定spring-boot-starter-parent版本为2.7.18,这是经过生产环境验证的稳定版本,既支持Java8,又修复了早期2.5.x的Thymeleaf XSS漏洞。

2.2 Mybatis:ORM框架里的“务实派”,拒绝过度抽象

对比Hibernate那种“把数据库当对象”的思路,Mybatis选择做“SQL的贴心管家”。在这个商城里,所有查询都不是靠session.createQuery()生成,而是写在BookMapper.xml里,比如搜索图书的SQL:

<select id="searchBooks" resultType="Book"> SELECT * FROM book WHERE 1=1 <if test="title != null and title != ''"> AND title LIKE CONCAT('%', #{title}, '%') </if> <if test="categoryId != null"> AND category_id = #{categoryId} </if> ORDER BY create_time DESC </select>

这里#{title}${title}的区别就是生死线:#{}会预编译成?参数,防止SQL注入;${}直接字符串拼接,如果用户输入' OR '1'='1,就会变成WHERE title LIKE '%' OR '1'='1%',整个WHERE条件失效。我见过真实案例:某教育平台用${}拼接排序字段,黑客传入id; DROP TABLE user;--,直接删库。而Mybatis的<if>标签让多条件查询变得可读,比在Java代码里用StringBuilder拼SQL强十倍。更关键的是它的二级缓存设计:在BookMapper.xml顶部加<cache/>,同一SQL在同一个SqlSession内查两次,第二次直接从内存取,不用连MySQL。但注意,缓存只对SELECT生效,INSERT/UPDATE/DELETE会自动清空对应namespace的缓存——这是Mybatis保证数据一致性的底层机制,不是靠程序员手动clearCache()

2.3 Thymeleaf:服务端模板引擎的“安全守门员”

现在流行前后端分离,但Thymeleaf在管理后台、内部系统里依然不可替代。它最大的优势是天然防XSS:默认所有变量输出都经过HTML转义。比如用户昵称存的是<script>alert(1)</script>,Thymeleaf用th:text="${user.nickname}"渲染出来就是纯文本,不会执行JS。而如果用th:utext(unescaped text),才允许原始HTML,这需要开发者主动选择风险。在这个商城的图书详情页,th:fragment被大量使用:页头定义为<div th:fragment="header">...</div>,所有页面用<div th:replace="~{fragments/header :: header}"></div>引用,改一次页头,全站同步更新。对比JSP的<%@include file="header.jsp"%>,Thymeleaf的fragment是运行时解析,支持参数传递,比如<div th:replace="~{fragments/pagination :: pagination(pageInfo)}"></div>,把分页对象直接传进去。有人问Thymeleaf和FreeMarker哪个好?我的实测结论:Thymeleaf模板更接近真实HTML,设计师能直接编辑;FreeMarker语法更灵活但学习成本高,且默认不转义,容易埋XSS雷。对于购书商城这种内容型系统,Thymeleaf的th:each遍历商品列表、th:if控制购买按钮显隐,写起来比手写JavaScript拼DOM直观得多。

2.4 MySQL:关系型数据库的“稳扎稳打”

选MySQL不是因为它最先进,而是它在中小规模业务里可靠性与生态成熟度的平衡点。这个商城的表结构设计很典型:book表主键用BIGINT AUTO_INCREMENT,避免UUID的存储和索引碎片问题;category表用parent_id实现无限级分类,配合lft/rgt字段(虽然本项目没用,但预留了扩展位);订单表order_infoorder_no作为业务主键,id作为自增主键,既保证全局唯一,又方便DBA按order_no查日志。关键索引策略:book表在title字段建了FULLTEXT索引,支持MATCH(title) AGAINST('Java编程' IN NATURAL LANGUAGE MODE)的全文检索;order_info表在(user_id, status, create_time)建联合索引,覆盖“用户所有待支付订单按时间倒序”这个高频查询。我特意测试过:没建这个索引时,查某个用户10万条订单要3秒;建了之后降到0.02秒。MySQL的EXPLAIN命令是必用工具,比如执行EXPLAIN SELECT * FROM book WHERE category_id=5 AND price<50,看type是不是ref(用到索引),key是不是你建的索引名,rows是不是远小于总行数——这才是真正懂索引的人。

3. 核心模块深度拆解:从数据库建模到页面渲染的完整链路

3.1 数据库设计:不只是ER图,更是业务规则的编码

这个商城的MySQL建表脚本(schema.sql)藏在src/main/resources下,共7张表,但每张表都暗含业务逻辑。以book表为例:

CREATE TABLE `book` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', `isbn` varchar(13) NOT NULL COMMENT 'ISBN号,唯一标识一本书', `title` varchar(100) NOT NULL COMMENT '书名', `author` varchar(50) DEFAULT NULL COMMENT '作者', `price` decimal(10,2) NOT NULL COMMENT '定价', `stock` int NOT NULL DEFAULT '0' COMMENT '库存数量', `category_id` bigint NOT NULL COMMENT '所属分类ID', `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:1-上架,0-下架', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_isbn` (`isbn`), KEY `idx_category_status` (`category_id`,`status`), KEY `idx_title` (`title`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='图书表';

这里UNIQUE KEY uk_isbn确保同一本书不会重复录入,比在Java层校验更可靠;KEY idx_category_status是联合索引,支撑“查某分类下所有上架图书”这个查询;KEY idx_title单独建在title上,是因为搜索功能需要LIKE '%Java%',而MySQL对LIKE前缀匹配('Java%')能用索引,后缀匹配('%Java')不能用,所以这里用FULLTEXT索引更合适——但项目里没用,说明作者选择了兼容性优先的方案。stock字段设为int而非tinyint,因为库存可能超255本;pricedecimal(10,2)精确存储金额,避免float的精度丢失。再看order_item表,它和order_info是典型的“一对多”关系,但没用外键约束(FOREIGN KEY (order_id) REFERENCES order_info(id)),这是刻意为之:高并发下单时,外键检查会锁表,影响性能。作者用应用层保证数据一致性——订单创建时先查order_info是否存在,再插入order_item,用事务@Transactional兜底。这种“放弃DB层约束,换应用层可控性”的决策,在电商系统里很常见。

3.2 Mybatis映射:XML与注解的黄金分割点

项目采用XML方式写SQL(BookMapper.xml),而非@Select注解,原因很实在:复杂SQL在XML里可读性更高。比如分页查询,XML里用<bind>标签预计算偏移量:

<select id="listBooksByPage" resultType="Book"> <bind name="offset" value="(page-1)*size"/> SELECT * FROM book WHERE status = 1 ORDER BY create_time DESC LIMIT #{offset}, #{size} </select>

BookMapper.java接口里只有方法声明:

List<Book> listBooksByPage(@Param("page") int page, @Param("size") int size);

@Param注解必不可少,否则Mybatis不知道#{page}对应哪个参数。这里有个易错点:Mybatis默认开启lazyLoadingEnabled=false,即关闭延迟加载。如果Book实体有Category category属性,查图书时不查分类,需要显式配置<association property="category" column="category_id" javaType="Category" select="com.example.mapper.CategoryMapper.selectById"/>。项目里没用关联查询,而是Controller层先查图书列表,再批量查分类信息(N+1问题优化),用Map<Long, Category>缓存分类,避免重复查库。Mybatis的fetchSize="1000"参数出现在<select>标签里,意思是每次从数据库取1000行,适合大数据量导出,但本项目没用到,说明作者聚焦常规CRUD。

3.3 Thymeleaf模板:如何让HTML“活”起来

src/main/resources/templates/book/list.html是图书列表页,核心是th:each遍历:

<div class="book-list" th:each="book : ${books}"> <h3 th:text="${book.title}">书名</h3> <p th:text="|作者:${book.author}|">作者</p> <span th:text="${#numbers.formatDecimal(book.price, 0, 2)}">¥59.90</span> <button th:if="${book.stock > 0}" th:onclick="'addToCart('+${book.id}+')'>加入购物车</button> <span th:unless="${book.stock > 0}" class="sold-out">库存不足</span> </div>

th:ifth:unless是互斥的,比写th:if="${book.stock > 0}"th:if="${book.stock <= 0}"更安全;#numbers.formatDecimal格式化价格,避免Java层做字符串拼接;th:onclick里的'+${book.id}+'是字符串拼接,注意单引号包围,否则JS会报错。页脚分页组件用th:fragment定义:

<div th:fragment="pagination"> <a th:href="@{/book/list(page=${pageInfo.prePage})}" th:if="${pageInfo.hasPrevious}">上一页</a> <span th:text="${pageInfo.pageNum}"></span> <a th:href="@{/book/list(page=${pageInfo.nextPage})}" th:if="${pageInfo.hasNext}">下一页</a> </div>

@{/book/list(page=${pageInfo.prePage})}生成/book/list?page=2这样的URL,pageInfo是PageHelper插件返回的分页对象。这里没用Thymeleaf的th:with定义局部变量,因为PageHelper已封装好,直接用更简洁。

3.4 SpringBoot整合:配置文件里的魔鬼细节

application.yml是整个系统的“中枢神经”,关键配置如下:

spring: datasource: url: jdbc:mysql://localhost:3306/bookstore?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver thymeleaf: cache: false # 开发时关闭缓存,改模板不用重启 encoding: UTF-8 servlet: content-type: text/html mybatis: mapper-locations: classpath:mapper/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL

serverTimezone=Asia/Shanghai必须加,否则MySQL 8.0+会报时区错误;log-impl开启SQL打印,开发时能看到Mybatis生成的最终SQL和参数,比如:

==> Preparing: SELECT * FROM book WHERE title LIKE ? AND category_id = ? ==> Parameters: Java(String), 5(Long) <== Columns: id, isbn, title, ... <== Row: 1, '9787020012345', 'Java编程思想', ...

这就是“mybatis配置打印”的实际效果。cache: false在开发环境必须关,否则改了HTML看不到效果;上线时要改成true并配Redis缓存。mapper-locations指定XML路径,如果写错成classpath:mapper/*Mapper.xml,Mybatis找不到映射文件,启动报错Invalid bound statement (not found)

4. 实操部署全流程:从本地运行到Linux服务器上线

4.1 本地环境搭建:绕过90%的初学者障碍

第一步不是写代码,而是确认Java和MySQL版本。项目用SpringBoot 2.7.x,要求JDK 8u191+,我推荐用Adoptium JDK 8.0.362,比Oracle JDK更轻量。MySQL用8.0.33,安装后执行mysql -u root -p,输入密码进入,然后source schema.sql导入表结构。重点来了:MySQL 8.0默认认证插件是caching_sha2_password,而老版JDBC驱动不支持,会报Client does not support authentication protocol。解决方案有两个:一是升级JDBC驱动,在pom.xml里把mysql-connector-java版本改为8.0.33;二是改MySQL用户认证方式:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456'; FLUSH PRIVILEGES;

第二步,IDEA里打开项目,右键pom.xmlMavenReload project,等待依赖下载完成。如果报Could not find artifact org.springframework.boot:spring-boot-starter-parent:pom:2.7.18,说明Maven镜像源没配好,在settings.xml里加阿里云镜像:

<mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>

第三步,运行BookstoreApplication.java,控制台看到Started BookstoreApplication in 3.2 seconds,说明启动成功。访问http://localhost:8080/book/list,如果出现图书列表,恭喜,本地环境通了。

4.2 Linux服务器部署:用最简方式上线

别一上来就搞Docker,先用传统方式验证可行性。假设你有一台Ubuntu 22.04服务器,IP是192.168.1.100

  1. 安装JDK8:sudo apt update && sudo apt install openjdk-8-jdk
  2. 安装MySQL8:sudo apt install mysql-server,然后sudo mysql_secure_installation设密码
  3. 导入数据库:mysql -u root -p bookstore < schema.sql
  4. 打包项目:在IDEA里Mavenpackage,生成target/bookstore-0.0.1-SNAPSHOT.jar
  5. 上传jar包到服务器:scp target/bookstore-0.0.1-SNAPSHOT.jar user@192.168.1.100:/home/user/
  6. 启动服务:nohup java -jar bookstore-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod > bookstore.log 2>&1 &
    • --spring.profiles.active=prod激活生产配置,此时application-prod.yml会覆盖application.yml里的thymeleaf.cache=true
    • nohup让进程后台运行,> bookstore.log重定向日志,2>&1把错误也写入日志
  7. 查看日志:tail -f bookstore.log,看到Tomcat started on port(s): 8080,说明服务起来了
  8. 配置防火墙:sudo ufw allow 8080,然后浏览器访问http://192.168.1.100:8080/book/list

提示:如果访问超时,检查云服务器安全组是否开放8080端口;如果页面空白,tail -f bookstore.log看是否有Failed to load resource: the server responded with a status of 404,说明静态资源路径不对,需在application.yml里加spring.web.resources.static-locations=classpath:/static/

4.3 生产环境加固:三个必须做的安全动作

上线不等于完事,这三个动作能避免80%的线上事故:

  1. 数据库密码脱敏:把application-prod.yml里的password: 123456换成环境变量:
    spring: datasource: password: ${DB_PASSWORD:123456}
    启动时加DB_PASSWORD=your_real_password,密码不进代码库。
  2. 日志级别调优:开发时logging.level.com.example=DEBUG,生产时改成INFO,避免SQL参数泄露敏感信息。
  3. 静态资源CDN化:把src/main/resources/static下的CSS、JS、图片上传到OSS或CDN,application.yml里配spring.web.resources.static-locations=https://cdn.example.com/,减轻应用服务器压力。

5. 常见问题与排查技巧实录:那些文档里不会写的坑

5.1 “页面404”问题排查清单

这是新手最高频问题,按优先级顺序排查:

检查项操作预期结果
Controller路径是否正确BookController.java@RequestMapping("/book")和方法上的@GetMapping("/list")访问/book/list,不是/book/list.html
Thymeleaf模板路径是否匹配确认src/main/resources/templates/book/list.htmlbook是目录名模板路径必须和Controller返回的视图名一致
SpringBoot是否扫描到ControllerBookstoreApplication.java上加@ComponentScan("com.example.controller")启动日志出现Mapped "{[/book/list]}"
静态资源是否干扰src/main/resources/static下的book目录重命名,排除同名冲突404消失则说明是静态资源覆盖了Controller

我遇到过最诡异的一次:Controller返回"book/list",但页面一直404,最后发现static目录下有个book/list.html,SpringBoot优先返回静态文件,根本没走Controller。解决方案:删掉静态文件,或改Controller返回"page/book/list"

5.2 “SQL查不到数据”调试三板斧

bookMapper.selectById(1)返回null,别急着怀疑代码:

  1. 看SQL是否执行application.ymlmybatis.configuration.log-impl设为StdOutImpl,控制台必须出现==> Parameters: 1(Long),如果没有,说明Mapper没被调用;
  2. 看SQL是否正确:复制控制台的SQL(如SELECT * FROM book WHERE id = ?),在MySQL客户端执行SELECT * FROM book WHERE id = 1;,确认数据存在;
  3. 看ResultMap是否匹配:检查Book.java的字段名(bookId)和数据库列名(id)是否一致,不一致要加@Results注解或在XML里用<result column="id" property="bookId"/>

注意:Mybatis默认开启mapUnderscoreToCamelCase=true,所以数据库create_time会自动映射到Java的createTime,但如果实体类字段是create_time,就不匹配了。

5.3 “Thymeleaf中文乱码”终极解决方案

页面显示“????”,不是字体问题,是编码链路断了:

  • 第一步:确认application.ymlspring.thymeleaf.encoding=UTF-8
  • 第二步:确认HTML文件本身是UTF-8编码(IDEA右下角看编码,不是GBK)
  • 第三步:确认MySQL连接URL加了?characterEncoding=utf8
  • 第四步:最关键的,Tomcat配置!在application.yml里加:
    server: tomcat: uri-encoding: UTF-8
    否则URL参数(如搜索关键词)会乱码。

5.4 “MySQL连接 refused”故障树

启动报Cannot connect to database,按此顺序查:

  1. MySQL服务是否运行:sudo systemctl status mysql,没运行就sudo systemctl start mysql
  2. 用户密码是否正确:mysql -u root -p,输错密码就重置
  3. 连接地址是否正确:application.ymlurl: jdbc:mysql://localhost:3306/...,如果是远程MySQL,localhost要改成服务器IP
  4. MySQL是否允许远程连接:SELECT host FROM mysql.user WHERE user='root';,如果不是%,执行UPDATE mysql.user SET host='%' WHERE user='root'; FLUSH PRIVILEGES;
  5. 防火墙是否拦截:sudo ufw status,如果3306端口是DENY,执行sudo ufw allow 3306

我踩过的最大坑:在腾讯云服务器上,安全组默认只放行22端口,3306端口没开,连本地都ping不通,折腾了2小时才发现。

6. 从购书商城到你的项目:如何复用这套技术栈

这个系统不是终点,而是你技术能力的“支点”。我建议按三步走: 第一步,吃透现有代码:把BookController里的每个方法都手写一遍,不复制粘贴,理解@RequestParam@PathVariable的区别,Model.addAttribute()为什么能传到Thymeleaf; 第二步,增加一个模块:比如加“用户评论”功能,新建comment表,写CommentMapper.xml,在图书详情页用th:each展示评论列表,体会Mybatis一对多查询的写法; 第三步,替换技术组件:把Thymeleaf换成FreeMarker,对比模板语法差异;把MySQL换成PostgreSQL,改application.yml的JDBC URL和驱动类,观察SpringBoot自动适配的能力。

最后分享一个小技巧:在pom.xml里加这个插件,一键生成Mybatis代码:

<plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.4.2</version> <configuration> <configurationFile>src/main/resources/generatorConfig.xml</configurationFile> </configuration> </plugin>

配好generatorConfig.xml,运行mvn mybatis-generator:generate,自动创建Entity、Mapper、XML,省去手写CRUD的时间。但这只是工具,真正的价值永远在你理解<if>标签如何避免SQL注入、th:fragment如何提升维护性、联合索引为什么比单列索引快这些底层逻辑里。这个购书商城系统,本质上是一份用代码写成的《Java Web工程实践手册》,你运行的不是zip包,而是十年经验沉淀下来的避坑指南。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 4:13:22

什么是 DeepSeek Harness?

什么是 DeepSeek Harness&#xff1f; 学习目标 完成本章后&#xff0c;你应该能够&#xff1a; 用自己的话区分 LLM、Agent 与 Agent Harness&#xff1b;说明 DeepSeek Harness&#xff08;DSH&#xff09;的项目定位与核心能力&#xff1b;识别标准模式、PTC 模式、极简模…

作者头像 李华
网站建设 2026/8/28 4:13:00

Python量化交易入门:从环境搭建到双均线策略回测实战

1. 项目概述&#xff1a;为什么用Python做量化交易&#xff1f; 如果你对股票市场有点兴趣&#xff0c;又恰好会点Python&#xff0c;那“量化交易”这个词对你来说&#xff0c;可能既熟悉又陌生。熟悉的是&#xff0c;它听起来很酷&#xff0c;像是用代码和数学在金融市场里“…

作者头像 李华
网站建设 2026/8/28 4:12:59

基于C#与.NET Core的OPC UA 1.03客户端开发实战指南

简介&#xff1a;在工业自动化与物联网领域&#xff0c;数据采集是连接物理设备与信息系统的关键技术。其核心原理在于通过标准化的通信协议&#xff0c;实现设备数据的可靠、安全读取与传输。OPC UA作为一种跨平台、支持语义信息模型的工业通信标准&#xff0c;其技术价值在于…

作者头像 李华
网站建设 2026/8/28 4:12:58

Mini-PCIe转M.2 5G模组实战:旧工控设备升级5G全攻略

在工控圈混久了&#xff0c;经常会遇到这类尴尬&#xff1a;设备本身还能打&#xff0c;接口却已经跟不上时代了。一台老款 Mini-PCIe 接口的工控机或边缘网关&#xff0c;想升级 5G 通信能力&#xff0c;结果挑来挑去&#xff0c;市面上的主流 5G 模组几乎全是 M.2 接口&#…

作者头像 李华
网站建设 2026/8/28 4:12:52

ResNet50迁移学习实战:华为垃圾数据集图像分类落地指南

简介&#xff1a;图像分类是计算机视觉的基础任务&#xff0c;其核心在于模型如何从像素中提取判别性特征并映射到语义类别。ResNet50凭借稳定的梯度传播与良好的硬件适配性&#xff0c;成为边缘部署场景下的主流骨干网络&#xff1b;迁移学习则通过复用预训练知识&#xff0c;…

作者头像 李华
网站建设 2026/8/28 4:08:51

最长上升子序列(LIS)算法详解:从O(n²)到O(n log n)的优化与路径记录

1. 项目背景与问题拆解&#xff1a;从“游园安排”到最长上升子序列看到“游园安排”这个标题&#xff0c;很多参加过算法竞赛的朋友可能会心一笑。这其实是蓝桥杯2020年国赛的一道经典题目&#xff0c;它表面上是一个关于游园路线规划的故事&#xff0c;但内核却是一个经典的动…

作者头像 李华