ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JSP惠友电子产品网上商城完整实战:从数据库设计到答辩展示

JSP惠友电子产品网上商城完整实战:从数据库设计到答辩展示 1. 选题思路与项目定位为什么“jsp惠友电子产品网上商城”值得做如果你正在为JSP毕业设计选题发愁jsp惠友电子产品网上商城这个题目可以重点考虑。它不是那种花哨但做完说不清原理的大项目也不是只有注册登录的水题而是覆盖了电商系统最常见链路的一个完整闭环用户注册登录、商品分类展示、购物车、订单生成、后台商品管理、订单处理。对计算机专业的学生来说这套流程既能体现数据库设计能力又能展示Servlet和JSP的核心用法答辩时也容易讲出东西来。很多同学选课题时容易走两个极端。一种是一上来就选“基于Spring Cloud的微服务商城”结果光是搭环境就耗掉两周最后代码全是抄的一问三不知另一种是选“XX系统”但只做增删改查页面寥寥几个答辩被老师追问“你的项目难点在哪”时直接卡住。惠友电子产品网上商城刚好卡在中间业务完整、难度可控、页面数量适中而且“电子产品”这个定位给商品管理和搜索筛选提供了很自然的发挥空间不是那种空泛的图书管理或新闻发布系统。1.1 这个课题真正值钱的地方第一是业务链路完整。从游客浏览商品到注册登录、加入购物车、提交订单、管理员发货这条主链路是完整电商项目的骨架。做完它你基本就理解了Web项目从前端表单到后端Servlet再到数据库表的全流程数据流转。第二是数据库设计有的讲。电子商城涉及用户、商品、分类、购物车、订单、订单明细、管理员等多张表表之间有一对多、多对一关系订单还要考虑事务和状态流转。这些内容在答辩时可以直接回答“为什么订单表要拆成主表和明细表”这种经典问题。第三是演示效果好。商品列表、商品详情、购物车角标、后台数据导出Excel、视频介绍页……这些都是能“看得见”的功能比抽象的管理系统更适合在答辩现场演示。1.2 功能模块梳理与工作量分配我建议把整个项目按下面几个模块拆开避免一开始就闷头写代码前台用户端注册登录、商品分类浏览、商品搜索、商品详情、购物车管理、订单提交、我的订单、个人信息维护。后台管理端管理员登录、商品管理、分类管理、订单管理、会员管理、数据导出Excel。公共支撑数据库连接工具类、分页工具类、前端公共页面、JSP标签封装。从工作量占比来说数据库设计和表关系梳理大概占30%后端Servlet与JavaBean逻辑占40%JSP页面和样式占30%。很多同学把时间全花在调页面上这是本末倒置。答辩老师真正关心的是你对表结构、请求流转、事务处理的理解深度页面丑一点反而显得真实重要的是核心功能能跑通。2. 技术选型与运行环境先把地基打稳再动手2.1 为什么选JSPServletJavaBean而不是直接上框架经常有学生问我老师JSP都过时了为什么毕业设计还要用这个问题在答辩时也几乎必被问到。我的建议是坦然承认JSP确实不是当前企业主流但要说明白JSP和Servlet是Java Web的底层基础Spring MVC的很多设计思路都是从Servlet规范里发展出来的。你把这个底层逻辑讲清楚比报一个Spring Boot项目背一堆注解有说服力得多。惠友电子产品网上商城采用经典的JSP Servlet JavaBean JDBC三层结构JSP负责页面展示Servlet负责接收请求和跳转JavaBean封装业务数据和数据库操作JDBC负责访问MySQL。这套结构简单直接任何一步报错都能顺着源码追踪非常适合毕业设计阶段用来巩固Java Web基础。另外框架项目在答辩时有一个隐藏风险老师会追问自动配置背后的原理。如果你只是会加注解很难扛住。而JSP项目里每个请求都走得明明白白你有底气讲清楚数据是怎么从数据库到页面显示的。2.2 JDK、Tomcat、MySQL版本怎么搭配更省心先说结论比较稳妥的组合是JDK 1.8 Tomcat 8.5/9.0 MySQL 5.7或8.0 Eclipse/IDEA。JDK版本不用刻意追新JDK 8仍然是很多老项目的主流环境Tomcat对它的支持最稳定。如果你装了JDK 11以上建议直接用Tomcat 9否则会有版本不兼容报错。数据库驱动方面我用的是mysql-connector-java 8.0.33连接URL一定要写成这样String url jdbc:mysql://localhost:3306/huiyou_mall?useSSLfalsecharacterEncodingutf8serverTimezoneAsia/Shanghai;不写serverTimezone的话MySQL 8.0会报时区错误不写characterEncoding的话JSP页面上显示中文商品名很可能乱码。开发工具这边Eclipse和IDEA都行。Eclipse对Dynamic Web Project支持得很直接建好项目就能部署到TomcatIDEA需要配置Artifact和External Libraries新手容易卡住。如果你用的是IDEA记住一个关键点WEB-INF/lib目录下必须能看到你引入的jar包否则运行时找不到类。2.3 项目目录结构与JSP编译运行机制一个标准的JSP电子商城项目目录结构大概长这样HuiyouMall/ ├─ src/ │ ├─ com.huiyou.entity │ ├─ com.huiyou.dao │ ├─ com.huiyou.servlet │ ├─ com.huiyou.util │ └─ com.huiyou.filter ├─ WebContent/ │ ├─ index.jsp │ ├─ login.jsp │ ├─ register.jsp │ ├─ cart.jsp │ ├─ order.jsp │ ├─ admin/ │ │ ├─ goods_list.jsp │ │ ├─ order_list.jsp │ │ └─ export_excel.jsp │ ├─ WEB-INF/ │ │ ├─ web.xml │ │ └─ lib/ │ │ ├─ mysql-connector-java-8.0.33.jar │ │ └─ fastjson-1.2.83.jar │ ├─ css/ │ ├─ js/ │ └─ upload/ │ ├─ images/ │ └─ videos/ └─ sql/ └─ huiyou_mall.sql这里有一个和热词“jsp编译class文件保存在哪里”直接相关的机制我提前说清楚JSP文件本身不是直接被执行的。第一次有人访问某个JSP时Tomcat会把它翻译成一个_jsp.java文件再编译成_jsp.class文件然后执行这个Servlet类。这个编译产物不会出现在你的项目目录里而是存放在Tomcat的work目录下。后面我会单独用一节详细讲这个问题因为太多项目因为这个机制出了“改了没生效”或者“找不到class”的怪事。3. 数据库设计电子商城项目最重要的30%工作量3.1 实体关系梳理惠友电子产品网上商城的数据库我设计了七张核心表用户表、管理员表、商品分类表、商品表、购物车表、订单表、订单明细表。实体关系看着复杂画一张图就清楚了一个用户有多个订单一个订单包含多个订单明细一个订单明细对应一个商品商品属于一个分类购物车是用户和商品之间的关联表。这里要重点说订单为什么要拆成“订单表”和“订单明细表”两张。订单表存的是整笔订单的公共信息比如下单用户、订单编号、总金额、收货人、订单状态订单明细表存的是这笔订单里的每一项商品比如买了哪几个商品、每个买了多少件、下单时单价是多少。如果不拆一笔订单买三件商品就要在订单表里存三行连“收货人是谁”这种信息都要重复三次数据冗余严重后面统计订单总金额也很麻烦。3.2 核心表字段设计参考下面是几张核心表的字段设计你可以直接参考表名主要字段说明userid, username, password, nickname, phone, address, avatar, create_time用户表密码建议存加盐后的MD5categoryid, name, sort_order商品分类表goodsid, category_id, name, brand, model, price, stock, image, detail, create_time商品表电子产品带品牌和型号字段cartid, user_id, goods_id, quantity, add_time购物车表一个用户可有多条记录ordersid, order_no, user_id, total_price, receiver_name, receiver_phone, receiver_address, status, create_time订单主表order_itemid, order_id, goods_id, goods_name, goods_price, quantity订单明细表冗余商品名称和下单时价格商品表里的image字段存的是图片的相对路径比如upload/images/手机.jpg不要直接把整张图片以二进制流存到数据库里。这样页面渲染更简单数据库体积也不会暴涨。3.3 设计阶段最容易踩的三个坑金额类型必须用decimal。商品单价和订单总金额不要用float或double浮点数在计算总价时会出现类似0.1 0.2 0.30000000000000004的精度问题。用decimal(10,2)可以精确到分订单金额计算才可靠。订单明细要冗余商品名称和下单时价格。这一点是很多新手容易忽略的。假设商品价格今天从5999改成4999之前已下单的订单明细如果只存goods_id再去关联商品表查价格查出来的就是改变后的价格历史订单金额就失真了。所以在生成订单明细时要把商品名称和当时单价直接冗余存下来这是电商系统的常规做法。库存扣减要做条件判断。提交订单时不能只“查库存是否够”然后“减少库存”这两步之间很可能被别人插进来。正确做法是在一条UPDATE语句里完成条件判断和扣减比如UPDATE goods SET stock stock - 1 WHERE id ? AND stock 1影响行数为0就说明库存不足下单失败。配合事务一起用才能保证不会超卖。4. 核心功能实现从注册登录到订单闭环4.1 用户注册登录与Session会话管理用户模块是整个商城的前置基础。注册页面负责收集用户名、密码、手机号等信息注册Servlet收到请求后先检查用户名是否被占用没有被占用再把密码加密落库。加密我建议用MD5加盐虽然电子商城毕设里很多人直接存明文但答辩时老师看到你考虑到了安全存储观感会好很多。登录成功后的关键操作是把用户对象放进Session并设置过期时间。这样用户在浏览商品、操作购物车、进入个人中心时都能通过Session判断“当前是谁”。JSP页面里用${sessionScope.user.username}就能直接显示登录用户名不用写Java代码。这里给一个登录Servlet的核心代码参考protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); UserDao userDao new UserDao(); User user userDao.findByUsernameAndPassword(username, Md5Util.getMd5(password)); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(user, user); session.setMaxInactiveInterval(30 * 60); response.sendRedirect(request.getContextPath() /index.jsp); } else { request.setAttribute(errorMsg, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } }一定要写request.setCharacterEncoding(UTF-8)不写的话表单提交的中文用户名或密码在数据库比对时极可能因为编码不对而匹配失败。4.2 商品列表分页与关键字搜索商品展示页面最核心的能力是分页和搜索。分页SQL用LIMIT实现SELECT * FROM goods WHERE category_id ? AND name LIKE CONCAT(%, ?, %) ORDER BY id DESC LIMIT ?, ?这里的?分别是分类ID、搜索关键字、当前页起始偏移量、每页条数。每页我习惯设8条或12条电子产品图片大列数太多反而难看。分页参数封装成一个PageBean对象包含pageNo、pageSize、totalCount、totalPage、list五个属性Servlet查完数据后把PageBean放进requestJSP页面用JSTL的c:forEach遍历输出。搜索功能有个细节要提醒必须用PreparedStatement的占位符拼SQL不能直接字符串拼接。直接拼接虽然也能跑通但存在SQL注入风险。答辩时老师问“你的搜索条件防注入吗”你回答“用的是预编译占位符”这就是加分项。商品详情页要看一个商品的完整信息路由设计可以简单一点比如goods_detail.jsp?id18Servlet根据request.getParameter(id)查出商品后转发到详情页。JSP页面里商品图片用${pageContext.request.contextPath}拼接绝对路径避免因为页面层级不同而找不到图片。4.3 购物车与下单事务购物车这一块我可以直接给你结论毕设项目推荐把购物车数据存到数据库表而不是放在Session或Cookie里。原因有两个第一数据库购物车在用户换浏览器、清缓存后依然存在演示时更可靠第二后台可以顺便看到所有会员的购物车情况功能上多一个可讲的点。商品详情页点“加入购物车”后端逻辑是先判断用户是否登录未登录跳转到登录页已登录则检查购物车表里是否已有该用户和该商品的记录有就把数量加1没有就插入一条新记录。购物车页面展示时要把购物车表和商品表关联查出商品名称、图片、单价并用goods_price * quantity算每一项小计。下单是整个项目里唯一需要“事务”的地方。用户点击提交订单后后端要连续做三件事写入订单主表、写入订单明细表、扣减商品库存。这三件事必须同时成功或同时失败。如果在Tomcat默认配置下前两步成功、第三步失败就会出现“订单生成了但库存没扣”的脏数据。处理办法是用JDBC的Connection手动控制提交Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); OrderDao orderDao new OrderDao(); orderDao.insertOrder(conn, order); orderDao.insertOrderItems(conn, orderItemList); int rows goodsDao.deductStock(conn, goodsId, quantity); if (rows 0) { conn.rollback(); // 提示库存不足 return; } conn.commit(); } catch (Exception e) { if (conn ! null) { conn.rollback(); } e.printStackTrace(); } finally { if (conn ! null) { conn.setAutoCommit(true); conn.close(); } }这段代码里deductStock执行的条件UPDATE就是前面说的库存判断返回影响行数为0就回滚整个事务。这是整个项目里最能体现“系统设计能力”的一段代码答辩时值得重点讲。4.4 个人信息展示页面怎么设计才不土“jsp个人信息展示页面”是一个高频搜索热词说明很多人在这个页面上卡住了。我的建议是不要做一个单纯展示用户名的死页面而是把个人中心设计成左侧菜单、右侧内容区的结构。左侧放“我的资料”“我的订单”“收货地址”“修改密码”右侧根据点击切换显示不同内容。数据回显的核心思路是页面顶部从Session中取用户对象然后直接渲染。修改资料时表单里给每个输入框的value填上当前用户信息用户提交后Servlet更新数据库再重新查询用户信息放回Session最后转发回个人信息页面。注意如果不把更新后的用户对象重新放回Session页面上显示的永远是旧数据这是最常见的Bug。如果个人信息页里要带一个“我的订单列表”可以用下面的方式循环展示% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % c:forEach items${orderList} varorder tr td${order.orderNo}/td td${order.totalPrice}/td td${order.statusText}/td /tr /c:forEach这里要求Servlet把查到的orderList放进request域页面里只用EL和JSTL就能完成展示不要往JSP里塞大段Java代码。4.5 管理员后台的数据导出Excel功能管理员需要把商品列表或订单列表导出成Excel这个功能在课题里看着不大却特别容易被问细节。网上常见的做法是在JSP页面里输出一个table然后把响应头改成Excel类型让浏览器下载。这个方案对纯数字表格勉强能用但只要表格里有商品图片、换行文本或特殊字符导出的文件很容易损坏。更稳的做法是用Apache POI在Servlet里生成真正的Excel文件再通过响应流输出。核心代码如下response.setContentType(application/vnd.ms-excel;charsetUTF-8); String fileName URLEncoder.encode(商品列表.xls, UTF-8); response.setHeader(Content-Disposition, attachment;filename fileName); Workbook workbook new HSSFWorkbook(); Sheet sheet workbook.createSheet(商品列表); Row header sheet.createRow(0); header.createCell(0).setCellValue(商品名称); header.createCell(1).setCellValue(品牌); header.createCell(2).setCellValue(价格); header.createCell(3).setCellValue(库存); // 遍历商品数据填充后续行... workbook.write(response.getOutputStream()); workbook.close();注意文件名中文一定要做URL编码否则不同浏览器下会出现“下载文件名乱码”的问题。POI的jar包要放到WEB-INF/lib目录下这块细节后面排查热词里我再展开。5. JSP高频问题排查记录这些坑我基本都踩过5.1 jsp改了不生效三步定位法“jsp改了不生效”基本是JSP开发新手必遇问题。表现形式是你在Eclipse或IDEA里改了页面代码保存、刷新浏览器页面还是老样子。遇到这种情况先别急着怀疑Tomcat按顺序排查第一步清浏览器缓存并强制刷新。浏览器发现当前URL有缓存时可能直接使用本地缓存的HTML根本不会向服务器发请求。在页面上按CtrlF5强制刷新一般能解决一半问题。第二步看IDE是否把修改同步到了Tomcat。Eclipse里修改JSP后需要保证项目处于自动发布状态有时要右键项目名称选择Clean清理再Publish重新发布。IDEA里则是重新Build或Restart服务器。第三步删除Tomcat的work目录后重启。因为JSP会预编译成class文件放在work目录如果Tomcat认为这个class还是最新的就不会重新编译页面。直接把work目录下对应项目的文件删掉再重启Tomcat让它强制重新翻译编译一次。一个容易混淆的点修改JSP文件通常不需要手动重启TomcatTomcat默认会自动检测JSP的修改时间并重新编译。但修改了Java类或者web.xml就必须重启Tomcat才生效。如果改完Java类发现没变化问题多半不在JSP机制而是IDE没有重新编译部署。5.2 jsp编译class文件到底保存在哪里JSP文件被Tomcat翻译后生成的Java和class文件存放在work目录里。具体路径是Tomcat安装目录/work/Catalina/localhost/项目名/org/apache/jsp/比如项目名是HuiyouMall访问index.jsp后在这个目录下能看到index_jsp.java和index_jsp.class两个文件文件名里的点变成了下划线。如果JSP在子目录下比如admin/goods_list.jsp对应的文件就是admin/goods_list_jsp.java。在IDEA里使用内置Tomcat时work目录不一定在Tomcat安装目录下而是被重定向到了系统临时目录比如C:\Users\你的用户名\AppData\Local\Temp\Tomcat...。你可以打开控制台看Tomcat启动日志里的Using CATALINA_BASE和CATALINA_HOME前者指向的目录下就有work。这个路径有什么用首先是排查“改了不生效”直接删掉对应的index_jsp.class再重启肯定重新编译。其次是调试JSP报错时Tomcat的500错误页会提示“Unable to compile class for JSP”打开这个目录下生成的index_jsp.java能看到出错行对应的翻译后代码比盯着JSP源码更直观。需要特别说明的是这部分class文件是Tomcat运行时动态生成的不要手动添加到项目里也不要试图在build/classes目录里找它。5.3 jsp jsonarray importJSON包引入与Ajax交互做商城时经常需要异步判断用户名是否已存在、异步加载购物车数量这就涉及JSON。很多人在JSP里写JSONArray报错就是import没弄对。JSP页面顶部需要这样导入% page importcom.alibaba.fastjson.JSONArray % % page importcom.alibaba.fastjson.JSONObject %引入后还有两件事必须做否则照样报ClassNotFoundException。第一把fastjson-1.2.83.jar放进项目的WEB-INF/lib目录。很多同学只在IDE的Build Path里加了jar运行时Tomcat在类路径里找不到这是最常见的原因。第二检查部署后的项目里WEB-INF/lib下确实有这个jarEclipse里可以在Deployment Assembly里配置IDEA里要确认Artifact输出包含lib依赖。对于这种异步场景我更推荐的做法是Servlet返回JSON字符串JSP页面用jQuery发送Ajax请求。Servlet侧不需要操作JSP里的JSONArray而是在Java代码里引入fastjson的JSONObject组装数据后通过response.getWriter().write(jsonString)输出。页面侧的写法是$.post(${pageContext.request.contextPath}/checkUsername, { username: username }, function(result) { if (result.valid false) { alert(用户名已被注册); } }, json);把JSON生成逻辑放在Servlet里JSP页面只做展示结构更清晰也避免在JSP页面里混入大量Java逻辑。5.4 jsp实现mp4视频播放路径和MIME映射电子产品商城经常要在详情页放一段产品宣传视频“jsp实现mp4视频播放”这个热词就是因为很多人视频放不出来才搜的。HTML5提供了一套非常简单的视频标签JSP页面里直接写video src${pageContext.request.contextPath}/upload/videos/product.mp4 controlscontrols width640 height360 您的浏览器不支持HTML5视频播放。 /video放不出来基本都是两个原因。第一个是路径问题。视频文件放在WebContent/upload/videos/目录下页面上要用${pageContext.request.contextPath}拼出绝对路径而不是相对路径。如果你直接写upload/videos/product.mp4在goods_detail.jsp位于一级目录时可能能访问但页面一旦放到admin/子目录下相对路径就失效了。第二个是MIME类型问题。Tomcat新版本已经内置了video/mp4的MIME映射但部分旧版本或自定义配置不完整时浏览器拿到响应后不认识它就不会触发视频播放。你可以在web.xml里加一段保险配置mime-mapping extensionmp4/extension mime-typevideo/mp4/mime-type /mime-mapping还有一个容易被忽略的点浏览器对视频编码有要求通常要H.264 AAC的MP4文件才能直接播放。从网上下载的有些MP4是H.265编码或用其他封装格式放进页面后就会黑屏、有声音没画面或者干脆无法播放。建议先用格式工具转成标准H.264格式再上传。5.5 jsp实现数据导出excel的正确打开方式前面4.5里我讲了用POI在Servlet中导出Excel这部分聊聊为什么不要直接在JSP页面里导出以及经常遇到的坑。一种错误写法是在JSP页面上放一个导出按钮点击后在另一个JSP里用JSP内置对象out输出Excel内容。这样做的结果是JSP引擎会把% page %指令和HTML模板中可能存在的空行、换行、空格都当成响应内容输出导致导出的Excel文件开头多出一串空行或乱码Excel打开时直接提示文件已损坏。正确思路是另写一个独立的ExportGoodsServlet专门处理导出请求。Servlet里不涉及任何HTML输出只负责生成Workbook并通过response.getOutputStream()写出。同时要注意在一个响应里不能同时调用response.getWriter()和response.getOutputStream()这两个方法同时使用会抛IllegalStateException导出功能自然就失败了。另外如果导出数据量比较大比如几十万条订单POI的HSSFWorkbook会有内存压力可能直接OutOfMemory。毕设场景里数据量一般不大不需要专门优化但这个方向值得在答辩时提一句“如果要支持大数据量导出可以改用SXSSFWorkbook流式写入”。6. 答辩展示与项目扩展建议6.1 答辩时怎么讲这个项目才有亮点答辩时间通常只有五分钟到十分钟很多同学上来就点页面“这是首页这是商品列表这是购物车”讲完时间也到了老师对你的能力认知几乎为零。换个思路不用把页面全部演示一遍挑三个最能体现设计能力的点讲透。第一个是订单事务处理。直接说“我的下单功能使用了数据库事务入库、扣库存、写明细三件事要么全成功要么全失败保证数据一致性”然后切到代码里setAutoCommit(false)那一行给老师看。第二个是数据库表设计重点说订单主表和明细表的拆分原因。第三个是登录状态管理讲清楚Session的创建、保存、销毁以及登录拦截Filter怎么设计。提前准备几个必被问到的问题JSP和Servlet到底是什么关系Session和Cookie有什么区别为什么用PreparedStatement商品搜索的关键字是怎么传到数据库的这些问题都能在课题里找到自然答案不要背概念要结合你的页面说明。6.2 从毕设到更完整系统的三个扩展方向如果时间和精力允许可以在现有项目上加三个扩展方向。第一把前端页面逐步换成Vue或原生JavaScript的异步交互后端Servlet接口保持不变改成返回JSON数据这样整个系统的前后端职责更清晰也能体现你对现代Web开发的理解。第二引入Redis保存Session和购物车数据服务重启后登录状态不丢失这是从单机项目走向分布式架构的一个小尝试。第三给订单模块对接一个支付沙箱接口模拟支付回调流程虽然这超出了JSP课程要求但在简历上可以作为一个完整闭环项目来写。我个人经验是不要贪多。先把现有主链路跑得特别稳再把其中一个扩展方向做出来就比绝大多数毕设项目完整了。答辩老师看重的不是你用了多少技术而是你能不能把一个功能从设计到实现讲得清清楚楚。
返回列表