В первой части мы разобрались, почему сервер 1С «слеп» к файлам на вашем диске C: , и подготовили поле ввода для пути к файлу. Пользователь нажал на заветные три точки … и выбрал документ. Путь к файлу мы научились делать за 3 шага. Что дальше? Теперь нам нужна большая, красивая кнопка, которая заставит этот файл оторваться от вашего компьютера, улететь на сервер, превратиться там в данные базы и вернуть нам красивое окошко с сообщением. Давайте по шагам разберем, как спроектировать это и запустить клиент-серверный мост.
Шаг 4. Создаем кнопку действия «Выполнить загрузку». Просто нарисовать кнопку на экране мало — нужно объяснить платформе, что должно произойти при клике.
В редакторе формы нашей внешней обработки переходим на вкладку Команды (она находится в правом верхнем окне, прямо рядом с «Реквизитами»). Нажимаем зелёный плюс «Добавить» и называем нашу команду просто и понятно: Загрузить. Берем эту команду мышкой и перетаскиваем в левое верхнее окно Элементы, прямо под наше поле с путем к файлу.
На форме появится кнопка. Выделите её, откройте свойства (Alt + Enter) и в поле Заголовок укажите текст, который увидит пользователь: Загрузить.
Шаг 5. Выбор типа обработчика события. Теперь необходимо связать созданную команду с программным кодом. В свойствах команды найдите строку Действие и нажмите на пиктограмму с лупой. Платформа откроет диалоговое окно выбора. Из предложенного списка необходимо выбрать пункт: «Создать на клиенте и процедуру на сервере без контекста».
Давайте разберем, почему платформа предлагает разделение и почему выбор директивы «без контекста» (&НаСервереБезКонтекста) является наиболее правильным.
Почему процедура создается и на клиенте, и на сервере?
Нажатие кнопки пользователем — это действие, которое физически происходит в интерфейсе программы, то есть на Клиенте. Однако клиентская процедура не имеет прямого доступа к серверным вычислениям и механизмам базы данных. Для этого управление необходимо передать на Сервер. Данный тип обработчика автоматически создает пару связанных процедур, обеспечивая правильную передачу данных между уровнями архитектуры.
В чем разница между «на сервере» и «на сервере без контекста»?
Когда вызывается обычная процедура &НаСервере, платформа 1С берет со стороны клиента абсолютно все данные формы (все реквизиты, таблицы, элементы интерфейса), упаковывает их и пересылает на сервер. Сервер тратит время и память на обработку этого объема информации, а затем отправляет всё обратно на клиент. Это называется «передачей контекста формы».
Если выбрать &НаСервереБезКонтекста:Платформа выполняет «легкий» вызов. Сервер получает только те переменные, которые мы сами явно передадим ему в параметрах. Контекст формы (интерфейс, лишние реквизиты) остается нетронутым на клиенте. Скорость выполнения операции возрастает в разы, так как программе не приходится гонять лишние мегабайты данных по сети между клиентом и сервером. Сервер получит только те переменные, которые передадим ему в параметрах (в нашем случае — файл). Сама форма и её элементы останутся на клиенте, не нагружая сеть и память сервера лишней работой. Поэтому использование директивы БезКонтекста — это стандарт качественной и производительной разработки в 1С. Нажимаем«ОК» платформа сгенерирует в модуле формы шаблоны двух процедур, готовых к написанию алгоритма.
После того как платформа создала пару процедур (клиентскую и бесконтекстную серверную), у начинающих разработчиков часто возникает вопрос: «Мы же создали серверную процедуру, почему мы не можем сразу передать туда строку с путем к файлу и начать его читать?»
Нет, сразу написать туда весь код чтения файла нельзя. И в этом кроется главная архитектурная ловушка для новичков. Когда платформа генерирует пустой шаблон процедуры &НаСервереБезКонтекста, может возникнуть соблазн сразу прописать туда привычный код (например, ТабДок.Прочитать(ПутьКФайлу)). Но программа мгновенно выдаст ошибку.
Причина кроется в строгих правилах безопасности и изоляции уровней архитектуры 1С.
Сервер не имеет доступа к вашему диску: Ваша серверная процедура выполняется в сеансе операционной системы на сервере приложений 1С. Если передадим на сервер обычную строку C:\Users\Nina\Desktop\Лист Microsoft Excel.xlsx, сервер попытается найти этот файл на своем собственном жестком диске (там, где физически установлена серверная часть 1С), а не на вашем персональном компьютере. Естественно, он выдаст ошибку «Файл не найден». Бесконтекстный вызов изолирован от формы: Поскольку мы выбрали директиву БезКонтекста, серверная процедура не видит саму форму нашей обработки. Она не может напрямую «посмотреть» в реквизит ПутьКФайлу на экране. Она видит только то, что мы передадим ей «в руках» через параметры. Именно поэтому мы не можем сразу приступить к разбору данных на сервере.
Шаг 6. Прежде чем написать код нужно понять еще один нюанс. В современных версиях платформы 1С (начиная с 8.3.15) старая и привычная функция ПоместитьФайлВоВременноеХранилище() признана устаревшей. Браузеры и операционные системы больше не разрешают программам «намертво» замораживать интерфейс пользователя, пока тяжелый файл летит по сети на сервер. Платформа требует, чтобы загрузка происходила в асинхронном режиме. Это значит, что файл отправляется в фоне, а программа ждет специального сигнала о том, что передача завершена.
Именно из-за этого современного правила безопасности наш мост усложняется: к стандартной паре процедур (на клиенте и на сервере без контекста) добавляется третье промежуточное звено — процедура обратного вызова (или завершения).
Теперь мост в клиент-серверной архитектуре и управляемых формах выглядит так:
1. Процедура на клиенте запускает фоновую отправку файла и говорит системе: «Как только файл долетит до сервера, автоматически передай управление процедуре завершения». И сама сразу закрывается.
2. Процедура завершения на клиенте встречает текстовый документ (ссылку) и передает его дальше. Процедура завершения ничего на сервер не записывает. Сам файл в эту строку записывает встроенная функция платформы. Например, в коде этот адрес выглядит как текстовая строка: e1cib/tempstorage/89a557bb-6927-4bda — документ по сети еще раз передавать не нужно, сервер найдет его в памяти именно по этому идентификатору.
Как сервер подхватывает эту строку?
Сама по себе серверная функция не узнает о появлении файла в памяти. Поэтому наша процедура завершения делает ключевой шаг: она вызывает бесконтекстную функцию сервера и передает полученную адресную строку в качестве параметра — ЗагрузитьДанныеНаСервере(РезультатПомещения.Адрес).
3. Функция на сервере без контекста по временному адресу сохраняет файл к себе на сервер с созданным адресом, выполняет ту обработку, которую мы пропишем в коде, и возвращает на клиент ровно то сообщение, которое мы написали.
Шаг 7. Теперь, когда логика клиент-серверного моста понятна, реализуем её в коде . Скопируйте и вставьте этот код:
&НаСервереБезКонтекстаФункция ЗагрузитьДанныеНаСервере(Знач АдресХранилища)// 1. Сервер по полученному трек-номеру (адресной строке) находит файл в памятиДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);// 2. Выполняет ту обработку, которую мы пропишем в коде:// Создаем на диске сервера пустой файл с расширением xlsxИмяВременногоФайлаСервер = ПолучитьИмяВременногоФайла("xlsx");// Записываем бинарное содержимое «письма» в этот файлДвоичныеДанныеФайла.Записать(ИмяВременногоФайлаСервер);// Инициализируем табличный документ 1С для парсинга ячеек ExcelТабличныйДокумент = Новый ТабличныйДокумент;Попытка// Сервер считывает внутреннюю структуру Excel-файлаТабличныйДокумент.Прочитать(ИмяВременногоФайлаСервер, СпособЧтенияЗначенийТабличногоДокумента.Текст);// [Именно здесь, ниже этой строки, пишется цикл перебора строк:// Для НомерСтроки = 1 По ТабличныйДокумент.ВысотаТаблицы Цикл ...]ТекстОтвета = "Файл успешно сохранен на сервере";Исключение// ИСПРАВЛЕНО: Используем стандартный метод платформы ПодробноеПредставлениеОшибкиТекстОтвета = "Ошибка обработки файла: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());КонецПопытки;// Обязательно удаляем за собой временный файл с диска сервера, чтобы не засорять памятьУдалитьФайлы(ИмяВременногоФайлаСервер);// 3. Возвращаем результат обработки на КлиентВозврат ТекстОтвета;КонецФункции
&НаКлиентеПроцедура ВыполнитьЗагрузку(Команда)Если ПустаяСтрока(ПутьКФайлу) ТогдаПоказатьПредупреждение(, "Пожалуйста, выберите файл Excel или MXL для загрузки!");Возврат;КонецЕсли;Сообщить("--- Запуск умного импорта файла ---");// Передаем параметры напрямую в метод, убрав лишнее объявление типаОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьЗагрузкуЗавершение", ЭтотОбъект);НачатьПомещениеФайлаНаСервер(ОписаниеОповещения, , , , ПутьКФайлу, УникальныйИдентификатор);КонецПроцедуры
&НаКлиентеПроцедура ВыполнитьЗагрузкуЗавершение(РезультатПомещения, ДополнительныеПараметры) Экспорт// ИСПРАВЛЕНО: Убрали несуществующее свойство ХранениеВыполненоЕсли РезультатПомещения = Неопределено ТогдаПоказатьПредупреждение(, "Ошибка при передаче файла на сервер или операция отменена!");Возврат;КонецЕсли;// Передаем серверу чистую адресную строкуТекстСообщения = ЗагрузитьДанныеНаСервере(РезультатПомещения.Адрес);// Выводим пользователю ровно то сообщение, которое вернул серверПоказатьПредупреждение(, ТекстСообщения);КонецПроцедуры
Шаг 8. Тестируем готовую форму в режиме «1С:Предприятие»
Внешняя обработка хороша тем, что для её проверки не нужно обновлять или перезапускать конфигурацию базы данных. Вы можете менять код, сохранять файл и сразу смотреть результат.
Сохраните ваш файл (Файл — Сохранить как…) на рабочий стол. Он запишется в формате .epf.
Запустите вашу базу 1С в обычном пользовательском режиме (1С:Предприятие).
Нажмите Главное меню — Файл — Открыть и выберите ваш сохраненный файл с рабочего стола и нажмите на созданную кнопку действия «Выполнить загрузку».
В этой части статьи успешно решили задачу по преодолению архитектурного барьера между клиентом и сервером в управляемом интерфейсе 1С. В следующей, третьей части разберем как создавать, заполнять и проводить документы внутри базы данных 1С.
ссылка на оригинал статьи https://habr.com/ru/articles/1100910/