首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

SSH 電商項目實戰:首頁 UI 設計與數據預熱機制

     編輯:Java 相關知識

業務需求分析

電商首頁需展示:多個熱門分類,每分類下推薦商品 4 個。數據來源:數據庫分類表 + 商品表,要求首屏秒開,不查數據庫。

後台 Service 接口設計

public interface CategoryService extends BaseService {
    // 查詢熱門分類(hot=true)
    List queryHotCategories();
}

public interface ProductService extends BaseService {
    // 根據分類 ID 查詢推薦商品(commend=true, open=true),按時間倒序,限制 4 條
    List queryRecommendByCategoryId(Integer categoryId);
}

Service 實現

@Service("categoryService")
public class CategoryServiceImpl extends BaseServiceImpl implements CategoryService {
    @Override
    public List queryHotCategories() {
        return getSession().createQuery("FROM Category WHERE hot = true", Category.class).list();
    }
}

@Service("productService")
public class ProductServiceImpl extends BaseServiceImpl implements ProductService {
    @Override
    public List queryRecommendByCategoryId(Integer categoryId) {
        String hql = "FROM Product p JOIN FETCH p.category " +
                     "WHERE p.commend = true AND p.open = true AND p.category.id = :cid " +
                     "ORDER BY p.date DESC";
        return getSession().createQuery(hql, Product.class)
                .setParameter("cid", categoryId)
                .setMaxResults(4)
                .list();
    }
}

ServletContextListener 實現首頁數據預熱

@WebListener
public class HomeDataInitListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext application = sce.getServletContext();
        // 從 Spring 容器獲取 Bean(Listener 非 Spring 管理)
        WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(application);
        
        CategoryService categoryService = ctx.getBean(CategoryService.class);
        ProductService productService = ctx.getBean(ProductService.class);
        
        // 1. 查詢熱門分類
        List hotCategories = categoryService.queryHotCategories();
        
        // 2. 為每個分類查推薦商品,構建二維列表
        List> categoryProducts = new ArrayList<>();
        for (Category cat : hotCategories) {
            List products = productService.queryRecommendByCategoryId(cat.getId());
            categoryProducts.add(products);
        }
        
        // 3. 存入 Application 域,前台 EL 表達式直接讀取
        application.setAttribute("categoryProducts", categoryProducts);
        application.setAttribute("hotCategories", hotCategories);
        
        System.out.println("首頁數據預熱完成,分類數: " + hotCategories.size());
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // 清理工作
    }
}

定時任務實現數據定期同步

@Component
public class HomeDataSyncScheduler {

    private static final Logger log = LoggerFactory.getLogger(HomeDataSyncScheduler.class);
    
    @Autowired CategoryService categoryService;
    @Autowired ProductService productService;
    @Autowired ServletContext application;

    // 每 6 小時執行一次,啟動後立即執行一次
    @Scheduled(fixedRate = 6 * 60 * 60 * 1000, initialDelay = 0)
    public void refreshHomeData() {
        log.info("開始同步首頁數據...");
        try {
            List hotCategories = categoryService.queryHotCategories();
            List> categoryProducts = new ArrayList<>();
            for (Category cat : hotCategories) {
                categoryProducts.add(productService.queryRecommendByCategoryId(cat.getId()));
            }
            // 原子性替換,讀取端無感知
            application.setAttribute("categoryProducts", categoryProducts);
            application.setAttribute("hotCategories", hotCategories);
            log.info("首頁數據同步完成");
        } catch (Exception e) {
            log.error("首頁數據同步失敗", e);
        }
    }
}

前台 JSP 渲染 (EasyUI / JSTL)

<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>
<div class="home-floor">
    <c:forEach items="${applicationScope.hotCategories}" var="cat" varStatus="vs">
        <div class="floor-header">
            <h3>${cat.name}</h3>
            <a href="/category/${cat.id}">更多></a>
        </div>
        <div class="floor-products">
            <c:forEach items="${applicationScope.categoryProducts[vs.index]}" var="product">
                <div class="product-card">
                    <img src="${product.imageUrl}" alt="${product.name}"/>
                    <p class="name">${product.name}</p>
                    <p class="price">¥${product.price}</p>
                    <a href="/product/${product.id}" class="btn-buy">購買</a>
                </div>
            </c:forEach>
        </div>
    </c:forEach>
</div>

Hibernate 二級緩存加速熱點數據

<!-- hibernate.cfg.xml / Spring 配置 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

<!-- 實體類註解 -->
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Cacheable
public class Product { ... }

<!-- 查詢緩存 -->
query.setCacheable(true);
query.setCacheRegion("product.recommend");

關鍵設計決策總結

決策點方案理由
數據存儲位置ServletContext (Application 域)全局共享、生命周期匹配、無需序列化
同步策略Listener 初始化 + Scheduled 定時刷新啟動即可用、定期修正、實現簡單
數據結構List<List<Product>> 對應分類順序前台直接索引遍歷,無需 Map 查找
緩存層級二級緩存 + Application 域雙層數據庫層面攔截重複查詢,內存層面極速讀取

遷移到 Spring Boot 的等效實現

@Configuration
public class HomeCacheConfig {
    @Bean
    public CacheManager cacheManager() {
        return new EhCacheCacheManager(ehCacheCacheManager().getObject());
    }
}

@Service
public class HomeDataService {
    @Autowired CategoryRepository categoryRepo;
    @Autowired ProductRepository productRepo;
    @Autowired CacheManager cacheManager;

    @PostConstruct
    @Scheduled(fixedRate = 6 * 3600 * 1000)
    public void refresh() {
        Cache cache = cacheManager.getCache("homeData");
        List cats = categoryRepo.findByHotTrue();
        Map> map = new LinkedHashMap<>();
        for (Category c : cats) {
            map.put(c.getId(), productRepo.findTop4ByCategoryIdAndCommendTrueAndOpenTrueOrderByDateDesc(c.getId()));
        }
        cache.put("categories", cats);
        cache.put("products", map);
    }
    
    public List getCategories() {
        return cacheManager.getCache("homeData").get("categories", List.class);
    }
}

這套「預熱 + 定時同步 + 多級緩存」方案,是高並發電商首頁架構的標準範式,無論 SSH 還是 Spring Boot/Cloud 皆適用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved