news 2026/9/3 17:47:32

JSP+Servlet+JDBC项目实战:从经典架构到现代化IDE配置与安全加固

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JSP+Servlet+JDBC项目实战:从经典架构到现代化IDE配置与安全加固

简介:本资源是一套面向Java Web初学者与高校课程设计学生的JSP教学管理系统完整开发包,聚焦教育信息化场景,解决传统教务管理中学生、课程、成绩、教师等模块手工操作效率低、数据分散等问题。压缩包共399个文件,总大小1.24MB,涵盖59个JSP页面(实现动态交互逻辑)、33个Java类文件(含DAO、Service及工具类如DBConnection、FileUpload等)、22个SQL与TXT文档(含数据库建表脚本与配置说明)、16个DOC格式论文材料(含系统分析、MVC架构设计、权限控制方案及性能评估),以及大量界面资源(144个PNG、83个GIF)。已有137人学习下载。读者可直接部署运行,深入理解JSP+Servlet+MySQL的三层架构实践,掌握角色权限分离、文件上传、连接池配置等关键技能,并通过附带论文系统梳理从需求分析到测试部署的全流程开发方法。

1. 项目缘起:一个被低估的“老”技术栈实战项目

最近在整理硬盘时,翻到了一个尘封已久的压缩包,文件名是“JSP教学管理系统设计(源代码+论文).rar”。相信很多从那个年代走过来的Java开发者,看到这个标题都会会心一笑。这几乎是十年前,甚至更早时期,计算机专业学生毕业设计的“标配”项目之一。在Spring Boot、微服务、前后端分离大行其道的今天,JSP(JavaServer Pages)似乎已经成了“上古”技术,被贴上了“落后”、“耦合度高”、“难以维护”的标签。很多新手甚至会觉得,花时间研究这样一个“过时”的项目,纯属浪费时间。

但作为一个经历过完整技术周期迭代的老兵,我的看法恰恰相反。我认为,透彻地理解并亲手实现一个经典的JSP+Servlet+JDBC架构的管理系统,其价值远超过盲目追逐最新框架却不知其所以然。这个项目麻雀虽小,五脏俱全,它几乎涵盖了Web应用最核心的MVC思想、数据库CRUD操作、会话管理、基础安全等所有关键概念。今天,我就以这个“JSP教学管理系统”为蓝本,抛开那些华而不实的框架外壳,带你重新审视Web开发的底层逻辑,并分享如何让这样一个“传统”项目在现代化的IDE(如IntelliJ IDEA)中顺畅运行、调试,甚至融入一些现代工程化的思考。你会发现,很多你现在在Spring里用注解轻松搞定的事情,在Servlet和JSP里是如何一步步手动实现的,这种理解对于构建坚实的技术地基至关重要。

2. 项目核心架构与MVC模式的“原始”实现

在开始动手之前,我们必须先厘清这个项目的技术栈和架构。典型的“JSP教学管理系统”通常采用JSP Model 2架构,这是MVC模式在Java Web早期的经典实践。它与我们今天熟悉的Spring MVC在思想上同源,但在实现上更为“赤裸”。

