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

Java 實現拼音智能搜索與換膚:pinyin4j + 數據庫函數 + 前端聯想完整方案

     編輯:Java 相關知識

業務場景

仿 360 導航首頁:輸入框輸入中文/拼音首字母/全拼,實時下拉聯想匹配「資料、音樂、新聞、小說、日誌」五大分類;用戶可自定義背景皮膚並即時生效。

技術架構

  • 拼音轉換:pinyin4j (Java 庫) + MySQL 自定義函數 (首字母/全拼索引)
  • 前端聯想:jQuery + jQuery UI Autocomplete / 原生 AJAX + 下拉列表
  • 換膚機制:Session 存儲用戶皮膚選擇,頁面載入時動態注入 CSS 背景

核心 Java 工具類:ChinesePinYinTool (基於 pinyin4j)

public class ChinesePinYinTool {
    // 全拼數組:["hao", "de"] 
    public static String[] stringToPinyin(String src) { ... }
    // 首字母數組:["h", "d"]
    public static String[] getHeadByString(String src) { ... }
    // 全拼字符串:"haode"
    public static String hanziToPinyin(String hanzi) { ... }
}

Maven 依賴:<dependency><groupId>com.belerweb</groupId><artifactId>pinyin4j</artifactId><version>2.5.0</version></dependency>

MySQL 拼音索引函數 (核心性能優化)

-- 1. 首字母函數:返回單字首字母
CREATE FUNCTION `fristPinyin`(P_NAME VARCHAR(255)) RETURNS VARCHAR(255)
BEGIN
    DECLARE V_RETURN VARCHAR(255);
    SET V_RETURN = ELT(INTERVAL(CONV(HEX(LEFT(CONVERT(P_NAME USING gbk),1)),16,10),
        0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7,
        0xBFA6,0xC0AC,0xC2E8,0xC4C3,0xC5B6,0xC5BE,0xC6DA,0xC8BB,
        0xC8F6,0xCBFA,0xCDDA,0xCEF4,0xD1B9,0xD4D1),
        'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P','Q','R','S','T','W','X','Y','Z');
    RETURN V_RETURN;
END;

-- 2. 字符串首字母拼接:如 "好的" -> "hd"
CREATE FUNCTION `pinyin`(P_NAME VARCHAR(255)) RETURNS VARCHAR(255)
BEGIN
    DECLARE V_RETURN VARCHAR(255) DEFAULT '';
    DECLARE I INT DEFAULT 1;
    WHILE I <= LENGTH(P_NAME) DO
        SET V_RETURN = CONCAT(V_RETURN, fristPinyin(SUBSTR(P_NAME, I, 1)));
        SET I = I + 1;
    END WHILE;
    RETURN IFNULL(NULLIF(V_RETURN, ''), P_NAME);
END;

-- 3. 全拼拼接:如 "好的" -> "haode" (需建拼音映射表 t_base_pinyin)
CREATE FUNCTION `to_pinyin`(NAME VARCHAR(255) CHARSET gbk) RETURNS VARCHAR(255) CHARSET gbk
BEGIN
    -- 實現略:遍歷 GBK 雙字節,查表拼接拼音
    RETURN LOWER(mypy);
END;

數據表設計 (以音樂表為例)

CREATE TABLE t_song (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(200) NOT NULL,
    pinyin_head VARCHAR(200) GENERATED ALWAYS AS (pinyin(name)) VIRTUAL, -- 首字母索引
    pinyin_full VARCHAR(500) GENERATED ALWAYS AS (to_pinyin(name)) VIRTUAL, -- 全拼索引
    patent_id INT, -- 專輯外鍵
    INDEX idx_pinyin_head (pinyin_head),
    INDEX idx_pinyin_full (pinyin_full)
);

關鍵點:使用 GENERATED ALWAYS AS ... VIRTUAL 虛擬列,寫入時自動計算拼音,查詢時直接走索引,無需觸發器維護。

後端搜索接口 (Spring MVC)

