请使用新发布的校内网相册批量下载工具 http://ldsea.cn/xiaonei-album/
完善校内助手,可以完成校内网相册批量下载
思想来源:今天看到很多人贴了地震的相关图片,想保存下来,可是一个一个保存太费事了,就写了代码来批量下载


下载地址:http://www.ldsea.cn/xiaonei-album/
完善校内助手,可以完成校内网相册批量下载
思想来源:今天看到很多人贴了地震的相关图片,想保存下来,可是一个一个保存太费事了,就写了代码来批量下载


下载地址:http://www.ldsea.cn/xiaonei-album/
此文也是较早之前写的文章!
一般的情况下我们都是使用IE或者Navigator浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据等等。所访问的这些页面有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要认证以及是一些通过加密方式传输,例如HTTPS。目前我们使用的浏览器处理这些情况都不会构成问题。不过你可能在某些时候需要通过程序来访问这样的一些页面,比如从别人的网页中“偷”一些数据;利用某些站点提供的页面来完成某种功能,例如说我们想知道某个手机号码的归属地而我们自己又没有这样的数据,因此只好借助其他公司已有的网站来完成这个功能,这个时候我们需要向网页提交手机号码并从返回的页面中解析出我们想要的数据来。如果对方仅仅是一个很简单的页面,那我们的程序会很简单,本文也就没有必要大张旗鼓的在这里浪费口舌。但是考虑到一些服务授权的问题,很多公司提供的页面往往并不是可以通过一个简单的URL就可以访问的,而必须经过注册然后登录后方可使用提供服务的页面,这个时候就涉及到COOKIE问题的处理。我们知道目前流行的动态网页技术例如ASP、JSP无不是通过COOKIE来处理会话信息的。为了使我们的程序能使用别人所提供的服务页面,就要求程序首先登录后再访问服务页面,这过程就需要自行处理cookie,想想当你用java.net.HttpURLConnection来完成这些功能时是多么恐怖的事情啊!况且这仅仅是我们所说的顽固的WEB服务器中的一个很常见的“顽固”!再有如通过HTTP来上传文件呢?不需要头疼,这些问题有了“它”就很容易解决了!
我们不可能列举所有可能的顽固,我们会针对几种最常见的问题进行处理。当然了,正如前面说到的,如果我们自己使用java.net.HttpURLConnection来搞定这些问题是很恐怖的事情,因此在开始之前我们先要介绍一下一个开放源码的项目,这个项目就是Apache开源组织中的httpclient,它隶属于Jakarta的commons项目,目前的版本是2.0RC2。commons下本来已经有一个net的子项目,但是又把httpclient单独提出来,可见http服务器的访问绝非易事。
Commons-httpclient项目就是专门设计来简化HTTP客户端与服务器进行各种通讯编程。通过它可以让原来很头疼的事情现在轻松的解决,例如你不再管是HTTP或者HTTPS的通讯方式,告诉它你想使用HTTPS方式,剩下的事情交给httpclient替你完成。本文会针对我们在编写HTTP客户端程序时经常碰到的几个问题进行分别介绍如何使用httpclient来解决它们,为了让读者更快的熟悉这个项目我们最开始先给出一个简单的例子来读取一个网页的内容,然后循序渐进解决掉前进中的所有问题。
1. 读取网页(HTTP/HTTPS)内容
下面是我们给出的一个简单的例子用来访问某个页面
在这个例子中首先创建一个HTTP客户端(HttpClient)的实例,然后选择提交的方法是GET或者POST,最后在HttpClient实例上执行提交的方法,最后从所选择的提交方法中读取服务器反馈回来的结果。这就是使用HttpClient的基本流程。其实用一行代码也就可以搞定整个请求的过程,非常的简单!
2. 以GET或者POST方式向网页提交参数
其实前面一个最简单的示例中我们已经介绍了如何使用GET或者POST方式来请求一个页面,本小节与之不同的是多了提交时设定页面所需的参数,我们知道如果是GET的请求方式,那么所有参数都直接放到页面的URL后面用问号与页面地址隔开,每个参数用&隔开,例如:http://java.sun.com?name=liudong&mobile=123456,但是当使用POST方法时就会稍微有一点点麻烦。本小节的例子演示向如何查询手机号码所在的城市,代码如下:
在上面的例子中页面http://www.imobile.com.cn/simcard.php需要一个参数是simcard,这个参数值为手机号码段,即手机号码的前七位,服务器会返回提交的手机号码对应的省份、城市以及其他详细信息。GET的提交方法只需要在URL后加入参数信息,而POST则需要通过NameValuePair类来设置参数名称和它所对应的值
3. 处理页面重定向
在JSP/Servlet编程中response.sendRedirect方法就是使用HTTP协议中的重定向机制。它与JSP中的的区别在于后者是在服务器中实现页面的跳转,也就是说应用容器加载了所要跳转的页面的内容并返回给客户端;而前者是返回一个状态码,这些状态码的可能值见下表,然后客户端读取需要跳转到的页面的URL并重新加载新的页面。就是这样一个过程,所以我们编程的时候就要通过HttpMethod.getStatusCode()方法判断返回值是否为下表中的某个值来判断是否需要跳转。如果已经确认需要进行页面跳转了,那么可以通过读取HTTP头中的location属性来获取新的地址。
状态码 对应HttpServletResponse的常量 详细描述
301 SC_MOVED_PERMANENTLY 页面已经永久移到另外一个新地址
302 SC_MOVED_TEMPORARILY 页面暂时移动到另外一个新的地址
303 SC_SEE_OTHER 客户端请求的地址必须通过另外的URL来访问
307 SC_TEMPORARY_REDIRECT 同SC_MOVED_TEMPORARILY
下面的代码片段演示如何处理页面的重定向
我们可以自行编写两个JSP页面,其中一个页面用response.sendRedirect方法重定向到另外一个页面用来测试上面的例子。
4. 模拟输入用户名和口令进行登录
本小节应该说是HTTP客户端编程中最常碰见的问题,很多网站的内容都只是对注册用户可见的,这种情况下就必须要求使用正确的用户名和口令登录成功后,方可浏览到想要的页面。因为HTTP协议是无状态的,也就是连接的有效期只限于当前请求,请求内容结束后连接就关闭了。在这种情况下为了保存用户的登录信息必须使用到Cookie机制。以JSP/Servlet为例,当浏览器请求一个JSP或者是Servlet的页面时,应用服务器会返回一个参数,名为jsessionid(因不同应用服务器而异),值是一个较长的唯一字符串的Cookie,这个字符串值也就是当前访问该站点的会话标识。浏览器在每访问该站点的其他页面时候都要带上jsessionid这样的Cookie信息,应用服务器根据读取这个会话标识来获取对应的会话信息。
对于需要用户登录的网站,一般在用户登录成功后会将用户资料保存在服务器的会话中,这样当访问到其他的页面时候,应用服务器根据浏览器送上的Cookie中读取当前请求对应的会话标识以获得对应的会话信息,然后就可以判断用户资料是否存在于会话信息中,如果存在则允许访问页面,否则跳转到登录页面中要求用户输入帐号和口令进行登录。这就是一般使用JSP开发网站在处理用户登录的比较通用的方法。
这样一来,对于HTTP的客户端来讲,如果要访问一个受保护的页面时就必须模拟浏览器所做的工作,首先就是请求登录页面,然后读取Cookie值;再次请求登录页面并加入登录页所需的每个参数;最后就是请求最终所需的页面。当然在除第一次请求外其他的请求都需要附带上Cookie信息以便服务器能判断当前请求是否已经通过验证。说了这么多,可是如果你使用httpclient的话,你甚至连一行代码都无需增加,你只需要先传递登录信息执行登录过程,然后直接访问想要的页面,跟访问一个普通的页面没有任何区别,因为类HttpClient已经帮你做了所有该做的事情了,太棒了!下面的例子实现了这样一个访问的过程。
6. 通过HTTP上传文件
httpclient使用了单独的一个HttpMethod子类来处理文件的上传,这个类就是MultipartPostMethod,该类已经封装了文件上传的细节,我们要做的仅仅是告诉它我们要上传文件的全路径即可,下面的代码片段演示如何使用这个类。
上面代码中,targetFilePath即为要上传的文件所在的路径。
7. 访问启用认证的页面
我们经常会碰到这样的页面,当访问它的时候会弹出一个浏览器的对话框要求输入用户名和密码后方可,这种用户认证的方式不同于我们在前面介绍的基于表单的用户身份验证。这是HTTP的认证策略,httpclient支持三种认证方式包括:基本、摘要以及NTLM认证。其中基本认证最简单、通用但也最不安全;摘要认证是在HTTP 1.1中加入的认证方式,而NTLM则是微软公司定义的而不是通用的规范,最新版本的NTLM是比摘要认证还要安全的一种方式。
下面例子是从httpclient的CVS服务器中下载的,它简单演示如何访问一个认证保护的页面:
8. 多线程模式下使用httpclient
多线程同时访问httpclient,例如同时从一个站点上下载多个文件。对于同一个HttpConnection同一个时间只能有一个线程访问,为了保证多线程工作环境下不产生冲突,httpclient使用了一个多线程连接管理器的类:MultiThreadedHttpConnectionManager,要使用这个类很简单,只需要在构造HttpClient实例的时候传入即可,代码如下:
以后尽管访问client实例即可。
一般的情况下我们都是使用IE或者Navigator浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据等等。所访问的这些页面有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要认证以及是一些通过加密方式传输,例如HTTPS。目前我们使用的浏览器处理这些情况都不会构成问题。不过你可能在某些时候需要通过程序来访问这样的一些页面,比如从别人的网页中“偷”一些数据;利用某些站点提供的页面来完成某种功能,例如说我们想知道某个手机号码的归属地而我们自己又没有这样的数据,因此只好借助其他公司已有的网站来完成这个功能,这个时候我们需要向网页提交手机号码并从返回的页面中解析出我们想要的数据来。如果对方仅仅是一个很简单的页面,那我们的程序会很简单,本文也就没有必要大张旗鼓的在这里浪费口舌。但是考虑到一些服务授权的问题,很多公司提供的页面往往并不是可以通过一个简单的URL就可以访问的,而必须经过注册然后登录后方可使用提供服务的页面,这个时候就涉及到COOKIE问题的处理。我们知道目前流行的动态网页技术例如ASP、JSP无不是通过COOKIE来处理会话信息的。为了使我们的程序能使用别人所提供的服务页面,就要求程序首先登录后再访问服务页面,这过程就需要自行处理cookie,想想当你用java.net.HttpURLConnection来完成这些功能时是多么恐怖的事情啊!况且这仅仅是我们所说的顽固的WEB服务器中的一个很常见的“顽固”!再有如通过HTTP来上传文件呢?不需要头疼,这些问题有了“它”就很容易解决了!
我们不可能列举所有可能的顽固,我们会针对几种最常见的问题进行处理。当然了,正如前面说到的,如果我们自己使用java.net.HttpURLConnection来搞定这些问题是很恐怖的事情,因此在开始之前我们先要介绍一下一个开放源码的项目,这个项目就是Apache开源组织中的httpclient,它隶属于Jakarta的commons项目,目前的版本是2.0RC2。commons下本来已经有一个net的子项目,但是又把httpclient单独提出来,可见http服务器的访问绝非易事。
Commons-httpclient项目就是专门设计来简化HTTP客户端与服务器进行各种通讯编程。通过它可以让原来很头疼的事情现在轻松的解决,例如你不再管是HTTP或者HTTPS的通讯方式,告诉它你想使用HTTPS方式,剩下的事情交给httpclient替你完成。本文会针对我们在编写HTTP客户端程序时经常碰到的几个问题进行分别介绍如何使用httpclient来解决它们,为了让读者更快的熟悉这个项目我们最开始先给出一个简单的例子来读取一个网页的内容,然后循序渐进解决掉前进中的所有问题。
1. 读取网页(HTTP/HTTPS)内容
下面是我们给出的一个简单的例子用来访问某个页面
/*
* Created on 2003-12-14 by Liudong
*/
package http.demo;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
/**
* 最简单的HTTP客户端,用来演示通过GET或者POST方式访问某个页面
* @author Liudong
*/
public class SimpleClient {
public static void main(String[] args) throws IOException
{
HttpClient client = new HttpClient();
//设置代理服务器地址和端口 //client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port);
//使用GET方法,如果服务器需要通过HTTPS连接,那只需要将下面URL中的http换成https
HttpMethod method = new GetMethod("http://java.sun.com");
//使用POST方法
//HttpMethod method = new PostMethod("http://java.sun.com");
client.executeMethod(method);
//打印服务器返回的状态
System.out.println(method.getStatusLine());
//打印返回的信息
System.out.println(method.getResponseBodyAsString());
//释放连接
method.releaseConnection();
}
}
* Created on 2003-12-14 by Liudong
*/
package http.demo;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
/**
* 最简单的HTTP客户端,用来演示通过GET或者POST方式访问某个页面
* @author Liudong
*/
public class SimpleClient {
public static void main(String[] args) throws IOException
{
HttpClient client = new HttpClient();
//设置代理服务器地址和端口 //client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port);
//使用GET方法,如果服务器需要通过HTTPS连接,那只需要将下面URL中的http换成https
HttpMethod method = new GetMethod("http://java.sun.com");
//使用POST方法
//HttpMethod method = new PostMethod("http://java.sun.com");
client.executeMethod(method);
//打印服务器返回的状态
System.out.println(method.getStatusLine());
//打印返回的信息
System.out.println(method.getResponseBodyAsString());
//释放连接
method.releaseConnection();
}
}
在这个例子中首先创建一个HTTP客户端(HttpClient)的实例,然后选择提交的方法是GET或者POST,最后在HttpClient实例上执行提交的方法,最后从所选择的提交方法中读取服务器反馈回来的结果。这就是使用HttpClient的基本流程。其实用一行代码也就可以搞定整个请求的过程,非常的简单!
2. 以GET或者POST方式向网页提交参数
其实前面一个最简单的示例中我们已经介绍了如何使用GET或者POST方式来请求一个页面,本小节与之不同的是多了提交时设定页面所需的参数,我们知道如果是GET的请求方式,那么所有参数都直接放到页面的URL后面用问号与页面地址隔开,每个参数用&隔开,例如:http://java.sun.com?name=liudong&mobile=123456,但是当使用POST方法时就会稍微有一点点麻烦。本小节的例子演示向如何查询手机号码所在的城市,代码如下:
/*
* Created on 2003-12-7 by Liudong
*/
package http.demo;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
/**
* 提交参数演示
* 该程序连接到一个用于查询手机号码所属地的页面
* 以便查询号码段1330227所在的省份以及城市
* @author Liudong
*/
public class SimpleHttpClient {
public static void main(String[] args) throws IOException
{
HttpClient client = new HttpClient();
client.getHostConfiguration().setHost("www.imobile.com.cn", 80, "http");
HttpMethod method = getPostMethod();//使用POST方式提交数据
client.executeMethod(method);
//打印服务器返回的状态
System.out.println(method.getStatusLine());
//打印结果页面
String response =
new String(method.getResponseBodyAsString().getBytes("8859_1"));
//打印返回的信息
System.out.println(response);
method.releaseConnection();
}
/**
* 使用GET方式提交数据
* @return
*/
private static HttpMethod getGetMethod(){
return new GetMethod("/simcard.php?simcard=1330227");
}
/**
* 使用POST方式提交数据
* @return
*/
private static HttpMethod getPostMethod(){
PostMethod post = new PostMethod("/simcard.php");
NameValuePair simcard = new NameValuePair("simcard", "1330227");
post.setRequestBody(new NameValuePair[] { simcard});
return post;
}
}
* Created on 2003-12-7 by Liudong
*/
package http.demo;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
/**
* 提交参数演示
* 该程序连接到一个用于查询手机号码所属地的页面
* 以便查询号码段1330227所在的省份以及城市
* @author Liudong
*/
public class SimpleHttpClient {
public static void main(String[] args) throws IOException
{
HttpClient client = new HttpClient();
client.getHostConfiguration().setHost("www.imobile.com.cn", 80, "http");
HttpMethod method = getPostMethod();//使用POST方式提交数据
client.executeMethod(method);
//打印服务器返回的状态
System.out.println(method.getStatusLine());
//打印结果页面
String response =
new String(method.getResponseBodyAsString().getBytes("8859_1"));
//打印返回的信息
System.out.println(response);
method.releaseConnection();
}
/**
* 使用GET方式提交数据
* @return
*/
private static HttpMethod getGetMethod(){
return new GetMethod("/simcard.php?simcard=1330227");
}
/**
* 使用POST方式提交数据
* @return
*/
private static HttpMethod getPostMethod(){
PostMethod post = new PostMethod("/simcard.php");
NameValuePair simcard = new NameValuePair("simcard", "1330227");
post.setRequestBody(new NameValuePair[] { simcard});
return post;
}
}
在上面的例子中页面http://www.imobile.com.cn/simcard.php需要一个参数是simcard,这个参数值为手机号码段,即手机号码的前七位,服务器会返回提交的手机号码对应的省份、城市以及其他详细信息。GET的提交方法只需要在URL后加入参数信息,而POST则需要通过NameValuePair类来设置参数名称和它所对应的值
3. 处理页面重定向
在JSP/Servlet编程中response.sendRedirect方法就是使用HTTP协议中的重定向机制。它与JSP中的的区别在于后者是在服务器中实现页面的跳转,也就是说应用容器加载了所要跳转的页面的内容并返回给客户端;而前者是返回一个状态码,这些状态码的可能值见下表,然后客户端读取需要跳转到的页面的URL并重新加载新的页面。就是这样一个过程,所以我们编程的时候就要通过HttpMethod.getStatusCode()方法判断返回值是否为下表中的某个值来判断是否需要跳转。如果已经确认需要进行页面跳转了,那么可以通过读取HTTP头中的location属性来获取新的地址。
状态码 对应HttpServletResponse的常量 详细描述
301 SC_MOVED_PERMANENTLY 页面已经永久移到另外一个新地址
302 SC_MOVED_TEMPORARILY 页面暂时移动到另外一个新的地址
303 SC_SEE_OTHER 客户端请求的地址必须通过另外的URL来访问
307 SC_TEMPORARY_REDIRECT 同SC_MOVED_TEMPORARILY
下面的代码片段演示如何处理页面的重定向
client.executeMethod(post);
System.out.println(post.getStatusLine().toString());
post.releaseConnection();
//检查是否重定向
int statuscode = post.getStatusCode();
if ((statuscode == HttpStatus.SC_MOVED_TEMPORARILY) ||
(statuscode == HttpStatus.SC_MOVED_PERMANENTLY) ||
(statuscode == HttpStatus.SC_SEE_OTHER) ||
(statuscode == HttpStatus.SC_TEMPORARY_REDIRECT)) {
//读取新的URL地址
Header header = post.getResponseHeader("location");
if (header != null) {
String newuri = header.getValue();
if ((newuri == null) || (newuri.equals("")))
newuri = "/";
GetMethod redirect = new GetMethod(newuri);
client.executeMethod(redirect);
System.out.println("Redirect:"+ redirect.getStatusLine().toString());
redirect.releaseConnection();
} else
System.out.println("Invalid redirect");
}
System.out.println(post.getStatusLine().toString());
post.releaseConnection();
//检查是否重定向
int statuscode = post.getStatusCode();
if ((statuscode == HttpStatus.SC_MOVED_TEMPORARILY) ||
(statuscode == HttpStatus.SC_MOVED_PERMANENTLY) ||
(statuscode == HttpStatus.SC_SEE_OTHER) ||
(statuscode == HttpStatus.SC_TEMPORARY_REDIRECT)) {
//读取新的URL地址
Header header = post.getResponseHeader("location");
if (header != null) {
String newuri = header.getValue();
if ((newuri == null) || (newuri.equals("")))
newuri = "/";
GetMethod redirect = new GetMethod(newuri);
client.executeMethod(redirect);
System.out.println("Redirect:"+ redirect.getStatusLine().toString());
redirect.releaseConnection();
} else
System.out.println("Invalid redirect");
}
我们可以自行编写两个JSP页面,其中一个页面用response.sendRedirect方法重定向到另外一个页面用来测试上面的例子。
4. 模拟输入用户名和口令进行登录
本小节应该说是HTTP客户端编程中最常碰见的问题,很多网站的内容都只是对注册用户可见的,这种情况下就必须要求使用正确的用户名和口令登录成功后,方可浏览到想要的页面。因为HTTP协议是无状态的,也就是连接的有效期只限于当前请求,请求内容结束后连接就关闭了。在这种情况下为了保存用户的登录信息必须使用到Cookie机制。以JSP/Servlet为例,当浏览器请求一个JSP或者是Servlet的页面时,应用服务器会返回一个参数,名为jsessionid(因不同应用服务器而异),值是一个较长的唯一字符串的Cookie,这个字符串值也就是当前访问该站点的会话标识。浏览器在每访问该站点的其他页面时候都要带上jsessionid这样的Cookie信息,应用服务器根据读取这个会话标识来获取对应的会话信息。
对于需要用户登录的网站,一般在用户登录成功后会将用户资料保存在服务器的会话中,这样当访问到其他的页面时候,应用服务器根据浏览器送上的Cookie中读取当前请求对应的会话标识以获得对应的会话信息,然后就可以判断用户资料是否存在于会话信息中,如果存在则允许访问页面,否则跳转到登录页面中要求用户输入帐号和口令进行登录。这就是一般使用JSP开发网站在处理用户登录的比较通用的方法。
这样一来,对于HTTP的客户端来讲,如果要访问一个受保护的页面时就必须模拟浏览器所做的工作,首先就是请求登录页面,然后读取Cookie值;再次请求登录页面并加入登录页所需的每个参数;最后就是请求最终所需的页面。当然在除第一次请求外其他的请求都需要附带上Cookie信息以便服务器能判断当前请求是否已经通过验证。说了这么多,可是如果你使用httpclient的话,你甚至连一行代码都无需增加,你只需要先传递登录信息执行登录过程,然后直接访问想要的页面,跟访问一个普通的页面没有任何区别,因为类HttpClient已经帮你做了所有该做的事情了,太棒了!下面的例子实现了这样一个访问的过程。
/*
* Created on 2003-12-7 by Liudong
*/
package http.demo;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.*;
import org.apache.commons.httpclient.methods.*;
/**
* 用来演示登录表单的示例
* @author Liudong
*/
public class FormLoginDemo {
static final String LOGON_SITE = "localhost";
static final int LOGON_PORT = 8080;
public static void main(String[] args) throws Exception{
HttpClient client = new HttpClient();
client.getHostConfiguration().setHost(LOGON_SITE, LOGON_PORT);
//模拟登录页面login.jsp->main.jsp
PostMethod post = new PostMethod("/main.jsp");
NameValuePair name = new NameValuePair("name", "ld");
NameValuePair pass = new NameValuePair("password", "ld");
post.setRequestBody(new NameValuePair[]{name,pass});
int status = client.executeMethod(post);
System.out.println(post.getResponseBodyAsString());
post.releaseConnection();
//查看cookie信息
CookieSpec cookiespec = CookiePolicy.getDefaultSpec();
Cookie[] cookies = cookiespec.match(LOGON_SITE, LOGON_PORT, "/", false, client.getState().getCookies());
if (cookies.length == 0) {
System.out.println("None");
} else {
for (int i = 0; i < cookies.length; i++) {
System.out.println(cookies[i].toString());
}
}
//访问所需的页面main2.jsp
GetMethod get = new GetMethod("/main2.jsp");
client.executeMethod(get);
System.out.println(get.getResponseBodyAsString());
get.releaseConnection();
}
}
5. 提交XML格式参数
提交XML格式的参数很简单,仅仅是一个提交时候的ContentType问题,下面的例子演示从文件文件中读取XML信息并提交给服务器的过程,该过程可以用来测试Web服务。
import java.io.File;
import java.io.FileInputStream;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.PostMethod;
/**
* 用来演示提交XML格式数据的例子
*/
public class PostXMLClient {
public static void main(String[] args) throws Exception {
File input = new File(“test.xml”);
PostMethod post = new PostMethod(“http://localhost:8080/httpclient/xml.jsp”);
// 设置请求的内容直接从文件中读取
post.setRequestBody(new FileInputStream(input));
if (input.length() < Integer.MAX_VALUE)
post.setRequestContentLength(input.length());
else post.setRequestContentLength(EntityEnclosingMethod.CONTENT_LENGTH_CHUNKED);
// 指定请求内容的类型
post.setRequestHeader("Content-type", "text/xml; charset=GBK");
HttpClient httpclient = new HttpClient();
int result = httpclient.executeMethod(post);
System.out.println("Response status code: " + result);
System.out.println("Response body: ");
System.out.println(post.getResponseBodyAsString());
post.releaseConnection();
}
}
* Created on 2003-12-7 by Liudong
*/
package http.demo;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.*;
import org.apache.commons.httpclient.methods.*;
/**
* 用来演示登录表单的示例
* @author Liudong
*/
public class FormLoginDemo {
static final String LOGON_SITE = "localhost";
static final int LOGON_PORT = 8080;
public static void main(String[] args) throws Exception{
HttpClient client = new HttpClient();
client.getHostConfiguration().setHost(LOGON_SITE, LOGON_PORT);
//模拟登录页面login.jsp->main.jsp
PostMethod post = new PostMethod("/main.jsp");
NameValuePair name = new NameValuePair("name", "ld");
NameValuePair pass = new NameValuePair("password", "ld");
post.setRequestBody(new NameValuePair[]{name,pass});
int status = client.executeMethod(post);
System.out.println(post.getResponseBodyAsString());
post.releaseConnection();
//查看cookie信息
CookieSpec cookiespec = CookiePolicy.getDefaultSpec();
Cookie[] cookies = cookiespec.match(LOGON_SITE, LOGON_PORT, "/", false, client.getState().getCookies());
if (cookies.length == 0) {
System.out.println("None");
} else {
for (int i = 0; i < cookies.length; i++) {
System.out.println(cookies[i].toString());
}
}
//访问所需的页面main2.jsp
GetMethod get = new GetMethod("/main2.jsp");
client.executeMethod(get);
System.out.println(get.getResponseBodyAsString());
get.releaseConnection();
}
}
5. 提交XML格式参数
提交XML格式的参数很简单,仅仅是一个提交时候的ContentType问题,下面的例子演示从文件文件中读取XML信息并提交给服务器的过程,该过程可以用来测试Web服务。
import java.io.File;
import java.io.FileInputStream;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.PostMethod;
/**
* 用来演示提交XML格式数据的例子
*/
public class PostXMLClient {
public static void main(String[] args) throws Exception {
File input = new File(“test.xml”);
PostMethod post = new PostMethod(“http://localhost:8080/httpclient/xml.jsp”);
// 设置请求的内容直接从文件中读取
post.setRequestBody(new FileInputStream(input));
if (input.length() < Integer.MAX_VALUE)
post.setRequestContentLength(input.length());
else post.setRequestContentLength(EntityEnclosingMethod.CONTENT_LENGTH_CHUNKED);
// 指定请求内容的类型
post.setRequestHeader("Content-type", "text/xml; charset=GBK");
HttpClient httpclient = new HttpClient();
int result = httpclient.executeMethod(post);
System.out.println("Response status code: " + result);
System.out.println("Response body: ");
System.out.println(post.getResponseBodyAsString());
post.releaseConnection();
}
}
6. 通过HTTP上传文件
httpclient使用了单独的一个HttpMethod子类来处理文件的上传,这个类就是MultipartPostMethod,该类已经封装了文件上传的细节,我们要做的仅仅是告诉它我们要上传文件的全路径即可,下面的代码片段演示如何使用这个类。
MultipartPostMethod filePost = new MultipartPostMethod(targetURL);
filePost.addParameter("fileName", targetFilePath);
HttpClient client = new HttpClient();
//由于要上传的文件可能比较大,因此在此设置最大的连接超时时间
client.getHttpConnectionManager(). getParams().setConnectionTimeout(5000);
int status = client.executeMethod(filePost);
filePost.addParameter("fileName", targetFilePath);
HttpClient client = new HttpClient();
//由于要上传的文件可能比较大,因此在此设置最大的连接超时时间
client.getHttpConnectionManager(). getParams().setConnectionTimeout(5000);
int status = client.executeMethod(filePost);
上面代码中,targetFilePath即为要上传的文件所在的路径。
7. 访问启用认证的页面
我们经常会碰到这样的页面,当访问它的时候会弹出一个浏览器的对话框要求输入用户名和密码后方可,这种用户认证的方式不同于我们在前面介绍的基于表单的用户身份验证。这是HTTP的认证策略,httpclient支持三种认证方式包括:基本、摘要以及NTLM认证。其中基本认证最简单、通用但也最不安全;摘要认证是在HTTP 1.1中加入的认证方式,而NTLM则是微软公司定义的而不是通用的规范,最新版本的NTLM是比摘要认证还要安全的一种方式。
下面例子是从httpclient的CVS服务器中下载的,它简单演示如何访问一个认证保护的页面:
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.GetMethod;
public class BasicAuthenticationExample {
public BasicAuthenticationExample() {
}
public static void main(String[] args) throws Exception {
HttpClient client = new HttpClient();
client.getState().setCredentials(
"www.verisign.com",
"realm",
new UsernamePasswordCredentials("username", "password")
);
GetMethod get = new GetMethod("https://www.verisign.com/products/index.html");
get.setDoAuthentication( true );
int status = client.executeMethod( get );
System.out.println(status+"\n"+ get.getResponseBodyAsString());
get.releaseConnection();
}
}
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.GetMethod;
public class BasicAuthenticationExample {
public BasicAuthenticationExample() {
}
public static void main(String[] args) throws Exception {
HttpClient client = new HttpClient();
client.getState().setCredentials(
"www.verisign.com",
"realm",
new UsernamePasswordCredentials("username", "password")
);
GetMethod get = new GetMethod("https://www.verisign.com/products/index.html");
get.setDoAuthentication( true );
int status = client.executeMethod( get );
System.out.println(status+"\n"+ get.getResponseBodyAsString());
get.releaseConnection();
}
}
8. 多线程模式下使用httpclient
多线程同时访问httpclient,例如同时从一个站点上下载多个文件。对于同一个HttpConnection同一个时间只能有一个线程访问,为了保证多线程工作环境下不产生冲突,httpclient使用了一个多线程连接管理器的类:MultiThreadedHttpConnectionManager,要使用这个类很简单,只需要在构造HttpClient实例的时候传入即可,代码如下:
MultiThreadedHttpConnectionManager connectionManager =
new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
以后尽管访问client实例即可。
已失效,停止更新......
用了LumaQQ的库,写一个QQ机器人,配合以前写的海蓝工具源码,实现了用QQ机器人来更改校内网状态,写日志,其实还可以实现更多功能,比如发邮件,群里发帖以前是可以的,现在不行了,群里发帖需要验证码,那个验证码以我现在的水平,我是破不了,呵呵
大家想测试的话,可以加304353193这个QQ为好友


更新内容:可以发布消息到饭否网


用了LumaQQ的库,写一个QQ机器人,配合以前写的海蓝工具源码,实现了用QQ机器人来更改校内网状态,写日志,其实还可以实现更多功能,比如发邮件,群里发帖以前是可以的,现在不行了,群里发帖需要验证码,那个验证码以我现在的水平,我是破不了,呵呵
大家想测试的话,可以加304353193这个QQ为好友
更新内容:可以发布消息到饭否网
1、你需要精通面向对象分析与设计(OOA/OOD)、涉及模式(GOF、J2EEDP)以及综合模式。你应该了解UML,尤其是class,object,interaction以及statediagrams。
2、你需要学习Java语言的基础知识以及它的核心类库(collections,serialization,streams, networking,multithreading,reflection,event,handling,NIO,localization以及其 他)。
3、你应该了解JVM,classloaders,classreflect以及垃圾回收的基本工作机制等。你应该有能力反编译一个类文件并且明白一些基本的汇编指令。
4、如果你将要写客户端程序,你需要学习Web的小应用程序(applet),必须掌握GUI设计的思想和方法,以及桌面程序的SWING, AWT,SWT。你还应该对UI部件的JavaBEAN组件模式有所了解。JavaBEANS也被应用在JSP中以把业务逻辑从表现层中分离出来。
5、你需要学习Java数据库技术,并且会使用至少一种persistence/ORM构架,例如Hibernate,JDO,CocoBase,TopLink,InsideLiberator(国产JDO红工厂软件)或者iBatis。
6、你还应该了解对象关系的阻抗失配的含义,以及它是如何影响业务对象的与关系型数据库的交互,和它的运行结果,还需要掌握不同的数据库产品运用,比如Oracle,Mysql,MS SQL Server。
7、你需要学习Servlets,JSP,以及JSTL(StandardTagLibraries)和可以选择的第三方TagLibraries。
8、你需要熟悉主流的网页框架,例如JSF,Struts,Tapestry,Cocoon,WebWork,以及他们下面的涉及模式,如MVC/MODEL2。
9、你需要学习如何使用及管理Web服务器,例如tomcat,resin,Jrun,并且知道如何在其基础上扩展和维护Web程序。
10、你需要学习分布式对象以及远程API,例如RMI和RMI/IIOP。
11、你需要掌握各种流行中间件技术标准和与Java结合实现,比如Tuxedo、CROBA,当然也包括JavaEE本身。
12、你需要学习最少一种的XMLAPI,例如JAXP(JavaAPIforXMLProcessing),JDOM(JavaforXMLDocumentObjectModel),DOM4J,或JAXR(JavaAPIforXMLRegistries)。
13、你应该学习如何利用Java的API和工具来构建WebService。例如JAX-RPC(JavaAPIforXML/RPC), SAAJ(SOAPwithAttachmentsAPIforJava),JAXB(JavaArchitectureforXMLBinding), JAXM(JavaAPIforXMLMessaging),JAXR(JavaAPIforXMLRegistries),或者JWSDP (JavaWebServicesDeveloperPack)。
14、你需要学习一门轻量级应用程序框架,例如Spring,PicoContainer,Avalon,以及它们的IoC/DI风格(setter,constructor,interfaceinjection)。
15、你需要熟悉不同的J2EE技术,例如JNDI(JavaNamingandDirectoryInterface),JMS (JavaMessageService),JTA/JTS(JavaTransactionAPI/JavaTransactionService), JMX(JavaManagementeXtensions),以及JavaMail。
16、你需要学习企业级JavaBeans(EJB)以及它们的不同组件模式:Stateless/StatefulSessionBeans, EntityBeans(包含Bean-ManagedPersistence[BMP]或者Container-ManagedPersistence [CMP]和它的EJB-QL),或者Message-DrivenBeans(MDB)。
17、你需要学习如何管理与配置一个J2EE应用程序服务器,如WebLogic,JBoss等,并且利用它的附加服务,例如簇类,连接池以及分布式处理支援。你还需要了解如何在它上面封装和配置应用程序并且能够监控、调整它的性能。
18、你需要熟悉面向方面的程序设计以及面向属性的程序设计(这两个都被很容易混淆的缩写为AOP),以及他们的主流Java规格和执行,例如AspectJ和AspectWerkz。
19、你需要熟悉对不同有用的API和framework等来为你服务。例如Log4J(logging/tracing),Quartz (scheduling),JGroups(networkgroupcommunication),JCache (distributedcaching),?Lucene(full-textsearch),JakartaCommons等等。
20、你应该熟练掌握一种JavaIDE例如sunOne,netBeans,IntelliJIDEA或者Eclipse。(有些人更喜欢VI或EMACS来编写文件。随便你用什么了。
21、Java(精确的说是有些配置)是冗长的,它需要很多的人工代码(例如EJB),所以你需要熟悉代码生成工具,例如XDoclet。
22、你需要熟悉一种单元测试体系(JNunit),并且学习不同的生成、部署工具(Ant,Maven)。
23、你需要熟悉一些在Java开发中经常用到的软件工程过程。例如RUP(RationalUnifiedProcess)andAgilemethodologies。
24、你还需要紧跟Java发展的步伐,比如现在可以深入的学习Webwork 2.0。
25、你必须要对实际项目的开发流程有所了解,至少要有两个有实际应用价值的项目,而不是练习项目!因为现在企业看重的是你有没有实际的开发经验,真正开发经验的体现就是你做的项目,也就是有实际应用的项目!
注:以上内容来自网络,本人不承担任何连带责任
文章转自:http://developer.51cto.com/art/200804/68871.htm
2、你需要学习Java语言的基础知识以及它的核心类库(collections,serialization,streams, networking,multithreading,reflection,event,handling,NIO,localization以及其 他)。
3、你应该了解JVM,classloaders,classreflect以及垃圾回收的基本工作机制等。你应该有能力反编译一个类文件并且明白一些基本的汇编指令。
4、如果你将要写客户端程序,你需要学习Web的小应用程序(applet),必须掌握GUI设计的思想和方法,以及桌面程序的SWING, AWT,SWT。你还应该对UI部件的JavaBEAN组件模式有所了解。JavaBEANS也被应用在JSP中以把业务逻辑从表现层中分离出来。
5、你需要学习Java数据库技术,并且会使用至少一种persistence/ORM构架,例如Hibernate,JDO,CocoBase,TopLink,InsideLiberator(国产JDO红工厂软件)或者iBatis。
6、你还应该了解对象关系的阻抗失配的含义,以及它是如何影响业务对象的与关系型数据库的交互,和它的运行结果,还需要掌握不同的数据库产品运用,比如Oracle,Mysql,MS SQL Server。
7、你需要学习Servlets,JSP,以及JSTL(StandardTagLibraries)和可以选择的第三方TagLibraries。
8、你需要熟悉主流的网页框架,例如JSF,Struts,Tapestry,Cocoon,WebWork,以及他们下面的涉及模式,如MVC/MODEL2。
9、你需要学习如何使用及管理Web服务器,例如tomcat,resin,Jrun,并且知道如何在其基础上扩展和维护Web程序。
10、你需要学习分布式对象以及远程API,例如RMI和RMI/IIOP。
11、你需要掌握各种流行中间件技术标准和与Java结合实现,比如Tuxedo、CROBA,当然也包括JavaEE本身。
12、你需要学习最少一种的XMLAPI,例如JAXP(JavaAPIforXMLProcessing),JDOM(JavaforXMLDocumentObjectModel),DOM4J,或JAXR(JavaAPIforXMLRegistries)。
13、你应该学习如何利用Java的API和工具来构建WebService。例如JAX-RPC(JavaAPIforXML/RPC), SAAJ(SOAPwithAttachmentsAPIforJava),JAXB(JavaArchitectureforXMLBinding), JAXM(JavaAPIforXMLMessaging),JAXR(JavaAPIforXMLRegistries),或者JWSDP (JavaWebServicesDeveloperPack)。
14、你需要学习一门轻量级应用程序框架,例如Spring,PicoContainer,Avalon,以及它们的IoC/DI风格(setter,constructor,interfaceinjection)。
15、你需要熟悉不同的J2EE技术,例如JNDI(JavaNamingandDirectoryInterface),JMS (JavaMessageService),JTA/JTS(JavaTransactionAPI/JavaTransactionService), JMX(JavaManagementeXtensions),以及JavaMail。
16、你需要学习企业级JavaBeans(EJB)以及它们的不同组件模式:Stateless/StatefulSessionBeans, EntityBeans(包含Bean-ManagedPersistence[BMP]或者Container-ManagedPersistence [CMP]和它的EJB-QL),或者Message-DrivenBeans(MDB)。
17、你需要学习如何管理与配置一个J2EE应用程序服务器,如WebLogic,JBoss等,并且利用它的附加服务,例如簇类,连接池以及分布式处理支援。你还需要了解如何在它上面封装和配置应用程序并且能够监控、调整它的性能。
18、你需要熟悉面向方面的程序设计以及面向属性的程序设计(这两个都被很容易混淆的缩写为AOP),以及他们的主流Java规格和执行,例如AspectJ和AspectWerkz。
19、你需要熟悉对不同有用的API和framework等来为你服务。例如Log4J(logging/tracing),Quartz (scheduling),JGroups(networkgroupcommunication),JCache (distributedcaching),?Lucene(full-textsearch),JakartaCommons等等。
20、你应该熟练掌握一种JavaIDE例如sunOne,netBeans,IntelliJIDEA或者Eclipse。(有些人更喜欢VI或EMACS来编写文件。随便你用什么了。
21、Java(精确的说是有些配置)是冗长的,它需要很多的人工代码(例如EJB),所以你需要熟悉代码生成工具,例如XDoclet。
22、你需要熟悉一种单元测试体系(JNunit),并且学习不同的生成、部署工具(Ant,Maven)。
23、你需要熟悉一些在Java开发中经常用到的软件工程过程。例如RUP(RationalUnifiedProcess)andAgilemethodologies。
24、你还需要紧跟Java发展的步伐,比如现在可以深入的学习Webwork 2.0。
25、你必须要对实际项目的开发流程有所了解,至少要有两个有实际应用价值的项目,而不是练习项目!因为现在企业看重的是你有没有实际的开发经验,真正开发经验的体现就是你做的项目,也就是有实际应用的项目!
注:以上内容来自网络,本人不承担任何连带责任
文章转自:http://developer.51cto.com/art/200804/68871.htm
2007 充满了激荡人心的事件,动态语言的不断升温,JVM在开源社区不断发展以及Java社区的重要贡献者,Google的崛起等。问题是,这些预示了来年什么 呢?安德鲁•格勒弗(Andrew Glover)准备了一些答案给那些打破砂锅问到底的Java开发者――现在,什么在2008接踵而至。
法国诗人保尔•瓦雷里曾经伤心地写下“困扰我们这个时代的是,未来,并不像过去看上去的那样”。然而,对于我们这些生活在Java平台崛起推动的互联网时代的人来说,瓦雷里多年前留下的这些诗句是永恒的。
过去的十多年,我们见证了Java Applet的兴起和没落,见证了EJB头顶上光环的不断暗淡,见证了JSF,Spring和Struts的异军突起(暂且不谈Struts渐渐显露的颓 势),见证了Java已经重新定义成为一种语言和一个平台。Java平台已经衍生出三个分支(标准版本,企业版本,微型版本),JDK也开放给了开源社 区。Java语言扩充了,包含了注解,范型,枚举类型,高级集合类型,还有更多。它也开始与动态语言,如Groovy,JRuby和Rhino等,共享 Java运行时(JRE)。事实上,如果稍稍留神一下,我们在过去的几年里注视着Java不断地从一种语言演变成为一个真正的平台。
在最近的十年里,我们知道Java已经不仅仅局限于一种语言或者一个平台了:它是一个社区,一个经济生态系统,一个鲜活的实体,而且这个实体已经发展成熟,成为了丰富的应用程序,或大或小公司的真正的生命线。
因此,尽管流言不少,我还是坚持认为Java在2008会持续红火。与其拿起卦子掐算未来,我们不如回顾一下过去的一年的趋势以及发生的重大事件。这些事件汇集起来,它们会告诉我们2008将发生什么。
遍地开花
2007 年犹如过山车一样,非常引人注目。人们对动态语言的不断关注, JVM在开源社区不断发展以及Java社区的重要贡献者,Google的崛起。更多的是,单元测试,持续化集成和其他敏捷开发技术得到了更广泛的接受,这 些都表明Java开发者开始认识到我们的技艺是一门有责任要求的行业。我们终于开始重视代码的质量和寿命,将其与推向市场的速度,或者是在企业的即时应用 放到同等重要的地位上来。
每个人都说,2007年有一些绝对的胜利,但是同时也有一些失望和争论,这给Java社区产生了超出预期更多的阻碍。留心一下以下这些体现过去一年的重大因素。
动态语言的成熟
随着1.0以及随后的1.5版本的发布,Groovy在2007的发展达到了一个关键的里程碑。走过过去5年或者多年的历程,Groovy没有替代Java,相反定位成了Java运行时(JRE)的补充语言。
Groovy的大卖点是简练的语法,简化了日常的开发工作。例如,打开和读取一个文件在Java语言是典型的冗长结构:
try {BufferedReader in = new BufferedReader(new FileReader(path)); String line; while((line = in.readLine()) != null){System.out.println(line); }in.close(); }catch(IOException e){System.err.println("Exception reading"); }
但是同样的代码,Groovy可以写的更加敏捷:
new File(path).eachLine{ line ->println line}
根本上,Groovy像其他动态语言一样,可以让你扔掉异常处理,类型和分号,还可以使得代码更加简练,而代码简练最终使得代码的可读性更强(是的,上面那个File对象是一个Java java.io.File对象)。
把网撒开
然而,Groovy并不是2007年动态语言阵营的唯一参与者。2006年发布的Java 6版本引入了一个与动态语言交互的标准API,很多Java开发者在去年临近年底才开始体验。对该API进行旗舰式集成的是Rhino。但是,看起来在 Java7版本发布时还会有更多集成进来。
最早进行集成的语言之一不容置疑是JRuby,1.0版本的发布和令人咋舌的比Ruby本身运行速度还快的实现,使得它备受瞩目。像Groovy一 样,由于可以使用更加宽松的语法,加入了一些特殊机制的JRuby(它可以使 RubyJVM里运行,且与正常的Java对象交互)使Java开发更加简单。例如,使用Ruby可以增强标准的对象,象用Ruby的String操作会 更加容易。在标准的Java里,检查一个String实例是否为空值可能要做象如下方法的一样的操作(这是一个Apache commons-lang的 isBlank实现)。
public static boolean isBlank(String str) {int strLen; if (str == null || (strLen = str.length()) == 0) {return true; }for (int i = 0; i < strLen; i++) {if ((Character.isWhitespace(str.charAt(i)) == false)) {return false; }}return true; }
在Java 里,String是一个final类,所以你无法为了让String类型支持一个象isBlank的方法而扩展它。后果是,你不得不依赖第三方类库,象 common-lang。有了Ruby,你就可以在Ruby的String上另外定义一个blank方法,如:
class Stringdef blank?empty? || strip.empty?endend
实际上,Ruby式的动态允许运行时添加额外的行为到核心类库或任意对象(象给String增加一个blank?方法)。更进一步,JRuby可以进行反作用对核心Java对象增加方法。因此,稍一施法就可以给Java String类添加一个blank方法。
开放Java核心
07年Java的开源意味Java平台的发展不再由Sun核心工程师们说了算了:现在它的前途由我们掌握了。对Java类库,Javac,甚至JVM本身都采取GPL协议,OpenJDK保证将会开创一个创新的周期。实际上,我们已经看到了。
在2007 年十月,一个名为Multi-Language VM的项目在OpenJDK旗下开展了。这个项目旨在通过修改Java的底层架构,实现“以JVM特性为原型,高效支持Java之外的语言”。很明显,这 项目结合了07年最令人振奋的两个发展潮流,也就是围绕在动态语言的热衷和OpenJDK,这宣称我们处在了一个Java核心创新的时代。
Sun 的开放当然不是从OpenJDk开始的,而是Glassfish,作为Sun支持的开源应用服务器,它在2007自始至终获得了社区更多的追捧。最近,我 们无法忽略Sun对MySQL AB的收购,MySQL背后的公司是MySQL AB,而MySQL似乎是当今最流行的开源数据库。
所有这些发展都表明Java的鼻祖采取了一种受开源软件很大影响的商业模式。这意味我们在2008或者更远将看到Java平台更多的开放。当然,这会对Java生态系统的商业方面产生深远影响。相比最近Oracle以70十亿美金收购BEA,这似乎很绿色,很健康。
Google flexes
移动Java领域曾经变的不景气,但是临近2007年尾时,却因Google的Android平台的发布而重焕青春。Android的目标是为新一 代移动设备引入应用软件,且运行在由Google主导的开源操作系统之上。虽然Android是一个完整的平台(很像Java),但是构建Android 应用程序的SDK却是建立在Java之上。
此外,Android的Java与J2ME的Java截然不同。实际上,在JVM层面,Android的JVM就已相当独特了。除了运行专门为 Android而设计,高度优化的字节码格式的代码,它不可以运行标准Java字节码。移动设备上运行不同实现的Java意味这我们将可以看到一些有趣的 应用程序――当然,这也仅进一步说明了Java的无处不在。
2007 年Google在Java世界移动领域之外也进展的很顺利。但是,备受关注的是Guice的发布,Guice是一个基于Java 5注解和范型的依赖注入开源框架。虽然IOC市场上的佼佼者还是Spring,因其摒弃XML文件,提倡使用注解和Guice本身的Module类型,注 定了Guice在公开发布时就是一个先行者。
考虑到Google对第二代IOC框架的影响和Google AdWrods本身的基础架构都是依赖Guice的,Guice在来年很有可能将得到更多的关注。
敏捷成为主流――测试时代到来了
敏捷(agile)这个名称对大家来说并不新鲜,单元测试与持续化集成也不陌生。不过,2007年似乎是这些实践更加成为主流的年份。你不会碰到一 个会议里没有一到两个关注在敏捷上的演示的。再哆嗦几句,瞥一眼2008年度Jolt Award大奖关于综合性和技术性书籍(从2007年甄选的)的最终名单,就可以看出关于单元测试和持续化集成的书籍占有一席之地。然而,更重要的是,不 管是享有盛誉的,还是刚刚发展的框架都已经开始宣称它们的架构是多么容易地进行测试了。似乎,开发人员的测试时代终于到来了。
Java成长之痛
Java在不断的成长,不断的扩充,然而它在逐渐变化成为一个平台,而不仅仅是一种语言。不知是好还是坏,独具特性的东西一直在不断的添加进来,以后还将会有,社区会接受特性吗?
然而,一些特性就没有其他特性那样受欢迎了。举个例子来说,注解就很受欢迎――象JUnit4, TestNG, Spring和Google的Guice这些框架,由于对注解的创新的使用,就得到了不少开发人员的青睐。相反的是,到目前为止,人们对范型(在Java 5中引入)并没有保持对其自始至终的热情。
闭包(Closure)未见踪影
如果范型不足以使编程的前景变的灰暗,有人可能会发现当前围绕关于在Java 7 foggy中加入闭包和局部函数提议的争论。虽然我绝不会否认它们是有用的组成部分,只是,将它们增加到Java语言的语义中,概念的复杂性增加只会降低它们的有用性。
例如,在一个闭包的典型参考实现中,找到如下代码,它定义了一个简单的支持整数加法的闭包:
{Integer,Integer=>Integer} plus1 = {Integer x, Integer y => x+y};
非常有趣的是,由于Java天生的对语义要求,语句变的拖沓冗余――用Groovy来重写同样功能,却很容易。例如
plus1 = { x, y -> x+y }
注意到,在Groovy的例子中,类型的缺失无疑使得代码的意图一目了然。当然,Ruby版本也会同样简明扼要。
显然,象动态语言普遍受到欢迎此类的外部力量在不断地影响Java。如果想使用闭包,你完全不必等待Java自带的闭包――Groovy和JRuby对其的支持就已经很优雅。
真正的并发
Java7 值得期待的其他事情是java.util.concurrent包的发布,这个包致力于通过充分利用底层硬件来达到真正的并发。虽然Java已经支持多线 程,但是通过对并行性的进一步重视,硬件资源将变的越来越健壮。最终,Java语言也发展的可以应付这些要求。
由JSR 166专家组领导的Java 7将很有可能包含一些新特性,包括名为join-fork的细粒度的并行计算框架。好消息是,看起来这些新特性是崭新的类(和API),与生俱来就不符合句法规则。
奔向RIA
07年,特别是Sun在2007年JavaOne上让JavaFx对公众面世后,RIA(Rich Internet Application)继续让Java Web应用程序开发人员产生莫大的兴趣。JavaFX产品家族现在由JavaFX Script和JavaFX Mobile组成。
由于开发类Ajax应用的JavaScript无处不在,对 JavaFx的反应显得见仁见智。看起来JavaFX将会加剧本来就已经四分五裂的移动环境之间的裂缝。很多人感觉JavaFX的公告有点操之过急,还有 一些人怀疑它究竟是不是一个雾件。不管怎样,Sun进入RIA领域传达了一个长期战略的消息,这会使Java的前景更加光明。
结束语
有个非洲谚语说“明天属于那些今天为它准备的人”。因此,Java的未来(至少来年)已经孕育了一段时间了。2008年的大事的很大部分将不仅由 JVM本身促成,而且也会随着JRuby和Groovy不断受欢迎,最终得到更多厂商的采纳而形成。由于Google Android的出击和Sun JavaFX Mobile的发布,使用Java开发用户移动应用的前景也好像比以前更加容易到达了。大部分人的注意力将被多核系统的出现吸引过去,期待Java 7 java.util.concurrent包对其的回应。最后,围绕它的开源的Java和商业模型也会不断的成长。
作者简介
Andrew Glover是Stelligent Incorporated的总裁,Stelligent Incorporated是一家帮助开发团队加速软件开发的咨询公司。他的blog通常是thediscoblog.com和testearly.com。
法国诗人保尔•瓦雷里曾经伤心地写下“困扰我们这个时代的是,未来,并不像过去看上去的那样”。然而,对于我们这些生活在Java平台崛起推动的互联网时代的人来说,瓦雷里多年前留下的这些诗句是永恒的。
过去的十多年,我们见证了Java Applet的兴起和没落,见证了EJB头顶上光环的不断暗淡,见证了JSF,Spring和Struts的异军突起(暂且不谈Struts渐渐显露的颓 势),见证了Java已经重新定义成为一种语言和一个平台。Java平台已经衍生出三个分支(标准版本,企业版本,微型版本),JDK也开放给了开源社 区。Java语言扩充了,包含了注解,范型,枚举类型,高级集合类型,还有更多。它也开始与动态语言,如Groovy,JRuby和Rhino等,共享 Java运行时(JRE)。事实上,如果稍稍留神一下,我们在过去的几年里注视着Java不断地从一种语言演变成为一个真正的平台。
在最近的十年里,我们知道Java已经不仅仅局限于一种语言或者一个平台了:它是一个社区,一个经济生态系统,一个鲜活的实体,而且这个实体已经发展成熟,成为了丰富的应用程序,或大或小公司的真正的生命线。
因此,尽管流言不少,我还是坚持认为Java在2008会持续红火。与其拿起卦子掐算未来,我们不如回顾一下过去的一年的趋势以及发生的重大事件。这些事件汇集起来,它们会告诉我们2008将发生什么。
遍地开花
2007 年犹如过山车一样,非常引人注目。人们对动态语言的不断关注, JVM在开源社区不断发展以及Java社区的重要贡献者,Google的崛起。更多的是,单元测试,持续化集成和其他敏捷开发技术得到了更广泛的接受,这 些都表明Java开发者开始认识到我们的技艺是一门有责任要求的行业。我们终于开始重视代码的质量和寿命,将其与推向市场的速度,或者是在企业的即时应用 放到同等重要的地位上来。
每个人都说,2007年有一些绝对的胜利,但是同时也有一些失望和争论,这给Java社区产生了超出预期更多的阻碍。留心一下以下这些体现过去一年的重大因素。
动态语言的成熟
随着1.0以及随后的1.5版本的发布,Groovy在2007的发展达到了一个关键的里程碑。走过过去5年或者多年的历程,Groovy没有替代Java,相反定位成了Java运行时(JRE)的补充语言。
Groovy的大卖点是简练的语法,简化了日常的开发工作。例如,打开和读取一个文件在Java语言是典型的冗长结构:
try {BufferedReader in = new BufferedReader(new FileReader(path)); String line; while((line = in.readLine()) != null){System.out.println(line); }in.close(); }catch(IOException e){System.err.println("Exception reading"); }
但是同样的代码,Groovy可以写的更加敏捷:
new File(path).eachLine{ line ->println line}
根本上,Groovy像其他动态语言一样,可以让你扔掉异常处理,类型和分号,还可以使得代码更加简练,而代码简练最终使得代码的可读性更强(是的,上面那个File对象是一个Java java.io.File对象)。
把网撒开
然而,Groovy并不是2007年动态语言阵营的唯一参与者。2006年发布的Java 6版本引入了一个与动态语言交互的标准API,很多Java开发者在去年临近年底才开始体验。对该API进行旗舰式集成的是Rhino。但是,看起来在 Java7版本发布时还会有更多集成进来。
最早进行集成的语言之一不容置疑是JRuby,1.0版本的发布和令人咋舌的比Ruby本身运行速度还快的实现,使得它备受瞩目。像Groovy一 样,由于可以使用更加宽松的语法,加入了一些特殊机制的JRuby(它可以使 RubyJVM里运行,且与正常的Java对象交互)使Java开发更加简单。例如,使用Ruby可以增强标准的对象,象用Ruby的String操作会 更加容易。在标准的Java里,检查一个String实例是否为空值可能要做象如下方法的一样的操作(这是一个Apache commons-lang的 isBlank实现)。
public static boolean isBlank(String str) {int strLen; if (str == null || (strLen = str.length()) == 0) {return true; }for (int i = 0; i < strLen; i++) {if ((Character.isWhitespace(str.charAt(i)) == false)) {return false; }}return true; }
在Java 里,String是一个final类,所以你无法为了让String类型支持一个象isBlank的方法而扩展它。后果是,你不得不依赖第三方类库,象 common-lang。有了Ruby,你就可以在Ruby的String上另外定义一个blank方法,如:
class Stringdef blank?empty? || strip.empty?endend
实际上,Ruby式的动态允许运行时添加额外的行为到核心类库或任意对象(象给String增加一个blank?方法)。更进一步,JRuby可以进行反作用对核心Java对象增加方法。因此,稍一施法就可以给Java String类添加一个blank方法。
开放Java核心
07年Java的开源意味Java平台的发展不再由Sun核心工程师们说了算了:现在它的前途由我们掌握了。对Java类库,Javac,甚至JVM本身都采取GPL协议,OpenJDK保证将会开创一个创新的周期。实际上,我们已经看到了。
在2007 年十月,一个名为Multi-Language VM的项目在OpenJDK旗下开展了。这个项目旨在通过修改Java的底层架构,实现“以JVM特性为原型,高效支持Java之外的语言”。很明显,这 项目结合了07年最令人振奋的两个发展潮流,也就是围绕在动态语言的热衷和OpenJDK,这宣称我们处在了一个Java核心创新的时代。
Sun 的开放当然不是从OpenJDk开始的,而是Glassfish,作为Sun支持的开源应用服务器,它在2007自始至终获得了社区更多的追捧。最近,我 们无法忽略Sun对MySQL AB的收购,MySQL背后的公司是MySQL AB,而MySQL似乎是当今最流行的开源数据库。
所有这些发展都表明Java的鼻祖采取了一种受开源软件很大影响的商业模式。这意味我们在2008或者更远将看到Java平台更多的开放。当然,这会对Java生态系统的商业方面产生深远影响。相比最近Oracle以70十亿美金收购BEA,这似乎很绿色,很健康。
Google flexes
移动Java领域曾经变的不景气,但是临近2007年尾时,却因Google的Android平台的发布而重焕青春。Android的目标是为新一 代移动设备引入应用软件,且运行在由Google主导的开源操作系统之上。虽然Android是一个完整的平台(很像Java),但是构建Android 应用程序的SDK却是建立在Java之上。
此外,Android的Java与J2ME的Java截然不同。实际上,在JVM层面,Android的JVM就已相当独特了。除了运行专门为 Android而设计,高度优化的字节码格式的代码,它不可以运行标准Java字节码。移动设备上运行不同实现的Java意味这我们将可以看到一些有趣的 应用程序――当然,这也仅进一步说明了Java的无处不在。
2007 年Google在Java世界移动领域之外也进展的很顺利。但是,备受关注的是Guice的发布,Guice是一个基于Java 5注解和范型的依赖注入开源框架。虽然IOC市场上的佼佼者还是Spring,因其摒弃XML文件,提倡使用注解和Guice本身的Module类型,注 定了Guice在公开发布时就是一个先行者。
考虑到Google对第二代IOC框架的影响和Google AdWrods本身的基础架构都是依赖Guice的,Guice在来年很有可能将得到更多的关注。
敏捷成为主流――测试时代到来了
敏捷(agile)这个名称对大家来说并不新鲜,单元测试与持续化集成也不陌生。不过,2007年似乎是这些实践更加成为主流的年份。你不会碰到一 个会议里没有一到两个关注在敏捷上的演示的。再哆嗦几句,瞥一眼2008年度Jolt Award大奖关于综合性和技术性书籍(从2007年甄选的)的最终名单,就可以看出关于单元测试和持续化集成的书籍占有一席之地。然而,更重要的是,不 管是享有盛誉的,还是刚刚发展的框架都已经开始宣称它们的架构是多么容易地进行测试了。似乎,开发人员的测试时代终于到来了。
Java成长之痛
Java在不断的成长,不断的扩充,然而它在逐渐变化成为一个平台,而不仅仅是一种语言。不知是好还是坏,独具特性的东西一直在不断的添加进来,以后还将会有,社区会接受特性吗?
然而,一些特性就没有其他特性那样受欢迎了。举个例子来说,注解就很受欢迎――象JUnit4, TestNG, Spring和Google的Guice这些框架,由于对注解的创新的使用,就得到了不少开发人员的青睐。相反的是,到目前为止,人们对范型(在Java 5中引入)并没有保持对其自始至终的热情。
闭包(Closure)未见踪影
如果范型不足以使编程的前景变的灰暗,有人可能会发现当前围绕关于在Java 7 foggy中加入闭包和局部函数提议的争论。虽然我绝不会否认它们是有用的组成部分,只是,将它们增加到Java语言的语义中,概念的复杂性增加只会降低它们的有用性。
例如,在一个闭包的典型参考实现中,找到如下代码,它定义了一个简单的支持整数加法的闭包:
{Integer,Integer=>Integer} plus1 = {Integer x, Integer y => x+y};
非常有趣的是,由于Java天生的对语义要求,语句变的拖沓冗余――用Groovy来重写同样功能,却很容易。例如
plus1 = { x, y -> x+y }
注意到,在Groovy的例子中,类型的缺失无疑使得代码的意图一目了然。当然,Ruby版本也会同样简明扼要。
显然,象动态语言普遍受到欢迎此类的外部力量在不断地影响Java。如果想使用闭包,你完全不必等待Java自带的闭包――Groovy和JRuby对其的支持就已经很优雅。
真正的并发
Java7 值得期待的其他事情是java.util.concurrent包的发布,这个包致力于通过充分利用底层硬件来达到真正的并发。虽然Java已经支持多线 程,但是通过对并行性的进一步重视,硬件资源将变的越来越健壮。最终,Java语言也发展的可以应付这些要求。
由JSR 166专家组领导的Java 7将很有可能包含一些新特性,包括名为join-fork的细粒度的并行计算框架。好消息是,看起来这些新特性是崭新的类(和API),与生俱来就不符合句法规则。
奔向RIA
07年,特别是Sun在2007年JavaOne上让JavaFx对公众面世后,RIA(Rich Internet Application)继续让Java Web应用程序开发人员产生莫大的兴趣。JavaFX产品家族现在由JavaFX Script和JavaFX Mobile组成。
由于开发类Ajax应用的JavaScript无处不在,对 JavaFx的反应显得见仁见智。看起来JavaFX将会加剧本来就已经四分五裂的移动环境之间的裂缝。很多人感觉JavaFX的公告有点操之过急,还有 一些人怀疑它究竟是不是一个雾件。不管怎样,Sun进入RIA领域传达了一个长期战略的消息,这会使Java的前景更加光明。
结束语
有个非洲谚语说“明天属于那些今天为它准备的人”。因此,Java的未来(至少来年)已经孕育了一段时间了。2008年的大事的很大部分将不仅由 JVM本身促成,而且也会随着JRuby和Groovy不断受欢迎,最终得到更多厂商的采纳而形成。由于Google Android的出击和Sun JavaFX Mobile的发布,使用Java开发用户移动应用的前景也好像比以前更加容易到达了。大部分人的注意力将被多核系统的出现吸引过去,期待Java 7 java.util.concurrent包对其的回应。最后,围绕它的开源的Java和商业模型也会不断的成长。
作者简介
Andrew Glover是Stelligent Incorporated的总裁,Stelligent Incorporated是一家帮助开发团队加速软件开发的咨询公司。他的blog通常是thediscoblog.com和testearly.com。








