简介:这是一套基于Java与MySQL开发的网上作业批改系统源码包,面向Java Web课程设计、毕业设计及需要练习增删改查与后台权限管理的初中级学习者。系统以简洁页面和友好错误提示为设计重点,管理员端覆盖班级、教师、学生、公告、留言、资料及管理员自身信息管理,支持录入、查询、删除、打印等常规操作,并兼顾基本的安全防护,适合用作教学演示、二次开发或课程作业参考。压缩包共265个文件,约1.93MB,包含45个jsp页面、24个java源文件与24个class编译文件、9个js脚本、6个css样式及1个sql数据库脚本,另有gif、png、jpg界面素材和少量doc、docx说明文档,结构完整,便于理解前后台交互与数据库设计。目前已有1615人学习下载,可作为Java Web入门项目拆解与功能扩展的实践样本。
1. 版本先对齐:网上作业批改系统这套 Java + MySQL 组合,八成翻车在版本上
上周帮 A 同学看他那套网上作业批改系统的安装问题,zip 解压出来目录完整,配置文件也在,可 Tomcat 窗口一闪就关,浏览器敲 8080 只给一个 404。他前后重装了三次,以为是包损坏,最后发现是机器上留着两个 JDK,JAVA_HOME 指到了 17,老项目的 class 文件按 52.0 编译,容器加载时直接抛 Unsupported major.minor version。这类 Java + MySQL 的作业批改系统在学校课程设计里实在太常见——教师端发作业、学生端提交、后台打分统计,功能不复杂,但对运行环境相当挑剔。装不好不是打不开首页那么简单,而是数据库连不上、中文全变问号、附件传上去打不开,一个比一个耗时间。下面这套流程,是我按“先对齐版本、再跑容器、再落数据库、最后调项目”的顺序整理出来的,适合第一次接触这类项目、手里只有一个 zip 包的人照着走。
2. 装 JDK 8 和 Tomcat 9:先把容器跑起来,别急着碰项目代码
这一章的思路很明确:在碰项目之前,先让一个空容器能正常返回页面。很多人反过来做,上来就把 war 包丢进去,出错时根本分不清是环境的问题还是项目的问题,排查起来像开黑匣子。先把 JDK 和 Tomcat 单独验证通过,后面所有报错都能定位到项目层面。
版本上我的建议是 JDK 8 配 Tomcat 8.5 或 9。这类基于 Servlet/JSP 的批改系统,绝大多数是五六年前的教学代码结构,用的还是javax.servlet包名,迁到 Tomcat 10 会直接因为包名改成jakarta.servlet而全线报 ClassNotFoundException。数据库那边对应 MySQL 5.7 最稳,8.0 也能跑,但驱动类和连接串参数得跟着改,后面单独说。
2.1 JDK 8 落地:路径、JAVA_HOME 和三个写错就白干的细节
安装包一路下一步没问题,问题全在环境变量。我一般把 JDK 装到一个不含空格、不含中文的路径下,比如D:\env\jdk1.8.0_202或/opt/jdk1.8.0_202。默认的C:\Program Files\Java\...在部分老脚本里会因为空格被截断,属于那种平时没事、关键时刻坑你一下的隐患。
Linux 或 macOS 下,环境变量写在~/.bashrc或/etc/profile里:
# JDK 8 环境变量,装在 /opt/jdk1.8.0_202 export JAVA_HOME=/opt/jdk1.8.0_202 export PATH=$JAVA_HOME/bin:$PATH # 老项目里偶尔有按 CLASSPATH 找 jar 的写法,一并补上更保险 export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar改完执行source ~/.bashrc让它生效。这三行的作用分别是:JAVA_HOME是给 Tomcat 的启动脚本读的,Tomcat 的setclasspath.sh会拿它去拼tools.jar和 JRE 路径,这一项没设,Linux 下启动脚本会直接退出;PATH是为了让java、javac命令在任何目录下都能敲;CLASSPATH现在多数情况用不上,但一些老的教学项目会在代码里硬写相对路径加载资源,补上不吃亏。
Windows 下不要手敲命令,走「此电脑 → 属性 → 高级系统设置 → 环境变量」,新建系统变量JAVA_HOME,值填D:\env\jdk1.8.0_202,注意不要带结尾反斜杠,也不要带\bin——这是最常见的两个写错法,带了\bin之后 Tomcat 会去找D:\env\jdk1.8.0_202\bin\bin\java.exe,报错信息还特别含糊。
配完必须开一个新的命令行窗口验证,老窗口读的是旧环境变量:
java -version # 期望输出:java version "1.8.0_202" javac -version # 期望输出:javac 1.8.0_202两条命令的版本号必须一致。如果java -version是 1.8 而javac -version是 17,说明 PATH 里还有另一个 JDK 排在前面,去where java(Windows)或which java(Linux)看一眼顺序,把多余的那条删掉。这种“版本打架”是最典型的玄学问题来源,表现是编译能过、运行报错,或者反过来。
2.2 Tomcat 9 解压式安装:端口、URIEncoding 与启动脚本
Tomcat 不需要安装,解压即用。我习惯解到D:\env\apache-tomcat-9.0.x或/opt/tomcat9,同样避开空格和中文。解压后第一件事不是启动,是改conf/server.xml里的 Connector:
<!-- conf/server.xml,找到 8080 那个 Connector --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" URIEncoding="UTF-8" redirectPort="8443" />这里只加了一个URIEncoding="UTF-8"。别小看这一行:Tomcat 8 之后 GET 请求默认解码用的是 UTF-8,但不少老配置文件是从 Tomcat 7 时代抄过来的,里面写着URIEncoding="ISO-8859-1",结果就是表单 POST 提交的中文正常,地址栏带参数的查询、搜索框里的中文全变问号。批改系统里按学生姓名搜索作业是高频操作,这个坑基本必踩。
port如果 8080 被占用(后面章节会讲怎么查),可以改成 8081、9090,但改完记得同步项目里所有写死端口的配置,包括一些硬编码的图片地址。
启动脚本:Windows 用bin\startup.bat,Linux 用bin/startup.sh。Linux 下还需要给脚本加执行权限:
chmod +x /opt/tomcat9/bin/*.sh /opt/tomcat9/bin/startup.sh # 查看启动日志,确认最后出现 Server startup in xxx ms tail -f /opt/tomcat9/logs/catalina.outstartup.sh实际上会去调catalina.sh start,它依赖JAVA_HOME或JRE_HOME,两个都没有就会打印Neither the JAVA_HOME nor the JRE_HOME environment variable is defined然后退出。看到这句话不用怀疑 Tomcat 包坏了,回去检查第 2.1 节的环境变量。
catalina.out是整个部署过程中最重要的文件,几乎所有启动异常、数据库连接失败、类找不到的堆栈都会落在这里。养成部署前先tail -f开着它的习惯,比事后翻日志省一半时间。
2.3 用一张静态页验证容器,别用项目本身试错
Tomcat 起来后,先别放项目,放一张自己写的测试页。在webapps下建目录webapps/probe,里面放一个index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <% // 打印当前 JVM 与容器信息,确认跑的是哪个 JDK、哪个 Tomcat out.println("JVM: " + System.getProperty("java.version") + "<br/>"); out.println("编码: " + response.getCharacterEncoding() + "<br/>"); out.println("中文测试:作业批改系统"); %>访问http://127.0.0.1:8080/probe/index.jsp。这一页能同时验证四件事:容器是否启动成功、JSP 是否被正确编译、当前 JVM 版本是否真的是 1.8、中文是否正常显示。如果 JSP 里那行中文变成了??????,说明response的编码链路有问题,但至少容器是活的,问题范围就缩小到了编码配置。
用127.0.0.1而不是localhost也有讲究。某些机器上localhost会先解析到 IPv6 的::1,而 Tomcat 默认只在 IPv4 的 0.0.0.0 上监听,结果是浏览器转半天最后连接被拒。这个现象特别迷惑人,因为 ping localhost 是通的。遇到“Tomcat 明明启动了但浏览器打不开”,先换127.0.0.1试一次,能省下半小时。
三件事都通过,容器这一层就算干净了。后面项目出任何问题,都可以放心地怀疑项目配置,而不是环境。
3. MySQL 5.7 落地:建库、导脚本、开账号三步走
数据库这一层是这类项目最容易埋雷的地方。批改系统的数据表不算多——用户表、作业表、提交记录表、评分表,撑死十几张——但脚本里往往带着建库语句、字符集声明和初始账号数据,一个环节对不上,登录就进不去。我的做法是:安装完先改配置,再用命令行导脚本,最后单独开一个业务账号,三步都不省。
3.1 安装后的第一件事:把字符集和时区写进配置文件
装完 MySQL 5.7,先找到配置文件。Windows 下通常是安装目录里的my.ini,Linux 下是/etc/my.cnf。在[mysqld]段落下补这几行:
[mysqld] # 服务端默认字符集,utf8mb4 才是真正的四字节 UTF-8 character-set-server=utf8mb4 collation-server=utf8mb4_general_ci # 时区固定为东八区,避免 Java 取到的时间差 8 小时 default-time-zone='+08:00' # 关闭严格模式之外不用动,但大小写敏感要注意 lower_case_table_names=1 [client] default-character-set=utf8mb4逐条说明。character-set-server选utf8mb4而不是utf8,因为 MySQL 里的utf8其实是三字节的残废版本,存不下 emoji 和部分生僻字。学生提交作业时如果带了这些字符,插入会直接报Incorrect string value,整条记录写不进去。utf8mb4_general_ci里的ci表示比较时不区分大小写,登录账号密码校验依赖这个行为,换成_bin会导致大小写不一致的账号登不进去。
default-time-zone='+08:00'这一行是血泪经验。MySQL 默认用系统时区,容器化环境或某些云主机上系统时区是 UTC,Java 端new Date()拿到的是本地时间,写进库里再读出来就差了 8 小时。表现是学生下午三点提交的作业,教师端显示成早上七点,按时间排序的全乱了。加这一行比在连接串里写serverTimezone更彻底。
lower_case_table_names=1让表名比较不区分大小写。SQL 脚本里写的是Homework,Java 代码里查的是homework,在 Linux 上 MySQL 默认区分大小写,直接就报表不存在。这个参数必须在初始化数据目录之前设定,装完再改需要重装实例,属于“没有后悔药”的配置,第一次装就写上。
改完配置必须重启服务:net stop mysql && net start mysql(Windows)或systemctl restart mysqld(Linux)。然后验证:
SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'time_zone'; SHOW VARIABLES LIKE 'lower_case_table_names';三行查询的返回值分别应该是utf8mb4、+08:00、1。对不上就是配置文件没被读到——Windows 下常见原因是配置文件放在了错误目录,MySQL 实际读的是C:\ProgramData\MySQL\MySQL Server 5.7\my.ini,可以用SELECT @@datadir;定位。
3.2 导入 .sql 脚本:命令行比双击可靠
zip 包里通常有个db或sql目录,放着建库建表的.sql文件。我见过太多人用图形工具双击打开再点执行,结果中文注释变乱码、部分语句被跳过的。命令行导一遍,可控性高得多。
先看一眼脚本开头有没有CREATE DATABASE:
# 大致扫一下脚本结构,确认是否自带建库语句、用的什么字符集 head -n 30 homework_db.sql grep -i "create database\|charset" homework_db.sql | head -n 5如果脚本自带CREATE DATABASE,直接导即可;如果没有,先自己建库再导:
# 建库,显式指定字符集,和 3.1 的配置保持一致 mysql -uroot -p -e "CREATE DATABASE homework_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" # 导入脚本,--default-character-set 必须写,否则按客户端默认字符集解析 mysql -uroot -p --default-character-set=utf8mb4 homework_db < homework_db.sql--default-character-set=utf8mb4这个参数不能省。它决定了 MySQL 客户端如何解释脚本文件的字节流,不写的话客户端可能用 GBK 或 latin1 去解析一个 UTF-8 编码的脚本,结果是表建出来了,但初始的管理员账号名、班级名称全是乱码,登录时怎么输都提示密码错误——因为用户名字段本身就是乱码,和你输入的对不上。
导入完成后验证表数量和数据:
USE homework_db; SHOW TABLES; -- 表数量应该和脚本里的 CREATE TABLE 条数一致 SELECT COUNT(*) FROM t_user; -- 随便查一张有初始数据的表,看中文是否正常 SELECT * FROM t_user LIMIT 5;如果SHOW TABLES出来的表名是乱码,或者表是空的但脚本明明有 INSERT 语句,回去检查脚本文件本身的编码。用file -i homework_db.sql看它到底是不是 UTF-8,有些包里的脚本是从 Windows 记事本另存的,带 BOM 头,MySQL 客户端解析第一行会报语法错误,用sed -i '1s/^\xEF\xBB\xBF//' homework_db.sql去掉 BOM 再导一次。
3.3 给项目开一个专用账号,别让 root 裸奔
连接串里直接写 root 是这类项目的通病,本地跑没事,一旦放到共享环境就是事故。我的习惯是建一个只对业务库有增删改查权限的账号:
-- 建业务账号,host 用 localhost 表示只允许本机连接 CREATE USER 'hw_app'@'localhost' IDENTIFIED BY 'Hw@2024#app'; -- 只给业务库的 DML 权限,不给 DROP、ALTER GRANT SELECT, INSERT, UPDATE, DELETE ON homework_db.* TO 'hw_app'@'localhost'; FLUSH PRIVILEGES;参数上要说清楚几点。'hw_app'@'localhost'中的 host 部分决定了允许从哪连:写localhost走的是 Unix socket 或命名管道,写127.0.0.1走 TCP,写%允许任意来源。Java 的 JDBC 驱动走的是 TCP,所以连接串里如果写127.0.0.1,账号的 host 就必须是127.0.0.1或%,否则报Access denied for user 'hw_app'@'localhost'——注意报错里的 host 会变成 localhost,因为驱动反查了。这个错在部署时出现的频率极高,遇到先查账号的 host 匹配。
只给四个 DML 权限是有意为之。批改系统正常运行不需要改表结构,万一代码里有地方误执行了DROP TABLE,没权限直接失败,比事后恢复数据划算。但要注意,如果项目带自动建表逻辑(有些框架启动时会执行 schema 脚本),第一次启动会因为缺CREATE权限失败,这种情况临时补一条GRANT CREATE, ALTER, INDEX ON homework_db.* TO 'hw_app'@'localhost';,跑起来之后可以再收回去。
密码里带#或@这类特殊字符时,在连接串里要么 URL 编码,要么干脆换成纯字母数字加下划线。#在 properties 文件里会被当成注释起始符,写进去之后密码后半截直接被吞掉,报的还是“密码错误”,查半天查不出来。
验证账号能连:
mysql -uhw_app -p'Hw@2024#app' -h127.0.0.1 -P3306 homework_db -e "SELECT 1;"能返回一行1就说明账号、host、权限、端口全对上了。这一步单独验证,比等部署完项目再去猜连接串有没有问题高效得多。
4. 部署配置:jdbc.properties 的四个参数与 war 包落地
环境层通了,剩下的是把项目接上去。批改系统的部署配置集中在两个地方:数据源配置文件和 war 包的放置方式。前者改错一个字符就连不上库,后者放错位置就是 404。
4.1 数据源四行参数,改错的都是细节
项目里通常有个jdbc.properties或db.properties,在src/main/resources或WEB-INF/classes下。内容大致是这样:
# 驱动类名,MySQL 5.7 用 com.mysql.jdbc.Driver jdbc.driver=com.mysql.jdbc.Driver # 连接串:库名、时区、编码、SSL 四个参数都要照顾到 jdbc.url=jdbc:mysql://127.0.0.1:3306/homework_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true jdbc.username=hw_app jdbc.password=Hw@2024#app逐段拆开看。com.mysql.jdbc.Driver是 MySQL 5.1.x 驱动的类名,如果用的是 8.0 的驱动 jar,类名要换成com.mysql.cj.jdbc.Driver,否则启动时报Loading class 'com.mysql.jdbc.Driver'. This is deprecated之后连接失败。判断用哪个的办法很简单:看WEB-INF/lib下那个 mysql-connector 的 jar 文件名,带5.1的用老类名,带8.0的用新类名。
连接串里的useUnicode=true&characterEncoding=utf8是一对,缺一个都可能出现写入正常、读取乱码的情况。useSSL=false在 MySQL 5.7 上不写会打一堆警告,在 8.0 上不写可能因为证书握手失败直接连不上。serverTimezone=Asia/Shanghai配合库端的default-time-zone双重保险,只配一边也够,但两边都配能避免容器时区漂移带来的问题。allowPublicKeyRetrieval=true只在 MySQL 8.0 的caching_sha2_password认证方式下才需要,5.7 写了也无害。
改这个文件有两个原则。第一是备份原文件,改成.bak放旁边,出问题直接换回来。第二是注意WEB-INF/classes下也可能有一份编译后的旧配置,如果项目是别人打好包给你的,改完src里的不生效,很可能是容器加载的是classes下那份。这种情况我一般直接把两边都改一遍,省得排查。
4.2 打包成 war 丢进 webapps,还是 IDE 里配 Tomcat
两种部署方式,看手里有没有源码。
有源码、用 Maven 管理的话,命令行打包最干净:
cd /opt/project/homework-system # 跳过测试,教学项目里的单元测试经常连的是写死的库,跑不过 mvn clean package -Dmaven.test.skip=true # 打出来的 war 在 target 下,复制到 webapps 并改名 cp target/homework-system-1.0.war /opt/tomcat9/webapps/homework.war改名的意义在于访问路径。war 包名就是上下文路径,叫homework.war就访问http://127.0.0.1:8080/homework/,叫homework-system-1.0.war就得访问/homework-system-1.0/,长且容易输错。改成短名省事。Tomcat 启动时会自动解压 war 包成同名目录,日志里出现Deploying web application archive [/opt/tomcat9/webapps/homework.war]就说明在部署了。
没有源码、只有 war 包的话更简单,直接丢进去重启。但要注意删掉旧的解压目录:
# 重新部署前,先清掉旧的解压目录,否则新 war 可能不生效 rm -rf /opt/tomcat9/webapps/homework rm -rf /opt/tomcat9/work/Catalina/localhost/homework cp homework.war /opt/tomcat9/webapps/work目录下放的是 JSP 编译后的 servlet 源码和 class,不清的话改了 JSP 页面刷新还是老的。这是“改了代码没反应”最常见的原因,比缓存还顽固。
用 IDE 的话,配置 Tomcat 运行时指向解压目录,部署方式选 exploded artifact,好处是改 JSP 立即生效,不用反复打包。但 IDE 里的配置和命令行启动的配置是两套,环境变量、catalina.base都可能不同,出问题时先确认自己到底是哪套在跑。
4.3 附件上传目录与日志目录:两个部署后才想起来的地方
批改系统必然有附件上传——学生交的作业文档、教师批改后的回传文件。这类目录的坑在于:在 IDE 里跑的时候路径是相对工程目录的,打成 war 部署后当前工作目录变成了 Tomcat 的bin,路径全错。
常见做法是在配置文件里单独指定一个绝对路径,比如:
# 上传根目录,部署后必须存在且可写 upload.root=/opt/homework/upload # 单文件大小上限,单位 MB upload.maxSize=20然后建目录并给权限:
mkdir -p /opt/homework/upload # Tomcat 以哪个用户跑,就给哪个用户写权限 chown -R tomcat:tomcat /opt/homework/upload chmod 755 /opt/homework/upload权限不对的表现很有特点:页面上传按钮点了没反应,或者提示“上传成功”但列表里没有文件,去catalina.out里能找到java.io.FileNotFoundException: /opt/homework/upload/xxx (Permission denied)。Windows 下没有权限概念,但会有另一个问题——路径里写反斜杠,在 properties 文件里被当成转义字符吃掉,D:\upload变成D:upload,目录不存在。统一用正斜杠D:/upload就没事。
日志目录同样要单独看。Tomcat 的日志在logs/下分好几个文件:catalina.out是标准输出和错误的汇总,localhost.log是应用级异常,localhost_access_log是访问记录。项目里如果配了 log4j 或 logback,日志可能落到WEB-INF/logs或者某个绝对路径下,部署后找不到日志别急着说没日志,先find / -name "*.log" -mmin -10扫一遍最近修改过的。
5. 避坑记录:五个把我按在工位上重装的现象
下面这五条,是我在装这类批改系统时反复遇到的。每条按现象、原因、解决三段写,遇到对应症状可以直接对号。
5.1 现象一:登录页中文全是问号,英文正常
现象:页面能打开,布局正常,但所有中文标签显示成??????或登录。
原因:编码链路中有一环没对齐。可能是 JSP 页面没写pageEncoding,可能是 Tomcat 的 Connector 没配URIEncoding,也可能是数据库连接串缺characterEncoding,还可能是响应头里的Content-Type没带 charset。这四环任意一环错,中文就废。
解决:按链路顺序查。先看浏览器开发者工具里响应头的Content-Type有没有charset=UTF-8,没有就查 JSP 顶部的<%@ page contentType="text/html;charset=UTF-8" %>。然后看 POST 表单提交的中文是否正常,正常说明请求编码没问题;GET 参数乱码则回到server.xml补URIEncoding="UTF-8"。最后查数据库,SHOW VARIABLES LIKE 'character_set%'看服务端、连接、结果三个字符集是不是都为utf8mb4,有latin1的按第 3.1 节改配置重启。
5.2 现象二:Communications link failure,服务明明起着
现象:项目启动时报Communications link failure或Could not create connection to database server,但用命令行mysql -u... -p能正常连上。
原因:三个可能。一是 JDBC 连接串里的端口写错,比如写成 3306 但实际实例跑在 3307;二是账号的 host 匹配不上,命令行走 socket、JDBC 走 TCP,'hw_app'@'localhost'有时候不放行 TCP 连接;三是 MySQL 8.0 的认证插件caching_sha2_password与老驱动不兼容。
解决:先确认端口,SHOW VARIABLES LIKE 'port';查一下真实端口。再把账号 host 改成127.0.0.1或%试一次,能连上就说明是 host 匹配问题。还不行就看驱动版本,WEB-INF/lib下的 connector 是 5.1.x 而库是 8.0 的话,要么换 8.0 驱动,要么把账号认证方式改回mysql_native_password:ALTER USER 'hw_app'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Hw@2024#app';。报错堆栈里如果带Public Key Retrieval is not allowed,在连接串补allowPublicKeyRetrieval=true即可。
5.3 现象三:404 和 500 白页,处理方式完全不同
现象:访问地址后要么是 Tomcat 自带的 404 页面,要么是 500 白页只有一行HTTP Status 500 - Internal Server Error。
原因:404 是路径问题,容器根本没找到这个应用或这个资源。常见于 war 包名和访问路径不一致、web.xml里的url-pattern写错、或者部署目录没解压成功。500 是应用内部抛异常,代码或配置执行到一半崩了,容器已经把请求交给应用了。
解决:404 先看webapps目录下有没有解压出来的同名文件夹,没有就看catalina.out里有没有Deploying失败的记录,常见是 war 包损坏或web.xml语法错误。确认目录存在但还 404,检查访问路径的大小写,Linux 下路径区分大小写。500 直接去localhost.log和catalina.out里找Caused by:,从最下面那条开始看,通常第一条只是包装异常,根因在最后。
5.4 现象四:Tomcat 窗口一闪而过,或者 8080 起不来
现象:Windows 下双击startup.bat,黑窗口闪一下就没了;Linux 下启动脚本执行完,ps里没有 java 进程。
原因:闪退基本是环境变量问题,JAVA_HOME没设或指向错误。8080 起不来则是端口被占用,或者 Connector 配置语法错误导致解析失败。
解决:闪退不要双击,开一个 cmd 窗口,cd到bin目录手动执行startup.bat,错误信息会留在窗口里。看到Neither the JAVA_HOME nor the JRE_HOME environment variable is defined就回去配环境变量。端口问题用netstat -ano | findstr :8080(Windows)或lsof -i:8080(Linux)查占用进程,杀掉或者改端口。还有一种情况是权限问题,Linux 下非 root 用户不能绑 1024 以下端口,但 8080 不受此限,这条一般不成立,别被误导。
5.5 现象五:交作业时间差 8 小时,附件传上去打不开
现象:学生提交作业后,教师端列表里显示的时间比实际早了 8 小时;或者文件上传显示成功,点下载提示 404 或文件损坏。
原因:时间问题是数据库时区和 JVM 时区不一致,一个 UTC 一个东八区。附件问题通常是上传目录用了相对路径,运行时的当前目录不是预期的那个;或者文件大小超过 Tomcat 的maxPostSize,被截断后仍然返回成功。
解决:时间问题按第 3.1 节在my.ini里固定default-time-zone='+08:00',同时连接串带serverTimezone=Asia/Shanghai,两处对齐。附件问题先把上传路径统一定义成绝对路径,再检查server.xml的 Connector 是否配了maxPostSize(默认 2MB,作业文档轻松超),需要写成maxPostSize="52428800"表示 50MB,同时maxSwallowSize="-1"避免大文件被容器吞掉。改完重启,再传一次 20MB 的文档验证。
6. 装完怎么验证:从登录到批改,三条链路依次打通
环境都配好之后,很多人打开首页看到登录框就认为装完了,结果一用就出问题。我的习惯是按业务链路走一遍,从下往上验证,每条链路都留一个明确的成功标志。
第一条链路是数据库到应用。不看页面,直接看容器日志:项目启动后catalina.out里应该出现连接池初始化的记录,没有Communications link failure、没有Access denied。如果用的是 Druid 或 HikariCP,日志里会有initialSize相关的行。这条链路过了,才说明第 3、4 章的配置真的生效了。
第二条链路是账号到权限。用初始管理员账号登录,能进后台就说明用户表读到了、密码校验逻辑通了、会话写进去了。然后立刻做一件容易被忽略的事:新建一个学生账号,用它登录,提交一份带中文文件名和中文内容的作业。这一步同时验证了写入权限、字符集、上传目录三件事,比单独测每一项效率高得多。
第三条链路是完整业务流。教师账号登录,发布一条作业,设置截止时间;学生账号提交;教师端看到提交记录,打分,写评语;学生端看到分数和评语。这条走完,整个系统才算真的跑通。
| 验证项 | 操作 | 通过标准 | 失败时先查 |
|---|---|---|---|
| 容器存活 | 访问/probe/index.jsp | 显示 JVM 1.8、中文正常 | catalina.out启动日志 |
| 数据库连通 | 重启 Tomcat | 无连接异常堆栈 | 连接串、账号 host、端口 |
| 登录 | 初始管理员登录 | 进入后台首页 | t_user表数据、密码加密方式 |
| 中文写入 | 学生提交中文作业 | 教师端显示原文,无乱码 | 库字符集、JSP 编码、Connector |
| 附件上传 | 传一个 20MB 文档 | 可下载且内容完整 | 上传目录权限、maxPostSize |
| 时间显示 | 提交后看列表时间 | 与本地时间一致 | 库时区、serverTimezone |
| 批改闭环 | 教师打分写评语 | 学生端可见 | 评分表关联字段 |
有一件事我吃过亏:验证完不要立刻把probe目录和测试账号删掉。系统跑一段时间后如果出问题,这两个东西是最好的对照物——probe能立刻判断是容器挂了还是应用挂了,测试账号能判断是权限问题还是数据问题。留着它们,成本几乎为零。
从那以后我每次装这类 Java + MySQL 的批改系统,都强制把这三条链路走一遍再交付,哪怕对方催得再急。跳过验证省下的二十分钟,后面往往要用两个晚上来还。希望这套流程能帮你少走几段弯路。
本文还有配套的精品资源,点击获取