@PostMapping("/search/suggest")
@ResponseBody
public String suggest(@RequestParam String keyword, @RequestParam String type) {
    // 1. Java 端轉拼音 (用於 LIKE 模糊匹配)
    String[] fullArr = ChinesePinYinTool.stringToPinyin(keyword);
    String fullPinyin = String.join("", fullArr);           // 全拼 "haode"
    String headPinyin = Arrays.stream(ChinesePinYinTool.getHeadByString(keyword))
                              .map(String::toLowerCase).collect(Collectors.joining()); // 首字母 "hd"

    // 2. 構建 HQL/SQL (以音樂為例)
    String hql = "FROM Song WHERE to_pinyin(name) LIKE :full OR pinyin(name) LIKE :head";
    List<Song> list = songDao.findByHql(hql, Map.of("full", "%" + fullPinyin + "%", "head", "%" + headPinyin + "%"), 0, 10);

    // 3. 組裝前端下拉 HTML
    StringBuilder sb = new StringBuilder();
    for (Song s : list) {
        sb.append("<li><a href='/music/detail/").append(s.getPatent().getId())
          .append("' target='_blank'>").append(s.getName()).append("</a></li>");
    }
    if (list.isEmpty()) sb.append("<li><a>無匹配結果</a></li>");
    sb.append("<li><a href='javascript:void(0)' onclick='hideSuggest()'>關閉</a></li>");
    return sb.toString();
}

前端聯想交互 (jQuery)

// 頁面輸入框綁定
$('#searchInput').on('keyup', function() {
    var kw = $(this).val().trim();
    var type = $('#searchForm').attr('name'); // 當前搜索類型
    if (!kw) { $('#suggestBox').empty().hide(); return; }

    $.post('/search/suggest', {keyword: kw, type: type}, function(html) {
        $('#suggestBox').html(html).show();
    });
});

// 點擊建議項填充輸入框並提交 (委託事件)
$('#suggestBox').on('click', 'a', function(e) {
    var text = $(this).text();
    if (text !== '無匹配結果' && text !== '關閉') {
        $('#searchInput').val(text);
        $('#searchForm').submit();
    }
    $('#suggestBox').hide();
    e.preventDefault();
});

換膚機制實現

// 1. 皮膚表
CREATE TABLE t_skin (id INT PK, name VARCHAR(50), photo VARCHAR(100)); -- photo 存背景圖文件名

// 2. 用戶表關聯皮膚
ALTER TABLE t_user ADD skin_id INT DEFAULT 1;

// 3. 切換皮膚接口
@PostMapping("/skin/change")
@ResponseBody
public void changeSkin(@RequestParam int skinId, HttpSession session) {
    Skin skin = skinDao.get(skinId);
    User user = (User) session.getAttribute("loginUser");
    user.setSkin(skin);
    userDao.update(user);
    session.setAttribute("loginUser", user); // 更新 Session
}

// 4. 頁面 head.jsp 動態注入背景
<c:if test="${loginUser.skin != null}">
<script>
$(function() {
    var bg = '/images/pf/${loginUser.skin.photo}';
    $('body').css('background', '#f6f6f6 url(' + bg + ') top repeat');
});
</script>
</c:if>

性能優化與避坑指南

問題解決方案
LIKE '%...%' 不走索引MySQL 8.0+ 支持函數索引;或用全文索引/Elasticsearch 替代
多音字處理pinyin4j 默認取第一個讀音;搜索時同時匹配首字母+全拼覆蓋大多數場景
前端請求過於頻繁輸入框防抖 200-300ms:_.debounce(doSearch, 300)
大數據量下聯想慢限制返回 10 條;必要時引入 Redis 緩存熱門搜索詞
換膚圖片 404部署時同步皮膚圖片到靜態資源服務器/CDN

總結

本方案融合 pinyin4j 本地轉換 + MySQL 虛擬列索引 + 前端防抖聯想 + Session 驅動換膚,實現了類 360 導航的智能搜索與個性化皮膚。核心亮點在於「寫時計算、讀時索引」的數據庫層拼音索引設計,兼顧了開發效率與查詢性能。

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