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

Java URL 中文編碼與解碼完整實現指南

     編輯:Java 程式設計入門

背景與需求

在 Web 開發中,URL 傳遞中文參數時需進行編碼(如 %E4%BD%A0),接收端再解碼還原。雖然 JDK 提供 URLEncoder/URLDecoder,但某些場景(舊系統兼容、特定編碼規則)仍需手動實現。本文提供基於 UTF-8 的完整編解碼工具類。

核心實現:URLtoUTF8 工具類

package com.gjob.common;

public class URLtoUTF8 {

    /** 將字符串轉為 %XX 格式(UTF-8 編碼) */
    public static String toUtf8String(String s) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            // ASCII 字符直接保留
            if (c >= 0 && c <= 255) {
                sb.append(c);
            } else {
                try {
                    byte[] b = String.valueOf(c).getBytes("UTF-8");
                    for (byte byteVal : b) {
                        int k = byteVal < 0 ? byteVal + 256 : byteVal;
                        sb.append("%").append(Integer.toHexString(k).toUpperCase());
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    /** 將 %XX 格式解碼為原始字符串(支持 UTF-8 多字節) */
    public static String unescape(String s) {
        StringBuffer sbuf = new StringBuffer();
        int l = s.length();
        int ch = -1;
        int b, sumb = 0;
        int more = -1;

        for (int i = 0; i < l; i++) {
            // 1. 獲取下一個字節 b
            switch (ch = s.charAt(i)) {
                case '%':
                    int hb = Character.digit(s.charAt(++i), 16);
                    int lb = Character.digit(s.charAt(++i), 16);
                    b = (hb << 4) | lb;
                    break;
                case '+':
                    b = ' ';
                    break;
                default:
                    b = ch;
            }

            // 2. UTF-8 解碼邏輯(狀態機)
            if ((b & 0xC0) == 0x80) {                // 10xxxxxx 續位
                sumb = (sumb << 6) | (b & 0x3F);
                if (--more == 0) sbuf.append((char) sumb);
            } else if ((b & 0x80) == 0x00) {         // 0xxxxxxx 單字節
                sbuf.append((char) b);
            } else if ((b & 0xE0) == 0xC0) {         // 110xxxxx 雙字節首位
                sumb = b & 0x1F; more = 1;
            } else if ((b & 0xF0) == 0xE0) {         // 1110xxxx 三字節首位
                sumb = b & 0x0F; more = 2;
            } else if ((b & 0xF8) == 0xF0) {         // 11110xxx 四字節首位
                sumb = b & 0x07; more = 3;
            } else if ((b & 0xFC) == 0xF8) {         // 111110xx 五字節首位
                sumb = b & 0x03; more = 4;
            } else {                                  // 1111110x 六字節首位
                sumb = b & 0x01; more = 5;
            }
        }
        return sbuf.toString();
    }

    public static void main(String[] args) {
        System.out.println(toUtf8String("你"));           // %E4%BD%A0
        System.out.println(unescape("%E4%BD%A0%20%E5%A5%BD")); // 你 好
    }
}

關鍵技術點解析

編碼邏輯

  • ASCII 字符(0-255)直接輸出,無需編碼。
  • 非 ASCII 字符調用 getBytes("UTF-8") 獲取字節數組,每字節轉為無符號整數後格式化為 %XX 大寫十六進制。

解碼邏輯(UTF-8 狀態機)

逐字符掃描,遇到 % 解析兩位十六進制得到字節 b,再根據 UTF-8 編碼規則判斷字節類型:

字節模式含義處理
0xxxxxxxASCII 單字節直接輸出字符
110xxxxx雙字節首位記錄 5 位,期待 1 個續位
1110xxxx三字節首位記錄 4 位,期待 2 個續位
11110xxx四字節首位記錄 3 位,期待 3 個續位
10xxxxxx續位累加 6 位,滿足期待數則組合輸出字符

此實現兼容 1-6 字節 UTF-8 序列,覆蓋所有 Unicode 字符平面。

標準庫替代方案

現代項目優先推薦使用 JDK 內建 API,自動處理邊界情況:

// 編碼
String encoded = URLEncoder.encode("你 好", StandardCharsets.UTF_8.toString());
// 解碼
String decoded = URLDecoder.decode("%E4%BD%A0%20%E5%A5%BD", StandardCharsets.UTF_8.toString());

注意:URLEncoder 會將空格編碼為 +,而手動實現中 + 也被視為空格,兩者行為一致。

常見坑點與測試驗證

  • 編碼不一致:客戶端用 UTF-8,服務端用 GBK 解碼會導致亂碼,雙端必須協商統一字符集。
  • 雙重編碼:已編碼字符串再次編碼會產生 %25XX,解碼時需確認是否為多層編碼。
  • 特殊字符:+、%、#、& 等在 URL 中有特殊含義,需按規範編碼。
// 單元測試片段
assertEquals("%E4%BD%A0", URLtoUTF8.toUtf8String("你"));
assertEquals("你 好", URLtoUTF8.unescape("%E4%BD%A0%20%E5%A5%BD"));
assertEquals("特殊字符+&#", URLtoUTF8.unescape(URLtoUTF8.toUtf8String("特殊字符+&#")));
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved