Автор статьи: Asmody
исходник: http://kb.mista.ru/article.php?id=473

Использование внешних web-сервисов в 1С:Предприятие 8

В статье дается пример использования внешних web-сервисов в 1С:Предприятие 8.1. В качестве примера показано, как с помощью web-сервиса компании «Аэрофлот» можно получить расписание рейсов самолетов в режиме реального времени.

Платформа «1С:Предприятие 8» постоянно развивается. В связи с чем, код, представленный в этой статье, в последних версиях платформы будет выдавать ошибку. Происходит это, в частности, из-за того, что изменился порядок вызова методов прокси-объекта web-сервиса: например, сложные объекты необходимо явно преобразовывать в ОбъектXDTO соответствующего типа, используя Фабрику соответствующего сервиса. Об этом вы можете почитать на нашем форуме или в книге «Технологии интеграции 1С:Предприятия» http://v8.1c.ru/metod/books/book.jsp?id=288

Вступление

Когда появляется новая версия какого-то программного продукта, то естественно, в первую очередь хочется понять, чего же такого в нем появилось нового. В случае с «1С:Предприятие 8.1» такой новой «фичей» для меня стали web-сервисы. Про web-сервисы написано и сказано много, поскольку существует эта технология по компьютерным меркам достаточно давно. По-этому я повторяться не буду, за справками отправляю всех к Яндексу. Скажу лишь, что с выходом новой редакции платформы «1С:Предприятие 8.1» у 1Сников появилась возможность создавать и использовать технологию web-сервисов, находясь, так сказать, в родной среде. В этой статье я хочу показать, как использовать внешние web-сервисы в своих разработках.

Для тех, кто совсем "не в теме": о web-сервисах "на пальцах"

ОК, специально для ТЕБЯ я чуть-чуть попытаюсь рассказать, что такое web-сервис, и почему именно это показалось мне таким «вкусным» новшеством платформы. Возможно ты знаешь про технологию COM или что-то слышал про OLE? С этой технологией рано или поздно сталкивается любой одинесник (особенно если надо быстро перекинуть какой-нибудь справочник «Сотрудники», а отдел кадров, предвидя необходимость снова вбивать всю 1500 сотрудников, готов повесить тебя на первом встречном подходящем гвозде).

Да, так вот, в основе технологии COM лежит идея о возможности вызова программного кода (и обращения к данным) одного приложения из другого приложения. Причем, возможности делать это не на уровне отдельных процедур и функций, но получая в распоряжение объекты другого приложения. При использовании OLE, мы в своем приложении создаем объект, являющийся «представителем» или, если хотите, «оберткой» некоторого объекта того приложения, с которым мы хотим наладить взаимодействие (т.н. «OLE-объект» или «COM-объект»). Через этот объект-«обертку» нам становятся доступны свойства и методы объекта другого приложения, причем только те из них, которыми разработчик того приложения разрешил нам пользоваться, опубликовав их в описании интерфейса. (Ну вот, не хотел лезть в дебри, но по-другому не получается…)

Теперь представим себе, что то-самое приложение находится на другом компьютере, и даже не в локальной сети (с такими случаями неплохо справляются DCOM, CORBA и прочие заумные аббревиатуры), а где-то далеко-далеко в Интернете. Вот тут-то и выходят на сцену web-сервисы (тоже в комплекте с заумными аббревиатурами: SOAP, WSDL и др.), которые позволяют проделывать аналогичный «фокус» и в этом случае: т.е. получать данные и манипулировать объектами приложения, выполняющегося на компьютере на другом краю Интернета.

Под «внешним» web-сервисом я буду понимать web-сервис, предоставляемый некоторым поставщиком сервиса (т.е. не нашим приложением.) Соответственно, под «внутренним» - web-сервис, который будем предоставлять мы из, или, точнее, на основе нашего приложения. При использовании внешних web-сервисов надо понимать, что хотя объект-«обертка» создается в нашем «локальном» приложении, «исполняющий код» этого объекта находится, может быть, на другой стороне Земного Шара. При этом обмен между нами и ними происходит на вездесущем ныне XML, с его известными «плюсами» (универсальностью и структурированностью) и «минусами» (раздутостью), а в качестве «линии передачи» используется старый добрый http.

Да, и не забудь про интернет-трафик! Причем, в случае с внешними web-сервисами большая часть его придется на входящую составляющую.

Все, остальное есть в Яндексе. Поехали дальше…

Откуда ноги, т.е. крылья растут

Порывшись в том же Яндексе, я нашел замечательный web-сервис от компании «Аэрофлот», который позволяет в режиме реального времени получать информацию о прилете и вылете самолетов, и решил сделать эдакое «Табло аэропорта» в «1С:Предприятие». Сам сервис живет тут Уже не живёт. Видимо, после переделки сайта «Аэрофлота», сервис был убит.