2.1 技术栈拆解:每一层的作用与选型理由

  1. 前端展示层 (View):JSP页面。这是项目的门面,负责数据的最终渲染和展示。JSP允许我们在HTML中嵌入Java代码(使用<% ... %>脚本片段或JSTL标签),这在当时是实现动态页面的主流方式。它的优势是直接、快速,但缺点也显而易见:业务逻辑和展示逻辑容易混杂,导致后期维护困难。项目中你会看到listStudent.jspaddCourse.jsp这类页面,它们就是各个功能的入口和结果展示页。

  2. 控制层 (Controller):Servlet。这是整个系统的大脑和交通枢纽。所有来自浏览器的请求(如/student/add,/course/delete)都会被web.xml中配置的Servlet拦截。Servlet负责:

    • 接收请求参数:通过request.getParameter()获取表单数据。
    • 调用业务逻辑:实例化对应的Service或DAO对象,执行业务操作。
    • 处理结果与路由:根据业务执行结果,将数据存入requestsession作用域,然后使用request.getRequestDispatcher().forward()跳转到目标JSP页面,或者使用response.sendRedirect()进行重定向。
    • 为什么是Servlet?在当时的背景下,Servlet是Java EE规范中处理HTTP请求的唯一标准组件。它定义了完整的生命周期(init, service, destroy),是理解Web请求-响应模型的最佳教材。
  3. 模型层 (Model): 主要由两部分构成。

    • 实体类 (JavaBean): 如Student.javaCourse.javaTeacher.java。这些是简单的POJO(Plain Old Java Object),包含属性、getter/setter方法,用于在层之间传输数据。它们对应数据库中的表结构。
    • 数据访问层 (DAO, Data Access Object): 如StudentDao.javaCourseDao.java。这一层封装了所有对数据库的操作,是系统中最需要稳定性的部分。它直接通过JDBC与数据库交互。
  4. 数据持久层:JDBC (Java Database Connectivity)。这是Java连接数据库的标准API。项目中会有一个DBUtil.java之类的工具类,负责管理数据库连接(Connection)、预处理语句(PreparedStatement)和结果集(ResultSet)。你会看到大量的Class.forName(“com.mysql.jdbc.Driver”)DriverManager.getConnection()以及手动处理try-catch-finally来关闭资源的代码。理解JDBC的原始操作,是后续理解MyBatis、Hibernate等ORM框架为何诞生以及解决了什么痛点的关键。

  5. 数据库:MySQL。教学管理系统的经典选择,轻量、开源、足够应对课程、学生、成绩、教师等基础数据的存储。

这个技术栈的选择,反映了当时(约2010年前后)高校教学和中小企业开发的普遍现状:技术成熟、资料丰富、环境要求低(一个Tomcat + 一个MySQL即可运行)。它不追求性能极致或分布式,而是力求在单一应用内清晰地展示Web应用从接收到响应全流程。

2.2 核心业务流程走查:以“学生选课”为例

让我们跟踪一个典型功能“学生选课”的完整代码流,来感受这个架构是如何运作的:

  1. 用户发起请求:学生登录后,在courseList.jsp页面点击“选课”按钮,链接指向/selectCourse?courseId=1001
  2. Servlet拦截:在web.xml中,这个URL模式可能被映射到SelectCourseServlet
  3. Servlet处理
    // SelectCourseServlet.java (简化示例) protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取参数 String courseId = request.getParameter("courseId"); String studentId = (String) request.getSession().getAttribute("userId"); // 从会话获取当前学生ID // 2. 调用业务逻辑 SelectCourseService service = new SelectCourseService(); boolean success = service.selectCourse(studentId, courseId); // 3. 处理结果与路由 if(success) { request.setAttribute("message", "选课成功!"); } else { request.setAttribute("error", "选课失败,可能课程已满或已选。"); } // 跳转回课程列表页,并显示消息 request.getRequestDispatcher("/courseList.jsp").forward(request, response); }
  4. Service层处理SelectCourseService会调用SelectionDao来检查选课条件(如名额是否已满、是否冲突),然后执行插入操作。
  5. DAO层操作SelectionDao使用JDBC,执行类似INSERT INTO selection (student_id, course_id) VALUES (?, ?)的SQL语句。
  6. 视图渲染:请求被转发到courseList.jsp。该JSP页面会通过JSTL或脚本片段,从request作用域中取出messageerror属性,并动态显示提示信息,同时重新从数据库查询并渲染最新的课程列表。

这个过程清晰地展示了数据如何从视图层,经过控制层、业务层、持久层,抵达数据库,再逆向返回的全过程。每一个环节都是显式、手动控制的,没有任何“魔法”。这种透明性对于初学者理解Web开发本质,具有不可替代的教育意义。

3. 现代化IDE中的项目配置与常见“坑点”修复

拿到一个十年前的JSP项目源码,直接扔进现代版的IntelliJ IDEA里,大概率是跑不起来的。你会遇到各种环境、配置、编码问题。下面我就带你一步步解决,这不仅是为了运行这个老项目,更是学习如何应对“历史遗留代码”的宝贵经验。

3.1 环境准备与项目导入

  1. JDK版本:老项目通常基于JDK 1.6或1.7。建议使用JDK 8作为兼容的起点。在IDEA中,确保Project Structure->Project设置中的Project SDK为JDK 8。
  2. Web服务器Apache Tomcat是唯一推荐的选择。版本建议使用Tomcat 8.5或9.x,它们对Servlet 3.0/3.1规范支持良好,且兼容老项目。在IDEA中下载并配置好Tomcat。
  3. 数据库:安装MySQL(5.7版本兼容性最好)。根据项目中的SQL脚本(通常名为database.sqlmydb.sql)创建数据库和表。
  4. 导入项目:由于是rar压缩包,解压后通常是一个包含src,WebContent(或WebRoot),lib等文件夹的普通Java项目。在IDEA中,选择Open,定位到项目根目录打开。IDEA通常会将其识别为一个普通项目,我们需要将其转换为Web项目。

