☰
Java+JSP+MySQL学生信息管理系统课设全攻略:从环境搭建到War部署
2026/9/28 13:25:34 网站建设 项目流程

简介:面向Java Web初学者的完整学生信息管理系统项目,基于Java、JSP与MySQL实现,覆盖从需求分析、数据库设计到前后端交互的典型开发流程,适合课程设计、毕业设计或自学练手。压缩包共75个文件,包含28个JSP视图页面、22个class编译类、11个Java源码、10个XML配置及1个SQL脚本等,整体约3.92MB,目录结构清晰。开发者可对照源码理解登录与权限管理、学生信息增删改查、条件查询和报表统计等核心模块,同时学习JavaBean封装数据、Servlet处理请求以及通过SQL操作MySQL数据库的完整链路。项目采用经典B/S架构,内置合理的分层设计与基础安全防护思路,可帮助读者规避常见SQL注入等风险,并体验从编码到测试的Web开发全流程。已有8989人学习下载,适合希望快速积累实战经验的初学者和需要参考完整项目的高校学生。

1. 为什么是Java+JSP+MySQL:学生信息管理系统这个题目,老但不过时

每年课设答辩季,学生信息管理系统都是JavaWeb方向出现频率最高的题目之一。很多人在选题时会犹豫:SpringBoot都卷到3.x了,再交一个Java+JSP+MySQL的Web项目会不会显得过时?我的看法恰好相反。这门课设的价值不是「用最潮的框架」,而是把Servlet生命周期、HTTP请求响应、JDBC数据库访问、Session状态管理这条链路亲手走通。JSP+Servlet正是这条链路最直接的呈现方式,MySQL负责把数据真正落盘,三者拼起来就是一个能演示、能答辩、能二次扩展的完整Web系统。本文按我实际做这类项目的顺序展开:先定环境和骨架,再定表和连接参数,然后写登录、增删改查和分页,最后把项目打成War包部署到独立Tomcat上。适合正在做课设、毕设或想补JavaWeb基础功力的读者。

2. 环境与项目骨架:用IDEA把传统JSP项目跑起来的完整路径

2.1 选型先说清:Servlet/JSP直出,还是SpringBoot套壳

先纠正一个误区:题目写「Java+JSP+MySQL」,但很多同学会偷偷用SpringBoot,把JSP塞进src/main/webapp里,再配一堆Resolver。这种做法不是不行,而是会让答辩变得很尴尬——老师问「请求怎么到Servlet的」「Tomcat怎么处理JSP的」,你答不上来。传统的JSP项目走的是最朴素的一条链:浏览器请求 → Tomcat解析URL找到对应的Servlet或JSP → Servlet调用DAO访问MySQL → 结果set到request → forward到JSP渲染输出。这条链上每个环节都肉眼可见,没有框架帮你隐藏细节,这正是课设想要你掌握的。

我一般建议直接用Servlet+JSP+JDBC三层结构,不引入Spring、MyBatis。理由有三个:第一,依赖少,整个项目只需要一个mysql-connector-java,出问题好查;第二,JSP页面可以直接通过<%= %>和JSTL输出数据,不用学习额外标签库;第三,答辩时你可以讲清楚每一行代码在干什么,这是框架黑匣子给不了的。如果你的老师要求「必须用框架」,那再考虑SpringBoot套壳,但那就不是本文的题目了。

2.2 环境版本搭配:JDK、Tomcat、MySQL的兼容边界

版本组合是这类项目第一个踩坑点,而且坑得毫无技术含量。常见翻车现场是:JDK 17 + Tomcat 10 + mysql-connector-java 5.1,启动直接报NoClassDefFoundError: javax/servlet/...。原因是Tomcat 10把包名从javax.servlet换成了jakarta.servlet,而很多课设老代码还在写import javax.servlet.*。

我的推荐组合是:JDK 8或11 + Tomcat 9.0.x + MySQL 5.7或8.0 + mysql-connector-java 8.0.x。这套组合下,代码里用的还是javax.servlet,和绝大多数教材、老项目完全一致;驱动选择8.0.x是因为它同时兼容MySQL 5.7和8.0,不用区分两个驱动包。如果你机器上已经装了JDK 17,能跑但没必要,课设场景JDK 8最稳,Tomcat 9对JDK 8和11都支持良好。