Он сказал: "Поехали!"

Для начала я создал пустую конфигурацию «1С:Предприятия 8.1» (на момент написания статьи в моем распоряжении была версия платформы 8.1.5.123). Затем я добавил в свою конфигурацию новый объект типа WS-ссылка. На предложенный запрос ввести URL импортируемого WSDL, я ввел ссылку на WSDL-файл, которая значится на странице сервиса: http://webservices.aeroflot.ru/flightstatus.wsdl (WSDL-файл является описанием web-сервиса. За подробностями - в Яндекс), и гордо назвал созданный объект «Аэрофлот». Щелкнув два раза на этом объекте, я получил дерево со структурой web-сервиса. Это дерево представляет собой «портрет» web-сервиса, как его видит 1Ска. Самое интересное находится в ветке «Web-сервисы»: это имена и порты web-сервисов (на самом деле WSDL-файл может описывать не один, а несколько web-сервисов, тогда для каждого web-сервиса будет создана своя ветка), и перечислены методы web-сервиса. Это и есть те самые «ниточки», подергав за которые можно приоткрыть себе доступ к тем данным, которые предоставляет web-сервис. В ветке «Модель данных» содержится описание библиотек типов данных, которые используются web-сервисом. Краткую справку об использовании web-сервиса обычно можно получить там же, где и ссылку на WSDL-файл. В случае с «Аэрофлотом», это страничка http://webservices.aeroflot.ru/flightstatus.asmx

"То взлет, то посадка..."

Для работы с web-сервисом я добавил в конфигурацию обработку «ТаблоВылетов», а в ней - одну форму, которую назначил основной. На форму я положил поле выбора «ВыборАэропорта», поле ввода «ДатаРейса», панель «ПанельТабло» с двумя страницами «Прилет» и «Вылет», при этом я снял флаг «Распределять по страницам» в свойствах панели, и табличное поле «ТаблицаТабло». Взаимодействие с web-сервисом происходит по принципу «запрос-ответ», при этом для web-сервиса создается специальный объект-посредник. Поэтому я добавил реквизит формы «СервисАэрофлот» произвольного типа. Если внимательно почитать описание сервиса, то можно увидеть, что web-сервис предоставляет данные о прилетах и вылетах через вызовы методов Arrival и Departure соответственно. При этом оба метода принимают в качестве параметров код аэропорта и нужную дату. Кроме того, web-сервис предоставляет возможность получить список аэропортов, по которым имеются данные в системе. Достаточно очевидным является следующий сценарий взаимодействия с web-сервисом: 1. Получить список аэропортов; 2. Выбрать нужный аэропорт и дату; 3. Получить данные о прилетах или вылетах; Но прежде чем обращаться к web-сервису, необходимо инициализировать объект-посредник (типа WSПрокси), что я и сделал в обработчике открытия формы:

    СервисАэрофлот=WSСсылки.Аэрофлот.СоздатьWSПрокси("http://www.aeroflot.ru/", "FlightStatus", "FlightStatusSoap" );

Первым параметром передается URI пространства имен web-сервиса. Узнать его можно открыв свойства web-сервиса в дереве WS-ссылки. Вторым и третьим параметром параметрами передаются соответственно имя и порт web-сервиса. (не надо путать понятия «имя», «порт», «прокси» и т.п. в применении к web-сервисам с более привычными понятиями протокола TCP/IP. Соответствие между ними если и есть, то скорее смысловое. В общем случае нужно понимать, что, например порт web-сервиса и TCP-порт - это абсолютно разные вещи). Таким образом я проинициализировал объект СервисАэрофлот типа WSПрокси, который по-сути своей является «оберткой» web-сервиса. Через него я смогу обращаться к методам web-сервиса как к «родным» методам платформы. Первым делом я получил список аэропортов и заполнил список поля выбора «ВыборАэропорта»:

    СписокВыбора=ЭлементыФормы.ВыборАэропорта.СписокВыбора;
    СписокВыбора.Очистить();
    СписокАэропортов=СервисАэрофлот.AirportList().ПолучитьСписок("list");
    ВсегоАэропортов=СписокАэропортов.Количество();
    Для ии=0 по ВсегоАэропортов-1 Цикл
        Аэропорт=СписокАэропортов.Получить(ии);
        СписокВыбора.Добавить(Аэропорт.code, ""+Аэропорт.city+" : "+Аэропорт.name);
    КонецЦикла;

Тут нужен небольшой комментарий по конструкции

СписокАэропортов=СервисАэрофлот.AirportList().ПолучитьСписок("list"); 

Дело в том, что значения, возвращаемые методами web-сервисов, представляются в платформе объектами типа ОбъектXDTO. Поскольку тематика технологии XDTO выходит за рамки этой статьи, скажу лишь, что для превращения этого объекта в список (чем он и является), я вызвал его метод ПолучитьСписок(). Остальное в коде достаточно очевидно, включая названия полей структуры Аэропорт, которые я нашел на странице описания web-сервиса. Теперь можно запустить конфигурацию и убедиться, что список поля выбора заполняется названиями аэропортов:

