
简介这是一份基于JSP/Servlet与StrutsHibernate架构的校园二手交易平台Java源码面向高校在校生、Java Web学习者或毕业设计开发者解决校园内二手物品信息发布、浏览与交易管理等需求。系统采用B/S模式与MySQL 5.0数据库具备面向对象、跨平台、多线程等特性适合用来理解MVC分层、ORM映射以及JDBC数据库访问的完整实现。资源共311个文件包含49个java源文件、40个jsp页面、49个class编译文件、25个xml配置、22个jar依赖库以及78张jpg图片和3个css/js等压缩包约7.05MB目录结构便于按模块查阅。其中还附带数据库SQL脚本默认数据库账号root/123456便于直接导入运行。目前已有3229人学习下载可作为课程设计、毕业设计或二手交易类项目实战的完整参考。1. java 校园二手交易平台源码一次把 SSM 项目跑通的完整工程做 Java 课程设计或者毕设的同学大概率都绕不开一个经典题目校园二手交易平台。这类项目在网上流传的源码版本非常多质量却良莠不齐有的缺数据库脚本有的用的框架版本老到 IDEA 都拉不起依赖还有的连登录校验都没写完整。这份 java 校园二手交易平台源码我拆过一遍属于「开箱即用」的类型基于 Spring SpringMVC MyBatis 三层架构前端用了 JSP 和 Bootstrap数据库脚本、项目说明、部署步骤都齐全直接用 IDEA 打开就能跑。适合正在做 Java 课程设计、毕设或者刚开始接触 SSM 整合、想找一个完整项目做参考的同学。这个平台覆盖的面很全前台包含用户注册登录、商品发布与浏览、按分类和关键词搜索、出价/留言互动、个人中心管理后台包含用户管理、商品管理、订单管理和公告管理。它不是单页面的演示 demo而是能直接当答辩项目交作业的完整业务闭环。如果你正愁找不到一份结构清晰、能跑通、能讲明白的源码这篇笔记会把项目结构、核心表设计、部署步骤和常见的坑一次说清。2. 技术选型和项目结构先看懂分层再动手改代码2.1 SSM 整合方式与为什么选这套组合项目用的是经典的 SSM 三件套Spring 管 BeanSpringMVC 管请求分发MyBatis 管数据库操作。这个组合在近几年高校项目里几乎成了默认标配不是说它比 Spring Boot 先进而是课程大纲还停留在这一代很多学校的 Java Web 课设明确要求用 SSM 而不是 Spring Boot。整套框架的整合思路是这样的web.xml里配置DispatcherServlet和ContextLoaderListener前者负责加载 SpringMVC 容器后者负责加载 Spring 父容器父容器管 Service 和 Mapper子容器管 Controller。一个常见的坑是子容器扫描到了 Service 导致事务失效所以要注意 spring-mvc 的配置文件里只扫描controller包别图省事直接写base-packagecom.example。2.2 工程目录逐层拆解打开工程后先看整体结构。项目采用了标准的 Maven 多目录布局核心目录如下src/main/java/com/example/secondhand ├── controller // 控制层接收请求、返回视图 ├── service // 业务层接口 实现 ├── dao // 数据访问层Mapper 接口 ├── pojo // 实体类User / Product / Order 等 └── utils // 工具类MD5加密、文件上传等源码包的作者把分层做得比较规整。controller 里按业务模块拆了UserController、ProductController、OrderController等pojo 里的实体类字段和数据库表字段一一对应没有蛇形转驼峰的配置烦恼。这一点对新手特别友好——你不用去猜数据库字段和 Java 属性是怎么映射的看到product_id就知道对应productId。2.3 关键设计登录拦截、文件上传与路由前台的登录拦截写在 SpringMVC 拦截器里。LoginInterceptor拦截/**排除掉登录页、注册页和静态资源路径未登录用户访问需要权限的页面会被重定向回/login。实现方式不算高级但胜在逻辑简单、好讲解——答辩时你能很清楚地说出「我是怎么处理未授权访问的」——这对课程设计项目来说比任何花哨设计都加分。文件上传用了 CommonsMultipartResolver。商品图片的保存路径是upload/目录下按日期分文件夹文件名用UUID.randomUUID()重命名避免重复。注意spring-mvc.xml里上传解析器的maxUploadSize默认配了 5MB如果你测试传大图失败先查这个配置而不是怀疑代码。商品管理这一块走的是典型的 Controller → Service → Mapper 链路发布商品时校验标题、价格、描述、图片四个字段价格用BigDecimal接收防止精度问题浏览商品列表时按发布时间倒序分页用的是 PageHelper引入后四行代码就能跑通分页PageHelper.startPage(pageNum, pageSize); ListProduct productList productMapper.selectByCondition(condition); PageInfoProduct pageInfo new PageInfo(productList);PageHelper.startPage后面必须紧跟第一条查询语句——中间不能插任何其他查询操作否则分页参数会被后面的查询吃掉这是 PageHelper 最典型的误用场景。PageInfo里除了数据列表还封装了 total、pages、pageNum 这些分页导航数据JSP 页面上直接pageInfo.total就能显示总记录数。3. 核心功能拆解与关键代码从数据库到页面的完整一条链3.1 数据库表设计与核心表结构数据库脚本放在sql/目录下一共五张核心表用户表、商品表、订单表、留言表、公告表。其中设计得最像真实业务的是订单表——它不是简单地存一个商品 ID而是把product_id、seller_id、buyer_id三个字段都冗余存了一份查询订单列表时不用再 JOIN 三张表拿用户信息。商品表的结构是业务设计的重点字段设计如下字段名类型说明idint(11) PK自增主键product_namevarchar(64)商品标题categoryvarchar(32)分类数码/图书/生活用品等pricedecimal(10,2)售价descriptiontext商品描述image_urlvarchar(255)图片路径seller_idint(11)发布者用户 IDstatustinyint(4)0在售/1已下架/2已售出created_atdatetime发布时间viewsint(11)浏览量重点关注status字段。这个项目里商品下架不是物理删除而是状态位翻转如果你改需求让买家直接拍下商品走订单流程这个状态字段就是消息的发出方——写UPDATE product SET status 2 WHERE id ?就行。很多同学改代码时习惯把下架做成 DELETE结果订单表里关联的商品没了查的时候报空指针都是没做好状态设计的原因。3.2 用户登录与注册MD5 加密和 Session 处理用户的密码在数据库里存的是 MD5 加盐后的散列值这是安全项目里最基础的一层。注册时前端拿到明文密码后端先拼接固定盐值再加密存储public String encryptPassword(String rawPassword) { String salted rawPassword SALT_KEY; return DigestUtils.md5Hex(salted); }DigestUtils底层调的是MessageDigest.getInstance(MD5)返回的是 32 位小写十六进制串。登录校验时把你输入的密码同样拼盐加密后与数据库对比一致才放行。可能有人会觉得 MD5 不够安全但作为课程设计的存储方案它已经比明文密码强一个量级答辩时能说出密码不能明文落库这一条印象分就上去了。登录成功的user对象放进 Session前台通过${sessionScope.user.username}判断登录态。要在 JSP 里用需要在pom.xml引入 JSTL 依赖同时注意项目用的 JSP 版本要支持 EL 表达式——如果页面显示${}原文而不是值八成是web.xml的 Servlet 版本声明写低了改成 3.0 即可。3.3 商品发布功能图片上传与数据落库商品发布是前台最核心的功能距离能跑和能答辩最近的一个模块。表单提交到ProductController.addProduct()方法PostMapping(/product/add) public String addProduct(ModelAttribute Product product, RequestParam(file) MultipartFile file, HttpSession session) throws IOException { if (!file.isEmpty()) { String savedPath uploadFile(file); // 保存并返回新文件名 product.setImageUrl(savedPath); } User user (User) session.getAttribute(user); product.setSellerId(user.getId()); product.setStatus(0); // 上架状态 productService.addProduct(product); return redirect:/product/list; }uploadFile内部用 UUID 重命名后再落盘避免中文文件名或重复文件名造成的路径错误。这里有一个很关键的细节ModelAttribute把整个表单字段自动绑定到Product对象上所以前端表单控件的name属性必须和实体字段名一致——如果你改了实体类字段比如把productName改成title就必须同步改 JSP 里的nametitle否则绑定不上数据库里写入的全是 null。这也是新手常遇到明明表单填了值数据库却是空的的主要原因。3.4 商品列表与详情分页、搜索和浏览量列表页是/product/list支持按分类过滤和关键词模糊搜索两者可以组合使用。模糊搜索的实现是这个项目的经典写法public ListProduct searchProducts(String keyword, String category) { ProductQuery query new ProductQuery(); if (StringUtils.hasText(keyword)) { query.setKeyword(% keyword %); // 拼接 % 用于 LIKE } if (StringUtils.hasText(category)) { query.setCategory(category); } return productMapper.selectByCondition(query); }代码里把%拼在 Java 层Mapper 里直接写if testkeyword ! nullAND product_name LIKE #{keyword}/if。注意一个坑如果在 Mapper XML 里写LIKE %${keyword}%用的是字符串拼接会有 SQL 注入风险#{}是预编译参数占位符安全。这个点答辩时很可能会被老师追问到你需要能说出两者区别。详情页的控制器做了一件聪明的事浏览一次详情views加 1。虽然只是简单的UPDATE product SET views views 1 WHERE id ?但它让热门商品排序有了数据支撑也让页面多了一个xxx 次浏览的可展示元素把项目的完整度又拉高了一档。4. 部署启动与 IDEA 导入配置从源码到本地跑通的完整步骤4.1 环境准备和数据库导入开始之前先确认环境版本。项目基于 JDK 1.8Tomcat 8.5MySQL 5.7 这套组合。原则上 JDK 11 也能跑但没必要冒险尤其 Tomcat 9 以下的兼容性问题很容易把你耗死。第一步先建库导数据。打开 MySQL 客户端执行下面两条命令mysql -u root -p -e CREATE DATABASE campus_secondhand DEFAULT CHARACTER SET utf8mb4; mysql -u root -p campus_secondhand sql/campus_secondhand.sqlutf8mb4 编码必须显式指定这是比 utf8 更宽松的字符集能存 emoji 和 4 字节中文生僻字。如果不指定商品描述里的特殊符号会在写入时报Incorrect string value的错误。sql/目录下如果只有一份脚本就用这个如果分 files.sql 和 project.sql注意先执行建表再执行数据别搞反了。4.2 IDEA 导入与 Maven 依赖下载打开 IDEA菜单栏依次选择File - New - Project from Existing Sources选中项目的根目录IDEA 检测到pom.xml后会提示 Import as Maven Project确认即可。初次加载时 Maven 需要联网下载依赖项目用到了mybatis-spring、jackson-databind、pagehelper这些常用库如果你的本地仓库没有会花点时间。如果 IDEA 没有自动识别 Maven 结构在Settings - Build Tools - Maven里手动指定pom.xml为项目根即可。注意 Maven 仓库用国内镜像源替换阿里云的话可以把~/.m2/settings.xml里的 mirror 配好否则一些老版本的依赖在中央仓库下载很慢。4.3 配置文件修改数据库连接和 Tomcat 部署打开src/main/resources/jdbc.properties把数据库连接改为你自己的账号密码jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/campus_secondhand?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 jdbc.usernameroot jdbc.password123456serverTimezoneAsia/Shanghai这行不是可有可无的。MySQL 8.x 的驱动强制要求时区设置不写会直接抛 CST 时区转换的异常。useSSLfalse是为了省去 SSL 证书的告警日志本地开发不需要加密连接。然后在Run/Debug Configurations里新增一个 Tomcat Server - LocalDeployment 标签页把war exploded加上Application context 填/secondhand。改这个值时记得路径要和代码里的跳转路径对上——看清楚项目里redirect:用的是绝对路径还是相对路径如果页面里硬编码了/secondhand/login那么 context 也必须是/secondhand改了之后所有跳转会全部 404这是一个非常坑的隐藏依赖。4.4 启动后自测清单项目启动成功的标志是 Tomcat 控制台出现Artifact ... is deployed successfully和SpringMVC 容器初始化完成之类的日志。不做部署遗漏的话首页和登录注册页一般几分钟就能打开。建议按下面的清单做一遍完整自测跑通一遍你才能确认这份源码在我手里是活的测试项预期结果注册新账号页面跳转登录页数据库出现新用户密码是 MD5 散列值登录成功跳转首页右上角显示用户名发布商品带图片列表页出现新商品图片能正常显示搜索笔记本电脑返回标题匹配的商品列表点击详情浏览量 1后台登录 admin能进管理页能看到用户和商品列表5. 避坑指南SSM 项目跑不起来最常见的五个坑5.1 页面打开报 404但控制台没有任何异常现象Tomcat 正常启动访问/secondhand/返回 404后台日志干净得像是没收到请求。原因application context 配的路径不对。项目内部 JSP 里的a标签和 redirect 全都带/secondhand前缀而你配的 context 是/或者自定义的其他路径。解决把 Deployment 里的 Application context 改成和项目代码里统一定的/secondhand。实在拿不准的话打开 JSP 文件搜一下href/和redirect:里的路径照着改 Deployment 的 context 就行。5.2 图片上传后页面无法显示现象发布商品时没报错但列表页的商品图片是个裂图直接访问图片 URL 也是 404。原因上传路径没落对。这个项目上传的文件默认保存到 Tomcat 部署的临时目录或者项目内的upload/目录但虚拟路径映射没配好。如果你重启 Tomcat 后发现图片丢了十有八九是文件存到了 target 目录的临时位置里被清掉了。解决看一下spring-mvc.xml里的资源配置确认mvc:resources mapping/upload/** location/upload/ /存在且路径正确。严格的做法是在 Tomcat 的 server.xml 里配置Context docBaseD:/upload path/upload/指向磁盘固定目录这样重启不丢文件。5.3 数据库查询报 Invalid bound statement (not found)现象点商品列表直接白屏控制台打出一行Invalid bound statement (not found): com.example.dao.ProductMapper.selectByCondition。原因这是 MyBatis 老生常谈的坑。ProductMapper.java接口和ProductMapper.xml文件不在同一个包结构下或者 pom.xml 的 build 配置没把 xml 文件打进去。解决检查src/main/resources/mapper/目录确认 XML 文件存在。同时确认mybatis-config.xml里 mapper 扫描路径写的是不是映射文件的实际路径。如果 XML 在resources下已经是这样配的看一下pom.xml有没有以下这段——Maven 默认把 resources 目录下的 xml 文件排除在生产包之外必须显式声明包含build resources resource directorysrc/main/resources/directory includes include**/*.xml/include /includes /resource /resources /build5.4 数据库中文乱码或插入失败现象注册用户时中文用户名变成问号???或者商品描述插入报Incorrect string value。原因数据库连接 URL 没声明编码或者建库时字符集不是 utf8。虽然 jdbc.properties 里已经写了characterEncodingutf8但建库命令只写了默认字符集。解决如果你用的是 4.1 版本的建库脚本把建库语句补上DEFAULT CHARACTER SET utf8mb4。同时确认 MySQL 的 my.ini 里character-set-serverutf8mb4已设置改完重启 MySQL 服务再试。5.5 JSP 页面显示 EL 表达式原文现象页面上能看到${user.username}但用户名没渲染出来。原因web.xml 的版本声明太老。Servlet 2.5 及以前版本的 JSP 默认禁用 EL 表达式。解决打开src/main/webapp/WEB-INF/web.xml如果里面写的是version2.5或者version3.0改成以下声明web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd version3.1 /web-app同时确认jsp-config里没有全局配置el-ignoredtrue/el-ignored。改完删掉 Tomcat 的 work 目录重新部署EL 表达式就能正常解析了。6. 二次开发方向的验证点把课程设计变成可用项目如果你打算在这份源码上改动功能而不是原封不动上交可以从三个方向做小改。第一个方向是给商品表加字段。假设要加成色这一列数据库先执行ALTER TABLE product ADD COLUMN condition_level VARCHAR(16) DEFAULT 全新再把Product.java实体类加private String conditionLevel;字段Mapperr XML 的 insert 和 select 语句同步把字段对应的列名加进去。注意 insert 标签里sql封装的公共字段片段不要漏了否则会出现写入为 null、查询为 null 的双重翻车。第二个方向是加入购物车与订单联动。这个项目里用户点击购买后直接生成订单没有购物车的概念。给前端页面加一个购物车按钮后端建一张cart表存user_id、product_id、quantity结算时把购物车里所有商品批量生成订单对应product.status统一置 2。列表页把status0作为在售条件写死所以已售出的商品不会出现在列表里。这个方向的改动量适合作为加分项代码量控制在一天内完成。第三个方向是把分页从 PageHelper 改成手写 LIMIT。PageHelper 好用是好用但它有一个隐藏风险——如果存在多数据源或者查询嵌套分页拦截器会把内部子查询的 SQL 也给分页了。手写方式如下public ListProduct getList(int pageNum, int pageSize, String keyword) { int offset (pageNum - 1) * pageSize; return productMapper.selectWithLimit(keyword, offset, pageSize); }Mapper XML 对应的 SQL 是select idselectWithLimit resultTypecom.example.pojo.Product SELECT id, product_name, price, image_url, status, views FROM product where if testkeyword ! null and keyword ! product_name LIKE CONCAT(%, #{keyword}, %) /if AND status 0 /where ORDER BY created_at DESC LIMIT #{offset}, #{pageSize} /selectLIMIT #{offset}, #{pageSize}这里的两个参数是 int 类型所以用#{}没问题但如果是字符串类型的排序条件就不能这么写——预编译参数只能用来传值不能用来传字段名。这也是手写分页相比 PageHelper 更可控的原因你能精确知道 SQL 长什么样答辩被追问时不会被问住。我自己后面做类似项目时都会先拿这份源码的 Mapper 层当模板它把 SSM 的配置方式和坑都暴露得很清楚——老手扫一眼配置就知道哪里容易翻车新手盯着踩坑区跑一遍就能把框架摸出感觉了。建议你下载后先不改代码完整跑通一遍流程把数据库的结构和 controller 的路由理清楚再加自己的功能。从那以后我每次导入这套项目的第一个动作都是先检查 jdbc.properties 的时区参数和分页起始页传参——这两处翻车率最高。希望这份拆解能帮你在 SSM 课设这条路上少绕几个弯。本文还有配套的精品资源点击获取