MySQL方面,5.7和8.0都行。唯一要注意的是8.0默认的认证插件是caching_sha2_password,老驱动连不上会报Unable to load authentication plugin,所以驱动必须用8.0.x。数据库编码在建库时直接指定utf8mb4,避免后面中文乱码。

2.3 IDEA新建JSP Web项目的最小配置

常见做法是用IDEA的Maven骨架建项目,而不是手动创建目录。操作路径:New Project → Maven → 勾选 Create from archetype → 选 maven-archetype-webapp。这个骨架会生成标准的Maven目录结构:src/main/java、src/main/resources、src/main/webapp,以及pom.xml。

生成后需要补几件事。第一,把src/main/java标记为Sources Root;第二,在webapp下建WEB-INF目录并补上web.xml(新版骨架可能自动生成,没有就手动建);第三,在pom.xml里加入Servlet API和JDBC驱动的依赖,下面是我常用的最小配置:

<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> </dependencies> <build> <finalName>student-management</finalName> </build>

javax.servlet-api的scope设为provided很关键,意思是编译时用它,但打包时不打进去,因为Tomcat自己已经带了Servlet实现,否则部署时会和Tomcat的类冲突。finalName决定打出的War包名字,也就是部署后访问路径的上下文名,我习惯设为student-management,这样启动后访问地址是http://localhost:8080/student-management/。

设置好之后,在IDEA的Run Configuration里加一个Tomcat Server,Deployment里把构建产物选成student-management:war exploded,Application context填/student-management。这一步很多人漏了,导致访问地址和预期不一致。配置完成后启动,浏览器访问http://localhost:8080/student-management/,能看到Maven骨架自带的index.jsp就说明Tomcat和项目关联成功了。

3. 数据库设计与连接池:学生信息表、用户表和连接参数一起定稿

3.1 三张表的设计:学生表、院系表、用户表

一个能过答辩的学生信息管理系统,数据库至少要有三张表:用户表存登录账号,院系表存学院或专业信息,学生表存核心业务数据。很多同学只建一张student表,把学院名称直接写死在里面,这会导致两个问题:一是数据冗余,「计算机学院」每个学生都重复一遍;二是老师追问「如果学院改名了怎么办」时答不上来。

学生表字段我按下面这套设计,覆盖常见需求又不过度设计:

CREATE DATABASE student_db DEFAULT CHARACTER SET utf8mb4; USE student_db; CREATE TABLE tb_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(20) ) ENGINE=InnoDB; CREATE TABLE tb_dept ( id INT PRIMARY KEY AUTO_INCREMENT, dept_name VARCHAR(50) NOT NULL UNIQUE ) ENGINE=InnoDB; CREATE TABLE tb_student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(20) NOT NULL, gender TINYINT DEFAULT 1 COMMENT '1男 0女', birthday DATE, phone VARCHAR(11), email VARCHAR(50), dept_id INT, enroll_date DATE, status TINYINT DEFAULT 1 COMMENT '1在读 0休学 2毕业', FOREIGN KEY (dept_id) REFERENCES tb_dept(id) ) ENGINE=InnoDB;

tb_user.password用VARCHAR(64)是为了以后能存SHA-256或BCrypt的密文,而不是明文。gender和status用TINYINT加注释,比VARCHAR省空间,也方便前端用三元表达式映射中文显示。student_no加UNIQUE约束,这是学生业务上的自然主键。外键dept_id关联院系表,实现一对多关系,导航时用JOIN查出院系名即可。

建好表之后,往tb_user插入一行测试数据,比如用户名admin、密码先用明文123456,项目能跑通后再改加密。别把这条忘了,很多人写完整套代码才发现库里连个登录账号都没有。

3.2 MySQL 8.0的连接参数:driver、useSSL、serverTimezone、allowPublicKeyRetrieval

JSP项目里数据库连接最容易出问题的地方不是SQL,而是连接串参数。MySQL 8.0 + mysql-connector-java 8.0.x 的经典连接串长这样:

String url = "jdbc:mysql://localhost:3306/student_db" + "?useSSL=false" + "&allowPublicKeyRetrieval=true" + "&serverTimezone=Asia/Shanghai" + "&characterEncoding=utf8"; String username = "root"; String password = "你的密码"; Class.forName("com.mysql.cj.jdbc.Driver"); Connection conn = DriverManager.getConnection(url, username, password);

