多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

基于JSPM的尤文图斯足球俱乐部商城系统开发全流程

基于JSPM的尤文图斯足球俱乐部商城系统开发全流程 做这个选题的时候说实话我心里是有点犹豫的。网上随便一搜满屏都是图书管理系统学生管理系统企业OA系统同质化严重到答辩老师可能一天要看十几遍。我当时就想着能不能找一个既贴合Java Web课程知识体系又不至于把自己绕晕的题目。最后定下基于JSPM的尤文图斯足球俱乐部网上商城系统一是因为自己确实看了十几年球对俱乐部周边产品的品类和用户的购买习惯有直觉二是JSPM这个技术栈——JSP Servlet JavaBean MySQL——足够经典把Web开发的请求响应、会话管理、数据持久化全链路都覆盖了一遍用来做毕业设计既撑得住场面又不会像Spring全家桶那样把大部分原理封装得看不见。这篇文章我不打算写成标准的系统说明书而是想把从确定需求、设计数据库到一步步实现购物车和订单流程再到最后写论文、录演示视频、准备答辩的真实过程拆开来讲。如果你正在纠结毕业设计题目或者选了JSPM但不知道从哪里下手这篇东西应该能帮你省掉不少弯路。1. 选题背后的真实动机为什么是足球俱乐部商城1.1 毕业设计选型的常见误区每年毕业季我都能看到隔壁组同学在做XX管理系统——不是说不可以做而是这类题目的业务逻辑太线性了增删改查而已压根体现不出一个Web系统的完整闭环。商城系统就不一样它有商品列表、商品详情、用户注册登录、购物车、下单、结算支付模拟这一整条业务链每一环都有明确的交互逻辑和数据处理需求拿来当作Java Web课程设计的承载对象知识点覆盖是非常完整的。另一个误区是追求高大全。有人一上来就想做秒杀、做分布式、做消息队列结果连数据库表之间的关系都没理清楚。我当时把需求砍得特别克制前台用户端做了商品浏览、按分类筛选、搜索、购物车管理、订单提交与管理后台管理端做了商品管理、库存管理、订单状态管理、用户管理。就这些没了。因为毕业设计的核心是把一个完整的东西做透彻而不是把一个庞大的东西做得稀烂。1.2 JSPM技术栈为什么仍然值得选JSPM不是某个框架而是 JSP Servlet JavaBean MySQL 的组合很多高校的Java Web程序设计课程就是按这个体系教的。选它有几个非常实际的好处贴近课程内容课程考试、实验报告、结课作业都围绕这套技术展开做项目的时候翻课本就行不太需要额外啃框架文档。原理透明没有Spring的自动化装配所有对象创建、请求分发、数据库连接都是自己一行行写出来的这对答辩特别有利。老师问请说明一次请求从浏览器到数据库再返回的完整过程你可以把每一行代码在干什么说得明明白白。部署简单不需要搞复杂的容器编排一个Tomcat加一个MySQL就能跑起来演示环境不容易翻车。当然我也得把丑话说在前面JSPM这套东西放到真实生产环境中确实过时了前端渲染靠JSP、控制逻辑堆在Servlet里开发效率和可维护性都不高。但作为毕业设计它的定位就是教学演示型项目把Web的核心原理吃透之后再去学Spring Boot、Vue这类工程化的东西理解成本会明显降低。1.3 功能清单的确定需求要先做减法当时我花了一个晚上列功能点第一版写出来整整二十多个功能包括积分系统、优惠券系统、限时折扣、用户评论楼中楼……冷静下来后我把超过工作量、又对主流程没有决定性影响的功能全删了。最终保留的主线功能只有两组用户端注册与登录密码使用MD5加密存储商品浏览首页推荐、分类查看、关键字搜索商品详情页展示图片、价格、库存、详细介绍购物车加入、修改数量、删除、清空订单提交订单、查看我的订单列表、取消未支付订单、模拟支付管理端管理员登录商品管理新增、编辑、上下架、删除库存管理进货补库存订单管理查看所有订单、修改订单状态发货/完成用户管理查看用户列表、禁用异常账号要注意我一再强调减法不是偷懒而是为了让每个保留的功能都能做得扎实。特别是订单流程它牵涉到购物车快照、库存扣减、状态流转这些才是真正体现能力和工作量、也最容易被答辩老师盯上的地方。2. 数据库设计先行商城的整座地基2.1 从商品表到购物车表的关系梳理我见过太多同学一上来就写代码写到购物车发现数据存哪都不对劲又回头改表结构。数据库是商城系统的地基这个顺序千万不能反。我最终设计了六张核心表每张表背后的设计理由我逐个说一下。用户表t_user主键信息、用户名、密码密文、联系方式、收货地址、注册时间、账号状态等。用户名加了唯一索引这个不用多解释注册逻辑里必须要做重复校验。账号状态字段是给管理端禁用用户功能用的虽然业务上比较粗暴但作为课程设计完全说得通。商品表t_product商品主键、名称、价格、原价、库存、所属分类、主图路径、详情描述、创建时间、是否上架。价格统一用小数存储比如DECIMAL(10,2)不要用FLOAT否则计算金额会出现精度问题这是一个非常经典的坑。库存字段用整数。是否上架这个字段特别关键管理端可以做下架操作下架的商品在用户端就查询不出来了这比直接删除商品要合理得多——订单历史里还引用了商品的名称和图片呢硬删会导致外键断裂或空引用。商品分类表t_category分类主键、分类名称。尤文图斯商城我分了几类球衣、训练装备、生活周边、纪念品。分类表不要做得太深一级分类就够了省去递归查询的麻烦。购物车表t_cart购物车主键、用户ID、商品ID、加入数量。这里有个典型的取舍购物车数据存Session还是存数据库。我最终选了数据库原因有二一是用户换浏览器、清缓存之后购物车数据不丢二是管理端可以查看到用户加入购物车但未下单的商品以此做简单的偏好分析这个点在论文里可以写成基于购物车数据的商品推荐展望。代价是每次加载购物车都要查一次数据库但对于课程设计的数据量来说性能完全不是问题。订单主表t_order订单号、用户ID、订单总金额、收货人信息直接冗余姓名、电话、地址、订单状态、下单时间、支付时间。订单号不要用自增ID建议用时间戳加随机数拼一个字符串。收货信息必须冗余到订单表里不能下单时再去关联用户表的地址——因为用户之后可能改了地址但你这个订单的收货地址是不能变的。订单明细表t_order_item明细主键、订单号逻辑外键、商品ID、购买时的商品名称、购买时的商品单价、购买数量、小计金额。商品名称和价格在这里也要冗余一份理由同上商品可能被修改、下架甚至删除但用户的订单历史必须原样保留。这就是订单快照的设计思路。没有快照的订单系统在答辩时基本是送人头。2.2 关于外键的取舍我建表的时候没有使用物理外键数据库级FOREIGN KEY约束所有表之间的关联都靠逻辑外键自己维护的关联字段来实现。原因很实际物理外键在删除、更新时会有一堆级联约束写SQL做测试的时候非常容易报错。课程设计阶段数据量小逻辑外键完全能保证业务正确性。演示删除商品这样的功能时物理外键可能会因为订单明细还在引用而删除失败反而会让演示流程卡壳。当然逻辑外键要求程序员在业务代码里自己保证数据一致性。比如删除一个用户之前要检查他有没有未完成的订单删除商品前检查购物车和订单明细里有没有引用。这些检查逻辑写在Service层里体现的恰恰是业务设计能力。2.3 建表的SQL语句修修改改了几轮第一版SQL我写了两个小时后来不断增加字段又改了四五次。这里直接给出一份关键建表语句字段名按照我实际项目的习惯做了整理你可以直接参考CREATE TABLE t_product ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 商品主键, product_name VARCHAR(100) NOT NULL COMMENT 商品名称, price DECIMAL(10,2) NOT NULL COMMENT 销售价格, original_price DECIMAL(10,2) DEFAULT NULL COMMENT 划线原价, stock INT NOT NULL DEFAULT 0 COMMENT 库存数量, category_id INT NOT NULL COMMENT 分类ID, image_path VARCHAR(255) DEFAULT NULL COMMENT 商品图片路径, description TEXT COMMENT 商品详细描述, is_on_sale TINYINT DEFAULT 1 COMMENT 是否上架1是 0否, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) COMMENT 商品表; CREATE TABLE t_cart ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL COMMENT 用户ID, product_id INT NOT NULL COMMENT 商品ID, quantity INT NOT NULL DEFAULT 1 COMMENT 购买数量, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT 购物车表; CREATE TABLE t_order ( order_no VARCHAR(32) PRIMARY KEY COMMENT 订单号, user_id INT NOT NULL, total_amount DECIMAL(10,2) NOT NULL COMMENT 订单总金额, receiver_name VARCHAR(50) NOT NULL COMMENT 收货人, receiver_phone VARCHAR(20) NOT NULL, receiver_address VARCHAR(255) NOT NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待支付 1已支付 2已发货 3已完成 4已取消, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, pay_time DATETIME DEFAULT NULL ) COMMENT 订单主表; CREATE TABLE t_order_item ( id INT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL COMMENT 所属订单号, product_id INT NOT NULL, product_name VARCHAR(100) NOT NULL COMMENT 商品名称快照, price DECIMAL(10,2) NOT NULL COMMENT 成交单价快照, quantity INT NOT NULL, subtotal DECIMAL(10,2) NOT NULL COMMENT 小计金额 ) COMMENT 订单明细表;3. 代码分层与请求流转最标准也最容易走样的地方3.1 经典的JSPM分层到底分哪几层上课的时候老师画的图是 JSP → Servlet → JavaBean → MySQL听起来很简单但真正落地的时候很容易走样。最常见的走样就是JSP页面里堆满了Java业务代码Servlet里又要拼接HTML输出。我自己的代码分是这样组织的视图层JSP只负责渲染数据。页面里使用EL表达式和JSTL标签处理动态内容涉及枚举、判断尽量用c:forEach和c:if。控制层Servlet只做三件事——接收请求参数、调用业务方法、决定跳转或转发到哪个页面。业务层Service / JavaBean把数据库操作和业务规则封装成方法。比如addToCart方法内部要做参数校验、查库存、判断是否重复加入这些逻辑都写在业务层而不是Servlet里。数据访问层DAO封装对数据库的增删改查SQL操作。框架源码管理这一块我还额外做了点工作整个项目按页面模块建包servlet包再按controller、admin拆开避免几十个Servlet类堆在一个目录里。这个习惯放到以后的任何项目里都是受用的。3.2 Servlet的统一处理一个请求一个入口Servlet的映射我没有用那种一个页面配一个Servlet的粗暴方式而是用了统一拦截某个路径前缀的做法。比如用户端所有请求都走/user/*然后在Servlet里用WebServlet(/user/*)结合request.getRequestURI()做分发根据最后一段路径决定调用哪个业务方法。WebServlet(/user/*) public class UserCartServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String path request.getRequestURI().substring(request.getContextPath().length()); switch (path) { case /user/cart/list: showCartList(request, response); break; case /user/cart/add: addToCart(request, response); break; case /user/cart/update: updateCartItem(request, response); break; case /user/cart/delete: deleteCartItem(request, response); break; default: response.sendError(HttpServletResponse.SC_NOT_FOUND); } } }这样写的好处非常明显每个页面对应的URL清清楚楚修改某个功能只需要动一个方法而且过滤器Filter只需要对一个前缀做登录校验不用写一堆重复的检查代码。我配合写了一个LoginFilter拦截/user/*路径从Session里取不到已登录用户就重定向到登录页。3.3 数据库连接从DriverManager手动获取到连接池第一个版本我用了最原始的DriverManager.getConnection()一个用户访问页面就开一个连接、用完就关实测写购物车加订单时明显感觉页面卡顿。后来换成了阿里的Druid连接池配置放在druid.properties文件里driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/juventus_mall?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai usernameroot passwordyourpassword initialSize5 maxActive20用连接池之后数据库连接不复用就是不释放性能提升很明显。而且Druid自带监控页面虽然课程设计不需要展示这个但我在论文里专门写了一段基于连接池的应用性能优化答辩老师对这段评价还不错——因为它超出了能跑就行的层次。DAO层的代码我统一用PreparedStatement执行SQL参数全部用?占位符从根上杜绝了SQL注入问题。这个点答辩必问你得准备好解释为什么PreparedStatement能防注入因为预编译机制会先把SQL骨架发送给数据库做编译后面的参数只作为纯数据处理不会参与SQL结构拼接所以单引号、注释符这类注入Payload没法改变原有语句结构。3.4 前端JSP页面的组织避免一页到底商品展示页面是用户打开商城的第一印象我当时用了一个通用商品卡片列表模板每个卡片显示商品图、名称、价格和一个加入购物车按钮。JSP里用JSTL循环渲染商品列表c:forEach varproduct items${productList} div classproduct-card img src${pageContext.request.contextPath}${product.imagePath} alt${product.productName} / div classproduct-name${product.productName}/div div classproduct-price${product.price}/div a href${pageContext.request.contextPath}/product/detail?id${product.id}查看详情/a button onclickaddToCart(${product.id})加入购物车/button /div /c:forEach这里特别提醒一个坑图片路径。商品图片我放在了webapp/upload目录下但JSP页面里引用图片时一定要用${pageContext.request.contextPath}拼接项目上下文路径否则直接写/upload/xxx.jpg在部署时会因为项目名不一样而找不到图片。这个小问题当时坑了我一个下午浏览器控制台全是404我还傻傻地以为是图片上传逻辑写错了。页面整体风格走的深色黑白搭配契合尤文图斯球队视觉。这些都是CSS的活不需要额外引入前端框架自己写响应式网格布局就够用了。4. 购物车与订单流程整条业务链里最见功底的部分4.1 购物车会话保持数据库购物车表的设计实现购物车功能大家平时买东西都用过但自己动手实现一遍才能真正理解什么叫会话状态。我选择把购物车数据持久化到t_cart表用户在未登录状态不能使用购物车点击加入购物车会先被过滤器重定向到登录页。加入购物车的核心逻辑是这样的接收商品ID和数量参数。判断购物车里是否已有同一用户、同一商品。如果已存在把数量累加如果不存在新增一条记录。每次执行前检查商品库存是否充足。这里还有一个细节是对购物车中的商品失效的处理。比如一个商品被管理员下架了用户在购物车还能看到这条记录如果直接删除会让用户困惑。正确的做法是查询购物车列表时使用左连接查出商品的最新状态如果已下架就置灰并提示该商品已下架无法结算。4.2 提交订单事务、库存扣减与并发控制订单提交是整个项目里技术含量最高、也最容易翻车的模块。它的动作链条是从购物车查出用户勾选的商品详情计算总金额生成订单主表和明细表扣减商品库存清空对应购物车记录。这中间任何一步失败都不能让系统处于订单生成了一半库存没扣这种中间状态。所以必须用事务把它们包起来。我的实现是在Servlet里手动管理JDBC事务Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 orderDao.insertOrder(conn, order); // 插入订单主表 for (CartVO item : cartList) { orderItemDao.insertOrderItem(conn, order, item); // 插入订单明细 productDao.deductStock(conn, item.getProductId(), item.getQuantity()); // 扣库存 } cartDao.clearCart(conn, userId); // 清空购物车 conn.commit(); } catch (Exception e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } throw new RuntimeException(订单提交失败); } finally { if (conn ! null) { try { conn.setAutoCommit(true); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }关于扣库存的SQL这是最核心的一条UPDATE t_product SET stock stock - #{quantity} WHERE id #{productId} AND stock #{quantity}注意这个AND stock #{quantity}条件它的作用是带条件的更新。如果库存不足这条SQL影响的行数会是0代码里检查影响行数就能感知到库存不足从而抛出异常回滚整个事务而不是等到后面插入订单明细成功了才发现库存是负数。这就是在很多项目里被反复强调的乐观锁扣减思想在JSPM这种教学技术栈下完全可以自己用SQL实现出来。当然如果并发量真的极大这种写法在极端情况下也有局限性但对于毕业设计的演示场景已经绰绰有余了。答辩的时候老师如果问多个用户同时抢购同一商品怎么办你只要把这个SQL的设计逻辑讲清楚再补一句真实生产环境还可以使用Redis分布式锁等方案就已经把深度展现出来了。4.3 订单状态机从待支付到已取消订单状态我定义成五档待支付、已支付、已发货、已完成、已取消。状态流转不能乱跳比如待支付可以取消可以支付已支付只能发货已发货只能完成。用户端的操作按钮是根据状态动态渲染的待支付显示去支付和取消订单。已支付只显示查看物流模拟和确认收货。已完成显示删除订单逻辑删除或直接隐藏。模拟支付我做了个独立的pay.jsp页面展示订单号和应付金额底部放一个模拟支付成功的按钮。虽然这只是一个假动作但页面要做得像样支付成功后订单状态改为已支付并记录支付时间。论文里写对接第三方支付接口的扩展方案时还可以顺便提一下支付宝沙箱环境——不过那就不用真做了。4.4 夜以继日排过的几个真实大坑这部分我单独拿出来说因为都是我在编码和演示阶段真正碰到过的问题常规教程里不会写第一个坑订单号和收货信息的静态化。最开始我偷懒订单表里不存收货人、电话、地址结账时直接联查用户表的地址字段。后来自己测试时改了用户地址发现历史订单的收货地址也跟着变了这才意识到订单必须做数据快照赶紧改了表结构。这种事如果在答辩演示时被发现会非常尴尬。第二个坑商品删除策略。最初我有物理删除商品的功能后来发现订单明细表的外键关联会让删除动作牵一发动全身。改成了逻辑上下架之后管理端删除按钮改成下架按钮订单历史完全不受影响整个系统的稳定性和演示流畅度提升了一大截。第三个坑图片路径和数据库的连接编码。图片路径问题前面说过了编码问题是往数据库里插入中文商品名称时全部变成了问号。排查到最后才发现是MySQL连接的URL里少了characterEncodingutf8参数。这个坑非常隐蔽数据库表本身查出来是中文唯独从Java程序写入时乱码说明问题出在JDBC连接层而不是数据库建表语句。第四个坑Tomcat部署路径。本地开发时项目名是juventus_mall导出WAR包部署到服务器上之后项目上下文路径变了所有前缀路径全部404。后来按前面说的统一用了pageContext.request.contextPath动态拼接才根治。5. 论文、PPT与演示视频毕业设计答辩的临门一脚5.1 论文结构主次要分明论文我采用的经典结构是绪论、相关技术介绍、需求分析、系统设计、系统实现、系统测试、总结。但最关键的诀窍是——论文里的截图和代码一定要跟实际运行效果完全一致。我见过不少同学论文里贴的界面跟演示时完全不是一码事老师翻两页就能看出来是东拼西凑的。需求分析这部分不要写空话用例图最好自己用工具画出来数据流图和数据字典哪怕简单一点也要有。系统设计里的数据库设计把ER图和表结构贴上去但表字段不要全贴核心字段加注释就够了全贴反而显得在凑页数。系统实现部分每一章按页面截图 核心代码片段 逻辑说明三段式来写。不要整段整段贴代码代码只贴最核心的、能体现思路的那十几行。比如事务控制的代码贴那段带回滚的try-catch就非常合适。5.2 演示视频的录制技巧答辩如果是在线上进行演示视频就是你的第一印象。我录视频用的是OBS Studio录屏整个流程控制在8分钟以内。流程安排有一条铁律先走主流程再走支线功能最后再做异常演示。我的演示顺序网站首页展示简单介绍商城定位和整体布局30秒。注册新用户走一遍注册流程1分钟。登录搜索球衣打开商品详情加入购物车1分30秒。购物车修改数量进入结算页提交订单1分钟。模拟支付查看订单状态变为已支付30秒。切换管理员账号查看订单列表修改状态为已发货1分钟。回到用户端看到订单状态更新完成整个闭环30秒。异常演示把商品库存改为0尝试购买提示库存不足1分钟。录视频最怕的是中途卡壳或者出现看着尴尬的操作失误。我的经验是先把流程写成一个脚本把每一步鼠标要点哪、输入什么都写清楚然后按脚本演练两遍再开始录。还有一个小技巧把浏览器窗口缩放成1080P的比例文字大小调到合适录出来的视频视觉上会比全屏分辨率小很多号的界面清晰得多。5.3 答辩高频问题预演这块我做的准备比较充分提前让几个同学模拟提问把高频问题的答案都写成了口播稿。我把核心问题列在这里你可以直接拿去用为什么选JSPM而不选Spring Boot答选题定位是课程知识体系的综合实践JSPM把Java Web底层原理暴露得足够清楚能体现对请求响应模型、会话管理、JDBC数据库访问的完整理解Spring Boot的核心是自动装配和起步依赖虽然开发快但不利于体现课程设计的核心目标。同时要有颗懂Spring Boot的心在展望里写清楚。你们是怎么处理高并发下的库存超卖问题的答我的实现通过UPDATE ... WHERE stock quantity的原子性条件更新结合事务机制来保证扣库存操作不出现负数如果扩展到真实高并发场景还要引入Redis预扣减、分布式锁等方案。密码是怎么加密存放的答使用MD5加密存储。当然我也知道MD5现在不太安全论文里会写清楚可以改用Salt多次哈希或BCrypt提升安全性作为未来优化方向。订单和购物车数据的一致性如何保证答整个订单提交过程放在同一个数据库事务里任何一步失败都整体回滚保证不会出现扣了库存却订单没生成的情况。你的系统有哪些安全性考虑答PreparedStatement防SQL注入、Filter防未登录访问、密码加密存储、管理端和用户端权限分离。这些问题基本就是大三Web课期末考试的加强版你只要真的写过代码答起来不慌最怕的是那种连自己项目代码里某个方法叫什么名字都说不出来的情况一看就是没动手。6. 部署运行与验收演示的注意事项6.1 环境依赖清单这个项目的运行环境需要提前准备好我把当时整理好的依赖列出来软件版本用途JDK1.8Java编译与运行环境Tomcat8.5Web应用服务器MySQL5.7数据库Maven3.6依赖管理与构建Druid1.2.x数据库连接池JSTL1.2JSP标签库Tomcat版本和JDK版本必须匹配JDK 8配Tomcat 8.5或9都是稳妥的如果用的是JDK 17你可能就要考虑Tomcat 10了同时javax.servlet包名也变成了jakarta.servlet这部分改动在当时也折腾了我不少时间。为了演示环境不翻车建议本地开发环境跟最终答辩环境保持一致。6.2 部署步骤里最容易出错的三步导入数据库我提供的是SQL文件导入MySQL命令行或者Navicat里执行就行。但注意MySQL 8默认的字符集和排序规则如果导入报错先检查SQL文件编码用UTF-8无BOM格式保存再导入。修改配置文件druid.properties里数据库地址、用户名、密码必须改成你自己环境里的实际值。这个文件我经常见到有人在演示前忘了改结果连接的是自己本地的库数据跟现场演示对不上。部署WAR包编译打包成WAR后放到Tomcat的webapps目录启动Tomcat自动解压。启动之后第一件事不是点首页而是去日志目录看catalina.out确认没有异常堆栈然后再打开浏览器访问。毕业答辩现场没有时间让你慢慢排错提前把启动流程跑上一遍C盘路径 / 中文目录 / 端口占用这类问题提前排除掉。6.3 验收演示时的数据准备答辩直接查空数据库是很尴尬的。我当时提前往数据库里灌了一批看起来像真实使用过的数据五六个测试用户、二十来个商品、每个商品不同的库存和销量、两条不同状态的订单。演示的时候再走一遍新用户注册→购买的主流程既能看到已有的历史数据又能看到整个系统动态运转。数据准备的细节还有一层——商品的图片要保证能正常访问。我当时把所有的图片素材放在Tomcat的webapps/upload目录并把数据库里的image_path字段写成相对路径这样即使部署到别的电脑上也能正常显示。如果图片是绝对路径带着你自己本机的盘符那换台电脑演示基本就全挂了。7. 一点真诚的复盘整个项目从确定题目到完成论文我前后花了大概三周时间其中编码占了大头论文反而写得比较快因为每一步都有实际的代码和截图支撑。回头再看JSPM这套技术栈虽然老但在理解Web系统是怎么跑起来的这件事上它的教学价值一点都没有过时。你亲自动手写过一次Servlet手动解析参数、手动管理事务回滚再看Spring MVC里那些注解背后的东西会有一层原来如此的通透感。做尤文图斯这个主题也给我自己留了点额外的动力——至少写代码写到烦躁的时候看看自己做的商城页面还挺像那么回事也算是把爱好和作业结合了一次。如果你也在纠结类似的选题我只提醒一句选出题方向之前先把自己会什么、想要锻炼什么想清楚然后用最快的速度把主流程跑通后面再慢慢打磨细节。主流程一天不跑通焦虑感和返工风险就会成倍增长。祝所有正在肝毕业设计的朋友都能顺利交稿、平稳答辩。
返回列表