27 декабря, 2024

REST сервис для 1С 7.7

Обычно все современные приложения, так или иначе, способны общаться с внешним миром, а особо продвинутые могут общаться через веб-технологии. Как оказалось, даже такую, устаревшую по современным меркам платформу, как 1С:Предприятие 7.7 возможно научить работать с полноценными Http запросами. Здесь я приведу пример внедрения максимально простого варианта REST сервиса для того чтобы понять сам принцип его запуска и работы. В целом система состоит из следующих компонент:

  • сервер приложений Apache-Tomcat, он принимает http запрос и запускает сервлет
  • сервлет, написанный на Java, который при получении http запроса запускает 1С через COM-объект, получает выборку данных, форматирует ответ в формате JSON и отправляет назад
  • Java-библиотека для обращения сервлета к 1С — Jawin
  • 1С:Предприятие 7.7, в конфигурацию необходимо внести дополнения — функции, через которые сервлет будет получать данные и выполнять нужные операции

Постараюсь описать по шагам, как заставить всё это работать вместе.

Установка Java Runtime Environment (JRE)

Для работы сервлета и самого сервера приложений понадобится среда Java, установщик можно скачать с сайта Oracle: ссылка. Разрядность Java, как и других программ далее, выбирал 32-битную, т.к. имеем дело с 1С 7.7, которая иначе работать не будет.

Установка Tomcat

С веб-сервером всё просто, я использовал версию 8.5.32.  Для удобства настройки качайте Windows Installer, во время установки будет предложено выбрать порт, имя и пароль пользователя с доступом к публикации приложений. Рекомендую сразу задать логин и надежный пароль, т.к. наша задача предполагает включение доступа к серверу из Интернета. Также можно выбрать каталог установки по-проще, например «C:\tomcat». Установщик попросит указать путь к JRE, если на предыдущем этапе ставили по умолчанию, путь будет примерно таким:

c:\Program Files (x86)\Java\jre1.8.0_181\

После завершения установки начальная страница сервера должна отображаться по адресу http://localhost:8080 или на том порту, который вы назначили сами.

Пишем Java-сервлет в IDEA Community

Для написания кода сервлета я использовал бесплатную среду разработки JetBrains IDEA Community Edition 2018.2.1, скачать можно с официального сайта: ссылка. Хотя в описании версий сказано, что только Ultimate версия поддерживает разработку веб-приложений, можете не переживать, для наших целей подойдет и Community. Установку можно сделать с параметрами по умолчанию, только в конце выбрать опцию «32-bit launcher».

Создаем новый проект Maven — используя архетип org.apache.maven.archetypes:maven-archetype-webapp, название проекта лучше сразу задать в нижнем регистре одним словом — потом это будет именем веб-приложения и соответственно частью url для вызова сервиса

Добавляем зависимости для работы сервлета и работы с JSON в pom.xml

<dependency>
      <groupId>org.glassfish.jersey.containers</groupId>
      <artifactId>jersey-container-servlet</artifactId>
      <version>2.26</version>
    </dependency>
    <dependency>
      <groupId>org.glassfish.jersey.inject</groupId>
      <artifactId>jersey-hk2</artifactId>
      <version>2.26</version>
    </dependency>
    <dependency>
      <groupId>com.googlecode.json-simple</groupId>
      <artifactId>json-simple</artifactId>
      <version>1.1.1</version>
    </dependency>

Пишем конфигурацию сервлета в web.xml, здесь вместо «ua.com.programmer.webapp» должен быть идентификатор вашего приложения, а ключ «url-pattern» задает путь к методам вебсервиса

