在高校校园环境中,闲置物品的循环利用一直是一个具有显著社会价值和经济价值的课题。每年毕业季,大量书籍、家电、生活用品被遗弃;而新生入学时,又往往需要购置各类必需品。传统的线下跳蚤市场或BBS论坛存在信息分散、交易不便、信任度低等问题。针对这一特定场景,采用JSP+Servlet技术栈构建的校园二手交易平台应运而生,它通过数字化的手段为校园社区提供了一个安全、便捷、高效的闲置物品流转渠道。
该平台严格遵循Java EE经典的MVC设计模式,实现了表现层、控制层和模型层的清晰分离。Servlet作为核心控制器,负责拦截和处理所有HTTP请求,进行业务逻辑调度和数据验证。JSP页面则专注于视图渲染,通过JSTL标签库和EL表达式动态展示数据,避免了在页面中嵌入Java代码,保证了代码的可维护性。后端采用MySQL数据库存储业务数据,通过JDBC进行数据访问。整个架构采用分层设计,将数据访问层(DAO)、业务逻辑层(Service)和Web层明确分离,使得系统具备良好的扩展性和可维护性。
数据库架构设计深度解析
平台的数据库设计体现了对校园二手交易业务逻辑的深刻理解。核心表包括用户表、商品表、订单表、购物车表、收藏表和管理员表,共计6张表支撑起整个平台的业务运转。
用户表(user)的设计充分考虑了校园环境的特殊性:
CREATE TABLE `user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL UNIQUE,
`password` varchar(255) NOT NULL,
`email` varchar(100) NOT NULL UNIQUE,
`phone` varchar(20) DEFAULT NULL,
`campus_card` varchar(50) UNIQUE,
`real_name` varchar(50) DEFAULT NULL,
`dormitory` varchar(100) DEFAULT NULL,
`avatar` varchar(255) DEFAULT '/images/default-avatar.png',
`balance` decimal(10,2) DEFAULT '0.00',
`credit_score` int(11) DEFAULT '100',
`status` tinyint(1) DEFAULT '1',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
该表设计的亮点在于引入了campus_card(校园卡号)字段作为校园身份验证的唯一标识,这不仅增强了交易双方的可信度,也为后续实现校园卡绑定支付提供了扩展空间。credit_score(信用积分)字段的设立构建了用户信用体系的基础,通过交易评价、履约情况等维度动态调整用户信用分,形成良性循环的交易环境。balance字段支持平台内虚拟账户体系,便于小额交易结算。
商品表(product)的设计体现了二手商品交易的复杂性:
CREATE TABLE `product` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`product_name` varchar(200) NOT NULL,
`description` text,
`original_price` decimal(10,2) NOT NULL,
`current_price` decimal(10,2) NOT NULL,
`category_id` int(11) NOT NULL,
`seller_id` int(11) NOT NULL,
`images` varchar(500) DEFAULT NULL,
`status` enum('pending','approved','rejected','sold') DEFAULT 'pending',
`view_count` int(11) DEFAULT '0',
`collect_count` int(11) DEFAULT '0',
`campus` varchar(100) DEFAULT NULL,
`publish_time` datetime DEFAULT CURRENT_TIMESTAMP,
`approve_time` datetime DEFAULT NULL,
`approver_id` int(11) DEFAULT NULL,
`reject_reason` varchar(255) DEFAULT NULL,
PRIMARY KEY (`product_id`),
KEY `idx_seller` (`seller_id`),
KEY `idx_category` (`category_id`),
KEY `idx_status` (`status`),
CONSTRAINT `fk_product_seller` FOREIGN KEY (`seller_id`) REFERENCES `user` (`user_id`),
CONSTRAINT `fk_product_approver` FOREIGN KEY (`approver_id`) REFERENCES `admin` (`admin_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
商品表采用审核机制设计,status字段包含'pending'(待审核)、'approved'(已审核)、'rejected'(已拒绝)和'sold'(已售出)四种状态,确保平台商品质量。campus字段支持多校区部署,不同校区的用户可以筛选本校区商品,减少物流成本。view_count和collect_count字段为热门商品推荐算法提供数据基础。外键约束保证了数据完整性,防止出现无效的用户ID或管理员ID。
核心业务功能实现剖析
用户认证与会话管理
用户登录模块采用安全的密码加密存储和会话管理机制。密码使用BCrypt算法加密,确保即使数据库泄露也不会导致明文密码泄漏。
// 用户登录验证核心逻辑
public class UserService {
public User login(String username, String password) throws SQLException {
UserDAO userDAO = new UserDAO();
User user = userDAO.findByUsername(username);
if (user != null && BCrypt.checkpw(password, user.getPassword())) {
// 更新最后登录时间
userDAO.updateLastLogin(user.getUserId());
return user;
}
return null;
}
}
// 登录Servlet处理
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
UserService userService = new UserService();
try {
User user = userService.login(username, password);
if (user != null) {
HttpSession session = request.getSession();
session.setAttribute("currentUser", user);
session.setMaxInactiveInterval(30 * 60); // 30分钟超时
// 根据用户角色跳转到不同页面
if (user.getRole() != null && user.getRole().equals("admin")) {
response.sendRedirect("admin/dashboard.jsp");
} else {
response.sendRedirect("index.jsp");
}
} else {
request.setAttribute("errorMsg", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
} catch (SQLException e) {
throw new ServletException("数据库错误", e);
}
}
}

