新闻详情

新闻详情

首页 / 资讯中心 / 详情

JSP+SQLServer网上书店系统源码:从建库到部署的完整指南

发布时间:2026/10/1 17:41:18来源:尧图网络
JSP+SQLServer网上书店系统源码:从建库到部署的完整指南
简介在Java Web开发中JSP与Servlet构成了经典的服务端页面技术组合而SQLServer作为企业级关系型数据库常与JDBC驱动配合支撑业务数据持久化。理解JSP页面的请求流转、Servlet的控制器职责以及DAO层对数据库的访问封装是掌握传统Java Web项目架构的基石。这类三层结构不仅适用于课程设计中的图书商城场景也是许多遗留系统维护与二次开发的核心思路。实际工程中从SQLServer的混合身份验证配置、TCP/IP协议开启到JDBC连接串参数调优再到分页查询的ROW_NUMBER写法与UTF-8字符集链路排查每一步都直接影响系统能否稳定运行。本文以网上书店系统源码为实例梳理从建库脚本执行、Tomcat部署到WAR打包交付的完整流程并给出典型故障的排查路径帮助开发者快速跑通一个可演示、可扩展的JSPSQLServer项目。1. 网上书店系统源码JSPSQLServer 这套组合为什么经久不衰网上书店系统是 Java Web 课程设计和毕业设计里出现频率最高的题目之一javajspSQLServer 又是被一届届学生验证过最多次的稳定组合。这套源码带说明文档意味着除了代码还包含建库脚本、部署步骤和功能截图能直接跑通注册登录、图书浏览、购物车、下单结算、后台图书与订单管理在内的完整流程。适合三类人想快速交付课程设计的学生、要把 JSP 全流程串起来理解的初级开发、打算在现成系统上二次改造的毕设选手。下面按项目结构、部署运行、关键参数、排错、改造的顺序讲透。2. 拆开网上书店源码JSP 页面、Servlet 和 DAO 三层到底怎么分工2.1 一张目录图看懂 src、WebRoot 和 SQL 脚本各管什么事老式 JSP 项目十有八九不是 Maven 工程而是一个 Dynamic Web Project目录结构高度一致。拿到源码后别急着双击 login.jsp先按目录把职责分清楚后面改代码才知道该动哪个文件。网上书店这类题目的源码基本是这样一个骨架目录 / 文件职责src/com/bookstore/entityUser、Book、Order、OrderItem 这几个 JavaBean字段跟数据库表一一对应src/com/bookstore/daoDBHelper 连接管理类加上 UserDao、BookDao、OrderDao 等数据访问类src/com/bookstore/servletLoginServlet、CartServlet、OrderServlet 等控制器接收请求、调 DAO、跳页面WebRoot前台 JSPindex、login、register、bookDetail、cart、orderadmin 子目录放后台WebRoot/WEB-INFweb.xmlServlet 映射、过滤器和欢迎页配置都在这里bookstore.sql建库建表脚本含测试数据是整个系统能跑起来的前提说明文档环境要求、部署步骤和功能截图这个分层对应的是最经典的 JSPServletJavaBean 三层。JSP 只负责把数据渲染成 HTML 给浏览器不写 JDBC 代码Servlet 是控制器负责接参数、调页面DAO 里才是真正的 SQL 和数据库操作。网上书店的网上两个字核心就在这三层之间的请求流转上。我一般建议先把 src 下的包结构展开看一眼确认 dao 包里有没有 DBHelper 或者 DBUtil。这个类就是整个系统的数据库入口后面的部署章节第一步就是改它。如果连这个类都没有说明源码缺了关键文件后面再怎么配都是白搭。2.2 用户登录的完整链路JSP 表单到 Servlet 再到数据库登录是网上书店最典型的请求流转例子牵涉到页面、控制器、DAO 三层。先从页面看起前台 login.jsp 里必然有一个表单指向一个 Servlet 的 URL%-- login.jsp 表单部分methodpost 才能走 Servlet 的 doPost --% form actionlogin methodpost input typetext nameusername placeholder用户名 required / input typepassword namepassword placeholder密码 required / button typesubmit登录/button /form %-- 登录失败时 Servlet 回传的提示消息 --% % if (request.getAttribute(msg) ! null) { % p stylecolor:red% request.getAttribute(msg) %/p % } %actionlogin并不是真的去访问 login.jsp而是匹配 web.xml 里配置的 url-pattern由容器把请求交给对应的 Servlet 处理。表单里的 nameusername 和 namepassword 是前后端约定的传参键名Servlet 端用 request.getParameter(username) 取的就是这里的值两边的名字必须一致这是新手最容易对不上的地方。接着看 Servlet 侧的处理逻辑。老式项目里 Servlet 要么在 web.xml 里注册要么直接在类上用 WebServlet 注解。完整的登录处理大致长这样// LoginServlet.java - 登录请求的统一入口 package com.bookstore.servlet; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.bookstore.dao.DBHelper; import com.bookstore.entity.User; public class LoginServlet extends HttpServlet { private static final long serialVersionUID 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 先处理POST请求里的中文编码否则用户名是中文时查询结果会异常 request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); // 使用PreparedStatement传参避免拼接SQL带来的注入问题和引号转义错误 String sql SELECT id, username, nickname, role FROM users WHERE username ? AND password ?; try (Connection conn DBHelper.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { User user new User(); user.setId(rs.getInt(id)); user.setUsername(rs.getString(username)); user.setNickname(rs.getString(nickname)); user.setRole(rs.getString(role)); // 登录状态放在Session里后续页面靠session.getAttribute(loginUser)判断 HttpSession session request.getSession(); session.setAttribute(loginUser, user); // 管理员和普通用户走不同首页 if (admin.equals(user.getRole())) { response.sendRedirect(admin/index.jsp); } else { response.sendRedirect(index.jsp); } } else { // 用户名或密码错误把提示塞回request转发回登录页 request.setAttribute(msg, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } } } catch (Exception e) { e.printStackTrace(); request.setAttribute(msg, 系统异常 e.getMessage()); request.getRequestDispatcher(login.jsp).forward(request, response); } } }这段代码里值得注意的参数和细节有几个。第一PreparedStatement 的 ? 占位符从 1 开始编号ps.setString(1, username) 对应第一个问号顺序不能反。第二rs.next() 返回 true 才说明查到记录查不到就走 else 分支给前端回错误消息这是登录判断的唯一依据。第三sendRedirect 是让浏览器重新发起一次请求地址栏会变适合登录成功后的跳转forward 是服务器内部转发地址栏不变适合把错误消息带回页面。两者用错会导致表单重复提交或者刷新页面时反复弹登录失败提示。数据库这层就看 UserDao 了它的作用就是把上面那段 SQL 再封装一层LoginServlet 拿到的其实是 DAO 方法返回的 User 对象或 null。这样做的直接好处是如果要把密码改成 MD5 存储只需要改 DAO 和注册逻辑Servlet 基本不用动。网上书店的购物车、下单模块走的全是同样一套 Servlet 调用 DAO 的套路看懂登录这一条链路其余模块就是换表和换 SQL 的事。2.3 SQLServer 侧的表设计users、books、orders、order_items 的关系网上书店建库脚本里通常有六张左右的表核心是用户、图书、订单、订单明细这四张。完整版还会带 categories 图书分类表和 book_comments 评论表但分类表在早期版本里经常被简化成 books 表里的一个 category 字段。先看最稳定的核心建表脚本-- bookstore.sql 核心表定义SQLServer 2008 及以上可用 USE bookstore; GO CREATE TABLE users ( id INT IDENTITY(1,1) PRIMARY KEY, username NVARCHAR(50) NOT NULL UNIQUE, password NVARCHAR(50) NOT NULL, nickname NVARCHAR(50), role NVARCHAR(20) DEFAULT user, -- user 普通用户 / admin 管理员 created_at DATETIME DEFAULT GETDATE() ); GO CREATE TABLE categories ( id INT IDENTITY(1,1) PRIMARY KEY, name NVARCHAR(50) NOT NULL ); GO CREATE TABLE books ( id INT IDENTITY(1,1) PRIMARY KEY, category_id INT REFERENCES categories(id), name NVARCHAR(100) NOT NULL, author NVARCHAR(50), publisher NVARCHAR(100), price DECIMAL(10,2), stock INT DEFAULT 0, cover NVARCHAR(200), description NVARCHAR(MAX) ); GO CREATE TABLE orders ( id INT IDENTITY(1,1) PRIMARY KEY, user_id INT NOT NULL REFERENCES users(id), total_amount DECIMAL(10,2), status NVARCHAR(20) DEFAULT pending, create_time DATETIME DEFAULT GETDATE() ); GO CREATE TABLE order_items ( id INT IDENTITY(1,1) PRIMARY KEY, order_id INT NOT NULL REFERENCES orders(id), book_id INT NOT NULL REFERENCES books(id), quantity INT DEFAULT 1, price DECIMAL(10,2) ); GO这几张表的设计有几个固定的套路。users 表用 role 字段区分管理员和普通用户登录成功后 Servlet 就是靠读这个字段决定跳后台还是前台这比单独建一张 admin 表简单得多。orders 只存订单本身的信息用户买了哪些书全部拆到 order_items 里一行订单项对应一本书和购买数量这是典型的一对多设计想统计哪本书卖得好直接对 order_items 做聚合就行。订单金额 total_amount 是下单那一刻从购物车算出来的快照不随图书价格变动这是电商系统处理价格的一致惯例。创建表时用 NVARCHAR 而不是 VARCHAR 存中文是有讲究的。NVARCHAR 按 Unicode 存储在 SQLServer 默认排序规则下对中文支持更稳VARCHAR 虽然配合 Chinese_PRC_CI_AS 排序规则也能存中文但一旦数据库排序规则是 Latin1_General中文就会变成问号。这个隐患到后面字符集那一章还会再提一次属于网上书店源码里典型的环境型翻车点。IDENTITY(1,1) 是 SQLServer 自增主键的写法从 1 开始每次加 1对应 MySQL 里的 AUTO_INCREMENT改库的时候要记住这个区别。3. 从 SQLServer 建库到 Tomcat 部署跑通网上书店系统的最小步骤3.1 先过 SQLServer 三关混合模式、TCP/IP、执行建库脚本网上书店的数据库连接默认走的是 SQLServer 的 sa 账号加密码登录也就是 SQL Server 身份验证。SQLServer 安装时默认只开了 Windows 身份验证直接拿源码里的连接参数去连十有八九会报 Login failed for user sa。所以动手之前先把三件事按顺序做掉。第一关是服务器身份验证模式。用 SSMS 登录后在实例上右键选属性切到安全性页把服务器身份验证改成SQL Server 和 Windows 身份验证模式。第二关是 sa 账号本身。在安全性→登录名→sa的属性里状态页需要把启用打开并且设置一个自己记得住的密码。第三关是网络协议。打开 SQL Server 配置管理器在SQL Server 网络配置→实例名的协议里把 TCP/IP 设为已启用然后重启 SQLServer 服务。如果 TCP/IP 不启用JDBC 走 1433 端口绝对连不上这在后面的排查章节会看到对应报错。# 在Windows命令行确认1433端口已经在监听 netstat -an | findstr 1433如果上面那行命令有结果说明 TCP/IP 协议和监听已经就绪。改完这三项后重启 SQLServer 服务然后在 SSMS 里用 sa 重新登录一次能登进去再继续下一步。这个验证动作不值钱但能省掉后面一整轮的排查时间。接着执行建库脚本。打开 SSMS用 sa 登录后新建查询把 bookstore.sql 整个内容贴进去执行。脚本里有 USE bookstore 和 GO 语句只有 SSMS 和 sqlcmd 能正确分批执行。如果脚本报错优先检查是不是执行工具的锅执行上下文是不是停在 master 库以及登录账号有没有建库权限。3.2 改 DBHelper 连接参数四个必改项一个都不能漏不管源码里是 DBHelper 还是 DBUtil功能都一样提供一个静态方法返回数据库 Connection。整个网上书店的所有 DAO 类都会调它所以这个类里的连接参数决定了全系统能不能连上数据库。常见的写法长这样// DBHelper.java - 整个系统的数据库连接入口 package com.bookstore.dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DBHelper { // 三个必改项地址端口、库名、sa密码 private static final String DB_URL jdbc:sqlserver://localhost:1433;DatabaseNamebookstore;encryptfalse;loginTimeout5; private static final String USER sa; private static final String PASSWORD 123456; static { try { // 加载SQLServer JDBC驱动jar要放在WEB-INF/lib下 Class.forName(com.microsoft.sqlserver.jdbc.SQLServerDriver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(DB_URL, USER, PASSWORD); } // 统一关闭资源顺序反了会出现连接泄漏 public static void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs ! null) rs.close(); } catch (SQLException e) { } try { if (stmt ! null) stmt.close(); } catch (SQLException e) { } try { if (conn ! null) conn.close(); } catch (SQLException e) { } } }要改的参数就三行DB_URL 里的 localhost数据库不在本机就换 IP、DatabaseNamebookstore建库脚本里建的库名、PASSWORDsa 的密码。USER 保持 sa。还有个隐形的必改项是 WEB-INF/lib 里的驱动 jar如果没有 sqljdbc4.jar 或微软官方新版 mssql-jdbc 驱动上面的 Class.forName 必然抛 ClassNotFoundException。这些细节一般写在说明文档里但很多源码的文档跟不上代码还是要自己动手核对。课程设计阶段把密码写死在代码里问题不大但提交之前记得把测试时改过的连接串还原成交付说明里的默认值。3.3 在 IDEA 里配置 Tomcat 启动项目拿到源码最直观的跑法是在 IDEA 里配置一个本地 Tomcat。这个方案的好处是改 JSP 或 Java 代码后IDEA 的 hot swap 能让你少按几次重启按钮。步骤按顺序来第一步File→Open 选中项目根目录如果 IDEA 提示这是 Eclipse 项目选 Import as project。第二步确保 src 目录被标记为 Sources RootWebRoot 被标记为 Web Resources Root这两个标记不对部署的时候页面和 class 文件就找不齐。第三步File→Project Structure→Artifacts新建一个 Web Application: Exploded把 WebRoot 设成 Web Resource Directory。第四步配置 TomcatRun→Edit Configurations加一个 Tomcat Server→Local在 Deployment 标签页里把这个 Artifact 加进去Application context 填 /bookstore。第五步启动前在库列表里把 Tomcat 目录下的 servlet-api.jar 加进来否则 JSP 编译时找不到 javax.servlet。提示IDEA 版本不同Artifact 和 Tomcat 配置的入口位置会有差异但目录标记和Deployment 里加 Artifact这两步是所有版本都躲不开的。注意网上书店源码是传统目录结构不是 Maven 结构所以不要指望 IDEA 一键导入后就能跑目录标记和 Artifact 这两步几乎每次都要手调。启动后浏览器访问 http://localhost:8080/bookstore/看到前台首页就说明环境通了。如果报了 404先看 IDEA 底部运行窗口里的实际端口和 context pathTomcat 默认 8080但本机被占时 IDEA 会自动换端口地址输对才能访问到。3.4 传统 JSP 项目打包 WAR部署到独立 Tomcat 的最小命令课程设计要交的可运行程序通常不要求对方装 IDEA所以把项目打成 WAR 包放到独立 Tomcat 的 webapps 下是最被接受的交付方式。传统 JSP 项目打包 WAR 有两种选择一是在 IDEA 里 Build→Build Artifacts选择 Web Application: Archive产出 bookstore.war另一条路是命令行打包。# 先把编译好的class确认在WebRoot/WEB-INF/classes下再执行打包 jar cvf bookstore.war -C WebRoot . # 把war复制到Tomcat的webapps目录 cp bookstore.war /opt/tomcat/webapps/ # 启动Tomcatwar会被自动解压成bookstore目录 sh /opt/tomcat/bin/startup.sh # 看启动日志确认没有异常 tail -f /opt/tomcat/logs/catalina.outjar 命令打包的关键是 -C WebRoot .它表示进入 WebRoot 目录后把当前目录所有内容打进 war这样 WEB-INF/classes 和 web.xml 都会在正确的位置。如果 class 没有编译到 WebRoot/WEB-INF/classes 下打出来的 war 就是残缺的访问任何页面都会报 404 或 500。Tomcat 启动后访问的路径是 war 包文件名也就是 http://localhost:8080/bookstore/跟前面 IDEA 里配置的 context path 要一致否则静态资源能打开Servlet 映射全部 404。交付前把这个地址在浏览器里完整走一遍注册到下单的流程比什么验收都管用。4. JDBC 连接串、SQLServer 分页和字符集三个决定系统死活的关键配置4.1 JDBC 连接串拆解每个参数对应一个坑网上书店的连接串基本都是 jdbc:sqlserver:// 开头跟 MySQL 的 jdbc:mysql://、Oracle 的 jdbc:oracle:thin: 都不同第一次从 MySQL 转过来的人经常在这里卡住。一个完整可用的连接串长这样jdbc:sqlserver://localhost:1433;DatabaseNamebookstore;encryptfalse;loginTimeout5每个部分的含义和常见踩坑点如下表参数取值示例含义与踩坑点localhostlocalhost / 127.0.0.1 / 内网 IP数据库不在本机时必须改写成 localhost 会连到本机去找库14331433SQLServer 默认端口命名实例的端口可能不同需在配置管理器里确认DatabaseNamebookstore库名必须和建库脚本创建的库一致大小写不敏感但别拼错encryptfalse新版驱动默认 true老 SQLServer 不支持加密连接时直接连不上要显式关掉loginTimeout5秒数设置后连接超时不至于让页面转圈好几分钟驱动类名也要对com.microsoft.sqlserver.jdbc.SQLServerDriver。这是 sqljdbc4.jar 和之后所有新版驱动微软官方叫 mssql-jdbc的包名。网上搜 SQLServer JDBC 会翻出一堆老代码写 com.microsoft.jdbc.sqlserver.SQLServerDriver那是 2000 年代老驱动的包名放到现代 Tomcat 里直接 ClassNotFound。判断驱动和 JDK 是否匹配看驱动包名里的 jre 标记sqljdbc4 对应 JDK6 及以上新版 mssql-jdbc 驱动分 jre8、jre11 等版本JDK 版本太老或太新都会在 Class.forName 那一步翻车。4.2 SQLServer 分页没有 LIMIT用 ROW_NUMBER() 或 OFFSET FETCH网上书店的图书列表页通常要分页但 SQLServer 和 MySQL 的方言差别在这里最明显。MySQL 写 LIMIT 10, 10 就能拿第 2 页SQLServer 直接不认这个语法。源码里如果是从 MySQL 迁移来的二手项目分页 SQL 往往是被改坏的灾区。SQLServer 2008 时代的标准写法是 ROW_NUMBER()-- 查询第2页数据每页10条 WITH BookList AS ( SELECT ROW_NUMBER() OVER (ORDER BY b.id DESC) AS rowNum, b.id, b.name, b.author, b.price, b.stock FROM books b WHERE b.category_id 1 ) SELECT * FROM BookList WHERE rowNum BETWEEN 11 AND 20;ROW_NUMBER() OVER (ORDER BY b.id DESC) 先按 id 倒序给每行编一个从 1 开始的序号外层再取序号在 11 到 20 之间的行这就是第 2 页的 10 条。注意 ORDER BY 必须写在 OVER 里面外层不能再乱排否则分页结果不稳定。DAO 层要做的是把页码换算成起始和结束行号start (page-1)pageSize1end pagepageSize。如果 SQLServer 版本在 2012 及以上有更简单的 OFFSET FETCH 写法SELECT id, name, author, price FROM books ORDER BY id DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;OFFSET 10 表示跳过前 10 条FETCH NEXT 10 ROWS ONLY 表示再取 10 条语义跟 MySQL 的 LIMIT 10,10 完全等价只是顺序反着写。这两个写法都只适用于 SQLServer网上书店源码如果同时提供 MySQL 版和 SQLServer 版分页 SQL 一定是各写各的别指望一张 SQL 通吃。分页参数在代码里是这样换算的// BookDao.java - 把页码换算成ROW_NUMBER的范围 public ListBook findBooksByPage(int categoryId, int page, int pageSize) throws SQLException { int start (page - 1) * pageSize 1; int end page * pageSize; String sql WITH t AS (SELECT ROW_NUMBER() OVER (ORDER BY id DESC) AS rn, * FROM books WHERE category_id ?) SELECT * FROM t WHERE rn BETWEEN ? AND ?; try (Connection conn DBHelper.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, categoryId); ps.setInt(2, start); ps.setInt(3, end); // 执行查询并组装Book对象的逻辑省略 } }page 从 1 开始pageSize 是每页条数这两个值通常来自 JSP 页面的请求参数。前端页码按钮传给 Servlet 的 page 如果没做校验直接拿负数去算 start 会得到小于 1 的数虽然 ROW_NUMBER 范围不会报错但结果集为空会让页面显示没有更多数据体验很差。稳妥做法是在 DAO 入口先做一次 Math.max(1, page) 的兜底。4.3 字符集链路同一个 UTF-8三处都得设网上书店源码的中文乱码是出现频率最高的玄学问题。乱码的本质是编码不统一而 JSP 项目里有三处各自的编码设置少设一处都可能出问号。第一处是 JSP 页面的头部指令% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %pageEncoding 决定 JSP 文件本身怎么读contentType 里的 charset 决定响应头里告诉浏览器用什么编码解析 HTML。两个都写 UTF-8页面上写死的中文才不会花。但表单提交过来的参数是另一条路POST 请求的编码由 servlet 容器决定必须在进入业务逻辑前设置 request.setCharacterEncoding(UTF-8)。最好的实现方式是写一个过滤器统一处理而不是在每个 Servlet 里重复写// EncodingFilter.java - 在web.xml里注册过滤所有请求 package com.bookstore.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class EncodingFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(UTF-8); response.setCharacterEncoding(UTF-8); chain.doFilter(request, response); } public void init(FilterConfig config) throws ServletException { } public void destroy() { } }!-- web.xml 中注册编码过滤器并让所有请求都经过它 -- filter filter-nameencoding/filter-name filter-classcom.bookstore.filter.EncodingFilter/filter-class /filter filter-mapping filter-nameencoding/filter-name url-pattern/*/url-pattern /filter-mapping第三处是数据库。SQLServer 的排序规则决定了它怎么理解字符串用 Latin1_General 排序规则的库存中文写入时就可能丢字符。建库时最好显式指定CREATE DATABASE bookstore COLLATE Chinese_PRC_CI_AS;还可以用下面这条语句检查现有库的排序规则结果不是 Chinese_PRC_CI_AS 的话建表时把中文列定义成 NVARCHAR 会更抗造。判断乱码出在哪段链路其实有规律页面显示乱码但数据库是对的问题在页面读取或响应编码页面和数据库都乱问题在写入链路的 request 编码只有数据库乱而页面正常问题在列类型或排序规则。按这个顺序查基本半小时内能定位。5. 网上书店源码部署排查五个让新手卡住两天的经典问题5.1 现象Tomcat 启动后访问页面报 ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver原因JDBC 驱动 jar 没有进入 WEB-INF/lib 目录或者 lib 下的驱动和 JDK 版本不匹配。还有一种是驱动 jar 放在 Tomcat 的 lib 目录但 IDEA 部署项目时没有把外部库带进 artifact运行时仍然找不到类。解决下载对应 JDK 版本的驱动 jar老项目用 sqljdbc4.jar新环境用微软官方 mssql-jdbc 的对应 jre 版本放到项目的 WebRoot/WEB-INF/lib 下然后在 IDEA 里确认 Artifact 输出包含这个目录。改了 lib 后必须重启 Tomcat 而不是热更新驱动类只在类加载时初始化一次。如果还是报错打开 IDEA 的运行配置看实际 classpath 里有没有这个 jar 的路径这一步能区分是项目缺失还是打包遗漏。5.2 现象页面加载时报 The TCP/IP connection to the host localhost, port 1433 has failed原因SQLServer 的 TCP/IP 协议根本没启用默认只开 Shared Memory 和 Named PipesJDBC 走不了 1433 端口或者 SQL Server Browser 服务没启动导致命名实例解析失败或者本机防火墙把 1433 端口拦了。解决打开 SQL Server 配置管理器在SQL Server 网络配置里把 TCP/IP 设为已启用右键重启 SQLServer 服务。然后在命令行执行 netstat -an | findstr 1433 确认端口在监听。如果数据库在远程服务器还要检查云安全组或本机防火墙是否放行 1433。这里的排查顺序是先看协议再看端口最后看防火墙别一上来就重装数据库。5.3 现象连接时报 Login failed for user sa错误码 18456原因SQLServer 实例还是 Windows 身份验证模式sa 密码不对或者 sa 账号处于禁用状态。最常见的情况是安装时选了 Windows 身份验证模式后来没改过来。解决用 Windows 身份登录 SSMS实例属性里把身份验证模式改成混合模式然后在安全性→登录名→sa的属性里启用账号并重置密码。改完必须重启 SQLServer 服务因为身份验证模式的变更要重启才生效。重启后再用 sa 登录一遍 SSMS能进说明数据库侧已经通过这时候再回 Tomcat 测试连接问题就隔离干净了。如果密码里带了特殊字符记得在连接串里保持原样不要被 JSP 页面或配置文件里的转义规则改掉。5.4 现象页面上中文全是问号或乱码数据库里存的也是乱码原因三层编码没对齐。JSP 文件本身不是 UTF-8 存储或者缺少 pageEncoding 指令或者请求没有经过编码过滤器或者数据库排序规则不是中文规则、列类型用了 varchar。这四个原因造成的现象相似但修法完全不同。解决按字符集章节的顺序逐层检查——先把 JSP 页面的 pageEncoding 和 contentType 统一成 UTF-8再确认 web.xml 里编码过滤器的 url-pattern 是 /*最后检查数据库排序规则和文本列类型。如果是 SQLServer 的 Latin1_General 排序规则把中文列改成 NVARCHAR或者重建库时指定 COLLATE Chinese_PRC_CI_AS。改完一处就刷新验证一处不要一次改四处然后不知道哪处生效。5.5 现象用 SSMS 执行 bookstore.sql 报语法错误或导入数据时提示数据无效原因脚本里的 GO 关键字需要分批执行有些精简版执行工具不认 GO或者脚本里用了 IDENTITY、GETDATE 这些 SQLServer 方言被误拿到 MySQL 里执行也可能是登录账号对 master 库没有建库权限CREATE DATABASE 那一步就被拒了。解决统一用 SSMS 执行建库脚本不要用别的工具硬跑。执行前先用 sa 登录确认当前连接上下文是 master 库。脚本执行时勾选遇到错误继续只会让错误越积越多正确的做法是让脚本在第一个错误处停下按报错行号回去看是 GO 的问题还是权限的问题。网上的sqlserver 无法导入数据 数据无效这类问题十有八九也是把 SQLServer 的导出文件和别的库的工具混用了导出的 .bak 或 .sql 只能在 SQLServer 体系里用。导入数据前先确认目标库排序规则和源数据的一致不一致时优先改库排序规则不要硬导。6. 拿到源码后的三个改造方向让课程设计从能跑到能答辩6.1 加一个图书评分功能最小改动但能讲清楚新增一张 book_comments 表字段就是 id、book_id、user_id、score、content、create_time然后建一个 CommentDao在 bookDetail.jsp 下面加评分表单和历史评论列表再写一个 CommentServlet 接收提交。这个改动只动了两个文件加一个表但能把一对多查询、外键关联、表单提交三个知识点串起来答辩时讲 10 分钟不成问题。评分字段用 TINYINT 或 INT 都行加一个 CHECK 约束限制在 1 到 5 之间属于能主动说出来的加分设计。6.2 把 SQLServer 换成本地 MySQL环境门槛降一半如果你只是想在自己电脑上快速演示不想背 SQLServer 的安装和配置可以只改四处驱动类换成 com.mysql.cj.jdbc.Driver连接串换成 jdbc:mysql://localhost:3306/bookstore?useUnicodetruecharacterEncodingutf8分页 SQL 把 ROW_NUMBER 换成 LIMIT建库脚本把 IDENTITY(1,1) 换成 AUTO_INCREMENT。注意这等于放弃了题目里 SQLServer 的部分答辩前要想清楚怎么解释选型。6.3 交付前的验收检查单功能操作预期结果注册注册一个新用户提示成功并能直接登录登录分别用正确和错误密码成功进首页 / 失败有提示图书浏览首页点分类、翻页列表正常页码可切换购物车加购、改数量、删商品金额实时变化下单提交订单生成订单库存扣减后台用 admin 账号登录能增删图书、改订单状态我拿到任何一套 javajsp 源码习惯是先跑通主流程再读代码顺序永远是建库→部署→注册→下单→进后台因为主流程跑不通代码读得再多也是纸上谈兵。这个习惯帮我绕过了大部分部署期的坑希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

