前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Win和Linux下JAVA默认编码问题导致的乱码解决

Win和Linux下JAVA默认编码问题导致的乱码解决

作者头像
kr
发布2022-06-15 18:05:39
4.2K0
发布2022-06-15 18:05:39
举报
文章被收录于专栏:个人教程

项目和起因

项目
  • 一个类似于Server酱的消息推送应用,只需通过一条URL即可给指定通道发送信息,可以用来发送告警、服务器状态、脚本运行状态等信息,约等于以前很多人用的邮件通知。
  • 目前只写了企业微信应用的通道,因为企业微信应用能在微信显示,而微信最常用基本不会关。
  • 以后应该会增加公众号、钉钉等通道,再看看要不要支持多人的。
遇到的问题
  • 版本:Java 1.8.0_333
  • 在Linux下使用正常,在Windows下发送中文会不显示或者乱码。

问题原因和解决

原因
  • Windows和Linux下Java默认编码不同的问题。
  • Windows下默认编码是GBK,Linux下默认编码是UTF-8。
  • 这个对新手来说挺坑的,以前一直听说Java跨平台好,没想到能遇到这种问题。
  • 在这之前用Python写过一个Dome就没遇到这种问题。
  • 可以用这段代码测试当前环境Java的默认编码
代码语言:javascript
复制
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
 
class Test {
    public static void main(String[] args) {
        System.out.println("Default Charset=" + Charset.defaultCharset());
        System.out.println("file.encoding=" + System.getProperty("file.encoding"));
        System.out.println("Default Charset=" + Charset.defaultCharset());
        System.out.println("Default Charset in Use=" + getDefaultCharSet());
    }
 
    private static String getDefaultCharSet() {
        OutputStreamWriter writer = new OutputStreamWriter(new ByteArrayOutputStream());
        String enc = writer.getEncoding();
        return enc;
    }
 
}
探究和解决
探索粗记录
项目基本逻辑
  1. 用SpringBoot写一个API,用来接收请求,例如:http://127.0.0.1:8080/qw?msg=你好&token=123
  2. 对比token,如果token与预设的不同返回错误信息,不给使用API。
  3. token相同,调用企业微信API把msg的信息推送到手机。

其中发送POST、GET请求的类如下:

代码语言:javascript
复制
package hello;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by chengxia on 2018/12/4.
 */
public class HttpURLConnectionWX {
    public String doPost(String URL,String jsonStr){
        OutputStreamWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        HttpURLConnection conn = null;
        try{
            URL url = new URL(URL);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            //发送POST请求必须设置为true
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //设置连接超时时间和读取超时时间
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(10000);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Accept", "application/json");
            //获取输出流
            out = new OutputStreamWriter(conn.getOutputStream());
            out.write(jsonStr);
            out.flush();
            out.close();
            //取得输入流,并使用Reader读取
            if (200 == conn.getResponseCode()){
                in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
                String line;
                while ((line = in.readLine()) != null){
                    result.append(line);
                    System.out.println(line);
                }
            }else{
                System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                if(out != null){
                    out.close();
                }
                if(in != null){
                    in.close();
                }
            }catch (IOException ioe){
                ioe.printStackTrace();
            }
        }
        return result.toString();
    }

    public String doGet(String URL){
        HttpURLConnection conn = null;
        InputStream is = null;
        BufferedReader br = null;
        StringBuilder result = new StringBuilder();
        try{
            //创建远程url连接对象
            URL url = new URL(URL);
            //通过远程url连接对象打开一个连接,强转成HTTPURLConnection类
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            //设置连接超时时间和读取超时时间
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(60000);
            conn.setRequestProperty("Accept", "application/json");
            //发送请求
            conn.connect();
            //通过conn取得输入流,并使用Reader读取
            if (200 == conn.getResponseCode()){
                is = conn.getInputStream();
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                String line;
                while ((line = br.readLine()) != null){
                    result.append(line);
                    System.out.println(line);
                }
            }else{
                System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
            }
        }catch (MalformedURLException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                if(br != null){
                    br.close();
                }
                if(is != null){
                    is.close();
                }
            }catch (IOException ioe){
                ioe.printStackTrace();
            }
            conn.disconnect();
        }
        return result.toString();
    }


    public static void main(String[] args) throws Exception {
        // 测试用
        new HttpURLConnectionWX().doPost("http://127.0.0.1:5000/qwtx", new String("{\"name\":\"你好\"}".getBytes("UTF-8")));

    }

}
尝试
  • 使用new String(msg.getBytes("UTF-8"))进行转码,无效。
  • 使用new String(msg.getBytes("GBK"))进行转码,无效。
  • 更改POST请求函数中的in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));为GBK,无效。

上面的无效指的是以下效果:直接是空的(一般是纯文字信息会遇到)、前部分文字能显示最后一个是乱码(一般是文字+数字/英文)、全是乱码(瞎改代码里面的编码转换后遇到的)

更多奇怪的尝试就不说了,当时已经知道通过加参数运行可以指定编码,但是感觉那样还得按照系统改命令不够人性化,就一直在尝试。 最后还是放弃了,没找到方法,等以后真正系统学了Java再说吧。

  • 最后放个辅助测试的Python脚本
代码语言:javascript
复制
import charset_normalizer
from flask import Flask, request
import json

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'hello world'

@app.route('/qw', methods=['POST'])
def register():
    byu = request.stream.read()
    # print(request.headers)
    print(charset_normalizer.detect(byu))
    try:
        print(str(byu ,encoding='GBK'))
    except:
        print('GBK ERR')
    try:
        print(str(byu,encoding='UTF-8'))
    except:
        print('UTF-8 ERR')
    return 'welcome'

if __name__ == '__main__':
    app.run(port=5000, debug=True)
解决

参考:设置Java JDK的默认编码为UTF-8_lc11535的博客-CSDN博客_java设置utf-8

  1. 添加一个名为JAVA_TOOL_OPTIONS的系统环境变量,变量值为-Dfile.encoding=UTF-8,参考官网说明
  2. 每次运行时都加一个-Dfile.encoding=UTF-8的参数。 如果是添加系统环境变量,添加完后需要重启CMD窗口才生效,可以用开头的检测默认编码的代码测试看看是否生效

未尝试:看B站有回复说Java 18把Win和Linux的默认编码都改成UTF-8了

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022 年 05 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目和起因
    • 项目
      • 遇到的问题
      • 问题原因和解决
        • 原因
          • 探究和解决
            • 探索粗记录
            • 解决
        相关产品与服务
        云服务器
        云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档