Android(java)学习笔记152:采用get请求提交数据到服务器(qq登录案例)

1.GET请求:

   组拼url的路径,把提交的数据拼装url的后面,提交给服务器。

缺点:(1)安全性(Android下提交数据组拼隐藏在代码中,不存在安全问题)  (2)长度有限不能超过4K(http协议限制),IE浏览器限制至1K

优点:代码方便编写

2.我们首先在电脑模拟下GET请求访问服务器的场景

(1)使用Eclipse 新建一个 " 动态web项目 ",如下:

(2)然后编写一个servlet程序(运行在服务端),命名为" LoginServlet ",如下:

代码内容如下:

 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()获得一个输出流,向浏览器写入数据(提示数据).这里是输出Output,服务器输出到浏览器
27          if("10086".equals(qq) && "123456".equals(password)) {
28              response.getOutputStream().write("Login Success".getBytes());
29          }else {
30              response.getOutputStream().write("Login Failed".getBytes());
31          }
32          
33     }
34 
35 }

刚刚我们说过GET请求方法,把提交的数据组拼到url路径上提交到服务器上,所以这里request.getParameter();

(3)接下来编写一个jsp动态页面(区别于html静态页面),首先我们说一下jsp和html区别,如下:

jsp和html区别:

      •HTML页面是静态页面,也就是事先由用户写好放在服务器上,由web服务器向客户端发送;JSP页面是动态页面,有JSP容器执行该页面的Java代码部分然后实时生成的页面.

      •定义上HTML页面是静态页面可以直接运行,JSP页面是动态页它运行时需要转换成servlet。 

      •HTML能直接打开,jsp只能发布到Tomact等服务器上才能打开

      •他们的表头不同,这个是JSP的头“ <%@ page language="java" import="java.util.*" pageEncoding="gbk"%>”在表头中有编码格式和倒入包等。

      •很好区分的在jsp中用<%%>就可以写Java代码了,而html没有<%%>。

编写一个login.jsp代码,在WebContent文件夹下

login.jsp代码如下:

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 2 <html>
 3 <head>
 4 <%@ page language="java" contentType="text/html; charset=utf-8"
 5     pageEncoding="utf-8"%>
 6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 7 <title>???????</title>
 8 </head>
 9 <body>
10     
11     <form action="LoginServlet" method="get">
12   请输入QQ账号: <input type="text" name="qq"> <br/>
13   请输入QQ密码: <input type="password" name="password"> <br/>
14     <input type="submit" value="登录">
15     </form>
16 </body>
17 </html>

右击login.jsp文件," 运行方式 "--> " 在服务器上运行 ";运行的结果如下:

(4)打开360浏览器抓包分析http通信的详细过程:

• 打开360浏览器,地址栏输入:http://localhost:8080/web/login.jsp,结果如下:

•随便输入一个QQ账号和QQ密码,输入QQ账号10000,输入QQ密码123123如下:

观察下面,我们可以观察到我们输入的QQ账号和QQ密码已经传输到Tomcat服务器上

详细的抓取数据包如下:

上面提到的Response的数据长度是12(字符数),如下Response数据内容

• 输入正确的QQ账号和QQ密码,如下:

由下面我们知道了我们输入的QQ账号和QQ密码已经传输到Tomcat服务器上面: 

同样抓取的数据包为:

上面提到的Response的数据长度是13(字符数),如下Response数据内容

(5)小结:

•首先我们让编写的Servlet的程序在LoginServlet在Tomcat运行,Tomcat则处于一直监听状态(监听外界Http--GET请求),当我们在login.jsp输入QQ账号和QQ密码时候,点击"登录"之后,浏览器会把QQ账号和QQ密码组拼到url路径上,把这些数据提交给Tomcat服务器;

•此时处于监听状态的Tomcat服务器则根据接收到http的请求数据包中提取到QQ账号和QQ密码,比对正确的QQ账号和QQ密码(现实则是比对数据库的QQ账号和QQ密码);

•根据QQ账号和QQ密码匹配状况,反馈不同的信息,匹配成功返回"Login Success" ,反之匹配失败返回"Login Failed";

•返回的数据包被电脑浏览器获取,然后提取出返回数据,显示在浏览上,这样浏览器上就出现了"Login Success"或"Login Failed";

3.Android下模拟出手机GET请求访问远端服务器场景:

