вторник, 11 декабря 2012 г.

Клиент JAVA для web service ЦБ РФ

Чтобы получить курс валют за любое число, можно сделать клиент веб сервиса. Но есть некоторые нюансы при использовании стандартных компонент Java. Сам сервис располагается по адресу http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx. Здесь представлен один из способов получить данные.

Создаем стандартный проект в eclipse  идем в консоли в корень проекта и выполняем команду.

wsimport -d bin -s src http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL
Нам показывается несколько ошибок.

C:\eclipse-juno-64\workspace\clientCB>wsimport -d bin -s src http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL parsing WSDL... [WARNING] src-resolve.4.2: Error resolving component 's:schema'. It was detected  that 's:schema' is in namespace 'http://www.w3.org/2001/XMLSchema', but components from this namespace are not referenceable from schema document 'http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL#types?schema1'. If this is he incorrect namespace, perhaps the prefix of 's:schema' needs to be changed. If this is the correct namespace, then an appropriate 'import' tag should be added to 'http ://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL#types?schema1'.   line 83 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL#types?schema1 [ERROR] undefined element declaration 's:schema'  line 83 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 105 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 127 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 170 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 213 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 272 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 347 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 390 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 412 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 455 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 498 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 541 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 584 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 627 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 670 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 734 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 777 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 820 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 901 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 946 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 1007 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL [ERROR] undefined element declaration 's:schema'   line 1028 of http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL 
Они вызваны тем, что ребята из microsoft не соблюли стандарт и добавили свои модификации в структуру WSDL (кто бы сомневался :) ). Между тем, указаны и номера строк, где встречены ошибки. Скачайте в корень проекта файл WSDL и откройте его текстовым редактором. Найдите и удалите все строки вида

<s:element ref="s:schema" />
номера строк вам подсказаны в выводе ошибок. А теперь выполним ту же команду, но в качестве параметра укажем наш файл.

wsimport -d bin -s src DailyInfo.asmx.xml
Теперь нам вывелось в консоли сообщение об успешной генерации исходников и компилированного кода.
Для дальнейшей работы нам понадобиться подключить два jar файла к проекту: serializer.jar и xercesImpl.jar
Найти их можно по адресу http://xerces.apache.org в разделе Build Tools Distributions в архиве Xerces2 Java 2.11.0 - zip

Делаем два класса: один для разбора ответа GetCursOnDateResultParser, второй для запуска теста Main. Листинг привожу далее

Класс Main:

package com.anteastra;   import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.XMLGregorianCalendar; import com.anteastra.GetCursOnDateResultParser; import com.anteastra.GetCursOnDateResultParser.Valute; import ru.cbr.web.*; import ru.cbr.web.EnumValutesResponse.EnumValutesResult; import ru.cbr.web.GetCursOnDateResponse.GetCursOnDateResult; import ru.cbr.web.GetCursOnDateXMLResponse.GetCursOnDateXMLResult;   public class Main {   public static void main(String[] args) { DailyInfo service = new DailyInfo(); DailyInfoSoap port = service.getDailyInfoSoap();   XMLGregorianCalendar onDate = null; try { onDate = GetCursOnDateResultParser.getXMLGregorianCalendarNow(); } catch (DatatypeConfigurationException e) { e.printStackTrace(); }   EnumValutesResult en = port.enumValutes(false); GetCursOnDateResult curs = port.getCursOnDate(onDate);   onDate =port.getLatestDateTime(); GetCursOnDateXMLResult result = port.getCursOnDateXML(onDate); Valute list = null;   try{ list = GetCursOnDateResultParser.getValuteByValuteCh("USD", result); } catch (Exception e){   } System.out.println(list.curs);   try{ list = GetCursOnDateResultParser.getValuteByValuteCode("840", result); } catch (Exception e){   } System.out.println(list.curs); }   }
Класс GetCursOnDateResultParser:

