随着电子商务的快速发展,传统线下文具采购模式面临着品类有限、比价困难、耗时耗力等痛点。文具易购平台应运而生,采用成熟的JSP+Servlet技术栈构建,为个人消费者和小型企业提供一站式文具采购解决方案。该系统通过线上集中展示与交易,显著降低了用户的采购成本与时间成本,同时为商家提供了标准化的管理后台,简化了日常运营流程。
系统架构与技术栈
该平台严格遵循MVC设计模式,构建了清晰的三层架构。Servlet作为核心控制器层,负责接收用户请求、调用业务逻辑并进行页面跳转控制;JSP页面专注于视图展示层,通过JSTL标签库和EL表达式简化前端逻辑;模型层则由JavaBean实体类和数据访问对象构成,通过JDBC与MySQL数据库进行交互。
技术栈选择体现了经典Java Web开发的最佳实践:
- 后端技术:Servlet 3.0+、JSP 2.0+
- 前端技术:HTML5、CSS3、JavaScript
- 数据持久化:JDBC、MySQL 5.7+
- 项目管理:Maven
- 服务器:Tomcat 8.0+
数据库设计亮点分析
文具表设计优化
CREATE TABLE `wenju` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '文具ID',
`name` varchar(255) NOT NULL COMMENT '文具名称',
`author` varchar(255) NOT NULL COMMENT '生产厂商/品牌',
`price` int(10) NOT NULL COMMENT '文具价格(单位:元)',
`introduction` varchar(255) DEFAULT NULL COMMENT '文具描述',
`stock` int(10) DEFAULT NULL COMMENT '库存数量',
`category` varchar(255) NOT NULL COMMENT '所属分类',
`cover` varchar(255) DEFAULT NULL COMMENT '封面图片路径',
`time` date DEFAULT NULL COMMENT '上架时间',
PRIMARY KEY (`id`),
KEY `category` (`category`),
KEY `name` (`name`),
KEY `price` (`price`),
KEY `cover` (`cover`),
CONSTRAINT `wenju_ibfk_1` FOREIGN KEY (`category`) REFERENCES `category` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=117 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='文具表'
该表设计体现了良好的数据库优化策略。价格字段采用int类型存储,避免了浮点数精度问题,实际应用中可通过除以100来支持小数。建立了多个复合索引,包括分类、名称、价格和封面路径,显著提升了商品检索和排序的性能。外键约束确保了分类数据的完整性。