<servlet>
    <servlet-name>jersey-servlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>jersey.config.server.provider.packages</param-name>
      <param-value>ua.com.programmer.webapp</param-value>
      <load-on-startup>1</load-on-startup>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>jersey-servlet</servlet-name>
    <url-pattern>/hs/*</url-pattern>
  </servlet-mapping>

Добавляем библиотеку Jawin.

В загруженном архиве будет несколько папок, нам нужна jawin.jar, её нужно положить в любое удобное место, например в папку lib внутри проекта и подключить в свойствах проекта:

Потом из архива нужно скопировать jawin.dll в каталог bin JRE, примерно такой: c:\Program Files (x86)\Java\jre1.8.0_181\bin\

Добавляем Java-class обработчик запросов сервера.

package ua.com.programmer.webapp;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

@Path("/dex")
public class DataLoadService {

    @GET
    @Path("/documents/{type}/{period}")
    public Response getDocumentsData(@PathParam("type") String dataType, @PathParam("period") String period){
        Connector connector = new Connector();
        String output = connector.getDocumentsData(dataType);
        return Response.status(200).entity(output).build();
    }

}

В заголовке класса параметр @Path(«/dex») задает путь к методам этого класса, потом у процедуры, аналогичный параметр @Path(«/documents/{type}/{period}») задает путь для конкретного метода и его входные параметры. Учитывая путь который был задан в web.xml, для процедуры getDocumentsData() получим полный путь: /hs/dex/documents/… и тут уже будут параметры.

Теперь можем делать стыковку с 1С, добавляем Java-class для связи с базой данных. Пара фрагментов из модуля класса:

    private final String init = "enterprise /D\"D:\\1S_Base" /N\"Odmin\" /P123";
    private DispatchPtr app;

    private boolean openConnection(){
        try {
            Ole32.CoInitialize();
            app = new DispatchPtr("V77.Application");
            app.invoke("Initialize",app.get("RMTrade"),init,"NO_SPLASH_SHOW");
            return true;
        }catch (Exception ex){
            System.out.println("Connection error: "+ex.toString());
        }
        return false;
    }

String getDocumentsData(String docType){
        String result;
        JSONObject jsonObject = new JSONObject();
        JSONArray resultArray = new JSONArray();
        if (openConnection()){
            try {
                DispatchPtr docItems = (DispatchPtr) app.invoke("ВыборкаДокументов", docType, period);
                while ((Double) docItems.invoke("GetDocument") > 0.0){
                    DispatchPtr item = (DispatchPtr) docItems.invoke("CurrentDocument");
                    readDocumentItemData(item, resultArray);
                }
            }catch (Exception ex) {
                System.out.println("Error: " + ex.toString());
                jsonObject.put("error", ex.toString());
            }finally {
                closeConnection();
            }
        }
        app = null;
        jsonObject.put("result", resultArray);
        result = jsonObject.toString();
        return result;
    }

Функция openConnection запускает подключение к 1С, строка запуска в переменной init, там прописан путь к базе, имя и пароль пользователя. Функция getDocumentsData возвращает выборку документов в виде текста в JSON формате. В ней вызывается функция из глобального модуля 1С: ВыборкаДокументов и потом происходит обычный перебор выборки с записью данных шапки в массив, процедура readDocumentItemData. Принцип простой, если нам нужно вызвать метод, используем invoke(«ИмяМетода», Параметр1, Параметр2….), когда нужен атрибут, используем get(«ИмяАтрибута»).

Код класса полностью:

Выглядит громоздко, просто тут уже добавлена ещё и выборка справочников.

Публикация на веб-сервер

Для запуска веб-сервиса нужно опубликовать его на сервере, для Tomcat понадобится war-файл, это делается с помощью мавен-плагина. Перед генерацией не забываем сделать билд проекта.

Готовый файл будет лежать в директории target в каталоге проекта. 

Теперь открываем Tomcat — Manager App, логин и пароль для перехода на эту страницу — это те, которые были заданы при установке. Загружаем файл на сервер, если всё сделано как надо, приложение появится в списке и будет уже запущено.

Изменения в конфигурации 1С

Остается добавить в конфигурацию функции, которые будет вызывать сервис, в этом примере их легко заметить в коде по кириллическим названиям. Функции должны располагаться в Глобальном модуле и обозначены как экспортируемые. 

Функция выборки данных должна вернуть указатель выборки, вот пример получения данных по документам за последние пол года :

Также, в коде класса можно заметить несколько служебных функций: ИдентификаторЭлемента, ДатаДокумента, СуммаДокумента, с ними логика простая — всё что может понадобиться в модуле сервиса и что хоть как-то зависит от конфигурации, пишем и вычисляем на стороне 1С.

Проверка работы сервиса

Для того чтобы убедиться в работоспособности сервиса достаточно открыть браузер и ввести нужный адрес. Путь составляем так: 

адрес_сервера:порт/имя_приложения/корневой_путь_приложения/путь_класса/путь_процедуры/параметры...

Если сервис работает верно, увидим ответ в виде текста в JSONформате. Можно не пугаться нечитаемой кириллицы, если цель сервиса не отображение данных в браузере — при передаче такого текста например в Андроид-приложение, все данные в порядке.

Ну, вот и всё.

Рабочий проект с примером кода для 1С доступен на GitHub: ссылка.