ARTICLE DETAIL

资讯详情

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

SSM校园二手交易系统源码解析:从项目搭建到框架整合实践

SSM校园二手交易系统源码解析:从项目搭建到框架整合实践 简介这是一套面向高校计算机专业学生与Java初学者的校园二手交易平台实战项目源码基于SSMSpringSpringMVCMyBatis框架构建兼顾Web管理端与移动端协同场景解决校内闲置物品流通效率低、信息不对称等实际问题。资源共188个文件含32个核心Java业务类、90个XML配置与映射文件涵盖Spring容器配置、MyBatis SQL映射及Android布局资源、50张PNG图标与界面素材以及JSP后台管理页面、Gradle构建脚本、WAR部署包等完整交付物压缩包大小为60.92MB。已有345人学习下载适合课程设计、毕业设计或小型团队快速搭建可运行的二手交易系统。读者可直接导入IDE运行后端服务配合原生Android客户端调用API并通过JSP页面完成商品审核、用户管理等后台操作目录结构清晰模块划分明确包含Fragment页面组织、Gradle多模块构建支持及基础权限控制逻辑。 毕业设计选了校园二手交易系统从网上下了一份SSM源码结果导入IDEA之后启动Tomcat直接白屏控制台报了一堆错——这是我在好几个技术交流群里见过最多的求助。这个项目本身其实不复杂真正难住人的地方在于面对一份完整的SSM框架源码你分不清哪些东西是基础配置、哪些是业务代码、哪些地方必须根据自己电脑环境去改。我自己前前后后帮人排查过几十个类似的报错也带过几个实习生从零把这个项目跑通所以把整个系统的设计思路、源码结构、数据库表关系、启动步骤和踩坑点一次性讲透。这篇博文围绕基于SSM框架的校园二手交易系统展开覆盖Spring、Spring MVC、MyBatis三个框架的整合方式、前后台功能拆解、数据库表设计、核心功能实现思路以及拿到源码后如何配置环境、启动项目、解决常见错误。适合正在做毕业设计、准备SSM框架面试、或者想通过一个完整项目练手来理解框架底层原理的读者。不管你是刚学完SSM基础语法还是已经能写单体接口但没接触过完整JSPSSM项目这篇内容都能给你省下不少时间。1. 为什么校园二手交易系统是最适合练手的SSM完整项目1.1 从项目复杂度看性价比我说个很直白的结论校园二手交易系统是一个“业务量足够、技术栈覆盖足够、代码量适中”的典型CRUD综合体。它不像电商秒杀系统那样需要高并发设计也不像企业级OA那样有复杂的工作流引擎但它能把SSM框架三个核心组件全部用到实处覆盖了注册登录、商品发布、图片上传、搜索筛选、收藏下单、订单状态管理、后台审核这些常见业务场景。你用这个项目去练手或者做毕设学的不是某个炫技算法而是一个真实Web项目应该有完整闭环前端页面发出请求Spring MVC负责接收分发Service层处理业务逻辑MyBatis通过Mapper接口和SQL语句访问MySQL数据库最后视图解析返回JSP页面。这个过程恰好是SSM框架中“谁负责什么、谁调用谁、配置怎么串起来”的最直观呈现。1.2 一份标准SSM校园二手交易源码包含哪些内容拿到源码后你首先要知道整个工程里有哪些东西。标准Maven结构的SSM项目通常包含以下内容src/main/javaJava源码按controller、service、mapper、pojo、common等包分层src/main/resources配置文件包括Spring配置、Spring MVC配置、MyBatis配置、数据库连接配置、日志配置src/main/webapp前端资源JSP页面、JS、CSS、图片、WEB-INF下的web.xmlsql目录数据库脚本文件通常是.sql格式包含建库建表语句和基础测试数据pom.xmlMaven依赖描述文件锁定项目依赖的三方库版本部分源码会附带README或部署文档但很多网上下载的源码没有这也是我写这篇文章的直接原因1.3 这套源码能让你学到什么我建议你带着这三个目标去读这份源码第一理解SSM整合的配置链路知道为什么需要applicationContext.xml、spring-mvc.xml、mybatis-config.xml以及它们各自的职责边界第二看懂一次完整的请求从JSP页面到数据库再返回页面的整个路径每条数据是怎么流动的第三掌握一个中等规模Web项目DAO层、Service层、Controller层的代码组织方式这种分层思想以后换到Spring Boot项目同样适用。2. 为什么选SSM而不是Spring Boot三个框架的分工逻辑2.1 Spring、Spring MVC、MyBatis各自解决什么问题很多人学框架时把SSM当成一个大黑盒每个框架具体干了什么说不清。打个比方一个外卖平台要完成一次送餐Spring就像是平台的调度中心负责管理所有员工Bean的生命周期员工之间谁依赖谁、谁需要谁都由调度中心统一分配Spring MVC是前台接待窗口用户下单HTTP请求先到这个窗口窗口根据订单内容分发给对应的处理部门ControllerMyBatis则是和仓库数据库打交道的物流组它把Java方法的调用翻译成仓库能听懂的SQL指令再把仓库返回的数据装回Java对象。对应到代码层面Spring管理Service和Mapper的Bean实例以及事务边界Spring MVC管理Controller的注册、请求映射、参数绑定、视图解析MyBatis负责Mapper接口与SQL映射文件之间的绑定关系执行增删改查并完成结果集到JavaBean的自动映射。2.2 SSM与Spring Boot的本质差异以及为什么这些源码用SSM有人问我现在新项目都用Spring Boot学SSM还有意义吗我的看法是SSM的价值不在“新”而在“透明”。Spring Boot把Tomcat内嵌、自动配置、约定大于配置全部做了封装你很容易写出一个能跑的接口但你不一定知道Spring容器是什么时候启动的、DispatcherServlet在哪里注册的、MyBatis的Mapper是怎么被扫描进容器的。SSM项目把这一切都摆在你面前每一段配置都对应一个明确的初始化动作你对照源码能真正理解框架的工作原理。此外大量高校课程设计和毕业设计仍然要求基于SSM框架实现这类源码的需求量一直很大。理解了SSM的整合方式后续迁移到Spring Boot非常快——Boot只是把配置变成自动约定底层核心逻辑并没有变。2.3 SSM整合时配置文件的职责划分一个典型的SSM项目至少有三类配置文件这是我强烈建议你逐个打开去看的配置文件职责范围关键内容applicationContext.xmlSpring根容器配置数据源、SqlSessionFactory、事务管理器、Service层扫描spring-mvc.xmlSpring MVC子容器配置Controller扫描、视图解析器、静态资源映射、文件上传解析器mybatis-config.xmlMyBatis全局配置驼峰映射、日志、类型别名少部分项目还会在这里配Mapper路径这里有一个容易忽略的知识点Spring根容器和Spring MVC子容器是父子容器关系Controller在子容器中注册Service和Mapper在父容器中注册子容器可以访问父容器的Bean父容器不能访问子容器的Bean。很多启动报NoSuchBeanDefinitionException的问题就是扫描包范围配置错了。3. 功能拆解前台和后台分别包含什么3.1 前台用户端核心模块校园二手交易系统的前台面向普通学生用户设计时围绕“逛—搜—发—买—管”这条完整链路展开用户注册与登录用户名、密码、学号、手机号、邮箱等信息校验密码加密存储登录状态通过Session或Cookie维持商品分类浏览按数码、图书、生活用品、衣物、运动器材等分类展示商品列表支持分页关键字搜索根据商品标题、描述做模糊查询筛选条件通常包括分类、价格区间、新旧程度商品详情查看展示商品图片、价格、原价、成色描述、卖家信息、发布时间同时显示浏览量商品发布登录用户填写标题、分类、描述、价格上传封面图和细节图提交后进入待审核或直接上架状态收藏功能用户可以对感兴趣的商品添加收藏后续在个人中心查看收藏列表下单购买针对某个商品生成订单如果项目包含在线支付模拟则增加支付状态字段如果不做支付通常采用线下见面交易模式订单状态流转相对简单站内留言或咨询买家在商品详情页留言提问卖家可以回复个人中心修改资料、查看自己发布的商品列表、管理订单状态、查看收藏列表3.2 后台管理端模块后台管理端是给系统管理员使用的很多源码把后台和前台的登录入口分开通过用户角色字段区分。核心功能主要有用户管理查看用户列表、启用或禁用账号、重置密码管理员账号通常单独在数据库初始化商品管理审核新发布的商品下架违规商品删除垃圾信息订单管理查看所有订单记录处理异常订单状态分类管理新增、编辑、删除商品分类调整分类排序数据统计部分项目包含统计每日新增用户数、新增商品数、成交订单数展示简单数据图表3.3 不同版本源码的常见差异需要提醒你的是网上的SSM校园二手交易系统源码有多种变体有的带管理员后台有的只有前台基础功能有的用了JSPJSTL做服务端渲染有的改成了前后端分离返回JSON有的集成了Redis缓存有的没有。下载源码后先花10分钟梳理它的功能列表和页面文件确认它用的是哪种模式再决定怎么动手改避免一上来就瞄着代码改结果越改越乱。4. 数据库设计六张表的字段、状态与关联关系4.1 核心表结构速览数据库设计决定了业务逻辑的复杂度边界。二手交易系统最核心的实体有用户、商品、分类、订单、收藏、留言对应的数据表通常如下4.2 用户表t_user字段类型说明idint主键自增usernamevarchar(50)登录用户名唯一passwordvarchar(128)加密后的密码nicknamevarchar(50)昵称student_novarchar(30)学号二手交易场景下常用来增强身份信任phonevarchar(20)手机号emailvarchar(100)邮箱avatarvarchar(255)头像图片路径roletinyint角色字段0普通用户1管理员statustinyint状态字段0禁用1正常create_timedatetime注册时间4.3 商品表t_goods这是整个系统中字段最多、状态变更最频繁的表。关键字段及设计思路如下title商品标题用于列表展示和搜索description商品详情描述一般用text类型price/original_price售价和原价使用decimal(10,2)category_id关联分类表的外键cover_image封面图路径列表页只取这一张图减轻页面渲染压力images细节图可用逗号分隔的多路径存储也可单独建一张商品图片表status商品状态我见过比较规范的设计是 0下架、1在售、2卖出、3审核中、4审核拒绝 五档view_count浏览量商品详情页每次打开自增这个字段可以以后扩展热度排序seller_id发布者ID关联用户表商品状态是项目中非常容易写错的地方。举个例子当买家对某商品下单成功后商品状态应该立刻切成“已卖出”否则其他用户还能继续下单同一件商品被重复卖出这在二手交易场景中是很严重的逻辑漏洞。4.4 分类表t_category和收藏表t_favorite分类表字段极简id、name、sort_order、create_time。sort_order用于控制前台分类展示顺序后台管理分类时可以修改。收藏表是典型的多对多关系中间表id、user_id、goods_id、create_time查询某个用户收藏列表时用user_id关联goods_id即可。4.5 订单表t_order与状态机设计订单表是理解整个系统业务逻辑的重点字段大致如下字段类型说明idint主键order_novarchar(64)订单编号通常用时间戳随机数生成goods_idint关联商品表buyer_idint买家IDseller_idint卖家IDpricedecimal(10,2)成交价statustinyint订单状态create_timedatetime下单时间pay_timedatetime支付/确认时间finish_timedatetime完成时间订单状态推荐用数字常量管理0待付款、1已付款待发货、2已发货、3确认完成、4已取消。在实际二手交易项目里如果走线下当面交易状态也可以简化为 0待确认、1进行中、2已完成、3已取消具体取决于你的业务设计。关键是状态之间的流转要有限制已取消的订单不能再变成已完成已完成的订单不能再被取消这些判断逻辑写在Service层而非Controller层。这里还有一个细节值得学习order_no之所以要单独生成而不是直接用自增主键是因为订单号可能出现在短信通知、聊天记录、线下核验等场景一个唯一且不易重复的订单号比纯数字主键更安全、更合理。5. 源码包结构与一次请求的完整旅程5.1 标准分包结构是这样的拿到一套完整的SSM项目源码Java包结构通常长这样com.secondhand ├── common │ ├── Result.java // 统一返回结果封装 │ ├── PageResult.java // 分页结果封装 │ └── Constant.java // 常量类定义订单状态、商品状态等 ├── controller │ ├── UserController.java │ ├── GoodsController.java │ ├── OrderController.java │ ├── FavoriteController.java │ └── AdminController.java ├── service │ ├── UserService.java │ ├── GoodsService.java │ ├── OrderService.java │ └── impl/ │ ├── UserServiceImpl.java │ ├── GoodsServiceImpl.java │ └── OrderServiceImpl.java ├── mapper │ ├── UserMapper.java │ ├── GoodsMapper.java │ ├── OrderMapper.java │ └── GoodsMapper.xml └── pojo ├── User.java ├── Goods.java ├── Order.java └── vo/ └── GoodsVO.java // 视图对象可能包含分类名、卖家昵称等冗余字段这套结构和Spring Boot项目本质上是一样的区别只是SSM项目多了XML配置文件Spring Boot项目则用注解把它压缩到极致。建议你先看pojo下的实体类再看mapper接口和XML然后顺着service、controller的顺序往上读这样整个项目的数据流转关系会非常清楚。5.2 一次“发布商品”请求是怎样从头走到尾的我以一个实际请求为例把调用链完整拆开用户在JSP页面的商品发布表单中填写信息点击提交浏览器发起POST /goods/publish请求表单数据中包含文件类型的图片DispatcherServlet前端控制器拦截请求根据RequestMapping(/goods/publish)找到GoodsController的对应方法Spring MVC将请求参数自动绑定到Goods对象中文件参数绑定到MultipartFile对象Controller调用GoodsService.publish(goods)Service层补充一些Controller层不该关心的逻辑校验用户是否登录、校验商品标题和价格是否合法、生成默认状态等Service层调用GoodsMapper.insert(goods)MyBatis执行SQL语句把数据写入MySQL返回成功结果Controller将用户重定向或转发到商品列表页整个请求完成这里面有一个典型的设计原则问题Controller不应该写业务逻辑。很多学生能写出来的代码长这样Controller里直接注入Mapper然后调用insertService层形同虚设。这种写法在小型项目里确实能跑但一旦业务变得复杂——比如下单时需要校验商品状态、需要更新商品状态、需要生成订单号——Controller就会膨胀得没法维护面试官考核代码质量时也会重点关注这一点。5.3 配置文件之间如何互相协作SSM项目的启动流程可以简单概括为Tomcat启动时读取web.xml加载Spring的ContextLoaderListener初始化根容器加载DispatcherServlet时初始化Spring MVC子容器两个容器各自扫描不同包下的Bean最终形成完整的Bean依赖网络。你在源码里找到web.xml里面会配置这两者的映射关系。配置文件里面最容易被忽略的是数据库连接配置。很多项目用jdbc.properties保存数据库账号密码配置内容大概是jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/secondhand?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456特别注意如果本地安装的是MySQL 8.0以上驱动类应该写com.mysql.cj.jdbc.Driver而不是com.mysql.jdbc.DriverURL里面必须加serverTimezone参数否则会报时区错误。这个问题在第七节还会详细说。6. 四个核心功能的实现思路与关键代码6.1 注册登录MD5加盐与登录状态拦截用户密码不能明文存储这是基本的安全底线。在SSM项目中最简单的做法是在注册时对密码做MD5加密登录时把用户输入的密码做相同加密后比对public String encryptPassword(String password, String salt) { return DigestUtils.md5DigestAsHex((password salt).getBytes()); }如果想要更安全可以在原始密码上拼接一个随机盐值每个用户盐值不同这样相同密码的密文也不一样。不过大部分课程设计用固定盐值的MD5已经足够但你要知道这个方案的缺陷没有加盐的MD5很容易被彩虹表撞库。登录状态通过拦截器维持是比较合理的方案。Spring MVC的拦截器配置在spring-mvc.xml中拦截所有需要登录才能访问的URL在preHandle方法中检查Session中是否存在用户对象不存在则跳转到登录页public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user request.getSession().getAttribute(user); if (user null) { response.sendRedirect(request.getContextPath() /login); return false; } return true; } }拦截器的思路可以扩展到权限控制后台管理请求除了需要登录还需要校验role 1管理员否则拒绝访问这就是一个最简单的基于角色的访问控制模型。6.2 商品发布与图片上传文件命名与回显路径上传图片是二手交易系统最核心的交互功能之一。Controller方法接收MultipartFile参数然后把文件写入服务器的某个目录PostMapping(/goods/publish) public String publish(RequestParam(file) MultipartFile file, Goods goods, HttpSession session) { if (!file.isEmpty()) { String originalFilename file.getOriginalFilename(); String suffix originalFilename.substring(originalFilename.lastIndexOf(.)); String filename System.currentTimeMillis() _ new Random().nextInt(1000) suffix; String realPath request.getServletContext().getRealPath(/upload); file.transferTo(new File(realPath File.separator filename)); goods.setCoverImage(/upload/ filename); } goodsService.publish(goods, user); return redirect:/goods/list; }这里有两个经验值得记下来。第一保存到数据库的路径应该是相对路径/upload/xxx.jpg而不是绝对路径。因为项目的部署环境可能改变绝对路径一旦变化页面上的图片就全部失效。相对路径配合Tomcat的静态资源映射无论在本地还是服务器上都能正常访问。第二文件名必须做重命名。用户上传的文件名可能是“毕业设计封面.jpg”甚至包含特殊字符直接用原名存储很容易造成路径解析错误。用时间戳随机数生成新文件名既避免文件名冲突也兼容各种字符集。Spring MVC的配置中还需要添加文件上传解析器和大小限制bean idmultipartResolver classorg.springframework.web.multipart.commons.CommonsMultipartResolver property namemaxUploadSize value5242880/ /bean6.3 商品搜索MyBatis动态SQL拼接商品搜索功能适合拿来理解MyBatis动态SQL。用户可能按标题搜也可能同时勾选分类、价格区间查询条件是不固定的如果每个组合都写一条SQL工作量巨大且不现实。MyBatis的方案是用where和if节点动态拼接查询条件select idsearchGoods resultTypecom.secondhand.pojo.Goods SELECT * FROM t_goods where if testkeyword ! null and keyword ! AND (title LIKE CONCAT(%, #{keyword}, %) OR description LIKE CONCAT(%, #{keyword}, %)) /if if testcategoryId ! null AND category_id #{categoryId} /if if testminPrice ! null AND price gt; #{minPrice} /if if testmaxPrice ! null AND price lt; #{maxPrice} /if AND status 1 /where ORDER BY create_time DESC /select这段SQL里有个小坑在MyBatis XML中大于号和小于号属于XML转义字符不能直接写。要么用gt;和lt;转义要么把整段SQL放进![CDATA[]]中否则解析XML时就会报错。你看到别人的源码中写gt;时别觉得奇怪那是XML的合法写法。6.4 订单状态流转从下单到完成的状态机控制订单模块最容易出现的逻辑问题前面已经提到过——商品被重复下单。这个问题必须在Service层通过事务控制来解决实现思路是下单前根据商品ID查询商品记录判断status 1在售校验通过后开启事务更新商品状态为2已卖出同时插入订单记录订单初始状态为0待付款或1待确认提交事务任何一步失败则回滚Transactional public void createOrder(Order order) { Goods goods goodsMapper.selectById(order.getGoodsId()); if (goods null || goods.getStatus() ! 1) { throw new RuntimeException(商品不存在或已下架); } // 更新商品状态为已卖出 goodsMapper.updateStatus(order.getGoodsId(), 2); // 生成订单 order.setOrderNo(generateOrderNo()); order.setStatus(0); orderMapper.insert(order); }Transactional是Spring声明式事务的体现它意味着这个方法内的所有数据库操作要么全部成功要么全部回滚。如果不加事务更新商品状态成功但插入订单失败就会出现商品变已卖但订单不存在的脏数据。这是很典型的数据库一致性问题面试时经常以此为切入点考察候选人对事务的理解。7. 部署实操从零把源码跑起来7.1 环境准备清单先说结论一个SSM小项目通常不需要太新的版本我推荐的搭配是组件推荐版本备注JDK1.8大部分SSM项目都基于Java 8编写代码中很少用到新版本语法Maven3.6.3稳定版配置阿里云镜像后依赖下载速度会快很多Tomcat8.5与Servlet 3.1规范兼容良好MySQL5.7 或 8.05.7和8.0在连接方式上有差异注意驱动配置IDEA任何较新版本Ultimate版自带Tomcat集成7.2 完整启动步骤第一步在IDEA中用File → Open打开下载好的源码目录确认它被识别为Maven项目。如果IDEA没有自动导入依赖在右侧Maven面板点击刷新按钮等待依赖下载完成。第二步安装并启动MySQL新建数据库然后执行SQL脚本。建议直接在Navicat或命令行中执行CREATE DATABASE secondhand DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE secondhand; SOURCE /path/to/secondhand.sql;执行后检查一下核心表是否创建成功确认表名前缀和源码中JDBC配置的表名一致。第三步修改jdbc.properties文件。这里有一个高频问题源码里自带的数据库密码是root或123456你本地环境不同如果漏改启动时不会报错但一访问数据库相关页面就会出现500错误所以配好后务必检查一遍。第四步配置Tomcat。在IDEA中打开Run → Edit Configurations添加一个Tomcat Server在Deployment选项卡中添加Artifact选择项目war或war exploded。建议选war exploded模式因为这种模式可以直接加载本地文件修改JSP页面后刷新浏览器就能看到效果不需要重新打包。第五步启动后访问地址。如果部署时没有修改Application context访问路径通常是http://localhost:8080/项目名/例如http://localhost:8080/secondhand/。如果出现404先确认项目名是否在URL中这是新手最容易犯的错误——Tomcat的根路径默认不是你的项目。7.3 启动成功后的验收清单项目能跑起来只是第一步我建议启动后按下面几条逐项验证注册一个新用户密码加密入库数据库中密码不是明文登录后进入商品列表确认图片能正常加载发布一个测试商品带上图片上传确认图片存储路径和回显正常用另一个账号查看该商品确认商品状态显示为“在售”下单后回到卖家账号确认商品状态已变为“已卖出”列表不再展示前往后台管理页面确认管理员账号可以登录并看到商品条目这套验收流程走完说明项目主体功能闭环是通的后面再改动代码就有底气了。8. 第一次跑SSM项目大概率踩的坑8.1 Java版本不匹配导致启动失败源码如果是在旧版JDK下编译的而你本地用JDK 11或17Maven编译时可能出现source 1.5 中不支持 diamond 运算符之类的报错。解决办法是在pom.xml中显式声明编译版本properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target /properties如果pom.xml里已经写了IDEA的Project Structure中也要确认Project SDK选择的是1.8三者保持一致才能避免编译版本冲突。8.2 Tomcat启动后访问全是404这个问题的出现概率非常高。第一个可能是项目没有成功部署在Tomcat部署配置里检查Artifact是否已经添加第二个可能是URL缺少项目名也就是把http://localhost:8080/secondhand/login写成了http://localhost:8080/login第三个可能比较隐蔽——项目结构不规范JSP文件放到了WEB-INF外面或者缺失欢迎页配置导致访问根路径找不到默认页面。逐项排查即可绝大多数404都出在前两种原因。8.3 MySQL连接失败和时区错误用MySQL 8.0的童鞋特别容易碰到这个问题。报错一般长这样java.sql.SQLException: The server time zone value Öйú±ê׼ʱ¼ä is unrecognized解决办法很明确在JDBC的URL后面追加serverTimezoneAsia/Shanghai同时把驱动类改成com.mysql.cj.jdbc.Driver。另外如果MySQL 8.0使用了caching_sha2_password认证插件而项目用的驱动版本过低也会连接失败把mysql-connector-java版本升到8.0以上即可。8.4 图片上传成功但页面不显示图片不显示十有八九是路径访问被Spring MVC拦截了。Spring MVC的DispatcherServlet默认映射为/时会拦截所有请求包括静态资源。需要在spring-mvc.xml中配置静态资源映射mvc:resources location/upload/ mapping/upload/**/ mvc:resources location/static/ mapping/static/**/否则浏览器请求/upload/xxx.jpg时会被当成一个Controller路径处理找不到映射自然404。这个问题虽然代码短但排查起来很隐蔽很多人以为是保存路径错了折腾半天才发现是静态资源映射没配。8.5 部署环境变动后图片全部丢失如果在本地能显示图片但发布到服务器后图片全部丢失多半是因为图片保存到了Tomcat部署目录下。这个目录会随项目重新部署而被清空。严格来说应该把上传目录单独配置到服务器固定路径比如/data/upload/再通过虚拟路径映射对外提供访问。不过对于课程设计和毕设项目而言本地开发使用相对路径已经足够知道自己部署到服务器时要注意这个区别即可。8.6 其他频率很高的坑除了上面说的几类还有几个在SSM项目里非常常见JSP页面中文乱码排查顺序是页面编码、请求和响应编码过滤器、数据库连接URL中的characterEncodingutf8MyBatis的Mapper接口和XML找不到绑定关系检查命名空间是否和接口全限定名一致mapper的XML文件是否被Maven打包到classes目录Controller返回的JSON数据中包含实体类循环引用导致序列化失败可以用JsonIgnore注解在关联字段上解决。这些坑单看都不难但它们串联起来的排查过程恰恰是你理解SSM项目运行机制最好的机会。一套源码跑通、读完、改过一遍你对Spring容器、Spring MVC的请求流程、MyBatis的SQL映射这几个抽象概念的理解会比看十遍教程都深刻。最后再分享一个我自己的经验拿到这类源码不要一开始就想着改功能。先按数据库脚本把表建好然后顺着web.xml → spring-mvc.xml → Controller → Service → Mapper.xml的顺序把代码通读一遍每读到一个模块就在纸上画一下它的请求链路。等你对整个项目有了全局认识再动手改第一处代码——比如给商品搜索页加一个排序功能或者给订单列表加一个状态筛选。改完跑通之后这个项目的源码才真正属于你了。后面无论做毕设答辩还是面试聊项目你都能拿出真东西。本文还有配套的精品资源点击获取
返回列表