3.2 关键配置步骤与避坑指南

坑点一:项目Facet配置缺失老项目没有像Maven/Gradle这样的构建工具描述文件。IDEA可能无法识别它是一个Web项目。

  • 操作:打开Project Structure(Ctrl+Alt+Shift+S),进入Facets。点击+,为你的模块添加WebFacet。在Deployment Descriptors下,指定web.xml的路径(通常在WebContent/WEB-INF/下)。在Web Resource Directories下,添加你的Web资源根目录(如WebContent)。
  • 为什么:这告诉IDEA,这个模块包含Web应用的结构,需要特定的编译、打包和部署支持。

坑点二:依赖库(Lib)未正确引入项目lib文件夹下的jar包(如mysql-connector-java-5.1.x.jar,servlet-api.jar,jstl.jar等)必须被加入到项目的类路径中。

  • 操作:在Project Structure->Libraries中,点击+->Java,然后选择项目中的lib文件夹。确保这些库被添加到模块的依赖中(Modules->Dependencies-> 检查lib依赖是否存在)。
  • 注意servlet-api.jar在部署到Tomcat时,Tomcat本身会提供,为避免冲突,可以将其依赖范围设置为Provided(如果你用Maven管理的话)。对于普通项目,直接放在lib里,IDEA在开发时能识别即可。

坑点三:JSP页面语法支持与高亮这是网络热词中提到的痛点:“idea设置jsp页面语法高亮”。新版IDEA对JSP的支持可能默认不完整。

  • 操作:打开Settings->Editor->File Types。找到JSPJSPX,确保它们的模式正确关联了.jsp.jspx文件。通常IDEA会自动识别。如果JSP页面内HTML或Java代码没有高亮,检查Settings->Editor->Color Scheme->JSP下的配色设置。
  • 更重要的:确保Project Structure->Modules-> 你的模块 ->Sources选项卡下,WebContent目录被标记为Resources(蓝色)。这样IDEA才会将其中的JSP文件视为资源文件进行索引和语法检查。

坑点四:JSP文件引用与跳转失效热词中提到“idea2026.2中jsp页面中的函数点击引用无法跳转”。这通常是因为IDEA的索引或缓存问题。

  • 操作
    1. 清理缓存File->Invalidate Caches...->Invalidate and Restart。这是解决各种IDE诡异问题的万能第一步。
    2. 重建索引:重启后,IDEA会自动重建索引。你也可以在项目根目录右键,选择Reindex
    3. 检查项目配置:确保上述Facet和依赖配置正确。如果JSP中使用了自定义的标签库(TLD文件),需要确保TLD文件在WEB-INF下,并且在web.xml或JSP头部通过<%@ taglib %>正确定义,IDEA才能识别。
  • 经验之谈:对于老项目,IDEA的“终极”解决方案是使用File->New->Project from Existing Sources,然后仔细选择每一步的配置,而不是直接打开文件夹。

坑点五:编码问题导致的乱码这是中文老项目的通病。源代码、JSP页面、数据库可能使用了不同的编码(GBK, UTF-8)。

  • 统一为UTF-8
    1. IDEA全局设置Settings->Editor->File Encodings,将Global EncodingProject EncodingDefault encoding for properties files全部设置为UTF-8。对于已存在的文件,选择Convert
    2. JSP页面:在每个JSP页面的头部,确保有<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
    3. Servlet过滤器:最佳实践是编写一个CharacterEncodingFilter,在web.xml中配置为第一个过滤器,统一设置requestresponse的编码为UTF-8。
    4. 数据库连接:在JDBC连接字符串中显式指定字符集,如jdbc:mysql://localhost:3306/teaching_db?useUnicode=true&characterEncoding=UTF-8

