1.POST请求:
数据是以流的方式写给服务器
优点:(1)比较安全 (2)长度不限制
缺点:编写代码比较麻烦
2.我们首先在电脑模拟下POST请求访问服务器的场景:
我们修改之前编写的login.jsp代码,如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>???????</title> </head> <body> <h3>GET方式提交数据</h3> <form action="LoginServlet" method="get"> 请输入QQ账号: <input type="text" name="qq"> <br/> 请输入QQ密码: <input type="password" name="password"> <br/> <input type="submit" value="登录"> </form> <br> <hr> <h3>POST方式提交数据</h3> <form action="LoginServlet" method="post"> 请输入QQ账号: <input type="text" name="qq"> <br/> 请输入QQ密码: <input type="password" name="password"> <br/> <input type="submit" value="登录"> </form> </body> </html>
将修改过的jsp代码在Tomcat服务器上运行,如下:
我们在"POST方式提交数据"一栏,输入正确的QQ 账号和QQ密码,如下的然后提交出现如下错误:
这是因为在LoginServlet中只有doGet()方法,对于POST请求,服务器自然是接收不到POST请求的数据包,自然会出现上面的错误,添加doPost()方法即可:
package com.himi.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class LoginServlet */ @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String qq = request.getParameter("qq"); String password = request.getParameter("password"); System.out.println("qq:"+qq); System.out.println("password:"+password); //模拟服务器操作,查询数据库,看qq和密码是否正确 if("10086".equals(qq) && "123456".equals(password)) { response.getOutputStream().write("Login Success".getBytes()); }else { response.getOutputStream().write("Login Failed".getBytes()); } } /** * 添加的doPost()方法,响应post数据请求 */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("post过来的数据"); doGet(req, resp); } }
这个时候我们再次刷新之前的错误页面,就会出现如下效果:
类似这里如果我们没有输入正确的数据信息,就会显示" Login Failed"
3.Android下模拟出手机POST请求访问远端服务器场景:
POST请求如何写代码,我们还是先在360浏览器抓包数据分析一下,再去考虑。
在Android下编写代码实现POST请求,如下:
步骤:
•//重要,记得设置请求方式post
conn.setRequestMethod("POST");
•//重要,记得设置数据的类型
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
String data = "qq="+qq+"&password="+pwd;
•//重要,记得设置数据的长度
conn.setRequestProperty("Content-Length", String.valueOf(data.length()));
•//重要,记得给服务器写数据
conn.setDoOutput(true);//声明要给服务器写数据
•//重要,把数据写给服务器
conn.getOutputStream().write(data.getBytes());
(1)MainActivity.java:
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="+qq+"&password="+pwd; 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 }
工具类还是StreamTools,如下:
1 package com.himi.post; 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 }
(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账号或密码时候,如下:
输入QQ账号:10000,QQ密码:123123,结果如下;
当我们输入QQ账号或者密码是正确的时候:
比如,我们输入QQ账号:10086,输入密码:123456,结果如下:
同时服务器端也出现了数据接收的记录,如下: