zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

Volley解析之表单提交篇详解手机开发

手机开发 详解 解析 提交 表单 Volley
2023-06-13 09:20:13 时间

要实现表单的提交,就要知道表单提交的数据格式是怎么样,这里我从某知名网站抓了一条数据,先来分析别人提交表单的数据格式。 
数据包:

Connection: keep-alive 

Content-Length: 123 

X-Requested-With: ShockwaveFlash/16.0.0.296 

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36 

Content-Type: multipart/form-data; boundary=----------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 

Accept: */* 

Accept-Encoding: gzip, deflate 

Accept-Language: zh-CN,zh;q=0.8 

Cookie: bdshare_firstime=1409052493497 

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 

Content-Disposition: form-data; name="position" 

1425264476444 

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 

Content-Disposition: form-data; name="editorIndex" 

ue_con_1425264252856 

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 

Content-Disposition: form-data; name="cm" 

100672 

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1--

看到上面的数据包,我们不需要全部分析,我们主要关心的是数据如何封装,因为http请求头,在网络请求中已经为我们封装好了;可以看到这里总共是提交了三条数据,每一条数据的格式都是一样的,所以我们只需要分析一条数据即可,这里拿最后一条数据来说,因为在所有的数据之后还有一个结尾的标志。

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 

Content-Disposition: form-data; name="cm" 

100672 

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1--

这条数据一共有四行组成,加上结尾标志共有五行 
1、第一行:

"--" + boundary + "/r/n" ;

说明:”–”为数据开始标志,boundary为http实体头定义的边界分割线,boundary可以是任意的字符串,只要和Content-Type: multipart/form-data; boundary=———-Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1中保持一直即可,”/r/n”为回车换行; 
2、第二行:

"Content-Disposition: form-data; name="参数的名称"" + "/r/n" ;

说明:Content-Disposition表示上传的内容特性,form-data上传内容特性为表单的形式; 
3、第三行:

"/r/n" ;

4、说明:这是一个空行,只有一个回车换行 ; 
第四行:

"参数的值" + "/r/n" ;

说明:每个参数都是由一个key和value组成,而这一行就是value跟回车换行符 
结尾行:

"--" + boundary + "--" + "/r/n" ;

说明:在所有的数据结束之后,需要有这个结尾标志。 
如果有多个参数,则重复1、2、3、4,直至最后一个参数的最后加上结尾行。

参数实体类

这里对参数做一个封装,因为往往提交表单的时候,都需要提交多个参数

/** 

 * Created by gyzhong on 15/3/2. 

/*表单提交的参数*/ 

public class FormText { 

 /*参数的名称*/ 

 private String mName ; 

 /*参数的值*/ 

 private String mValue ; 