四个参数各有各的用途。useSSL=false是因为本地开发不需要加密连接,不关掉的话MySQL 8.0会因SSL握手失败报Communications link failure;allowPublicKeyRetrieval=true是配合8.0的caching_sha2_password认证插件使用的,不设置会在连接时提示Public Key Retrieval is not allowed;serverTimezone=Asia/Shanghai解决时区报错,默认UTC会让birthday这类日期字段读取时差8小时;characterEncoding=utf8保证驱动传输层使用UTF-8编码。

驱动类名也别忘了,8.0.x用的com.mysql.cj.jdbc.Driver,不是老版本的com.mysql.jdbc.Driver。虽然新驱动会自动注册,不用写Class.forName也能连,但我建议保留这行,一是兼容老写法,二是答辩时能讲清楚「JDBC四步:加载驱动、获取连接、执行SQL、释放资源」。

3.3 连接池选型和Druid参数:为什么课设也要用连接池

如果DAO层每次查询都DriverManager.getConnection一次,功能能跑,但性能和代码质量都不过关。老师常问的一个加分题就是「为什么用连接池」,答案很简单:建立数据库连接是重操作,包括TCP握手、认证、分配资源,每次创建再释放很浪费;连接池提前创建一批连接放着,用的时候借、用完还,能大幅减少开销。

常见选择有Druid、C3P0、HikariCP。传统JSP项目里Druid用得多,因为它自带监控页面,答辩时能演示SQL执行统计,算个小亮点。Maven里加Druid依赖,然后在src/main/resources下建druid.properties:

driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/student_db?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8 username=root password=你的密码 initialSize=5 maxActive=20 minIdle=5 maxWait=3000

初始化连接池的Java代码封装成一个工具类即可:

public class DbUtils { private static DruidDataSource dataSource; static { try (InputStream in = DbUtils.class.getClassLoader() .getResourceAsStream("druid.properties")) { Properties props = new Properties(); props.load(in); dataSource = (DruidDataSource) DruidDataSourceFactory .createDataSource(props); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }

initialSize=5是池子启动时预先创建5个连接,maxActive=20是最大连接数,minIdle=5是池内最少空闲连接数,maxWait=3000是当池子满时,调用方最多等3000毫秒,超过就抛异常。课设场景并发不高,maxActive不用调太大,20就够。DruidDataSourceFactory.createDataSource(props)会自动读取properties里以driverClassName、url、username、password开头的配置并创建数据源。静态块里把数据源初始化好,整个项目共用一个池子,DAO层每次getConnection()都是从池中借连接。

4. 功能实现:登录拦截、学生CRUD、分页查询的完整代码串联

4.1 登录与拦截:Session + Filter,别把权限写在每个页面里

登录功能是Web系统的门面,也是答辩必问点。核心逻辑是:登录页提交用户名密码 → LoginServlet查询tb_user→ 成功则把用户信息放进Session并跳转到主页面 → 失败则提示并留在登录页。代码不复杂,但有一个设计点必须做好:对未登录访问的拦截。

新手常见写法是在每个页面开头都写一遍「判断Session里有没有user,没有就跳回login」,这是复制粘贴式开发,最后总有页面漏写。正确做法是用Filter统一拦截。先写登录Servlet:

@WebServlet("/login") public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); UserDao dao = new UserDao(); User user = dao.findByUsernameAndPassword(username, password); if (user != null) { HttpSession session = req.getSession(); session.setAttribute("loginUser", user); resp.sendRedirect(req.getContextPath() + "/student/list"); } else { req.setAttribute("error", "用户名或密码错误"); req.getRequestDispatcher("/login.jsp").forward(req, resp); } } }

再写一个过滤器拦截所有除登录页、静态资源外的请求:

@WebFilter("/*") public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String uri = request.getRequestURI(); if (uri.endsWith("/login") || uri.endsWith("/login.jsp") || uri.contains("/css/") || uri.contains("/js/") || uri.endsWith(".jpg") || uri.endsWith(".png")) { chain.doFilter(req, resp); return; } if (request.getSession().getAttribute("loginUser") == null) { response.sendRedirect(request.getContextPath() + "/login.jsp"); return; } chain.doFilter(req, resp); } }

@WebServlet("/login")是Servlet 3.0以后提供的注解写法,省去在web.xml里配置Servlet映射。req.getContextPath()获取的是项目部署上下文路径,用它拼URL可以避免项目改名或部署路径变化时跳转失效。Filter里的白名单很重要:静态资源、登录页、登录接口必须放行,否则会出现「登录页都打不开」或「CSS样式全丢」的问题。Session超时时间在web.xml里配:

<session-config> <session-timeout>30</session-timeout> </session-config>

这个值单位是分钟,30分钟表示用户30分钟无操作后Session自动失效,需要重新登录。课设演示时建议改成60,避免讲到一半Session过期被强制踢回登录页。

4.2 StudentDAO:增删改查的SQL和参数绑定

DAO把SQL和业务逻辑隔离开,JSP里不写SQL,Servlet里不写SQL,SQL只出现在DAO层。学生管理最核心的四个操作是查询列表、新增、更新、删除,每个都对应一个方法。以新增和查询为例:

public class StudentDao { private DbUtils dbUtils = new DbUtils(); PreparedStatement ps = null; ResultSet rs = null; Connection conn = null; public List<Student> findAll(int page, int pageSize) { List<Student> list = new ArrayList<>(); String sql = "SELECT s.*, d.dept_name FROM tb_student s " + "LEFT JOIN tb_dept d ON s.dept_id = d.id " + "ORDER BY s.id DESC LIMIT ?, ?"; try { conn = dbUtils.getConnection(); ps = conn.prepareStatement(sql); ps.setInt(1, (page - 1) * pageSize); ps.setInt(2, pageSize); rs = ps.executeQuery(); while (rs.next()) { Student s = new Student(); s.setId(rs.getInt("id")); s.setStudentNo(rs.getString("student_no")); s.setName(rs.getString("name")); s.setDeptName(rs.getString("dept_name")); list.add(s); } } catch (SQLException e) { e.printStackTrace(); } finally { close(rs, ps, conn); } return list; } public int insert(Student s) { String sql = "INSERT INTO tb_student(student_no, name, gender, birthday, " + "phone, email, dept_id, enroll_date) VALUES(?,?,?,?,?,?,?,?)"; // 参数绑定、执行和关闭逻辑同上的模式 } }

PreparedStatement用?占位符,通过setInt、setString绑定参数,相比字符串拼接SQL的好处是防止SQL注入,比如用户名传' or '1'='1时不会拼出破坏性SQL;其次是MySQL会缓存预编译语句,多次执行同一条SQL时性能更好。查询列表用了LEFT JOIN关联院系表,这样前端可以直接取dept_name,不需要再查一次院系表。LIMIT ?, ?的第一个参数是偏移量,第二个是每页条数,分页的核心就这两行。

finally块里必须按ResultSet → PreparedStatement → Connection逆序关闭资源,顺序反了可能会出现连接泄漏。连接池里的连接用close()不是真的断开,而是还回池中,所以更要保证每条连接都走到close,否则池里的连接会被借完,项目跑一段时间后卡死。

4.3 分页查询:LIMIT参数、页码计算和JSP回显

分页是学生管理系统里老师最常追问的功能点,它的本质是「不要把全表数据一次性查出来放内存」。常见做法是前端传page(当前页)和pageSize(每页条数),后端算出偏移量(page-1)*pageSize,执行LIMIT查询。同时还需要一条SELECT COUNT(*)的SQL来算总页数。

Servlet端只需要把两个参数接住:

int page = 1; int pageSize = 10; try { page = Integer.parseInt(req.getParameter("page")); pageSize = Integer.parseInt(req.getParameter("pageSize")); } catch (NumberFormatException e) { // 参数缺失或非法时用默认值 }

这里必须用try-catch包住parseInt。用户手输一个page=abc,或者直接访问不带参数的URL,NumberFormatException会把整个请求打挂,页面直接500。用默认值兜底是课设项目里最容易加分的小细节。取到参数后调用DAO层查列表和总条数:

int total = studentDao.count(); int totalPages = (int) Math.ceil(total * 1.0 / pageSize); List<Student> list = studentDao.findAll(page, pageSize); req.setAttribute("list", list); req.setAttribute("currentPage", page); req.setAttribute("totalPages", totalPages); req.getRequestDispatcher("/student_list.jsp").forward(req, resp);

totalPages计算用的Math.ceil含义是向上取整:总数23条,每页10条,总页数是3而不是2。最后一页不足10条是正常的,不能因为查不到10条就报错。JSP页面里循环输出列表并生成分页导航:

<c:forEach items="${list}" var="s"> <tr> <td>${s.studentNo}</td> <td>${s.name}</td> <td>${s.deptName}</td> </tr> </c:forEach> <nav> <a href="${pageContext.request.contextPath}/student/list?page=${currentPage-1}">上一页</a> <span>${currentPage} / ${totalPages}</span> <a href="${pageContext.request.contextPath}/student/list?page=${currentPage+1}">下一页</a> </nav>

如果使用JSTL要在JSP页面顶部加<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>,并在pom.xml里引入jstl依赖。上一页链接当currentPage-1小于1时要禁用,下一页链接在currentPage+1大于totalPages时也要禁用,否则点到最后会查出一堆空数据。这里的pageContext.request.contextPath是JSP内置对象,等价于Servlet里的getContextPath(),用来拼项目根路径。

5. 避坑清单:JSP项目从404到中文乱码的5个典型翻车现场

5.1 中文全是问号:乱码问题不是一处配置能解决的

现象:页面能打开,但数据库里的中文显示成???,或者表单提交的中文存进库后变成乱码。

原因:乱码的根源是「请求编码、响应编码、页面编码、数据库编码」四个环节不一致。最常见的是:JSP文件本身是UTF-8,但浏览器提交请求时Tomcat默认用ISO-8859-1解码;数据库表用了latin1编码;或者是response.setContentType没设置,浏览器用默认编码解析页面。

解决:四个环节一次性理顺。数据库层建库时指定utf8mb4(第3章的建表语句里已经做了);数据源连接串加characterEncoding=utf8;JSP页面顶部设置统一的编码指令;Servlet接收参数前调用req.setCharacterEncoding("UTF-8")。关键是Servlet里这句必须在读取任何参数之前调用:

req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8");

另外一个隐藏点是Tomcat 9对GET请求参数的默认编码也是ISO-8859-1。如果表单用GET提交中文,光设setCharacterEncoding没用,需要改Tomcat的server.xml,在Connector上加URIEncoding="UTF-8"。或者更简单,所有表单强制用POST提交。

5.2 Tomcat启动报端口占用:分不清是8080被占还是项目重复部署

现象:启动Tomcat时控制台报Port 8080 required by Tomcat v9.0 Server at localhost is already in use,启动失败。

原因:本机已有进程占用8080端口,通常是上次Tomcat没正常关闭,或者IDE里的Tomcat实例没有停止就又启动了一次。

解决:先确认是谁占用了端口。Windows下执行:

netstat -ano | findstr 8080 taskkill /PID 进程号 /F

Linux或macOS用lsof -i:8080查看PID再kill -9。如果端口杀了还是报占用,检查IDEA里是不是有多个Tomcat实例在跑,全部停掉再重启。还有一种情况是war exploded和war两种deployment方式重复部署到同一个Context,报错信息类似deploy is in progress,这时在Deployment配置里只保留一种方式。

5.3 Communications link failure:驱动版本和连接参数一起背锅

现象:首次访问数据库时报Communications link failure,后面跟着一串The last packet successfully received from the server was...;有时还会提示Public Key Retrieval is not allowed。

原因:三种情况最常见。一是MySQL服务没启动,连接被拒绝;二是驱动版本和MySQL版本不匹配,比如用5.x的驱动连MySQL 8.0;三是连接串缺少8.0必需的参数,导致SSL握手失败或公钥获取被拒。

解决:先确认MySQL确实在运行,命令行执行mysql -uroot -p能进去再说。然后看驱动版本,Maven依赖里确认是mysql-connector-java8.0.x。最后把连接串补全,7个参数缺一不可:

"jdbc:mysql://localhost:3306/student_db" + "?useSSL=false" + "&allowPublicKeyRetrieval=true" + "&serverTimezone=Asia/Shanghai" + "&characterEncoding=utf8"

这个错误排查顺序不要反过来。很多人一看到Communications link failure就去改连接串,折腾半天发现是MySQL服务根本没启动,白花时间。

5.4 登录成功后跳回登录页:Session没存住还是Filter放行逻辑错了

现象:输入正确的用户名密码后,页面闪了一下又回到登录页,也没有报错提示。

原因:Filter的拦截逻辑把所有请求都拦了,登录成功后sendRedirect跳转到列表页,这个列表请求再次经过Filter时发现Session里没有loginUser,又给踢回登录页。更隐蔽的一种可能是登录成功页跳转用了相对路径,比如sendRedirect("student/list"),浏览器解析地址错误,落到一个不存在的URL上,被Filter当未登录处理。

解决:在LoginServlet里确认设置Session的属性名,和Filter里读取的名字完全一致。跳转一律使用req.getContextPath() + "/student/list"这种带上下文的绝对路径,不要用相对路径。排查时可以在Filter的拦截分支里加一行输出到控制台,打印被拦截的URI和Session内容,能很快定位是哪种情况。还有一种不太常见的原因是浏览器禁用了Cookie,Tomcat用JSESSIONID标识Session,Cookie被禁则每次请求都是新Session,手动放行Cookie或改用URL重写可以解决,但课设场景一般不用考虑。

5.5 部署后CSS和JS全部丢失:JSP里的相对路径坑

现象:本地用IDEA内置Tomcat跑,页面样式正常;打成War包部署到独立Tomcat后,样式和脚本全丢了,页面变成纯HTML文本排列。

原因:JSP里CSS引用的路径写成了css/style.css这种相对路径。浏览器解析相对路径时以当前页面URL的目录为基准。登录页在/student-management/login.jsp时,css/style.css解析为/student-management/css/style.css,没问题;但学生列表页在/student-management/student/list时,相对路径会解析成/student-management/student/css/style.css,这个路径不存在,CSS自然加载失败。

解决:所有静态资源引用必须加上项目上下文路径。在JSP页面顶部先定义上下文变量:

<c:set var="ctx" value="${pageContext.request.contextPath}" /> <link rel="stylesheet" href="${ctx}/css/style.css"> <script src="${ctx}/js/common.js"></script>

或者在Filter白名单里直接放行所有/css/和/js/前缀的请求。这个坑还有一个变体:页面用forward转发到JSP时,浏览器地址栏还停留在Servlet路径上,相对路径同样解析错误,统一用${ctx}前缀是治本的办法。

6. 打包War部署:把传统JSP项目交到别人机器上跑通

课设答辩到最后一公里,往往是要把项目部署到另一台电脑或服务器上演示。传统JSP项目的交付物就是War包。用Maven打包最省事,在项目根目录执行:

mvn clean package

然后到target目录下找到student-management.war,把它复制到Tomcat的webapps目录,启动Tomcat后它会自动解压部署。这里有一个细节:如果部署环境的Tomcat本来就在运行,复制War包后要等几秒让它自动解压,访问路径就是War包的文件名,即http://服务器IP:8080/student-management/。

如果想部署成根路径,把War包改名为ROOT.war再放到webapps下,访问时直接http://服务器IP:8080/即可。但要注意,原来的ROOT目录要提前删掉,否则Tomcat可能解压失败。部署完成后,按这个顺序验证系统是否真正可用:先访问登录页确认CSS加载正常;用admin账号登录,确认跳转到列表页;新增一条学生记录,确认MySQL里能查到;修改这条记录并删除,确认操作生效;翻到第二页再翻回来,确认分页参数没有串页。

最后说说我自己的习惯。每次做完这类JSP项目,我都会故意把环境版本降一档测试一次,比如把MySQL从8.0换成5.7跑一遍,把Tomcat从9换成8.5跑一遍。这个习惯帮我提前暴露了很多「本地能跑、换机器就崩」的问题,尤其是驱动版本和连接参数对环境的敏感度,能避免答辩前一天的深夜翻车。另一个教训是数据库脚本一定要单独存一份.sql文件放在项目里,不要只留在本地MySQL里,否则换机器部署时连建表语句都找不到。这套Java+JSP+MySQL的组合虽然不够新潮,但把这条链路走通之后,你再去学SpringBoot、MyBatis,理解映射和封装背后的原理会轻松得多。希望这篇笔记帮到你,少踩几个我当年踩过的坑。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询