"День отлета, день прилета..."

Теперь у меня практически все готово для того, чтобы заставить мое табло функционировать. Осталось только его «выкрасить и выбросить» :) Чем и займусь:

Процедура ЗаполнитьТабло(Прилет=Истина)
    ТаблицаТабло.Колонки.Очистить();
    ТаблицаТабло.Колонки.Добавить("КодРейса",, "Код рейса");
    ТаблицаТабло.Колонки.Добавить("КодАвиакомпании",, "Авиакомпания");
    ТаблицаТабло.Колонки.Добавить("НомерРейса",, "Номер");
    ТаблицаТабло.Колонки.Добавить("АэропортТранзит",, "Аэропорт-транзит");
    ТаблицаТабло.Колонки.Добавить("Аэропорт",, "Аэропорт "+?(Прилет,"вылета","прилета"));
    ТаблицаТабло.Колонки.Добавить("ВремяРасписание",, "По расписанию");
    ТаблицаТабло.Колонки.Добавить("ВремяПланируемое",, "Планируемое");
    ТаблицаТабло.Колонки.Добавить("ВремяФактическое",, "Фактическое");
    ТаблицаТабло.Колонки.Добавить("ВремяРасчетное",, "Расчетное");
    ТаблицаТабло.Колонки.Добавить("ВремяПосадки",, ?(Прилет,"Посадка","Взлет"));
    ТаблицаТабло.Колонки.Добавить("ОбъедРейс",, "Объед.рейс");
    ТаблицаТабло.Колонки.Добавить("Статус",, "Статус");
    Если Не Прилет Тогда
        ТаблицаТабло.Колонки.Добавить("Регистрация",, "Регистрация");
        ТаблицаТабло.Колонки.Добавить("Посадка",, "Посадка");
    КонецЕсли;
 
    ЭлементыФормы.ТаблицаТабло.СоздатьКолонки();
    ЭлементыФормы.ТаблицаТабло.Колонки.КодРейса.Видимость=Ложь;
    Если Не Прилет Тогда
        ЭлементыФормы.ТаблицаТабло.Колонки.ВремяРасчетное.Видимость=Ложь;
    КонецЕсли;
 
    Если Прилет Тогда
        Данные=СервисАэрофлот.Arrival(ВыборАэропорта, ДатаРейса).ПолучитьСписок("list");
    Иначе
        Данные=СервисАэрофлот.Departure(ВыборАэропорта, ДатаРейса).ПолучитьСписок("list");
    КонецЕсли;
 
    ВсегоЗаписей=Данные.Количество();
    Для ии=0 по ВсегоЗаписей-1 Цикл
        Запись=ДАнные.Получить(ии);
        НоваяСтрока=ТаблицаТабло.Добавить();
        НоваяСтрока.КодАвиакомпании=Запись.company;
        НоваяСтрока.НомерРейса=Запись.flight_no;
        НоваяСтрока.АэропортТранзит=Запись.airport_inter;
        НоваяСтрока.Аэропорт=Запись.airport;
        НоваяСтрока.ВремяРасписание=Запись.sched;
        НоваяСтрока.ВремяПланируемое=Запись.plan;
        НоваяСтрока.ВремяФактическое=Запись.fact;
        НоваяСтрока.ВремяРасчетное=Запись.calc;
        НоваяСтрока.ВремяПосадки=Запись.real;
        НоваяСтрока.ОбъедРейс=Запись.union_flight_no;
        НоваяСтрока.Статус=Запись.status;
        Если Не Прилет Тогда
            НоваяСтрока.Регистрация=Запись.is_check;
            НоваяСтрока.Посадка=Запись.is_board;
        КонецЕсли;
    КонецЦикла;
 
КонецПроцедуры

Для того, чтобы проверить как это все работает, я добавил на командную панель формы кнопку «Обновить» с соответствующей картинкой, а в ее обработчике написал такое:

Процедура КоманднаяПанель1Обновить(Кнопка)
    ЗаполнитьТабло(ЭлементыФормы.ПанельТабло.ТекущаяСтраница=ЭлементыФормы.ПанельТабло.Страницы.Прилет);
КонецПроцедуры

Сохраняю, запускаю, выбираю, нажимаю, получаю

Послесловие

Удивительное дело, но уже после того, как статья была написана и опубликована, выяснилось, что уважаемый ZAV уже опубликовал похожий пример на IT-Land'е: http://itland.ru/biblio/detail.php?ID=1060 Дабы избежать возможных обвинений в плагиате, настоятельно рекомендую ознакомиться и с этой статьей тоже и сравнить подходы авторов.