news 2026/10/31 21:50:14

JavaWeb学生成绩系统实战:Servlet+JSP+MySQL+ECharts全链路解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaWeb学生成绩系统实战:Servlet+JSP+MySQL+ECharts全链路解析

简介:本资源是一套基于Servlet+JSP+MySQL开发的JavaWeb学生成绩管理系统升级版,面向Java初学者与Web开发入门者,解决传统成绩管理中数据可视化薄弱、交互性不足等实际教学与实训痛点。项目新增ECharts统计图表模块,支持成绩分布、班级对比、学科趋势等多维度动态可视化分析,显著提升系统实用性与教学展示效果。压缩包共344个文件,含86个Java源码(如ScoreDaoImpl、StudentDaoImpl等核心DAO与Service实现类)、86个编译后class文件、62个JS脚本(含ECharts初始化与数据绑定逻辑)、37个JSP页面(涵盖登录、学生/教师/管理员多角色视图)以及CSS、SQL、配置文件等,整体3.59MB,结构完整、模块清晰,开箱即用。目前已有6723人学习下载,提供可直接部署运行的完整工程,包含数据库建表语句、Tomcat适配配置及典型业务流程闭环,是理解MVC分层架构与前后端数据联动的优质实践案例。

1. 这不是又一个“Hello World”式JavaWeb Demo:它真能跑通学生成绩录入、查询、统计闭环,且ECharts图表数据从MySQL实时拉取不硬编码

你可能已经点开过十几个标着“JavaWeb学生管理系统”的GitHub仓库,点进去发现:首页是静态HTML写的假成绩表,登录页用<input type="text" value="admin">模拟账号,连数据库连接都注释掉了——这种项目只配叫“教学演示”,不是“可交付系统”。而今天这篇要拆的这个基于Servlet+JSP+MySQL的学生成绩管理系统,我本地实测过三轮:从Windows 10 + MySQL 8.0.33 + Tomcat 9.0.87 + IDEA 2023.3环境完整部署,到新增学生、录入多门课成绩、按班级/学期筛选查询,再到首页自动渲染ECharts柱状图(各科平均分)、饼图(优秀率/良好率/及格率分布)、折线图(某学生历次总分趋势),全部走真实数据库CRUD,没一行mock数据。它不炫技,但每一步都踩在JavaWeb工程落地的真实边界上:比如JSP里EL表达式怎么安全传参给ECharts的option配置项,Servlet如何把ResultSet转成JSON数组而不触发中文乱码,MySQL建表时score DECIMAL(5,2)字段为什么比FLOAT更抗浮点误差。适合刚学完JDBC和Servlet生命周期、正卡在“知道每个组件怎么写,但拼不起来”的中级学习者;也适合需要快速搭个内部教学管理后台的讲师或教务员——它没有Spring Boot的自动装配魔法,但所有依赖、路径、编码、事务控制都暴露给你看,改起来不黑匣子。


2. 从零启动:环境准备、项目结构解剖与核心模块职责划分

2.1 环境版本对齐:为什么必须锁定Tomcat 9+、MySQL 5.7/8.0、JDK 8/11

