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

数据包:

  1. Connection: keep-alive
  2. Content-Length: 123
  3. X-Requested-With: ShockwaveFlash/16.0.0.296
  4. User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36
  5. Content-Type: multipart/form-data; boundary=----------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
  6. Accept: */*
  7. Accept-Encoding: gzip, deflate
  8. Accept-Language: zh-CN,zh;q=0.8
  9. Cookie: bdshare_firstime=1409052493497
  10. ------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
  11. Content-Disposition: form-data; name="position"
  12. 1425264476444
  13. ------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
  14. Content-Disposition: form-data; name="editorIndex"
  15. ue_con_1425264252856
  16. ------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
  17. Content-Disposition: form-data; name="cm"
  18. 100672
  19. ------------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请求头,在网络请求中已经为我们封装好了;可以看到这里总共是提交了三条数据,每一条数据的格式都是一样的,所以我们只需要分析一条数据即可,这里拿最后一条数据来说,因为在所有的数据之后还有一个结尾的标志。

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

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

1、第一行:

  1. "--" + boundary + "\r\n" ;
    • 1

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

2、第二行:

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

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

3、第三行:

  1. "\r\n" ;
    • 1

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

第四行:

  1. "参数的值" + "\r\n" ;
    • 1

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

结尾行:

  1. "--" + boundary + "--" + "\r\n" ;
    • 1

说明:在所有的数据结束之后,需要有这个结尾标志。 

如果有多个参数,则重复1、2、3、4,直至最后一个参数的最后加上结尾行。

参数实体类

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

  1. /**
  2. * Created by gyzhong on 15/3/2.
  3. */
  4. /*表单提交的参数*/
  5. public class FormText {
  6. /*参数的名称*/
  7. private String mName ;
  8. /*参数的值*/
  9. private String mValue ;
  10. public FormText(String mName, String mValue) {
  11. this.mName = mName;
  12. this.mValue = mValue;
  13. }
  14. public String getName() {
  15. return mName;
  16. }
  17. public String getValue() {
  18. return mValue;
  19. }
  20. }
    • 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 的时候,需要重写获取实体的方法

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

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

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

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

  1. @Override
  2. public byte[] getBody() throws AuthFailureError {
  3. if (mListItem == null||mListItem.size() == 0){
  4. return super.getBody() ;
  5. }
  6. ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
  7. int N = mListItem.size() ;
  8. FormText formText ;
  9. for (int i = 0; i < N ;i++){
  10. formText = mListItem.get(i) ;
  11. StringBuffer sb= new StringBuffer() ;
  12. /*第一行:"--" + boundary + "\r\n" ;*/
  13. sb.append("--"+BOUNDARY);
  14. sb.append("\r\n") ;
  15. /*第二行:"Content-Disposition: form-data; name="参数的名称"" + "\r\n" ;*/
  16. sb.append("Content-Disposition: form-data;");
  17. sb.append("name=\"");
  18. sb.append(formText.getName()) ;
  19. sb.append("\"") ;
  20. sb.append("\r\n") ;
  21. /*第三行:"\r\n" ;*/
  22. sb.append("\r\n") ;
  23. /*第四行:"参数的值" + "\r\n" ;*/
  24. sb.append(formText.getValue()) ;
  25. sb.append("\r\n") ;
  26. try {
  27. bos.write(sb.toString().getBytes("utf-8"));
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. /*结尾行:"--" + boundary + "--" + "\r\n" ;*/
  33. String endLine = "--" + BOUNDARY + "--"+ "\r\n" ;
  34. try {
  35. bos.write(endLine.toString().getBytes("utf-8"));
  36. } catch (IOException e) {
  37. e.printStackTrace();
  38. }
  39. Log.v("zgy","=====formText====\n"+bos.toString()) ;
  40. return bos.toByteArray();
  41. }
    • 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 头部中声明内容类型为表单数据

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

所以的重写下面方法为

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

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

  1. /**
  2. * Created by gyzhong on 15/3/2.
  3. */
  4. public class PostFormRequest<T> extends Request<T> {
  5. /**
  6. * 正确数据的时候回掉用
  7. */
  8. private ResponseListener mListener ;
  9. /*用来解析 json 用的*/
  10. private Gson mGson ;
  11. /*在用 gson 解析 json 数据的时候,需要用到这个参数*/
  12. private Type mClazz ;
  13. /*请求 数据通过参数的形式传入*/
  14. private List<FormText> mListItem ;
  15. private String BOUNDARY = "---------8888888888888"; //数据分隔线
  16. private String MULTIPART_FORM_DATA = "multipart/form-data";
  17. public PostFormRequest(String url, List<FormText> listItem, Type type, ResponseListener listener) {
  18. super(Method.POST, url, listener);
  19. this.mListener = listener ;
  20. mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() ;
  21. mClazz = type ;
  22. setShouldCache(false);
  23. mListItem = listItem ;
  24. }
  25. /**
  26. * 这里开始解析数据
  27. * @param response Response from the network
  28. * @return
  29. */
  30. @Override
  31. protected Response<T> parseNetworkResponse(NetworkResponse response) {
  32. try {
  33. T result ;
  34. String jsonString =
  35. new String(response.data, HttpHeaderParser.parseCharset(response.headers));
  36. Log.v("zgy", "====SearchResult===" + jsonString);
  37. result = mGson.fromJson(jsonString,mClazz) ;
  38. return Response.success(result,
  39. HttpHeaderParser.parseCacheHeaders(response));
  40. } catch (UnsupportedEncodingException e) {
  41. return Response.error(new ParseError(e));
  42. }
  43. }
  44. /**
  45. * 回调正确的数据
  46. * @param response The parsed response returned by
  47. */
  48. @Override
  49. protected void deliverResponse(T response) {
  50. mListener.onResponse(response);
  51. }
  52. @Override
  53. public byte[] getBody() throws AuthFailureError {
  54. if (mListItem == null||mListItem.size() == 0){
  55. return super.getBody() ;
  56. }
  57. ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
  58. int N = mListItem.size() ;
  59. FormText formText ;
  60. for (int i = 0; i < N ;i++){
  61. formText = mListItem.get(i) ;
  62. StringBuffer sb= new StringBuffer() ;
  63. /*第一行:"--" + boundary + "\r\n" ;*/
  64. sb.append("--"+BOUNDARY);
  65. sb.append("\r\n") ;
  66. /*第二行:"Content-Disposition: form-data; name="参数的名称"" + "\r\n" ;*/
  67. sb.append("Content-Disposition: form-data;");
  68. sb.append("name=\"");
  69. sb.append(formText.getName()) ;
  70. sb.append("\"") ;
  71. sb.append("\r\n") ;
  72. /*第三行:"\r\n" ;*/
  73. sb.append("\r\n") ;
  74. /*第四行:"参数的值" + "\r\n" ;*/
  75. sb.append(formText.getValue()) ;
  76. sb.append("\r\n") ;
  77. try {
  78. bos.write(sb.toString().getBytes("utf-8"));
  79. } catch (IOException e) {
  80. e.printStackTrace();
  81. }
  82. }
  83. /*结尾行:"--" + boundary + "--" + "\r\n" ;*/
  84. String endLine = "--" + BOUNDARY + "--"+ "\r\n" ;
  85. try {
  86. bos.write(endLine.toString().getBytes("utf-8"));
  87. } catch (IOException e) {
  88. e.printStackTrace();
  89. }
  90. Log.v("zgy","=====formText====\n"+bos.toString()) ;
  91. return bos.toByteArray();
  92. }
  93. /*获取内容类型,这里为表单类型*/
  94. @Override
  95. public String getBodyContentType() {
  96. return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY;
  97. }
  98. }
  99.  
    • 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

表单提交接口

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

  1. /**
  2. * minong 测试post表单提交接口
  3. * @param value 测试数据
  4. * @param listener 回调接口,包含错误回调和正确的数据回调
  5. */
  6. public static void postFormMiNongApi(String value,ResponseListener listener){
  7. List<FormText> formTextList = new ArrayList<FormText>() ;
  8. formTextList.add(new FormText(" test",value));
  9. Request request = new PostFormRequest(Constant.MiNonghost,formTextList,new TypeToken<SearchResult>(){}.getType(),listener) ;
  10. VolleyUtil.getRequestQueue().add(request) ;
  11. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

测试

PostFormActivity.java的测试代码如下

  1. public class PostFormActivity extends ActionBarActivity {
  2. private ListView mListView ;
  3. private SongAdapter mAdapter ;
  4. private List<SongDetail> mSongList ;
  5. private ProgressDialog mDialog ;
  6. private View mHeaderView ;
  7. private TextView mShowPostData ;
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_post_form);
  12. mSongList = new ArrayList<SongDetail>() ;
  13. mListView = (ListView) findViewById(R.id.id_list_view);
  14. mAdapter = new SongAdapter(this,mSongList) ;
  15. mHeaderView = getLayoutInflater().inflate(R.layout.list_header_item,null) ;
  16. mShowPostData = (TextView) mHeaderView.findViewById(R.id.id_post_data) ;
  17. mListView.addHeaderView(mHeaderView);
  18. mListView.setAdapter(mAdapter);
  19. mDialog = new ProgressDialog(this) ;
  20. mDialog.setMessage("数据提交中...");
  21. mDialog.show() ;
  22. /*请求网络获取数据*/
  23. MiNongApi.postFormMiNongApi(" minongbang",new DataResponseListener<SearchResult>() {
  24. @Override
  25. public void onErrorResponse(VolleyError error) {
  26. Log.v("zgy","======onErrorResponse====="+error);
  27. mDialog.dismiss();
  28. }
  29. @Override
  30. public void onResponse(SearchResult response) {
  31. Log.v("zgy","======onResponse====="+response);
  32. mSongList.addAll(response.getData().getInfo()) ;
  33. mAdapter.notifyDataSetChanged();
  34. mDialog.dismiss();
  35. }
  36. @Override
  37. public void postData(String data) {
  38. mShowPostData.setText(data);
  39. }
  40. });
  41. }

Volley解析之表单提交篇的更多相关文章

  1. 用python模拟登录(解析cookie + 解析html + 表单提交 + 验证码识别 + excel读写 + 发送邮件)

    老婆大人每个月都要上一个网站上去查数据,然后做报表. 为了减轻老婆大人的工作压力,所以我决定做个小程序,减轻我老婆的工作量. 准备工作 1.tesseract-ocr 这个工具用来识别验证码,非常好用 ...

  2. Django框架之第二篇--app注册、静态文件配置、form表单提交、pycharm连接数据库、django使用mysql数据库、表字段的增删改查、表数据的增删改查

    本节知识点大致为:静态文件配置.form表单提交数据后端如何获取.request方法.pycharm连接数据库,django使用mysql数据库.表字段的增删改查.表数据的增删改查 一.创建app,创 ...

  3. 深入理解ajax系列第八篇——表单提交

    前面的话 在以前,网站的用户与后端交互的主要方式是通过HTML表单的使用.表单的引入在1993年,由于其简单性和易用性,直到电子商务出现之前一直保持着重要位置.理解表单提交,对于更深入地理解ajax是 ...

  4. nodejs学习之表单提交(1)

    nodejs作为一门后端语言,接触的最多的是它的框架,但是它本身的api我觉得更是非学不可,所有才有了这篇文章 表单提交是最基本的也是最实用的入门实例 HTML: <!DOCTYPE html& ...

  5. Swift3.0服务端开发(二) 静态文件添加、路由配置以及表单提交

    今天博客中就来聊一下Perfect框架的静态文件的添加与访问,路由的配置以及表单的提交.虽然官网上有聊静态文件的访问的部分,但是在使用Perfect框架来访问静态文件时还是有些点需要注意的,这些关键点 ...

  6. SpringMVC(十四):SpringMVC 与表单提交(post/put/delete的用法);form属性设置encrypt='mutilpart/form-data'时,如何正确配置web.xml才能以put方式提交表单

    SpringMVC 与表单提交(post/put/delete的用法) 为了迎合Restful风格,提供的接口可能会包含:put.delete提交方式.在springmvc中实现表单以put.dele ...

  7. 天河微信小程序入门《四》:融会贯通,form表单提交数据库

    天河在阔别了十几天之后终于又回来了.其实这篇文章里的demo是接着(天河微信小程序入门<三>)后面就做了的,但是因为最近在做别的项目,所以就偷懒没有发出来.放到今天来看,从前台提交数据到数 ...

  8. [转]django自定义表单提交

    原文网址:http://www.cnblogs.com/retop/p/4677148.html 注:本人使用的Django1.8.3版本进行测试 除了使用Django内置表单,有时往往我们需要自定义 ...

  9. AngularJS 1.2.x 学习笔记(表单校验篇)

    https://my.oschina.net/cokolin/blog/526911 摘要: 本文首发于 blog.csdn.net/vipshop_ebs/article/details/39472 ...

随机推荐

  1. sizeof(结构体)和内存对齐以及位域

    Win32平台下的微软C编译器的对齐策略: 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除: 备注:编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能被该 ...

  2. Android必知必会-App 常用图标尺寸规范汇总

    若移动端访问不佳,请使用 –> Github版 内容持续更新中,更新日期:2016-08-11 1. 程序启动图标(icon launcher) 放在mipmap-*dpi下,文件名为ic_la ...

  3. 使用OpenCV读、操作、写图像并与bash合作对某个目录下所有图像进行类似处理

    我门要对某个目录下所有图像文件进行统一处理,如果图像的数量过多,那么手动地一张张处理就会显得有些麻烦.本文使用OpenCV和bash来完成我们指定的任务. 任务 将目录A下的所有统一格式的jpg图像变 ...

  4. CCSpriteBatchNode中存放元素的一点理解

    该对象只能包含基于CCSprite的对象,并且该要求适用于一切子孙对象.即加入CCSpriteBatchNode的任何对象都必须是CCSprite或其子类. 比如CCSpriteBatchNode包含 ...

  5. memcached实战系列(七)理解Memcached的数据过期方式、新建过程、查找过程

    1.1.1. 新建Item分配内存过程 1:快速定位slab classid,先计算Item长度 key键长+flag+suffix(16字节)+value值长+结构大小(32字节),如90byte ...

  6. Android中常用开发工具类—持续更新...

    一.自定义ActionBar public class ActionBarTool { public static void setActionBarLayout(Activity act,Conte ...

  7. (一〇二)静态库(.a)的打包

    库是代码的集合,根据代码公开程度,分为开源库和闭源库. 其中闭源库主要包括静态库和动态库,是经过编译的二进制文件,看不到具体实现. 静态库的拓展名是.a或者.framework,动态库则是.dylib ...

  8. Android 导入v7包常见错误,以及项目引用v7包错误解决

    android下v4    v7   v21等包是android系统的扩展支持包,就想windows的系统补丁一个道理. android的扩展包主要是用来兼容低版本的,比如android3.0以后出现 ...

  9. iOS中 图文混排/自定义图文混排 作者:韩俊强

    指示根视图:(准备几张图片,把label加载在window上) CustomLable *label = [[CustomLable alloc]initWithFrame:CGRectMake(0, ...

  10. Html标签中thead、tbody、tfoot的作用

    Html标签中thead.tbody.tfoot的作用 为了让大表格(table)在下载的时候可以分段的显示,就是说在浏览器解析HTML时,table是作为一个整体解释的,使用TBODY可以优化显示. ...