简介:一套基于 JSP + Servlet + SQL Server 的购物车系统完整实现,面向正在学习 Java Web 开发、需要参考完整项目结构的初学者或课程设计开发者。项目覆盖用户注册登录、商品展示、选购、购物车维护及订单结算等典型流程,并体现 JDBC 连接 SQL Server、Session 临时存储、PreparedStatement 防注入等实践要点。压缩包共 35 个文件,其中包括 10 个 JSP 页面、JavaBean/Servlet 相关的 .java/.class 文件,以及 SQL Server 数据库 MDF/LDF 备份文件、jpg/gif/swf 图片动画、txt 说明文档等,整体仅 381KB,结构清晰,特别适合作为 Java Web 课程设计的参考源码。已有 203 人学习下载。通过对照源码、JSP 页面和数据库文件,可快速理解前后端交互方式、购物车状态维持和数据库表设计;并包含注册、登录、商品浏览、下单等页面,数据库文件可直接还原后运行调试,也可在此基础上扩展为课程设计或毕业设计项目,无论是入门练习还是二次开发,都有较高参考价值。
1. 拿JSP购物车做课设之前,先看清Java+SQL Server这套方案的边界
JSP购物车(Java+SQL Server)是Java Web课程设计里出现频率最高的选题,资源站上一搜“JSP 购物车”全是这种压缩包。典型组成是:JSP页面负责商品展示,Servlet处理登录、加购、删除请求,SQL Server存用户、商品和订单数据。它能覆盖课设要求的大部分功能点,适合交作业、做毕设演示,也是第一次接触Java Web全流程的练手项目。
反直觉的地方在于:JSP在商业项目里确实越来越少见,但课设阶段选它反而最稳。它不依赖复杂框架和构建工具,一个Tomcat加一个SQL Server就能跑,核心逻辑全在你能读懂的Java代码里,出了问题排查路径很短。接下来按“环境准备、数据库还原、核心代码、避坑、二次开发”这条线,把值得花时间的地方一次讲透。
2. 搭建运行环境并还原数据库:让JSP购物车项目在本地跑起来
先把话说在前面:这类压缩包的代码质量参差不齐,但99%的问题出在环境而不是代码。只要版本搭配合理、数据库能还原、驱动能加载,JSP购物车项目跑起来的成功率非常高。这一章把从零到能打开登录页的三个关键步骤拆开讲。
2.1 JDK、Tomcat、SQL Server版本怎么搭配才不打架
先定版本组合。这类JSP购物车源码大多是前几年课程设计的产物,编译目标普遍是Java 7或Java 8,所以JDK 8(Java 1.8)是最省事的选择。用JDK 11、17不是完全不行,但老代码可能用到JDK 8里的内部API,新版本把非公开类收掉之后,会出现编译通过、运行报NoClassDefFoundError的情况。课设阶段别给自己加戏,直接装JDK 8,同时把JAVA_HOME指到JDK安装目录,PATH里加上%JAVA_HOME%\bin,这一步能用命令行验证:执行java -version,看到1.8.x开头就说明环境变量配对了。
Tomcat建议8.5或9.0,对应Servlet 3.1/3.4版本,能兼容绝大多数课设写法。如果你的项目WEB-INF/web.xml声明的是老式<web-app version="2.5">,Tomcat 7也能跑,但8.5向下兼容,所以仍然推荐8.5。Tomcat版本直接影响web.xml里监听器、过滤器等配置的解析方式,换版本后页面报404,先回头看web.xml头声明是否与容器匹配。如果用Eclipse,还要注意编译级别保持1.8,Eclipse默认可能用1.5编译,泛型语法会在编译期直接报错;IDEA则在Project Structure里设置Project SDK和Language Level,这两项不对,源码明明没错也会编译失败。
SQL Server这边2012到2019都能选。区别主要在驱动:老驱动sqljdbc4.jar配合2012/2014不需要额外参数;2016以后的实例,建议用新版mssql-jdbc-x.x.jar,否则可能出现握手失败或提示加密类型错误。安装SQL Server时用默认实例,选“混合认证模式”,给sa账号设一个记得住的密码。很多项目配置文件里写死user=sa,如果你装成了Windows认证模式,后面JDBC怎么连都会报“cannot open database”。安装完打开“SQL Server配置管理器”,检查两件事:MSSQLSERVER服务是否在运行;“SQL Server网络配置”下TCP/IP协议是否已启用,默认端口1433。这两项是JDBC连接SQL Server的前提。
图形化工具用SSMS就够,Navicat也可以连接SQL Server验证库表,但对课程设计来说不是必须。连接测试很简单:SSMS里输入服务器名localhost,选SQL Server认证,填sa账号密码,能进就说明数据库服务层面没问题,后面所有连不上的锅都甩不到SQL Server头上。
提示:资源包如果附带.sql脚本而不是.bak文件,优先用脚本建库。脚本是所有版本通用的交付方式,能避开备份文件版本不兼容的问题,省得后面走还原失败的老路。
2.2 还原数据库:.bak备份文件导入SQL Server的操作流程
压缩包里最常见的数据库交付形式是.bak文件,体积小、打包方便。还原它有两种入口:SSMS图形化和SQL命令。
图形化的路径是:打开SSMS,右键“数据库”→“还原数据库”,源设备选择.bak文件,目标数据库填一个名字比如ShopDB,左侧“选项”页勾选“覆盖现有数据库”,点确定。如果一切顺利,状态会从“正在还原”变成“已就绪”,展开数据库就能看到表。
如果报错,常见原因有两个:备份集来自更高版本的SQL Server,低版本实例读不了;或者.bak里记录的物理文件路径和本机数据目录不一致。第二种情况用MOVE参数解决,先看备份里有几个逻辑文件:
RESTORE FILELISTONLY FROM DISK = N'C:\work\ShopDB.bak';返回结果里LogicalName列会有两行左右,通常是ShopDB和ShopDB_log这类名字。把逻辑文件名填进下面命令:
RESTORE DATABASE ShopDB FROM DISK = N'C:\work\ShopDB.bak' WITH REPLACE, MOVE 'ShopDB' TO N'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\ShopDB.mdf', MOVE 'ShopDB_log' TO N'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\ShopDB_log.ldf';MOVE负责把备份逻辑文件映射到本机实际物理目录,REPLACE允许覆盖同名库。命令里MSSQL15.MSSQLSERVER是SQL Server 2019的实例路径,2017是MSSQL14,2016是MSSQL13,改成你自己的版本路径,不确定的话去C:\Program Files\Microsoft SQL Server目录下看一眼实际文件夹名。
还原完成后展开数据库看表,一般能看到users、product或goods、cart、orders这四类表。如果表数量为0,多半是还原错了库或者.bak本身不是SQL Server备份文件。有些下载站把没重命名的压缩包当备份上传,用记事本打开.bak,文件头不是“SQL Server”相关字样就直接删掉重找资源;错误提示“无法导入数据 数据无效”时,十有八九是这种情况。
2.3 部署到Tomcat:war包与直接拷贝项目目录
数据库就绪后,把JSP购物车项目部署进Tomcat。先看压缩包里是war文件还是整个项目目录。
war包方式最简单:把.war复制到Tomcat的webapps目录,启动startup.bat,容器自动解压出同名目录。访问地址是http://localhost:8080/项目名/,项目名就是war文件去掉扩展名后的名字。直接拷贝目录的方式同理,保持WEB-INF结构,整个文件夹放进webapps,不要只拷jsp文件。两种方式本质一样,Tomcat认的始终是WEB-INF/web.xml和WEB-INF/lib。
如果你的项目是传统JSP项目且不带Maven,可以用JDK自带的jar命令在项目根目录打包:
cd shop jar -cvf ../shop.war .这个命令把当前目录所有内容压成war包,执行前确认WEB-INF在压缩包根目录下,而不是外面套了一层shop/shop/WEB-INF。打包后丢进webapps,Tomcat启动时会自动展开。
部署前务必改数据库连接配置。这类项目连接信息一般集中在src下的db.properties,或者DBHelper.java工具类里,把URL、用户名、密码改成2.1节里设置的SQL Server账号。很多课设包默认密码是123456或sa,如果你改了sa密码,这里就是第一个翻车点。启动Tomcat后,观察日志里有没有出现项目名对应的“Deploying web application”,然后访问登录页。页面能加载说明环境通了;如果页面能开但点登录报错,去第4章对照排查数据库连接问题。
3. 读懂购物车核心代码:JSP+Servlet+SQL Server的数据流转
环境通了之后,真正的得分点在于能不能把代码讲清楚。JSP购物车项目的核心就三块:数据库表设计、会话管理、JDBC连接。这章把它们拆开,对照代码说明参数和取舍。理解这三块,等于把Java Web最基础的三层结构——展示层、控制层、数据层——都过了一遍。
3.1 数据库表设计:用户、商品、购物车、订单怎么建
很多下载包里附带建表脚本,表名可能不一样,但四张主表的结构大同小异。用户表记录登录信息,商品表维护库存和价格,购物车表记录“谁买了什么、买几件”,订单表在结算时生成。下面是一套可直接执行的建表脚本:
CREATE TABLE users ( id INT IDENTITY(1,1) PRIMARY KEY, username NVARCHAR(50) NOT NULL UNIQUE, password NVARCHAR(50) NOT NULL, nickname NVARCHAR(50) ); CREATE TABLE product ( id INT IDENTITY(1,1) PRIMARY KEY, pname NVARCHAR(100) NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT NOT NULL, pic NVARCHAR(200) ); CREATE TABLE cart ( id INT IDENTITY(1,1) PRIMARY KEY, user_id INT NOT NULL, product_id INT NOT NULL, count INT NOT NULL DEFAULT 1, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (product_id) REFERENCES product(id) ); CREATE TABLE orders ( id INT IDENTITY(1,1) PRIMARY KEY, user_id INT NOT NULL, total DECIMAL(10,2) NOT NULL, create_time DATETIME DEFAULT GETDATE() );要点说明:NVARCHAR是SQL Server里的Unicode类型,存中文不乱码,比VARCHAR更适合用户名和商品名;金额字段用DECIMAL(10,2)而不是FLOAT,十进制精确类型才能保证价格计算结果正确,浮点数会出现0.1+0.2不等于0.3这种情况;IDENTITY(1,1)是自增主键,插入时不需要显式赋值。购物车表用外键关联用户和商品,意味着同一用户对同一商品可以有多条记录,也可以由业务代码控制去重,这个在3.2节会说到。
注意一点:如果下载包里已经建好了库,不要重复执行CREATE TABLE,会报“数据库中已存在名为users的对象”。检查表是否存在,可以用SSMS左侧目录直接看,或者执行SELECT name FROM sys.tables。
3.2 登录注册与会话管理:session里到底该存什么
登录流程决定购物车归属。常见做法是LoginServlet校验用户名密码后,把整个user对象放进session:
HttpSession session = request.getSession(); session.setAttribute("user", user);购物车页面里判断是否登录,就查这个属性是否为空。如果每个页面都手动判空,代码会非常啰嗦。更省事的方式是写一个过滤器,在web.xml里把需要保护的页面全部拦下来:
<filter> <filter-name>loginFilter</filter-name> <filter-class>com.demo.filter.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>loginFilter</filter-name> <url-pattern>/cart.jsp</url-pattern> <url-pattern>/order.jsp</url-pattern> </filter-mapping>过滤器内部的逻辑很简单:从session里取user,取不到就重定向到登录页,取到就放行。这样购物车页面本身不需要写权限判断,新加受保护页面时只要在映射里加一行即可。这个写法的意义在于把权限校验从散落的Servlet里抽出来,答辩时讲这一条,比说“我用了session存用户”有说服力得多。
购物车数据本身,我倾向于放数据库而不是session。放session的优点是实现快,一个HashMap就能存“商品ID→数量”;缺点是浏览器关了数据就没了,而且session天然是单用户的,没法实现多终端同步。放数据库的cart表,用户每次加购执行一条INSERT或UPDATE,刷新页面后购物车还在,演示时是明显的加分点,成本只多了一条SQL,值得做。session里只存登录用户信息即可,它是“身份凭证”,不承担业务数据存储。
3.3 JDBC连接SQL Server:驱动类名、URL与参数说明
数据访问层是JSP购物车项目的“黑匣子”,大多数报错都集中在这里。标准连接写法如下:
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); String url = "jdbc:sqlserver://localhost:1433;DatabaseName=ShopDB;encrypt=false;trustServerCertificate=true"; String user = "sa"; String password = "123456"; Connection conn = DriverManager.getConnection(url, user, password);几个参数说清楚:Class.forName负责加载驱动类,驱动jar必须放在WEB-INF/lib目录,或通过项目classpath引用,否则抛ClassNotFoundException。URL里的encrypt=false很关键,新版驱动默认要求加密连接,本地SQL Server没配置证书时必须关闭;trustServerCertificate=true表示即使证书不可信也接受,配合前者使用。如果SQL Server改了端口,URL要同步改,比如localhost:14330。
驱动jar版本按经验选:SQL Server 2012/2014用sqljdbc4.jar,SQL Server 2016/2017/2019用mssql-jdbc-7.0以上版本。版本不匹配最常见的报错是“此驱动版本不支持该SQL Server版本”或者握手失败。
把连接封装成工具类,是所有Servlet共用逻辑的正确做法:
public class DBHelper { private static final String DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; private static final String URL = "jdbc:sqlserver://localhost:1433;DatabaseName=ShopDB;encrypt=false;trustServerCertificate=true"; private static final String USER = "sa"; private static final String PASSWORD = "123456"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); } } public static Connection getConn() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }真正执行SQL时,用PreparedStatement而不是Statement,好处是防SQL注入,也避免拼接字符串时处理引号转义。写入操作示例:
String sql = "INSERT INTO cart (user_id, product_id, count) VALUES (?, ?, 1)"; try (Connection conn = DBHelper.getConn(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, currentUser.getId()); ps.setInt(2, Integer.parseInt(request.getParameter("productId"))); ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }参数说明:?占位符用setInt填充,第一个是用户ID,第二个是商品ID。executeUpdate()返回影响行数,为0说明插入失败,可以打日志排查。注意把请求里的字符串转数字时,Integer.parseInt前先判空,否则抛NumberFormatException。价格计算同理,字符串转数字用new BigDecimal(request.getParameter("price")),不要用Double.parseDouble,避免金额精度丢失。
数据库操作完成后,连接、PreparedStatement、ResultSet三个资源都要关。上面用try-with-resources写法,Connection和PreparedStatement会自动关闭,ResultSet也要放进try资源列表或单独关闭。每次都new连接虽然简单,但并发高时会很吃力,课设阶段没问题,性能优化不是这个项目该操心的事。
4. JSP购物车避坑指南:从数据库还原到JDBC报错的五个现场
项目跑起来不算完,把坑提前踩平才能安稳演示。我整理了这类项目里出现频率最高的五个问题,每一条都是“现象→原因→解决”的结构,遇到类似的可以直接照查。
4.1 SQL Server还原失败:备份集版本与物理路径不对
现象:SSMS还原.bak文件弹窗报“数据库备份集”错误,或者提示“无法导入数据 数据无效”,还原进度走一点就中断。
原因:备份文件来自更高版本SQL Server,低版本实例拒绝读取;或者.bak里的物理文件名与当前实例数据目录不一致。还有一种可能,下载站把普通压缩包改名成.bak,文件本身是假的。
解决:先确认SQL Server实例版本能匹配备份来源。版本读不了时换一种交付方式,让对方重新导出.sql脚本,脚本不挑版本。路径不一致的用2.2节的RESTORE FILELISTONLY查看逻辑名称,再用MOVE指向本机安装路径。怀疑文件损坏的,用记事本打开.bak看文件头是不是SQL Server备份标记,不是就删掉重找资源,别在无效文件上浪费时间。
4.2 JDBC连接报错:驱动缺失与TCP/IP未开启
现象:Tomcat控制台出现ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver,或者长时间卡在连接后报The TCP/IP connection to the host ... has failed。
原因:驱动jar没有打进WEB-INF/lib;SQL Server服务没启动或TCP/IP协议被禁用;连接URL的端口和实例实际端口不一致;sa账号密码不对。
解决:先从项目lib目录确认存在sqljdbc4.jar或mssql-jdbc-x.x.jar,没有就从资源包里找对应版本,复制进去后在IDE里“Add as Library”。再用SQL Server配置管理器确认服务运行、TCP/IP启用。命令行执行telnet localhost 1433,能通就是端口没问题。最后单独写一段最小JDBC代码测试连接,排除项目干扰。如果密码里带分号或@这类特殊字符,连接URL解析会出歧义,改用properties文件配置或者对特殊字符转义。
4.3 中文乱码:响应、请求、数据库三层都要统一
现象:商品中文名称在JSP页面显示正常,但提交订单后数据库存成???;或者页面表单提交中文,查询结果为空。
原因:乱码在JSP项目里最容易让人感觉“玄学”,其实规律很清楚,分成三处:页面响应编码、请求参数解码、数据库字段类型。只改某一处,另外两处不一致,中文照样乱。
解决:JSP页面顶部统一写<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>;用一个过滤器在入口处执行request.setCharacterEncoding("UTF-8"),保证所有请求参数先按UTF-8解码;数据库表字段用NVARCHAR而不是VARCHAR,表结构如果已经建成VARCHAR,用ALTER TABLE ... ALTER COLUMN ... NVARCHAR(...)改掉。三层统一后,乱码基本绝迹。
4.4 Tomcat启动失败:端口占用与web.xml版本不匹配
现象:双击startup.bat后窗口闪退,或者启动日志显示Port 8080 required by Tomcat ... is already in use;项目能启动但访问全是404。
原因:8080端口被其他服务占用,常见的是另一个Tomcat实例或开发服务器的端口冲突;web.xml头的version="5.0"与Tomcat 8.5支持的Servlet 3.1不匹配,导致当前项目部署失败。
解决:修改conf/server.xml的<Connector port="8080">为一个新端口,比如8081,重启后访问新端口。命令行netstat -ano | findstr 8080可以定位占用进程PID,再在任务管理器里结束对应进程,两者选一。web.xml版本问题把根元素<web-app version="5.0"改成version="3.1",同时确认代码里没有用到Servlet 5.0独有的API。
4.5 IDEA导入老项目:maven依赖下载失败和Web Facet缺失
现象:用IntelliJ IDEA打开下载的JSP购物车项目,提示Download from maven failed,或者Servlet/JSP代码飘红,项目目录结构里看不到Web模块。
原因:这类课设包大多不是Maven工程,目录结构是传统的src加WebRoot/WEB-INF。用IDEA的Open直接打开,会被识别成普通Java项目,IDEA按Maven处理时必然去找外部依赖,网络一卡就失败。代码飘红是没关联Tomcat的Servlet API,或者驱动jar没有加进模块依赖。
解决:放弃Maven方式。File→Project Structure→Modules→加号→Web,为当前模块指定web.xml和web资源目录;再在Libraries里把Tomcat的servlet-api.jar和SQL Server驱动jar加进来。这样项目变成纯手工Web工程,不依赖网上自动下载。网上那句“intellij idea sqlserver jdbc 自动下载 download from maven failed”说的就是这种场景,手动加库比折腾Maven仓库快得多。
5. 从“能跑”到“能答辩”:购物车项目最后必做的三个动作
项目跑通只完成一半,剩下的一半是让它在答辩和复盘时经得起问。我自己有过教训:第一次做这个题时只对着页面点来点去,觉得哪里都对,结果老师一个“刷新页面购物车为什么还在”就让我愣住了。所以最后三个动作建议你做满。
第一个动作是库存校验。多数模板项目下单时只查购物车,不关心商品表的stock。在OrderServlet下单前加一条查询:SELECT stock FROM product WHERE id=?,当购买数量大于库存时,直接提示“库存不足”,不再生成订单。这一小段逻辑把购物车和商品表关联起来,避免了超卖问题,是面试时容易讲清楚的亮点。
第二个动作是购物车改数量。cart.jsp页面每个商品数量输入框指定name="count",提交到UpdateCartServlet后先做数字校验:
String count = request.getParameter("count"); if (count == null) { response.sendRedirect("cart.jsp"); return; } int newCount; try { newCount = Integer.parseInt(count); } catch (NumberFormatException e) { response.sendRedirect("cart.jsp"); return; } if (newCount <= 0) { // 数量为0或负数时删除该购物车项 }这段代码体现了从请求参数到业务判断的完整链路:先判空,再做类型转换,最后判断业务合法性。页面上的输入框可以被绕过,后端必须每种情况都挡一道,这是一个值得长期保留的习惯。
第三个动作是多浏览器验证会话隔离。用Chrome和Edge同时登录两个账号,分别加购不同商品,互相刷新看购物车内容。如果两个账号的购物车混在一起,说明有人用application或static变量存数据,这是session方案里最典型的错误。一个很有效的验证方法是下单流程走到最后,打开数据库看cart和orders表的记录变化,确保每一步操作都留下了可查的数据痕迹。
我现在的习惯是:答辩前把“注册→登录→加购→改数量→下单”完整跑两遍,一遍正常流程,一遍故意输入负数和不存在的商品ID。项目本身是老技术,但它教会我的请求处理、会话状态、参数校验这些底层能力,在后来接触框架和微服务时仍然通用。别嫌弃这个压缩包里的代码,先把环境跑通,再把每一行讲清楚,最后把它改出自己的痕迹,这门课设就算真正拿到手了。希望帮到你。
本文还有配套的精品资源,点击获取