CSDN首页发布文章CSDN同步助手【模拟电力变压器电气测试】使用电磁暂态程序(EMTP)对各种情景进行建模(包括:正常运行、一次绕组故障、铁芯故障)(Matlab代码实现)69 / 10 2026/10/1 19:50:39

CSDN首页发布文章CSDN同步助手【模拟电力变压器电气测试】使用电磁暂态程序(EMTP)对各种情景进行建模(包括:正常运行、一次绕组故障、铁芯故障)(Matlab代码实现)69 / 10

发布文章 ​编辑CSDN同步助手 69 / 100 0 / 256 AI提取摘要 您已同意GitCode 用户协议 和 隐私政策,我们会为您自动创建账号并备份文章至我的项目。 活动 话题 共 0 字 i今日发文额度已用完,可去这里提升额度 反馈已提交,感谢你的帮助。

阅读更多 →
STM32 串口底层深度解析|USART 中断标志、硬件 FIFO,乱码根源底层定位 2026/10/1 19:50:33

STM32 串口底层深度解析|USART 中断标志、硬件 FIFO,乱码根源底层定位

摘要 很多人调试 STM32 串口,只停留在 HAL 库HAL_UART_RxCpltCallback回调函数,遇到乱码、丢字节、偶发接收异常,只会怀疑波特率或者上位机。 但实际上大量工程里的串口玄学 bug,根源来自USART 硬件中断标志理解错误、硬件 FIFO 溢…

