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

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

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--
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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

------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 
Content-Disposition: form-data; name="cm" 
 
100672 
------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1--
  • 1
  • 2
  • 3
  • 4
  • 5

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

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

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

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

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

"/r/n" ;
  • 1

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

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

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

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

说明:在所有的数据结束之后,需要有这个结尾标志。 
如果有多个参数,则重复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; 
    } 
 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Volley 对数据的封装

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

public byte[] getBody() throws AuthFailureError {}
  • 1

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

protected Map<String, String> getParams() throws AuthFailureError {}
  • 1

最核心的方法也就在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 < N ;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(); 
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

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

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

所以的重写下面方法为

public String getBodyContentType() { 
        return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY; 
    }
  • 1
  • 2
  • 3

同样,我们还是前面我们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 < N ;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; 
} 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106

表单提交接口

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

    /** 
*  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) ; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

测试

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); 
} 
}); 
}

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/5548.html

(0)
上一篇 2021年7月16日
下一篇 2021年7月16日

相关推荐

发表回复

登录后才能评论