十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

基于SSM的桂林二手交易市场毕业设计:从选题到答辩全流程解析

基于SSM的桂林二手交易市场毕业设计:从选题到答辩全流程解析 要是你现在正为计算机毕业设计发愁手头这个题目是“基于SSM的桂林二手交易市场”那这篇文章你应该能直接用上。SSM框架在今天依然是很多高校毕业设计的主流选择二手交易又是一个贴近真实生活、业务逻辑完整、演示效果直观的典型场景。把“桂林”这个地域属性加进去本质上是在给系统做本地化定位而不是简单的换皮这个点恰恰是答辩时能讲出东西的地方。这篇文章我会从选题逻辑、功能模块、数据库设计、SSM核心实现、常见坑位到答辩准备完整拆一遍。所有内容都基于实际做毕设的流程来写技术栈是Spring、SpringMVC、MyBatis前端用JSP配合Bootstrap/Layui这一类轻量框架数据库用MySQL。如果你正在写这一题或者打算拿类似二手交易系统练手可以直接参照里面的思路和代码片段去落地。1. 为什么二手交易市场是毕业设计里的“稳妥之选”很多同学做毕业设计时容易两极分化要么选个纯管理系统功能太简单答辩被老师说“工作量不足”要么选个商城类系统订单、支付、库存全都要做做到最后连核心逻辑都没跑通。二手交易市场刚好夹在中间它比普通管理系统多了一层交易业务又比完整商城少了很多支付和物流复杂度非常适合在几个月内完成并做扎实。1.1 选题价值不是“土项目”而是“实用业务”二手交易市场的核心价值在于“信息撮合”。一个学生用户登录后可以发布自己闲置的物品比如教材、自行车、数码设备、宿舍小家电其他用户浏览后产生意向通过系统内留言或电话联系最终在线下完成交易。这个业务链路不需要真正接入支付网关也不需要复杂的订单物流但它天然包含用户管理、商品发布、分类浏览、搜索筛选、收藏、留言、交易状态管理、后台审核等模块覆盖面足够广。把题目定位成“桂林二手交易市场”意味着系统要面向桂林本地的高校和社区。这个地域属性不是摆设而是可以在设计上做出差异化比如商品发布时必须选择校区或城区筛选时支持按“桂林电子科技大学”“广西师范大学”或“七星区”“象山区”这样的粒度来过滤比如在“交易方式”上支持“校内自提”“同城面交”再比如把“桂林特产”“旅游纪念品”单独做一个分类。答辩时如果你能清楚说出这些本地化设计是怎么影响表结构和查询条件的这就不只是一个CRUD项目了。另外二手交易系统的核心难点不是“卖东西”而是“信任”。所以系统设计里一定要有举报、下架、审核、用户信用记录这类管理功能。这会让你的项目在业务完整性上明显比“一个商品表一个订单表”的管理系统高一个档次。1.2 SSM框架为什么至今还能打SSM是Spring、SpringMVC、MyBatis三个框架的组合虽然现在新项目很多人用Spring Boot但高校教学和毕业设计里SSM依然大量存在。原因很直接学校课程一般还是按Spring、SpringMVC、MyBatis分层来讲你写SSM项目可以把你学过的东西一个不落地展示出来而且SSM是XML配置加注解的混合模式你对配置的理解会更深入换个Spring Boot项目反而容易“只会用不会讲”。从技术分工来看Spring负责对象管理和事务SpringMVC负责请求路由和参数绑定MyBatis负责数据库操作。这个分工和二手交易系统的功能天然匹配。比如用户登录时Controller接收账号密码Service里校验Mapper里查表商品发布时Controller接收表单和图片Service里处理业务Mapper里插入数据库。每一层干什么清清楚楚答辩时被问到“为什么用SSM”你可以回答因为它的分层能让业务代码更清晰事务和依赖管理交给Spring请求处理交给SpringMVCSQL控制交给MyBatis三个框架各司其职非常适合中小型Web系统的快速开发。有一个点需要提醒Spring Boot已经普及但你现在做的是SSM就不要在项目里强行套一堆Spring Boot的注解更不要拿一个Spring Boot项目去冒充SSM。答辩老师一眼就能看出来。老老实实按SSM的经典结构来做配置到位流程完整反而更容易拿到好分数。2. 系统功能拆解从登录到交易的完整闭环拿到题目后第一件事不是写代码而是把功能模块图想清楚。二手交易市场按角色分通常有三类用户普通用户、管理员、游客。游客只能浏览和搜索登录后可以发布商品、收藏、留言管理员负责用户管理和商品审核。下面我按用户端和管理员端两条线来拆。2.1 用户端从注册到下单用户端最核心的功能包括注册与登录用户名、密码、手机号、学校/区域等基本信息密码不要明文存储至少用MD5加盐或者BCrypt做一次加密。商品浏览首页展示最新发布的商品列表支持按分类、按区域、按价格区间筛选也支持关键词搜索。商品发布填写商品标题、描述、分类、成色全新/几乎全新/轻微使用痕迹等、原价、转让价、交易方式、所在校区或城区并上传1到5张图片。商品详情展示完整信息同时显示发布者信息和信用记录提供收藏、留言、举报入口。个人中心管理我发布的商品上架/下架/编辑查看我收藏的商品查看收到的留言和评论。交易闭环双方在线下沟通后买家可以点击“我想要”或直接联系卖家在个人中心把商品标记为“已交易”系统自动下架该商品。这个流程里最容易忽略的是“下架原因”。商品最终不一定是因为成功卖出才下架也可能是卖家不想卖了或者被管理员判定为违规。所以商品状态至少要设计成在售、已下架、已交易、审核不通过、管理员强制下架。不要把状态图省成一个简单的“0/1”。2.2 管理员端审核、分类与数据看板管理员端不需要太花哨但模块必须齐全。主要包括用户管理查看用户列表、禁用/启用账号、重置密码。商品审核对用户发布的商品进行审核支持通过、驳回、强制下架。审核不通过时最好填写原因让用户知道怎么改。分类管理维护商品分类的增删改查比如“教材书籍”“数码电器”“生活用品”“体育器材”“其他”等。留言评论管理删除违规留言。数据统计统计注册用户数、商品总数、今日新增商品数、分类商品占比等用简单图表展示。数据统计这个模块经常被学生忽略但它其实是答辩加分项。你可以不用ECharts那种复杂图表直接在后台首页放几个统计卡片再用JFreeChart或者前端图表库画一个分类占比柱状图工作量不大但会显得系统有“管理驾驶舱”的概念。2.3 核心业务流程与状态流转这里我把交易的核心状态流转写一下方便你设计数据库和写业务逻辑。商品从发布到最终变成“已交易”大致经历用户提交发布 - 系统置为“待审核” - 管理员审核通过后变为“在售” - 买家或卖家发起交易意向 - 线下成交 - 卖家标记“已交易” - 系统记录成交时间并下架。你可以把这条状态流转画在论文里但不要用流程图工具生成那种花哨的图直接用简单的箭头文字描述就行。代码层面要特别注意状态变更必须走Service层方法不能直接在Controller里更新状态字段否则后面没法加权限校验和日志记录。比如管理员强制下架的方法里要同时把商品状态置为“违规下架”并给发布者生成一条系统通知。3. 数据库设计与建模要点二手交易系统的地基数据库设计是毕业设计里最能体现工作量的一部分。二手交易系统的表不算多但关系比较典型用户、商品、分类、收藏、留言、举报、通知、管理员大概七八张表。下面我说几个核心表的字段设计思路你可以直接参考。3.1 核心表结构与字段说明用户表t_user建议字段字段名类型说明idint主键自增usernamevarchar(50)登录名唯一passwordvarchar(100)加密后的密码nicknamevarchar(50)昵称phonevarchar(20)联系电话schoolvarchar(100)学校或区域比如桂林电子科技大学avatarvarchar(255)头像图片路径credit_scoreint信用分默认100statustinyint0禁用 1正常create_timedatetime注册时间商品表t_goods建议字段字段名类型说明idint主键user_idint发布者IDcategory_idint分类IDtitlevarchar(100)商品标题descriptiontext商品描述original_pricedecimal(10,2)原价sell_pricedecimal(10,2)转让价qualityvarchar(20)成色如“几乎全新”trade_typevarchar(20)交易方式如“校内自提”regionvarchar(100)所在区域或校区cover_imagevarchar(255)封面图statustinyint0待审核 1在售 2已下架 3已交易 4审核驳回 5违规下架view_countint浏览量create_timedatetime发布时间收藏表t_favorite主要字段为 id、user_id、goods_id、create_time要设置唯一索引uk_user_goods(user_id, goods_id)避免同一用户重复收藏同一商品。留言表t_comment主要字段为 id、goods_id、user_id、content、create_time、status0正常 1删除。留言内容要做好长度限制和敏感词过滤虽然毕设不一定非要接第三方过滤服务但至少要在前端限制长度后端也要做非空判断。3.2 表关系与外键表关系比较清晰一个用户对应多个商品一个商品对应一个分类一个用户能收藏多个商品一个商品能被多个用户收藏因此收藏表是典型的用户和商品多对多关系的中间表。留言表则是商品和用户的一对多关系。关于外键我的建议是表结构里不强制建物理外键但逻辑上一定要保持外键关系。也就是说插入商品时校验user_id和category_id是否存在删除用户时要同步处理该用户发布的商品、收藏和留言这些都在Service层完成。物理外键在毕业设计里用不用都可以但如果你用了要能解释清楚级联删除和更新规则如果不用要会解释“外键约束影响插入性能项目中靠业务层保证数据一致性”。两种说法都能过关就怕你自己都说不清。3.3 涉及金额与时间的字段设计细节金额字段一定用decimal(10,2)不要用float或者double。因为二进制浮点数在比较时存在精度问题二手交易虽然不像金融系统那样严格但答辩老师看到你用float存金额会扣分。时间字段统一用datetimeJava端使用Date类型接收MyBatis里映射的时候注意jdbcTypeTIMESTAMP否则可能出现日期插入成功但查询显示乱码或格式不对的情况。有一个细节商品表中“原价”和“转让价”要分开设计。虽然二手商品最重要的是转让价但原价能帮助买家判断划算程度。你可以在商品列表页隐藏原价详情页展示并显示一个“折扣比例”这个计算可以用Java代码完成也可以写SQL查出来后在页面算。4. SSM项目搭建与核心实现把设计落到代码上功能想清楚之后项目搭建就比较顺了。这里我按照SSM经典开发流程给出一套可以直接照做的方案。开发环境建议使用JDK 8、Maven 3.6、Tomcat 8.5、MySQL 5.7这些版本组合最稳定网上资料也最多。4.1 Maven工程结构与依赖用Maven创建一个war包工程目录结构大概长这样src/main/java com.guilin.secondhand controller service service.impl mapper entity common src/main/resources mapper spring mybatis-config.xml jdbc.properties src/main/webapp WEB-INF jsp static index.jsppom.xml里的核心依赖不要贪多够用就行。大概包括spring-context、spring-webmvc、mybatis、mybatis-spring、mysql-connector-java、druid连接池、jackson-databind、jstl、servlet-api、commons-fileupload。下面是一个简化版依赖配置你可以直接参考properties spring.version5.2.22.RELEASE/spring.version /properties dependencies dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version${spring.version}/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.6/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.6/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.8/version /dependency dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.12.5/version /dependency /dependencies注意Spring版本不要用太新的6.x因为Spring 6要求JDK 17起步很多学校机房和老师的电脑还是JDK 8用5.2.x最稳妥。4.2 请求链路Controller-Service-MapperSSM的请求链路很简单浏览器发起请求DispatcherServlet根据HandlerMapping找到Controller方法Controller调用Service接口Service实现类里调用Mapper接口Mapper通过动态代理绑定到XML里的SQL语句最后把结果逐层返回给页面。以商品列表为例Controller里可以这样写Controller RequestMapping(/goods) public class GoodsController { Autowired private GoodsService goodsService; RequestMapping(/list) public String list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, Integer categoryId, String keyword, Model model) { PageHelper.startPage(pageNum, pageSize); ListGoods goodsList goodsService.findGoods(categoryId, keyword); PageInfoGoods pageInfo new PageInfo(goodsList); model.addAttribute(pageInfo, pageInfo); model.addAttribute(categoryId, categoryId); model.addAttribute(keyword, keyword); return goods/list; } }Service实现类里要处理参数校验和业务逻辑Service public class GoodsServiceImpl implements GoodsService { Autowired private GoodsMapper goodsMapper; Override public int publishGoods(Goods goods) { if (goods.getSellPrice() null || goods.getSellPrice().compareTo(BigDecimal.ZERO) 0) { throw new ServiceException(转让价必须大于0); } goods.setStatus(0); // 待审核 goods.setViewCount(0); goods.setCreateTime(new Date()); return goodsMapper.insert(goods); } }Mapper接口和XML对应关系是SSM项目最常见的出错点。接口方法名必须和XML中statement的id一致参数类型和返回值类型也必须对得上。比如public interface GoodsMapper { ListGoods selectGoodsList(Param(categoryId) Integer categoryId, Param(keyword) String keyword); }对应的GoodsMapper.xmlselect idselectGoodsList resultTypecom.guilin.secondhand.entity.Goods select * from t_goods where if testcategoryId ! null and category_id #{categoryId} /if if testkeyword ! null and keyword ! and (title like concat(%, #{keyword}, %) or description like concat(%, #{keyword}, %)) /if and status 1 /where order by create_time desc /select这段SQL里最重要的一点是加上了status 1也就是只查“在售”状态。很多同学写查询时忘了过滤状态结果后台还没审核的商品直接出现在首页这是个低级但常见的错误。4.3 商品发布与图片上传实现商品发布的关键是图片上传。二手交易对图片的依赖很高买家第一眼就是看图。SSM里做图片上传一般用MultipartFile配合commons-fileupload。首先在spring-mvc.xml里配置文件解析器bean idmultipartResolver classorg.springframework.web.multipart.commons.CommonsMultipartResolver property namedefaultEncoding valueUTF-8/ property namemaxUploadSize value5242880/ /bean然后在Controller里接收文件RequestMapping(value /publish, method RequestMethod.POST) public String publish(RequestParam(file) MultipartFile[] files, Goods goods, HttpServletRequest request) { ListString imagePaths new ArrayList(); String uploadDir request.getServletContext().getRealPath(/upload); File dir new File(uploadDir); if (!dir.exists()) dir.mkdirs(); for (MultipartFile file : files) { if (file.isEmpty()) continue; String originalFilename file.getOriginalFilename(); String ext originalFilename.substring(originalFilename.lastIndexOf(.)); String filename System.currentTimeMillis() _ new Random().nextInt(1000) ext; file.transferTo(new File(dir, filename)); imagePaths.add(/upload/ filename); } goods.setCoverImage(imagePaths.get(0)); // 其它图片可以拼成一个字符串存到字段或者单独建商品图片表 goodsService.publishGoods(goods); return redirect:/goods/my; }这里有几个坑要说一下。第一文件保存路径不要写到项目源码目录里否则重新部署就丢了。用request.getServletContext().getRealPath(/upload)部署时会在Tomcat的webapps下生成upload目录虽然也不完美但作为毕设够用。第二文件名一定要重命名不要直接用用户上传的名字否则两个用户上传同名文件会互相覆盖而且中文文件名容易乱码。第三图片大小和后缀都要校验不能只靠前端控制我在实际测试时经常跳过前端直接POST后端不限制的话很容易传一个超大文件拖垮Tomcat。4.4 分页搜索与条件筛选分页推荐用PageHelper这是MyBatis最常用的分页插件。使用方式很简单在查询前调用PageHelper.startPage(pageNum, pageSize)然后紧接着执行Mapper查询再用PageInfo包装结果。PageHelper会自动生成count查询和limit语句。但要注意PageHelper的“安全调用”问题。startPage之后必须紧跟一条Mapper查询中间不能夹杂其他查询否则分页参数会被后面的语句消费导致数据错乱。比如你在Controller里先调了用户Service查询当前登录用户再调用商品查询那你必须把分页放在商品查询前一步不能放到Controller方法的最开头。搜索和筛选的SQL主要用动态SQL解决。比如用户选分类、选区域、填关键词、按价格区间筛选这些条件可能是空的用where加if可以优雅处理动态拼接。除了按时间倒序还可以加一个“最新优先”和“价格从低到高”的排序选项排序字段用参数传入但要注意排序字段不能直接字符串拼接否则存在SQL注入风险最好在Java代码里做白名单校验比如只允许传“create_time”或“sell_price”。5. 实操过程中最容易踩的五个坑这部分是我最想说的。代码照着视频教程敲完真正跑起来才发现问题一大堆。下面这些坑我基本都踩过也帮学生排查过不少提前了解能帮你省下好几个通宵。5.1 Maven依赖冲突与版本选择SSM最常见的依赖冲突是javax.servlet-api、jsp-api和tomcat自带servlet-api冲突。如果你在pom里引入了servlet-api部署到Tomcat后经常会报ClassNotFoundException或NoSuchMethodError因为Tomcat自己也有servlet-api两个类库打架了。解决办法很简单servlet-api和jsp-api这两个依赖的scope改成provided意思是由Tomcat在运行时提供打包时不要包含。dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version3.1.0/version scopeprovided/scope /dependency另外MyBatis和Spring的版本搭配也要注意。mybatis-spring 2.x对应MyBatis 3.5如果你用mybatis-spring 1.x可能不支持新版MyBatis启动时会报TypeException。经验之谈直接用上面pom里的版本组合能避开大部分坑。5.2 JSON日期格式与前端展示不一致SSM项目里如果你用Ajax请求商品列表后端返回JSON日期默认序列化出来是一长串时间戳前端怎么解析都不对。这是因为Jackson默认把java.util.Date转成时间戳。解决方式是在实体类的日期字段上加注解JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8) private Date createTime;同时记得在Jackson配置里设置时间格式或者直接在applicationContext.xml里配置一个ObjectMapper。否则你本地测试没问题部署到服务器上可能会差8个小时因为服务器时区不是东八区。5.3 事务不生效在SSM里事务默认只有RuntimeException才会回滚。如果你在Service方法里catch住了异常事务是不会回滚的。比如下面的代码Transactional public void deleteUser(Long userId) { try { userMapper.deleteById(userId); goodsMapper.deleteByUserId(userId); } catch (Exception e) { e.printStackTrace(); } }这段代码看起来没问题但实际上如果第二个删除失败事务不会回滚因为异常已经被捕获Spring感知不到。正确做法是让异常继续向上抛或者手动TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。还有一点Transactional默认只对public方法生效。如果你在同一个类的私有方法上加事务一点用都没有。这个坑特别隐蔽建议在Service方法上都用public修饰并且在调用入口处控制事务边界。5.4 数据库连接池耗尽如果在开发时频繁重启Tomcat或者压测时发现连接池耗尽报错CannotGetJdbcConnectionException多半是连接池配置太小或连接没有释放。Druid配置里可以加上最小空闲和最大活跃数spring.datasource.druid.initial-size5 spring.datasource.druid.min-idle5 spring.datasource.druid.max-active20然后开启Druid的监控页面查看活跃连接数。不过要注意如果你是SSM的XML配置方式Druid的监控统计需要配置StatFilter和StatViewServlet如果只是为了毕设不开监控也行但至少要把连接池参数调好。5.5 文件上传大小限制commons-fileupload默认最大上传大小是2MB如果你用手机拍的照片直接传肯定报错。上面配置里我已经设置了maxUploadSize5242880也就是5MB。但要注意这个参数只限制单次请求总大小如果你允许一次传5张图每张不能太大。我建议前端也加一个图片压缩或者限制单张不超过1MB这样既节省服务器空间上传速度也快。还有一个相关坑表单提交时如果Controller方法同时接收MultipartFile和MultipartHttpServletRequest在某些版本下会拿不到文件列表。这里推荐直接在方法参数上用RequestParam(file) MultipartFile[] files前端input的name属性一定写成file否则参数绑定不上。6. 毕业设计答辩怎么把项目讲出亮点项目做完了只完成一半还有一半是答辩。很多同学代码写得很顺一上讲台就不知道说什么。下面我给你梳理一套讲项目的顺序按这个顺序讲逻辑清晰不容易被问倒。6.1 演示系统的核心顺序千万不要一上来就管理员登录又点用户管理又点数据统计这是在浪费答辩时间。正确的演示顺序应该是先以普通用户身份演示门户首页展示二手商品列表和搜索功能让老师一眼看到系统的核心业务。然后演示商品详情突出商品状态、成色、交易方式、区域信息。接着演示发布商品最好提前准备好一两张图片现场发一条测试数据走一遍待审核流程。再切到管理员账号在后台看到刚才发布的那条商品审核通过回到前台确认商品出现在列表中。最后演示一次“交易成功”的状态变更把商品从“在售”改成“已交易”。这个顺序本质是在讲一个完整的故事用户发布商品管理员审核商品上架最终成交。每一步都有数据支撑老师跟着你的节奏看下来基本能明白整个系统的价值。6.2 技术问答准备老师大概率会问这么几个问题为什么用SSM而不用Spring Boot你可以回答课程体系和毕设要求以SSM为主SSM能更直观地体现Spring的IoC和AOP、SpringMVC的请求处理流程、MyBatis的SQL映射机制分层更清晰。权限控制怎么做的如果你用了拦截器判断登录状态可以把拦截器的实现细节讲清楚比如HandlerInterceptor的preHandle方法里检查session中的user对象。表结构为什么要这样设计可以结合商品状态字段和收藏唯一索引来回答状态字段保证业务流程可控唯一索引防止数据重复。图片上传后的文件是怎么管理的建议说明用UUID或时间戳重命名存储到服务器upload目录数据库只存相对路径页面通过相对路径访问。6.3 可以做的扩展方向如果学有余力可以在基础版本上做几个低成本但高分值的扩展增加基于用户信用分的排序信用分高的用户发布的商品排在前面。增加收藏排行榜在首页展示被收藏最多的商品Top10。增加相似商品推荐根据当前商品分类找出同分类下其他在售商品。增加消息通知有人留言后给卖家生成一条站内信。这些扩展不需要改架构只需要加表、加接口、加页面但对提升项目完成度很有帮助。最后再说一个我自己的体会做这类毕业设计千万不要追求堆砌功能而是要把一条核心流程做通做顺。二手交易市场的核心竞争力就是“从发商品到交易完成”这条路走得通其他都是锦上添花。只要你把这条主链路的数据流和状态流转讲清楚再把上面几个坑避开这个设计就能稳稳落地。
返回列表