Главная » Spring » Генерирование вывода, отличного от HTML Spring

0

До сих пор веб-слой приложения производил вывод только в формате HTML. В действительности HTML – наиболее типич- ный способ отображения информации в веб. Но формат HTML не всегда соответствует представляемой информации.

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

Возможно, вам потребуется более точно управлять форматирова- нием документов. Точное форматирование HTML-документов прак- тически невозможно, особенно когда они просматриваются в раз- личных типах браузеров. Однако имеется формат PDF (Portable Document Format – переносимый формат документов), де-факто ставший стандартом для создания документов с точным формати- рованием, который может просматриваться на разных платформах.

Электронные таблицы и документы PDF – это обычные файлы. Но в Spring имеются классы представлений, позволяющие создавать электронные таблицы и документы PDF динамически, опираясь на данные, имеющиеся в приложении.

Давайте исследуем поддержку не-HTML-представлений в Spring, начав с динамического создания электронных таблиц в формате Excel.

Создание  электронных  таблиц  Excel

Занимающиеся разработкой программного обеспечения достаточ- но продолжительное время могли заметить, что электронные табли- цы Microsoft Excel прочно обосновались в бизнесе. Плохо ли, хоро- шо ли, но бизнесмены обожают электронные таблицы. С помощью электронных таблиц они обмениваются информацией, анализируют ее, составляют диаграммы, планируют и принимают решения. Ис- чезни Excel – и работа во многих компаниях застопорится.

Учитывая такую любовь к электронным таблицам на рабочих местах, очень важно иметь возможность генерировать электронные таблицы в приложении. И такая возможность есть: в состав Spring входит AbstractExcelView – представление, подходящее для создания электронных таблиц.

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

Фреймворк Spring поддерживает возможность вывода электрон- ных таблиц Excel посредством AbstractExcelView. Как следует из име- ни, это абстрактный класс, на основе которого нужно создать свой подкласс, где определить все особенности электронной таблицы.

В качестве примера создания подкласса абстрактного класса AbstractExcelView рассмотрим класс RantExcelView (листинг 8.19). Эта реализация представления воспроизводит список сообщений в фор- мате электронной таблицы Excel.

Листинг 8.19. Список сообщений в виде электронной таблицы

package  com.roadrantz.mvc; import   java.util.Collection; import     java.util.Iterator; import java.util.Map;

import      javax.servlet.http.HttpServletRequest;  import     javax.servlet.http.HttpServletResponse; import  org.apache.poi.hssf.usermodel.HSSFCellStyle; import   org.apache.poi.hssf.usermodel.HSSFDataFormat;

import   org.apache.poi.hssf.usermodel.HSSFRow; import     org.apache.poi.hssf.usermodel.HSSFSheet; import  org.apache.poi.hssf.usermodel.HSSFWorkbook;

import     org.springframework.web.servlet.view.document.AbstractExcelView; import   com.roadrantz.domain.Rant;

import   com.roadrantz.domain.Vehicle;

public  class  RantExcelView  extends  AbstractExcelView  { protected  void  buildExcelDocument(

Map  model,  HSSFWorkbook  workbook,

HttpServletRequest  request,  HttpServletResponse  response) throws Exception {

Collection   rants   =   (Collection)   model.get("rants"); Vehicle  vehicle  =  (Vehicle)  model.get("vehicle");

HSSFSheet sheet = createSheet(workbook, vehicle.getPlateNumber());

HSSFCellStyle  cellStyle  =  workbook.createCellStyle(); cellStyle.setDataFormat(                                 // Установка формата даты

HSSFDataFormat.getBuiltinFormat("m/d/yy    h:mm"));

int rowNum = 1;

for (Iterator iter =  rants.iterator(); iter.hasNext();) { // Добавление Rant rant =  (Rant) iter.next();                               // сообщений rowNum = addRantRow(sheet, cellStyle, rowNum, rant);    // в таблицу

}

}

private int addRantRow(HSSFSheet sheet, HSSFCellStyle cellStyle, int rowNum, Rant rant) {

HSSFRow row = sheet.createRow(rowNum++);  row.createCell((short)            0).setCellValue(rant.getPostedDate()); row.createCell((short)            1).setCellValue(rant.getRantText()); row.getCell((short)            1).setCellStyle(cellStyle);

return rowNum;

}

private  HSSFSheet  createSheet(HSSFWorkbook  workbook, String  plateNumber)  {

HSSFSheet sheet = workbook.createSheet( "Rants  for  "  +  plateNumber);

HSSFRow  header  =  sheet.createRow(0);                                   // Добавление  строки

header.createCell((short) 0).setCellValue("Date");  // заголовка header.createCell((short)   1).setCellValue("Text");

return  sheet;

}

}

