---
# System prepended metadata

title: '**首頁介紹**'
tags: [java]

---

{%hackmd @themes/orangeheart %}

# **首頁介紹**

![](https://i.imgur.com/iXayJRx.jpg)
### <font color="3E54AC"> **使用到的技術**
:computer:	ES(ElasticSearch)
:computer:	Redis
:computer:	Quartz
:computer:	緩存預熱</font>

首頁主要分成5大區塊
1. 網頁菜單區
2. 關鍵字搜索區
3. 新品推薦區
4. 熱門商品區
5. 優惠商品區

## 網頁菜單區
網頁菜單區塊，可以連接到網站中各個主要功能
 <pre><code>
首頁菜單
├── 首頁 -- 訪問首頁
├── 商品介紹 -- 訪問所有商品頁面
├── 購物車 -- 訪問當前用戶的購物清單
├── 顧客中心 -- 顧客資料修改、訂單詳情
└── 會員登入 -- 登入功能
 </code></pre>

:exclamation:當會員登入以後Menu會從【會員登入】轉換成【會員登出】
![](https://i.imgur.com/dNn3c6f.png)

## 關鍵字搜索區
這個區塊分成二個部分
* 搜索框
    針對用戶輸入的關鍵字透過 ==ES(ElasticSearch)== 分詞器將關鍵字進行分析然後再使用ES進行模糊查詢
* 熱門搜尋
    針對用戶輸入的關鍵字進行計數，將搜尋前10名的關鍵字展示在這裡，用戶可以直接點擊進行搜尋
    
>如果每一次使用搜尋功能就更改一次資料庫，會造成伺服的壓力無謂消耗效能，所以將計數的功能交由==Redis==來操作。

```mermaid
graph LR
    關鍵字輸入 --> 在Redis中計數
    在Redis中計數 --> 使用ES進行模糊查詢
    使用ES進行模糊查詢 --> 響應結果
 ```   
 進行計數的相關程式碼

``` java
    /**
     * 對關鍵字進行判斷
     * 如果存在則計數+1，如果不存在則新增關鍵字
     * @param keywordName 前端發送的關鍵字
     */
    public void initKeyword(String keywordName){
        log.debug("開始對關鍵字進行分析");
        //從redis工具包獲取關鍵字key 
        String key = RedisUtils.KEY_PREFIX_KEYWORD + keywordName;
        //increment() 如果 key值不存在，會創建一個並賦值1
        //如果key存在則，值+1
        stringRedisTemplate.boundValueOps(key).increment();
    }
```
>由於資料只存在於Redis中，我們必須再從Redis中寫入資料庫

``` java
    /**
     * 將redis中的資料寫入mysql
     */
    @Override
    public void updateDatabaseFromRedis() {
        //獲取前綴
        String key = RedisUtils.KEY_PREFIX_KEYWORD;
        //獲取該前綴下的所有key
        Set<String> keys = redisTemplate.keys(key.concat("*"));
        //創建要寫入資料庫的對象
        Keyword keyword = new Keyword();
        //遍歷key值
        for (String keyString : keys) {
            //取出後綴
            String keywordName = keyString.substring(keyString.lastIndexOf(":")+1);
            if (!"list".equals(keywordName)){
                //獲取計數值
                String countString = stringRedisTemplate.boundValueOps(keyString).get();
                //將計數值轉成Integer
                int count = Integer.parseInt(countString);
                keyword.setKeywordName(keywordName);
                keyword.setCount(count);
                //判斷該關鍵字是否存在database中
                int countByKeywordName = keywordMapper.countByKeywordName(keywordName);
                if(countByKeywordName !=0){
                    //已存在則更新
                    keywordMapper.updateCount(keyword);
                }else{
                    //不存在則新增
                    keywordMapper.insert(keyword);
                }
                //刪除redis中的資料
                deleteItem(keywordName);
            }
        }
    }
```
>最後使用==Quartz==進行排程，讓系統自動更新資料庫中的資料
```java
    @Override
    public void execute(JobExecutionContext jobExecutionContext)
            throws JobExecutionException {
        log.debug("開始更新redis中的資料");
        //從redis中獲取關鍵字資料，並更新到資料庫
        keywordRepository.updateDatabaseFromRedis();
        //更新ES
        searchService.loadProducts();
    }
```

## 新品推薦區、熱門商品區、優惠商品區
>這三個區塊的資料會根據商品新增的時候所設定的==推播種類==從資料庫中抓取資料並響應，這些資料是固定且使用頻率高，所以也將資料載入Redis降低資料庫的讀取壓力。

:point_right:透過實現ApplicationRunner來進行==緩存預熱==
```java!
@Override
    public void run(ApplicationArguments args) throws Exception {
        log.debug("開始預熱redis");
        //加載品牌資料
        brandRepository.putList();
        //加載商品資料
        //TODO 之後更新與資料庫對應有多少種商品類別，目前寫死
        for (int i = 2; i <=4 ; i++) {
            productRepository.putList(i);
        }
        //加載推播種類
        productRepository.putProductTypeList();
        //加載關鍵字
        keywordRepository.putList();
    }
```

###### tags: `java`