Java Web入门必练:JDBC+Servlet+JSP实现部门增删改查系统

发布时间:2026/9/26 20:15:25

Java Web入门必练:JDBC+Servlet+JSP实现部门增删改查系统 学 Java 到第 14 天终于不再是照着教程敲语法 demo 了。这篇博文记录的是一套完整的“部门系统”案例开发过程核心功能就是部门的增删查改。选它当第一个完整案例是因为它足够小却能覆盖 Java Web 开发里最要命的一整条链路页面提交请求 → Servlet 接收参数 → Service 做业务判断 → DAO 访问数据库 → 再把结果返回页面。如果你也处在 Java 基础刚过完、想找一个能练手的闭环项目或者准备课程设计却不知道从哪下手这份 Day14 笔记应该能直接抄作业。我自己的进度是第 1~13 天过完了变量、流程控制、面向对象、集合、异常、IO还花了两天把 JDBC 的基础 API 摸了一遍用的是 MySQL 8 原生 JDBC从第 14 天开始进入 Web 层。技术栈是 JDBC Servlet JSP没有引入 Spring 那一套。正因为还没上框架原生方式反而把问题暴露得更彻底后面再换框架时你才会知道框架到底帮我们省了什么。1. 为什么拿“部门系统”当第一个完整案例1.1 案例选型它小到什么程度又大到什么程度很多人学完 Java 基础之后会面临同一个问题资料看了一堆真正动手时脑子里一片空白。我当时也这样。Day14 之前我试着写过图书管理、学生信息管理发现要么是表字段太多写着写着就去调样式了要么是业务太抽象根本理解不了为什么要分 Service 和 DAO 两层。部门系统刚好卡在一个很舒服的位置。部门这个对象只有几个核心属性部门编号、部门名称、部门描述、创建时间。增删查改的每一个功能都直白得不需要解释但背后的工程问题一个都不少表单怎么提交、参数怎么校验、数据库连接什么时候关闭、列表查询结果为空怎么办、删除一个被引用的部门会出什么问题。它小到一天能跑完大到足够把 Java Web 的分层思想完整串一遍。1.2 前后 13 天的知识在这里完成第一次合流我整理了一下这套案例到底用到了哪些前 13 天的内容列出来之后连我自己都吓一跳面向对象Department 实体类封装属性私有、提供 getter/setter集合框架查询结果用ListDepartment承载循环渲染到表格异常处理SQLException 的上抛与 finally 中关闭资源JDBCConnection、PreparedStatement、ResultSet 的常规使用流程控制根据 action 参数分发到不同业务方法。更关键的是它第一次强迫你关注“一个请求从浏览器到数据库再回来”这件事。以前写 JDBC 是在 main 方法里打印结果一旦放进 Web 容器你会发现控制台输出的时代结束了数据的去处变成了 JSP 页面上的表格。这个转变是第 14 天最重要的收获。1.3 技术栈为什么不直接上 Spring Boot我在网上搜了很多案例教程清一色用 Spring Boot 一键生成 CRUD。对初学者来说这其实是有毒的。一键生成之后你只知道点“运行”按钮网页就出来了但数据是怎么流过去的、请求是怎么被路由的、SQL 是怎么拼接的全部被框架吞掉了。所以我坚持用 JDBC Servlet JSP 裸写一遍。目的很简单让每一条数据流肉眼可见。Servlet 里你亲眼看着request.getParameter()取出字符串DAO 里你亲手把字符串填进PreparedStatementJSP 上用 EL 表达式把数据渲染出来。等以后接触 MyBatis 和 Spring Data JPA你会觉得那些框架的底层设计全是顺理成章的而不是一片黑盒。2. 搭工程和设计表动手前先想清楚这三件事2.1 环境清单和项目目录长什么样动手前先确认环境别到写代码时才发现问题JDK 11Tomcat 9MySQL 8.0数据库名company_dbIDE 用的 IDEA直接配置本地 Tomcat 运行Maven 管理依赖项目是 war 包结构。如果你是手动导入 jar 包的流程思路完全一样区别只是把依赖文件放进WEB-INF/lib而已。Maven 的pom.xml里我引入了三个依赖Servlet APIprovided 作用域、MySQL 驱动、JSTL 标签库。后三个用不到 EL 也许可以不引但我为了给列表页做遍历用到了 JSTL 的c:forEach所以提前补上了。项目包结构我按照 Web 项目的经典分层来建src/main/java ├── com.demo.entity -- Department 实体类 ├── com.demo.dao -- DepartmentDao 数据访问类 ├── com.demo.service -- DepartmentService 业务逻辑类 ├── com.demo.servlet -- DepartmentServlet 控制器 └── com.demo.util -- DBUtil 数据库连接工具 src/main/webapp ├── department │ ├── list.jsp -- 列表页 │ ├── add.jsp -- 新增页 │ └── edit.jsp -- 修改页 └── WEB-INF/web.xml包结构划分的意义不在好看而在隔离变化。DAO 只管数据库读写Service 只管业务规则Servlet 只管接收参数和转向页面。后面你哪怕把 JDBC 换成 MyBatis前端页面不用动一行这就是分层的价值。2.2 department 表设计的三个关键字唯一、默认、可空表结构我第一版建得很偷懒只有 id 和 name后来加搜索功能时发现没有描述字段搜索不知道该匹配什么只好回头重建表。第二版我稳了一点建表语句如下CREATE TABLE department ( id INT NOT NULL AUTO_INCREMENT COMMENT 部门编号, name VARCHAR(50) NOT NULL COMMENT 部门名称, description VARCHAR(255) DEFAULT NULL COMMENT 部门职责描述, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;三个细节值得说。第一个是 name 加了唯一约束这样重名部门在数据库层面就被拦住了比在 Java 代码里先查再插更可靠。并发场景下“先查后插”会有竞态问题唯一索引才是最终防线。第二个是 create_time 用了DEFAULT CURRENT_TIMESTAMP插入的时候完全不用管它数据库自动写当前时间。第三个是 description 允许为空因为不是所有部门都需要填职责描述强制 NOT NULL 反而给用户制造麻烦。2.3 实体类与数据库连接工具的最小骨架实体类没什么技术含量但字段类型要和数据库对齐。MySQL 的DATETIME对应 Java 的java.util.DateTINYINT类型很容易被顺手写成Integer在这里还没遇到后面做员工状态字段时要小心。public class Department { private Integer id; private String name; private String description; private Date createTime; public Department() {} public Department(String name, String description) { this.name name; this.description description; } // getter 和 setter 省略IDE 自动生成 }DBUtil 工具类是整个项目的地基。我最初写的时候把驱动注册放到每次获取连接里结果每调用一次就 Class.forName 一次虽然影响不大但看着别扭。后来改成了静态代码块类加载时只注册一次public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/company_db ?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingUTF-8; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(MySQL驱动加载失败请检查依赖); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }注意这里的 URL 参数serverTimezoneAsia/Shanghai解决 MySQL 8 的时区警告characterEncodingUTF-8解决下文中文字符乱码。这两个参数不写后面一定会回来补课。3. 查询和删除两个越简单越容易漏的功能3.1 列表查询和关键字搜索SQL 别这么拼查询是所有页面的入口。列表页一打开就要把全部部门查出来然后渲染成表格。DAO 里最基础的findAll方法public ListDepartment findAll() throws SQLException { String sql SELECT id, name, description, create_time FROM department; ListDepartment list new ArrayList(); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Department dept new Department(); dept.setId(rs.getInt(id)); dept.setName(rs.getString(name)); dept.setDescription(rs.getString(description)); dept.setCreateTime(rs.getDate(create_time)); list.add(dept); } } return list; }这里我要特意强调 try-with-resources 的写法。第 13 天之前我习惯用 finally 手动关闭 ResultSet、Statement、Connection代码又臭又长。JDK 7 之后 try-with-resources 会自动关闭实现了 AutoCloseable 的资源而且关闭顺序是反着的ResultSet 先关、Connection 最后关。初学阶段就该养成这个习惯不然写数据库代码一半时间都在处理资源泄漏。关键字搜索是列表查询的自然延伸。我在列表页上面加了一个搜索框提交一个keyword参数过来。SQL 的写法是最容易翻车的地方// 错误写法 String sql SELECT * FROM department WHERE name LIKE % keyword %; // 正确写法 String sql SELECT id, name, description, create_time FROM department WHERE name LIKE ?; ps.setString(1, % keyword %);错的那种写法有两个问题一是字符串拼接容易引发 SQL 注入二是如果 keyword 里有单引号整个 SQL 直接语法错误。用PreparedStatement占位符然后传%关键字%既防注入又干净。我一开始甚至想过写LIKE %?%执行后毫无悬念地报错占位符不能嵌在字符串字面量里。想实现前后模糊匹配要么用concat(%, ?, %)要么在 Java 测把百分号拼进参数里我选了后者可读性更好。Servlet 层通过 action 参数分发列表和搜索共用一套方法WebServlet(/department) public class DepartmentServlet extends HttpServlet { private DepartmentService service new DepartmentService(); Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action req.getParameter(action); if (list.equals(action) || action null) { listWithSearch(req, resp); } else if (delete.equals(action)) { delete(req, resp); } else if (edit.equals(action)) { showEditPage(req, resp); } } private void listWithSearch(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String keyword req.getParameter(keyword); ListDepartment list service.findDepartments(keyword); req.setAttribute(deptList, list); req.getRequestDispatcher(/department/list.jsp).forward(req, resp); } }action null时也默认走列表这样直接访问/department就能看到列表页减少一次手输参数的麻烦。3.2 删除单个部门外键约束第一次教做人删除功能的代码很短private void delete(HttpServletRequest req, HttpServletResponse resp) throws IOException { int id Integer.parseInt(req.getParameter(id)); boolean success service.deleteDepartment(id); if (success) { resp.sendRedirect(req.getContextPath() /department?actionlist); } else { resp.sendRedirect(req.getContextPath() /department?actionlisterror1); } }真正有戏的是 Service 层。删除一个部门之前必须考虑“这个部门下面还有员工”。我为了验证这个问题专门建了一张employee表里面dept_id外键指向department.id。然后试着删除一个部门数据库直接报错Cannot delete or update a parent row: a foreign key constraint fails这个报错是好事它说明数据完整性被保护住了。但直接把异常抛给用户不友好。我的处理方式是在 Service 里显式检查public boolean deleteDepartment(int id) { try (Connection conn DBUtil.getConnection()) { // 先查部门下是否有员工 String checkSql SELECT COUNT(*) FROM employee WHERE dept_id ?; try (PreparedStatement ps conn.prepareStatement(checkSql)) { ps.setInt(1, id); try (ResultSet rs ps.executeQuery()) { rs.next(); if (rs.getInt(1) 0) { return false; // 有关联员工删除失败 } } } // 再执行删除 String deleteSql DELETE FROM department WHERE id ?; try (PreparedStatement ps conn.prepareStatement(deleteSql)) { ps.setInt(1, id); return ps.executeUpdate() 0; } } catch (SQLException e) { throw new RuntimeException(删除部门失败, e); } }列表页上的删除按钮我加了一个onsubmit确认问一句“确定删除该部门吗”。这个交互虽然简单但能挡住很多手滑误删。删除成功后必须用sendRedirect重定向回列表页不能用forward原因后面第 5 章专门讲。3.3 两个容易踩的坑空集合与重复提交第一个坑是查询结果为空。有人喜欢在 DAO 里返回null然后在 JSP 里判断if (null ! deptList)。这个习惯非常危险因为你无法保证 Service 层的每一处都对 null 做了判空一个疏忽就是 NullPointerException。我在自己的项目里定了条规矩查询集合永远返回空集合而不是 null。ListDepartment list new ArrayList(); // 初始就是空集合 return list;这样 JSP 页面用c:forEach遍历空集合时会自动什么都不显示不用单独写判空逻辑。第二个坑是删除和新增之后的重复提交。我刚写完删除功能时用的是forward转发到列表页。结果发现删除一次之后按一下 F5浏览器提示“是否重新提交表单”确认之后又删了一次。原因是转发只在服务器内部跳转浏览器地址栏还是原来的删除请求地址。改成重定向之后浏览器先收到一个 302然后重新发起一次 GET 请求到列表页地址栏变成/department?actionlist刷新就只会重新查询不会再次删除。4. 新增和修改把表单校验写进 Service 层4.1 新增部门的完整数据流与自增主键回显新增功能的页面是add.jsp表单里有两个字段部门名称和部门描述。提交之后走doPost我照样通过 action 分发Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action req.getParameter(action); if (add.equals(action)) { add(req, resp); } else if (update.equals(action)) { update(req, resp); } }add 方法接收参数、调用 Service、重定向private void add(HttpServletRequest req, HttpServletResponse resp) throws IOException { String name req.getParameter(name); String description req.getParameter(description); boolean success service.addDepartment(name, description); if (success) { resp.sendRedirect(req.getContextPath() /department?actionlist); } else { resp.sendRedirect(req.getContextPath() /department?actionadderror1); } }Service 层负责最核心的插入逻辑。这里有一个知识点很多人会忽略插入之后要拿到数据库自动生成的自增主键。业务场景很常见比如新增部门成功后跳转到这个部门的编辑页就需要先有这个 id 才能回显。public boolean addDepartment(String name, String description) { if (name null || name.trim().isEmpty() || name.length() 50) { return false; } String sql INSERT INTO department(name, description) VALUES(?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { ps.setString(1, name.trim()); ps.setString(2, description); ps.executeUpdate(); try (ResultSet rs ps.getGeneratedKeys()) { if (rs.next()) { int generatedId rs.getInt(1); System.out.println(新生成的部门ID generatedId); } } return true; } catch (SQLException e) { if (e instanceof SQLIntegrityConstraintViolationException) { return false; // 部门重名唯一约束触发 } throw new RuntimeException(新增部门失败, e); } }注意prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)这个重载。如果不传第二个参数执行完executeUpdate后getGeneratedKeys()很可能拿不到自增 id。这是 MySQL 驱动的一个实际行为我当时查了很久才发现是这个细节。4.2 修改部门的三步走查详情、回显、提交更新修改功能比新增多了一个步骤回显。用户点“编辑”时需要先把这条部门数据查出来填到表单里用户改完再提交更新。private void showEditPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int id Integer.parseInt(req.getParameter(id)); Department dept service.findDepartmentById(id); req.setAttribute(dept, dept); req.getRequestDispatcher(/department/edit.jsp).forward(req, resp); }edit.jsp 的表单和 add.jsp 几乎一样区别只有两点第一form 里多了个隐藏域id第二输入框的 value 从dept对象里取。EL 表达式写起来很爽input typehidden nameid value${dept.id} input typetext namename value${dept.name} required textarea namedescription${dept.description}/textarea这里有个小坑${dept.description}如果数据库里是 null页面上会显示字符串null而不是空白。解决办法是回显时在 Service 里做一次 null 到空串的转换或者直接用 JSTL 的c:out加默认值。我嫌麻烦直接在实体类的 getter 里兜底public String getDescription() { return description null ? : description; }修改的 update 方法就是 SQL 的 UPDATE 语句把 name 和 description 按 id 更新。执行完同样重定向回列表页。核心点在于修改不涉及主键别把 id 写在 SET 子句里Where 条件只写 id。有的初学者把 SQL 写成UPDATE department SET name?, id? WHERE id?数据错乱得很隐蔽。4.3 前后端双重校验别把希望全押在 required 上很多人以为 HTML 表单里写了required属性后端就能高枕无忧了。这完全是错觉。required只是浏览器层面的提示用户可以绕过前端直接构造请求。所以后端必须有一层真正的校验。我把校验逻辑统一放在 Service 层新增和修改复用同一个方法private String validate(String name, String description) { if (name null || name.trim().isEmpty()) { return 部门名称不能为空; } if (name.trim().length() 50) { return 部门名称长度不能超过50; } if (description ! null description.length() 255) { return 部门描述长度不能超过255; } return null; }校验不通过时直接把错误消息返回给 ServletServlet 把消息放到 request 域里转发回原表单页面并在页面上显示。这套流程比返回一个笼统的 false 要友好得多用户能立刻知道错在哪。可能有人会问为什么不在 Servlet 里写校验因为校验属于业务规则放在 Servlet 会让你以后复用很痛苦。假设将来出现一个批量导入部门的接口如果校验逻辑只在表单提交的 Servlet 里批量导入就得重写一遍。放在 Service 层所有入口共用一套规则这才是分层设计的意义。5. 乱码和运行时错误两段高价值排错记录5.1 中文变问号从 JSP 到 MySQL 的四层排查这是整套案例里我花时间最长的一个 bug。新增部门时填“技术部”点击提交到数据库里看变成“????”。问题出在四个环节任何一个不对中文都会翻车。第一层是 JSP 页面本身的编码。新建的 JSP 文件顶部必须有% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %pageEncoding告诉 JSP 引擎用 UTF-8 读这个文件contentType告诉浏览器响应用 UTF-8 显示。第二层是请求编码。POST 请求的表单数据在请求体里Servlet 读取时必须先设定编码而且必须在第一次调用getParameter之前。我一开始写在doPost末尾完全无效。req.setCharacterEncoding(UTF-8);如果漏了这行浏览器用 UTF-8 编码提交的中文到了 Servlet 里会被当成 ISO-8859-1 解码妥妥乱码。第三层是 JDBC 连接 MySQL 时的编码。这一步就是前面 2.3 节 DBUtil 里 URL 上的characterEncodingUTF-8参数。它告诉 MySQL 驱动客户端发过来的字符串是 UTF-8 编码的请按 UTF-8 处理。第四层是表和数据库的字符集。我建表时用的CHARSETutf8mb4可以放心存中文。如果建库时默认字符集是 latin1那前面三层全对了也白搭。排查顺序建议从数据库往浏览器倒着查先看表结构字符集再看 JDBC URL再看请求编码最后看 JSP 头。实际踩坑时往往是同时改好几处才恢复正常的所以最好一次性把四层全部检查到位再测试。5.2 NullPointerException多半是参数名叫错了Day14 里我遇到的最多的运行时错误就是 NullPointerException。排查下来有一个规律绝大多数 NPE 的前一行都是request.getParameter的返回值直接调了方法。举个例子表单里input namedeptNameServlet 里写成String name req.getParameter(deptName); if (name.trim().isEmpty()) { ... } // NPEgetParameter拿不到参数时返回 null然后对 null 调用.trim()必炸。而且这个 bug 很隐蔽因为你肉眼扫代码看不出问题只有跑起来在控制台看到异常栈才能顺着at com.demo.servlet.DepartmentServlet.add()定位到具体哪一行。我的解决习惯是写一个安全取值方法所有 Servlet 入口统一走它private String getParam(HttpServletRequest req, String name) { String value req.getParameter(name); return value null ? : value.trim(); }这样至少不会因为一个 null 就把整个请求打崩。还有一类 NPE 来自 rs 取不到数据。比如findDepartmentById方法里如果查不到结果rs.next()返回 false你再去rs.getInt(id)就会抛SQLException不是 NPE。但如果你把查询结果直接赋给实体类代码又不判空在 Servlet 里传dept.getId()就会 NPE。所以查询单个对象时查不到就返回 null 没问题但使用方必须判空查多条的就按 3.3 节的习惯返回空集合。5.3 刷新就重复提交转发和重定向到底差在哪这个坑其实在 3.2 节已经提过但我还想单独拎出来说因为它太典型了。用forward转发做新增成功跳转会有什么后果req.getRequestDispatcher(/department/list.jsp).forward(req, resp);转发是服务器内部动作浏览器地址栏还停留在/department?actionadd。用户看到新增成功想刷新一下列表浏览器重新提交上一次的 POST 请求结果又插了一条一模一样的部门记录而且因为 name 有唯一约束这次刷新会触发重复键异常。重定向写的是resp.sendRedirect(req.getContextPath() /department?actionlist);浏览器收到 302 响应后会主动发起一个新的 GET 请求地址栏变成列表中。/GET 请求天然是安全幂等的刷新一万次只是重新查一次列表不会产生副作用。这个原则记住一句话凡是会修改数据的请求处理完一定用重定向不要用转发。此外还有一个很小的性能细节重定向比转发多一次网络往返但这个代价换来的正确性完全值得。6. 从部门系统到员工系统下一步扩展建议这一整套部门系统跑通之后第 15 天的计划就非常清晰了直接套用同样的分层结构去做员工系统。员工表的字段更多卡片更复杂还需要在设计部门删除时处理“部门下有员工”的联动。我的具体建议是往这几个方向扩展第一列表页加上分页。LIMIT ? OFFSET ?两行 SQL 就能实现还要配合一个SELECT COUNT(*)算总页数。这个练习能帮你理解为什么前端分页和后端分页对大数据量来说完全是两个概念。第二删除改成批量删除。用 checkbox 勾选多个部门提交时把 id 拼成逗号分隔的字符串后端拆开后用动态拼接生成 IN 占位符。这个练的是字符串处理和 SQL 动态拼接的功力。第三把查询条件从“部门名称模糊搜索”扩展到“按创建时间范围查询”。你会发现写一条带日期参数的 SQL 也没多难但日期格式的前后端传递会小小折磨你一下早点踩坑早点长记性。我做完这套部门 CRUD 之后最大的变化是不再害怕看完整代码了。以前点开一个项目总觉得眼花缭乱现在哪怕是大项目的 Controller-Dao 分层我也能顺着请求路径逐个摸清。这就是第 14 天这一整套案例开发给我的最大回报。最后再分享一个习惯每次写完一个功能我会在浏览器里把“正常操作、空输入、超长输入、连续点击提交”这四类情况各测一遍。这套部门系统后来能顺利扩展成员工系统而没有返工靠的就是前期这些看起来有点笨的测试。如果你也在学 Java 的道路上走到了类似阶段建议别急着开新章节先把手头的这套 CRUD 改到滚瓜烂熟你会发现后面很多 Web 框架的引入都变得顺理成章了。
延伸阅读

更多相关文章

2026/9/26 20:15:25

SpringBoot+Vue书城阅读器:从架构设计到部署的全栈实践指南

最近花了两周时间把一个书城阅读器系统从零到部署完整跑通了一遍,技术栈用的就是现在求职市场上最常见的SpringBootVue全栈组合。这个系统说白了就是一个在线的电子书城加阅读器:用户可以注册登录、浏览书城里的书籍、加入书架、搜索图书,点开…

2026/9/26 20:15:25

开源项目避坑指南:从卖家秀到买家秀的实战教训

开源项目,GitHub上随便一搜,满屏的star、漂亮的徽章、花里胡哨的演示动图,再配上一句“Powerful and easy to use”,简直让人以为全世界最好的代码都是摆在你家门口的免费午餐。但凡在嵌入式、前端、算法这些行当里真正泡过几年的…

2026/9/26 20:10:25

Netty内存池核心设计:从ByteBuf分配到Arena/Chunk/Subpage源码解析

做Java服务端开发的人,应该都有过被NIO ByteBuffer折磨的经历:要手动管理position、limit,用完还要自己释放DirectBuffer,稍微粗心一点就内存泄漏。后来Netty提供了ByteBuf,配合引用计数和内存池,才把这些麻…

2026/9/26 21:20:30

从数据集到部署:机器人手语识别全流程落地指南

简介:这是一套面向深度学习与计算机视觉任务的手语图片数据集,围绕手语字母识别场景构建,适合算法工程师、机器人开发者、图像分类学习者以及高校相关课程实验使用,用于模型训练、算法验证与效果对比。资源以zip格式打包&#xff…

2026/9/26 21:20:30

训练机器人理解手语数据集:从关键点到机械臂动作映射

简介:这份数据集面向深度学习、计算机视觉方向的研究者与入门学习者,以手语字母图像为媒介,为训练机器人理解手语提供标注清晰的训练素材,适用于图像分类、手势识别等模型的练手与实验。包内共2000个文件,其中1998张PN…

2026/9/26 21:20:30

LLM应用安全护栏实战:从输入过滤到密钥治理的完整落地

最近我把手头一个内部知识库问答应用从Demo阶段推上生产,最揪心的反而不是生成效果,而是安全。模型答错一句可以改prompt,可要是用户直接套出系统提示词、把API密钥带进上下文的日志里、或者绕过权限拿到不该看的数据,那就不再是“…

2026/9/26 21:20:30

托管CRM与自建系统如何选?从技术形态到成本协作的全面解析

先说个有意思的事。前几天帮一位做外贸的朋友选客户管理系统,他把我拉到电脑前,搜索记录里赫然躺着几行字——“免费crm与私人网站的区别在哪百度知道”“永久在线的crm网站”“飞鱼crm怎么邀请员工”。他有点不好意思,说搜了好几轮还是没整明…

2026/9/26 21:15:29

银河麒麟V10重装CUPS与驱动:重建打印信任链实战指南

1. 项目概述:为什么重装CUPS和驱动在银河麒麟V10上不是“修电脑”,而是重建打印信任链在银河麒麟V10桌面版的实际运维中,我见过太多人把“打印机不工作”当成一个孤立故障来处理——重启服务、重插USB线、换根数据线、甚至重装系统。但真正卡…

2026/9/25 21:00:17

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/25 20:59:52

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/26 0:04:28

画质修复APP怎么选?Wink影像修复能力与产品实力解析

现如今手机拍摄场景愈发丰富,演唱会直拍、漫展记录、老视频翻新、日常vlog录制,都会遇到画面模糊、噪点多、曝光失衡等问题,不少用户在挑选工具时比较在意一款画质修复APP能够兼顾修复效果与自然质感。Wink作为美图公司推出的全球化AI影像增强…

2026/9/26 0:04:28

超低能耗建筑K值要求能否满足?浙东铝业建筑型材解析

核心摘要浙东铝业的超低能耗系统门窗产品,资料显示保温性能可达 K≤1.4W/(㎡K),能够对应上海地区超低能耗住宅对门窗保温性能的应用需求。判断建筑是否满足超低能耗要求,不能只看铝型材本身,还需要结合玻璃、隔热条、密封系统、开…

2026/9/25 20:55:38

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/26 19:58:38

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/25 18:34:56

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