Важным требованием во многих приложениях является отчетность. Это могут быть внутренние отчеты (то же приложение jsp / html) или во внешнем формате, таком как xls, pdf или xml и т. Д. Популярным механизмом отчетов является JasperReports. В последние несколько месяцев я видел общую тему публикаций на форумах Spring сообщества (даже спрашивая меня по электронной почте), касающуюся интеграции между JasperReports с Spring Web MVC и Spring Web Flow (SWF), особенно с Hibernate.
Распространенной архитектурная картина M odel- V iew- C ontroller (MVC). Ситуация будет выглядеть следующим образом:
некоторые пользователи из слоя View (jsp / html) нажимают какую-то кнопку, чтобы запросить нужный отчет (например, pdf, xls); запрос должен обрабатываться на уровне контроллера (класс контроллера для Spring Web MVC или класс действия для SWF), контроллер / действие должен вызывать уровень модели ( Service / BO ) для делегирования своей работы на этом уровне. Service / BO будет вызывать классы DAO , чтобы получить некоторые данные (строки из базы данных для заполнения и создания отчета). После этого Служба / BO должны отправить отчет обратноУровень контроллера, который затем должен отправить отчет на уровень просмотра .
Кроме того, общий подход при работе со Spring — это использование Hibernate. Если вы работаете с Hibernate, мы используем классы POJO для представления наших сущностей или экземпляра Customer, Provider и т . Д. Простым отчетом будет список всех наших Клиентов и, возможно, всех наших Провайдеров , тогда логично будет работать со списком (например, ArrayList) для этих сущностей.
По моему опыту, многие приложения требуют сложных отчетов. Например, может быть, специальный доклад требуется вашим боссом. После некоторого анализа вы можете сделать вывод, что решение будет результатом выполнения запроса в базе данных, работающего с двумя-шестью объектами, связанными (или даже худшими, не связанными !). Здесь Hibernate был бы не очень полезен, поэтому требуется классический синтаксис SQL-запросов ( в данном случае это предложение JOIN ) — здесь вы можете использовать jdbcTemplate вместо Hibernate.
Теперь предположим, что для этих шести таблиц у каждой есть по двадцать полей, и для вашего отчета вам нужно только четыре поля каждой таблицы, тогда у нас есть другая проблема. Вы получаете много полей, которые вам не нужны. Раньше я работал с моими собственными классами переноса, теперь возникает вопрос, как узнать, какие поля или переменные я должен создать для своего класса переноса? , Решением является то, что из вашего yourreport.jrxml откройте его, и вы должны увидеть что-то вроде (о структуре)
<field name="idCustomer" class="java.lang.String"/> <field name="nameCustomer" class="java.lang.String"/> <field name="phoneCustomer" class="java.lang.String"/>
Не забывайте, что вы можете создавать свои собственные отчеты с помощью инструмента IReport . Затем, когда вы пишете свои собственные операторы sql ( конечно, с / внутри IReport ) для тестирования своих отчетов, в то же время неявно и динамически , вы создаете «<поле …» для каждого поля, полученного из запроса. Каждое поле должно быть переменной в вашем классе переноса
Для этого примера и для целей обучения я создам простой класс переноса и избегаю соединения с БД. Прежде чем мы начнем рассматривать эти ситуации:
- Если вы работаете с SWF, последняя страница вашего процесса потока (т. Е. 5/5) должна позволить вам завершить процесс или создать отчет в формате PDF , вы можете выбрать один из них. Если вы выберете отчет, он должен открыть отчет в формате PDF (будет выполнен Adobe Reader), но не располагать последней страницей JSP процесса потока, чтобы позволить вам завершить процесс. Другой случай, когда вы приходите на последнюю страницу JSP и вам еще не нужен отчет, тогда вы только завершаете процесс потока.
- Если в упомянутом выше процессе потока вы не сгенерировали отчет и не завершили процесс, но по прошествии некоторого времени, когда это необходимо, вы должны вызвать какую-либо опцию в веб-меню и запросить нужный отчет (возможно, предоставьте какой-либо параметр запроса ) — для этого достаточно использовать Spring Web MVC. SWF здесь не логичен
Теперь у вас должно быть понятно, что SWF и Spring Web MVC должны вызывать один и тот же сервис / BO и получать нужный отчет.
Прежде чем начать, фреймворки и другие инструменты, используемые (не все действительно необходимо)
- Весна 2.5.0
- Spring Web Flow 1.0.5
- JasperReports 2.0.3
- Затмение 3.4
- Tomcat 5.5.25
- TomcatPlugin 3.2.1
- Spring IDE 2.1.0
Этот учебник предполагает базовый-средний уровень о Spring и его подпроектах.
Шаг 1: Создание структуры папок
Чтобы быстро и легко выполнить этот учебник, создайте проект Tomcat с именем springjasperreports в папке webapps вашей установки Tomcat. Я покажу вам структуру всех папок внутри проекта (будет меняться в зависимости от вашей логики). На первый взгляд это может немного смущать, но позже это будет легче понять.
Шаг 2. Настройка web.xml
<display-name>springjasperreports</display-name>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>springjasperreports.root</param-value>
</context-param>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/springjasperreports-servlet.xml
/WEB-INF/xml/context/applicationContext-swf.xml
/WEB-INF/xml/context/applicationContext-jasperreports.xml
/WEB-INF/xml/context/applicationContext-jasperreportsengine.xml
</param-value>
</context-param>
<servlet>
<servlet-name>springjasperreports</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>detectAllViewResolvers</param-name>
<param-value>false</param-value>
</init-param>
</servlet>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet-mapping>
<servlet-name>springjasperreports</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>/spring</taglib-uri>
<taglib-location>/WEB-INF/spring.tld</taglib-location>
</taglib>
Важной частью будет contextConfigLocation , там вы можете увидеть
- / WEB-INF / springjasperreports-servlet.xml (для преобразователя представления, отображения URL -адресов и некоторых bean-компонентов Web MVC)
- / WEB-INF / xml / context / applicationContext-swf.xml (для настройки потока)
- / WEB-INF / xml / context / applicationContext-jasperreports.xml (для контроллера, обрабатывающего запрос)
- / WEB-INF / xml / context / applicationContext-jasperreportsengine.xml (для нашего механизма отчетов)
Шаг 3: класс Engine and Wrap
Важной частью является класс EngineSomeEntitiesJasperReport , потому что он создает и заполняет объект JRBeanCollectionDataSource данными (здесь я использую Wrap SomeEntities , простое pojo), заполненные явно. Затем этот класс должен вызываться контроллером / действием S-MVC и SWF
public class EngineSomeEntitiesJasperReport {
public JRBeanCollectionDataSource engine(){
WrapSomeEntities wrapSomeEntitiesOne = new WrapSomeEntities();
wrapSomeEntitiesOne.setIdCustomer("MJE-88");
wrapSomeEntitiesOne.setNameCustomer("Manuel Jordan");
wrapSomeEntitiesOne.setPhoneCustomer("222222");
wrapSomeEntitiesOne.setIdProvider("XYZ-123");
wrapSomeEntitiesOne.setNameProvider("Company A");
wrapSomeEntitiesOne.setPhoneProvider("457898");
wrapSomeEntitiesOne.setIsbn("1590599799");
wrapSomeEntitiesOne.setTitleBook("Spring Recipes");
wrapSomeEntitiesOne.setPriceBook(new BigDecimal("49.99"));
WrapSomeEntities wrapSomeEntitiesTwo = new WrapSomeEntities();
wrapSomeEntitiesTwo.setIdCustomer("MJE-88");
wrapSomeEntitiesTwo.setNameCustomer("Manuel Jordan");
wrapSomeEntitiesTwo.setPhoneCustomer("222222");
wrapSomeEntitiesTwo.setIdProvider("XYZ-777");
wrapSomeEntitiesTwo.setNameProvider("Company B");
wrapSomeEntitiesTwo.setPhoneProvider("697451");
wrapSomeEntitiesTwo.setIsbn("020161622X");
wrapSomeEntitiesTwo.setTitleBook("The Pragmatic Programmer");
wrapSomeEntitiesTwo.setPriceBook(new BigDecimal("45.99"));
List<WrapSomeEntities> myList = new ArrayList<WrapSomeEntities>();
myList.add(wrapSomeEntitiesOne);
myList.add(wrapSomeEntitiesTwo);
JRBeanCollectionDataSource jRBeanCollectionDataSource = new JRBeanCollectionDataSource(myList);
return jRBeanCollectionDataSource;
}
}
Не забывайте, что наше pojo Wrap SomeEntities должно содержать все переменные, созданные как <field name = «…….» /> в файле * .jrxml по запросу, выполненному в IReport
Более реалистичный листинг кода:
public class EngineLineasArticulosJasperReport {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
/**
* <p>
* Metodo que me llena y retorna el JRBeanCollectionDataSource
* </p>
*
* @return JRBeanCollectionDataSource
*/
public JRBeanCollectionDataSource engine(){
String query=" SELECT *, a.descripcion as descripcionarticulo " +
" FROM lineacategoria l, articulo a, medida d WHERE " +
" l.idLineaCategoria = a.idLineaCategoria AND a.idMedida=d.idMedida order by l.idLineaCategoria ";
Collection mycollecion = this.jdbcTemplate.query(
query ,
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
WrapLineasArticulos a = new WrapLineasArticulos();
a.setIdLineaCategoria(rs.getString("idLineaCategoria"));
a.setDescripcion(rs.getString("descripcion"));
a.setIdArticulo(rs.getString("idArticulo"));
a.setStockactual(rs.getBigDecimal("stockactual"));
a.setPrecioUnitario(rs.getBigDecimal("precioUnitario"));
a.setPrecioUnitarioVenta(rs.getBigDecimal("precioUnitarioVenta"));
a.setTotalValorizado(rs.getBigDecimal("totalValorizado"));
a.setXtraTextUnoArticulo(rs.getString("xtraTextUnoArticulo"));
a.setXtraNumDosArticulo(rs.getBigDecimal("xtraNumDosArticulo"));
a.setIdMedida(rs.getString("idMedida"));
a.setNombre(rs.getString("nombre"));
a.setDescripcionarticulo(rs.getString("descripcionarticulo"));
return a;
}
});
JRBeanCollectionDataSource jRBeanCollectionDataSource = new JRBeanCollectionDataSource(mycollecion);
return jRBeanCollectionDataSource;
}
}
Если вы внимательно посмотрите оператор SQL, он работает для связанных таблиц (отношение Pk / Fk). Другой случай может быть для несвязанных таблиц (работа с предложением JOIN ). Остальная часть кода очевидна
Ниже декларация нашего Wrap SomeEntities
public class WrapSomeEntities {
private String idCustomer;
private String nameCustomer;
private String phoneCustomer;
private String idProvider;
private String nameProvider;
private String phoneProvider;
private String isbn;
private String titleBook;
private BigDecimal priceBook;
public String getIdCustomer() {
return idCustomer;
}
public void setIdCustomer(String idCustomer) {
this.idCustomer = idCustomer;
}
public String getNameCustomer() {
return nameCustomer;
}
public void setNameCustomer(String nameCustomer) {
this.nameCustomer = nameCustomer;
}
public String getPhoneCustomer() {
return phoneCustomer;
}
public void setPhoneCustomer(String phoneCustomer) {
this.phoneCustomer = phoneCustomer;
}
public String getIdProvider() {
return idProvider;
}
public void setIdProvider(String idProvider) {
this.idProvider = idProvider;
}
public String getNameProvider() {
return nameProvider;
}
public void setNameProvider(String nameProvider) {
this.nameProvider = nameProvider;
}
public String getPhoneProvider() {
return phoneProvider;
}
public void setPhoneProvider(String phoneProvider) {
this.phoneProvider = phoneProvider;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitleBook() {
return titleBook;
}
public void setTitleBook(String titleBook) {
this.titleBook = titleBook;
}
public BigDecimal getPriceBook() {
return priceBook;
}
public void setPriceBook(BigDecimal priceBook) {
this.priceBook = priceBook;
}
}
Наш EngineSomeEntitiesJasperReport должен быть объявлен в контексте Spring. Для этого компонента он объявлен в applicationContext-jasperreportsengine.xml
<beans>
<bean id="idEngineSomeEntitiesJasperReport"
class="com.springjasperreports.model.jasperreport.engine.EngineSomeEntitiesJasperReport" />
</beans>
Объявление бина само по себе понятно.
Шаг 04: Spring Web MVC
Мы сделали уровень модели (для простоты в данном случае класс EngineSomeEntitiesJasperReport ), теперь мы должны обработать контроллеры, поэтому он находится в Spring Web MVC.
Для этого создается ReportSimplePdfJasperReportController , см. Код ниже
public class ReportSimplePdfJasperReportController extends AbstractController {
private EngineSomeEntitiesJasperReport engineSomeEntitiesJasperReport;
public void setEngineSomeEntitiesJasperReport(
EngineSomeEntitiesJasperReport engineSomeEntitiesJasperReport) {
this.engineSomeEntitiesJasperReport = engineSomeEntitiesJasperReport;
}
protected ModelAndView handleRequestInternal(
HttpServletRequest request, HttpServletResponse res)throws Exception{
ModelAndView mav = null;
try{
JRBeanCollectionDataSource jRBeanCollectionDataSource =
this.engineSomeEntitiesJasperReport.engine();
Map<String,Object> parameterMap = new HashMap<String,Object>();
parameterMap.put("datasource", jRBeanCollectionDataSource);
mav = new ModelAndView("reportsimplepdfjasperreport",parameterMap);
}
catch(Exception e){
}
return mav;
}
}
Мы используем метод установки, чтобы внедрить наш класс движка; handleRequestInternal метод вызова метода двигателя и получает JRBeanCollectionDataSource объект. В этом примере параметры не используются (т. Е. Request.getParameter (…)). Важной частью кода является параметрMap.put («источник данных», jRBeanCollectionDataSource);
Наш ReportSimplePdfJasperReportController должен быть объявлен в контексте Spring. Для этого компонента он объявлен в applicationContext-jasperreports.xml.
<beans>
<bean id="idReportSimplePdfJasperReportController"
class="com.springjasperreports.controler.mvc.jasperreports.ReportSimplePdfJasperReportController" >
<property name="engineSomeEntitiesJasperReport" >
<ref bean="idEngineSomeEntitiesJasperReport" />
</property>
</bean>
</beans>
Объявление бина само по себе понятно
Шаг 5: Spring Web Flow
Для обработки действий мы используем Spring Web Flow. Для этого создается ReportSimplePdfJasperReportAction , см. Код ниже
public class ReportSimplePdfJasperReportAction extends AbstractAction{
private EngineSomeEntitiesJasperReport engineSomeEntitiesJasperReport;
public void setEngineSomeEntitiesJasperReport(
EngineSomeEntitiesJasperReport engineSomeEntitiesJasperReport) {
this.engineSomeEntitiesJasperReport = engineSomeEntitiesJasperReport;
}
protected Event doExecute(RequestContext context)throws Exception{
try{
JRBeanCollectionDataSource jRBeanCollectionDataSource =
this.engineSomeEntitiesJasperReport.engine();
context.getRequestScope().put("datasource", jRBeanCollectionDataSource);
}
catch(Exception e){
}
return success();
}
}
Опять же, мы используем метод setter для внедрения нашего класса двигателя; doExecute метод вызывает метод двигателя и получать в JRBeanCollectionDataSource объект. Для этого примера снова никакие параметры не используются (то есть context.getFlowScope (). Get (…)). Важной частью кода является context.getRequestScope (). Put («источник данных», jRBeanCollectionDataSource);
Наш ReportSimplePdfJasperReportAction также должен быть объявлен как бин; но мы работаем с SWF; затем для этого компонента он объявляется в springwebflowjasperreports-beans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="reportSimplePdfJasperReportAction"
class="com.springjasperreports.swf.actions.jasperreports.ReportSimplePdfJasperReportAction" >
<property name="engineSomeEntitiesJasperReport" >
<ref bean="idEngineSomeEntitiesJasperReport" />
</property>
</bean>
</beans>
Теперь мы должны объявить состояния нашего потока . Затем для этого потока мы создадим springwebflowjasperreports-flow.xml и увидим код ниже
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">
<start-state idref="springwebflowjasperreports-one" />
<view-state id="springwebflowjasperreports-one"
view="springwebflowjasperreports-stepone">
<transition on="next" to="springwebflowjasperreports-two" />
</view-state>
<view-state id="springwebflowjasperreports-two"
view="springwebflowjasperreports-steptwo">
<transition on="next" to="springwebflowjasperreports-printpdf" />
<transition on="end" to="springwebflowjasperreports-end" />
</view-state>
<view-state id="springwebflowjasperreports-printpdf"
view="reportsimplepdfjasperreport" >
<render-actions>
<action bean="reportSimplePdfJasperReportAction" />
</render-actions>
<!-- I am still using the last jsp of the flow -->
<transition on="next" to="springwebflowjasperreports-printpdf" />
<transition on="end" to="springwebflowjasperreports-end" />
</view-state>
<end-state id="springwebflowjasperreports-end" view="welcome" >
</end-state>
<import resource="springwebflowjasperreports-beans.xml"/>
</flow>
Декларация штатов понятна сама по себе. Для лучшей идеи, используя Spring IDE, мы можем увидеть поток в графическом виде.
Последняя часть с SWF должна создать конфигурацию. Для этого мы создадим applicationContext-swf.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:flow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-1.0.xsd">
<bean id="idSpringWebFlowJasperReportsFlowController"
class="org.springframework.webflow.executor.mvc.FlowController">
<property name="flowExecutor" ref="flowExecutorSpringWebFlowJasperReports" />
</bean>
<flow:executor id="flowExecutorSpringWebFlowJasperReports"
registry-ref="flowRegistrySpringWebFlowJasperReports"
repository-type="singlekey"/>
<flow:registry id="flowRegistrySpringWebFlowJasperReports">
<flow:location path="/WEB-INF/flows/springwebflowjasperreports-flow.xml" />
</flow:registry>
</beans>
Шаг 6: Настройка других бинов
Для этого примера мы должны сконфигурировать преобразователь представления, отображение URL и некоторые bean-компоненты Web MVC. Для этого мы должны использовать springjasperreports-servlet.xml
<beans>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename" value="views"/>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="cacheSeconds" value="5"/>
<property name="basename" value="/WEB-INF/interproperties/messages"/>
</bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/welcome.htm">idWelcomeController</prop>
<prop key="/prereportsimplejasperreport.htm">idPreReportSimpleJasperReportController</prop>
<prop key="/reportsimplepdfjasperreport.htm">idReportSimplePdfJasperReportController</prop>
<prop key="/springwebflowjasperreports.htm">idSpringWebFlowJasperReportsFlowController</prop>
</props>
</property>
</bean>
<bean id="idWelcomeController"
class="com.springjasperreports.controler.mvc.welcome.WelcomeController" />
<bean id="idPreReportSimpleJasperReportController"
class="com.springjasperreports.controler.mvc.jasperreports.PreReportSimpleJasperReportController" />
</beans>
Декларации бина сами по себе понятны. Вы должны обратить внимание на два последних компонента: idWelcomeController и idPreReportSimpleJasperReportController . Это два простых контроллера, которые расширяют суперкласс AbstractController , оба используются для форвардных целей.
Шаг 7: views.properties
Все наши представления (jsp / pdf) должны быть настроены в views.properties, для этого см. Ниже
welcome.(class) = org.springframework.web.servlet.view.JstlView
welcome.url = /WEB-INF/jsp/inicio.jsp
prereportsimplejasperreport.(class) = org.springframework.web.servlet.view.JstlView
prereportsimplejasperreport.url = /WEB-INF/jsp/mvc/reportSimpleJasperReport.jsp
springwebflowjasperreports-stepone.(class) = org.springframework.web.servlet.view.JstlView
springwebflowjasperreports-stepone.url = /WEB-INF/jsp/flow/swfjr-stepone.jsp
springwebflowjasperreports-steptwo.(class) = org.springframework.web.servlet.view.JstlView
springwebflowjasperreports-steptwo.url = /WEB-INF/jsp/flow/swfjr-steptwo.jsp
reportsimplepdfjasperreport.(class) = org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
reportsimplepdfjasperreport.reportDataKey = datasource
reportsimplepdfjasperreport.url = /WEB-INF/reports/SpringJasperReportsspring.jasper
Самая важная часть для просмотра PDF используется:
- ReportSimplePdfJasperReportController class
- springwebflowjasperreports-printpdf Просмотр состояния
Они состоят из трех частей:
- Первый наш весенний пакет для генерации просмотра PDF
- Вторая и в некотором роде хитрость связана с jRBeanCollectionDataSource, содержанием нашего отчета. Если вы видите ваши классы Controller / Action, ключевое слово datasource используется в обоих для назначения отчета:
- parameterMap.put ( «источник данных» , jRBeanCollectionDataSource); в классе контроллера ReportSimplePdfJasperReport
- context.getRequestScope (). put ( «источник данных» , jRBeanCollectionDataSource); в ReportSimplePdfJasperReport действий класса
Однако источник данных отправляется в файл SpringJasperReportsspring.jasper .
- Третья часть — это расположение нашего SpringJasperReportsspring.jasper.
Шаг 8: просмотр файлов
Мы увидим каждый файл ресурсов, используемый views.properties.
Первый код inicio.jsp.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<center>
<p>
This Simple tutorial show you how use <i>Spring Web MVC</i> and <i>Spring Web Flow</i>
working together with <i>JasperReports</i>.
</p>
<ul>
<li>Spring Web MVC - JasperReports
<a href="/springjasperreports/prereportsimplejasperreport.htm">start</a></li>
<li>Spring Web Flow - JasperReports
<a href="/springjasperreports/springwebflowjasperreports.htm?_flowId=springwebflowjasperreports-flow">
start</a>
</li>
</ul>
</center>
</body>
</html>
Он предлагает только две ссылки для запуска каждого типа примерного процесса, как показано здесь:
Если мы нажмем первую ссылку, она должна показать reportSimpleJasperReport.jsp . Ниже приведен код
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
<html>
<head>
<title>Spring Web MVC - JasperReports</title>
</head>
<body>
<center>
<br><br>
<p>
Click in <i>Generate Pdf</i> button to open a Pdf Report
</p>
<form action="/springjasperreports/reportsimplepdfjasperreport.htm" method="post" >
<input type="submit" class="button" name="next" value="Generate Pdf"/>
</form>
<p>
Click in <i>Go To Welcome Page</i> button if you want to start again
</p>
<form action="/springjasperreports/welcome.htm" method="post" >
<input type="submit" class="button" name="next" value="Go To Welcome Page"/>
</form>
</center>
</body>
</html>
Он состоит только из двух форм, с URL-действием для каждой, цели очевидны. Ниже страницы исполнения
Примечание. Я настроил свой веб-браузер (Firefox / Opera) для открытия Adobe Reader и просмотра отчета в формате PDF.
Теперь, если мы нажмем на вторую ссылку в inicio.jsp , она должна запустить процесс потока, тогда первое состояние состояния просмотра использует swfjr-stepone.jsp , ниже кода
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
<html>
<head>
<title>Spring Web Flow - JasperReports - Page One</title>
</head>
<body>
<center>
<p>
It is the first page of N pages of a flow process, it would be a simple form.
For simplicity it flow consist only in two pages.
</p>
<form action="" method="post" >
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionkey}"/>
<input type="submit" class="button" name="_eventId_next" value="Go To Page Two"/>
</form>
</center>
</body>
</html>
Он состоит из одной кнопки отправки, ниже выполнения JSP
Если мы нажмем кнопку « Перейти ко второй странице», мы перейдем к следующему состоянию просмотра и используем файл swfjr-steptwo.jsp , расположенный под кодом.
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
<html>
<head>
<title>Spring Web Flow - JasperReports - Page Two</title>
</head>
<body>
<p align="justify">
It is the last page of N pages of a flow process.
For simplicity according to the explanation it gives the options to
<ul>
<li>Generate a pdf</li>
<li>Finish the flow process</li>
</ul>
In the case that you decide to finish the process without generate the pdf
and then after some time you want to see the report
(obvious that the flow process is already terminated),
then you should use Spring Web MVC for get the report like a simple search
</p>
<center>
<form action="" method="post" >
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionkey}"/>
<input type="submit" class="button" name="_eventId_next" value="Generate Pdf"/>
<br><br>
<input type="submit" class="button" name="_eventId_end" value="End Process"/>
</form>
</center>
</body>
</html>
Код понятен сам по себе, ниже — выполнение jsp
Тогда желаемый результат — файл PDF, ниже сгенерированного файла PDF
Здесь часть SpringJasperReportsspring.jrxml , в «<поля …» декларации
<property name="ireport.scriptlethandling" value="0" />
<property name="ireport.encoding" value="UTF-8" />
<import value="java.util.*" />
<import value="net.sf.jasperreports.engine.*" />
<import value="net.sf.jasperreports.engine.data.*" />
<field name="idCustomer" class="java.lang.String"/>
<field name="nameCustomer" class="java.lang.String"/>
<field name="phoneCustomer" class="java.lang.String"/>
<field name="idProvider" class="java.lang.String"/>
<field name="phoneProvider" class="java.lang.String"/>
<field name="isbn" class="java.lang.String"/>
<field name="titleBook" class="java.lang.String"/>
<field name="priceBook" class="java.math.BigDecimal"/>
Вы должны создать свой собственный файл войны и скомпилировать свой SpringJasperReportsspring.jrxml с задачами Ant . (Через несколько дней я приложу исходный код, чтобы поделиться)
Я надеюсь, что это руководство поможет вам, если у вас есть какие-либо сомнения или рекомендации, пожалуйста, дайте мне знать и извините за мою грамматику.
В другой статье я поделюсь, пожалуй, самым важным учебником; громоздкий пример интеграции Spring / JasperReports, но связанный с подотчетами .