坑点六:JSP页面报错“file not found”热词中有“jsp file [/hotline.jsp] not found”。这通常是路径问题。

  • 排查
    1. 检查web.xml<welcome-file>配置或Servlet中转发/重定向的路径是否正确。路径是相对于Web应用根目录的。
    2. 在IDEA的Tomcat运行配置中,Deployment选项卡下,检查应用的Application context是什么。如果设置为/,那么/hotline.jsp就对应项目WebContent/hotline.jsp。如果设置为/teaching,那么访问地址应为http://localhost:8080/teaching/hotline.jsp
    3. 确认文件是否真的存在于WebContent目录下,注意大小写(Linux环境下区分大小写)。

4. 从“能跑”到“好看”:前端与用户体验的简易优化

原始的教学管理系统前端,往往就是最基础的HTML表格和表单,样式可能直接写在标签里,或者引用一个非常简单的CSS。从工程和审美角度,我们可以做一些最小成本的优化,让项目看起来更专业,也更利于理解前后端分离的雏形。

4.1 引入轻量级CSS框架:Bootstrap

完全重写CSS成本太高。最快捷的方式是引入Bootstrap 3或4版本。它是一个成熟的前端组件库,能快速让页面布局变得整齐、响应式。

  • 操作:从官网下载Bootstrap的CSS和JS文件,放入WebContent/static/cssWebContent/static/js目录。或者直接使用CDN链接,在<head>中引入。
  • 应用:将原来的<table>套上class=“table table-hover”,按钮套上class=“btn btn-primary”,表单控件套上class=“form-control”,整个页面容器用class=“container”包裹。立刻就能获得一个风格统一、间距合理的现代化界面。
  • 价值:这不仅提升了视觉效果,更重要的是让你实践了静态资源(CSS, JS, 图片)的组织和管理,理解<link><script>标签的使用。

4.2 用JSTL和EL表达式替换脚本片段

原始JSP中可能充斥着大量的<% ... %>Java脚本片段和<%= ... %>表达式,这极大地降低了页面的可读性和可维护性。

  • 目标:尽可能使用JSTL(JSP Standard Tag Library)和EL(Expression Language)来替代。
  • 示例对比
    <!-- 旧方式:脚本片段 --> <% List<Student> list = (List<Student>)request.getAttribute("studentList"); for(Student s : list) { %> <tr><td><%= s.getName() %></td></tr> <% } %> <!-- 新方式:JSTL + EL --> <%@ taglib prefix=“c” uri=“http://java.sun.com/jsp/jstl/core” %> <c:forEach var=“student” items=“${studentList}”> <tr><td>${student.name}</td></tr> </c:forEach>
  • 好处:JSTL+EL的写法更简洁、更安全(自动HTML转义)、更易于前端人员理解。这体现了关注点分离的思想,是迈向更清晰架构的一小步。

4.3 实现简单的表单验证与用户反馈

老项目往往缺乏客户端验证和友好的用户交互。

  • 客户端验证:可以在提交表单前,用JavaScript进行非空、格式(如邮箱、学号)等基础验证。即使为了教学简化,也至少应该在关键字段(如登录名、密码)上加上required属性。
  • 服务端反馈优化:Servlet处理完业务后,通常会将成功或失败信息放入requestsession。在JSP页面,不要只是简单地out.print(message)。可以用Bootstrap的Alert组件来优雅地展示:
    <c:if test=“${not empty message}”> <div class=“alert alert-success” role=“alert”>${message}</div> </c:if> <c:if test=“${not empty error}”> <div class=“alert alert-danger” role=“alert”>${error}</div> </c:if>
  • 体验提升:对于删除等危险操作,应该使用JavaScript的confirm()对话框进行二次确认,防止误操作。

5. 安全考量与代码审计视角

教学项目通常以功能实现为首要目标,安全性考虑不足。但从学习和实战角度,我们必须审视其中潜在的安全风险。网络热词中甚至提到了“jsp一句话后门”和“jsp文件上传绕过方式”,这从侧面说明了JSP时代安全问题的普遍性。

