解決文字和表情存儲到msql數據庫出現異常問題

異常:java

Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\xA4\x97 \xF0...' for column 'name' at row 1
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3878)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2478)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2625)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2551)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
    at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1192)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:45)
    at com.sun.proxy.$Proxy21.execute(Unknown Source)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:23)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:51)
    at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:29)
    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:74)
    at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:43)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:44)
    at com.sun.proxy.$Proxy20.update(Unknown Source)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:118)
    ... 61 moremysql

異常緣由:sql

數據庫通常設置的編碼格式是utf-8格式,而utf-8只包含3個字節編碼,然而如今出現了4個字節編碼格式,致使程序識別失敗。數據庫

兩種解決方法apache

1)把數據庫編碼格式設置成utf8mb4格式,其對應數據表也設置成其utf8mb4編碼格式數組

2)直接過濾掉其多餘的編碼格式字節。使用其過濾工具類進行過濾,從而達到目的session

public class UTF8Utils {

    public static Map<String, Integer> hexMap = new HashMap<String, Integer>();
    public static Map<String, Integer> byteMap = new HashMap<String, Integer>();

    static {
        hexMap.put("0", 2);
        hexMap.put("1", 2);
        hexMap.put("2", 2);
        hexMap.put("3", 2);
        hexMap.put("4", 2);
        hexMap.put("5", 2);
        hexMap.put("6", 2);
        hexMap.put("7", 2);
        hexMap.put("c", 4);
        hexMap.put("d", 4);
        hexMap.put("e", 6);
        hexMap.put("f", 8);

        byteMap.put("0", 1);
        byteMap.put("1", 1);
        byteMap.put("2", 1);
        byteMap.put("3", 1);
        byteMap.put("4", 1);
        byteMap.put("5", 1);
        byteMap.put("6", 1);
        byteMap.put("7", 1);
        byteMap.put("c", 2);
        byteMap.put("d", 2);
        byteMap.put("e", 3);
        byteMap.put("f", 4);
    }

    /**
     * 是否包含4字節UTF-8編碼的字符(先轉換16進制再判斷)
     * @param s 字符串
     * @return 是否包含4字節UTF-8編碼的字符
     */
    public static boolean contains4BytesChar(String s) {
        if (s == null || s.trim().length() == 0) {
            return false;
        }

        String hex = UTF8Utils.bytesToHex(s.getBytes());
//        System.out.println("full hex : " + hex);

        String firstChar = null;
        while (hex != null && hex.length() > 1) {
            firstChar = hex.substring(0, 1);
//            System.out.println("firstChar : " + firstChar);

            if ("f".equals(firstChar)) {
//                System.out.println("it is f start, it is 4 bytes, return.");
                return true;
            }

            if (hexMap.get(firstChar) == null) {
//                System.out.println("it is f start, it is 4 bytes, return.");
                // todo, throw exception for this case
                return false;
            }

            hex = hex.substring(hexMap.get(firstChar), hex.length());
//            System.out.println("remain hex : " + hex);
        }

        return false;
    }

    /**
     * 是否包含4字節UTF-8編碼的字符
     * @param s 字符串
     * @return 是否包含4字節UTF-8編碼的字符
     */
    public static boolean contains4BytesChar2(String s) {
        if (s == null || s.trim().length() == 0) {
            return false;
        }

        byte[] bytes = s.getBytes();

        if (bytes == null || bytes.length == 0) {
            return false;
        }

        int index = 0;
        byte b;
        String hex = null;
        String firstChar = null;
        int step;
        while (index <= bytes.length - 1) {
//            System.out.println("while loop, index : " + index);
            b = bytes[index];

            hex = byteToHex(b);
            if (hex == null || hex.length() < 2) {
//                System.out.println("fail to check whether contains 4 bytes char(1 byte hex char too short), default return false.");
                // todo, throw exception for this case
                return false;
            }

            firstChar = hex.substring(0, 1);

            if (firstChar.equals("f")) {
                return true;
            }

            if (byteMap.get(firstChar) == null) {
//                System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false.");
                // todo, throw exception for this case
                return false;
            }

            step = byteMap.get(firstChar);
//            System.out.println("while loop, index : " + index + ", step : " + step);
            index = index + step;
        }

        return false;
    }

    /**
     * 去除4字節UTF-8編碼的字符
     * @param s 字符串
     * @return 已去除4字節UTF-8編碼的字符
     */
    public static byte[] remove4BytesUTF8Char(String s) {
        byte[] bytes = s.getBytes();
        byte[] removedBytes = new byte[bytes.length];
        int index = 0;

        String hex = null;
        String firstChar = null;
        for (int i = 0; i < bytes.length; ) {
            hex = UTF8Utils.byteToHex(bytes[i]);

            if (hex == null || hex.length() < 2) {
//                System.out.println("fail to check whether contains 4 bytes char(1 byte hex char too short), default return false.");
                // todo, throw exception for this case
                return null;
            }

            firstChar = hex.substring(0, 1);

            if (byteMap.get(firstChar) == null) {
//                System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false.");
                // todo, throw exception for this case
                return null;
            }

            if (firstChar.equals("f")) {
                for (int j = 0; j < byteMap.get(firstChar); j++) {
                    i++;
                }
                continue;
            }

            for (int j = 0; j < byteMap.get(firstChar); j++) {
                removedBytes[index++] = bytes[i++];
            }
        }

        return Arrays.copyOfRange(removedBytes, 0, index);
    }

    /**
     * 將字符串的16進制轉換爲HEX,並按每一個字符的16進制分隔格式化
     * @param s 字符串
     */
    public static String splitForReading(String s) {
        if (s == null || s.trim().length() == 0) {
            return "";
        }

        String hex = UTF8Utils.bytesToHex(s.getBytes());
//        System.out.println("full hex : " + hex);

        if (hex == null || hex.length() == 0) {
//            System.out.println("fail to translate the bytes to hex.");
            // todo, throw exception for this case
            return "";
        }

        StringBuilder sb = new StringBuilder();
        int index = 0;

        String firstChar = null;
        String splittedString = null;
        while (index < hex.length()) {
            firstChar = hex.substring(index, index + 1);

            if (hexMap.get(firstChar) == null) {
//                System.out.println("fail to check whether contains 4 bytes char(no firstchar mapping), default return false.");
                // todo, throw exception for this case
                return "";
            }

            splittedString = hex.substring(index, index + hexMap.get(firstChar));
            sb.append(splittedString).append(" ");
            index = index + hexMap.get(firstChar);
        }

//        System.out.println("formated sb : " + sb);
        return sb.toString();
    }

    /**
     * 字節數組轉十六進制
     * @param bytes 字節數組
     * @return 十六進制
     */
    public static String bytesToHex(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            int r = bytes[i] & 0xFF;

            String hexResult = Integer.toHexString(r);
            if (hexResult.length() < 2) {
                sb.append(0); // 前補0
            }
            sb.append(hexResult);
        }

        return sb.toString();
    }

    /**
     * 字節轉十六進制
     * @param b 字節
     * @return 十六進制
     */
    public static String byteToHex(byte b) {
        int r = b & 0xFF;//得到低8位
        String hexResult = Integer.toHexString(r);

        StringBuilder sb = new StringBuilder();
        if (hexResult.length() < 2) {
            sb.append(0); // 前補0
        }
        sb.append(hexResult);
        return sb.toString();
    }
}
相關文章
相關標籤/搜索