商品发布与审核流程
商品发布功能包含完整的前端验证和后端处理流程,支持多图上传和富文本描述。
// 商品发布Servlet
@WebServlet("/product/publish")
@MultipartConfig
public class ProductPublishServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 验证用户登录状态
User user = (User) request.getSession().getAttribute("currentUser");
if (user == null) {
response.sendRedirect("../login.jsp");
return;
}
try {
// 获取表单数据
String productName = request.getParameter("productName");
String description = request.getParameter("description");
BigDecimal originalPrice = new BigDecimal(request.getParameter("originalPrice"));
BigDecimal currentPrice = new BigDecimal(request.getParameter("currentPrice"));
int categoryId = Integer.parseInt(request.getParameter("categoryId"));
String campus = request.getParameter("campus");
// 处理图片上传
String imagePaths = "";
Collection<Part> parts = request.getParts();
for (Part part : parts) {
if (part.getName().equals("images") && part.getSize() > 0) {
String fileName = UUID.randomUUID().toString() +
getFileExtension(part.getSubmittedFileName());
String savePath = getServletContext().getRealPath("/uploads") +
File.separator + fileName;
part.write(savePath);
imagePaths += "/uploads/" + fileName + ",";
}
}
// 创建商品对象
Product product = new Product();
product.setProductName(productName);
product.setDescription(description);
product.setOriginalPrice(originalPrice);
product.setCurrentPrice(currentPrice);
product.setCategoryId(categoryId);
product.setSellerId(user.getUserId());
product.setCampus(campus);
product.setImages(imagePaths.isEmpty() ? null : imagePaths.substring(0, imagePaths.length() - 1));
product.setStatus(ProductStatus.PENDING);
// 保存到数据库
ProductService productService = new ProductService();
boolean success = productService.publishProduct(product);
if (success) {
request.setAttribute("successMsg", "商品发布成功,等待管理员审核");
} else {
request.setAttribute("errorMsg", "商品发布失败,请重试");
}
request.getRequestDispatcher("../publish-result.jsp").forward(request, response);
} catch (Exception e) {
throw new ServletException("商品发布处理错误", e);
}
}
private String getFileExtension(String fileName) {
return fileName.substring(fileName.lastIndexOf("."));
}
}