5.1 常见漏洞分析与加固

  1. SQL注入:这是此类项目最高发的漏洞。检查所有DAO层代码,是否使用Statement进行字符串拼接。

    • 危险代码String sql = “SELECT * FROM user WHERE name='” + username + “' AND password='” + password + “'”;
    • 修复方案必须使用PreparedStatement。它通过预编译和参数绑定,从根本上杜绝SQL注入。
    String sql = “SELECT * FROM user WHERE name=? AND password=?”; PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setString(1, username); pstmt.setString(2, password); ResultSet rs = pstmt.executeQuery();
  2. 会话固定与劫持:登录功能是否在验证成功后生成新的会话ID?HttpSession的管理是否安全?

    • 加固建议:用户登录成功后,调用request.getSession().invalidate();使旧会话失效,然后request.getSession(true);创建一个新会话。对于敏感操作(如修改密码、支付),可以增加二次验证(如密码、短信验证码)。
  3. 不安全的直接对象引用:是否通过URL参数直接传递数据库ID,且未校验权限?例如/deleteStudent?id=123,任何用户只要修改id值就能删除他人信息。

    • 修复方案:在Servlet中,执行操作前必须进行权限校验。确保当前登录用户(从session中获取)有权限操作目标数据(id=123的学生)。这需要业务逻辑的配合。
  4. 文件上传漏洞:如果系统有上传头像、提交作业的功能,风险极高。

    • 检查点
      • 是否校验了文件扩展名和MIME类型?禁止仅在前端校验,必须在服务端使用白名单机制。
      • 上传的文件是否存储在Web应用目录下?如果是,用户上传的JSP文件可能被直接执行(即“一句话后门”)。
      • 上传的文件名是否使用了原始文件名?这可能导致目录遍历(../../../etc/passwd)和覆盖系统文件。
    • 安全实践
      • 将上传文件存储在一个独立的、非Web应用直接访问的目录。
      • 使用随机生成的文件名(如UUID)保存文件,并将原始文件名和映射关系存入数据库。
      • 通过一个专门的Servlet或Controller来提供文件下载服务,在该服务中校验用户权限,并安全地读取文件流输出。
  5. 密码明文存储:这是教学项目的“经典”问题。数据库中密码字段经常是明文。

    • 必须纠正:即使只是课程设计,也应实践密码安全存储。使用如BCrypt、PBKDF2等加盐哈希算法对密码进行单向加密存储。在UserDaoaddUservalidateUser方法中实现。

5.2 代码审计实战:以登录功能为例

让我们模拟一次简单的代码审计,目标是最常见的登录Servlet。

// 假设一个存在问题的LoginServlet.doPost方法片段 String username = request.getParameter(“username”); String password = request.getParameter(“password”); String sql = “SELECT * FROM admin WHERE username='” + username + “' AND password='” + password + “'”; Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); if(rs.next()) { // 登录成功,将用户信息放入session request.getSession().setAttribute(“admin”, username); response.sendRedirect(“admin/index.jsp”); } else { // 登录失败 request.setAttribute(“error”, “用户名或密码错误”); request.getRequestDispatcher(“login.jsp”).forward(request, response); }
  • 漏洞1 (SQL注入):第3行,直接拼接字符串,攻击者输入admin' --作为用户名,即可绕过密码检查。
  • 漏洞2 (密码明文传输与存储):密码明文参与SQL查询,且数据库很可能也是明文存储。
  • 漏洞3 (错误信息过于详细):直接告诉用户“用户名或密码错误”,有助于攻击者枚举用户名(先确定存在哪些用户名)。
  • 漏洞4 (会话管理):登录成功后未创建新会话,存在会话固定风险。
  • 修复后的代码思路
    1. 使用PreparedStatement
    2. 查询时,只根据用户名取出存储在数据库中的密码哈希值。
    3. 使用BCrypt等库的checkpw方法,比对用户输入的密码(经过相同算法哈希后)与数据库存储的哈希值。
    4. 无论用户名是否存在或密码是否正确,都返回统一的模糊错误信息:“登录失败”。
    5. 登录成功后,使旧会话失效并创建新会话。

通过这样的审计和修复练习,你会对Web安全有最直观和深刻的认识,这是只看理论无法比拟的。

6. 论文部分的价值挖掘与项目重构思考

一个完整的毕业设计项目包通常包含“论文”。不要忽视这份文档,它往往是理解项目设计思路的钥匙。

6.1 如何从论文中提取有价值的信息

  1. 需求分析:论文中会详细描述系统的功能性需求(如学生管理、课程管理、成绩录入)和非功能性需求(如性能、安全性、易用性)。这帮助你理解每一个功能模块存在的意义。
  2. 系统设计:重点关注数据库设计(E-R图、表结构)系统架构图。这是项目的基石。理解表与表之间的关系(一对一、一对多、多对多),对于编写正确的SQL查询和业务逻辑至关重要。
  3. 核心模块详细设计:论文会对关键模块(如选课模块、成绩统计模块)的流程进行说明,有时会包含流程图或伪代码。这是理解复杂业务逻辑的捷径。
  4. 测试用例:虽然可能很简单,但其中的测试思路(如边界值测试、功能测试)值得学习。