В классе RantExcelView необходимо определить только один метод класса AbstractExcelView – buildExcelDocument(). Этот метод получает отображение (Map) с данными модели для электронной таблицы. Ему также передаются HttpServletRequest и HttpServletResponse, на тот слу- чай, если потребуется дополнительная информация, отсутствующая в модели. Однако в данном примере используются только данные модели.

Кроме того, метод buildExcelDocument() получает HSSFWorkbook – ком- понент из Jakarta POI, представляющий рабочую книгу (workbook) Excel1. Реализация собственного представления в Spring MVC для вывода файлов Excel – это лишь вопрос использования библиоте- ки POI для отображения модели данных в рабочую книгу. В Rant- ExcelView список сообщений извлекается из модели данных и в цикле, построчно добавляется в электронную таблицу.

Чтобы сделать класс RantExcelView доступным в Spring MVC, его необходимо зарегистрировать с помощью ResourceBundleViewResolver или XmlViewResolver. Мы воспользуемся XmlViewResolver, поэтому сле- дующего объявления в roadrantz-views.xml  будет достаточно:

<bean    id="vehicleRants.xls" class="com.roadrantz.mvc.RantExcelView"  />

Теперь, чтобы продемонстрировать работу RantExcelView, необхо- димо создать контроллер, помещающий список сообщений в модель данных. Так получилось, что имеющийся контроллер RantsForVehicle- Controller уже  делает  все  необходимое.  Единственная  проблема в том, что RantsForVehicleController уже используется для отображе- ния разметки HTML. Нам необходимо немного изменить его, чтобы придать дополнительную гибкость в выборе представления.

1 Префикс «HSSF» в имени HSSFWorkbook и в именах других классов из POI является аббревиатурой от «Horrible SpreadSheet Format» (отвра- тительный формат электронных таблиц). Видимо, у разработчиков POI сформировалось устойчивое мнение о формате файлов Excel.

Первое, что нужно сделать, – добавить URL отображения запро- са на получение книги Excel. Добавьте следующий элемент <prop> в свойство mappings компонента urlMapping:

<prop key="/rantsForVehicle.xls"> rantsForVehicleController

</prop>

Если теперь DispatcherServlet примет запрос для /rantsForVehicle.xls, он передаст его компоненту rantsForVehicleController. Это тот же конт- роллер, что обслуживает запросы для /rantsForVehicle.htm. Но как он определит, какое представление следует использовать, Excel или JSP?

URI запроса содержит подсказку, описывающую тип представле- ния. URI запроса HTML-страницы уже заканчивается расширением htm. Запросы на получение данных в формате Excel будут отличаться по расширению xls в конце URI. Следующий метод getViewName() из- влекает расширение из URI и использует его при конструировании имени представления:

private static final String BASE_VIEW_NAME  =  "vehicleRants"; private String getViewName(HttpServletRequest request) {

String   requestUri   =   request.getRequestURI(); String  extension  =  "."  +

requestUri.substring(requestUri.lastIndexOf(".")); if("htm".equals(extension)) { extension=""; }

return  BASE_VIEW_NAME  +  extension;

}

Если URI оканчивается расширением htm, тогда считается, что получен запрос на получение HTML-страницы и арбитру Internal- ResourceViewResolver будет позволено выбрать представление JSP. В противном случае именем представления будет vehicleRants, за которым следует расширение URI.

Далее необходимо изменить метод handle() контроллера RantsFor- VehicleController и задействовать в нем метод getViewName() при вы- боре представления:

protected  ModelAndView  handle(HttpServletRequest  request, HttpServletResponse response, Object  command, BindException  errors)  throws  Exception  {

return new ModelAndView(getViewName(request), model);

Осталось решить еще одну проблему. Сервлет DispatcherServlet никогда не получит запроса для адреса /rantsForVehicle.xls, потому что он настроен в web.xml для обработки запросов *.htm. Поэтому не- обходимо настроить еще один элемент <servletmapping>, как показано ниже:

<servlet-mapping>

<servlet-name>roadrantz</servlet-name>

<url-pattern>*.xls</url-pattern>

</servlet-mapping>

Теперь DispatcherServlet  будет обрабатывать оба типа запросов,

*.htm  и *.xls, и приложение будет способно генерировать списки сообщений в формате Excel.

Электронная таблица предназначается в первую очередь для тех, кто привык к работе с Excel. Но других они могут отпугивать. Для таких пользователей желательно выводить информацию в более дружественном формате. Чтобы осчастливить их, посмотрим, как с помощью Spring организовать вывод информации в виде доку- ментов PDF.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии