• Android(java)学习笔记155:中文乱码的问题处理(qq登录案例)


    1. 我们在之前的笔记中LoginServlet.java中,我们Tomcat服务器回复给客户端的数据是英文的"Login Success","Login Failed".

    现在我们改成如下的汉字:

     1 package com.himi.web;
     2 
     3 import java.io.IOException;
     4 import javax.servlet.ServletException;
     5 import javax.servlet.annotation.WebServlet;
     6 import javax.servlet.http.HttpServlet;
     7 import javax.servlet.http.HttpServletRequest;
     8 import javax.servlet.http.HttpServletResponse;
     9 
    10 /**
    11  * Servlet implementation class LoginServlet
    12  */
    13 @WebServlet("/LoginServlet")
    14 public class LoginServlet extends HttpServlet {
    15     private static final long serialVersionUID = 1L;
    16 
    17     /**
    18      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
    19      */
    20     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    21          String qq = request.getParameter("qq");
    22          String password = request.getParameter("password");
    23          System.out.println("qq:"+qq);
    24          System.out.println("password:"+password);
    25          
    26          //模拟服务器操作,查询数据库,看qq和密码是否正确. response.getOutputStream()获得一个输出流,向浏览器写入数据(提示数据)
    27          if("10086".equals(qq) && "123456".equals(password)) {
    28              response.getOutputStream().write("登录成功".getBytes());
    29          }else {
    30              response.getOutputStream().write("登录失败".getBytes());
    31          }
    32          
    33     }
    34 
    35 }

    这时候,我们布署之前的Android手机端http程序到模拟器上,运行产生如下效果

    2.常见的乱码处理

    (1)菱形里面有问号 : gbk的中文数据用utf-8表示的

    Tomcat默认的编码是iso-8859-1的码表,没有中文,如果遇到了不认识的字符串就使用本地默认编码gbk

    当我们把这些gbk编码数据通过http协议传递给手机Android客户端的时候,Android客户端的默认编码是utf-8.所以会出现这样的问题。

    这个乱码解决问题的方式:在客户端或者服务器端任意一端(不能同时修改两端).比如服务器端把回复数据编码改成utf-8,要么就是客户端把接收到数据指定以gb2312

    (2)中文用户名输入出现乱码

    • 手机客户端

    还是之前的qq登录的案例,这里输入中文:

    点击登录之后,服务器端接收到数据,显示乱码,效果如下:出现?乱码

     • PC端浏览器

    这里也是输入中文用户名,如下:

    结果出现乱码如下:出现的?乱码

    (3)PC端到服务器端的乱码问题解决:

    PC端到服务器端的乱码是由于之前客户端是以utf-8流的方式把中文用户名,传递给服务器端服务端默认编码是ios-8859-1,它是不能识别中文的

    所以服务器端以ios-8859-1的方式显示数据,就会上面的问号乱码

    解决办法:修改服务器端代码,如下:

    qq.getBytes("iso-8859-1"),这里必须指定iso-8859-1的方式,不然会默认是系统本地编码gb2312;

    此时再次在浏览器提交数据,服务器端就不会出现乱码,如下:

    (4)GET客户端到服务器端的乱码问题解决:

    上面只是解决PC端到服务器端的乱码出现的问题,但是客户端到服务器端的乱码还是没有解决,如下:

    这里我们知道get方式是组拼url路径的,提交的数据包含在这个路径下,提交的数据要是包含中文或者其他不合法字符就会转化,就如下:

    解决方法:拼接url的路径时候,对中文进行转化:

    (5)POST客户端到服务器端的乱码问题解决:

    之前POST方式编写的QQ登录案例,直接布署程序到模拟器上会出现如下错误:

    解决办法:

      1 package com.himi.post;
      2 
      3 import java.io.BufferedReader;
      4 import java.io.File;
      5 import java.io.FileInputStream;
      6 import java.io.FileOutputStream;
      7 import java.io.InputStream;
      8 import java.io.InputStreamReader;
      9 import java.net.HttpURLConnection;
     10 import java.net.MalformedURLException;
     11 import java.net.URL;
     12 
     13 import android.app.Activity;
     14 import android.os.Bundle;
     15 import android.text.TextUtils;
     16 import android.util.Log;
     17 import android.view.View;
     18 import android.widget.CheckBox;
     19 import android.widget.EditText;
     20 import android.widget.Toast;
     21 
     22 public class MainActivity extends Activity {
     23     private static final String Tag = "MainActivity";
     24     private EditText et_qq;
     25     private EditText et_pwd;
     26     private CheckBox cb_remember;
     27 
     28     @Override
     29     protected void onCreate(Bundle savedInstanceState) {
     30         super.onCreate(savedInstanceState);
     31         setContentView(R.layout.activity_main);
     32         //查询关心的控件
     33         et_qq = (EditText) findViewById(R.id.et_qq);
     34         et_pwd = (EditText) findViewById(R.id.et_pwd);
     35         cb_remember = (CheckBox) findViewById(R.id.cb_remember);
     36         Log.i(Tag,"oncreate 被调用");
     37         //完成数据的回显。
     38         readSavedData();
     39     }
     40     //读取保存的数据
     41     private void readSavedData() {
     42         // getFilesDir() == /data/data/包名/files/  获取文件的路径 一般系统是不会清理的。 用户手工清理,系统会有提示。
     43         // getCacheDir()==  /data/data/包名/cache/ 缓存文件的路径 当系统内存严重不足的时候 系统会自动的清除缓存 用户手工清理系统没有提示
     44         File file = new File(getFilesDir(),"info.txt");
     45         if(file.exists()&&file.length()>0){
     46             try {
     47                 //FileInputStream fis = new FileInputStream(file);
     48                 FileInputStream fis =this.openFileInput("info.txt");
     49                 BufferedReader br = new BufferedReader(new InputStreamReader(fis));
     50                 //214342###abcdef
     51                 String info = br.readLine();
     52                 String qq = info.split("###")[0];
     53                 String pwd = info.split("###")[1];
     54                 et_qq.setText(qq);
     55                 et_pwd.setText(pwd);
     56                 fis.close();
     57             } catch (Exception e) {
     58                 e.printStackTrace();
     59             }
     60         }
     61     }
     62     /**
     63      * 登陆按钮的点击事件,在点击事件里面获取数据
     64      * @param view
     65      */
     66     public void login(View view){
     67         final String qq = et_qq.getText().toString().trim();
     68         final String pwd = et_pwd.getText().toString().trim();
     69         if(TextUtils.isEmpty(qq)||TextUtils.isEmpty(pwd)){
     70             Toast.makeText(this, "qq号码或者密码不能为空", 0).show();
     71             return;
     72         }
     73         //判断用户是否勾选记住密码。
     74         if(cb_remember.isChecked()){
     75             //保存密码
     76             Log.i(Tag,"保存密码");
     77             try {
     78 //                File file = new File(getFilesDir(),"info.txt");
     79 //                FileOutputStream fos = new FileOutputStream(file);
     80                 FileOutputStream fos = this.openFileOutput("info.txt", 0);
     81                 //214342###abcdef
     82                 fos.write((qq+"###"+pwd).getBytes());
     83                 fos.close();
     84                 Toast.makeText(this, "保存成功", 0).show();
     85             } catch (Exception e) {
     86                 e.printStackTrace();
     87                 Toast.makeText(this, "保存失败", 0).show();
     88             }
     89         }else{
     90             //无需保存密码
     91             Log.i(Tag,"无需保存密码");
     92         }
     93         
     94         //登录的操作,网络的请求
     95         new Thread() {
     96             public void run() {
     97                 //post请求提交数据
     98                 //String path = "http://localhost:8080/web/LoginServlet";这里不能写成localhost
     99                 try {
    100                     String path = getString(R.string.serverip);
    101                     URL url = new URL(path);
    102                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    103                     //重要,记得设置请求方式post
    104                     conn.setRequestMethod("POST");
    105                     //重要,记得设置数据的类型
    106                     conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
    107                     String data = "qq="+URLEncoder.encode(qq,"utf-8")+"&password="+URLEncoder.encode(pwd,"utf-8");
    108                     //重要,记得设置数据的长度
    109                     conn.setRequestProperty("Content-Length", String.valueOf(data.length()));
    110                     
    111                     //重要,记得给服务器写数据
    112                     conn.setDoOutput(true);//声明要给服务器写数据
    113                     //重要,把数据写给服务器
    114                     conn.getOutputStream().write(data.getBytes());
    115                     
    116                     int code = conn.getResponseCode();
    117                     if(code == 200) {
    118                         InputStream is = conn.getInputStream();
    119                         String result = StreamTools.readStream(is);
    120                         showToastInAnyThread(result);
    121                     }else {
    122                         showToastInAnyThread("请求失败");
    123                     }
    124                 } catch (Exception e) {
    125                     e.printStackTrace();
    126                     showToastInAnyThread("请求失败");
    127                 }
    128             };
    129         }.start();
    130         
    131     }
    132     
    133     /**
    134      * 显示土司 在主线程更新UI
    135      * @param text
    136      */
    137     public void showToastInAnyThread(final String text) {
    138         runOnUiThread(new Runnable() {
    139             
    140             public void run() {
    141                 Toast.makeText(MainActivity.this, text, 0).show();
    142                 
    143             }
    144         });
    145     }
    146 }

    这时候我们输入提交数据给服务器就不会出现乱码,如下:

    (6)HttpClient-Get客户端到服务器端的乱码问题解决:

      1 package com.himi.post;
      2 import java.io.BufferedReader;
      3 import java.io.File;
      4 import java.io.FileInputStream;
      5 import java.io.FileOutputStream;
      6 import java.io.InputStream;
      7 import java.io.InputStreamReader;
      8 import org.apache.http.HttpResponse;
      9 import org.apache.http.client.HttpClient;
     10 import org.apache.http.client.methods.HttpGet;
     11 import org.apache.http.impl.client.DefaultHttpClient;
     12 import android.app.Activity;
     13 import android.os.Bundle;
     14 import android.text.TextUtils;
     15 import android.util.Log;
     16 import android.view.View;
     17 import android.widget.CheckBox;
     18 import android.widget.EditText;
     19 import android.widget.Toast;
     20 public class MainActivity extends Activity {
     21     private static final String Tag = "MainActivity";
     22     private EditText et_qq;
     23     private EditText et_pwd;
     24     private CheckBox cb_remember;
     25     @Override
     26     protected void onCreate(Bundle savedInstanceState) {
     27         super.onCreate(savedInstanceState);
     28         setContentView(R.layout.activity_main);
     29         //查询关心的控件
     30         et_qq = (EditText) findViewById(R.id.et_qq);
     31         et_pwd = (EditText) findViewById(R.id.et_pwd);
     32         cb_remember = (CheckBox) findViewById(R.id.cb_remember);
     33         Log.i(Tag,"oncreate 被调用");
     34         //完成数据的回显。
     35         readSavedData();
     36     }
     37     //读取保存的数据
     38     private void readSavedData() {
     39         // getFilesDir() == /data/data/包名/files/  获取文件的路径 一般系统是不会清理的。 用户手工清理,系统会有提示。
     40         // getCacheDir()==  /data/data/包名/cache/ 缓存文件的路径 当系统内存严重不足的时候 系统会自动的清除缓存 用户手工清理系统没有提示
     41         File file = new File(getFilesDir(),"info.txt");
     42         if(file.exists()&&file.length()>0){
     43             try {
     44                 //FileInputStream fis = new FileInputStream(file);
     45                 FileInputStream fis =this.openFileInput("info.txt");
     46                 BufferedReader br = new BufferedReader(new InputStreamReader(fis));
     47                 //214342###abcdef
     48                 String info = br.readLine();
     49                 String qq = info.split("###")[0];
     50                 String pwd = info.split("###")[1];
     51                 et_qq.setText(qq);
     52                 et_pwd.setText(pwd);
     53                 fis.close();
     54             } catch (Exception e) {
     55                 e.printStackTrace();
     56             }
     57         }
     58     }
     59     /**
     60      * 登陆按钮的点击事件,在点击事件里面获取数据
     61      * @param view
     62      */
     63     public void login(View view){
     64         final String qq = et_qq.getText().toString().trim();
     65         final String pwd = et_pwd.getText().toString().trim();
     66         if(TextUtils.isEmpty(qq)||TextUtils.isEmpty(pwd)){
     67             Toast.makeText(this, "qq号码或者密码不能为空", 0).show();
     68             return;
     69         }
     70         //判断用户是否勾选记住密码。
     71         if(cb_remember.isChecked()){
     72             //保存密码
     73             Log.i(Tag,"保存密码");
     74             try {
     75 //                File file = new File(getFilesDir(),"info.txt");
     76 //                FileOutputStream fos = new FileOutputStream(file);
     77                 FileOutputStream fos = this.openFileOutput("info.txt", 0);
     78                 //214342###abcdef
     79                 fos.write((qq+"###"+pwd).getBytes());
     80                 fos.close();
     81                 Toast.makeText(this, "保存成功", 0).show();
     82             } catch (Exception e) {
     83                 e.printStackTrace();
     84                 Toast.makeText(this, "保存失败", 0).show();
     85             }
     86         }else{
     87             //无需保存密码
     88             Log.i(Tag,"无需保存密码");
     89         }
     90         
     91         //登录的操作,网络的请求
     92         new Thread() {
     93             public void run() {
     94                 //String path = "http://localhost:8080/web/LoginServlet";这里不能写成localhost
     95                 try {
     96                     //httpclient get请求提交数据
     97                     String path = getString(R.string.serverip)+"?qq="+URLEncoder.encode(qq)+"&password="+URLEncoder.encoder(pwd);
     98                     //1.打开浏览器
     99                     HttpClient client = new DefaultHttpClient();
    100                     //2.输入地址
    101                     HttpGet httpGet = new HttpGet(path);
    102                     //3.敲回车
    103                     HttpResponse response = client.execute(httpGet);
    104                     int code = response.getStatusLine().getStatusCode();
    105                     if(code == 200) {
    106                         InputStream is = response.getEntity().getContent();
    107                         String result = StreamTools.readStream(is);
    108                         showToastInAnyThread(result);
    109                     }else {
    110                         showToastInAnyThread("请求失败,返回码是:"+code);
    111                     }
    112                     
    113                     
    114                 } catch (Exception e) {
    115                     e.printStackTrace();
    116                     showToastInAnyThread("请求失败");
    117                 }
    118             };
    119         }.start();
    120         
    121     }
    122     
    123     /**
    124      * 显示土司 在主线程更新UI
    125      * @param text
    126      */
    127     public void showToastInAnyThread(final String text) {
    128         runOnUiThread(new Runnable() {
    129             
    130             public void run() {
    131                 Toast.makeText(MainActivity.this, text, 0).show();
    132                 
    133             }
    134         });
    135     }
    136 }
    

    (7)HttpClient-Post客户端到服务器端的乱码问题解决:

      1 package com.himi.post;
      2 import java.io.BufferedReader;
      3 import java.io.File;
      4 import java.io.FileInputStream;
      5 import java.io.FileOutputStream;
      6 import java.io.InputStream;
      7 import java.io.InputStreamReader;
      8 import java.util.ArrayList;
      9 import java.util.List;
     10 import org.apache.http.HttpResponse;
     11 import org.apache.http.NameValuePair;
     12 import org.apache.http.client.HttpClient;
     13 import org.apache.http.client.entity.UrlEncodedFormEntity;
     14 import org.apache.http.client.methods.HttpPost;
     15 import org.apache.http.impl.client.DefaultHttpClient;
     16 import org.apache.http.message.BasicNameValuePair;
     17 import android.app.Activity;
     18 import android.os.Bundle;
     19 import android.text.TextUtils;
     20 import android.util.Log;
     21 import android.view.View;
     22 import android.widget.CheckBox;
     23 import android.widget.EditText;
     24 import android.widget.Toast;
     25 public class MainActivity extends Activity {
     26     private static final String Tag = "MainActivity";
     27     private EditText et_qq;
     28     private EditText et_pwd;
     29     private CheckBox cb_remember;
     30     @Override
     31     protected void onCreate(Bundle savedInstanceState) {
     32         super.onCreate(savedInstanceState);
     33         setContentView(R.layout.activity_main);
     34         //查询关心的控件
     35         et_qq = (EditText) findViewById(R.id.et_qq);
     36         et_pwd = (EditText) findViewById(R.id.et_pwd);
     37         cb_remember = (CheckBox) findViewById(R.id.cb_remember);
     38         Log.i(Tag,"oncreate 被调用");
     39         //完成数据的回显。
     40         readSavedData();
     41     }
     42     //读取保存的数据
     43     private void readSavedData() {
     44         // getFilesDir() == /data/data/包名/files/  获取文件的路径 一般系统是不会清理的。 用户手工清理,系统会有提示。
     45         // getCacheDir()==  /data/data/包名/cache/ 缓存文件的路径 当系统内存严重不足的时候 系统会自动的清除缓存 用户手工清理系统没有提示
     46         File file = new File(getFilesDir(),"info.txt");
     47         if(file.exists()&&file.length()>0){
     48             try {
     49                 //FileInputStream fis = new FileInputStream(file);
     50                 FileInputStream fis =this.openFileInput("info.txt");
     51                 BufferedReader br = new BufferedReader(new InputStreamReader(fis));
     52                 //214342###abcdef
     53                 String info = br.readLine();
     54                 String qq = info.split("###")[0];
     55                 String pwd = info.split("###")[1];
     56                 et_qq.setText(qq);
     57                 et_pwd.setText(pwd);
     58                 fis.close();
     59             } catch (Exception e) {
     60                 e.printStackTrace();
     61             }
     62         }
     63     }
     64     /**
     65      * 登陆按钮的点击事件,在点击事件里面获取数据
     66      * @param view
     67      */
     68     public void login(View view){
     69         final String qq = et_qq.getText().toString().trim();
     70         final String pwd = et_pwd.getText().toString().trim();
     71         if(TextUtils.isEmpty(qq)||TextUtils.isEmpty(pwd)){
     72             Toast.makeText(this, "qq号码或者密码不能为空", 0).show();
     73             return;
     74         }
     75         //判断用户是否勾选记住密码。
     76         if(cb_remember.isChecked()){
     77             //保存密码
     78             Log.i(Tag,"保存密码");
     79             try {
     80 //                File file = new File(getFilesDir(),"info.txt");
     81 //                FileOutputStream fos = new FileOutputStream(file);
     82                 FileOutputStream fos = this.openFileOutput("info.txt", 0);
     83                 //214342###abcdef
     84                 fos.write((qq+"###"+pwd).getBytes());
     85                 fos.close();
     86                 Toast.makeText(this, "保存成功", 0).show();
     87             } catch (Exception e) {
     88                 e.printStackTrace();
     89                 Toast.makeText(this, "保存失败", 0).show();
     90             }
     91         }else{
     92             //无需保存密码
     93             Log.i(Tag,"无需保存密码");
     94         }
     95         
     96         //登录的操作,网络的请求
     97         new Thread() {
     98             public void run() {
     99                 //post请求提交数据
    100                 //String path = "http://localhost:8080/web/LoginServlet";这里不能写成localhost
    101                 try {
    102                     String path = getString(R.string.serverip);
    103                     //1.打开浏览器
    104                     HttpClient client = new DefaultHttpClient();
    105                     //2.输入地址
    106                     HttpPost httpPost = new HttpPost(path);
    107                     //设置一个url的表单的数据
    108                     List<NameValuePair> paramters = new ArrayList<NameValuePair>();
    109                     paramters.add(new BasicNameValuePair("qq", qq));
    110                     paramters.add(new BasicNameValuePair("password", pwd));
    111                     httpPost.setEntity(new UrlEncodedFormEntity(paramters,"utf-8"));
    112                     //3.敲回车
    113                     HttpResponse response = client.execute(httpPost);
    114                     int code = response.getStatusLine().getStatusCode();
    115                     if(code == 200) {
    116                         InputStream is = response.getEntity().getContent();
    117                         String result = StreamTools.readStream(is);
    118                         showToastInAnyThread(result);
    119                     }else {
    120                         showToastInAnyThread("请求失败,返回码是:"+code);
    121                     }
    122                     
    123                 } catch (Exception e) {
    124                     e.printStackTrace();
    125                     showToastInAnyThread("请求失败");
    126                 }
    127             };
    128         }.start();
    129         
    130     }
    131     
    132     /**
    133      * 显示土司 在主线程更新UI
    134      * @param text
    135      */
    136     public void showToastInAnyThread(final String text) {
    137         runOnUiThread(new Runnable() {
    138             
    139             public void run() {
    140                 Toast.makeText(MainActivity.this, text, 0).show();
    141                 
    142             }
    143         });
    144     }
    145 }
  • 相关阅读:
    superset可视化不同算法的点击率
    flume通过avro对接(汇总数据)
    Flume同时输出数据到HDFS和kafka
    剑指offer题目系列二
    剑指offer题目系列一
    Servlet生命周期与线程安全
    Servlet初始化及处理HTTP请求
    Servlet及相关类和接口
    web.xml配置文件详解
    递归与斐波那契数列
  • 原文地址:https://www.cnblogs.com/hebao0514/p/4784685.html
Copyright © 2020-2023  润新知