(1)新建一个Android工程,命名为”qq登录",下面首先是MainActivity.java

  1 package com.itheima.qqlogin;
  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                 //String path = "http://localhost:8080/web/LoginServlet";这里不能写成localhost
 98                 try {
 99                     String path = getString(R.string.serverip);
100                     URL url = new URL(path+"?qq="+qq+"&password="+pwd);
101                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();
102                     conn.setRequestMethod("GET");
103                     int code = conn.getResponseCode();
104                     if(code == 200) {
105                         InputStream is = conn.getInputStream();
106                         String result = StreamTools.readStream(is);
107                         showToastInAnyThread(result);
108                     }else {
109                         showToastInAnyThread("请求失败");
110                     }
111                 } catch (Exception e) {
112                     e.printStackTrace();
113                     showToastInAnyThread("请求失败");
114                 }
115             };
116         }.start();
117         
118     }
119     
120     /**
121      * 显示土司 在主线程更新UI
122      * @param text
123      */
124     public void showToastInAnyThread(final String text) {
125         runOnUiThread(new Runnable() {
126             
127             @Override
128             public void run() {
129                 Toast.makeText(MainActivity.this, text, 0).show();
130                 
131             }
132         });
133     }
134 }

其中使用到的工具类StreamTools如下:

 1 package com.itheima.qqlogin;
 2 
 3 import java.io.ByteArrayOutputStream;
 4 import java.io.InputStream;
 5 
 6 /**
 7  * 流的工具类
 8  * @author Administrator
 9  *
10  */
11 public class StreamTools {
12     /**
13      * 把输入流的内容转换成字符串
14      * @param is
15      * @return null解析失败, string读取成功
16      */
17     public static String readStream(InputStream is) throws Exception {
18             ByteArrayOutputStream baos = new ByteArrayOutputStream();
19             byte[] buffer = new byte[1024];
20             int len = 0;
21             while((len = is.read(buffer)) != -1) {
22                 baos.write(buffer, 0, len);
23             }
24             is.close();
25             String result = baos.toString();
26             baos.close();
27             return result;
28             
29         
30     }
31 }

ByteArrayOutputStream类:是在创建它的实例时,程序内部创建一个byte型别数组的缓冲区

ByteArrayInputStream:的实例向数组中写入或读出byte型数据。

具体用法:

         ByteArrayOutputStream:    可以捕获内存缓冲区的数据,转换成字节数组

         ByteArrayInputStream:     可以将字节数组转化为输入流

(2)布局文件activity_main.xml

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:gravity="center_horizontal"
 5     android:paddingLeft="10dp"
 6     android:paddingRight="10dp"
 7     android:orientation="vertical" >
 8 
 9     <ImageView
10         android:layout_width="200dip"
11         android:layout_height="200dip"
12         android:src="@drawable/ic_launcher" />
13 
14     <EditText
15         android:id="@+id/et_qq"
16         android:inputType="text"
17         android:layout_width="match_parent"
18         android:layout_height="wrap_content"
19         android:hint="请输入qq号码" />
20     
21      <EditText
22          android:id="@+id/et_pwd"
23          android:layout_width="match_parent"
24          android:layout_height="wrap_content"
25          android:hint="请输入密码"
26          android:inputType="textPassword" />
27      
28      <CheckBox 
29          android:id="@+id/cb_remember"
30            android:layout_width="match_parent"
31          android:layout_height="wrap_content"
32          android:text="记住密码"
33          />
34 
35      <Button
36          android:onClick="login" 
37          android:layout_width="match_parent"
38          android:layout_height="wrap_content"
39          android:text="登陆"
40          
41          />
42 </LinearLayout>

布局效果图如下:

(3) 布署程序到模拟器上,我们进行演示:

当我们输入QQ账号:10000,QQ密码:123123,效果如下:

点击登录,出现”Login Failed",如下:

与此同时,我们的Tomcat服务器端也接收到了账号和密码

(4)当我们输入正确的QQ账号和密码时候:

同时我们看到了Tomcat服务器上面,也收到QQ账号和QQ密码的信息,如下:

(5)小结:

我们点击"登录",程序中提取到QQ账号 和 QQ密码,组拼成url网络访问路径,访问Tomcat服务器;

Tomcat服务器得到账号和密码,会在LoginServlet程序中进行比对,如果匹配成功就返回"Login Success",匹配失败就是返回"Login Failed";

返回的信息数据,手机端程序获取之后,以土司的形式打印出来,提示用户登录的情况。

原文地址:https://www.cnblogs.com/hebao0514/p/4783000.html