`
sarin
  • 浏览: 1746876 次
  • 性别: Icon_minigender_1
  • 来自: 大连
博客专栏
E3b14d1f-4cc5-37dd-b820-b6af951740bc
Spring数据库访问系列...
浏览量:172722
C2083dc5-6474-39e2-993e-263652d27795
Android学习笔记
浏览量:366360
5f40a095-b33c-3e8e-8891-606fcf3b8d27
iBatis开发详解
浏览量:188215
B272a31d-e7bd-3eff-8cc4-c0624ee75fee
Objective-C学习...
浏览量:98592
社区版块
存档分类
最新评论

使用XStream解析XML(使用HttpClient 4发送请求)

阅读更多
    本文意在简单说明XStream解析XML,配合HttpClient 4发送请求,请求淘宝的开放API,那么我们在电子商务模式的系统中就可以使用一些淘宝API来为系统增加一个与众不同的模块。
    首先来看淘宝API,这是本应用的重要部分,淘宝API的手册可以在线查看:下面就来说说简单的流程。我们通过URL发出请求,并收到返回的结果(XML或JSON)。请求中包含了一些必须的参数,这个就是文档中说明的。这里我们使用淘宝的商品API,获取一些商品的信息。在这之前需要在开放平台注册,获取你自己的APP_KEY和APP_SECRET,很简单。
    获取到必要信息后,我们来看一下URL请求,这个需要符合TAOBAO的要求,才能请求到数据,其中有一段信息是加密的,就是签名字段,这个字段的计算比较复杂,网站提供的方法好像已经不能用了,那么我根据TAOBAO提供的SDK源码自行提取有用部分来编写了一个简单的算法。首先我们来看一下测试应用的结构:

    使用Maven对应用进行管理,因为只是简单的应用程序,所以配置很简单,引入的第三方依赖也不多,我们来看看都需要些什么:

    加入了这些依赖之后,我们就可以进行开发了。看了之前的代码结构,我们先从请求TAOBAO的数据开始说。就是生成请求签名的类SinguratureGenerator.java来看:
package taobao.util;
import java.security.MessageDigest;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;
import org.apache.commons.lang.StringUtils;

/**
 * 生成淘宝API中的签名密码
 * 
 * @author Sarin
 * 
 */
public class SignatureGenerator {
	/**
	 * 获取MD5加密结果
	 * 
	 * @param params
	 *            参数集合
	 * @param secret
	 *            申请得到的APP_SECRET
	 * @return
	 */
	public static String getMD5Signature(TreeMap<String, String> params,
			String secret) {
		// 存储签名的StringBuffer
		StringBuilder sign = new StringBuilder();
		// 获取参数的项集合
		Set<Entry<String, String>> paramSet = params.entrySet();
		// 组合要编码的串
		StringBuilder query = new StringBuilder(secret);
		// 遍历参数集合,获取参数值,形式key+value
		for (Entry<String, String> param : paramSet) {
			if (StringUtils.isNotEmpty(param.getKey())
					&& StringUtils.isNotEmpty(param.getValue())) {
				query.append(param.getKey()).append(param.getValue());
			}
		}
		try {
			// 使用MD5加密
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			byte[] bytes = md5.digest(query.toString().getBytes("UTF-8"));
			// 把二进制转化为大写的十六进制
			for (int i = 0; i < bytes.length; i++) {
				String hex = Integer.toHexString(bytes[i] & 0xFF);
				if (hex.length() == 1) {
					sign.append("0");
				}
				sign.append(hex.toUpperCase());
			}
		} catch (Exception e) {
			throw new java.lang.RuntimeException("Signature Generate Error!");
		}
		return sign.toString();
	}
}

    我们使用的是MD5的加密算法,需要传入一个TreeMap类型的参数集合对象,还有就是申请到的APP_SECRET字符串。使用TreeMap主要是利用其按照参数名的字典顺序排序特性,这也是TAOBAO的API要求的,那么算法注释很清楚了,这也是对它的SDK的简化,只保留必要内容。下面就是请求TAOBAO-API的类了,里面拼凑了请求参数并获得返回的结果:
package taobao;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import taobao.util.SignatureGenerator;
/**
 * 获取淘宝API返回的结果
 * 
 * @author Sarin
 * 
 */
public class GetResult {
	// 需要的常量参数
	private static final String URL = "http://gw.api.taobao.com/router/rest";
	private static final String APP_KEY = "请填写你申请的";
	private static final String APP_SECRET = "请填写你申请的";
	private static final String FORMAT = "xml";
	private static final String METHOD = "taobao.item.get";
	private static final String VERSION = "2.0";
	private static DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	/**
	 * 获取结果的方法
	 * 
	 * @param fields
	 *            需要请求的商品字段
	 * @param num_iid
	 *            商品ID,淘宝网URL中获得
	 * @return
	 */
	public static String getResult(String fields, String num_iid) {
		String content = null;
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(URL);
		String timestamp = getFullTime();
		List<NameValuePair> params = new ArrayList<NameValuePair>();
		params.add(new BasicNameValuePair("app_key", APP_KEY));
		params.add(new BasicNameValuePair("format", FORMAT));
		params.add(new BasicNameValuePair("method", METHOD));
		params.add(new BasicNameValuePair("num_iid", num_iid));
		params.add(new BasicNameValuePair("fields", fields));
		params.add(new BasicNameValuePair("timestamp", timestamp));
		params.add(new BasicNameValuePair("partner_id", "911"));
		params.add(new BasicNameValuePair("v", VERSION));
		params.add(new BasicNameValuePair("sign", SignatureGenerator
				.getMD5Signature(getParams(timestamp, fields, num_iid),
						APP_SECRET)));
		try {
			post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
			HttpResponse response = client.execute(post);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_IMPLEMENTED) {
				System.err
						.println("The Post Method is not implemented by this URI");
			} else {
				content = EntityUtils.toString(response.getEntity());
			}
		} catch (IOException e) {
			System.err.println(e);
		} finally {
			client.getConnectionManager().shutdown();
		}
		return content;
	}
	/**
	 * 拼装参数
	 * 
	 * @param timestamp
	 *            当前时间戳
	 * @param fields
	 *            需要请求的商品字段
	 * @param num_iid
	 *            商品ID,淘宝网URL中获得
	 * @return
	 */
	public static TreeMap<String, String> getParams(String timestamp,
			String fields, String num_iid) {
		TreeMap<String, String> treeMap = new TreeMap<String, String>();
		treeMap.put("timestamp", timestamp);
		treeMap.put("v", VERSION);
		treeMap.put("app_key", APP_KEY);
		treeMap.put("method", METHOD);
		treeMap.put("partner_id", "911");
		treeMap.put("format", FORMAT);
		treeMap.put("fields", fields);
		treeMap.put("num_iid", num_iid);
		return treeMap;
	}
	/**
	 * 获取格式化好的时间
	 * 
	 * @return
	 */
	public static String getFullTime() {
		return df.format(new java.util.Date());
	}
}

    至此我们已经可以获得返回的XML数据,其中封装了商品信息,剩下的就是解析商品信息了,TAOBAO对商品信息定义了数据结构,我们按照这个结构封装对象,之后结合XStream来解析XML就获得了我们想要的数据了,那么先看商品数据结构,这里仅获取几个简单的供示例演示使用:
package taobao.bean;
public class Response {
	private Item item;
	public Item getItem() {
		return item;
	}
	public void setItem(Item item) {
		this.item = item;
	}
}

    这里封装了整体的响应结果,item是商品的数据结构,如下:
package taobao.bean;
public class Item {
	private String nick;
	private String price;
	private Location location;
	public String getNick() {
		return nick;
	}
	public void setNick(String nick) {
		this.nick = nick;
	}
	public String getPrice() {
		return price;
	}
	public void setPrice(String price) {
		this.price = price;
	}
	public Location getLocation() {
		return location;
	}
	public void setLocation(Location location) {
		this.location = location;
	}
}

    这里我们只要三个信息:卖家名称,商品价格,商品所在地,而所在地又是一个封装的数据结果对象,简单示例如下:
package taobao.bean;
public class Location {
	private String state;
	private String city;
	public String getState() {
		return state;
	}
	public void setState(String state) {
		this.state = state;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
}

    获取省份和城市,这些数据结构的完整信息就要参考API文档了,这里仅仅是示例。下面就可以运行测试类了:
package taobao;
import taobao.bean.Item;
import taobao.bean.Location;
import taobao.bean.Response;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
/**
 * 获取商品信息测试类
 * 
 * @author Sarin
 * 
 */
public class TaobaoXMLResult {
	public static void main(String[] args) throws Exception {
		// 获取的商品ID和需要的字段
		String resultXML = GetResult.getResult("price,location,nick",
				"74222099XX");
		// XStream解析XML
		XStream xstream = new XStream(new DomDriver());
		xstream.alias("item_get_response", Response.class);
		xstream.alias("item", Item.class);
		xstream.alias("location", Location.class);
		System.out.println(resultXML);
		// XML转对象
		Response response = (Response) xstream.fromXML(resultXML);
		Item item = response.getItem();
		// 打印结果
		System.out.println("省份: " + item.getLocation().getState());
		System.out.println("价格: " + item.getPrice());
		System.out.println("店铺名称: " + item.getNick());
	}
}

    XStream的使用很简单,将XML中的标签和对象进行别名绑定,之后读取XML并根据标签的层级进行数据填充,之后我们就可以按照预先定于的对象进行数据获取了,这里为了保护测试的卖家信息,将ID中最后两位隐藏,运行测试类,就得到如下的信息了:

    本文系作者的实践探索,文中做法也许并非最佳实践,仅提供简单示例供参考,后续还有使用JACKON解析JSON的示例,同时结合另外一种API来展示应用。欢迎交流,希望对使用者有用。
  • 大小: 9.3 KB
  • 大小: 56 KB
  • 大小: 53.3 KB
分享到:
评论
4 楼 sarin 2011-04-18  
sckalman 写道
我用您的代码测试出现这个问题

Exception in thread "main" com.thoughtworks.xstream.mapper.CannotResolveClassException: error_response : error_response
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:68)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)at com.thoughtworks.xstream.XStream.fromXML(XStream.java:853)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:845)
at taobao.TaobaoXMLResult.main(TaobaoXMLResult.java:25) 请指教 suncansoftware@gmail.com

这个代码的允许需要TAOBAO的key,看看是不是返回的XML本身出现问题导致后面无法解析的。设置断点跟踪一下即可。
3 楼 sckalman 2011-04-18  
我用您的代码测试出现这个问题

Exception in thread "main" com.thoughtworks.xstream.mapper.CannotResolveClassException: error_response : error_response
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:68)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)at com.thoughtworks.xstream.XStream.fromXML(XStream.java:853)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:845)
at taobao.TaobaoXMLResult.main(TaobaoXMLResult.java:25) 请指教 suncansoftware@gmail.com
2 楼 sarin 2010-11-25  
sniperking 写道
问一下你那个类图是用什么工具生成的啊

maven的eclipse插件m2e
1 楼 sniperking 2010-11-25  
问一下你那个类图是用什么工具生成的啊

相关推荐

Global site tag (gtag.js) - Google Analytics