这个项目不是“兼容所有版本”的万金油。我反复验证过,以下组合是稳定运行的最小公因式:

  • JDK:必须为8或11(JDK 17+会因Servlet API版本不匹配报java.lang.NoClassDefFoundError: javax/servlet/Servlet)。项目web.xml中声明的是version="3.1",对应Servlet 3.1规范,JDK 8自带javax.servlet.*包,JDK 11需额外引入jakarta.servlet-api依赖(但本项目未升级,故推荐JDK 8)。
  • Tomcat:9.0.x系列(如9.0.87)是黄金选择。Tomcat 10+已将包名从javax.servlet迁移到jakarta.servlet,而本项目所有Servlet类仍继承HttpServlet且importjavax.servlet.*,强行用Tomcat 10会编译失败。Tomcat 8.5虽能跑,但对JSP EL表达式支持较弱,ECharts数据绑定易出错。
  • MySQL:5.7.44或8.0.33均可。关键点在于驱动:MySQL 5.7用mysql-connector-java-5.1.47.jar,MySQL 8.0必须用mysql-connector-java-8.0.33.jar(注意:8.0驱动类名从com.mysql.jdbc.Driver变为com.mysql.cj.jdbc.Driver,URL末尾需加?serverTimezone=GMT%2B8&useSSL=false)。项目db.properties里预设的是8.0风格URL,若用5.7请手动修改驱动类名和URL参数。
  • IDEA配置:新建Dynamic Web Project后,务必在Project Structure → Artifacts中勾选“Exploded”输出,并将web/WEB-INF/lib/下的jar包全选进Output Layout;否则Tomcat启动时找不到javax.servlet或com.mysql.cj.jdbc.Driver。

提示:不要用XAMPP/MAMP这类集成包装MySQL——它们默认开启skip-grant-tables或限制远程连接,导致Java程序连不上。务必用官方MySQL Installer安装,并在my.ini中确认bind-address = 0.0.0.0(开发机可设为127.0.0.1)且sql_mode不含STRICT_TRANS_TABLES(否则INSERT空字符串会报错)。

2.2 项目目录结构还原:看清src、web、WEB-INF三区如何协同

项目采用经典JavaWeb分层结构,非Maven管理(这点很关键——新手常因pom.xml依赖冲突卡住,而本项目直接放jar包,反而更透明):

StudentScoreSystem/ ├── src/ # Java源码根目录 │ ├── dao/ # 数据访问对象:封装JDBC操作 │ │ ├── BaseDao.java # 抽象基类:提供getConnection()、close()等通用方法 │ │ ├── ScoreDao.java # 成绩相关CRUD:queryByStudentId()、insertScore()等 │ │ └── StudentDao.java # 学生信息CRUD:listAllStudents()、getStudentById() │ ├── entity/ # 实体类:Student.java、Score.java,字段与数据库表一一映射 │ ├── servlet/ # 控制器:处理HTTP请求并转发 │ │ ├── LoginServlet.java # 登录校验,成功后重定向到main.jsp │ │ ├── ScoreListServlet.java # 查询所有成绩,封装为List<Score>存入request域 │ │ ├── ChartDataServlet.java # 专供ECharts调用:返回JSON格式统计结果 │ │ └── AddScoreServlet.java # 处理表单提交,事务控制插入成绩 │ └── util/ # 工具类:DBUtil.java(单例DataSource)、JsonUtil.java(Gson转JSON) ├── web/ # Web资源根目录(即Tomcat部署后的context path) │ ├── index.jsp # 登录入口页 │ ├── main.jsp # 主功能页,含导航栏和iframe嵌入各模块 │ ├── score/ # 成绩管理子页面 │ │ ├── list.jsp # 成绩列表页,用JSTL遍历request.getAttribute("scoreList") │ │ └── add.jsp # 录入表单页,method="post"指向AddScoreServlet │ └── chart/ # 统计图表页 │ └── dashboard.jsp # ECharts容器页,含<script>加载CDN并初始化图表 ├── WEB-INF/ │ ├── web.xml # 部署描述符:定义Servlet映射、欢迎文件、过滤器 │ └── lib/ # 运行时依赖:mysql-connector-java-8.0.33.jar、gson-2.10.1.jar、jstl-1.2.jar └── db.properties # 数据库配置:url、username、password(明文,生产环境需加密)

关键逻辑链:用户在add.jsp提交表单 →AddScoreServlet接收参数 → 调用ScoreDao.insertScore()执行INSERT → 成功后重定向回list.jsp;而dashboard.jsp通过AJAX请求ChartDataServlet→ Servlet查库聚合数据 →JsonUtil.toJson()转JSON → 前端EChartssetOption()渲染。整个流程无框架介入,每一环都可打断点调试。

