JAXB 专题二(BSP接口实战)
BSP下单接口
1、xml格式如下
<?xml version="1.0" encoding="utf-8"?> <Request service="OrderService" lang="zh-CN"> <Head>BSPdevelop</Head> <Body> <Order j_tel="联系电话" j_province="重庆" j_county="渝中区" j_contact=" " j_company="company1" j_city="重庆市" j_address="重庆重庆市渝中区测试一下" d_tel="电话" d_province="广东省"
d_county="南山区" d_contact="联系人" d_company="company1" d_city="深圳市" d_address="广东深圳宝安布心一村" pay_method="2" orderid="123456789"
is_gen_bill_no="1" is_docall="1" express_type="2"> <Cargo name="旧手机"/> </Order> </Body> </Request>
2、构造的xml实体类如下
import java.util.List; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.bind.annotation.XmlType; /** * @ClassName BSPRequest * @Description bsp接口请求元素 * @author * @Date 2018年4月20日 下午4:46:04 * @version 1.0.0 * @param <T> */ @XmlRootElement(name="Request") //@XmlSeeAlso({OrderServiceBody.class}) //工具类中实例化时如果没有加入泛型对象,也可以在这里利用此注解加入可能用到的所有泛型对象 @XmlType(propOrder = { "head", "body"}) //指明生成xml的标签顺序,写属性名 public class BSPRequest<T> { private String service; //请求接口服务名 private String lang; //响应报文语言,中文简体:zh-CN private String head; //接入编码:BSPdevelop private T body; //body:请求数据XML @XmlAttribute(name="service") public String getService() { return service; } public void setService(String service) { this.service = service; } @XmlAttribute(name="lang") public String getLang() { return lang; } public void setLang(String lang) { this.lang = lang; } @XmlElement(name="Head") public String getHead() { return head; } public void setHead(String head) { this.head = head; } @XmlElement(name="Body") public T getBody() { return body; } public void setBody(T body) { this.body = body; } }
import javax.xml.bind.annotation.XmlElement; /** * @ClassName OrderServiceBody * @Description BSP下单接口请求体 * @author * @Date 2018年4月20日 下午5:18:28 * @version 1.0.0 */ public class OrderServiceRequestBody { private BSPOrder order;//order:下单接口请求数据 @XmlElement(name="Order") public BSPOrder getOrder() { return order; } public void setOrder(BSPOrder order) { this.order = order; } }
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; /** * @ClassName BSPOrder * @Description 下单(含筛选)接口 Order元素 * @author * @Date 2018年4月20日 下午4:45:56 * @version 1.0.0 */ public class BSPOrder { private String orderId; //客户订单号 private int isGenBillNo; //1:要求接口返回顺丰运单号 private String jCompany; //寄件方公司名称 private String jContact; //寄件方联系人 private String jTel; //寄件方联系电话 private String jProvince; //寄件方省 private String jCity; //寄件方城市 private String jCounty; //寄件方区/县 private String jAddress; //寄件方详细地址 private String dCompany; //到件方公司名称 private String dContact; //到件方联系人 private String dTel; //到件方联系电话 private String dProvince; //到件方所在省份 private String dCity; //到件方所在城市 private String dCounty; //到件方所在县/区 private String dAddress; //到件方详细地址 private String custid; //顺丰月结卡号 private int payMethod; //付款方式;1:寄方付 2:收方付 3:第三方付 private String remark; //备注 // private int isGenEletricPic; //是否生成电子运单图片,1为是 private OrderCargo cargo; //order下的cargo元素 private int isDocall; //是否要求通过是否手持终端;通知顺丰收派员收件;1:要求 ;其它为不要求 private int expressType; //顺丰默认是1:顺丰特快,2:顺丰特惠; @XmlAttribute(name="orderid") public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } @XmlAttribute(name="is_gen_bill_no") public int getIsGenBillNo() { return isGenBillNo; } public void setIsGenBillNo(int isGenBillNo) { this.isGenBillNo = isGenBillNo; } @XmlAttribute(name="j_company") public String getjCompany() { return jCompany; } public void setjCompany(String jCompany) { this.jCompany = jCompany; } @XmlAttribute(name="j_contact") public String getjContact() { return jContact; } public void setjContact(String jContact) { this.jContact = jContact; } @XmlAttribute(name="j_tel") public String getjTel() { return jTel; } public void setjTel(String jTel) { this.jTel = jTel; } @XmlAttribute(name="j_address") public String getjAddress() { return jAddress; } public void setjAddress(String jAddress) { this.jAddress = jAddress; } @XmlAttribute(name="d_company") public String getdCompany() { return dCompany; } public void setdCompany(String dCompany) { this.dCompany = dCompany; } @XmlAttribute(name="d_contact") public String getdContact() { return dContact; } public void setdContact(String dContact) { this.dContact = dContact; } @XmlAttribute(name="d_tel") public String getdTel() { return dTel; } public void setdTel(String dTel) { this.dTel = dTel; } @XmlAttribute(name="d_province") public String getdProvince() { return dProvince; } public void setdProvince(String dProvince) { this.dProvince = dProvince; } @XmlAttribute(name="d_city") public String getdCity() { return dCity; } public void setdCity(String dCity) { this.dCity = dCity; } @XmlAttribute(name="d_county") public String getdCounty() { return dCounty; } public void setdCounty(String dCounty) { this.dCounty = dCounty; } @XmlAttribute(name="d_address") public String getdAddress() { return dAddress; } public void setdAddress(String dAddress) { this.dAddress = dAddress; } @XmlAttribute(name="custid") public String getCustid() { return custid; } public void setCustid(String custid) { this.custid = custid; } @XmlAttribute(name="pay_method") public int getPayMethod() { return payMethod; } public void setPayMethod(int payMethod) { this.payMethod = payMethod; } @XmlAttribute(name="remark") public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } @XmlElement(name="Cargo",required = true) public OrderCargo getCargo() { return cargo; } public void setCargo(OrderCargo cargo) { this.cargo = cargo; } @XmlAttribute(name="j_province") public String getjProvince() { return jProvince; } public void setjProvince(String jProvince) { this.jProvince = jProvince; } @XmlAttribute(name="j_city") public String getjCity() { return jCity; } public void setjCity(String jCity) { this.jCity = jCity; } @XmlAttribute(name="j_county") public String getjCounty() { return jCounty; } public void setjCounty(String jCounty) { this.jCounty = jCounty; } @XmlAttribute(name="is_docall") public int getIsDocall() { return isDocall; } public void setIsDocall(int isDocall) { this.isDocall = isDocall; } @XmlAttribute(name="express_type") public int getExpressType() { return expressType; } public void setExpressType(int expressType) { this.expressType = expressType; } }
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; /** * @ClassName OrderCargo * @Description 元素<请求>Order/Cargo * @author * @Date 2018年4月20日 下午4:46:45 * @version 1.0.0 */ public class OrderCargo { private String name; //货物名称:旧手机 @XmlAttribute(name="name") public String getName() { return name; } public void setName(String name) { this.name = name; } }
3、jaxb的工具类
import java.io.StringReader; import java.io.StringWriter; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; /** * @ClassName JaxbXmlUtil * @Description Jaxb工具类 xml和java类相互转换 * @author * @Date 2018年4月20日 下午4:45:34 * @version 1.0.0 */ public class JaxbXmlUtil { public static final String DEFAULT_ENCODING = "UTF-8"; /** * pojo转换成xml 默认编码UTF-8 * * @param obj 待转化的对象 * @return xml格式字符串 * @throws Exception JAXBException */ public static String convertToXml(Object obj) throws Exception { return convertToXml(obj, DEFAULT_ENCODING); } /** * pojo转换成xml * * @param obj 待转化的对象 * @param encoding 编码 * @return xml格式字符串 * @throws Exception JAXBException */ public static String convertToXml(Object obj, String encoding) throws Exception { String result = null; JAXBContext context = JAXBContext.newInstance(obj.getClass(), OrderServiceRequestBody.class, RouteServiceRequestBody.class);//指定obj中可以传入的泛型对象,这里BSPRequest<T>使用了泛型,所以必须加入具体可能用到的泛型对象 // JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller marshaller = context.createMarshaller(); // 指定是否使用换行和缩排对已编组 XML 数据进行格式化的属性名称。 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding); StringWriter writer = new StringWriter(); marshaller.marshal(obj, writer); result = writer.toString(); return result; } /** * xml转换成JavaBean * * @param xml xml格式字符串 * @param t 待转化的对象 * @return 转化后的对象 * @throws Exception JAXBException */ @SuppressWarnings("unchecked") public static <T> T convertToJavaBean(String xml, Class<T> t) throws Exception { T obj = null; JAXBContext context = JAXBContext.newInstance(t); Unmarshaller unmarshaller = context.createUnmarshaller(); obj = (T) unmarshaller.unmarshal(new StringReader(xml)); return obj; } /** * @Description <body> 标签中其余字符去掉 (TODO这里用一句话描述这个方法的作用) * @param str * @return * @throws Exception */ public static String StringFilter(String str)throws Exception { //将<Body xsi:type="orderServiceBody" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">替换为<Body> String regEx = "<Body(.|\\s)*?>"; Pattern pattern = Pattern.compile(regEx); Matcher matcher = pattern.matcher(str); return matcher.replaceAll("<Body>").trim(); } }
测试下单接口如下
public class XMLTest { public static void main(String[] args) { try { BSPRequest<OrderServiceRequestBody> orderService = new BSPRequest<OrderServiceRequestBody>(); orderService.setHead("BSPdevelop"); orderService.setLang("zh-CN"); orderService.setService("OrderService"); BSPOrder order = new BSPOrder(); order.setOrderId("15648154"); order.setIsGenBillNo(1); order.setjProvince("重庆"); order.setjCity("重庆"); order.setjCounty("璧山区"); order.setjAddress("广东省深圳市宝安区布心一村"); order.setdCompany("公司1"); order.setdContact("联系人"); order.setdTel("电话"); order.setdAddress("地址"); order.setPayMethod(2); order.setjTel("电话"); OrderCargo cargo = new OrderCargo(); cargo.setName("旧手机"); order.setCargo(cargo); OrderServiceRequestBody body = new OrderServiceRequestBody(); body.setOrder(order); orderService.setBody(body); String xml = JaxbXmlUtil.convertToXml(orderService); System.out.println(xml); String xmlRequest = JaxbXmlUtil.StringFilter(xml).replace("standalone=\"yes\"", ""); //jaxb默认会生成standalone字符串,如果不想要可以这样替换为空串 System.out.println(xmlRequest); } catch (Exception e) { e.printStackTrace(); } } }
BSP路由查询接口
1、xml格式如下
<Request service='RouteService' lang='zh-CN'> <Head>BSPdevelop</Head> <Body> <RouteRequest tracking_type='1' method_type='1' tracking_number='444003077898'/> </Body> </Request>
2、构造的xml实体类如下(请求类和下单一样,只不过具体的请求体不一样)
import javax.xml.bind.annotation.XmlElement; /** * @ClassName RouteServiceBody * @Description 路由查询接口请求体 * @author * @Date 2018年4月24日 上午10:46:32 * @version 1.0.0 */ public class RouteServiceRequestBody { private BSPRouteRequest routeRequest; //RouteRequest元素 @XmlElement(name="RouteRequest") public BSPRouteRequest getRouteRequest() { return routeRequest; } public void setRouteRequest(BSPRouteRequest routeRequest) { this.routeRequest = routeRequest; } }
import javax.xml.bind.annotation.XmlAttribute; /** * @ClassName BSPRouteRequest * @Description 路由查询接口RouteRequest元素 * @author * @Date 2018年4月24日 上午10:48:57 * @version 1.0.0 */ public class BSPRouteRequest { private int trackingType; //查询号类别,1:顺丰运单号查询;2:客户订单号查询 private String trackingNumber; //查询号 @XmlAttribute(name="tracking_type") public int getTrackingType() { return trackingType; } public void setTrackingType(int trackingType) { this.trackingType = trackingType; } @XmlAttribute(name="tracking_number") public String getTrackingNumber() { return trackingNumber; } public void setTrackingNumber(String trackingNumber) { this.trackingNumber = trackingNumber; } }
3、测试路由查询接口(jaxb工具类和前面一样)
public class XMLTest { public static void main(String[] args) { try { BSPRequest<RouteServiceRequestBody> routeService = new BSPRequest<RouteServiceRequestBody>(); routeService.setHead("BSPdevelop"); routeService.setLang("zh-CN"); routeService.setService("RouteService"); RouteServiceRequestBody body = new RouteServiceRequestBody(); BSPRouteRequest routeRequest = new BSPRouteRequest(); routeRequest.setTrackingType(2); routeRequest.setTrackingNumber("哈哈"); body.setRouteRequest(routeRequest); routeService.setBody(body); String xml = JaxbXmlUtil.convertToXml(routeService); System.out.println(xml); String xmlRequest = JaxbXmlUtil.StringFilter(xml).replace("standalone=\"yes\"", ""); System.out.println(xmlRequest); } catch (Exception e) { e.printStackTrace(); } } }
这两个都是jaxb将java对象转换为xml的例子,下面讲一个xml转换为java对象的例子。
BSP路由查询接口的响应体XML转换为java对象
1、xml格式如下
<?xml version="1.0" encoding="utf-8"?> <Response service="RouteService"> <Head>OK</Head> <Body> <RouteResponse mailno="444003077899"> <Route accept_time="2015-01-04 10:11:26" accept_address="深圳" remark="已收件" opcode="50"/> <Route accept_time="2015-01-05 17:41:50" remark="此件签单返还的单号为 123638813181" opcode="922"/> </RouteResponse> </Body> </Response>
2、构造的xml实体类如下
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.bind.annotation.XmlType; /** * @ClassName BSPResponse * @Description bsp响应接口 * @author * @Date 2018年4月24日 上午11:19:14 * @version 1.0.0 */ @XmlRootElement(name="Response") public class BSPResponse { private String service; //响应接口服务名 private String head; //OK:交易成功,只返回Body元素;ERR:交易失败,只返回Error元素; Body元素和Error元素不能同时存在 private BSPError error; //失败时的error元素 private BSPResponseBody body; //响应体 @XmlAttribute(name="service") public String getService() { return service; } public void setService(String service) { this.service = service; } @XmlElement(name="Head") //例如<Head>OK</Head>这样的用XmlElement注释,所以此注释是填充标签之间的内容;而XmlAttribute是填充开始标签中的属性值 public String getHead() { return head; } public void setHead(String head) { this.head = head; } @XmlElement(name="ERROR") public BSPError getError() { return error; } public void setError(BSPError error) { this.error = error; } @XmlElement(name="Body") public BSPResponseBody getBody() { return body; } public void setBody(BSPResponseBody body) { this.body = body; } @Override public String toString() { return "BSPResponse [service=" + service + ", head=" + head + ", error=" + error + ", body=" + body + "]"; } }
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlValue; /** * @ClassName BSPError * @Description 响应Error元素 * @author * @Date 2018年4月24日 上午11:43:46 * @version 1.0.0 */ public class BSPError { private int code; //错误代码 private String message; //错误详细信息 @XmlAttribute(name="code") public int getCode() { return code; } public void setCode(int code) { this.code = code; } @XmlValue //<ERROR code="4001">系统发生数据错误或运行时异常</ERROR>像这样,既有属性值,又有标签内容怎么办呢?就用到XmlValue注释,此注释就是添加内容,不会增加子标签; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } @Override public String toString() { return "BSPError [code=" + code + ", message=" + message + "]"; } }
import javax.xml.bind.annotation.XmlElement; /** * @ClassName BSPResponseBody * @Description BSP响应体(这里用一句话描述这个类的作用) * @author * @Date 2018年4月25日 上午11:41:04 * @version 1.0.0 */ public class BSPResponseBody { private BSPOrderResponse orderResponse; //下单接口响应体 private BSPRouteResponse routeResponse; //路由查询接口响应体内容 @XmlElement(name="OrderResponse") public BSPOrderResponse getOrderResponse() { return orderResponse; } public void setOrderResponse(BSPOrderResponse orderResponse) { this.orderResponse = orderResponse; } @XmlElement(name="RouteResponse") public BSPRouteResponse getRouteResponse() { return routeResponse; } public void setRouteResponse(BSPRouteResponse routeResponse) { this.routeResponse = routeResponse; } }
注意:我们前面请求接口例子中,请求接口对象是可以用泛型的,可是我网上找了发现xml转换为javabean时用不了泛型,所以我就在响应体BSPResponseBody中写了多个响应体对象,这里有下单和路由查询两个响应体对象,这样我也不用重复写多个响应接口BSPResponse ,一个响应接口对象中有一个BSPResponseBody响应体对象,响应体对象中有多个不同的响应对象,即使要转换的xml中没有此对象也没关系,不过是转换后的java对象中对应的该对象为空而已,不会影响业务代码。
import java.util.List; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; /** * @ClassName BSPRouteResponse * @Description 路由查询接口响应元素RouteResponse * @author * @Date 2018年4月25日 上午10:37:46 * @version 1.0.0 */ public class BSPRouteResponse { private String mailNo; //顺丰运单号 private String orderId; //客户订单号,按客户订单号查询时为必填。按顺丰运单号查询时为空。 private List<RouteResponseRoute> routeResponseRouteList; //子元素 RouteResponse/Route,多个 @XmlAttribute(name="mailno") public String getMailNo() { return mailNo; } public void setMailNo(String mailNo) { this.mailNo = mailNo; } @XmlAttribute(name="orderid") public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } @XmlElement(name="Route") public List<RouteResponseRoute> getRouteResponseRouteList() { return routeResponseRouteList; } public void setRouteResponseRouteList(List<RouteResponseRoute> routeResponseRouteList) { this.routeResponseRouteList = routeResponseRouteList; } @Override public String toString() { return "BSPRouteResponse [mailNo=" + mailNo + ", orderId=" + orderId + ", routeResponseRouteList=" + routeResponseRouteList + "]"; } }
import java.util.Date; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; /** * @ClassName RouteResponseRoute * @Description 路由查询接口 响应元素 RouteResponse/Route * @author * @Date 2018年4月25日 上午10:50:27 * @version 1.0.0 */ public class RouteResponseRoute implements Comparable<RouteResponseRoute> { private Date acceptTime; //路由节点发生的时间,格式:YYYY-MM-DD HH24:MM:SS,示例:2012-7-30 09:30:00。 private String acceptAddress; //路由节点发生的地点 private String remark; //路由节点具体描述 private String opcode; //路由节点操作码 @XmlAttribute(name="accept_time") @XmlJavaTypeAdapter(JaxbDateSerializer.class) //日期格式的转换,定义了一个JaxbDateSerializer转换类,使用此注解就可以了 public Date getAcceptTime() { return acceptTime; } public void setAcceptTime(Date acceptTime) { this.acceptTime = acceptTime; } @XmlAttribute(name="accept_address") public String getAcceptAddress() { return acceptAddress; } public void setAcceptAddress(String acceptAddress) { this.acceptAddress = acceptAddress; } @XmlAttribute(name="remark") public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } @XmlAttribute(name="opcode") public String getOpcode() { return opcode; } public void setOpcode(String opcode) { this.opcode = opcode; } @Override public String toString() { return "RouteResponseRoute [acceptTime=" + acceptTime + ", acceptAddress=" + acceptAddress + ", remark=" + remark + ", opcode=" + opcode + "]"; } @Override public int compareTo(RouteResponseRoute o) { long l = this.getAcceptTime().getTime() - o.getAcceptTime().getTime(); if (l > 0) { return -1; }else if (l == 0) { return 0; }else { return 1; } } }
import java.text.SimpleDateFormat; import java.util.Date; import javax.xml.bind.annotation.adapters.XmlAdapter; //日期转化的类 public class JaxbDateSerializer extends XmlAdapter<String, Date> { private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public Date unmarshal(String date) throws Exception { return dateFormat.parse(date); } @Override public String marshal(Date date) throws Exception { return dateFormat.format(date); } }
3、测试xml转换为java对象(jaxb工具类和前面一样)
public class XMLTest { public static void main(String[] args) { try { BSPResponse response = JaxbXmlUtil.convertToJavaBean("<Response service='RouteService'><Head>OK</Head><Body><RouteResponse mailno='444003077899'><Route accept_time='2015-01-04 10:11:26' accept_address='深圳' remark='已收件' opcode='50'/><Route accept_time='2015-01-05 17:41:50' remark='此件签单返还的单号为 123638813181' opcode='922'/></RouteResponse></Body></Response>", BSPResponse.class); System.out.println("head:" + response.getHead()); System.out.println("service:" + response.getService()); System.out.println("error:" + response.getError()); System.out.println("osrBody:" + response.getBody().getOrderResponse()); System.out.println("rsrBody:" + response.getBody().getRouteResponse()); System.out.println("RouteResponse/route:" + response.getBody().getRouteResponse().getRouteResponseRouteList()); Date d1 = response.getBody().getRouteResponse().getRouteResponseRouteList().get(0).getAcceptTime(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String str1 = sdf.format(d1); System.out.println(str1); Date d2 = response.getBody().getRouteResponse().getRouteResponseRouteList().get(1).getAcceptTime(); String str2 = sdf.format(d2); System.out.println(str2); } catch (Exception e) { e.printStackTrace(); } } }
后续用到更复杂jaxb操作的再来补上....
带着疑问去思考,然后串联,进而归纳总结,不断追问自己,进行自我辩证,像侦查嫌疑案件一样看待技术问题,漆黑的街道,你我一起寻找线索,你就是技术界大侦探福尔摩斯