package com.anteastra;   import java.math.BigDecimal; import java.util.GregorianCalendar; import java.util.List;   import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar;   import org.apache.xerces.dom.ElementNSImpl; import org.apache.xerces.dom.TextImpl; import org.w3c.dom.Node; import org.w3c.dom.NodeList;   import ru.cbr.web.GetCursOnDateXMLResponse.GetCursOnDateXMLResult;   public class GetCursOnDateResultParser {   public static class Valute{ public String name; public String chCode; public int code; public BigDecimal nom; public BigDecimal curs;   public Valute(){   }   public Valute(String vname, String vchcode, int vcode, BigDecimal vnom, BigDecimal vcurs){ this.name = vname; this.chCode = vchcode; this.code = vcode; this.nom = vnom; this.curs = vcurs; } }   public static Valute getValuteByValuteCh(String valuteCh, GetCursOnDateXMLResult result) throws Exception{   Valute answer = new Valute();   List<Object> list = result.getContent(); ElementNSImpl e = (ElementNSImpl) list.get(0); NodeList chCodeList = e.getElementsByTagName("VchCode"); int length = chCodeList.getLength();   boolean isFound = false; for (int i = 0; i< length; i++){ if (isFound) break;   Node valuteChNode = chCodeList.item(i); TextImpl textimpl = (TextImpl)valuteChNode.getFirstChild(); String chVal = textimpl.getData();   if (chVal.equalsIgnoreCase(valuteCh)){ isFound = true; Node parent = valuteChNode.getParentNode(); NodeList nodeList = parent.getChildNodes(); int paramLength = nodeList.getLength();   for (int j=0; j<paramLength; j++){ Node currentNode = nodeList.item(j);   String name = currentNode.getNodeName(); Node currentValue = currentNode.getFirstChild(); String value = currentValue.getNodeValue(); if (name.equalsIgnoreCase("Vname")){ answer.name = value; } if (name.equalsIgnoreCase("Vnom")){ answer.nom = new BigDecimal(value); } if (name.equalsIgnoreCase("Vcurs")){ answer.curs = new BigDecimal(value); } if (name.equalsIgnoreCase("Vcode")){ answer.code = Integer.parseInt(value); } if (name.equalsIgnoreCase("VchCode")){ answer.chCode = value; } } } }   return answer;   }   public static Valute getValuteByValuteCode(String valuteCode, GetCursOnDateXMLResult result) throws Exception{   Valute answer = new Valute();   List<Object> list = result.getContent(); ElementNSImpl e = (ElementNSImpl) list.get(0); NodeList chCodeList = e.getElementsByTagName("Vcode"); int length = chCodeList.getLength();   boolean isFound = false; for (int i = 0; i< length; i++){ if (isFound) break;   Node valuteChNode = chCodeList.item(i); TextImpl textimpl = (TextImpl)valuteChNode.getFirstChild(); String chVal = textimpl.getData();   if (chVal.equalsIgnoreCase(valuteCode)){ isFound = true; Node parent = valuteChNode.getParentNode(); NodeList nodeList = parent.getChildNodes(); int paramLength = nodeList.getLength();   for (int j=0; j<paramLength; j++){ Node currentNode = nodeList.item(j);   String name = currentNode.getNodeName(); Node currentValue = currentNode.getFirstChild(); String value = currentValue.getNodeValue(); if (name.equalsIgnoreCase("Vname")){ answer.name = value; } if (name.equalsIgnoreCase("Vnom")){ answer.nom = new BigDecimal(value); } if (name.equalsIgnoreCase("Vcurs")){ answer.curs = new BigDecimal(value); } if (name.equalsIgnoreCase("Vcode")){ answer.code = Integer.parseInt(value); } if (name.equalsIgnoreCase("VchCode")){ answer.chCode = value; } } } }   return answer;   }     public static XMLGregorianCalendar getXMLGregorianCalendarNow() throws DatatypeConfigurationException { GregorianCalendar gregorianCalendar = new GregorianCalendar(); DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); XMLGregorianCalendar now = datatypeFactory.newXMLGregorianCalendar(gregorianCalendar); return now; }   }  

6 комментариев:

  1. Спасибо! Оказалось очень полезно.

    ОтветитьУдалить
  2. Когда запускаю комманду из корня проекта выводит ошибку wsimport is nor recognized an an internal or external command.
    Почему так? Как исправить?

    ОтветитьУдалить
    Ответы
    1. потому что путь к jdk/bin не указан в переменной PATH. Указывайте абсолютный путь к wsimport, либо добавьте в переменную PATH путь к wsimport

      Удалить
  3. wsimport -d bin -s src DailyInfo.asmx.xml
    не работает. выдает что не правильная команда

    ОтветитьУдалить