现在的位置: 首页 > 综合 > 正文

java 提交数据表单

2013年09月01日 ⁄ 综合 ⁄ 共 11729字 ⁄ 字号 评论关闭
文章目录

(1)使用Java程序自动发博客的尝试-带附件

这个文章主要是熟悉Upload数据时的数据格式,许多的upload组件看上去很神秘,其实内部并不复杂。

一、我们先来看看当表单

类型为multipart/form-data

<form action="/admin/blogs" enctype="multipart/form-data" id="blog_form" method="post"> 
// 标题
<input class="text required min-length-3 bad-words" id="blog_title" maxlength="50"
name
="blog[title]" size="45" style="width:400px;" type="text" />
// 内容
<textarea class="validate-richeditor bad-words min-length-5" cols="40" id="editor_body"
name="blog[body]" rows="20" style="width: 510px; height: 350px;"></textarea>
</form>

二、拿到的一个数据

  1. ...
  2. Content-Type: multipart/form-data; boundary=---------------------------29510474520649
  3. Content-Length: 4281
  4. -----------------------------29510474520649
  5. Content-Disposition: form-data; name="blog[blog_type]"
  6. 1
  7. -----------------------------29510474520649
  8. Content-Disposition: form-data; name="blog[title]"
  9. 测试博客标题
  10. -----------------------------29510474520649
  11. Content-Disposition: form-data; name="blog[category_id]"
  12. -----------------------------29510474520649
  13. Content-Disposition: form-data; name="blog[user_tags]"
  14. -----------------------------29510474520649
  15. Content-Disposition: form-data; name="auto_save_id"
  16. -----------------------------29510474520649
  17. Content-Disposition: form-data; name="blog[bbcode]"
  18. true
  19. -----------------------------29510474520649
  20. Content-Disposition: form-data; name="blog[body]"
  21. 测试博客的内容,
  22. 附件为java2000.net的LOGO
  23. -----------------------------29510474520649
  24. Content-Disposition: form-data; name="blog[diggable]"
  25. 0
  26. -----------------------------29510474520649
  27. Content-Disposition: form-data; name="blog[forum_id]"
  28. -----------------------------29510474520649
  29. Content-Disposition: form-data; name=""filename=""
  30. Content-Type: application/octet-stream
  31. -----------------------------29510474520649
  32. Content-Disposition: form-data; name="attachments[][remark]"
  33. java2000.net的LOGO
  34. -----------------------------29510474520649
  35. Content-Disposition: form-data; name="attachments[][uploaded_data]"filename="www.java2000.net.gif"
  36. Content-Type: image/gif
  37. GIF89a。。。。。
  38. -----------------------------29510474520649
  39. Content-Disposition: form-data; name="commit"
  40. 提交
  41. -----------------------------29510474520649--

解释一下,其中的
Content-Type: multipart/form-data; boundary=---------------------------29510474520649
是关键,前面代表提交数据的类型,后面是分割边界的标志boundary
后面的数据,使用 -- 加上 boundary 作为分割标志
最后一行数据,使用 -- 加上boundary 再加上 -- 作为结尾标志

