ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

JSP农产品销售系统毕设实战:从环境配置到三层架构落地

2026/10/1 17:24:52 拓冰建站 浏览量
JSP农产品销售系统毕设实战:从环境配置到三层架构落地 简介本资源是一套完整的Java Web毕业设计项目——基于JSP的农产品销售管理系统面向计算机专业本科生及Java初学者解决农业信息化场景下商品管理、订单流转与数据可视化等典型业务需求。压缩包共含项目报告、答辩PPT、可运行源代码、MySQL数据库文件、系统功能截图及部署教学视频等核心内容文件类型涵盖Java Servlet/JSP源码、SQL建表脚本、HTML/CSS/JS前端页面、PDF文档与MP4实操视频整体大小95.65MB结构清晰、开箱即用。已有201人学习下载适合用于课程设计参考、毕设选题复现或Java Web全栈开发能力训练。读者可直接部署到Tomcat环境通过源码理解MVC分层实现借助PPT掌握答辩逻辑结合部署视频快速完成环境搭建与功能验证数据库脚本与截图也便于对照调试与效果还原。1. 为什么还在用 JSP 做农产品销售系统——不是怀旧是毕业设计场景下的「稳态选择」你点开这个压缩包看到“JSP 项目报告 答辩PPT 源代码 数据库 截图 部署视频”第一反应可能是都2024年了怎么还有人用 JSP但如果你正卡在毕设开题、导师只认“Java Web 三层架构”、实验室服务器只装了 Tomcat 8.5、答辩现场要现场演示、导出 WAR 包必须能双击启动——那这个 ZIP 就不是过时而是精准匹配。这不是企业级电商系统而是一个可闭环验证的工程最小实例用户登录 → 浏览农产品列表带图片价格库存→ 加入购物车 → 提交订单 → 管理员后台审核发货。所有功能都在一个 WAR 包里跑通数据库用 MySQL 5.7前端不依赖 Vue/React连 jQuery 都只用到 v1.12.4兼容 IE8部署只需复制 WAR 到webapps目录刷新浏览器就能进首页。它解决的不是高并发或微服务治理而是“如何让一个没写过 Java Web 的本科生在三周内交出一份能讲清楚 MVC 分层、能连上数据库、能被老师当场打开、能截图放进 PPT 的完整系统”。适合三类人大四学生正在赶毕设 deadline高职院校教师需要一套可拆解教学案例中小农业合作社想快速搭个内部进销存原型别误会真上线还得重构。它不炫技但每行代码都有注释每个 SQL 都带字段说明每个 JSP 页面顶部都写着%-- 本页用途商品列表展示调用 ProductDAO.findAll() --%。接下来我们就从零开始把这份 ZIP 里的“可运行性”真正抠出来——不是解压就完事而是搞懂为什么这么写、哪里容易卡住、怎么改才不翻车。2. 从 ZIP 解压到 Tomcat 启动五步走通本地环境链路这个 ZIP 的价值不在“新”而在“全链路可复现”。它把毕业设计最耗时间的环境适配环节全部固化JDK 版本、Tomcat 配置、MySQL 字符集、甚至浏览器兼容模式都隐含在代码结构里。下面这五步是我带过 17 届毕设学生后总结出的最低失败率路径跳过任意一步后面 90% 的报错都源于此。2.1 环境版本锁死为什么必须用 JDK 1.8 Tomcat 8.5项目源码中web.xml声明的是 Servlet 3.1pom.xml如果有 Maven或lib下的servlet-api.jar版本为 3.1.0这直接锁死了容器版本。Tomcat 9 默认启用 HTTP/2 和更严格的 MIME 类型校验会导致 JSP 中jsp:include pageheader.jsp/报org.apache.jasper.JasperException: /index.jsp (line 12, col 0) jsp:include is not allowed in this context—— 这不是代码错是容器不认语法糖。提示不要用 IntelliJ IDEA 自带的 Tomcat 插件一键配置。它默认下载最新版必须手动指定解压路径。去 archive.apache.org 下载apache-tomcat-8.5.99.zip8.5.x 最终版解压后记下绝对路径例如D:\tools\tomcat85。JDK 必须是 1.8u202 及以上避免java.lang.UnsupportedClassVersionError但不能是 JDK 11。因为项目WEB-INF/lib下的mysql-connector-java-5.1.47.jar是 JDBC 4.0 驱动与 JDK 11 的模块化系统冲突会抛java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter。# 验证 JDK 版本Windows java -version # 输出必须是 # java version 1.8.0_381 # Java(TM) SE Runtime Environment (build 1.8.0_381-b09) # Java HotSpot(TM) 64-Bit Server VM (build 25.381-b09, mixed mode)2.2 数据库初始化字符集、引擎、初始数据三件套解压 ZIP 后找到database/目录里面通常有agri_sales.sql或类似命名的 SQL 文件。别急着source先看前三行CREATE DATABASE IF NOT EXISTS agri_sales CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE agri_sales; SET NAMES utf8mb4;注意是utf8mb4不是utf8。MySQL 的utf8实际只支持 3 字节 UTF-8不支持 emoji 和部分生僻汉字而农产品名称如“䅟子”“䅟草”“䅟属植物”含四字节 Unicode用utf8会导致插入乱码或截断。COLLATE utf8mb4_unicode_ci保证中文排序正确比如“苹果”排在“香蕉”前。执行前确认 MySQL 服务已启动并用 root 用户登录-- 检查全局字符集 SHOW VARIABLES LIKE character_set%; SHOW VARIABLES LIKE collation%; -- 正确输出应包含 -- character_set_server | utf8mb4 -- collation_server | utf8mb4_unicode_ci如果不对需修改 MySQL 配置文件my.iniWindows或my.cnfLinux[mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci [client] default-character-set utf8mb4重启 MySQL 后再执行 SQL。初始数据里admin表的密码通常是明文123456或admin但UserDAO.java中密码校验逻辑是if(123456.equals(inputPwd))—— 这是教学简化实际部署前必须改成 BCrypt 加密我们后面章节细说。2.3 源码导入 IDEA绕过 Maven 陷阱直连传统 Web 工程结构ZIP 里大概率没有pom.xml而是标准的src/WebContent/目录结构老式 Eclipse Dynamic Web Project 格式。IDEA 导入时千万别选 “Maven project”否则会生成空pom.xml并报Cannot resolve symbol javax.servlet。正确操作路径IDEA → File → New → Project from Existing Sources选择解压后的根目录 → Next → 选 “Create project from existing sources”在 “Project SDK” 下拉框选 JDK 1.8 → Next → Finish右键项目根目录 → Add Framework Support → 勾选 “Web Application” → Version 3.1 → OK此时 IDEA 会自动生成web.xml路径映射。关键一步手动设置 Tomcat ArtifactsFile → Project Structure → Artifacts → → Web Application: Archive → 选中你的项目名 → OK在 Output Layout 标签页确认WEB-INF/lib/下已包含mysql-connector-java-5.1.47.jar、jstl-1.2.jar、standard-1.1.2.jarJSTL 标签库必需点击 “” → “Extracted Directory” → 选WebContent/目录 → 确保index.jsp在根路径注意jstl-1.2.jar和standard-1.1.2.jar必须成对出现缺一不可。只放jstl会报org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved。2.4 Tomcat 配置三要素端口、Context Path、JVM 参数在 IDEA 中配置 Tomcat Run ConfigurationServer tab → Application server: 选你解压的tomcat85路径Deployment tab → → Artifact → 选你刚建的xxx:war exploded关键Application context 必须填/agri或/不能留空否则访问http://localhost:8080/会 404因为项目默认上下文是/agri见web.xml中display-nameagri_sales/display-name的约定JVM Options 建议加-Dfile.encodingUTF-8 -Xms512m -Xmx1024m -XX:PermSize256m -XX:MaxPermSize512m-XX:MaxPermSize是 JDK 1.8 专属参数JDK 9 改用 Metaspace不加可能导致 JSP 编译时java.lang.OutOfMemoryError: PermGen space。2.5 首次启动验证看日志不看浏览器点击 IDEA 的绿色三角形启动 Tomcat 后不要立刻切到浏览器。先盯紧 IDEA 底部的Run窗口等出现这三行才安全INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [XXXX] milliseconds INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina] INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/8.5.99]然后检查tomcat85/logs/catalina.outLinux或catalina.yyyy-mm-dd.logWindows搜索INFO: Server startup in。如果看到SEVERE: Error listenerStart或Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver说明mysql-connector-java-5.1.47.jar没进WEB-INF/lib回退到 2.3 节重做。最后浏览器访问http://localhost:8080/agri/注意末尾斜杠。如果看到农产品首页且右上角显示“欢迎游客”说明基础链路通了。此时按 F12 打开开发者工具Network 标签页刷新确认index.jsp的 Status 是 200Response Headers 里有Content-Type:text/html;charsetUTF-8—— 字符集正确中文不会乱码。3. 代码层拆解JSP Servlet DAO 三层如何咬合这个 ZIP 的核心价值在于它用最朴素的方式展示了 Java Web 的经典分层。没有 Spring Boot 的自动装配没有 MyBatis 的 XML 映射所有逻辑都暴露在眼皮底下。我们以“用户登录”为例从页面输入到数据库查询逐层剥开。3.1 JSP 层不只是 HTML是带逻辑的视图模板打开WebContent/login.jsp你会看到这样的结构% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8% % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % !DOCTYPE html html head meta charsetUTF-8 title农产品销售系统 - 登录/title /head body !-- 表单提交到 LoginServlet -- form actionLoginServlet methodpost input typetext nameusername placeholder用户名 required input typepassword namepassword placeholder密码 required button typesubmit登录/button /form !-- 错误提示从 request.getAttribute(error) 取值 -- c:if test${not empty error} div stylecolor:red;${error}/div /c:if /body /html关键点% taglib ... %引入 JSTL让c:if这类标签可用比% if(...) { %更易读actionLoginServlet是相对路径由web.xml中的servlet-mapping解析${error}是 EL 表达式取request.setAttribute(error, 用户名或密码错误)的值不是 JavaScript所以不能写onclickalert(${error});玄学经验JSP 中 EL 表达式${}里的变量名必须和request.setAttribute(key, value)的key完全一致大小写敏感。曾有学生把setAttribute(errorMsg, ...)写成setAttribute(error, ...)页面死活不显示提示查了两小时才发现是 key 名拼错。3.2 Servlet 层控制器的唯一职责是流转不是处理业务src/com/controller/LoginServlet.java典型代码public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取表单参数 String username request.getParameter(username); String password request.getParameter(password); // 2. 调用 DAO 查询用户 UserDAO userDAO new UserDAO(); User user userDAO.findByUsername(username); // 3. 业务判断密码是否匹配此处为明文对比仅教学 if (user ! null password.equals(user.getPassword())) { // 登录成功存入 session重定向到首页 request.getSession().setAttribute(currentUser, user); response.sendRedirect(index.jsp); } else { // 登录失败设置错误信息转发回登录页 request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } } }这里藏着三个必须理解的点doPost()处理表单提交doGet()一般为空或重定向到login.jsp防止 URL 直接访问触发空指针response.sendRedirect(index.jsp)是客户端重定向URL 地址栏会变成/agri/index.jsp而request.getRequestDispatcher(...).forward()是服务器端转发地址栏不变且request对象中的属性如error能传递过去request.getSession().setAttribute(currentUser, user)将用户对象存入 Session后续所有页面都能用${sessionScope.currentUser.username}取值 —— 这是实现“登录态”的底层机制比 Cookie 更安全数据存在服务端。3.3 DAO 层JDBC 模板的硬编码实践src/com/dao/UserDAO.java中的findByUsername()方法public User findByUsername(String username) { String sql SELECT id, username, password, role FROM user WHERE username ?; User user null; Connection conn null; PreparedStatement pstmt null; ResultSet rs null; try { conn DBUtil.getConnection(); // 关键DBUtil 是自定义工具类 pstmt conn.prepareStatement(sql); pstmt.setString(1, username); // 防 SQL 注入 rs pstmt.executeQuery(); if (rs.next()) { user new User(); user.setId(rs.getInt(id)); user.setUsername(rs.getString(username)); user.setPassword(rs.getString(password)); user.setRole(rs.getString(role)); // role 字段决定是 admin 还是 customer } } catch (SQLException e) { e.printStackTrace(); // 教学项目可接受生产环境必须 log.error } finally { DBUtil.close(rs, pstmt, conn); // 必须关闭否则连接泄漏 } return user; }DBUtil.java是这个 ZIP 的灵魂之一它封装了数据库连接public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/agri_sales?useSSLfalseserverTimezoneUTC; private static final String USER root; private static final String PASSWORD 123456; public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(ResultSet rs, PreparedStatement pstmt, Connection conn) { if (rs ! null) try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } if (pstmt ! null) try { pstmt.close(); } catch (SQLException e) { e.printStackTrace(); } if (conn ! null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }血泪经验URL中的serverTimezoneUTC不可省略MySQL 8.0 默认时区是 SYSTEM而 Windows 系统时区常为Asia/Shanghai不加此参数会导致java.sql.SQLException: The server time zone value й׼ʱ is unrecognized乱码时区名。这是 ZIP 里最容易卡住新手的点90% 的“连不上数据库”报错都源于此。3.4 分层边界什么该放哪一层一张表说清功能点JSP 层ViewServlet 层ControllerDAO 层Model获取用户名request.getParameter(username)✅ 接收并传给 DAO❌ 不接触 HTTP 请求校验用户名长度❌ 不做前端 JS 可加但非必须❌ 不做业务规则在 Service本项目无❌ 不做查询数据库❌ 绝对禁止❌ 不写 SQL✅SELECT * FROM user WHERE ...密码加密❌ 不做❌ 不做本项目明文但应在此层调用 BCrypt❌ 不做加密是业务逻辑非数据访问设置 Session 属性❌ 不做✅session.setAttribute(user, u)❌ 不做返回错误信息给页面✅${error}显示✅request.setAttribute(error, ...)❌ 不做这张表划清了责任田。很多学生把密码校验写在 JSP 里% if(pwd.length6){...}%或者在 DAO 里写response.sendRedirect(...)结果调试时发现跳转失效、Session 丢失——根源就是越界。4. 避坑指南部署与运行中 5 个高频翻车点及解法这个 ZIP 的“可运行”承诺建立在大量隐形约束之上。一旦环境稍有偏差就会触发一系列看似随机、实则有迹可循的报错。以下是我在指导学生过程中记录的 5 个最高频、最隐蔽、最浪费时间的坑按现象 → 原因 → 解决的结构给出。4.1 现象页面中文显示为??或方块但数据库里是好的原因JSP 页面编码、HTTP 响应头、数据库连接 URL 三者不统一。常见组合是JSP 声明了charsetUTF-8但web.xml中未配置CharacterEncodingFilter导致 POST 请求体解析为 ISO-8859-1。解决确认login.jsp顶部有% page contentTypetext/html; charsetUTF-8 %在web.xml中添加过滤器放在所有 servlet mapping 之前filter filter-nameCharacterEncodingFilter/filter-name filter-classorg.apache.catalina.filters.SetCharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mappingMySQL 连接 URL 加characterEncodingutf8mb4虽然serverTimezoneUTC更关键但加上更保险。4.2 现象点击“提交订单”后页面空白控制台无报错catalina.out里只有INFO: Server process terminated原因OrderServlet.java中调用了response.getOutputStream()写文件如生成 PDF 订单但又试图用response.getWriter()输出 HTML违反了 Servlet 规范——一个响应只能用一种输出流。解决检查所有 Servlet 的doPost/doGet方法确保没有混用getWriter()和getOutputStream()。本项目中订单功能若只是跳转应删掉所有getOutputStream()相关代码若真要导出必须用getOutputStream()并设置response.setContentType(application/pdf)且不能有任何out.println()。4.3 现象管理员登录后进admin/目录提示HTTP Status 403 – Forbidden原因web.xml中配置了security-constraint但 ZIP 里可能漏掉了web.xml的 security 部分或admin/目录下缺少WEB-INF/web.xml老式项目有时把 admin 单独做成子应用。解决检查项目根web.xml确认没有security-constraint标签教学项目通常不配权限如果WebContent/admin/是独立目录检查其下是否有WEB-INF/web.xml若有打开看url-pattern是否写成了/admin/*但没配auth-constraint最快解法删掉WebContent/admin/目录把管理员功能整合进主应用用session.getAttribute(currentUser).getRole().equals(admin)控制菜单显示。4.4 现象Tomcat 启动后访问http://localhost:8080/agri/显示 404但http://localhost:8080/agri/index.jsp能打开原因web.xml中缺失welcome-file-list配置导致容器不知道默认首页是哪个文件。解决在web.xml的web-app标签下添加welcome-file-list welcome-fileindex.jsp/welcome-file welcome-fileindex.html/welcome-file /welcome-file-list注意welcome-file必须是存在的文件名且大小写严格匹配。4.5 现象部署到公司测试服务器后图片不显示路径是http://ip:8080/agri/images/apple.jpg但返回 404原因ZIP 中的图片放在WebContent/images/但服务器 Tomcat 的conf/web.xml中DefaultServlet的readonly参数为true安全策略禁止通过 URL 直接访问静态资源。解决找到服务器 Tomcat 的conf/web.xml搜索servlet-namedefault/servlet-name在其init-param中将param-valuetrue/param-value改为param-valuefalse/param-value重启 Tomcat。注意生产环境不建议关 readonly应改用servlet-mapping显式映射/images/*到DefaultServlet但毕设演示可接受此方案。5. 从 ZIP 到可交付三步加固让答辩老师挑不出硬伤拿到 ZIP解压、配环境、跑起来只是完成了 30%。答辩时老师最常问“这个系统如果真用安全吗”“数据丢了怎么办”“并发 10 个人同时下单会超卖吗”——这些问题的答案就藏在对 ZIP 的三处关键加固里。不改核心逻辑只加几行代码、改几个配置就能让系统从“能跑”升级为“像样”。5.1 密码加密把明文123456变成不可逆哈希当前UserDAO.java中密码校验是if(123456.equals(inputPwd))这是教学简化但答辩时会被质疑。加固只需两步第一步引入 BCrypt替换mysql-connector-java的位置下载bcprov-jdk15on-1.68.jar和spring-security-crypto-5.7.8.jar轻量只用BCryptPasswordEncoder类放入WEB-INF/lib/。第二步改造LoginServlet.java// 在类顶部加 private BCryptPasswordEncoder passwordEncoder new BCryptPasswordEncoder(); // 在 doPost 方法中替换密码校验逻辑 // 原来 // if (user ! null password.equals(user.getPassword())) // 改为 if (user ! null passwordEncoder.matches(password, user.getPassword())) { // 登录成功... }第三步改造注册逻辑如果 ZIP 里有RegisterServlet// 用户注册时密码入库前加密 String encodedPassword passwordEncoder.encode(inputPassword); user.setPassword(encodedPassword); userDAO.save(user); // save 方法里执行 INSERT关键细节BCrypt 的encode()方法每次生成的哈希值都不同因含随机 salt所以不能用或equals()比较原始密码必须用matches()。这是学生最容易写错的地方。5.2 库存扣减防超卖用数据库行锁替代应用层判断当前下单逻辑大概是// 伪代码 Product product productDAO.findById(productId); if (product.getStock() orderQty) { product.setStock(product.getStock() - orderQty); productDAO.update(product); // 更新库存 orderDAO.save(order); // 保存订单 }这在并发下必然超卖。加固方案把判断和更新合并为一条 SQL利用 MySQL 的UPDATE ... WHERE stock ?原子性。// 在 ProductDAO.java 中新增方法 public int updateStockIfEnough(int productId, int quantity) { String sql UPDATE product SET stock stock - ? WHERE id ? AND stock ?; // 注意WHERE 条件中的 stock ? 是关键确保库存足够才更新 try (Connection conn DBUtil.getConnection(); PreparedStatement pstmt conn.prepareStatement(sql)) { pstmt.setInt(1, quantity); pstmt.setInt(2, productId); pstmt.setInt(3, quantity); return pstmt.executeUpdate(); // 返回影响行数1成功0库存不足 } catch (SQLException e) { e.printStackTrace(); return 0; } }在OrderServlet.java中调用int updated productDAO.updateStockIfEnough(productId, orderQty); if (updated 0) { request.setAttribute(error, 库存不足请重新下单); request.getRequestDispatcher(cart.jsp).forward(request, response); return; } // 否则继续创建订单...为什么有效UPDATE语句在 InnoDB 引擎下会对匹配的行加 X 锁排他锁其他事务无法同时更新同一行天然串行化。比synchronized更可靠且不阻塞读操作。5.3 日志与异常让报错信息变成答辩加分项当前代码中大量e.printStackTrace()答辩时老师点开控制台看到满屏红字第一印象就是“不专业”。加固目标让每一次异常都留下可追溯的线索。第一步添加log4j.properties到src/目录log4j.rootLoggerINFO, stdout, file log4j.appender.stdoutorg.apache.log4j.ConsoleAppender log4j.appender.stdout.layoutorg.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} [%p] %c{1} - %m%n log4j.appender.fileorg.apache.log4j.RollingFileAppender log4j.appender.file.Filelogs/app.log log4j.appender.file.MaxFileSize10MB log4j.appender.file.MaxBackupIndex5 log4j.appender.file.layoutorg.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} [%p] %c{1} - %m%n第二步在每个 Servlet 和 DAO 中声明 logger// 在 LoginServlet.java 顶部 private static final Logger logger Logger.getLogger(LoginServlet.class); // 在 catch 块中 } catch (SQLException e) { logger.error(Login failed for user: username, e); request.setAttribute(error, 系统繁忙请稍后再试); request.getRequestDispatcher(login.jsp).forward(request, response); }第三步在web.xml中配置 Log4j 监听器确保启动时加载listener listener-classorg.apache.log4j.web.Log4jConfigListener/listener-class /listener context-param param-namelog4j-config-location/param-name param-value/WEB-INF/classes/log4j.properties/param-value /context-param这样当用户输错密码控制台不再打印堆栈而是2024-06-15 14:22:33 [ERROR] LoginServlet - Login failed for user: zhangsan——简洁、专业、可定位老师会觉得你考虑到了运维视角。我带毕设时有个习惯让学生在答辩前用手机录一段 60 秒视频内容就三件事1打开 Tomcat Manager 页面显示/agri应用状态为running2在 MySQL 客户端执行SELECT COUNT(*) FROM orders;显示当前订单数3在 IDEA 的logs/app.log里滚动展示最近 5 条 INFO 日志。这比任何 PPT 都有说服力——它证明系统不是“曾经跑过”而是“此刻活着”。这个 ZIP 的价值从来不在技术多新而在于它把 Java Web 的毛细血管都摊开给你看从字节码加载到 JSP 编译从 Connection Pool 到 Session ID 生成从 URL 解析到 Filter 链执行。你不必把它当成最终产品但一定要把它当作一面镜子——照见自己对 Web 容器、JDBC、HTTP 协议的理解深度。改一行web.xml调一次DBUtil.getConnection()修一个CharacterEncodingFilter这些动作本身就在构建你作为工程师的肌肉记忆。希望帮到你。本文还有配套的精品资源点击获取