分两部分:一部Java Net(大部分来自Java Doc), 一部分XML Parser, 通过一个Twitter的例子来描述简单的使用情况。
java.net 包的概述:
java.net包大致可分为两部分:
在整个 java.net API 中,地址或者用作主机标识符或者用作套接字端点标识符。
InetAddress 类是表示 IP(Internet 协议)地址的抽象,它拥有两个子类:
Inet4Address。Inet6Address。但是,在大多数情况下,不必直接处理子类,因为 InetAddress 抽象应该覆盖大多数必需的功能。
套接字是在网络上建立机器之间的通信链接的方法。java.net 包提供 4 种套接字:
Socket 是 TCP 客户端 API,通常用于将 (java.net.Socket.connect(SocketAddress)) 连接到远程主机。ServerSocket 是 TCP 服务器 API,通常接受 (java.net.ServerSocket.accept) 源于客户端套接字的连接。DatagramSocket 是 UDP 端点 API,用于发送和接收 java.net.DatagramPackets。MulticastSocket 是 DatagramSocket 的子类,在处理多播组时使用。使用 TCP 套接字的发送和接收操作需要借助 InputStream 和 OutputStream 来完成,这两者是通过 java.net.Socket.getInputStream 和 java.net.Socket.getOutputStream 方法获取的。
java.net 包中的许多类可以提供更加高级的抽象,允许方便地访问网络上的资源。这些类为:
URI 是表示在 RFC 2396 中指定的统一资料标识符的类。顾名思义,它只是一个标识符,不直接提供访问资源的方法。URL 是表示统一资源定位符的类,它既是 URI 的旧式概念又是访问资源的方法。URLConnection 是根据 URL 创建的,是用于访问 URL 所指向资源的通信链接。此抽象类将大多数工作委托给底层协议处理程序,如 http 或 ftp。HttpURLConnection 是 URLConnection 的子类,提供一些特定于 HTTP 协议的附加功能。建议的用法是使用 URI 指定资源,然后在访问资源时将其转换为 URL。从该 URL 可以获取 URLConnection 以进行良好控制,也可以直接获取 InputStream。
下面是一个示例:
URI uri = new URI("http://java.sun.com/");
URL url = uri.toURL();
InputStream in = url.openStream();
抽象类 URLConnection 是所有表示应用程序与 URL 之间通信链路的类的超类。该类的实例可以用来对由 URL 引用的资源进行读取和写入操作
HttpURLConnection 仅是支持了 HTTP 特定功能的 URLConnection
openConnection 方法产生一连接对象。connect 方法,实现对远程对象的实际连接。通过如下的方法修改设置参数:
通过使用如下的方法修改一般请求属性:
AllowUserInteraction 和 UseCaches 参数的缺省值可以通过使用 setDefaultAllowUserInteraction 和 setDefaultUseCaches 方法来设置。 而一般请求属性的缺省值可以通过方法 setDefaultRequestProperty 来设置 。
上面的每个 set 方法都有相应 get 方法来获取参数和一般请求属性的值。可用的特定参数和一般请求属性是特定于协议的。
对远程对象的连接完成后,用下列方法访问报头域和内容:
确认报头域能够被频繁访问。方法:
提供对这些域的便利访问。 getContentType 方法由 getContent 方法调用以确定远程对象的类型; 子类来覆盖方法 getContentType 可能是有利的。
下面是一个通过Twitter API去获信息的demo:
URL url = new URL("http://t.bbercn.com/statuses/user_timeline.xml");
String username = (String) params[0];
String password = (String) params[1];
String user_paw = username + ":" + password;
String encoding = "Basic " + Base64Converter.encode(user_paw.getBytes());
URLConnection uc = url.openConnection();
uc.setRequestProperty("Authorization", encoding);
InputStream content = (InputStream) uc.getInputStream();
剩下的工作就是对InputStream 进行本地处理,Twitter返回的是XML,那么我们下面就对XML进行解析,获取我们要获取的信息。
关于 xml 解析的工具有很多,具体可以看这里:http://www.open-open.com/31.htm 罗列的一些。
下面通过Commons-Digester来处理上面我们获取的InputStream
public class ParseTools {
private List statuses = new ArrayList<Status>();
public List<Status> getStatuses() {
Collections.sort(statuses);
return statuses;
}
public void parseStatus(InputStream stream) throws IOException, SAXException {
Digester digester = new Digester();
digester.setValidating(false);
digester.push(this);
digester.addObjectCreate("statuses/status", Status.class);
//status
digester.addBeanPropertySetter("statuses/status/id");
digester.addBeanPropertySetter("statuses/status/created_at");
digester.addBeanPropertySetter("statuses/status/text");
digester.addBeanPropertySetter("statuses/status/source");
digester.addBeanPropertySetter("statuses/status/truncated");
digester.addBeanPropertySetter("statuses/status/in_reply_to_status_id");
digester.addBeanPropertySetter("statuses/status/in_reply_to_user_id");
digester.addBeanPropertySetter("statuses/status/favorited");
digester.addBeanPropertySetter("statuses/status/in_reply_to_screen_name");
//user
digester.addObjectCreate("statuses/status/user", User.class);
digester.addBeanPropertySetter("statuses/status/user/id");
digester.addBeanPropertySetter("statuses/status/user/name");
digester.addBeanPropertySetter("statuses/status/user/screen_name");
digester.addBeanPropertySetter("statuses/status/user/description");
digester.addBeanPropertySetter("statuses/status/user/location");
digester.addBeanPropertySetter("statuses/status/user/profile_image_url");
digester.addBeanPropertySetter("statuses/status/user/url");
digester.addBeanPropertySetter("statuses/status/user/isProtected");
digester.addBeanPropertySetter("statuses/status/user/followers_count");
digester.addBeanPropertySetter("statuses/status/user/friends_count");
digester.addSetNext("statuses/status/user", "setUser");
digester.addSetNext("statuses/status", "addStatuses", Status.class.getName());
digester.parse(stream);
}
public void addStatuses(Status status) {
Status d = new Status();
d.setId(status.getId());
d.setCreated_at(status.getCreated_at());
d.setFavorited(status.isFavorited());
d.setText(status.getText());
d.setSource(status.getSource());
d.setTruncated(status.isTruncated());
d.setIn_reply_to_screen_name(status.getIn_reply_to_screen_name());
d.setIn_reply_to_status_id(status.getIn_reply_to_status_id());
d.setIn_reply_to_user_id(status.getIn_reply_to_user_id());
d.setUser(status.getUser());
getStatuses().add(d);
}
}
周三赶鸭子上架的组织了一次JQuery入门培训,由于时间上的原因,自己没做Demo,拿官方现成的,主要是认识JQuery,了解JQuery核心函数,介绍一些常用的选择器,还有事件处理,以及Ajax的使用,这里简单分享下:
$ 表示JQuery类,$(…) 构造一个JQuery类,这里的JQuery类是一个集合数组对象,而非Dom对象。
jQuery(expression,[context])
$("div > p"); $("input:radio", document.forms[0]); $("div", xml.responseXML);jQuery( html )
$("<div>Hello</div>").appendTo("body");主要用来加载html
jQuery( elements )
$(document.body).css("background-color", "black"); $(myForm.elements).hide();jQuery( callback )
$(function(){ alert('hello'); });JQuey中执行方法是在页面加载结束后,官方解释是:A shorthand for $(document).ready().
JQuery选择器是JQuery的一大亮点,快捷,高效的遍历整个HTML文档,常用的如下面几种:
$("#id"); $("div"); $(".className"); $("div,span,p.myClass") $("form input") $("form > input")强烈建议直接看官方文档:http://docs.jquery.com/Selectors
$("p").bind("click", function(e){}); $("p").click(function() {}) trigger( event, data ) //触发事件 triggerHandler( event, data ) //触发事件,但不触发浏览器的默认事件 $("p").live("click", function(){ //在p以及p的下面的子elements上都加上click事件 $(this).after("<p>Another paragraph!</p>"); });更多,参见官方文档:http://docs.jquery.com/Events
ajax这块感觉和其他框架没多少差别,用起来基本类似:
1、$.post(…) 和 $.get(…)$.post('save.cgi', { text: 'my string', number: 23 }, function() { alert('Your data has been saved.'); });2、$.ajax(…)
$.ajax({ url: 'getdata.action', type: 'GET', dataType: 'html', Timeout: 1000, beforeSend: function(){ // Handle the beforeSend event }, success: function(html){ // do something with html }, complete: function(){ // Handle the complete event }, error: function(){ alert('Error loading HTML document'); }, });
1、http://jquery.com/
2、jQuery 1.3 API 中文参考文档
3、http://jqueryui.com/
4、http://jquery.org.cn/
5、有关Ajax的一个中文文章
由于最近另一个项目的启动,工作方面基本上是掐着时间在忙,所以周主题的任务就只能稍微往后推一周了。
预计本周四结合公司的培训内容,出一个有关JQuery的入门介绍,这个内容顺便就补给上周的周主题。
顺便预告下:接下来这周和下周会整理有关Java.Net包下一些常用类的使用,包括HttpClient的使用,以及XML Parser方面的汇总。
关于Twitter这里就不多介绍了, 基本上能看到这篇文章的都用过的, 当然不知道也没关系, Google一下.由于Twitter的API 开放性, 所以其应用现在可以用多如牛毛也描述了, 各种各样的, 本文基于Java, 通过twitter API来获取twitter消息, 并以PDF的形式进行归档.准备工具:
1. HttpClient 3.x 库文件, 通过此库来从Twitter API获取消息, 同时需要 Comomons Logging 和 Codec 两个库文件. 请自行下载.
2. dom4j 库文件, 通过此库来解析Twitter的消息XML和获取中间的数据.
3. iText 库文件, 用来创建PDF文档.
Twitter API提供XML, JSON 和RSS几种格式, 这里我们选择XML格式, 通过dom4j来解析, 上面是一个叫做TweetConsumer的借口, 作用就是来处理消息的, 其实现在后面会讲到. 自定义一个消息异常, 当出现问题时抛出: 接下来是本文的重点, 通过Twitter API去获取消息: TweetProducer 里面有三个方法: 获取消息: Twitter API默认获取的消息条数是20, 最大200, 你可以自己定义获取的数量, 同时也可以通过一些参数来指定获取第几页的消息等, 具体使用参考Twitter API WIKI上的定义. 例如, 获取消息ID为since_id以后的200个消息: 设置完查询条件后, 执行: 将返回的信息传给SAXReader,以便获取消息root: 最后迭代每个带 标签的Element: 由于Twitter的消息列表是按时间降序排列, 那么第一个消息就是最新的消息了, 这个消息ID就是excute()要返回的String. 获取到消息后, 接下来我们就输出消息: 将上面的介绍的代码整理好, 并执行, 就会在控制台输出, XML格式的消息列表, 如下是其中的一个片段: 同时会输出, 你的最后一个消息的消息ID: 当然你也可以直接通过这个ID, 来去获取你的该ID以后的消息: OK, 到这里, 我们的任务已经过去一半多了, 获取twitter消息, 那么接下来的内容, 我们来看如何将消息以PDF的形式进行归档. 通过iText生成PDF, 需要5步, 请看下面的Demo : 大体工作流程就如上面所说,相信都可以看懂, OK, 下面我就直接给出代码, 重点地方提一下. PDFWriter类 上面的类已经可以输出PDF了, 但是不是很美观, 加点修饰, 每个Twitter消息一个框, 这是背景: 下面再画蛇添足, 加点外围修饰, 每个PDF页面左侧加上文字, 算是起点宣传作用: 最后配个截图, 为本文画上句号, 注, 由于图缩略了, 效果有点虚了: 英文原版出处: http://www.javaworld.com/javaworld/jw-03-2009/jw-03-write-your-own-twitter-app.html , 本文抽取了原英文的重点, 并配以文字介绍,加工而成.
每个Twitter应用都是基于twitter API来实现的, 有关Twitter API的使用可以看这里: Twitter API wiki(官方的,需要翻墙), 这里我们假设你只对获取数据感兴趣, 同时想以某种方式显示他们, 至于其他功能, 相信通过本教程的介绍, 你可以自己去钻研了.从TweetConsumer开始:
import org.dom4j.Element;
public interface TweetConsumer {
public String tweet(Element element) throws TweetException;
}
public class TweetException extends Exception {
private static final long serialVersionUID = 7577136074623618615L;
public TweetException(Exception e) {
super(e);
}
}
public class TweetProducer {
protected HttpClient client;
protected TweetConsumer consumer;
public void createClient(String username, String password) {
client = new HttpClient();
client.getState().setCredentials(
//由于GFW的原因, 直连twitter肯定是不行了, 建议使用第三方API,比如我的GAE应用:xiao-quan.appspot.com
new AuthScope("twitter.com", 80, AuthScope.ANY_REALM),
new UsernamePasswordCredentials(username, password));
client.getParams().setAuthenticationPreemptive(true);
}
public void setConsumer(TweetConsumer consumer) {
this.consumer = consumer;
}
public String execute(String since_id) throws TweetException {
String id = null;
String tmp;
//由于GFW的原因, 直连twitter肯定是不行了, 建议使用第三方API,比如我的GAE应用:http://xiao-quan.appspot.com/api/statuses/friends_timeline.xml
GetMethod get = new GetMethod("http://twitter.com/statuses/friends_timeline.xml");
if (since_id != null && since_id.length() > 0) {
get.setQueryString("?count=200&since_id=" + since_id);
}
else {
get.setQueryString("?count=200");
}
get.setDoAuthentication(true);
try {
client.executeMethod(get);
SAXReader reader = new SAXReader();
Document document = reader.read(get.getResponseBodyAsStream());
Element root = document.getRootElement();
for (Iterator i = root.elementIterator(); i.hasNext(); ) {
tmp = consumer.tweet((Element)i.next());
if (id == null) id = tmp;
}
} catch (HttpException e) {
throw new TweetException(e);
} catch (IOException e) {
throw new TweetException(e);
} catch (DocumentException e) {
throw new TweetException(e);
} finally {
get.releaseConnection();
}
return id;
}
}
createClient(), 创建HttpClient对象, 通过HttpClient来连接Twitter API, 由于Twitter使用了HTTP Basic Authentication,
所以你需要提供你的twitter用户名和密码来登录, 获取你的朋友们的消息.
setConsumer(), 传一个TweetConsumer接口给TweetProducer, 我们有多种输出方案, 当然这里要通用点.
excute(), 这是才是做事情的地方, 获取哪个消息ID以后的消息, 返回一个消息ID.
GetMethod get = new GetMethod("http://twitter.com/statuses/friends_timeline.xml");
get.setQueryString("?count=200&since_id=" + since_id);
client.executeMethod(get);
SAXReader reader = new SAXReader();
Document document = reader.read(get.getResponseBodyAsStream());
Element root = document.getRootElement();
for (Iterator i = root.elementIterator(); i.hasNext(); ) {
tmp = consumer.tweet((Element)i.next());
if (id == null) id = tmp;
}
import org.dom4j.Element;
public class SystemOutTweets implements TweetConsumer {
public String tweet(Element tweet) {
System.out.println(tweet.asXML());
return tweet.elementText("id");
}
public static void main(String[] args) throws TweetException {
TweetProducer t = new TweetProducer();
t.createClient("gavinquan", "123456");
t.setConsumer(new SystemOutTweets());
System.out.println("Start tweeting:");
String id = t.execute(null);
System.out.println("The End; last tweet: " + id);
}
}
<status>
<created_at>Wed Sep 09 06:07:04 +0000 2009</created_at>
<id>3858278078</id>
<text>gmail服务器错误了?</text>
<source><a href="http://twitterfox.net/" rel="nofollow">TwitterFox</a></source>
<truncated>false</truncated>
<in_reply_to_status_id/>
<in_reply_to_user_id/>
<favorited>false</favorited>
<in_reply_to_screen_name/>
<user>
<id>10415752</id>
<name>hugege</name>
<screen_name>hugege</screen_name>
<location>Shantou Guangdong China </location>
<description>www.gegehost.com 博客主机服务</description>
<profile_image_url>http://a1.twimg.com/profile_images/329549706/hugegelogo_normal.jpg</profile_image_url>
<url>http://hugege.com/</url>
<protected>false</protected>
<followers_count>1607</followers_count>
<profile_background_color>C6E2EE</profile_background_color>
<profile_text_color>663B12</profile_text_color>
<profile_link_color>1F98C7</profile_link_color>
<profile_sidebar_fill_color>DAECF4</profile_sidebar_fill_color>
<profile_sidebar_border_color>C6E2EE</profile_sidebar_border_color>
<friends_count>1335</friends_count>
<created_at>Tue Nov 20 16:00:58 +0000 2007</created_at>
<favourites_count>3</favourites_count>
<utc_offset>28800</utc_offset>
<time_zone>Beijing</time_zone>
<profile_background_image_url>http://s.twimg.com/a/1252448032/images/themes/theme2/bg.gif</profile_background_image_url>
<profile_background_tile>false</profile_background_tile>
<statuses_count>1540</statuses_count>
<notifications>false</notifications>
<verified>false</verified>
<following>false</following>
</user>
</status>
The End; last tweet: 3858279409
t.execute("3858279409");
import java.io.FileOutputStream;
import com.lowagie.text.Document;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;
public class HelloWorld {
public static void main(String args[]) {
try {
// step 1: create a Document object
Document document = new Document();
// step 2: connect the Document with an OutputStream using a PdfWriter
PdfWriter.getInstance(document, new FileOutputStream("hello.pdf"));
// step 3: open the document
document.open();
// step 4: add content
document.add(new Paragraph("Hello World"));
// step 5: close the document
document.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.PageSize;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import com.quanlei.exception.TweetException;
import com.quanlei.twitter.TweetConsumer;
import com.quanlei.twitter.TweetProducer;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PdfTwitter implements TweetConsumer {
private int counter = 0;
private Document document;
private Font small_white = new Font(Font.HELVETICA, 8, Font.BOLD);
private Font bold = new Font(Font.HELVETICA, 11, Font.BOLD);
private BaseFont bfChinese = BaseFont.createFont("STSong-Light",
"UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
private Font FontChinese = new Font(bfChinese, 12, Font.NORMAL);
private SimpleDateFormat simpleDateTimeFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public PdfTwitter() throws DocumentException, IOException {
document = new Document(PageSize.A4, 72, 36, 36, 36);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(
"world.pdf"));
writer.setPageEvent(new TwitterPage());
document.open();
}
public void close() {
document.close();
}
public String tweet(org.dom4j.Element tweet) throws TweetException {
try {
org.dom4j.Element user = tweet.element("user");
PdfPTable table = new PdfPTable(new float[]{1, 10, 12});
table.setTableEvent(new TableBackground());
table.setWidthPercentage(100);
table.setSpacingBefore(8);
table.getDefaultCell().setPadding(5);
table.getDefaultCell().setBorder(Rectangle.NO_BORDER);
table.addCell("");
table.addCell(new Phrase(user.elementText("screen_name"),
small_white));
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
table.addCell(new Phrase(simpleDateTimeFormat.format(
new Date(tweet.elementText("created_at"))),
small_white));
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
table.getDefaultCell().setFixedHeight(38);
table.addCell(new Phrase(String.valueOf(++counter), small_white));
table.getDefaultCell().setColspan(2);
Phrase p = new Phrase();
p.add(new Phrase(user.elementText("name"), FontChinese));
p.add(new Phrase(": ", bold));
p.add(new Phrase(tweet.elementText("text"), FontChinese));
table.addCell(p);
document.add(table);
return tweet.elementText("id");
} catch (DocumentException e) {
e.printStackTrace();
throw new TweetException(e);
} catch (IOException e) {
e.printStackTrace();
throw new TweetException(e);
}
}
public static void main(String[] args)
throws DocumentException, org.dom4j.DocumentException,
FileNotFoundException, IOException, TweetException {
PdfTwitter pdf = new PdfTwitter();
TweetProducer t = new TweetProducer();
t.createClient("gavinquan", "123456");
t.setConsumer(pdf);
t.execute(null);
pdf.close();
}
}
import java.io.IOException;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfPTableEvent;
public class TableBackground implements PdfPTableEvent {
protected BaseFont bf;
public TableBackground() throws DocumentException, IOException {
bf = BaseFont.createFont(BaseFont.TIMES_BOLDITALIC, BaseFont.WINANSI,
BaseFont.NOT_EMBEDDED);
}
public void tableLayout(PdfPTable table, float[][] width, float[] height,
int headerRows, int rowStart, PdfContentByte[] canvas) {
PdfContentByte cb = canvas[PdfPTable.BACKGROUNDCANVAS];
cb.saveState();
cb.setRGBColorFill(0x9a, 0xe4, 0xe8);
cb.roundRectangle(width[0][0], height[2], width[0][3] - width[0][0],
height[0] - height[2], 4);
cb.roundRectangle(width[0][1], height[2] + 3,
width[0][3] - width[0][1] - 3, height[1] - height[2] - 6, 4);
cb.eoFill();
cb.beginText();
cb.setRGBColorStroke(0x9a, 0xe4, 0xe8);
cb.setFontAndSize(bf, 28);
cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_STROKE);
cb.showTextAligned(Element.ALIGN_LEFT, "\"", width[0][1],
height[1] - 10, 0);
cb.endText();
cb.restoreState();
}
}
import java.io.IOException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfWriter;
public class TwitterPage extends PdfPageEventHelper {
protected BaseFont bf;
public TwitterPage() throws DocumentException, IOException {
bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",
BaseFont.NOT_EMBEDDED);
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
cb.saveState();
cb.beginText();
cb.setRGBColorStroke(0x9a, 0xe4, 0xe8);
cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_STROKE);
cb.setFontAndSize(bf, 18);
cb.showTextAligned(Element.ALIGN_RIGHT, "www.quanlei.com", 68, 806, 90);
cb.endText();
cb.restoreState();
}
}