阅读更多 →
参保意愿预测5-标签定义与时间切分的坑 2026/10/1 19:50:33

参保意愿预测5-标签定义与时间切分的坑

参保意愿预测5-标签定义与时间切分——一个模型最容易被忽略的两个坑 模型上线后数字对不上业务预期,最常见的两个根源不在模型——在标签定义和时间切分。“最终参保"还是"当年参保”、随机切分还是时间切分——这两个决定比选RF还是GBDT重要一百倍。这篇…

阅读更多 →
基于改进型YOLOv8的森林火灾实时监测系统设计与实现 2026/10/1 19:50:33

基于改进型YOLOv8的森林火灾实时监测系统设计与实现

本研究为森林火灾智能监测提供了坚实的理论依据和高效的技术支持,并且也为计算机视觉技术应用于灾害科学领域开辟了新的实践路径。一、研究背景和问题考察由于全球气候变化越来越强烈、极端天气事件也越来越多地出现,所以森林火灾作为一次突发性很强、危…

阅读更多 →
参保意愿预测6-工程全貌与细节 2026/10/1 19:50:33

参保意愿预测6-工程全貌与细节

参保意愿预测6-从网格搜索到村级任务表——一个政务ML项目的工程全貌 模型只是中间产物——从"一份GBK乱码的CSV"到"各村任务分配表",中间是一条完整的工程流水线。这篇按数据流走一遍:编码修复→特征构建→调参训练→打分标定→分档…

阅读更多 →
800V超充往上走,充电桩里的几个电流检测点也该重新看了 2026/10/1 19:50:32

800V超充往上走,充电桩里的几个电流检测点也该重新看了

800V平台、480kW、液冷枪、600A甚至更高电流——这几年超充设备的参数越来越“猛”。但功率做上去以后,一个很容易被忽略的问题也跟着来了:这么大的电流,究竟在哪里测?用什么测?这听起来不像什么难题。毕竟电流传感器在…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