购物车与订单处理系统
购物车功能采用Session和数据库双存储策略,确保用户在不同设备间同步购物车数据。
// 购物车业务逻辑实现
public class CartService {
public void addToCart(int userId, int productId, int quantity) throws SQLException {
// 检查商品是否存在且可售
ProductDAO productDAO = new ProductDAO();
Product product = productDAO.findById(productId);
if (product == null || !product.getStatus().equals(ProductStatus.APPROVED)) {
throw new IllegalArgumentException("商品不存在或不可售");
}
// 检查库存(对于限量商品)
if (product.getStock() != null && product.getStock() < quantity) {
throw new IllegalArgumentException("商品库存不足");
}
// 添加购物车项
CartDAO cartDAO = new CartDAO();
CartItem existingItem = cartDAO.findByUserAndProduct(userId, productId);
if (existingItem != null) {
// 更新数量
cartDAO.updateQuantity(existingItem.getItemId(), existingItem.getQuantity() + quantity);
} else {
// 新增购物车项
CartItem newItem = new CartItem();
newItem.setUserId(userId);
newItem.setProductId(productId);
newItem.setQuantity(quantity);
newItem.setUnitPrice(product.getCurrentPrice());
newItem.setCreateTime(new Date());
cartDAO.insert(newItem);
}
}
public List<CartItem> getCartItems(int userId) throws SQLException {
CartDAO cartDAO = new CartDAO();
return cartDAO.findByUserId(userId);
}
public BigDecimal calculateTotal(List<CartItem> cartItems) {
return cartItems.stream()
.map(item -> item.getUnitPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
// 订单生成逻辑
public class OrderService {
public Order createOrder(int userId, String shippingAddress, String paymentMethod)
throws SQLException {
// 获取购物车商品
CartService cartService = new CartService();
List<CartItem> cartItems = cartService.getCartItems(userId);
if (cartItems.isEmpty()) {
throw new IllegalArgumentException("购物车为空");
}
// 计算总金额
BigDecimal totalAmount = cartService.calculateTotal(cartItems);
// 创建订单
Order order = new Order();
order.setUserId(userId);
order.setOrderNumber(generateOrderNumber());
order.setTotalAmount(totalAmount);
order.setStatus(OrderStatus.PENDING_PAYMENT);
order.setShippingAddress(shippingAddress);
order.setPaymentMethod(paymentMethod);
order.setCreateTime(new Date());
OrderDAO orderDAO = new OrderDAO();
int orderId = orderDAO.insert(order);
// 创建订单明细
OrderItemDAO orderItemDAO = new OrderItemDAO();
for (CartItem cartItem : cartItems) {
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(orderId);
orderItem.setProductId(cartItem.getProductId());
orderItem.setQuantity(cartItem.getQuantity());
orderItem.setUnitPrice(cartItem.getUnitPrice());
orderItemDAO.insert(orderItem);
}
// 清空购物车
CartDAO cartDAO = new CartDAO();
cartDAO.clearByUserId(userId);
return orderDAO.findById(orderId);
}
private String generateOrderNumber() {
return "ORD" + System.currentTimeMillis() +
String.format("%04d", (int)(Math.random() * 10000));
}
}

实体模型与业务逻辑封装
平台采用面向对象的设计思想,将核心业务概念封装为实体类,每个实体类对应数据库中的一张表,并通过DAO模式实现数据访问的封装。
用户实体模型:
public class User {
private int userId;
private String username;
private String password;
private String email;
private String phone;
private String campusCard;
private String realName;
private String dormitory;
private String avatar;
private BigDecimal balance;
private int creditScore;
private boolean status;
private Date createTime;
private String role;
// 构造方法、getter和setter省略
public boolean canPublishProduct() {
return creditScore >= 60 && status;
}
public boolean hasSufficientBalance(BigDecimal amount) {
return balance.compareTo(amount) >= 0;
}
}
商品实体模型:
public class Product {
private int productId;
private String productName;
private String description;
private BigDecimal originalPrice;
private BigDecimal currentPrice;
private int categoryId;
private int sellerId;
private String images;
private ProductStatus status;
private int viewCount;
private int collectCount;
private String campus;
private Date publishTime;
private Date approveTime;
private Integer approverId;
private String rejectReason;
public boolean isApproved() {
return status == ProductStatus.APPROVED;
}
public boolean isAvailable() {
return isApproved() && !status.equals(ProductStatus.SOLD);
}
public BigDecimal getDiscount() {
if (originalPrice.compareTo(BigDecimal.ZERO) > 0) {
return originalPrice.subtract(currentPrice)
.divide(originalPrice, 2, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(100));
}
return BigDecimal.ZERO;
}
}
用户界面与交互体验
平台的前端界面采用响应式设计,确保在不同设备上都能提供良好的用户体验。首页采用卡片式布局展示商品,支持按分类、价格、校区等多维度筛选。

用户中心整合了个人信息管理、我的发布、我的订单、收藏夹等功能模块,提供一站式的个人交易管理界面。

商品详情页采用标签页设计,分别展示商品信息、卖家信息和用户评价,帮助买家全面了解商品情况。

技术优化与扩展方向
基于当前平台架构,未来可以从以下几个方向进行深度优化和功能扩展:
性能优化与缓存策略
引入Redis作为缓存层,对热点商品数据、用户会话、系统配置等进行缓存,减轻数据库压力。实现二级缓存机制,在Service层使用Ehcache本地缓存,在分布式环境下使用Redis集中式缓存。
// 缓存配置示例 @Service public class ProductServiceWithCache { @Autowired private RedisTemplate<String, Product> redisTemplate; private static final String PRODUCT_CACHE_KEY = "product:"; private static final long CACHE_EXPIRE_HOURS = 24; public Product findByIdWithCache(int productId) { String cacheKey = PRODUCT_CACHE_KEY + productId; Product product = redisTemplate.opsForValue().get(cacheKey); if (product == null) { product = productDAO.findById(productId); if (product != null) { redisTemplate.opsForValue().set(cacheKey, product, CACHE_EXPIRE_HOURS, TimeUnit.HOURS); } } return product; } }智能推荐系统集成
基于用户行为数据(浏览、收藏、购买记录)构建推荐算法,实现个性化商品推荐。采用协同过滤和内容-based推荐相结合的策略,提升用户粘性和交易转化率。
移动端应用开发
开发React Native或Flutter移动应用,提供更便捷的移动交易体验。实现推送通知、扫码识别、位置服务等移动端特有功能。
支付系统集成与校园卡对接
集成微信支付、支付宝等第三方支付平台,同时探索与校园一卡通系统的对接,实现校园卡在线支付功能,进一步提升支付便利性和安全性。
微服务架构改造
随着业务规模扩大,可将单体应用拆分为用户服务、商品服务、订单服务、支付服务等微服务,采用Spring Cloud技术栈实现服务治理、配置管理和链路追踪。
数据分析与可视化
构建数据仓库,对交易数据、用户行为数据进行深度分析,为运营决策提供数据支持。开发管理员数据看板,实时监控平台运营状况。
该校园二手交易平台通过严谨的技术架构设计和深入的业务逻辑实现,为校园社区提供了一个安全可靠的数字化交易环境。其模块化设计和分层架构为后续功能扩展和技术升级奠定了坚实基础,具备持续演进的能力。随着技术的不断迭代和业务需求的深化,平台有望成为校园数字化