三,根据数据我们配置了一个提交数据的模板

  1. {BOUNDARY}{BR}Content-Disposition: form-data; name="blog[blog_type]"{BR}{BR}1{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[title]"{BR}{BR}{TITLE}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[category_id]"{BR}{BR}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[user_tags]"{BR}{BR}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="auto_save_id"{BR}{BR}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[bbcode]"{BR}{BR}true{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[body]"{BR}{BR}{CONTENT}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[forum_id]"{BR}{BR}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="commit"{BR}{BR}{SUBMIT}{BR}{BOUNDARY}--{BR}

其中的 
{BOUNDARY} 是分割标志,
{BR}是换行
{TITLE}是标题
{CONTENT}是内容
{SUBMIT}是提交的按钮标签

四、用程序提交数据
  对于cookie的操作和获取我就不多说了,请自行参考前一个文章。

1 这里只贴出来一个简单的配置结果

  1. host=zhaoxq-java2000-net.javaeye.com
  2. charset=UTF-8
  3. cookie=    
  4. post=http://zhaoxq-java2000-net.javaeye.com/admin/blogs/new
  5. action=http://zhaoxq-java2000-net.javaeye.com/admin/blogs
  6. message={BOUNDARY}{BR}Content-Disposition: form-data; name="blog[blog_type]"{BR}{BR}1{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[title]"{BR}{BR}{TITLE}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[category_id]"{BR}{BR}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[user_tags]"{BR}{BR}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="auto_save_id"{BR}{BR}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[bbcode]"{BR}{BR}true{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[body]"{BR}{BR}{CONTENT}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="blog[forum_id]"{BR}{BR}{BR}{BOUNDARY}{BR}Content-Disposition: form-data; name="commit"{BR}{BR}{SUBMIT}{BR}{BOUNDARY}--{BR}

2 发布的程序

  1. package net.java2000.blogsender.javaeye;
  2. import java.io.IOException;
  3. import java.util.Properties;
  4. import net.java2000.blogsender.Sender;
  5. import net.java2000.blogsender.baidu.BaiduSender;
  6. import net.java2000.blogsender.util.PostUtil;
  7. public class JavaEyeSender implements Sender {
  8.   private String host;
  9.   private String charset;
  10.   private String post;
  11.   private String action;
  12.   private String cookie;
  13.   private String message;
  14.   private String boundary;
  15.   public boolean send(String title, String content) {
  16.     return PostUtil.postMultiPart(host, charset, action, post, cookie, message, boundary, title, content);
  17.   }
  18.   public JavaEyeSender() {
  19.     Properties p = new Properties();
  20.     try {
  21.       p.load(BaiduSender.class.getResourceAsStream("javaeye.properties"));
  22.       host = p.getProperty("host");
  23.       charset = p.getProperty("charset");
  24.       post = p.getProperty("post");
  25.       action = p.getProperty("action");
  26.       cookie = p.getProperty("cookie");
  27.       message = p.getProperty("message");
  28.       boundary = "---------------------------" + System.currentTimeMillis();
  29.       String boundary1 = "--" + boundary;
  30.       message = message.replace("{BR}""/r/n");
  31.       message = message.replace("{BOUNDARY}", boundary1);
  32.       message = message.replace("{SUBMIT}""提交");
  33.     } catch (IOException e) {
  34.       e.printStackTrace();
  35.     }
  36.   }
  37.   public static void main(String[] args) {
  38.     Sender sender = new JavaEyeSender();
  39.     sender.send("测试测试""测试[b]测试测[/b]试/r/n121212/r/n32324324/r/n65465465465/r/n");
  40.   }
  41. }

3 发布数据的辅助类

  1.   public static boolean postMultiPart(String host, String charset, String postURL, String referer, String cookies, String message, String boundary, String title, String content) {
  2.     try {
  3.       URL url = new URL(postURL);
  4.       HttpURLConnection con = (HttpURLConnection) url.openConnection();
  5.       con.setDoOutput(true); // POST方式
  6.       con.setDoInput(true);
  7.       con.setRequestMethod("POST");
  8.       con.addRequestProperty("Host", host);
  9.       con.addRequestProperty("Referer", referer);
  10.       con.addRequestProperty("Cookie", cookies.trim());
  11.       con.addRequestProperty("Content-Type""multipart/form-data; boundary=" + boundary);
  12.       message = message.replace("{TITLE}", title);
  13.       message = message.replace("{CONTENT}", content);
  14.       con.addRequestProperty("Content-Length", Integer.toString(message.getBytes(charset).length));
  15.       OutputStream os = con.getOutputStream(); // 输出流,写数据
  16.       os.write(message.getBytes(charset));
  17.       os.flush();
  18.       BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), charset)); // 读取结果
  19.       String line;
  20.       while ((line = reader.readLine()) != null) {
  21.         System.out.println(line);
  22.         // break;
  23.       }
  24.       os.close();
  25.       reader.close();
  26.       return true;
  27.     } catch (Exception ex) {
  28.       ex.printStackTrace();
  29.       return false;
  30.     }
  31.   }

五、总结:
  我简单说明了提交upload数据的格式已经实现的一个简单方法。有兴趣的人可以自行看看html的协议内容,里面讲解的很清楚。你会对upload不在神秘。
  顺便说一句,对于二进制数据的提交,大部分会进行Base64或者QP的编码,这样整个数据里面将只有ASCII码,而不会出现怪字符。不过有些客户端,不会这么做。

这个数据格式与我们邮件的内部格式非常类似。

原文地址:http://www.java2000.net/p8849

 

 

(2)

使用Java程序自动发博客的尝试

手里有好多的技术资料,不想一个一个的粘贴到那里,包括在CSDN的一些代码,想复制一份到那里,留个备份。决定使用Java程序直接向博客里发数据。
需要解决的几个问题
1 认证
2 发送数据
3 解决发送太频繁的问题

一 认证

百度支持保存用户名和密码,也就是自动登录,所以其登录信息肯定保存在cookie里面。
如何获得cookie呢?我提供2个方法
1 你去你机器的IE的临时目录里查找cookie吧,比如
C:/Documents and Settings/Administrator/Local Settings/Temporary Internet Files

里面有许多的cookie文件,具体是哪个?你自己找吧,我就不多说了。

2 用Firefox + Firebug 你只要看一下网络链接数据的Header,就可以看到cookie部分的数据了,比如

我们编写的程序,就需要把这个同时送过去,这样对方的程序就会自动识别登录的用户信息了。

二 发送数据

我们使用HttpURLConnection 的 POST方法进行数据的发送,注意其中关键的几个部分

  1. Host 这个一定要设置成提交的主机相同,因为对于虚拟主机,这个最关键了
  2. Referer 这个一般被用来防止盗链,所以一定要设置为一个属于他站点的链接,比如发贴的页面链接
  3. Cookie 这个是认证的关键,否则发贴后会让你登录的
  4. Content-Type 对于普通的POST提交,使用 application/x-www-form-urlencoded,如果是带附件的提交,则需要使用multipart/form-data; boundary=XXXXXXX, 其中的XXXXXX是数据的边缘分界标志
  5. Content-Length 提交的数据长度,字节数

数据没啥特殊的,只要符合表单的要求就可以了,比如百度博客的数据格式如下
ct=1&cm=1&spRefURL=http%3A%2F%2Fhi.baidu.com%2Fjava2000%25255Fnet%2Fcreat%2Fblog%2F&spBlogTitle={TITLE}&spBlogText={CONTENT}&spBlogCatName=%C4%AC%C8%CF%B7%D6%C0%E0&spIsCmtAllow=1&spBlogPower=0&spVcode=&spVerifyKey=&tj=+%B7%A2%B1%ED%CE%C4%D5%C2+

其中的{TITLE}应该替换为我们自己的主题,{CONTENT}替换为我们自己的内容。
下面是发送数据的代码

  1.   /**
  2.    * 发送普通的POST数据
  3.    * 
  4.    * @param host
  5.    *          主机
  6.    * @param charset
  7.    *          编码
  8.    * @param postURL
  9.    *          表单提交的地址URL
  10.    * @param referer
  11.    *          来源,使用填写表单的页面
  12.    * @param cookies
  13.    *          认证数据
  14.    * @param message
  15.    *          发送的数据模板
  16.    * @param title
  17.    *          标题,将替换模板里的对应位置
  18.    * @param content
  19.    *          内容,将替换模板里的对应位置
  20.    * @return 成功返回true
  21.    */
  22.   public static boolean post(String host, String charset, String postURL, String referer, String cookies, String message, String title, String content) {
  23.     try {
  24.       URL url = new URL(postURL);
  25.       HttpURLConnection con = (HttpURLConnection) url.openConnection();
  26.       con.setDoOutput(true); // POST方式
  27.       con.setRequestMethod("POST");
  28.       con.addRequestProperty("Host", host);
  29.       con.addRequestProperty("Referer", referer);
  30.       con.addRequestProperty("Cookie", cookies);
  31.       con.addRequestProperty("Content-Type""application/x-www-form-urlencoded");
  32.       message = message.replace("{TITLE}", URLEncoder.encode(title, charset));
  33.       message = message.replace("{CONTENT}", URLEncoder.encode(content, charset));
  34.       con.addRequestProperty("Content-Length", Integer.toString(message.getBytes(charset).length));
  35.       OutputStream os = con.getOutputStream(); // 输出流,写数据
  36.       os.write(message.getBytes(charset));
  37.       os.flush();
  38.       BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), charset)); // 读取结果
  39.       String line;
  40.       while ((line = reader.readLine()) != null) {
  41.         // System.out.println(line); // 我这里不再读取每一样了,大家测试时可以去掉注释掉的break,并去掉这里的注释
  42.         break;
  43.       }
  44.       os.close();
  45.       reader.close();
  46.       return true;
  47.     } catch (Exception ex) {
  48.       ex.printStackTrace();
  49.       return false;
  50.     }
  51.   }