 public FormText(String mName, String mValue) { 

 this.mName = mName; 

 this.mValue = mValue; 

 public String getName() { 

 return mName; 

 public String getValue() { 

 return mValue; 

}
Volley 对数据的封装

在上一篇文章中我们讲了如何定制自己的 Request,在这里同样需要用到。在定制 Request 的时候,需要重写获取实体的方法

public byte[] getBody() throws AuthFailureError {}

把参数通过二进制的形式传给服务器,当然就不需要重写获取参数的方法

protected Map String, String getParams() throws AuthFailureError {}

最核心的方法也就在getBody()中,这个方法的实现,如果对表单提交的数据格式很了解,实现起来非常简单,因为这个方法就是把参数拼接成我们所分析的数据格式;

 @Override 

 public byte[] getBody() throws AuthFailureError { 

 if (mListItem == null||mListItem.size() == 0){ 

 return super.getBody() ; 

 ByteArrayOutputStream bos = new ByteArrayOutputStream() ; 

 int N = mListItem.size() ; 

 FormText formText ; 

 for (int i = 0; i i++){ 

 formText = mListItem.get(i) ; 

 StringBuffer sb= new StringBuffer() ; 

 /*第一行:"--" + boundary + "/r/n" ;*/ 

 sb.append("--"+BOUNDARY); 

 sb.append("/r/n") ; 

 /*第二行:"Content-Disposition: form-data; name="参数的名称"" + "/r/n" ;*/ 

 sb.append("Content-Disposition: form-data;"); 

 sb.append("name=/""); 

 sb.append(formText.getName()) ; 

 sb.append("/"") ; 

 sb.append("/r/n") ; 

 /*第三行:"/r/n" ;*/ 

 sb.append("/r/n") ; 

 /*第四行:"参数的值" + "/r/n" ;*/ 

 sb.append(formText.getValue()) ; 

 sb.append("/r/n") ; 

 try { 

 bos.write(sb.toString().getBytes("utf-8")); 

 } catch (IOException e) { 

 e.printStackTrace(); 

 /*结尾行:"--" + boundary + "--" + "/r/n" ;*/ 

 String endLine = "--" + BOUNDARY + "--"+ "/r/n" ; 

 try { 

 bos.write(endLine.toString().getBytes("utf-8")); 

 } catch (IOException e) { 

 e.printStackTrace(); 

 Log.v("zgy","=====formText====/n"+bos.toString()) ; 

 return bos.toByteArray(); 

 }

可以看到,这个方法的实现,就是对数据按照我们所分析的格式组装。 
在 Request 中还有一个关键的地方,需要在 http 头部中声明内容类型为表单数据

Content-Type: multipart/form-data; boundary=----------8888888888888

所以的重写下面方法为

public String getBodyContentType() { 

 return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY; 

 }

同样,我们还是前面我们blog 中讲到的接口http://www.minongbang.com/test.php?test=minongbang来测试,所以解析数据那一块跟 前面我们将的一样,具体实现如下:

/** 

 * Created by gyzhong on 15/3/2. 

public class PostFormRequest T extends Request T { 

 /** 

 * 正确数据的时候回掉用 

 private ResponseListener mListener ; 

 /*用来解析 json 用的*/ 

 private Gson mGson ; 

 /*在用 gson 解析 json 数据的时候,需要用到这个参数*/ 

 private Type mClazz ; 

 /*请求 数据通过参数的形式传入*/ 

 private List FormText mListItem ; 

 private String BOUNDARY = "---------8888888888888"; //数据分隔线 

 private String MULTIPART_FORM_DATA = "multipart/form-data"; 

 public PostFormRequest(String url, List FormText listItem, Type type, ResponseListener listener) { 

 super(Method.POST, url, listener); 

 this.mListener = listener ; 

 mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() ; 

 mClazz = type ; 

 setShouldCache(false); 

 mListItem = listItem ; 

 /** 

 * 这里开始解析数据 

 * @param response Response from the network 

 * @return 

 @Override 

 protected Response T parseNetworkResponse(NetworkResponse response) { 

 try { 

 T result ; 

 String jsonString = 

 new String(response.data, HttpHeaderParser.parseCharset(response.headers)); 

 Log.v("zgy", "====SearchResult===" + jsonString); 

 result = mGson.fromJson(jsonString,mClazz) ; 

 return Response.success(result, 

 HttpHeaderParser.parseCacheHeaders(response)); 

 } catch (UnsupportedEncodingException e) { 

 return Response.error(new ParseError(e)); 

 /** 

 * 回调正确的数据 

 * @param response The parsed response returned by 

 @Override 

 protected void deliverResponse(T response) { 

 mListener.onResponse(response); 

 @Override 

 public byte[] getBody() throws AuthFailureError { 

 if (mListItem == null||mListItem.size() == 0){ 

 return super.getBody() ; 

 ByteArrayOutputStream bos = new ByteArrayOutputStream() ; 

 int N = mListItem.size() ; 

 FormText formText ; 

 for (int i = 0; i i++){ 

 formText = mListItem.get(i) ; 

 StringBuffer sb= new StringBuffer() ; 

 /*第一行:"--" + boundary + "/r/n" ;*/ 

 sb.append("--"+BOUNDARY); 

 sb.append("/r/n") ; 

 /*第二行:"Content-Disposition: form-data; name="参数的名称"" + "/r/n" ;*/ 

 sb.append("Content-Disposition: form-data;"); 

 sb.append("name=/""); 

 sb.append(formText.getName()) ; 

 sb.append("/"") ; 

 sb.append("/r/n") ; 

 /*第三行:"/r/n" ;*/ 

 sb.append("/r/n") ; 

 /*第四行:"参数的值" + "/r/n" ;*/ 

 sb.append(formText.getValue()) ; 

 sb.append("/r/n") ; 

 try { 

 bos.write(sb.toString().getBytes("utf-8")); 

 } catch (IOException e) { 

 e.printStackTrace(); 

 /*结尾行:"--" + boundary + "--" + "/r/n" ;*/ 

 String endLine = "--" + BOUNDARY + "--"+ "/r/n" ; 

 try { 

 bos.write(endLine.toString().getBytes("utf-8")); 

 } catch (IOException e) { 

 e.printStackTrace(); 

 Log.v("zgy","=====formText====/n"+bos.toString()) ; 

 return bos.toByteArray(); 

 /*获取内容类型,这里为表单类型*/ 

 @Override 

 public String getBodyContentType() { 

 return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY; 

表单提交接口

接口我们在上一篇博文中也做了比较详细的讲解,这里就不累赘了。

 /** 

 * minong 测试post表单提交接口 

 * @param value 测试数据 

 * @param listener 回调接口,包含错误回调和正确的数据回调 

 public static void postFormMiNongApi(String value,ResponseListener listener){ 

 List FormText formTextList = new ArrayList FormText 

 formTextList.add(new FormText(" test",value)); 

 Request request = new PostFormRequest(Constant.MiNonghost,formTextList,new TypeToken SearchResult (){}.getType(),listener) ; 

 VolleyUtil.getRequestQueue().add(request) ; 

 }

PostFormActivity.java的测试代码如下

public class PostFormActivity extends ActionBarActivity { 

 private ListView mListView ; 

 private SongAdapter mAdapter ; 

 private List SongDetail mSongList ; 

 private ProgressDialog mDialog ; 

 private View mHeaderView ; 

 private TextView mShowPostData ; 

 @Override 

 protected void onCreate(Bundle savedInstanceState) { 

 super.onCreate(savedInstanceState); 

 setContentView(R.layout.activity_post_form); 

 mSongList = new ArrayList SongDetail 

 mListView = (ListView) findViewById(R.id.id_list_view); 

 mAdapter = new SongAdapter(this,mSongList) ; 

 mHeaderView = getLayoutInflater().inflate(R.layout.list_header_item,null) ; 

 mShowPostData = (TextView) mHeaderView.findViewById(R.id.id_post_data) ; 

 mListView.addHeaderView(mHeaderView); 

 mListView.setAdapter(mAdapter); 

 mDialog = new ProgressDialog(this) ; 

 mDialog.setMessage("数据提交中..."); 

 mDialog.show() ; 

 /*请求网络获取数据*/ 

 MiNongApi.postFormMiNongApi(" minongbang",new DataResponseListener SearchResult () { 

 @Override 

 public void onErrorResponse(VolleyError error) { 

 Log.v("zgy","======onErrorResponse====="+error); 

 mDialog.dismiss(); 

 @Override 

 public void onResponse(SearchResult response) { 

 Log.v("zgy","======onResponse====="+response); 

 mSongList.addAll(response.getData().getInfo()) ; 

 mAdapter.notifyDataSetChanged(); 

 mDialog.dismiss(); 

 @Override 

 public void postData(String data) { 

 mShowPostData.setText(data); 

 }); 

 }

5548.html

app程序应用开发手机开发无线开发移动端开发