校园二手交易平台是解决学生群体闲置物品流转的刚需产品。每年毕业季,大量教材、电子产品、生活用品被低价转卖或直接丢弃;而新生入学时又需要购置这些物品。传统线下交易存在信息不对称、交易效率低、缺乏保障等问题。
我在母校担任技术社团指导时,发现学生们在微信群和贴吧的交易存在以下痛点:
这个系统采用Vue+SpringBoot+MySQL技术栈实现,具有以下典型特征:
提示:校园场景的特殊性在于用户群体单纯但流动性强,系统设计需要平衡功能完备性和开发效率,避免过度设计。
采用Vue3组合式API开发,主要技术选型考虑:
bash复制npm create vue@latest
前端工程结构示例:
code复制src/
├── api/ # 接口定义
├── assets/ # 静态资源
├── components/ # 公共组件
├── composables/ # 组合式函数
├── router/ # 路由配置
├── stores/ # Pinia状态
├── styles/ # 全局样式
└── views/ # 页面组件
SpringBoot采用经典三层架构:
code复制com.campus.trade
├── config # 配置类
├── controller # 控制层
├── service # 服务层
│ └── impl # 实现类
├── mapper # DAO接口
├── entity # 实体类
├── dto # 数据传输对象
├── vo # 视图对象
└── util # 工具类
关键配置示例(application.yml):
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/campus_trade?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: 127.0.0.1
port: 6379
核心表结构设计:
| 表名 | 字段 | 说明 |
|---|---|---|
| user | id, username, password, phone, avatar | 用户表 |
| goods | id, name, price, category, description | 商品表 |
| order | id, buyer_id, seller_id, goods_id, status | 订单表 |
| comment | id, order_id, content, rating | 评价表 |
ER图关键点:
注意:校园场景下需要特别设计举报功能字段,如goods表需要包含report_count和is_blocked字段。
前端关键代码(Vue3 + Element Plus):
vue复制<template>
<el-upload
action="/api/upload"
list-type="picture-card"
:on-success="handleUploadSuccess"
>
<el-icon><Plus /></el-icon>
</el-upload>
</template>
<script setup>
const form = reactive({
name: '',
price: 0,
category: '',
description: ''
})
const handleSubmit = async () => {
await axios.post('/api/goods', form)
}
</script>
后端商品校验逻辑:
java复制@PostMapping("/goods")
public Result addGoods(@Valid @RequestBody GoodsDTO dto) {
// 价格必须大于0
if(dto.getPrice() <= 0) {
throw new BusinessException("价格必须大于0");
}
// 敏感词过滤
if(SensitiveFilter.contains(dto.getDescription())){
throw new BusinessException("描述包含敏感内容");
}
return goodsService.addGoods(dto);
}
订单状态机设计:
java复制public enum OrderStatus {
UNPAID(0, "待支付"),
PAID(1, "已支付"),
SHIPPED(2, "已发货"),
COMPLETED(3, "已完成"),
CANCELLED(4, "已取消");
// 状态转换校验逻辑
public static boolean canChange(OrderStatus from, OrderStatus to) {
switch (from) {
case UNPAID: return to == PAID || to == CANCELLED;
case PAID: return to == SHIPPED || to == CANCELLED;
// 其他状态转换规则...
}
}
}
采用WebSocket实现简易聊天:
java复制@ServerEndpoint("/chat/{userId}")
@Component
public class ChatEndpoint {
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
// 用户连接处理
}
@OnMessage
public void onMessage(String message, Session session) {
// 消息转发逻辑
}
}
前端消息处理:
javascript复制const socket = new WebSocket(`ws://localhost:8080/chat/${userId}`)
socket.onmessage = (event) => {
const msg = JSON.parse(event.data)
messageList.value.push(msg)
}
java复制@RateLimiter(value = 10, key = "#userId")
@PostMapping("/comment")
public Result addComment(@RequestBody CommentDTO dto) {
// 评价逻辑
}
java复制@Cacheable(value = "goods", key = "#id")
public GoodsVO getGoodsById(Long id) {
return goodsMapper.selectById(id);
}
sql复制ALTER TABLE `goods` ADD INDEX `idx_category_status` (`category`, `status`);
使用Docker Compose编排:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: 123456
redis:
image: redis:alpine
backend:
build: ./backend
ports:
- "8080:8080"
frontend:
build: ./frontend
ports:
- "80:80"
properties复制management.endpoints.web.exposure.include=health,info,metrics
javascript复制window.onerror = (message, source, lineno, colno, error) => {
axios.post('/api/log/error', {
message,
stack: error?.stack
})
}
后端配置类:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.maxAge(3600);
}
}
SpringBoot配置:
yaml复制spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MB
Nginx配置:
nginx复制location / {
try_files $uri $uri/ /index.html;
}
在项目开发过程中,最大的收获是对全栈开发流程的深入理解。特别提醒后来者注意:校园类产品一定要做好敏感内容过滤和用户实名认证,我们在第一版上线后就遇到了广告机器人刷帖的问题,后来通过"校园邮箱验证+人工审核"双重机制才有效控制。