В первой части мы разобрались, почему сервер 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. Теперь, когда логика клиент-серверного моста понятна, реализуем её в коде . (Шаг 5. Выбор типа обработчика события. Теперь необходимо связать созданную команду с программным кодом. В свойствах команды найдите строку Действие и нажмите на пиктограмму с лупой. Платформа откроет диалоговое окно выбора. Из предложенного списка необходимо выбрать пункт: «Создать на клиенте и процедуру на сервере без контекста».) Скопируйте и вставьте этот код:
&НаСервереБезКонтекста
Функция ЗагрузитьДанныеНаСервере(Знач АдресХранилища)
// 1. Сервер по полученному трек-номеру (адресной строке) находит файл в памяти
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
// 2. Выполняет ту обработку, которую мы пропишем в коде:
// Создаем на диске сервера пустой файл с расширением xlsx
ИмяВременногоФайлаСервер = ПолучитьИмяВременногоФайла("xlsx");
// Записываем бинарное содержимое «письма» в этот файл
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайлаСервер);
// Инициализируем табличный документ 1С для парсинга ячеек Excel
ТабличныйДокумент = Новый ТабличныйДокумент;
Попытка
// Сервер считывает внутреннюю структуру Excel-файла
ТабличныйДокумент.Прочитать(ИмяВременногоФайлаСервер, СпособЧтенияЗначенийТабличногоДокумента.Текст);
// [Именно здесь, ниже этой строки, пишется цикл перебора строк:
// Для НомерСтроки = 1 По ТабличныйДокумент.ВысотаТаблицы Цикл ...]
ТекстОтвета = "Файл успешно сохранен на сервере";
Исключение
// ИСПРАВЛЕНО: Используем стандартный метод платформы ПодробноеПредставлениеОшибки
ТекстОтвета = "Ошибка обработки файла: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
// Обязательно удаляем за собой временный файл с диска сервера, чтобы не засорять память
УдалитьФайлы(ИмяВременногоФайлаСервер);
// 3. Возвращаем результат обработки на Клиент
Возврат ТекстОтвета;
КонецФункции
&НаКлиенте
Процедура ВыполнитьЗагрузку(Команда)
Если ПустаяСтрока(ПутьКФайлу) Тогда
ПоказатьПредупреждение(, "Пожалуйста, выберите файл Excel или MXL для загрузки!");
Возврат;
КонецЕсли;
Сообщить("--- Запуск умного импорта файла ---");
// Передаем параметры напрямую в метод, убрав лишнее объявление типа
ОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьЗагрузкуЗавершение", ЭтотОбъект);
НачатьПомещениеФайлаНаСервер(ОписаниеОповещения, , , , ПутьКФайлу, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьЗагрузкуЗавершение(РезультатПомещения, ДополнительныеПараметры) Экспорт
// ИСПРАВЛЕНО: Убрали несуществующее свойство ХранениеВыполнено
Если РезультатПомещения = Неопределено Тогда
ПоказатьПредупреждение(, "Ошибка при передаче файла на сервер или операция отменена!");
Возврат;
КонецЕсли;
// Передаем серверу чистую адресную строку
ТекстСообщения = ЗагрузитьДанныеНаСервере(РезультатПомещения.Адрес);
// Выводим пользователю ровно то сообщение, которое вернул сервер
ПоказатьПредупреждение(, ТекстСообщения);
КонецПроцедуры
Шаг 8. Тестируем готовую форму в режиме «1С:Предприятие»
Внешняя обработка хороша тем, что для её проверки не нужно обновлять или перезапускать конфигурацию базы данных. Вы можете менять код, сохранять файл и сразу смотреть результат.
Сохраните ваш файл (Файл — Сохранить как...) на рабочий стол. Он запишется в формате .epf.
Запустите вашу базу 1С в обычном пользовательском режиме (1С:Предприятие).
Нажмите Главное меню — Файл — Открыть и выберите ваш сохраненный файл с рабочего стола.
Выберите файл и нажмите на созданную кнопку действия «Загрузить».
В этой части статьи успешно решили задачу по преодолению архитектурного барьера между клиентом и сервером в управляемом интерфейсе 1С. В следующей, третьей части нашего практического цикла перейдем к финальному этапу работы с данными и разберем, как запустить цикл перебора строк и колонок полученного табличного документа, извлечь из ячеек чистые значения и на их основе автоматически создавать, заполнять и проводить реальные документы внутри базы данных 1С.
Вступайте в нашу телеграмм-группу Инфостарт