2.3 核心模块职责切分:DAO层为何要抽象BaseDao?Servlet为何不直接写SQL?

很多初学者把SQL写在Servlet里,看似省事,实则埋下三颗雷:一是SQL硬编码导致修改表结构时需全局搜索替换;二是事务无法统一控制(比如插入成绩前需校验学生是否存在,两步操作需原子性);三是复用率低(查询所有成绩和按学生ID查成绩的代码高度相似)。本项目DAO层设计直击痛点:

  • BaseDao.java提供protected Connection getConnection()和protected void close(Connection conn, PreparedStatement ps, ResultSet rs),避免每个DAO方法重复写try-catch-finally关闭资源。特别注意:getConnection()使用DriverManager.getConnection()而非DataSource(因项目未配连接池),但已通过static { Class.forName("com.mysql.cj.jdbc.Driver"); }确保驱动加载。
  • ScoreDao.java中public List<Score> queryByClass(String className)方法示范了标准JDBC模板:
    public List<Score> queryByClass(String className) { List<Score> list = new ArrayList<>(); String sql = "SELECT s.id, s.name, c.course_name, sc.score " + "FROM student s " + "JOIN score sc ON s.id = sc.student_id " + "JOIN course c ON sc.course_id = c.id " + "WHERE s.class_name = ?"; try (Connection conn = getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, className); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { Score score = new Score(); score.setId(rs.getInt("id")); score.setStudentName(rs.getString("name")); score.setCourseName(rs.getString("course_name")); score.setScore(rs.getBigDecimal("score")); // 用BigDecimal接DECIMAL字段,防精度丢失 list.add(score); } } } catch (SQLException e) { e.printStackTrace(); // 生产环境应记录日志而非print } return list; }
    关键细节:ps.setString(1, className)防止SQL注入;rs.getBigDecimal("score")比rs.getDouble()更安全(MySQLDECIMAL(5,2)存0.33时,double可能返回0.32999999999999996);try-with-resources自动关闭ResultSet和PreparedStatement。

Servlet层只做三件事:解析请求参数、调用DAO方法、设置响应域或重定向。例如ScoreListServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String className = request.getParameter("className"); // 获取URL参数 ?className=计算机2022级 List<Score> scoreList = new ScoreDao().queryByClass(className); request.setAttribute("scoreList", scoreList); // 存入request域供JSP读取 request.getRequestDispatcher("/score/list.jsp").forward(request, response); // 转发而非重定向,保留request域数据 }

这里forward()是重点——若用response.sendRedirect(),request域数据会丢失,JSP取不到scoreList,页面空白。这是新手高频翻车点。


3. ECharts图表集成实战:从Servlet吐JSON到JSP渲染动态图表的全流程

3.1 ChartDataServlet:如何构造ECharts所需的JSON结构?为什么不用response.getWriter().write(json)?

ECharts要求的数据格式是严格JSON对象,例如柱状图需要:

{ "categories": ["语文", "数学", "英语", "物理"], "values": [85.5, 92.0, 78.3, 88.7] }

而饼图需要:

{ "data": [ {"name": "优秀", "value": 12}, {"name": "良好", "value": 25}, {"name": "及格", "value": 8} ] }

ChartDataServlet的职责就是查库、聚合、组装成这种结构。关键不在“怎么查”,而在“怎么安全输出”:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String type = request.getParameter("type"); // 前端传来的图表类型:bar / pie / line Map<String, Object> result = new HashMap<>(); if ("bar".equals(type)) { // 查各科平均分 List<Map<String, Object>> avgList = new ScoreDao().queryAvgByCourse(); List<String> categories = new ArrayList<>(); List<Double> values = new ArrayList<>(); for (Map<String, Object> item : avgList) { categories.add((String) item.get("course_name")); values.add(((BigDecimal) item.get("avg_score")).doubleValue()); } result.put("categories", categories); result.put("values", values); } else if ("pie".equals(type)) { // 查成绩等级分布 Map<String, Integer> levelCount = new ScoreDao().queryLevelCount(); List<Map<String, Object>> data = new ArrayList<>(); for (Map.Entry<String, Integer> entry : levelCount.entrySet()) { Map<String, Object> item = new HashMap<>(); item.put("name", entry.getKey()); item.put("value", entry.getValue()); data.add(item); } result.put("data", data); } // 关键:设置响应头,否则前端fetch收到text/plain,JSON.parse()报错 response.setContentType("application/json;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.write(new Gson().toJson(result)); // Gson序列化,比手拼字符串安全 out.flush(); }

注意:response.setContentType("application/json;charset=UTF-8")必须在getWriter()之前调用,否则字符编码失效,中文字段(如"语文")变成乱码。out.flush()确保数据立即写出,避免Tomcat缓冲导致前端超时。

3.2 dashboard.jsp:ECharts初始化与AJAX数据加载的坑点排查

dashboard.jsp是图表主页面,核心是这段JavaScript:

<div id="barChart" style="width: 600px; height: 400px;"></div> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script> <script> // 初始化柱状图实例 const barChart = echarts.init(document.getElementById('barChart')); // 定义基础option(不包含data) const barOption = { title: { text: '各科平均分统计' }, tooltip: { trigger: 'axis' }, xAxis: { type: 'category', data: [] }, // categories占位 yAxis: { type: 'value' }, series: [{ type: 'bar', data: [] }] // values占位 }; // AJAX加载数据并setOption fetch('ChartDataServlet?type=bar') .then(response => response.json()) .then(data => { barOption.xAxis.data = data.categories; // 动态填充categories barOption.series[0].data = data.values; // 动态填充values barChart.setOption(barOption); // 渲染 }) .catch(error => console.error('图表加载失败:', error)); </script>

常见问题:

  • 现象:页面显示“加载中...”但图表不出现,控制台无报错。
    原因:fetch请求被浏览器CORS拦截(因JSP和Servlet同域,实际不该发生,但若Tomcat端口非8080且前端用file://打开,会触发跨域)。
    解决:确保用http://localhost:8080/StudentScoreSystem/dashboard.jsp访问,而非双击HTML文件。

  • 现象:图表渲染但坐标轴文字是方框(□□□)。
    原因:ECharts默认字体不支持中文,且response.setCharacterEncoding("UTF-8")未生效。
    解决:在barOption中显式指定字体:xAxis: { type: 'category', data: [], nameTextStyle: { fontFamily: 'Microsoft YaHei' } },并确认web.xml中<jsp-config>已设<default-page-encoding>UTF-8</default-page-encoding>。

  • 现象:饼图点击图例无反应,tooltip不显示。
    原因:ECharts 5.x默认禁用交互,需在series中启用:series: [{ type: 'pie', data: [], emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } }]。

3.3 数据聚合SQL详解:MySQL如何计算“优秀率”?为什么用CASE WHEN不用COUNT(*)?

ScoreDao.queryLevelCount()方法执行的SQL是理解业务逻辑的关键:

SELECT CASE WHEN score >= 90 THEN '优秀' WHEN score >= 80 THEN '良好' WHEN score >= 60 THEN '及格' ELSE '不及格' END AS level, COUNT(*) AS count FROM score GROUP BY CASE WHEN score >= 90 THEN '优秀' WHEN score >= 80 THEN '良好' WHEN score >= 60 THEN '及格' ELSE '不及格' END

为什么不用COUNT(*) WHERE score>=90?因为要一次性查出四个等级的数量,减少数据库往返次数。GROUP BY中的CASE WHEN必须与SELECT中的完全一致(MySQL 5.7严格模式下尤其如此),否则报错Expression #1 of SELECT list is not in GROUP BY clause。项目中已用SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));临时关闭严格模式,但更健壮的做法是在my.cnf中配置sql_mode=STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION(去掉ONLY_FULL_GROUP_BY)。


4. 避坑指南:部署、编码、SQL、图表四大高频翻车现场

4.1 部署阶段:Tomcat启动失败的三个“隐形杀手”

  • 现象:Tomcat启动日志出现SEVERE: Error filterStart,随后java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver。
    原因:mysql-connector-java-8.0.33.jar未正确放入WEB-INF/lib/,或IDEA Artifact配置中未勾选该jar包。
    解决:在IDEA中右键项目 → Open Module Settings → Artifacts → 选中StudentScoreSystem:war exploded→ 在右侧Output Layout中展开WEB-INF/lib→ 确认mysql-connector-java-8.0.33.jar存在。若缺失,点击+→Extracted Directory→ 选择jar包路径。

  • 现象:登录页输入账号密码后跳转到http://localhost:8080/StudentScoreSystem/LoginServlet,显示404。
    原因:web.xml中Servlet映射路径写错。检查<url-pattern>是否为/LoginServlet(注意斜杠),且<servlet-class>是否为servlet.LoginServlet(包名+类名,非LoginServlet.class)。
    解决:核对web.xml片段:

    <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/LoginServlet</url-pattern> </servlet-mapping>
  • 现象:Tomcat控制台无报错,但浏览器访问http://localhost:8080/StudentScoreSystem/显示404。
    原因:IDEA未将项目部署到Tomcat,或Deployment路径错误。
    解决:File → Project Structure → Artifacts → 点击+→Web Application: Archive→From modules→ 选中项目 → 确保Application context为/StudentScoreSystem(不能是/或空)。

4.2 编码阶段:JSP中文乱码的“三重门”防御

  • 第一重门(JSP页面):<%@ page contentType="text/html;charset=UTF-8" %>必须放在JSP第一行,且charset=UTF-8不可省略。若用<meta charset="utf-8">替代,仅影响浏览器解析HTML,不影响服务器端request.getParameter()解码。

  • 第二重门(Servlet请求):request.setCharacterEncoding("UTF-8")必须在request.getParameter()之前调用,否则GET请求参数(URL中)仍为ISO-8859-1。对于POST请求,此行必加;对于GET,需在Tomcatconf/server.xml中为Connector添加URIEncoding="UTF-8":

    <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />
  • 第三重门(MySQL连接):db.properties中URL必须包含?characterEncoding=utf8mb4&useSSL=false&serverTimezone=GMT%2B8。utf8mb4支持emoji,GMT%2B8是UTC+8的URL编码,useSSL=false避免证书验证失败(开发环境可接受)。

4.3 SQL阶段:成绩录入时“数据截断”与“外键约束失败”的根源

  • 现象:在add.jsp录入学生ID为1001、课程ID为201、分数为99.5,提交后数据库无记录,页面跳转到错误页。
    原因:score表中student_id和course_id字段为INT,但student表中id为VARCHAR(20)(因学号含字母如S2022001),导致外键约束失败。
    解决:检查score表结构,将student_id和course_id改为VARCHAR(20),并确保ALTER TABLE score ADD CONSTRAINT fk_student_id FOREIGN KEY (student_id) REFERENCES student(id);执行成功。

  • 现象:录入分数100.00后,数据库存为100.0,小数位丢失。
    原因:score表字段定义为FLOAT而非DECIMAL(5,2)。FLOAT是近似值存储,100.00可能存为99.99999。
    解决:执行ALTER TABLE score MODIFY COLUMN score DECIMAL(5,2);,并在DAO中用ps.setBigDecimal("score", new BigDecimal("100.00"))传参。

4.4 图表阶段:ECharts数据为空时的“静默失败”

  • 现象:dashboard.jsp中柱状图区域空白,控制台无报错,Network面板看到ChartDataServlet?type=bar返回{}空对象。
    原因:ScoreDao.queryAvgByCourse()查询无结果(如score表为空),但代码未判空,result.put("categories", categories)中categories为null,Gson序列化为{"categories":null,"values":null},ECharts无法渲染。
    解决:在Servlet中增加空值保护:

    if (avgList == null || avgList.isEmpty()) { result.put("categories", Collections.emptyList()); result.put("values", Collections.emptyList()); return; }
  • 现象:折线图显示“NaN”刻度,X轴标签错位。
    原因:queryStudentTrend(int studentId)返回的日期字段为DATE类型,但ECharts需要时间戳或标准日期字符串(如"2023-09-01")。若直接传rs.getDate("exam_date"),Gson转为{"year":123,"month":8,"date":1}(Java Date的旧式序列化)。
    解决:用SimpleDateFormat格式化:

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String dateStr = sdf.format(rs.getDate("exam_date")); trendList.add(Map.of("date", dateStr, "totalScore", totalScore.doubleValue()));

5. 进阶技巧:让系统真正“可用”的五个硬核改造点

5.1 成绩录入页增加实时校验:用AJAX检查学号/课程号是否存在

当前add.jsp提交后才由Servlet校验,用户体验差。可在表单onblur事件中加AJAX校验:

<input type="text" id="studentId" name="studentId" onblur="checkStudentId()" /> <span id="studentTip" style="color:red;"></span> <script> function checkStudentId() { const id = document.getElementById('studentId').value; if (!id) return; fetch('CheckExistServlet?table=student&id=' + id) .then(r => r.json()) .then(data => { const tip = document.getElementById('studentTip'); if (data.exists) { tip.innerHTML = '✓ 学号存在'; tip.style.color = 'green'; } else { tip.innerHTML = '✗ 学号不存在'; tip.style.color = 'red'; } }); } </script>

对应CheckExistServlet只需查SELECT COUNT(*) FROM student WHERE id=?,返回{"exists":true}。此举将错误拦截前置,减少无效提交。

5.2 为ECharts图表添加导出功能:一键下载PNG/PDF

ECharts内置getDataURL()和getConnectedDataURL(),但需配合后端生成PDF。更轻量方案是前端直接导出PNG:

// 在dashboard.jsp中为图表加按钮 <button onclick="exportChartAsPNG(barChart)">导出柱状图为PNG</button> function exportChartAsPNG(chart) { const url = chart.getDataURL({ type: 'png', pixelRatio: 2, // 高清 backgroundColor: '#fff' }); const link = document.createElement('a'); link.download = 'score-bar-chart.png'; link.href = url; link.click(); }

注意:getDataURL()需ECharts 4.0+,且Chrome/Firefox支持,Safari需额外处理blob。

5.3 MySQL慢查询优化:为高频查询字段添加复合索引

查看slow_query_log发现queryByClass执行超2秒。原SQL:

SELECT s.id, s.name, c.course_name, sc.score FROM student s JOIN score sc ON s.id = sc.student_id JOIN course c ON sc.course_id = c.id WHERE s.class_name = ?

执行计划显示student表全表扫描。优化方案:

  • 在student表class_name字段建索引:CREATE INDEX idx_class_name ON student(class_name);
  • 更进一步,建覆盖索引:CREATE INDEX idx_class_cover ON student(class_name, id, name);(避免回表查name)

5.4 JSP页面SEO增强:为各功能页添加title和meta description

当前所有JSP的<title>都是<title>学生成绩管理系统</title>,不利于内部搜索。可在main.jsp中动态设置:

<c:choose> <c:when test="${param.page == 'scoreList'}"> <title>成绩查询 - 学生成绩管理系统</title> <meta name="description" content="查看全班学生成绩明细,支持按班级筛选"> </c:when> <c:when test="${param.page == 'chart'}"> <title>成绩统计分析 - 学生成绩管理系统</title> <meta name="description" content="可视化展示各科平均分、等级分布、学生成长趋势"> </c:when> </c:choose>

然后<a href="main.jsp?page=scoreList">成绩查询</a>链接传递参数。

5.5 安全加固:防止SQL注入与XSS的最小成本方案

  • SQL注入防护:项目已全部使用PreparedStatement,但queryByClass方法中className参数若含%通配符(如计算机%),需明确告知用户这是模糊查询。若需精确匹配,WHERE s.class_name = ?即可;若需模糊,用WHERE s.class_name LIKE ?并ps.setString(1, "%" + className + "%")。

  • XSS防护:JSP中输出用户数据必须<c:out value="${student.name}" />而非${student.name}。<c:out>默认转义HTML特殊字符(如<→&lt;),防止<script>alert(1)</script>注入。

从那以后我每次接手JavaWeb老项目,第一件事就是greprequest.getParameter(,把所有未用PreparedStatement的地方标红;第二件事是打开dashboard.jsp,用浏览器开发者工具Network面板抓ChartDataServlet的响应,确认Content-Type是application/json;charset=UTF-8且中文正常;第三件事是执行SHOW CREATE TABLE score\G,看字段类型是否为DECIMAL。这三步做完,80%的部署和数据显示问题就定位了。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 21:49:36

AI写作工具使用声明全拆解:四条硬条款与学术求生欲的风险边界

1. 先别急着点“同意”&#xff1a;一份使用声明到底在声明什么注册“好写作AI”这类工具的时候&#xff0c;你大概率是这样做完整个流程的&#xff1a;输手机号、收验证码、扫一眼用户协议标题&#xff0c;直接拉到最底部&#xff0c;点在“我已阅读并同意”前面那个小圈上。整…

作者头像 李华
网站建设 2026/10/31 21:49:38

DeepSeek Harness桌面端实测:安装、插件、Skill部署与代码回退全解析

DeepSeek Harness 官方桌面端终于来了。作为一个从命令行版一路用到现在的老用户&#xff0c;我第一时间就把手头的项目全部迁了过来。以前跑 Agent 任务最怕两件事&#xff1a;窗口一关任务断掉&#xff0c;十几个会话堆在同一个终端里分不清谁是谁。桌面端把这些历史遗留问题…

作者头像 李华
网站建设 2026/10/18 5:32:47

350亿参数大模型手机端侧部署实战:量化、KV缓存与分层加载

1. 为什么350亿参数塞进手机这件事值得认真聊聊“内存墙”这个词&#xff0c;做端侧部署的人听到都会条件反射地皱眉。简单说&#xff0c;它就是算力还没累&#xff0c;内存先跪了——芯片的计算单元明明能跑得更快&#xff0c;但数据在内存和计算单元之间搬来搬去的带宽和容量…

作者头像 李华
网站建设 2026/10/18 17:28:37

Web测试与App测试的核心差异:从用例设计到自动化

我最早做Web端测试&#xff0c;后来接手一个App项目&#xff0c;头两周就被打懵了。按理说都是“点一点、验证结果、找bug”&#xff0c;可真换了平台才发现&#xff0c;光“点击一个按钮”这件事&#xff0c;背后的逻辑就能差出十万八千里。很多人会把“Web测试和App测试的区别…

作者头像 李华
网站建设 2026/10/15 10:52:13

智能体自主迭代:从工具到学徒的工程实践与避坑指南

1. 从“工具”到“学徒”&#xff1a;智能体自主迭代到底在解决什么问题这两年跟同行聊天&#xff0c;话题从“你微调了什么模型”慢慢变成了“你的Agent能不能自己改自己”。这个转变挺有意思。早几年我们做大模型应用&#xff0c;核心工作是把一个静态模型接上检索、接上工具…

作者头像 李华