订单表业务逻辑设计
CREATE TABLE `orders` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '订单ID',
`name` varchar(255) NOT NULL COMMENT '商品名称',
`price` int(10) NOT NULL COMMENT '商品单价',
`quantity` int(10) NOT NULL DEFAULT 1 COMMENT '购买数量',
`total` int(10) NOT NULL COMMENT '订单总金额',
`user` varchar(255) NOT NULL DEFAULT '' COMMENT '下单用户',
`wenjuid` int(11) DEFAULT NULL COMMENT '关联文具ID',
`shou` varchar(255) DEFAULT NULL COMMENT '收货人姓名',
`ADDRESS` varchar(255) DEFAULT NULL COMMENT '收货地址',
`info` varchar(255) DEFAULT NULL COMMENT '订单备注信息',
`phone` varchar(255) DEFAULT NULL COMMENT '收货人联系电话',
`status` int(11) DEFAULT NULL COMMENT '订单状态(0待处理,1已发货,2已完成)',
PRIMARY KEY (`id`),
KEY `user` (`user`),
CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`user`) REFERENCES `user` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='订单信息表'
订单表设计采用了反范式化策略,存储了商品名称和价格等冗余信息,避免了因商品信息变更导致的订单历史数据不一致问题。状态字段使用枚举值管理订单生命周期,确保了业务流程的清晰可控。
核心功能实现详解
用户认证与权限管理
系统实现了完整的用户认证体系,通过Session管理用户登录状态。以下是用户登录验证的核心Servlet代码:
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private UserDAO userDAO = new UserDAO();
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userDAO.findByUsernameAndPassword(username, password);
if (user != null) {
HttpSession session = request.getSession();
session.setAttribute("user", user);
session.setMaxInactiveInterval(30 * 60); // 30分钟超时
response.sendRedirect("index.jsp");
} else {
request.setAttribute("error", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
管理员权限控制通过过滤器实现,确保敏感操作的安全性:
@WebFilter("/admin/*")
public class AdminFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpSession session = httpRequest.getSession(false);
if (session != null && session.getAttribute("admin") != null) {
chain.doFilter(request, response);
} else {
((HttpServletResponse) response).sendRedirect("../adminLogin.jsp");
}
}
}
商品管理模块
商品CRUD操作通过统一的Servlet控制器处理,支持文件上传功能:
@WebServlet("/admin/product")
@MultipartConfig
public class ProductServlet extends HttpServlet {
private ProductDAO productDAO = new ProductDAO();
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
switch (action) {
case "add":
addProduct(request, response);
break;
case "update":
updateProduct(request, response);
break;
case "delete":
deleteProduct(request, response);
break;
}
}
private void addProduct(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Part filePart = request.getPart("cover");
String fileName = extractFileName(filePart);
String savePath = getServletContext().getRealPath("/uploads") + File.separator + fileName;
filePart.write(savePath);
Product product = new Product();
product.setName(request.getParameter("name"));
product.setPrice(Integer.parseInt(request.getParameter("price")));
product.setStock(Integer.parseInt(request.getParameter("stock")));
product.setCover("uploads/" + fileName);
productDAO.add(product);
response.sendRedirect("productList.jsp");
}
}
购物车与订单处理
购物车功能通过Session实现临时数据存储,支持商品添加、数量修改和删除操作:
@WebServlet("/cart")
public class CartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
Map<Integer, CartItem> cart = getOrCreateCart(session);
int productId = Integer.parseInt(request.getParameter("productId"));
int quantity = Integer.parseInt(request.getParameter("quantity"));
Product product = productDAO.findById(productId);
if (cart.containsKey(productId)) {
CartItem item = cart.get(productId);
item.setQuantity(item.getQuantity() + quantity);
} else {
cart.put(productId, new CartItem(product, quantity));
}
session.setAttribute("cart", cart);
response.sendRedirect("cart.jsp");
}
@SuppressWarnings("unchecked")
private Map<Integer, CartItem> getOrCreateCart(HttpSession session) {
Map<Integer, CartItem> cart = (Map<Integer, CartItem>) session.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
}
return cart;
}
}
订单生成过程包含库存检查和事务处理:
public class OrderService {
private OrderDAO orderDAO = new OrderDAO();
private ProductDAO productDAO = new ProductDAO();
public boolean createOrder(Order order, List<CartItem> items) {
Connection conn = null;
try {
conn = DatabaseUtil.getConnection();
conn.setAutoCommit(false);
// 检查库存
for (CartItem item : items) {
Product product = productDAO.findById(item.getProduct().getId());
if (product.getStock() < item.getQuantity()) {
throw new RuntimeException("商品库存不足: " + product.getName());
}
}
// 扣减库存
for (CartItem item : items) {
productDAO.updateStock(item.getProduct().getId(),
item.getProduct().getStock() - item.getQuantity());
}
// 创建订单
orderDAO.add(order);
conn.commit();
return true;
} catch (Exception e) {
if (conn != null) {
try { conn.rollback(); } catch (SQLException ex) {}
}
return false;
}
}
}
分类管理系统
支持多级分类管理,通过递归算法实现分类树的构建:
public class CategoryDAO {
public List<Category> getCategoryTree() {
List<Category> allCategories = findAll();
return buildTree(allCategories, 0);
}
private List<Category> buildTree(List<Category> categories, int parentId) {
List<Category> tree = new ArrayList<>();
for (Category category : categories) {
if (category.getParent() == parentId) {
category.setChildren(buildTree(categories, category.getId()));
tree.add(category);
}
}
return tree;
}
public List<Category> findByParentId(int parentId) {
String sql = "SELECT * FROM category WHERE parent = ?";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Category.class), parentId);
}
}
实体模型设计
系统采用标准的JavaBean规范设计实体类,每个实体对应数据库中的一张表。以下是管理员实体类的完整实现:
package com.zhy.beans;
public class Admin {
private int id;
private String username;
private String password;
public Admin() {}
public Admin(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
用户实体类设计考虑了业务扩展性:
package com.zhy.beans;
public class User {
private int id;
private String username;
private String nickname;
private String password;
private String email;
private String phone;
private Date createTime;
// 构造方法和getter/setter省略
}
功能展望与优化方向
性能优化方案
- 引入Redis缓存层
- 实现商品分类信息、热门商品等数据的缓存
- 减少数据库访问压力,提升系统响应速度
- 使用Redis集群支持高并发场景
public class CategoryService {
private RedisTemplate redisTemplate;
private CategoryDAO categoryDAO;
public List<Category> getCategoryTree() {
String cacheKey = "category:tree";
List<Category> tree = redisTemplate.opsForList().range(cacheKey, 0, -1);
if (tree == null || tree.isEmpty()) {
tree = categoryDAO.getCategoryTree();
redisTemplate.opsForList().rightPushAll(cacheKey, tree);
redisTemplate.expire(cacheKey, 1, TimeUnit.HOURS);
}
return tree;
}
}
- 数据库读写分离
- 主数据库处理写操作,从数据库处理读操作
- 使用Sharding-JDBC实现透明的数据分片
- 支持水平扩展,提升系统吞吐量
功能扩展建议
搜索引擎集成
- 集成Elasticsearch实现商品全文检索
- 支持拼音搜索、同义词扩展等高级功能
- 提升商品发现能力和用户体验
微服务架构改造
- 将单体应用拆分为用户服务、商品服务、订单服务等微服务
- 使用Spring Cloud实现服务治理和配置管理
- 支持独立部署和弹性伸缩
移动端适配
- 开发React Native或Flutter移动应用
- 实现PWA渐进式Web应用
- 支持离线浏览和推送通知功能
技术架构升级
前后端分离重构
- 后端提供RESTful API接口
- 前端使用Vue.js或React框架
- 实现更好的团队协作和技术栈灵活性
消息队列集成
- 使用RabbitMQ处理订单异步通知
- 实现库存预警和统计报表生成
- 提升系统解耦度和可靠性
总结
文具易购平台作为一个典型的JSP+Servlet电商应用,展现了经典Java Web技术的成熟度和稳定性。系统通过清晰的MVC架构、优化的数据库设计和完整的业务功能实现,为中小型电商项目提供了可参考的技术方案。实体模型的设计体现了面向对象的设计原则,而各个功能模块的实现则展示了Servlet和JSP技术的实际应用场景。
虽然当前系统采用传统技术栈,但其架构设计为后续的技术升级奠定了良好基础。通过引入缓存、微服务、搜索引擎等现代技术组件,可以进一步提升系统的性能、可扩展性和用户体验。该项目的技术实现为同类电商平台的开发提供了有价值的参考,特别是在业务逻辑处理、数据持久化和用户交互方面的实践经验值得借鉴。