在传统零售行业数字化转型的浪潮中,食品零售领域面临着商品信息更新滞后、订单处理效率低下等痛点。针对这一市场需求,我们设计并实现了一套专业的甜品零食电商平台,采用经典的J2EE架构,为中小型食品零售商提供完整的线上业务解决方案。
系统架构与技术栈
该平台基于Model 2设计模式构建,前端使用JSP进行动态页面渲染,结合HTML、CSS和JavaScript实现丰富的用户交互体验。后端核心采用Servlet作为控制器,负责业务逻辑处理和请求路由。数据持久层使用纯JDBC技术,通过DAO模式封装数据库操作,确保代码结构的清晰性和可维护性。
技术栈配置如下:
- 服务器:Apache Tomcat 9.0
- 数据库:MySQL 8.0
- 前端技术:JSP 2.3、HTML5、CSS3、JavaScript
- 后端技术:Servlet 4.0、JDBC
- 开发环境:Java SE 11
<!-- web.xml配置示例 -->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
version="3.1">
<servlet>
<servlet-name>GoodsServlet</servlet-name>
<servlet-class>com.snackshop.servlet.GoodsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GoodsServlet</servlet-name>
<url-pattern>/goods/*</url-pattern>
</servlet-mapping>
</web-app>
数据库设计亮点分析
商品表设计优化
商品表(goods)的设计充分考虑了电商平台的业务特性:
CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '商品ID',
`name` varchar(45) DEFAULT NULL COMMENT '商品名称',
`cover` varchar(45) DEFAULT NULL COMMENT '商品封面图',
`image1` varchar(45) DEFAULT NULL COMMENT '商品图片1',
`image2` varchar(45) DEFAULT NULL COMMENT '商品图片2',
`price` float DEFAULT NULL COMMENT '商品价格',
`intro` varchar(300) DEFAULT NULL COMMENT '商品介绍',
`stock` int(11) DEFAULT NULL COMMENT '商品库存',
`type_id` int(11) DEFAULT NULL COMMENT '商品类型ID',
PRIMARY KEY (`id`),
KEY `fk_type_id_idx` (`type_id`),
CONSTRAINT `fk_type_id` FOREIGN KEY (`type_id`) REFERENCES `type` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=188 DEFAULT CHARSET=utf8 COMMENT='商品表'
设计亮点分析:
- 多图片存储设计:采用cover、image1、image2三个字段分别存储商品封面图和详情图片,支持多图展示需求
- 文本长度优化:商品介绍intro字段设置为300字符,平衡了存储空间与内容展示需求
- 索引策略:对type_id建立外键索引,优化按分类查询的性能
- 库存监控:stock字段实时跟踪商品库存,为库存预警提供数据基础
订单项表关系设计
订单项表(orderitem)的设计体现了电商系统核心的订单管理逻辑:
CREATE TABLE `orderitem` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单项ID',
`price` float DEFAULT NULL COMMENT '商品单价',
`amount` int(11) DEFAULT NULL COMMENT '商品数量',
`goods_id` int(11) DEFAULT NULL COMMENT '商品ID',
`order_id` int(11) DEFAULT NULL COMMENT '订单ID',
PRIMARY KEY (`id`),
KEY `fk_order_id_idx` (`order_id`),
KEY `fk_orderitem_goods_id_idx` (`goods_id`),
CONSTRAINT `fk_order_id` FOREIGN KEY (`order_id`) REFERENCES `order` (`id`),
CONSTRAINT `fk_orderitem_goods_id` FOREIGN KEY (`goods_id`) REFERENCES `goods` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=56 DEFAULT CHARSET=utf8 COMMENT='订单项表'
关系设计优势:
- 价格快照:独立存储下单时的商品价格,避免后续价格变动影响历史订单
- 双重外键约束:确保订单项与商品、订单的完整性和一致性
- 复合索引优化:通过goods_id和order_id的索引优化查询性能
核心功能实现详解
用户认证与权限管理
系统采用基于角色的访问控制(RBAC)模型,用户表通过isadmin字段区分管理员和普通用户:
public class UserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
UserDAO userDAO = new UserDAO();
User user = userDAO.login(username, password);
if (user != null) {
HttpSession session = request.getSession();
session.setAttribute("user", user);
if (user.isAdmin()) {
response.sendRedirect("admin/index.jsp");
} else {
response.sendRedirect("index.jsp");
}
} else {
request.setAttribute("error", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}

商品展示与购物车功能
商品展示模块支持按分类浏览、关键词搜索等功能,购物车采用Session临时存储:
public class CartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int goodsId = Integer.parseInt(request.getParameter("goodsId"));
int quantity = Integer.parseInt(request.getParameter("quantity"));
HttpSession session = request.getSession();
Map<Integer, CartItem> cart = (Map<Integer, CartItem>) session.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
session.setAttribute("cart", cart);
}
GoodsDAO goodsDAO = new GoodsDAO();
Goods goods = goodsDAO.findById(goodsId);
if (cart.containsKey(goodsId)) {
CartItem item = cart.get(goodsId);
item.setQuantity(item.getQuantity() + quantity);
} else {
CartItem newItem = new CartItem(goods, quantity);
cart.put(goodsId, newItem);
}
response.sendRedirect("cart.jsp");
}
}

订单处理流程
订单处理包含下单、支付、发货等完整流程,采用事务保证数据一致性:
public class OrderService {
public boolean createOrder(Order order, List<CartItem> cartItems) {
Connection conn = null;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
OrderDAO orderDAO = new OrderDAO(conn);
OrderItemDAO orderItemDAO = new OrderItemDAO(conn);
GoodsDAO goodsDAO = new GoodsDAO(conn);
// 插入订单主记录
int orderId = orderDAO.insert(order);
order.setId(orderId);
// 插入订单项并更新库存
for (CartItem item : cartItems) {
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(orderId);
orderItem.setGoodsId(item.getGoods().getId());
orderItem.setPrice(item.getGoods().getPrice());
orderItem.setAmount(item.getQuantity());
orderItemDAO.insert(orderItem);
// 更新商品库存
goodsDAO.updateStock(item.getGoods().getId(),
-item.getQuantity());
}
conn.commit();
return true;
} catch (SQLException e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
return false;
} finally {
DBUtil.closeConnection(conn);
}
}
}

后台商品管理
管理员可以对商品进行全面的CRUD操作,支持图片上传和库存管理:
public class GoodsManageServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
GoodsDAO goodsDAO = new GoodsDAO();
if ("add".equals(action)) {
Goods goods = new Goods();
goods.setName(request.getParameter("name"));
goods.setPrice(Float.parseFloat(request.getParameter("price")));
goods.setStock(Integer.parseInt(request.getParameter("stock")));
goods.setTypeId(Integer.parseInt(request.getParameter("typeId")));
goods.setIntro(request.getParameter("intro"));
// 处理图片上传
Part coverPart = request.getPart("cover");
if (coverPart != null && coverPart.getSize() > 0) {
String coverFileName = saveUploadedFile(coverPart);
goods.setCover(coverFileName);
}
goodsDAO.insert(goods);
response.sendRedirect("goods_list.jsp?msg=add_success");
}
}
private String saveUploadedFile(Part part) throws IOException {
String fileName = System.currentTimeMillis() + "_" +
getFileName(part);
String filePath = getServletContext().getRealPath("/uploads") +
File.separator + fileName;
try (InputStream input = part.getInputStream();
FileOutputStream output = new FileOutputStream(filePath)) {
IOUtils.copy(input, output);
}
return fileName;
}
}

实体模型设计
系统采用面向对象的设计思想,核心实体模型如下:
public class Goods {
private int id;
private String name;
private String cover;
private String image1;
private String image2;
private float price;
private String intro;
private int stock;
private int typeId;
private Type type;
// 构造函数、getter和setter方法
public Goods() {}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// 其他getter/setter方法...
}
public class Order {
private int id;
private float total;
private int amount;
private int status;
private int paytype;
private String name;
private String phone;
private String address;
private Date datetime;
private int userId;
private List<OrderItem> itemList;
// 业务方法
public void calculateTotal() {
this.total = 0;
this.amount = 0;
if (itemList != null) {
for (OrderItem item : itemList) {
this.total += item.getPrice() * item.getAmount();
this.amount += item.getAmount();
}
}
}
}
功能展望与优化方向
1. 引入Redis缓存层
当前系统每次商品查询都直接访问数据库,在高并发场景下存在性能瓶颈。建议引入Redis作为缓存层:
public class GoodsServiceWithCache {
private Jedis jedis = new Jedis("localhost");
private GoodsDAO goodsDAO = new GoodsDAO();
public Goods findById(int id) {
String key = "goods:" + id;
String cached = jedis.get(key);
if (cached != null) {
return JSON.parseObject(cached, Goods.class);
} else {
Goods goods = goodsDAO.findById(id);
if (goods != null) {
jedis.setex(key, 3600, JSON.toJSONString(goods));
}
return goods;
}
}
}
2. 微服务架构改造
将单体应用拆分为商品服务、订单服务、用户服务等微服务,提高系统可扩展性:
// 商品服务接口定义
@RestController
@RequestMapping("/api/goods")
public class GoodsController {
@Autowired
private GoodsService goodsService;
@GetMapping("/{id}")
public ResponseEntity<Goods> getGoods(@PathVariable int id) {
Goods goods = goodsService.findById(id);
return ResponseEntity.ok(goods);
}
@PostMapping("/")
public ResponseEntity<Goods> createGoods(@RequestBody Goods goods) {
Goods created = goodsService.create(goods);
return ResponseEntity.status(201).body(created);
}
}
3. 增加弹性搜索支持
实现更强大的商品搜索功能,支持全文检索、拼音搜索、同义词匹配等:
public class GoodsSearchService {
public List<Goods> search(String keyword, int page, int size) {
SearchRequest searchRequest = new SearchRequest("goods");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.multiMatchQuery(keyword,
"name", "intro", "type.name"));
sourceBuilder.from((page - 1) * size);
sourceBuilder.size(size);
searchRequest.source(sourceBuilder);
// 执行搜索并返回结果
return executeSearch(searchRequest);
}
}
4. 消息队列异步处理
订单创建、库存扣减等操作可以通过消息队列实现异步处理,提高系统响应速度:
@Component
public class OrderMessageListener {
@JmsListener(destination = "order.queue")
public void processOrder(OrderMessage message) {
// 异步处理订单库存扣减
inventoryService.deductStock(message.getGoodsList());
// 发送订单确认邮件
emailService.sendOrderConfirmation(message.getUserId(), message.getOrderId());
}
}
5. 移动端适配与PWA支持
开发响应式界面,支持PWA(渐进式Web应用)特性,提供接近原生应用的体验:
// 注册Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW registered: ', registration);
})
.catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
}
总结
该甜品零食电商平台基于成熟的J2EE技术栈,实现了完整的电子商务功能。系统采用分层架构设计,数据库设计合理,具备良好的扩展性和维护性。通过深入分析核心功能实现代码,展示了如何利用Servlet和JSP技术构建稳健的Web应用。
未来通过引入缓存、微服务、搜索引擎等现代化技术,可以进一步提升系统性能和用户体验。该平台为传统食品零售商向数字化转型提供了可靠的技术基础,具有良好的市场应用前景。