由于项目需要,需要一个返回结果中包括多个值,比如包括Map,List等。由于客户端使用的类型没有确定,而且是变化的,所以考虑用泛型来实现。
下面的类Pair可以看做包括2种类型数据的容器,而其内部类Three是包括3种数据类型的容器。之所以将Three作为Pair的内部类,是因为Three的方法要用到Pair的内部方法或属性,而这些内部方法和属性对外部是不可见的,而其内部类可以访问。
package cn.ac.registAService.commons.util; /** * @author secret * @version 1.0 * @date 2012-12-3 下午4:07:54 * @fuction Just a container of 2 elements. Good for returning 2 values. */ public class Pair<L,R> { /** * A factory to create a new pair * @param <L> The left component type * @param <R> The right component type * @param left The left component value * @param right The right component value * @return A new Pair object */ public static <L, R> Pair<L, R> of(L left,R right) { return new Pair<L, R>(left, right); } /** * A factory to create a new pair * @param <L> The left component type * @param <R> The right component type * @param p A pair of objects * @return A new Pair object */ public static <L, R> Pair<L, R> of(Pair<? extends L,? extends R> p) { return new Pair<L, R>(p); } private L left; private R right; /** * Constructor to create the Pair object * @param left The left component value * @param right The right component value */ private Pair(L left,R right) { this.left=left; this.right=right; } /** * Constructor to create the Pair object * @param p A pair of objects */ private Pair(Pair<? extends L,? extends R> p) { left=p.getLeft(); right=p.getRight(); } public L getLeft() { return left; } public R getRight() { return right; } //Just a container of 3 elements. Good for returning 3 values. public static class Three<L,R,C> extends Pair<L, R> { //A factory to create a new three public static <L,R,C> Three<L,R,C> of(L left,R right,C c) { return new Three<L,R,C>(left, right, c); } //constructor private Three(L left,R right,C c) { super(left, right); this.c=c; } private C c; public C getC(){ return c; } } @Override public String toString() { return "Pair [left=" + left + ", right=" + right + "]"; } }
对上述类的使用
1 方法getRecordsResponse返回一个包括2个Element(指dom4j中xml节点元素)的数据类型
/** * GetTecords操作,查询符合条件的资源 * @param strQuery 查询条件 * @param maxRecords return Pair.of(, right); * @return Pair<Element, Element> * 第一个Element记录返回结果中节点geonet:Summary 的信息,第二个Element记录返回结果中节点csw:SearchResults信息 * @throws BusinessException */ private Pair<Element, Element> getRecordsResponse(String strQuery,long maxRecords) throws BusinessException { //查询资源模版 Document queryDocument = null; //1获取查询资源模版 logger.info("4.1查询多个资源:获取查询资源模版"); try { queryDocument=XmlReader.getDocument(CswTool.getRecordsFilePath); } catch (DocumentException e) { throw new BusinessException("读取查询多个资源模版出错,文件路径"+CswTool.getRecordsFilePath); } //设置返回结果数目(如果为0,返回全部结果) if(maxRecords>0) { queryDocument.getRootElement().addAttribute("maxRecords", Long.toString(maxRecords)); } //2设置查询条件 logger.info("4.2查询多个资源:设置查询条件"); Element queryElement=(Element)queryDocument.selectSingleNode("/csw:GetRecords/csw:Query/csw:Constraint/ogc:Filter"); if(strQuery!=null && strQuery!="") queryElement.setText(strQuery); //3查询资源 String requestXml = queryDocument.asXML(); logger.info("4.3查询多个资源requestXml:"+"\n"+requestXml); String responseXml = CswTool.loginAndRun(requestXml); logger.info("4.3查询资源responseXml:"+"\n"+responseXml); //4 解析查询结果 Document responseDoc; try { responseDoc = XmlReader.StringToXml(responseXml); Element summaryElement=(Element) responseDoc.selectSingleNode("/csw:GetRecordsResponse/geonet:Summary"); Element searchResultsElement=(Element) responseDoc.selectSingleNode("/csw:GetRecordsResponse/csw:SearchResults"); return Pair.of(summaryElement, searchResultsElement); } catch (DocumentException e) { throw new BusinessException("解析查询结果xml出错:"+e.getMessage()); } }
2 getRecordsAllInfor 方法使用了上述1中的方法,然后返回包括3种类型的数据String,Map,List
/** * 得到GetRecords查询的所有信息,包括summary信息 * @param strQuery 查询条件 * @param maxRecords 最多返回符合查询结果的数目,如果为0,则返回全部查询结果 * @return Three<String, Map<String, String>, List<MetadataIso>> * String 符合查询条件的资源数目 * Map<String, String>存放summary中的信息(目前只存资源组织信息<资源组织名称,资源组织数目>,后期可扩展存储服务等信息) * List<MetadataIso>>存放返回的资源信息 * @throws BusinessException */ public Three<String, Map<String, String>, List<MetadataIso>> getRecordsAllInfor(String strQuery,long maxRecords) throws BusinessException { String matchedRecords=null; //符合查询条件的资源数目 //TODO 存放summary中的信息(目前只存资源组织信息<资源组织名称,资源组织数目>,后期可扩展存储服务等信息) Map<String, String> hashMap=new HashMap<String,String>(); List<MetadataIso> arrayList=new ArrayList<MetadataIso>(); //存放返回的资源信息 Pair<Element, Element> pair=getRecordsResponse(strQuery, maxRecords); Element summaryElement=pair.getLeft(); Element searchResultsElement=pair.getRight(); logger.info("GetRecords的summary节点"+"\n"+summaryElement.asXML()); logger.info("GetRecords的searchResultsElement节点"+"\n"+summaryElement.asXML()); try { if(summaryElement!=null) { List<Element> listOrg=summaryElement.selectNodes("//organizationNames/organizationName"); if(listOrg!=null) { for(Element el:listOrg) { String orgName=el.attributeValue("name"); //资源组织名称 String orgCount=el.attributeValue("count"); //资源组织数目 hashMap.put(orgName, orgCount); } //end for(Element el:listOrg) } //end if(listOrg!=null) } //end if(summaryElement!=null) if(searchResultsElement!=null) { matchedRecords=searchResultsElement.attributeValue("numberOfRecordsMatched"); List<Element> listMetadata=searchResultsElement.selectNodes("//gmd:MD_Metadata"); if(listMetadata!=null) { for(Element el:listMetadata) { arrayList.add(CswTool.getMetadata(el)); } } //end if(listMetadata!=null) } //end if(searchResultsElement!=null) return Pair.Three.of(matchedRecords, hashMap, arrayList); } catch (BusinessException e) { throw new BusinessException("GetRecords处理返回结果出错:"+e.getMessage()); } }
3 getRecords从Three类中得到数据对象MetadataIso的数据
public List<MetadataIso> getRecords(String strQuery, long maxRecords) throws BusinessException { Three<String, Map<String, String>, List<MetadataIso>> threeTuple=getRecordsAllInfor(strQuery, maxRecords); List<MetadataIso> listMetadata=threeTuple.getC(); return listMetadata; }
泛型在为编写通用的,需求变化的类提供了方便。