给大家提供一个参考的参数数据

  1. host=hi.baidu.com
  2. charset=GBK
  3. cookie=
  4. post=http://hi.baidu.com/java2000%5Fnet/creat/blog/
  5. action=http://hi.baidu.com/java2000%5Fnet/commit
  6. message=ct=1&cm=1&spRefURL=http%3A%2F%2Fhi.baidu.com%2Fjava2000%25255Fnet%2Fcreat%2Fblog%2F&spBlogTitle={TITLE}&spBlogText={CONTENT}&spBlogCatName=%C4%AC%C8%CF%B7%D6%C0%E0&spIsCmtAllow=1&spBlogPower=0&spVcode=&spVerifyKey=&tj=+%B7%A2%B1%ED%CE%C4%D5%C2+

其中的cookie我去掉了,哈哈。 post 就是填写博客的地址,action就是提交博客的地址,其它的大家自己看吧

发送的接口

  1. package net.java2000.blogsender;
  2. public interface Sender {
  3.   public boolean send(String title, String message);
  4. }

我们给百度博客的实现类

  1. package net.java2000.blogsender.baidu;
  2. import java.io.IOException;
  3. import java.util.Properties;
  4. import net.java2000.blogsender.Sender;
  5. import net.java2000.blogsender.util.PostUtil;
  6. /**
  7.  * 百度的博客发送实现类
  8.  * 
  9.  * @author 赵学庆,Java世纪网(java2000.net)
  10.  * 
  11.  */
  12. public class BaiduSender implements Sender {
  13.   private String host;
  14.   private String charset;
  15.   private String post;
  16.   private String action;
  17.   private String cookie;
  18.   private String message;
  19.   public boolean send(String title, String content) {
  20.     content = content.replace("/r/n""<br/>");
  21.     content = content.replace("/n""<br/>");
  22.     return PostUtil.post(host, charset, action, post, cookie, message, title, content);
  23.   }
  24.   public BaiduSender() {
  25.     Properties p = new Properties();
  26.     try {
  27.       p.load(BaiduSender.class.getResourceAsStream("baidu.properties"));
  28.       host = p.getProperty("host");
  29.       charset = p.getProperty("charset");
  30.       post = p.getProperty("post");
  31.       action = p.getProperty("action");
  32.       cookie = p.getProperty("cookie");
  33.       message = p.getProperty("message");
  34.     } catch (IOException e) {
  35.       e.printStackTrace();
  36.     }
  37.   }
  38. }

三 解决发送太频繁的问题
  我测试,百度的文章最快需要1分钟才能发一个,否则会因为发送太快而让你输入验证码,那个我可破解不了。
所以我们的程序应该发送一个之后,休眠1分钟再发另外一个。

小结

用程序做类似的东西基本都差不多,都是模拟浏览器进行数据的提交。
JavaEye的博客发送程序也快弄好了,整理完毕后也发上来和大家分享。

抱歉!评论已关闭.