Как правильно передать картинку из хранилища значений с сервера на клиент для вывода оповещения

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В разработке на платформе 1С часто возникает ситуация, когда необходимо отобразить пользователю картинку, хранящуюся в базе данных (в реквизите типа ХранилищеЗначения). Сложность заключается в том, что прямое обращение к базе данных возможно только на сервере, а методы взаимодействия с пользователем, такие как ПоказатьОповещениеПользователя, доступны исключительно на клиенте. В данной статье мы подробно разберем, как преодолеть этот контекстный барьер и передать данные эффективно.

Постановка задачи и анализ контекстов

Представим ситуацию: у нас есть справочник, где в одном из реквизитов хранится логотип или иконка в формате ХранилищеЗначения. Нам нужно реализовать механизм, который извлекает эту картинку и показывает её в системном оповещении (всплывающем окне в нижнем углу экрана). Разберем по шагам, почему нельзя просто вернуть «содержимое» хранилища и какие инструменты платформы нам помогут.

Для начала проанализируем типы данных. Объект ХранилищеЗначения не существует на клиенте. Однако объект типа Картинка является сериализуемым. Это означает, что платформа может автоматически преобразовать его в поток данных при передаче с сервера на клиент. Тем не менее, для работы в веб-клиенте или при передаче больших изображений более предпочтительным является использование временного хранилища.

Способ 1. Использование временного хранилища (рекомендуемый)

Этот метод считается наиболее профессиональным и стабильным. Вместо того чтобы передавать «тяжелый» объект картинки целиком, мы помещаем его в специальную область памяти сервера и передаем на клиент лишь короткую строковую ссылку (адрес).

Рассмотрим алгоритм реализации. На сервере мы создаем функцию, которая извлекает данные и помещает их в хранилище:


&НаСервере
Функция ПолучитьАдресКартинкиИзХранилища(СсылкаНаОбъект)
    
    // Получаем объект из базы данных
    ОбъектСКартинкой = СсылкаНаОбъект.ПолучитьОбъект();
    
    // Извлекаем данные из ХранилищаЗначения
    ДанныеКартинки = ОбъектСКартинкой.РеквизитХранилище.Получить();
    
    // Проверяем, что в хранилище действительно картинка или двоичные данные
    Если ТипЗнч(ДанныеКартинки) <> Тип("Картинка") Тогда
        КартинкаОбъект = Новый Картинка(ДанныеКартинки);
    Иначе
        КартинкаОбъект = ДанныеКартинки;
    КонецЕсли;
    
    // Помещаем во временное хранилище. 
    // Вторым параметром рекомендуется передавать УникальныйИдентификатор формы, 
    // чтобы данные жили до закрытия этой формы.
    АдресВХ = ПоместитьВоВременноеХранилище(КартинкаОбъект, ЭтаФорма.УникальныйИдентификатор);
    
    Возврат АдресВХ;

КонецФункции

Теперь на стороне клиента мы можем легко вызвать эту функцию и использовать полученный адрес для вывода оповещения:


&НаКлиенте
Процедура ПоказатьСообщениеПользователю()
    
    // Вызываем серверную функцию для получения ссылки
    АдресКартинки = ПолучитьАдресКартинкиИзХранилища(ВыбСсылка);
    
    // Используем адрес в стандартной процедуре оповещения
    ПоказатьОповещениеПользователя(
        "Новое сообщение", 
        "Событие успешно обработано", 
        "Текст пояснения", 
        АдресКартинки
    );
    
КонецПроцедуры

Способ 2. Прямая передача объекта Картинка

Как было замечено в обсуждении, объект Картинка сериализуется. Это означает, что его можно вернуть напрямую из серверной функции. Этот способ проще в кодировании, но может создавать нагрузку на сеть, если картинок много или они имеют большой размер.

Проанализируем пример кода для этого случая:


&НаСервереБезКонтекста
Функция ПолучитьОбъектКартинка(СсылкаНаЗапись)
    
    Хранилище = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаЗапись, "ДанныеФайла");
    Возврат Хранилище.Получить(); // Возвращаем объект типа Картинка напрямую
    
КонецФункции

&НаКлиенте
Процедура ВыполнитьОповещение()
    
    НужнаяКартинка = ПолучитьОбъектКартинка(Элементы.Список.ТекущаяСтрока);
    
    // Платформа корректно примет объект типа Картинка в качестве параметра
    ПоказатьОповещениеПользователя("Внимание!", , "Данные загружены", НужнаяКартинка);
    
КонецПроцедуры

Особенности работы с регламентными заданиями

Разберем важный нюанс, упомянутый в теме: автор хотел использовать регламентное задание для показа оповещений. Выясним причину, по которой это нельзя сделать напрямую. Регламентное задание выполняется в фоновом сеансе на сервере. У этого сеанса нет пользовательского интерфейса («морды»), поэтому вызвать ПоказатьОповещениеПользователя внутри кода регламентного задания невозможно — система выдаст ошибку.

Для решения этой задачи мы рекомендуем использовать следующую схему:

  1. Регламентное задание на сервере обрабатывает данные и делает отметку в специальном регистре сведений (например, «ОчередьОповещений»), записывая туда ссылку на картинку и текст.
  2. Клиентское приложение с помощью метода ПодключитьОбработчикОжидания периодически (например, раз в минуту) опрашивает этот регистр.
  3. Если найдены новые записи, клиент вызывает серверную функцию, получает картинку (через АдресВременногоХранилища) и вызывает ПоказатьОповещениеПользователя.

Рекомендации по оптимизации

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

Таким образом, мы выяснили, что наиболее гибким и масштабируемым решением является использование временного хранилища. Это позволяет минимизировать объем передаваемых данных между сервером и клиентом и обеспечивает совместимость со всеми типами клиентских приложений 1С.

← На главную