游戏商城管理平台是采用经典J2EE Model 1架构构建的数字化商品交易管理解决方案。该系统针对中小型游戏发行商和独立开发者的实际业务需求,通过集中化的Web管理界面实现了游戏商品、用户账户、销售订单和财务数据的统一管控,有效解决了传统手工管理方式效率低下、易出错的核心痛点。
系统架构与技术栈
平台采用分层架构设计,严格遵循J2EE规范。前端视图层使用JSP技术负责动态页面渲染,内嵌JSTL标签库简化逻辑判断与数据循环操作。后端控制层由Servlet担当,作为系统的核心调度器,负责接收HTTP请求、进行参数校验与业务逻辑分发。数据模型层通过封装了核心业务逻辑的JavaBean组件实现,与MySQL数据库进行交互。
技术栈配置如下:
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
</dependencies>
数据库连接采用JDBC标准接口,通过连接池技术优化资源利用。整个系统将显示、控制和数据处理清晰分离,为团队协作和后续功能扩展提供了良好的基础。
数据库设计亮点分析
商品表设计优化
商品表(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 0 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='商品表'
设计亮点包括:
- 字段长度优化:商品名称采用varchar(45)长度,平衡存储效率与业务需求
- 价格字段默认值:price字段设置默认值0,防止空值导致的业务异常
- 外键索引优化:为type_id字段建立索引,提升分类查询性能
- 文本字段长度规划:intro字段采用varchar(300)满足商品描述需求
订单项表的关系设计
订单项表(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=46 DEFAULT CHARSET=utf8 COMMENT='订单项表'
关键设计特点:
- 价格历史记录:独立存储下单时的商品价格,确保订单数据的完整性
- 双重外键约束:同时关联订单和商品表,维护数据一致性
- 复合索引策略:为两个外键字段分别建立索引,优化关联查询性能
推荐系统的灵活架构
推荐表(recommend)采用类型字段实现多场景推荐功能,展现了灵活的业务扩展能力:
CREATE TABLE `recommend` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '推荐ID',
`type` tinyint(1) DEFAULT NULL COMMENT '推荐类型',
`goods_id` int(11) DEFAULT NULL COMMENT '商品ID',
PRIMARY KEY (`id`),
KEY `fk_goods_id_idx` (`goods_id`),
CONSTRAINT `fk_goods_id` FOREIGN KEY (`goods_id`) REFERENCES `goods` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=39 DEFAULT CHARSET=utf8 COMMENT='推荐表'
创新设计包括:
- 级联删除:设置ON DELETE CASCADE,自动清理无效推荐记录
- 类型字段扩展性:tinyint类型支持多种推荐场景(热门、新品、特价等)
- 最小化数据冗余:通过外键关联避免重复存储商品信息

核心功能实现详解
用户身份验证与权限管理
系统采用双角色权限体系,通过isadmin字段区分管理员和普通用户。登录验证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();
User user = userService.login(username, password);
if (user != null) {
if (user.getIsvalidate()) {
HttpSession session = request.getSession();
session.setAttribute("user", user);
if (user.getIsadmin()) {
response.sendRedirect("admin/index.jsp");
} else {
response.sendRedirect("index.jsp");
}
} else {
request.setAttribute("msg", "账户未验证,请检查邮箱验证邮件");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
} else {
request.setAttribute("msg", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
权限拦截器确保安全访问:
public class AuthFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession(false);
String path = req.getRequestURI();
if (path.contains("/admin/")) {
if (session == null || session.getAttribute("user") == null) {
res.sendRedirect(req.getContextPath() + "/login.jsp");
return;
}
User user = (User) session.getAttribute("user");
if (!user.getIsadmin()) {
res.sendRedirect(req.getContextPath() + "/error/403.jsp");
return;
}
}
chain.doFilter(request, response);
}
}

商品管理功能实现
商品管理模块支持完整的CRUD操作,包含图片上传和库存管理功能:
@WebServlet("/admin/goods")
public class GoodsServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
GoodsService goodsService = new GoodsService();
switch (action) {
case "add":
addGoods(request, response, goodsService);
break;
case "edit":
editGoods(request, response, goodsService);
break;
case "delete":
deleteGoods(request, response, goodsService);
break;
}
}
private void addGoods(HttpServletRequest request, HttpServletResponse response,
GoodsService goodsService) throws ServletException, IOException {
// 文件上传处理
String uploadPath = getServletContext().getRealPath("/uploads");
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) uploadDir.mkdir();
Goods goods = new Goods();
goods.setName(request.getParameter("name"));
goods.setPrice(Float.parseFloat(request.getParameter("price")));
goods.setStock(Integer.parseInt(request.getParameter("stock")));
goods.setIntro(request.getParameter("intro"));
goods.setTypeId(Integer.parseInt(request.getParameter("type_id")));
// 处理多图片上传
Part coverPart = request.getPart("cover");
if (coverPart != null && coverPart.getSize() > 0) {
String coverFileName = generateFileName(coverPart);
coverPart.write(uploadPath + File.separator + coverFileName);
goods.setCover(coverFileName);
}
boolean success = goodsService.addGoods(goods);
if (success) {
response.sendRedirect("goods_manage.jsp?msg=添加成功");
} else {
request.setAttribute("error", "添加失败");
request.getRequestDispatcher("goods_add.jsp").forward(request, response);
}
}
}
商品列表分页查询实现:
public class GoodsService {
public PageBean<Goods> getGoodsByPage(int pageNo, int pageSize, String keyword, Integer typeId) {
PageBean<Goods> pageBean = new PageBean<>();
pageBean.setPageNo(pageNo);
pageBean.setPageSize(pageSize);
// 计算总记录数
int totalCount = goodsDao.getGoodsCount(keyword, typeId);
pageBean.setTotalCount(totalCount);
// 计算总页数
int totalPage = (totalCount + pageSize - 1) / pageSize;
pageBean.setTotalPage(totalPage);
// 获取当前页数据
int start = (pageNo - 1) * pageSize;
List<Goods> goodsList = goodsDao.getGoodsList(start, pageSize, keyword, typeId);
pageBean.setList(goodsList);
return pageBean;
}
}

购物车与订单处理
购物车功能采用Session存储,确保用户交互的流畅性:
public class CartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
HttpSession session = request.getSession();
Map<Integer, CartItem> cart = getCart(session);
switch (action) {
case "add":
addToCart(request, cart);
break;
case "update":
updateCart(request, cart);
break;
case "remove":
removeFromCart(request, cart);
break;
}
session.setAttribute("cart", cart);
response.sendRedirect("cart.jsp");
}
private void addToCart(HttpServletRequest request, Map<Integer, CartItem> cart) {
int goodsId = Integer.parseInt(request.getParameter("goods_id"));
int amount = Integer.parseInt(request.getParameter("amount"));
GoodsService goodsService = new GoodsService();
Goods goods = goodsService.getGoodsById(goodsId);
if (cart.containsKey(goodsId)) {
CartItem item = cart.get(goodsId);
item.setAmount(item.getAmount() + amount);
} else {
CartItem item = new CartItem(goods, amount);
cart.put(goodsId, item);
}
}
}
订单创建流程包含事务管理和库存验证:
public class OrderService {
public boolean createOrder(Order order, List<CartItem> cartItems) {
Connection conn = null;
try {
conn = DataBaseUtil.getConnection();
conn.setAutoCommit(false);
// 验证库存
for (CartItem item : cartItems) {
if (!checkStock(conn, item.getGoods().getId(), item.getAmount())) {
conn.rollback();
return false;
}
}
// 插入订单主表
OrderDao orderDao = new OrderDao(conn);
int orderId = orderDao.addOrder(order);
// 插入订单明细并更新库存
OrderItemDao orderItemDao = new OrderItemDao(conn);
GoodsDao goodsDao = new GoodsDao(conn);
for (CartItem item : cartItems) {
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(orderId);
orderItem.setGoodsId(item.getGoods().getId());
orderItem.setPrice(item.getGoods().getPrice());
orderItem.setAmount(item.getAmount());
orderItemDao.addOrderItem(orderItem);
goodsDao.updateStock(item.getGoods().getId(), -item.getAmount());
}
conn.commit();
return true;
} catch (SQLException e) {
if (conn != null) {
try { conn.rollback(); } catch (SQLException ex) {}
}
return false;
} finally {
DataBaseUtil.closeConnection(conn);
}
}
}
推荐系统实现
基于用户行为和商品属性的智能推荐算法:
public class RecommendService {
public List<Goods> getRecommendGoods(int userId, int type, int limit) {
List<Goods> recommendList = new ArrayList<>();
// 基于协同过滤的推荐
List<Goods> cfRecommend = getCFRecommend(userId, limit/2);
recommendList.addAll(cfRecommend);
// 基于内容的推荐
List<Goods> contentRecommend = getContentRecommend(userId, limit - cfRecommend.size());
recommendList.addAll(contentRecommend);
// 热门商品补全
if (recommendList.size() < limit) {
List<Goods> hotGoods = getHotGoods(limit - recommendList.size());
recommendList.addAll(hotGoods);
}
return recommendList;
}
private List<Goods> getCFRecommend(int userId, int limit) {
// 实现基于用户的协同过滤算法
String sql = """
SELECT g.* FROM goods g
INNER JOIN orderitem oi ON g.id = oi.goods_id
INNER JOIN order o ON oi.order_id = o.id
WHERE o.user_id IN (
SELECT DISTINCT o2.user_id FROM order o2
INNER JOIN orderitem oi2 ON o2.id = oi2.order_id
WHERE oi2.goods_id IN (
SELECT goods_id FROM orderitem oi3
INNER JOIN order o3 ON oi3.order_id = o3.id
WHERE o3.user_id = ?
) AND o2.user_id != ?
) AND g.id NOT IN (
SELECT goods_id FROM orderitem oi4
INNER JOIN order o4 ON oi4.order_id = o4.id
WHERE o4.user_id = ?
) GROUP BY g.id ORDER BY COUNT(*) DESC LIMIT ?
""";
return goodsDao.query(sql, userId, userId, userId, limit);
}
}
实体模型设计
系统采用面向对象的设计思想,核心实体模型体现了丰富的业务语义:
用户实体设计
public class User {
private Integer id;
private String username;
private String email;
private String password;
private String name;
private String phone;
private String address;
private Boolean isadmin;
private Boolean isvalidate;
// 构造方法、getter和setter
public User() {}
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
this.isadmin = false;
this.isvalidate = false;
}
// 业务方法
public boolean validatePassword(String inputPassword) {
return this.password.equals(MD5Util.md5(inputPassword));
}
public boolean canAccessAdmin() {
return Boolean.TRUE.equals(isadmin) && Boolean.TRUE.equals(isvalidate);
}
}
商品实体与值对象
public class Goods {
private Integer id;
private String name;
private String cover;
private String image1;
private String image2;
private Float price;
private String intro;
private Integer stock;
private Integer typeId;
private Type type; // 关联对象
// 业务逻辑方法
public boolean isAvailable() {
return stock != null && stock > 0;
}
public boolean isOnSale() {
return price != null && price > 0;
}
public String getMainImage() {
return cover != null ? cover : (image1 != null ? image1 : image2);
}
}
public class CartItem {
private Goods goods;
private Integer amount;
private Float itemTotal;
public CartItem(Goods goods, Integer amount) {
this.goods = goods;
this.amount = amount;
this.itemTotal = goods.getPrice() * amount;
}
// 更新数量时的业务逻辑
public void updateAmount(Integer newAmount) {
this.amount = newAmount;
this.itemTotal = goods.getPrice() * newAmount;
}
}
功能展望与优化方向
性能优化方案
- 引入Redis缓存层:对热门商品数据、用户会话、页面片段进行缓存
@Component
public class GoodsCacheService {
@Autowired
private RedisTemplate<String, Goods> redisTemplate;
public Goods getGoodsById(Integer id) {
String key = "goods:" + id;
Goods goods = redisTemplate.opsForValue().get(key);
if (