编码与解码及乱码解决方案

编码与解码及乱码解决方案

编码与解码.png

码表:

码表 解释
ASCII 美国标准信息交换码。用一个字节的7位可以表示。 -128~127 256
ISO8859-1 拉丁码表。欧洲码表,用一个字节的8位表示。又称Latin-1(拉丁编码)或“西欧语言”。ASCII码是包含的仅仅是英文字母,并且没有完全占满256个编码位置,所以它以ASCII为基础,在空置的0xA0-0xFF的范围内,加入192个字母及符号,藉以供使用变音符号的拉丁字母语言使用。从而支持德文,法文等。因而它依然是一个单字节编码,只是比ASCII更全面。
GB2312 中国的中文编码表。 英文占一个字节, 中文占两个字节。
GBK 中国的中文编码表升级,融合了更多的中文文字符号。
Unicode 国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。
UTF-8 英文占一个字节,中文占三个字节。 最多用三个字节来表示一个字符。
UTF-16 英文中文都是占两个字节。

注意:Unicode不是一个码表,只是一个规范。

一、编码

编码: 把看得懂的字符变成看不懂码值这个过程我们称作为编码。

字符串--->字节数组
String类的getBytes() 方法进行编码,将字符串转为对应的二进制,并且这个方法可以指定编码表。如果没有指定码表,该方法会使用操作系统默认码表。

注意:中国大陆的Windows系统上默认的编码一般为GBK。在Java程序中可以使用System.getProperty("file.encoding")方式得到当前的默认编码。

二、解码

解码: 把码值查找对应的字符,我们把这个过程称作为解码。
字节数组--->字符串
String类的构造函数完成。
String(byte[] bytes) 使用系统默认码表
String(byte[],charset)指定码表

注意:我们使用什么字符集(码表)进行编码,就应该使用什么字符集进行解码,否则很有可能出现乱码(兼容字符集不会)。

public class Demo7 {
    
    public static void main(String[] args) throws Exception {
        /*
        String str = "中国";
        // getBytes() :使用的是平台默认的编码表---gbk编码表。 一个中文占两个字节
        byte[] buf = str.getBytes("utf-8"); //编码过程
        System.out.println("数组的元素:"+Arrays.toString(buf)); 
        
        str = new String(buf,"utf-8");  //默认使用了gbk码表去解码。 如果解码过程与编码是不一样的码表,就会产生乱码
        System.out.println("解码后的字符串:"+ str);        
        */
        
        
        /*String str = "a中国"; //[-2,-1,0,97,78,45,86,-3]
        String str = "中国";//[-2,-1,78,45,86,-3]
        byte[] buf = str.getBytes("unicode");  //编码与解码的时候指定的码表是unicode,实际上是用了utf-16.
        System.out.println("数组的内容:"+ Arrays.toString(buf)); //[-2,-1,0,97,78,45,86,-3]
        */
        //-2和-1是utf-16自己另外加的,作为UTF-16的标志
        
        String str = "大家好";
        byte[] buf = str.getBytes(); //使用平台默认的编码gbk进行编码,但是要以文件本身的编码为准
        
        System.out.println("字节数组:"+ Arrays.toString(buf));  // -76, -13, -68, -46, -70, -61
        
        str = new String(buf,"iso8859-1"); //乱码 大家好
        //在iso8859-1码表中,每个数字都有对应不同的字符,是唯一一个填满了的码表
        
        // 还原:使用这一串特殊的字符找回之前的数字,再使用gbk进行编码
        byte[] buf2 = str.getBytes("iso8859-1");
        str = new String(buf2,"gbk"); 

        System.out.println(str);

    }
    
}

注意: 编码与解码一般都使用统一的码表。否则非常容易出乱码。

不是所有的乱码都可以还原的:
以上情况拿着数字去iso8859-1去找,因为该码表每个数字都有对应的字符,但是如果对于一些其他码表,对应的数字没有该字符,就会造成数据丢失。

三、乱码解决方案

中文乱码问题是编码不一致导致的,只要保证了前端(页面使用meta标记utf-8),后端(对参数的解析、与连接库的连接),和数据库(数据库的编码格式)都使用统一的编码,一般不会出现乱码问题。

1.查看页面是否使用utf-8编码

①JSP页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

②HTML页面

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

2.在数据库连接url后面加上unicode参数

①使用的是非properties文件(如在hibernate.cfg.xml中配置):

<property name="hibernate.connection.url">
     jdbc:mysql://localhost:3306/数据库名?useUnicode=true&amp;characterEncoding=UTF-8
</property>

②使用的是properties文件

jdbcUrl=jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8

注意:如果使用的是properties文件配置数据库的连接信息,参数连接要用&,不要使用& amp;

3.在struts.xml中使用国际化

<constant name="struts.i18n.encoding" value="UTF-8" />

4.使用全局中文乱码过滤器

GlobalFilter类:

/**
 * 全局中文过滤器
 * 适用get和post请求参数的中文乱码问题,从此不同在servlet中对参数做处理
 */
public class GlobalFilter implements Filter {

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;

        // 解决POST请求参数乱码问题
        // request.setCharacterEncoding("UTF-8");

        req = new MyRequest(req);

        chain.doFilter(req, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

}

MyRequest:

/**
 * 使用装饰模式包装HttpServletRequest,解决getParamter中文乱码问题
 */
class MyRequest extends HttpServletRequestWrapper {

    private HttpServletRequest req;
    private boolean flag = true;// 标记是否getParameterMap方法还未被调用过(如果在同个servlet中调用了2次getParameter等方法2次,没有用flag做标记的话,会对参数进行2次编码,结果第2次得到的参数会是乱码)

    public MyRequest(HttpServletRequest request) {
        super(request);
        req = request;
    }

    @Override
    public String getParameter(String name) {
        return getParameterMap().get(name)[0];
    }

    @Override
    public String[] getParameterValues(String name) {
        return getParameterMap().get(name);
    }

    @Override
    public Map<String, String[]> getParameterMap() {

        Map<String, String[]> map = req.getParameterMap();

        if (flag) {
            for (Map.Entry<String, String[]> entry : map.entrySet()) {
                String[] value = entry.getValue();
                for (int i = 0; i < value.length; i++) {
                    try {
                        value[i] = new String(value[i].getBytes("iso-8859-1"),
                                "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            }
            flag = false;
        }

        return map;
    }

}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <!-- filter要放在servlet之前 -->
    <filter>
        <filter-name>GlobalFilter</filter-name>
        <filter-class>com.java.filter.GlobalFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>GlobalFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        ...
    </servlet>

    <servlet-mapping>
        ...
    </servlet-mapping>

</web-app>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容