
作为毕设导师我每年都会看到几十个类似“JSP扶贫管理系统”的题目。说句实在话这个题目和“JSP学生管理系统”“JSP图书管理系统”在技术内核上几乎一样都是那一套JSP页面 Servlet MySQL。但每年仍有不少学生卡在同一个地方——建表建到一半不知道业务字段怎么设计写登录写到最后Session控制不住部署到Tomcat又冒出一堆404、500、乱码问题。这篇文章就当一次完整复盘从题目边界、技术选型、数据库设计、核心功能实现到运行调试踩坑一条线全部讲清楚适合正在做类似毕设题目、或者想把手头半成品项目真正跑通的同学参考。1. 做这类题目之前先把系统边界想清楚1.1 目标用户与角色设计很多同学拿到“扶贫管理系统”第一反应是这系统到底给谁用、要管什么。这个答案搞不清楚后面所有建表都是瞎猜。从毕设常用的模拟场景出发我建议把用户拆成三个角色系统管理员、帮扶干部业务人员、普通用户被帮扶对象或访客。三个角色对应三种完全不同的操作视角。系统管理员的主要工作是维护用户、分配账号、发公告、看操作日志他不需要天天录贫困对象资料帮扶干部才是核心业务用户负责录入帮扶对象档案、新增帮扶记录、跟进回访状态普通用户登录后能看与自己相关的档案信息和帮扶进度能提交一些基础申请。这样一拆系统菜单就很清晰管理员看用户管理和公告管理干部看对象管理和帮扶管理普通用户看个人中心和进度查询。千万不要一上来就想把整个单位内部OA那套全部复制过来毕设的核心目标是把一个业务闭环讲明白不是做一个能卖给政府的商业系统。一个用户有一个角色一个角色打开不同的菜单登录后跳转不同主页能演示、能讲清楚这个阶段就及格了。1.2 功能模块的合理裁剪扶贫管理系统常见模块可以拆成四块基础数据、对象档案、帮扶记录、数据统计。基础数据包括用户、角色、登录、公告对象档案是整个项目的核心要有新增、修改、删除、详情查看、关键字搜索、状态筛选帮扶记录则是跟着每一个对象走的每次帮扶访问都要留痕数据统计属于加分项能在首页用几个数字卡片展示总户数、本月新增、待回访数量就足够了。有不少同学想直接上Excel导入导出、短信提醒、流程审批这些功能。我的建议是先把Excel导出放最后因为POI操作在JSP老项目里容易出版本冲突而且前四项功能没跑通之前做这些只会拖慢进度。流程审批如果用一张表中的状态字段来实现会更适合别急着上Activiti工作流引擎那是给自己挖坑。1.3 容易被忽略的需求细节设计和开发过程中有几个细节容易被忽略第一帮扶对象的档案资料谁录入、谁审核必须有一个可区分字段第二同一个家庭被多次帮扶需要记录每次不同的帮扶内容不能只更新一条记录第三对象状态要从“待审核”到“帮扶中”再到“已完成”不能只用一个开关判断。这些细节能不能做到直接决定答辩时老师问你“如果用户重复录入怎么办”时能不能答上来。2. JSP作为核心技术的架构选型详解2.1 为什么毕业设计还要继续用JSP我知道你心里可能有个疑问都什么年代了怎么还在搞JSP其实这个问题的答案很简单学校课程大纲还停留在经典Java Web阶段指导老师最熟悉的就是JSPServlet这套方案。另外从技术复杂度看JSP项目不需要Spring容器、不需要Maven繁琐依赖管理IDE配好Tomcat就能跑正好匹配毕设的时间周期。用JSP不代表项目没水平关键在于你能否把MVC分清楚能否在Servlet里控制好请求转发和重定向。还有一点经验之谈JSP项目特别适合用来讲原理。Spring Boot帮你把Tomcat内嵌了、把视图解析器配置好了反而说不清楚一次HTTP请求如何在Servlet、JSP、数据库之间流转。你如果能在答辩时把Filter、Servlet生命周期、Session存储机制讲清楚老师对你的认可度不亚于你用了一套Spring Cloud。2.2 Model1还是Model2先定Controller写法JSP开发有两套经典模式。Model1是JSP页面既负责显示又负责业务逻辑适合页面少、逻辑简单的小项目Model2是标准MVC分层JSP只做视图Servlet做控制器JavaBean/DAO做模型毕设项目推荐用Model2。一个清晰的项目包名结构长这样com.fpms ├── controller # Servlet负责接收请求和跳转 │ ├── LoginServlet.java │ ├── UserServlet.java │ ├── ObjectServlet.java │ └── HelpRecordServlet.java ├── service # 业务逻辑层可选小项目可省 ├── dao # 数据访问层 │ ├── BaseDao.java │ ├── UserDao.java │ └── PoorObjectDao.java ├── entity # 实体类 │ ├── User.java │ ├── PoorObject.java │ └── HelpRecord.java ├── filter │ └── AuthFilter.java └── util └── DbUtil.java这个结构的好处是分工明确JSP只负责接收request域里的数据并用JSTL标签渲染Servlet只做参数接收和页面调度DAO只写SQL。就算后期要换数据库或者加接口改动面会小很多。实际写代码时很多教科书会把Service层拿掉Servlet直接调DAO毕设完全够用不要在这个问题上纠结太久。2.3 开发环境怎么搭最省事用一个最不容易出错的组合JDK 1.8、Tomcat 8.5、Eclipse IDE for Enterprise Java and Web Developers数据库用MySQL 5.7或8.0。如果你习惯用IntelliJ IDEA请一定装Ultimate版社区版没有Web应用运行支持如果只有社区版就手动下载Tomcat用catalina.bat run方式启动并部署war包。Eclipse虽然界面老一些但对JSP项目的支持反而非常直接Dynamic Web Project模板点下一步就能创建。我见过太多因为IDE版本不对、Tomcat版本过高导致一整晚调不通环境的例子。Tomcat 10之后Servlet包名从javax.servlet迁到了jakarta.servlet很多老教程代码会直接编译报错所以新老项目尽量选Tomcat 8.5或Tomcat 9.0。用JDK8配Tomcat8.5是最保守的方案兼容性最好。2.4 搭建项目骨架的两种方式方式一是在Eclipse里新建Dynamic Web Project勾选Generate web.xml deployment descriptor这样会自动生成src/main/java和WebContent目录JSP放在WebContent根目录下。方式二是下载一个现有的JSP项目模板改包名。第二种方式要小心如果原项目已经跑过Tomcat缓存、classpath配置都可能残留反而不如从零建省心。项目建好后第一件要做的事情不是写代码而是先把WEB-INF/lib里放入mysql驱动jar和JSTL的jar包否则后面写DAO层立刻会报ClassNotFoundException。3. 数据库表结构与核心字段设计3.1 从用户角色拆出权限字段用户表和角色表是最基础的两张表。有的毕设项目图省事只在用户表里放一个role字段取值为“admin”或“user”这种做法做登录没问题但一旦想扩展不同角色的菜单就非常僵硬。我的经验是拆成三张表用户表、角色表、用户角色关联表如果只有一个用户可以只有一个角色那简化为用户表带role字段也问题不大。用户表需要的基础字段用户ID、登录名、密码、真实姓名、联系电话、所属单位或部门、角色ID、创建时间。密码不要明文存储至少要MD5加密数据库里存密文后登录时把用户输入密码做同样处理再比对。角色表就简单一点角色ID、角色名称、角色标识super_admin / worker / normal、菜单权限描述。管理员和帮扶干部的差别就在登录后能看到哪些页面这个用Session里的角色标识实现就很方便。3.2 帮扶对象主表与状态机帮扶对象表是整个系统的设计核心。先想明白一个对象是什么——通常以一个“家庭”为单位户主作为档案的登记人。这张表的字段一定要贴近业务我建议这样设计CREATE TABLE t_poor_object ( id INT PRIMARY KEY AUTO_INCREMENT, family_code VARCHAR(20) NOT NULL COMMENT 家庭编号, head_name VARCHAR(30) NOT NULL COMMENT 户主姓名, id_card VARCHAR(18) COMMENT 身份证号, phone VARCHAR(11) COMMENT 联系电话, address VARCHAR(255) COMMENT 家庭住址, family_num INT DEFAULT 1 COMMENT 家庭人口数, poverty_type VARCHAR(20) COMMENT 致困类型, reason VARCHAR(500) COMMENT 情况说明, annual_income DECIMAL(10,2) COMMENT 年收入, audit_status TINYINT DEFAULT 0 COMMENT 审核状态 0待审 1通过 2退回, help_status TINYINT DEFAULT 0 COMMENT 帮扶状态 0未帮扶 1帮扶中 2已完成, helper_id INT COMMENT 帮扶责任人, create_time DATETIME, update_time DATETIME, delete_flag TINYINT DEFAULT 0 COMMENT 逻辑删除 );注意几点family_code要有规则通常可以做成“年份四位序号”比如2025开头的20250001这样可以避免程序自动生成主键后无法形成业务编号身份证号不要用int用varchar(18)因为要支持尾号X金额字段用DECIMAL而不是FLOAT否则后面统计会有精度问题。audit_status和help_status组合起来就构成了审核流和帮扶流的核心状态机。3.3 帮扶记录、公告和台账的关系帮扶记录表是另一张必须的表。一个帮扶对象家庭会有多次走访每次帮扶的时间、方式、内容、责任人可能都不一样所以帮扶记录和帮扶对象之间是“多对一”关系CREATE TABLE t_help_record ( id INT PRIMARY KEY AUTO_INCREMENT, object_id INT NOT NULL COMMENT 对象ID, help_time DATETIME COMMENT 帮扶时间, help_type VARCHAR(20) COMMENT 帮扶方式, content VARCHAR(1000) COMMENT 具体内容, result_status TINYINT COMMENT 回访结果, helper_name VARCHAR(30) COMMENT 帮扶人, create_time DATETIME );公告表非常简单字段就是标题、正文、发布人、发布时间。需要做首页统计时通过SQL对帮扶对象表做COUNT、对本月新增做WHERE create_time 日期即可。经常有同学问要不要建物理外键实践中我建议不要。外键在查询时影响效率删除或批量更新时会卡住实体表之间的关联完全可以在业务层通过join来保证。数据库设计到这里先不要急着加字段每张表核心字段能用就行后面需要加字段再加数据库迁移成本远低于一开始设计复杂。4. 页面与后端联动的核心实现细节4.1 登录页与Session拦截的标配写法JSP项目登录功能的标配流程是JSP登录页面提交用户名和密码到LoginServletServlet调用DAO查询用户表查到就把用户对象放进Session再根据角色跳转到对应主页查不到就返回登录页并提示错误信息。这里有个容易忽略的点是登录密码传输建议用POST方式表单上要加form actionlogin methodpost避免账号密码直接出现在地址栏。Servlet中设置Session超时可以在web.xml里用session-config配置默认30分钟对毕设来说够了。Session设置为登录用户信息后问题来了用户没登录也能直接访问中间页面怎么办这时需要写一个Filter统一拦截。这是我强烈建议加进去的代码亮点public class AuthFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI(); if (uri.endsWith(login.jsp) || uri.endsWith(/login) || uri.contains(/css/) || uri.contains(/js/) || uri.contains(/images/)) { chain.doFilter(request, response); return; } Object user req.getSession().getAttribute(loginUser); if (user null) { resp.sendRedirect(req.getContextPath() /login.jsp); return; } chain.doFilter(request, response); } }再在web.xml里声明filter并映射到/*。要注意的是Filter的判断逻辑不要只判断字符串后缀有静态资源时要放行对应目录否则登录页的CSS也加载不出来。这段代码如果写对答辩时可以直接说“我通过Filter解决了未授权访问问题”这是一个实实在在的安全控制点。4.2 档案列表与分页查询的完整写法档案管理页面是工作量最大的地方也是最能体现编码能力的模块。列表页通常有这个需求顶部一个搜索框输入姓名或编号下面一个表格逐行展示档案信息底部有页码导航。整个流程是浏览器GET请求携带page和keyword访问ObjectServlet的list方法Servlet拿到参数后调用DAO层查询把结果放进request域转发到object_list.jsp。分页是这里的重头戏。很多刚做项目的人直接SELECT * FROM t_poor_object然后一次性显示数据少没问题数据一多页面就卡。手写分页其实不复杂SQL语句借助MySQL的LIMIT实现关键在于两个参数计算要准确int pageSize 10; int currentPage 1; String pageStr request.getParameter(page); if (pageStr ! null !pageStr.equals()) { currentPage Integer.parseInt(pageStr); } int offset (currentPage - 1) * pageSize; // 先查总数 int totalCount poorObjectDao.count(keyword); int totalPages (int) Math.ceil(totalCount * 1.0 / pageSize); // 再查当前页数据 ListPoorObject list poorObjectDao.findList(keyword, offset, pageSize); request.setAttribute(list, list); request.setAttribute(totalPages, totalPages); request.setAttribute(currentPage, currentPage); request.getRequestDispatcher(/object_list.jsp).forward(request, response);DAO里的列表查询SQL大体长这样SELECT * FROM t_poor_object WHERE delete_flag 0 AND (head_name LIKE CONCAT(%, ?, %) OR family_code LIKE CONCAT(%, ?, %)) ORDER BY create_time DESC LIMIT ?, ?分页导航在JSP页面里通过JSTL的c:forEach渲染页码上一页、下一页按钮的链接拼上page参数即可。这里强烈建议所有SQL查参用PreparedStatement的?占位符不要用字符串拼接字符串拼接不仅容易出错还会留下SQL注入的隐患。你代码里出现PreparedStatement使用在答辩时是非常明显的加分项。4.3 新增和编辑页面到底怎么处理数据回显对象档案的新增和编辑页面可以共用同一个JSP。现在有一个很容易写乱的痛点点“编辑”时要先把表单回显数据很多新手会直接在JSP的value属性中写% request.getParameter(name) %这样的表达式导致页面超级乱。我建议这样做编辑操作时ObjectServlet先从数据库查出这条对象的完整数据放到request域再转发到object_edit.jsp。页面中的每个input的value属性统一从request属性取。例如input nameheadName value${obj.headName} /。如果${obj}为null表示当前是新增页则value为空。同一个JSP即可兼容新增与编辑。表单处理逻辑上也用同一个Servlet的save方法如果传了id则走update没传id则走insert这种统一的入口能少写一半代码。4.4 图片上传证件材料怎么落盘涉及帮扶对象的材料比如身份证明、住房照片会需要文件上传。JSP表单必须设置enctypemultipart/form-data如果你用的是Servlet 3.0的TomcatServlet类上加MultipartConfig注解然后用Part API处理即可不需要额外引第三方上传jar包String uploadDir getServletContext().getRealPath(/upload); File dir new File(uploadDir); if (!dir.exists()) dir.mkdirs(); Part part request.getPart(photo); String fileName System.currentTimeMillis() _ part.getSubmittedFileName(); part.write(uploadDir File.separator fileName); // 数据库里只存相对路径 String dbPath upload/ fileName;注意数据库表里保存的是upload/文件名这样的相对路径不要存C:\...这种磁盘绝对路径否则项目换个目录部署立刻找不到图片。页面上展示时用${pageContext.request.contextPath}/拼接图片路径即可。上传文件时还要限制文件大小和扩展名防止用户传了超大jpg或者伪装成图片的可执行文件这是安全侧必须讲的点。4.5 JSP页面上用JSTL代替散落的Java代码热词里大家都在搜“jsp脚本片段”和“如果在jsp上写java代码的风险”这个我必须多讲几句。JSP里的% %脚本片段确实能执行Java代码早期很多老项目都是这么写。但把Java代码塞进JSP里的风险很明显第一是前后端混在一起后期想改版式动不动就碰到圈起来的Java逻辑改一行代码要测试半天第二是业务逻辑无法复用同一段判断很难在别的页面中再使用第三是JSP被容器翻译成Servlet时任何编译错误只会显示在500页面排查时不直观。推荐的做法是引入JSTL。在页面头部写上% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %然后列表循环、条件判断都用标签完成。例如展示状态时c:if test${obj.auditStatus 0}待审核/c:if c:if test${obj.auditStatus 1}已通过/c:if c:if test${obj.auditStatus 2}已退回/c:if要用JSTL必须在WEB-INF/lib下放两个jarjstl.jar和standard.jar。如果忘了放页面一运行就会报java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core。遇到这个报错别慌把两个jar放进去再重启Tomcat就好。5. 部署运行与调试环境实录5.1 从零到能访问的一次完整配置以Eclipse为例我从项目能访问的角度给一个可复现的步骤清单创建数据库执行建表脚本并插入一条管理员初始数据。用Eclipse新建Dynamic Web Project把项目名设为fpms。把MySQL驱动jar、JSTL jar拷贝到WebContent/WEB-INF/lib。在src下新建util/DbUtil.java写好数据库连接工具。新建LoginServlet包名和类名确认无误在类上或web.xml中配置访问映射。在Servers面板配置Tomcat 8.5右键项目Run on Server。这里我用的项目名fpms对应访问地址http://localhost:8080/fpms/login.jsp。contextPath就是/fpms在代码和页面中最好通过request.getContextPath()动态获取不要写死localhost:8080/fpms不然换端口或换机器又要改一遍。5.2 DbUtil与MySQL驱动的版本对应JSP项目连接MySQL最常见的写法就是用DriverManager.getConnection我建议封装成一个工具类避免每个DAO里重复写连接代码。一个简化的DbUtilpublic class DbUtil { private static final String URL jdbc:mysql://localhost:3306/fpms?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiuseSSLfalse; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }注意MySQL 5.7对应驱动类是com.mysql.jdbc.DriverMySQL 8.0对应驱动类是com.mysql.cj.jdbc.Driver。如果你本机装的是MySQL 8.0又用了老版本的mysql-connector-java 5.x大概率会报Public Key Retrieval is not allowed或ClassNotFoundException。最直接的解决办法是统一使用mysql-connector-java-8.0.x.jar连接串中配置serverTimezoneAsia/Shanghai解决时区问题。把数据库账号密码放到工具类里没问题正规项目这个位置确实不该硬编码但对毕设来说保持简单更重要。5.3 静态资源和JSP修改后不生效的问题IDE开发阶段还有一个经典困扰改了JSP页面刷新浏览器还是老样子。原因多半是Tomcat没有重新部署。Eclipse中修改JSP后要先保存再到Servers视图右键项目Clean最后RestartIDEA中按下CtrlF10选择Update resources只更新静态资源不需要重启。热部署有时只对静态资源和JSP文件有效如果修改了Servlet或Filter必须重启Tomcat。图片上传后刷新不出来的问题很常见一般是因为Tomcat运行目录的webapps/项目名/upload和工程目录里的WebContent/upload不是同一个。项目在Eclipse中以Exploded方式部署时文件通常是先发布到wtpwebapps目录访问的图片来源于那里。上传后没看到图片去wtpwebapps/fpms/upload下面看看文件在不在这个排查方向比改半天页面代码高效得多。6. 运行调试常见问题与避坑清单6.1 中文乱码整套解决方案JSP中文乱码是出现频率最高的bug没有之一。乱码通常分三种页面显示乱码、请求参数乱码、数据库存取乱码。页面显示乱码先检查JSP文件头部是否有% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%并且确认文件的实际编码是UTF-8。IDEA右下角能看到文件编码Eclipse在Properties里设置Text file encoding不要只在代码里写UTF-8但文件本身是GBK编码这种隐藏问题最恶心。如果jsp页面声明了还不行检查IDE默认编码改成UTF-8后重新新建文件。请求参数乱码推荐直接用一个EncodingFilter在doFilter里设置request.setCharacterEncoding(UTF-8)这样POST请求表单数据就不会乱。Tomcat 8及以上GET请求的URI默认编码也是UTF-8如果你用的老Tomcat7还需要修改server.xml里的URIEncodingUTF-8。数据库存取乱码第一要保证连接串中带useUnicodetruecharacterEncodingUTF-8第二建库时指定字符集例如CREATE DATABASE fpms DEFAULT CHARACTER SET utf8mb4;第三是表结构字段编码也统一成utf8mb4尤其是有remark、content这种长文本字段时。按这三层查基本没有解决不了的乱码。6.2 404和500最常见的诱因404错误分两种一种是访问的JSP页面根本不存在这个直接看URL拼写和文件目录另一种是项目路径没写对http://localhost:8080/fpms/index.jsp访问不了但http://localhost:8080/index.jsp访问的了这类问题一半是项目没有正确部署到Tomcat的webapps目录一半是URL里少了contextPath。查404时先看Tomcat控制台有没有报错如果连控制台都提示找不到web模块就去Servers视图确认模块是否已经添加进来了。500错误则要看异常栈的第一行提示。常见的如数据库驱动找不到、表不存在、字段名写错、空指针。SQL字段写错有个特征错误信息里会带SQL语句很快能定位空指针则要打日志建议在每个Servlet入口就加上try-catch并打印异常信息不然控制台干净得让你无从下手。排查大忌是只刷新页面不看控制台一定要学会看Tomcat的日志输出每一个异常都是一行有效线索。6.3 JSP里大量Java代码的维护风险再回到热词里“如果在jsp上写java代码的风险”。一个典型的混乱场景是页面上有一个表格循环有人在JSP的% for (int i 0; i list.size(); i) { ... } %里直接访问DAO再查一遍关联数据又有人在点击删除按钮时用a hrefobject?methoddeleteid% obj.getId() %删除/a这是一个非常危险的设计。上一条说了GET请求修改数据会让爬虫或用户误点直接把记录删了还有一个安全风险是未经过滤的用户名直接在页面上输出导致XSS这两点都属于安全实践问题现场演示时被老师点出来会很被动。我推荐的JSP页面代码约束是三条页面内尽量不要出现%开头的脚本片段数据获取统一在Servlet里完成通过request域传递页面上只做展示和简单判断复杂逻辑放到Java类里。这样做出来的项目结构清晰代码查重也不容易因为全是乱码式脚本被误判。6.4 后端“审批状态”怎么用最简代码实现热词里有人问“jsjquery如何设置审批流”。这个问题放到JSP项目里完全没必要动工作流引擎。帮扶对象档案从提交到审核再到帮扶进度跟进本质就是一张表的字段状态迁移。实现要点是列表页中的“审核”按钮提交请求到ObjectServlet的audit方法方法里接收id和审核结果执行UPDATE t_poor_object SET audit_status ? WHERE id ?然后重定向回列表。前端可以做一层二次确认提示用jQuery弹个confirm框就够了。审批流在这里体现为业务约束未审核通过的对象不允许进入帮扶记录添加页面帮扶记录添加完成后自动把help_status改为1同一对象帮扶次数达到目标时可手动标记完成。纯后端来控制状态迁移比在前端用复杂JS轮子更实用也让答辩时关于状态机的表述更清晰。6.5 数据统计页面的实现思路系统首页的统计卡片是最容易出视觉效果又不太难实现的地方。用一个Dashboard Servlet在DAO里写几条聚合SQL总档案数SELECT COUNT(*) FROM t_poor_object WHERE delete_flag0本月新增数SELECT COUNT(*) FROM t_poor_object WHERE create_time ?待回访数SELECT COUNT(*) FROM t_poor_object WHERE help_status1。查出来放进request域转发到index.jsp再用${totalCount}、${monthCount}这些EL表达式渲染到卡片上。这个页面的实现难点不在于技术而在于你有没有把数据库连接和查询逻辑放到Servlet而不是直接放到JSP里。我个人的体会是遇到这类经典题目最忌讳的不是技术老而是技术老还不做到位。用JSP不丢人丢人的是Controller、View不分家逻辑全写在JSP脚本片段里数据库表设计连逻辑删除和创建时间都没有。如果你能把上面说的Filter统一登录拦截、PreparedStatement防注入、状态字段流转、分页查询、逻辑删除这五个点全部落进代码再在文档和答辩PPT里把它们当成设计亮点而不是“功能”来讲这套JSP系统的完成度已经超过同题目的大部分人。最后再提醒一个容易被忽视的操作细节整个项目开发过程中每次改完数据库表结构都要同步更新实体类和DAO中的字段映射最常见的翻车现场就是数据库多了字段Java代码没同步页面一访问就报“column not found”提前养成改表三件套的习惯——改SQL、改实体、改DAO能省下后面大量联调时间。