解决程序中乱码问题

乱码出现的原因

我们在写程序的时候经常会遇到乱码的情况,有时乱码是一些不认识的汉字,有些乱码是一连串的问号,这让我们非常难受。乱码问题我想一定困扰过许多刚刚开始学习web的朋友,综上所述我写了一些东东,希望对各位有所帮助。

乱码出现的原因其实本质上就是对汉字使用A方式编码,然后使用B方式解码就会出现乱码的问题。

而出现两者不同会存在两个地方需要注意:

  • 前端:第一个前端向后端传输时会将文本编码,文本到了后端会对编码后的内容进行解码,当两者不一样时就会出现乱码。
  • 数据库:第二个我们利用dao向数据库存贮时,也会将文本编码,然后到了数据库时也会再次解码,这时也有可能会出现乱码的情况
  • tomcat

那么又有小伙伴要问你凭什么说编码和解码不一样就会出现问题呢?

回答:我直接上代码。

package test;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : 范东升  @date : 2023/4/24
 * CONTENT:
 */
public class BMTest {
    private static final String STR = "我爱包头";
    private static final List<Charset> MyStandardCharsets = new ArrayList<>();
    static {
        MyStandardCharsets.add(StandardCharsets.US_ASCII);
        MyStandardCharsets.add(StandardCharsets.ISO_8859_1);
        MyStandardCharsets.add(StandardCharsets.UTF_8);
        MyStandardCharsets.add(StandardCharsets.UTF_16BE);
        MyStandardCharsets.add(StandardCharsets.UTF_16LE);
        MyStandardCharsets.add(StandardCharsets.UTF_16);
        MyStandardCharsets.add(Charset.forName("GBK"));
    }

    public static void main(String[] args) {

        for (int i=0;i<MyStandardCharsets.size();i++)
        {
            for (int j=0;j<MyStandardCharsets.size();j++)
            {
                if (i==j)
                    continue;
                byte[] bytes = codeString(STR,MyStandardCharsets.get(i));
                String s = decodeBytes(bytes, MyStandardCharsets.get(j));
                System.out.println("结果 : "+s + "\n");
            }
            System.out.println("********************************");
        }
    }



    /***
     * @param str 字符串
     * @param encode 解码方式
     * @return 解码后字节流
     */
    private static byte[] codeString(String str , Charset encode ) {
        System.out.print("编码 : "+ encode.displayName() +"  ");
        return str.getBytes(encode);
    }

    /**
     * @param bytes 字节流
     * @param encode 解码方式
     * @return 返回解码后的字符串
     */
    private static String decodeBytes(byte[] bytes,Charset encode){
        System.out.println("解码 : "+ encode.displayName());
        return new String(bytes,encode);
    }

    private static void printBytes(byte[] bytes) {
        for (int i=0;i<bytes.length;i++)
        {
            System.out.print(bytes[i]+" | ");
        }
        System.out.println();
    }
}

结果

"我爱包头"

行表示编码方式,列表示解码方式

US_ASCII

ISO_8859_1

UTF_8

UTF_16BE

UTF_16LE

UTF_16

GBK

US_ASCII

????

������������

br1SY4

b1rS4Y

��br1SY4

��������

ISO_8859_1

????

æç±å头

br1SY4

b1rS4Y

þÿbr1SY4

ÎÒ°®°üÍ·

UTF_8

????

????

br1SY4

b1rS4Y

��br1SY4

�Ұ���ͷ

UTF_16BE

㼿㼿

㼿㼿

釧袱藥꒴

ᅢㅲՓ㑙

我爱包头

컒낮냼춷

UTF_16LE

㼿㼿

㼿㼿

裦놈賥뒤

ᅢㅲՓ㑙

�ᅢㅲՓ㑙

틎꺰ﲰ럍

UTF_16

㼿㼿

㼿㼿

釧袱藥꒴

我爱包头

ᅢㅲՓ㑙

컒낮냼춷

GBK

????

????

鎴戠埍鍖呭ご

br1SY4

b1rS4Y

�br1SY4

那么又有小伙伴要问了,为什么编码和解码方式不一样就会出现这种问题呢?

如utf-8中,一个字母用一个字节表示,一个汉字用三个字节表示,特殊的汉字用四个字节表示,而gbk中,一个字母用一个字节表示,一个汉字用两个字节表示。相信说这里聪明的小伙伴就已经恍然大悟了,后面可以自己去实践一下。当然你可以在上面的代码中观察到。

解决办法其实也很简单,当我们明白到这里的时候想要解决这个问题,那么规定好4个口的编码就解码就可以了。

JPS+SERVLET解决方案:

前端传输编码:

我们在jsp文件中加入下面这句话,这一步其实是解决了前端传输的编码问题。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

当该JSP页面发送请求时,contentType中的内容也会被包含在请求头中,一起发送过去。

(我们还有可能会使用ajax去发请求,记得也带上编码方式)

后端解析解码:

我们需要在servlet中加入。

request.setCharacterEncoding("utf-8");

当然给每一个servlet去配置utf-8明显太麻烦。这时我们可以在web.xml文件中去配置一个过滤器是常用的方法。

<filter>
  <filter-name>encodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
  </init-param>
  <init-param>
    <param-name>forceEncoding</param-name>
    <param-value>true</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping> 

 

数据库字段设置为UTF-8

这个也有多种方案:第一个直接给mysql下配置

查看mysql字符集

show variables like 'character%';

修改配置文件里内容

[client]
default-character-set=utf8
[mysqld]
character-set-server=utf8
collation_server=utf8_general_ci 

去编辑某个库的字符集,建议navcat直接看和改

这里需要注意一点:改库之后表里面已经存在字段的字符集不会改变记得要改。

 后端传输数据库编码

useUnicode=true&characterEncoding=utf8&serverTimezone=UTC

springboot解决方案

解决方法是换汤不换药啊,毕竟springBoot中的springMVC就是servlet的自动挡。我们可以springboot配置的理念解决问题也可以使用springMVC的理念去解决问题。

1:配置文件

#编码格式
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8

 2:写一个过滤器放到容器里。

@Configuration
    public class MyConfiguration extends WebMvcConfigurationSupport {
        @Bean
        public CharacterEncodingFilter characterEncodingFilter(){
            CharacterEncodingFilter filter = new CharacterEncodingFilter();
            filter.setEncoding("UTF-8");
            filter.setForceEncoding(true);
            return filter;
        }
    }

3:这种其实和上面的request.setCharacterEncoding("utf-8");差不多一个意思,springMVC又自动化了一层。

@RestController
public class TestController {
 
    @Value("${book.name}")
    private String name;
 
    @Value("${book.number}")
    private String number;
 
    //防止中文乱码
    @RequestMapping(value = "/getBook",produces = "application/json;charset=utf-8")
    public String getBook(){
        return name + number;
    }
 
}

结论:解决办法不少,一定知道本质问题。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

范范_24

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值