6.2 基于现有项目的“现代化”重构思考

在完全理解了这个传统项目之后,我们可以思考如何用现代技术栈重构它。这不是必须的,但是一个极佳的思维训练。

  1. 技术栈升级

    • 后端:Spring Boot + Spring MVC + MyBatis-Plus。Spring Boot简化配置,Spring MVC提供更优雅的Controller层,MyBatis-Plus极大简化DAO层开发。
    • 前端:Vue.js / React + Element UI / Ant Design。实现彻底的前后端分离,后端仅提供RESTful API,前端负责所有渲染和交互。
    • 构建工具:Maven或Gradle,管理项目依赖和构建流程。
  2. 架构演进

    • 包结构:从按层分包(com.xxx.dao,com.xxx.service)演变为按功能模块分包(com.xxx.module.student,com.xxx.module.course),每个模块内包含自己的Controller, Service, Mapper, Entity。这更符合高内聚、低耦合的原则。
    • API设计:设计清晰的RESTful接口,如GET /api/students,POST /api/courses,PUT /api/grades/{id}。并使用Swagger生成API文档。
  3. 工程化改进

    • 连接池:使用HikariCP替代原始的JDBC DriverManager,提升数据库连接性能。
    • 日志:使用SLF4J + Logback替代System.out.println,实现分级、可配置的日志输出。
    • 异常处理:定义全局异常处理器,统一处理业务异常和系统异常,返回结构化的错误信息给前端。
    • 配置管理:将数据库连接信息、服务器端口等配置外置到application.yml文件中。

思考如何将老项目中的业务逻辑,逐块迁移到新的架构中,并解决遇到的技术差异(如JSP标签到Vue组件的转换,Servlet的forward到RESTfulJSON响应的转换),是一个能让你融会贯通Java Web开发全貌的绝佳练习。

回过头看,这个“JSP教学管理系统”远不止是一份作业或一个过时的项目。它是一个完整的、自包含的Web开发微缩景观。通过亲手配置、运行、调试、优化甚至重构它,你能够穿透现代框架的层层抽象,触摸到Web应用最本质的请求-响应循环、数据流转和状态管理。在技术飞速迭代的今天,这种对底层原理的深刻理解,是应对未来任何新框架、新范式变化时最宝贵的定力和底气。下次再遇到类似的“历史项目”,希望你能带着探索宝藏的心态,而不仅仅是完成任务的烦躁。

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

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

卡特彼勒1亿美元押注工业AI:真实场景落地与工程化实践

从卡特彼勒宣布未来五年投入 1 亿美元培训员工、把 AI 推向真实作业现场这件事来看&#xff0c;工业 AI 的落地逻辑已经变了&#xff1a;不是实验室里跑通一个 demo&#xff0c;而是要直接进矿山、进工地、进产线&#xff0c;在挖掘机、推土机、卡车和重型设备旁边解决实际问题…

作者头像 李华
网站建设 2026/9/2 13:07:12

算法竞赛必备:字符串哈希核心原理、实现陷阱与实战应用

上周在给一个刚接触算法竞赛的同学讲题时&#xff0c;他盯着一个字符串匹配的问题&#xff0c;反复调试了快一个小时&#xff0c;最后发现是输入字符串末尾有个不起眼的空格。他叹了口气说&#xff1a;“字符串题&#xff0c;感觉每个字符都在跟我作对。”这几乎是每个算法竞赛…

作者头像 李华
网站建设 2026/9/2 13:05:09

【单片机毕设案例分享】基于 STM32 的环境感知采集与蓝牙移动端监控平台设计 基于 STM32 的室内空气多指标监测与继电器驱动控制系统设计(010106)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于单片机&#xff0c;STM32单片机&#xff0c;51单片机&#xff0c;J…

作者头像 李华
网站建设 2026/9/3 16:35:50

单片机毕设项目:基于 STM32 的室内空气质量监测与多模式设备调控系统设计 基于 STM32 传感器组网的室内环境监测报警远程控制系统设计(010306)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华