前言:
博客园似乎不太喜欢设计模式的东西,一连写了几篇设计模式的东西,都没什么人气,也许是写的水平有些不够,另外设计模式属于内功,怎们都得修炼一下,否则,设计混乱,不成体系,对于大型项目来说,就会显的特别的小儿科,因此,无论如何,都得继续学习与修炼。今天就写点之前项目涉及到的Webservice处的一些关键设计与部分源码,这里只是描述关键部分,因为涉及到之前公司的一些东西,特别是对于数据库操作部分没有展示,另外对于部分内容,也进行了重构与简化,希望各位了解。
业务场景:
先描述一下业务场景,我们系统运行稳健,由于某些原因,有部分业务功能需要切换到另外的系统去处理,但是,需要保证双方系统数据在业务层面的实时更新[因此仅数据库层面的同步更新是不可取,以后,会开源自己开发的数据库层面的同步工具,有需要可以留言,以便尽快整理],所以主要是利用webservice技术,由于双方系统的固有差距,相关webservice的互联调试费了些功夫,这里不做太多介绍,双方通信的基础是互相传递Xml数据,这就涉及到了xml的解析,xml的构造等。另外,由于业务的多样化,这里用到了类似简单工厂的设计方法,现在看来,当时只是为了尽快的解决的问题,对于设计的深层考虑还是缺乏的,有很多地方都是不尽合理的,还需要继续深究设计模式。还有一部分就是数据持久化的过程,这一块对于不同的业务需求做了封装,具体这里就不做介绍。其他如日志记录等也就不赘述了。用到的开源类库有Jdom,axis,cxf等
核心实现代码:
webservice互联部分:
服务器端ServiceRun.java:
package me.service; public class ServiceRun { public static void main(String[] args) { System.out.println("Starting Server"); ZC zc = new ZCImpl(); String address = "http://localhost:8090/ZC"; javax.xml.ws.Endpoint.publish(address, zc); System.out.println("服务启动完成。。。。"); } }
客户端访问:
package me.service; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; import org.apache.axis.client.Call; import org.apache.axis.client.Service; public class ClientRun { public static void main(String[] args) throws Exception { String url = "http://localhost:8090/ZC"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(new URL(url)); String targetNamespace = "http://service.me/"; QName qName = new QName(targetNamespace,"getZcmethod"); call.setOperationName(qName); call.addParameter("text", null,ParameterMode.IN); String message = (String) call.invoke( new Object[]{"test"}); System.out.println(message); } }
辅助实现类:
package me.service; import javax.jws.WebService; @WebService(endpointInterface="me.service.ZC",name="ZC") public class ZCImpl implements ZC{ @Override public String getZcmethod(String text) throws Exception { System.out.println("parameter is =======>>>> " + text); return "parameter is =======>>>> " + text; } }
这一部分代码,较为简单而且属于固定模式的。不多介绍。
==================================华丽分割线=======================================
xml服务类,包括解析与构造,这里使用了单例模式(发现之前使用的很不规范,现在仍然使用了饿汉模式,又重新写了双重锁机制)。另外使用了反射机制机制,主要目的是将解析得到的结果转化为类的结果。还是看代码吧。
/** * <p>File Name:xmlService.java</p> * <p>Create Time:2014-9-22</p> * <p>Create Author:ljl</p> * <p>Description:</p> * <p>Version:1.0</p> * <p>Modify:</p> */ package com.service.xmlService; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import com.service.business.bean.ZC_GDZC; import com.service.serviceHelper.StrUtil; import com.service.xmlService.node.CWROW; import com.service.xmlService.node.CWROWDATA; import com.service.xmlService.node.DATAPACKAGE; /** * <p>Class Name:xmlService.java</p> * <p>Create Time:2014-9-22</p> * <p>Create Author:ljl</p> * <p>Description:</p> * <p>Version:1.0</p> * <p>Modify:</p> */ public class XmlService { /** 不重复随机号*/ private static String PACKAGEID = ""; /** 调用监控服务*/ private static String PACKAGETYPE = ""; private static List sendRdList = new ArrayList(); private static String sendStrXml = ""; private static Object Bean; private static XmlService instance=null; /** * <p>Method Name:</p> * <p>Create Time:2014-9-22</p> * <p>Create Author:ljl</p> * <p>Description:</p> * <p>Version:1.0</p> * <p>Modify:</p> */ private XmlService(){ } public static XmlService getInstance(){ if(null==instance){ synchronized (XmlService.class) { if(null==instance){ instance=new XmlService(); } } } return instance; } public void setBean(Object bean) { Bean = bean; } public Object getBean() { return Bean; } /** * * <p>Method Name:</p> * <p>Create Time:2014-9-24</p> * <p>Create Author:ljl</p> * <p>Description:make the bean to xml</p> * <p>Version:1.0</p> * <p>Modify:</p> */ public String beansToStrXml(Object []beans) throws Exception{ sendRdList = new ArrayList(); sendStrXml = ""; for(int i=0;i<beans.length;i++){ sendRdList.add(beans[i]); } DATAPACKAGE dpSend = new DATAPACKAGE(); CWROWDATA cwSend = new CWROWDATA(); CWROW row = new CWROW(); cwSend.setPACKAGEID(PACKAGEID); cwSend.setPACKAGETYPE(PACKAGETYPE); row.setROW(sendRdList); cwSend.setROWDATA(row); dpSend.setCW(cwSend); Document document = XMLDocumentUtil.createXMLDocument(dpSend); sendStrXml = XMLDocumentUtil.getStrFromDoc(document); return sendStrXml; } /** * * <p>Method Name:</p> * <p>Create Time:2014-9-24</p> * <p>Create Author:ljl</p> * <p>Description:get the data node list</p> * <p>Version:1.0</p> * <p>Modify:</p> */ public ArrayList parseXML(String recStrXml){ // System.out.println(recStrXml); LinkedHashMap map=new LinkedHashMap(); ArrayList retArr=new ArrayList(); if(StrUtil.isEmpty(recStrXml)){ return null; }else{ SAXBuilder builder = new SAXBuilder(); Document doc=null; try { doc = builder.build(new ByteArrayInputStream(recStrXml.getBytes("GB2312"))); Element cw = null; if (doc.getRootElement()!=null&&doc.getRootElement().getChild(IXmlMemberUtil.CWNAME) != null){ cw = doc.getRootElement().getChild(IXmlMemberUtil.CWNAME); PACKAGEID = cw.getChildText(IXmlMemberUtil.PACKANGEIDNAME); // PACKAGETYPE = cw.getChildText(IXmlMemberUtil.PACKAGETYPENAME); // } if (cw.getChild(IXmlMemberUtil.ROWDATA)!=null&&cw.getChild(IXmlMemberUtil.ROWDATA).getChildren(IXmlMemberUtil.ROW)!= null){ List rds = cw.getChild(IXmlMemberUtil.ROWDATA).getChildren(IXmlMemberUtil.ROW); for(int i=0;i<rds.size();i++){ Element row=((Element)rds.get(i)); List rows=row.getChildren(); for(int j=0;j<rows.size();j++){ Element rs=((Element)rows.get(j)); map.put(rs.getName(), rs.getValue()); } retArr.add(map); } } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } return retArr; } /** * * <p>Method Name:</p> * <p>Create Time:2014-9-26</p> * <p>Create Author:ljl</p> * <p>Description:change the bean to linkedhashmap.</p> * <p>Version:1.0</p> * <p>Modify:</p> */ public LinkedHashMap beanToLinkedHashMap(Object bean){ java.lang.reflect.Field []f= bean.getClass().getFields(); LinkedHashMap lmap=new LinkedHashMap(); for(int i=0;i<f.length;i++){ try { lmap.put(f[i].getName(), f[i].get(bean)); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return lmap; } /** * * <p>Method Name:</p> * <p>Create Time:2014-9-26</p> * <p>Create Author:ljl</p> * <p>Description:chage the linkedhashmap to the bean.</p> * <p>Version:1.0</p> * <p>Modify:</p> */ public void LinkedHashMapToBean(LinkedHashMap lmap){ if(lmap==null){ return; } Class bClass=Bean.getClass(); Iterator it=lmap.entrySet().iterator(); Method []method=bClass.getMethods(); while(it.hasNext()){ Map.Entry entry=(Map.Entry)it.next(); String kName=entry.getKey().toString().toUpperCase(); for(int i=0;i<method.length;i++){ Method m=method[i]; String mName=m.getName().toUpperCase(); if((mName.indexOf(kName)!=-1)&&(mName.indexOf(IXmlMemberUtil.SET)!=-1)){ try { Class [] o= new Class[1]; o[0]=String.class; Method mSet=bClass.getDeclaredMethod(m.getName(), o); try { String [] s=new String[1]; s[0]=entry.getValue().toString(); mSet.invoke(Bean,s); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } } } } /** * * <p>Create Auther:ljl</p> * <p>Create Time:2014-10-29</p> * <p>Description:</p> * <p>Version:1.0</p> * <p>Modify Time:</p> * <p>Modify Author:</p> * <p>Modify Content:</p> */ public Object invokeMehtod(Object bean,String methodName,Object[]args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{ Class bClass=bean.getClass(); Class []argClass=new Class[args.length]; for(int i=0;i<args.length;i++){ argClass[i] = args.getClass(); } Method method=bClass.getDeclaredMethod(methodName, argClass); return method.invoke(bean, args); } public static void main(String[] args) { XmlService c =XmlService.getInstance(); StringBuffer sb=new StringBuffer(); sb.append("<?xml version='1.0' encoding='GB2312'?>" +"<DATAPACKAGE>" +"<CW>" +"<PACKAGEID>001</PACKAGEID>" +"<PACKAGETYPE>GDZC</PACKAGETYPE>" +"<ROWDATA>" +"<ROW>" +"<JLHH>123122312</JLHH>" +"<ZCMC>你好</ZCMC>" +"</ROW>" +"<ROW>" +"<JLHH>1213545</JLHH>" +"<ZCMC>你好adds</ZCMC>" +"</ROW>" +"</ROWDATA>" +"</CW>" +"</DATAPACKAGE>"); ArrayList arr=new ArrayList(); arr=c.parseXML(sb.toString()); c.setBean(new ZC_GDZC()); ZC_GDZC z[] =new ZC_GDZC[arr.size()]; for(int i=0;i<arr.size();i++){ LinkedHashMap lmap= (LinkedHashMap)arr.get(i); Iterator it=lmap.entrySet().iterator(); while(it.hasNext()){ Map.Entry entry=(Map.Entry)it.next(); String kName=entry.getKey().toString().toUpperCase(); String kValue=entry.getValue().toString().toUpperCase(); System.out.println(kName+":"+kValue); } c.LinkedHashMapToBean(lmap); System.out.println("+++"+((ZC_GDZC)c.getBean()).getJLHH()); System.out.println("+++"+((ZC_GDZC)c.getBean()).getZCMC()); z[i]=(ZC_GDZC)c.getBean(); System.out.println("==="+z[i].getJLHH()); System.out.println("==="+z[i].getZCMC()); } try { System.out.println(c.beansToStrXml(z)); } catch (Exception e) { e.printStackTrace(); } // // // try { // PACKAGEID="001"; // PACKAGETYPE="MESSAGE"; // try { // MESSAGE m=new MESSAGE(); //// Class bClass=Class.forName(getBean().getClass().getName()); // try { //// m = (MESSAGE)bClass.newInstance(); // m.setMsgResult("1"); // m.setMsgType("GDZC"); // Bean=m; // System.out.println("msg:"+m.getMsgType()); // System.out.println(c.beanToLinkedHashMap(m)); // System.out.println(c.beanToStrXml(m)); // // ArrayList arr=c.parseXML(c.beanToStrXml(m)); // for(int i=0;i<arr.size();i++){ // LinkedHashMap lmap= (LinkedHashMap)arr.get(i); // c.LinkedHashMapToBean(lmap); // } // } catch (InstantiationException e) { // e.printStackTrace(); // } catch (IllegalAccessException e) { // e.printStackTrace(); // } // } catch (ClassNotFoundException e) { // e.printStackTrace(); // } // } catch (Exception e) { // e.printStackTrace(); // } } }
另外将xml的基础类,写在下边:
package com.service.xmlService; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; public class XMLDocumentUtil { /** * 利用对象生产相应的xml数据信息 * @param obj 数据源 * @return document xml文档对象 * @throws Exception */ public static Document createXMLDocument(Object obj) throws Exception { Element headerNode = getElementFromName(obj.getClass().getName()); Document document = new Document(headerNode); int flag = estimateNestingNode(obj); if (0 == flag) { headerNode.addContent("" + obj); } else { distributeCreateNodeTask(null, obj, headerNode, flag); } return document; } /** * 根据属性类型选择相应的处理方法 * @param name 父节点的名称 * @param obj 数据源 * @param element 父节点 * @flag 相应方法的选择依据 * throws Exception * */ private static void distributeCreateNodeTask(String name, Object obj, Element element, int flag) throws Exception { if (flag == 1) { createNodeProperties(name, obj, element); } else if (flag == 2) { createSingleNode(name, obj, element); } else if (flag == 3) { createListNode(name, obj, element); } else if (flag == 4) { createMapNode(name, obj, element); } else if (flag == 5) { createSetNode(name, obj, element); } } /** * 生成对象数组结点 * @param name 父节点的名称 * @param obj 数据源 * @param element 父节点 * @flag 相应方法的选择依据 * throws Exception */ public static void createNodeProperties(String name, Object obj, Element element) throws Exception { Element nodes; if (null == name || name.equals("") || name.trim().equals("")) { nodes = element; } else { nodes = new Element(name); element.addContent(nodes); } Object[] objects = (Object[]) obj; for (int i = 0; i < objects.length; i++) { Element node = getElementFromName(objects[i].getClass().getName()); nodes.addContent(node); createSingleElement(objects[i], node); } } /** * @Title createSingleNode * @Description TODO * @param name * @param obj * @param element * @throws Exception * @Return void * @Throws * @user Administrator * @Date 2016年1月20日 */ public static void createSingleNode(String name, Object obj, Element element) throws Exception { Element node; if (null == name || name.equals("") || name.trim().equals("")) { node = element; } else { node = new Element(name); element.addContent(node); } createSingleElement(obj, node); } /** * 将类属性所有数据依次写入相应xml的类结点中 * * @param obj 数据源 * @param element 类结点 * throws Exception */ public static void createSingleElement(Object obj, Element element) throws Exception { Field[] fields = obj.getClass().getDeclaredFields(); for (int i = 0; i < fields.length; i++) { int flag = estimateNestingNode(fields[i], obj); String name = fields[i].getName(); if (0 == flag) { setNodeProperties(fields[i], obj, element); } else { distributeCreateNodeTask(name, fields[i].get(obj), element,flag); } } } /** * 生成List类型的结点 * * @param name 结点名称 * @param obj 数据源 * @param element 父结点 * throws Exception */ public static void createListNode(String name, Object obj, Element element) throws Exception { Element node; // if (null != name && !name.trim().equals("")) { // node = new Element(name); // //node.setAttribute("name", name); // element.addContent(node); // } else { node = element; // } List list = (List) obj; for(int i=0;i<list.size();i++){ Object object = (Object)list.get(i); createListElement(object, node,name); } } /** * 将List类型数据写入相应xml的List结点 * * @param name 结点名称 * @param obj 数据源 * @param element 类结点 * throws Exception */ public static void createListElement(Object obj, Element element,String name) throws Exception { int flag = estimateNestingNode(obj); //String name = "value"; if (0 == flag) { Element node = new Element(name); node.addContent("" + obj); element.addContent(node); } else { distributeCreateNodeTask(name, obj, element, flag); } } /** * 将Map类型数据写入相应xml的Map结点 * * @param name 结点名称 * @param obj 数据源 * @param element 类结点 * throws Exception */ public static void createMapNode(String name, Object obj, Element element) throws Exception { Element node; if (null != name && !name.trim().equals("")) { node = new Element("Map"); node.setAttribute("name", name); element.addContent(node); } else { node = element; } Map map = (Map) obj; for (Iterator key= map.keySet().iterator();key.hasNext();) { if (null == key) { continue; } Object object = (Object)key.next(); Element ele = new Element("entry"); ele.setAttribute("key", "" + object); node.addContent(ele); createMapElement(map.get(object), ele); } } /** * 将Map类型数据写入相应xml的Map结点 * @param name 结点名称 * @param obj 数据源 * @param element 类结点 * throws Exception */ public static void createMapElement(Object obj, Element node) throws Exception { int flag = estimateNestingNode(obj); String name = "value"; if (0 == flag) { node.setAttribute(name, "" + obj); } else { distributeCreateNodeTask(name, obj, node, flag); } } /** * 将Set类型数据写入相应xml的Set结点 * @param name 结点名称 * @param obj 数据源 * @param element 类结点 * throws Exception */ public static void createSetNode(String name, Object obj, Element element) throws Exception { Element node; if (null != name && !name.trim().equals("")) { node = new Element("Set"); node.setAttribute("name", name); element.addContent(node); } else { node = element; } Set set = (Set) obj; for (Iterator key= set.iterator(); key.hasNext();) { Object object = (Object)key.next(); createListElement(object, node,name);// set、list结构一样 } } /** * 将单个基础java类型(flag==0)的属性数据写入相应xml的类节点的子结点中 * @param field 属性信息 * @param obj 数据源 * @param element 类结点 * throws Exception */ private static void setNodeProperties(Field field, Object obj, Element element) throws Exception { String name = field.getName(); boolean accFlag = field.isAccessible(); field.setAccessible(true); Object value = field.get(obj); field.setAccessible(accFlag); Element node; if (null == name || name.equals("") || name.trim().equals("")) { node = element; } else { node = new Element(name); element.addContent(node); } node.setText(String.valueOf(value)); } /** * @Title estimateNestingNode * @Description * 0--基本数据类型、String * 1--数组 * 2--自定义类 * 3--List * 4--Map * 5--Set * @param obj * @return * @Return int * @Throws * @user Administrator * @Date 2016年1月20日 */ private static int estimateNestingNode(Object obj) { String str = ""; if (obj instanceof List) { return 3;// 表示该属性是list } if (obj instanceof Map) { return 4;// 表示该属性是Map } if (obj instanceof Set) { return 5;// 表示该属性是Set } if (null != obj) { str = obj.getClass().getName(); } if (str.indexOf("[") != -1) { return 1; } if (str.indexOf("java") != -1) { return 0; } return 2; } private static int estimateNestingNode(Field field, Object obj) throws Exception { String str = ""; Object value = null; value = field.get(obj); if (value instanceof List) { return 3;// 表示该属性是list } if (value instanceof Map) { return 4;// 表示该属性是list } if (value instanceof Set) { return 5;// 表示该属性是list } if (null != value) { str = value.getClass().getName(); if (str.indexOf("[") != -1) { return 1; } if (str.indexOf("java") != -1) { return 0; } } return 2; } /** * @Title getElementFromName * @Description TODO * @param name * @return * @Return Element * @Throws * @user Administrator * @Date 2016年1月20日 */ private static Element getElementFromName(String name) { String[] namesplit = name.split("\."); if (namesplit[namesplit.length - 1].endsWith(";")) { namesplit[namesplit.length - 1] = namesplit[namesplit.length - 1].replace(';', 'S'); } return new Element(namesplit[namesplit.length - 1]); } public static String getCurrentTime(){ Calendar cal = Calendar.getInstance(); java.util.Date date = cal.getTime(); SimpleDateFormat sdFormat = new SimpleDateFormat("HHmmssSSS"); String myTime = sdFormat.format(date); return myTime; } public static String getCurrentDate(){ Calendar cal = Calendar.getInstance(); java.util.Date date = cal.getTime(); SimpleDateFormat sdFormat = new SimpleDateFormat("yyyyMMdd"); String myTime = sdFormat.format(date); return myTime; } public static String getCurrentDateMiles(){ Calendar cal = Calendar.getInstance(); java.util.Date date = cal.getTime(); SimpleDateFormat sdFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); String myTime = sdFormat.format(date); return myTime; } /** * @Title getStrFromDoc * @Description 从document生成xml * @param document * @return * @throws IOException * @Return String * @Throws * @user Administrator * @Date 2016年1月20日 */ public static String getStrFromDoc(Document document) throws IOException{ Format format = Format.getPrettyFormat(); format.setEncoding("GB2312"); XMLOutputter xmlout = new XMLOutputter(format); ByteArrayOutputStream bo = new ByteArrayOutputStream(); xmlout.output(document,bo); String xmlStr = bo.toString(); return xmlStr; } }
后续有用到的基础类,再在新的文章中介绍。