1. 项目概述与技术选型
这个二手交易平台项目采用了前后端分离的架构设计,前端使用Django框架,后端采用Java技术栈的SSM框架(Spring+SpringMVC+MyBatis)。这种技术组合在实际开发中非常典型,既能发挥Python在快速开发方面的优势,又能利用Java在企业级应用中的稳定性。
选择Django作为前端框架有几个重要考量:
- Django自带强大的admin后台管理系统,可以快速搭建商品管理、用户管理等后台功能
- Python生态中有丰富的模板引擎和UI组件,便于快速实现前端界面
- Django ORM对数据库操作进行了良好封装,简化了数据持久层开发
后端选择SSM框架则基于以下考虑:
- Spring的IoC容器和AOP支持为系统提供了良好的解耦和扩展性
- SpringMVC的请求处理机制清晰明了,便于RESTful API开发
- MyBatis作为半自动化的ORM框架,既保留了SQL的灵活性又简化了数据库操作
2. 系统架构设计
2.1 整体架构
系统采用典型的三层架构:
- 表现层:Django模板引擎渲染前端页面
- 业务逻辑层:Spring管理的Service组件
- 数据访问层:MyBatis实现的DAO组件
前后端通过JSON格式的RESTful API进行通信,这种设计使得前端和后端可以独立开发和部署,提高了开发效率。
2.2 数据库设计
系统使用MySQL作为主数据库,主要包含以下几类表:
- 用户相关:user(用户表)、seller(卖家表)
- 商品相关:category(分类表)、goods(商品表)
- 交易相关:order(订单表)、consult(咨询表)
特别要注意的是商品表的设计,我们采用了以下字段结构:
sql复制CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL COMMENT '商品标题',
`category_id` int(11) NOT NULL COMMENT '分类ID',
`seller_id` int(11) NOT NULL COMMENT '卖家ID',
`price` decimal(10,2) NOT NULL COMMENT '价格',
`original_price` decimal(10,2) DEFAULT NULL COMMENT '原价',
`description` text COMMENT '商品描述',
`images` varchar(500) DEFAULT NULL COMMENT '图片URL,多个用逗号分隔',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1-上架 0-下架',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_category` (`category_id`),
KEY `idx_seller` (`seller_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心功能实现
3.1 用户认证与授权
系统采用基于Token的认证机制,用户登录后服务器返回一个JWT Token,后续请求都需要在Header中携带这个Token。Spring Security配合自定义的JWT过滤器实现了这一机制。
核心代码实现:
java复制@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String authHeader = request.getHeader(Constants.TOKEN_HEADER);
if (authHeader != null && authHeader.startsWith(Constants.TOKEN_PREFIX)) {
String authToken = authHeader.substring(Constants.TOKEN_PREFIX.length());
String username = jwtTokenUtil.getUsernameFromToken(authToken);
if (username != null &&
SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource()
.buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
chain.doFilter(request, response);
}
}
3.2 商品发布与管理
卖家发布商品时,系统需要处理以下几个关键点:
- 图片上传处理:支持多图上传,生成不同尺寸的缩略图
- 价格验证:确保售价不高于原价
- 敏感词过滤:对商品标题和描述进行敏感词检测
Django端的商品发布表单处理:
python复制class GoodsForm(forms.ModelForm):
class Meta:
model = Goods
fields = ['title', 'category', 'price', 'original_price', 'description']
def clean(self):
cleaned_data = super().clean()
price = cleaned_data.get('price')
original_price = cleaned_data.get('original_price')
if price and original_price and price > original_price:
raise forms.ValidationError("售价不能高于原价")
return cleaned_data
@login_required
def publish_goods(request):
if request.method == 'POST':
form = GoodsForm(request.POST, request.FILES)
if form.is_valid():
goods = form.save(commit=False)
goods.seller = request.user.seller
goods.save()
# 处理多图上传
images = request.FILES.getlist('images')
for image in images:
GoodsImage.objects.create(goods=goods, image=image)
return redirect('goods_detail', pk=goods.pk)
else:
form = GoodsForm()
return render(request, 'goods/publish.html', {'form': form})
4. 交易流程实现
4.1 订单创建流程
用户下单时系统需要完成以下操作:
- 检查商品库存(针对可量化商品)
- 生成订单编号(使用分布式ID生成器)
- 创建订单记录
- 更新商品状态
- 发送订单通知
订单服务的核心实现:
java复制@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private GoodsMapper goodsMapper;
@Autowired
private OrderMapper orderMapper;
@Autowired
private IdGenerator idGenerator;
@Transactional
@Override
public Order createOrder(Integer goodsId, Integer buyerId, Integer quantity) {
// 1. 检查商品状态
Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
if (goods == null || goods.getStatus() != GoodsStatus.ON_SALE.getCode()) {
throw new BusinessException("商品不可购买");
}
// 2. 生成订单
Order order = new Order();
order.setOrderNo(idGenerator.nextId());
order.setGoodsId(goodsId);
order.setSellerId(goods.getSellerId());
order.setBuyerId(buyerId);
order.setQuantity(quantity);
order.setAmount(goods.getPrice().multiply(new BigDecimal(quantity)));
order.setStatus(OrderStatus.UNPAID.getCode());
orderMapper.insertSelective(order);
// 3. 更新商品状态
goods.setStatus(GoodsStatus.SOLD.getCode());
goodsMapper.updateByPrimaryKeySelective(goods);
// 4. 发送通知(异步)
sendOrderNotification(order);
return order;
}
private void sendOrderNotification(Order order) {
// 异步发送消息到消息队列
// ...
}
}
4.2 支付集成
系统接入了第三方支付平台(如支付宝、微信支付),实现了以下功能:
- 生成支付参数
- 处理支付回调
- 更新订单状态
- 记录支付日志
支付回调处理的核心逻辑:
java复制@RestController
@RequestMapping("/payment")
public class PaymentController {
@Autowired
private PaymentService paymentService;
@Autowired
private OrderService orderService;
@PostMapping("/callback/{channel}")
public String paymentCallback(@PathVariable String channel,
HttpServletRequest request) {
// 1. 验证回调签名
boolean valid = paymentService.verifyCallback(channel, request);
if (!valid) {
return "failure";
}
// 2. 解析回调参数
PaymentCallbackParam param = paymentService.parseCallbackParam(channel, request);
// 3. 处理订单状态
orderService.handlePaymentSuccess(param.getOrderNo(), param.getAmount());
return "success";
}
}
5. 系统优化与扩展
5.1 性能优化
针对二手交易平台的特点,我们做了以下优化:
- 商品列表缓存:使用Redis缓存热门分类的商品列表
- 图片静态化:使用CDN加速图片加载
- 数据库读写分离:查询操作走从库,减轻主库压力
商品列表缓存的实现:
java复制@Service
public class GoodsServiceImpl implements GoodsService {
@Autowired
private GoodsMapper goodsMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String GOODS_LIST_CACHE_KEY = "goods:list:";
@Override
public List<Goods> listGoodsByCategory(Integer categoryId, int page, int size) {
String cacheKey = GOODS_LIST_CACHE_KEY + categoryId + ":" + page;
List<Goods> goodsList = (List<Goods>) redisTemplate.opsForValue().get(cacheKey);
if (goodsList == null) {
PageHelper.startPage(page, size);
goodsList = goodsMapper.selectByCategory(categoryId);
// 缓存10分钟
redisTemplate.opsForValue().set(cacheKey, goodsList, 10, TimeUnit.MINUTES);
}
return goodsList;
}
}
5.2 安全防护
系统实现了多层次的安全防护:
- XSS防护:对用户输入进行转义处理
- CSRF防护:Django内置CSRF中间件,Java端使用Spring Security的CSRF保护
- SQL注入防护:MyBatis使用预编译语句
- 敏感数据加密:用户密码等敏感信息使用BCrypt加密
密码加密处理的实现:
java复制@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User register(String username, String password) {
// 检查用户名是否已存在
if (userMapper.selectByUsername(username) != null) {
throw new BusinessException("用户名已存在");
}
// 密码加密
String encryptedPassword = BCrypt.hashpw(password, BCrypt.gensalt());
// 创建用户
User user = new User();
user.setUsername(username);
user.setPassword(encryptedPassword);
user.setCreateTime(new Date());
userMapper.insertSelective(user);
return user;
}
@Override
public User login(String username, String password) {
User user = userMapper.selectByUsername(username);
if (user == null || !BCrypt.checkpw(password, user.getPassword())) {
throw new BusinessException("用户名或密码错误");
}
return user;
}
}
6. 部署与运维
6.1 环境准备
系统部署需要以下环境:
- Java环境:JDK 8+
- Python环境:Python 3.6+
- 数据库:MySQL 5.7+
- 缓存:Redis 4.0+
- Web服务器:Nginx(前端) + Tomcat(后端)
推荐使用Docker进行容器化部署,可以简化环境配置和依赖管理。
6.2 部署步骤
后端服务部署流程:
- 打包Spring Boot应用:
mvn clean package - 构建Docker镜像:
dockerfile复制FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
- 启动容器:
docker run -d -p 8080:8080 --name backend your-image
前端服务部署流程:
- 收集静态文件:
python manage.py collectstatic - 配置Nginx:
nginx复制server {
listen 80;
server_name your-domain.com;
location /static/ {
alias /path/to/static/files;
}
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
- 启动Django应用:
gunicorn your_project.wsgi:application -b :8000
7. 常见问题与解决方案
7.1 跨域问题
前后端分离架构下常见的跨域问题,我们通过以下方式解决:
- Spring Boot端配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
- Django端使用django-cors-headers中间件
7.2 事务管理
对于需要保证原子性的操作(如创建订单),我们使用Spring的声明式事务管理:
java复制@Service
public class OrderServiceImpl implements OrderService {
@Transactional(rollbackFor = Exception.class)
@Override
public Order createOrder(Integer goodsId, Integer buyerId) {
// 订单创建逻辑
// 如果抛出异常,事务会自动回滚
}
}
7.3 性能监控
我们使用Spring Boot Actuator提供系统监控端点,配合Prometheus和Grafana实现可视化监控:
- 添加依赖:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
- 配置application.properties:
properties复制management.endpoints.web.exposure.include=health,info,prometheus
management.metrics.export.prometheus.enabled=true
8. 项目扩展方向
这个二手交易平台还可以进一步扩展以下功能:
- 即时通讯:集成WebSocket实现买卖家实时沟通
- 推荐系统:基于用户行为实现个性化商品推荐
- 物流跟踪:对接第三方物流API实现物流状态查询
- 信用评价:建立用户信用评价体系
- 移动端适配:开发React Native或Flutter移动应用
即时通讯功能的简单实现:
java复制@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
}
@Controller
public class ChatController {
@MessageMapping("/chat.send")
@SendTo("/topic/public")
public ChatMessage sendMessage(ChatMessage message) {
return message;
}
}
在实际开发中,我们遇到的主要挑战是如何处理高并发下的商品抢购场景。我们最终采用的解决方案是使用Redis的分布式锁配合库存缓存,确保在高并发情况下不会出现超卖问题。具体实现时,我们使用了Redisson客户端提供的分布式锁实现,相比自己实现更加可靠和高效。