posts - 310, comments - 6939, trackbacks - 0, articles - 3
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表

          Posted on 2008-01-25 09:32 詩(shī)特林 閱讀(7011) 評(píng)論(10)  編輯  收藏 所屬分類(lèi): BI
          應(yīng)該IT168寫(xiě)的專(zhuān)稿:http://publish.itpub.net/j/2008-01-24/200801241020641.shtml
           

          使用JasperReportiBATIS開(kāi)發(fā)Web報(bào)表

           

          JasperReport是一種采用純Java實(shí)現(xiàn)的快速且非常流行的生成報(bào)表的類(lèi)庫(kù)。而對(duì)于任何的報(bào)表方案,取得數(shù)據(jù)并傳遞給報(bào)表引擎是其中最重要且最值得關(guān)心的方面。但遺憾的是,在這方面JasperReport本身似乎有一定的不足。而如今的很多Java應(yīng)用程序,采用數(shù)據(jù)獲取框架來(lái)進(jìn)行數(shù)據(jù)的匹配與動(dòng)態(tài)生成SQL。例如iBATIS數(shù)據(jù)映射框架。當(dāng)然,如果只是使用JasperReport獲取數(shù)據(jù)及管理數(shù)據(jù)的默認(rèn)機(jī)制的話(huà),不足以與現(xiàn)成的數(shù)據(jù)框架進(jìn)行很好的平衡。但可喜的是,可以通過(guò)使用傳遞給JasperReport一個(gè)數(shù)據(jù)庫(kù)的連接進(jìn)行代替,當(dāng)然這種連接可以通過(guò)使用XML進(jìn)行非常方便的管理與配置。

          源代碼下載:http://cid-7b377ace522ff6c7.skydrive.live.com/self.aspx/iBatisJasper/iBatisJasper.rar

          一、準(zhǔn)備工作

          Hibernate類(lèi)似,iBATIS也是一個(gè)ORM解決方案,不同的是兩者各有側(cè)重。Hibernate提供了Java對(duì)象到數(shù)據(jù)庫(kù)表之間的直接映射,開(kāi)發(fā)者無(wú)需直接涉及數(shù)據(jù)庫(kù)操作的實(shí)現(xiàn)細(xì)節(jié),實(shí)現(xiàn)了一站式的ORM解決方案。而iBATIS則采取了另一種方式,即提供Java對(duì)象到SQL(面向參數(shù)和結(jié)果集)的映射實(shí)現(xiàn),實(shí)際的數(shù)據(jù)庫(kù)操作需要通過(guò)手動(dòng)編寫(xiě)SQL實(shí)現(xiàn)。

          iBATIS是又一個(gè)O/R Mapping解決方案,j2eeO/R方案真是多,和Hibernate相比,iBATIS最大的特點(diǎn)就是小巧,上手很快。如果你不需要太多復(fù)雜的功能,iBATIS是能滿(mǎn)足你的要求又足夠靈活的最簡(jiǎn)單的解決方案。在本文的示例中,采用Spring+JSF+iBATIS的模式進(jìn)行示例的開(kāi)發(fā)。所使用的lib如下圖所示:


          1.所使用的jar

          二、在iReport中可視化定制模板

          定制報(bào)表格式有二種方式,一種就是寫(xiě)jrxml文件,其實(shí)就是xml文件,只不過(guò)是后綴名不一樣罷了。另一種方式更直接,就是生成一個(gè)JasperDesign類(lèi)的實(shí)例,在japsperDesign中自己定義模板。jrxml文件也是通過(guò)一個(gè)JRXmlLoad加載過(guò)來(lái),轉(zhuǎn)成JasperDesign類(lèi)的實(shí)例。也就是說(shuō)寫(xiě)jrxml文件還需要進(jìn)行解析,加載?,F(xiàn)實(shí)中我們使用的報(bào)表一般格式比較固定,因而可以通過(guò)先使用iReport工具生成模板,再加載解析的方式。這種方式簡(jiǎn)單,而且可見(jiàn)性強(qiáng)。

          iReport做為一個(gè)優(yōu)秀的報(bào)表設(shè)計(jì)器,有著功能非常強(qiáng)大的特性。作為開(kāi)源的Java程序,不但有適合于Windows安裝的應(yīng)用程序,同時(shí),還提供完全開(kāi)放的源代碼,可供參考及原理分析。在本文中,主要通過(guò)圖形界面中的模板設(shè)計(jì),以及與數(shù)據(jù)庫(kù)的連接等一系列的操作,來(lái)介紹如何定制一定要求的報(bào)表模板。

          通過(guò)iReport可初見(jiàn)化的圖形界面,可以設(shè)計(jì)出各種各樣的簡(jiǎn)單或復(fù)雜的報(bào)表。通過(guò)iReport的這種可視化界面設(shè)計(jì),可以為JasperReport提供優(yōu)秀的報(bào)表模板,而無(wú)須去理解或是掌握那些復(fù)雜的XML語(yǔ)法。如此則可以Web報(bào)表開(kāi)發(fā)節(jié)省大量的開(kāi)發(fā)時(shí)間。

          在進(jìn)行iReport模板設(shè)計(jì)之前,需要編寫(xiě)JavaBean類(lèi):MonthlySalesBean.java,代碼如下:

          import java.math.BigDecimal;
          import java.util.ArrayList;
          import java.util.List;


          public class MonthlySalesBean {

              
          private int employeeID;;
              
          private String last = null;
              
          private String first = null;
              
          private BigDecimal total = null;
              
          private List sales = null;
              
          private LatestSale latestSale = null;
              
              
          public static List createBeanCollection () {
                  List list 
          = new ArrayList ();
                  
                  MonthlySalesBean msb 
          = new MonthlySalesBean ();
                  msb.setEmployeeID(
          1);
                  msb.setFirst(
          "John");
                  msb.setLast(
          "Doe");
                  msb.setTotal(
          new BigDecimal ("1600.50"));
                  
                  LatestSale ls 
          = new LatestSale ();
                  ls.setAmount(
          new BigDecimal ("32.21"));
                  msb.setLatestSale(ls);
                  
                  list.add(msb);
                  
                  
          return list;
              }

              
          public int getEmployeeID() {
                  
          return employeeID;
              }

              
          public void setEmployeeID(int employeeID) {
                  
          this.employeeID = employeeID;
              }

              
          public String getFirst() {
                  
          return first;
              }

              
          public void setFirst(String first) {
                  
          this.first = first;
              }

              
          public String getLast() {
                  
          return last;
              }

              
          public void setLast(String last) {
                  
          this.last = last;
              }

              
          public BigDecimal getTotal() {
                  
          return total;
              }

              
          public void setTotal(BigDecimal total) {
                  
          this.total = total;
              }

              
          public List getSales() {
                  
          return sales;
              }

              
          public void setSales(List sales) {
                  
          this.sales = sales;
              }

              
          public LatestSale getLatestSale() {
                  
          return latestSale;
              }

              
          public void setLatestSale(LatestSale latestSale) {
                  
          this.latestSale = latestSale;
              }
              
          }


           

          將上面的類(lèi)打成一個(gè)jar包,并置于classpath目錄下,則iReport可以進(jìn)行訪問(wèn)。使用JavaBean做為數(shù)據(jù)源,為了在設(shè)計(jì)報(bào)表時(shí)能夠看到數(shù)據(jù),在程序中要為iReport提供一個(gè)靜態(tài)方法,該方法返回上面定義JavaBean的一個(gè)結(jié)果集,這個(gè)靜態(tài)方法可能在程序運(yùn)行中并不是必須的,但是在iReport中它確實(shí)必須的,換句話(huà)說(shuō),這個(gè)靜態(tài)方法是專(zhuān)門(mén)為iReport量身定做的,為了iReport在設(shè)計(jì)報(bào)表時(shí)能夠調(diào)用這個(gè)靜態(tài)方法返回相應(yīng)的JavaBean結(jié)果集,以便設(shè)計(jì)的報(bào)表放在Java項(xiàng)目中之前就能像使用SQL數(shù)據(jù)庫(kù)數(shù)據(jù)源一樣可以瀏覽。在iReport中先進(jìn)行數(shù)據(jù)源的連接配置,此處采用是JavaBeans set data source連接方式:

          2.iReport進(jìn)行數(shù)據(jù)源的連接

           

          三、處理iBati返回?cái)?shù)據(jù)

           

          如果iBATIS沒(méi)有采用JavaBean作為返回對(duì)象,則可以采用java.util.map作為數(shù)據(jù)的返回對(duì)象。采用java.util.Map對(duì)象,需要額外的一些步驟。下面的代碼則說(shuō)明了iBATISselect語(yǔ)句返回的java.util.Map對(duì)象。Src/ iBATIS.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 1.0//EN"
              "http://iBATIS.apache.org/dtd/sql-map-2.dtd"
          >
          <sqlMap>

              
          <select id="salesByListOfMapsSQL" resultClass="java.util.HashMap">
                  SELECT
                      E.EMPLOYEE_ID "ID",
                      E.FIRST_NAME "FIRST",
                      E.LAST_NAME "LAST",
                      MS.TOTAL_SALES "TOTAL",
                      MS.LATEST_SALE
                  FROM
                      EMPLOYEE E,
                      MONTHLY_SALES MS
                  WHERE
                      E.EMPLOYEE_ID = MS.EMPLOYEE_ID
                      AND MS.MONTH = #value#
              
          </select>
              
              
          <resultMap id="searchResultList" class="MonthlySalesBean">
                      
          <result property="employeeID" column="ID"/>
                      
          <result property="first" column="FIRST"/>
                      
          <result property="last" column="LAST"/>
                      
          <result property="total" column="TOTAL"/>
                      
          <result property="latestSale.amount" column="LATEST_SALE"/>
              
          </resultMap>    
              
              
          <select id="salesByJavaBeansSQL" resultMap="searchResultList">
                  SELECT
                      E.EMPLOYEE_ID "ID",
                      E.FIRST_NAME "FIRST",
                      E.LAST_NAME "LAST",
                      MS.TOTAL_SALES "TOTAL",
                      MS.LATEST_SALE
                  FROM
                      EMPLOYEE E,
                      MONTHLY_SALES MS
                  WHERE
                      E.EMPLOYEE_ID = MS.EMPLOYEE_ID
                      AND MS.MONTH = #value#
              
          </select>    
          </sqlMap>

           

          上面的代碼返回的對(duì)象即為map對(duì)象。請(qǐng)注意,map對(duì)象中的Key值直接來(lái)自于select語(yǔ)句,因此,像TO_CHARMS.TOTAL_SALES)這樣的表達(dá)式在報(bào)表中不提倡使用。因此,比較人性化的為字段命名,是一件很值得的事情。因?yàn)?/span>mapkey值是作為java.lang.Object類(lèi)型來(lái)進(jìn)行存儲(chǔ)的,因此有必要對(duì)字段返回類(lèi)型進(jìn)行一下整理。

          真正的數(shù)據(jù)填充類(lèi)應(yīng)該是ServiceLocatorBean.java類(lèi),其代碼如下所示:

          import java.sql.Connection;
          import java.sql.SQLException;
          import java.sql.Statement;

          import javax.servlet.ServletContext;

          import org.springframework.context.ApplicationContext;
          import org.springframework.web.context.support.WebApplicationContextUtils;

          public class ServiceLocatorBean implements ServiceLocatorIF {
              
              
          private static final long serialVersionUID = -7166271873610635886L;

              
          //the Spring application context
              private ApplicationContext appContext;
                  
              DAO dao 
          = null;
              
              
          public ServiceLocatorBean() {
                  
                  
          try {
                  
                      
          // get the spring context
                      ServletContext context = FacesUtils.getServletContext();
                      
          this.appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
                      
                      
          // create instance of the business object
                      this.dao = (DAO) this.lookupService("dao");
                      
                      Connection conn 
          = this.dao.getSqlMapClient().getDataSource().getConnection();
                      
                      conn.setAutoCommit(
          false);
              
                      
          /*
                         Creating a statement lets us issue commands against
                         the connection.
                       
          */

                      Statement s 
          = conn.createStatement();
                      
                      
          // just in case old tables from prior run (after first run which
                      
          // will create the USER1 schema)
                      try {
                          s.execute(
          "drop table employee");
                          s.execute(
          "drop table monthly_sales");
                      }
           catch (Exception ex) {
                          
          // not to be concerned (at least in this example
                      }

              
                      
          /*
                         We create a table, add a few rows, and update one.
                       
          */

                      s.execute(
          "create table employee (employee_id int, first_name varchar(40), last_name varchar(40))");
                      
                      s.execute(
          "insert into employee values (1,'sterning', 'chen')");
                      s.execute(
          "insert into employee values (2,'yuxuan', 'Wand')");
                      s.execute(
          "insert into employee values (3,'Mickey', 'Li')"); 
                      
                      s.execute(
          "create table monthly_sales (employee_id int, total_sales numeric(16, 2), latest_sale numeric(8, 2), month int)");
                      
                      s.execute(
          "insert into monthly_sales values (1, 1600.50, 32.50, 1)");
                      s.execute(
          "insert into monthly_sales values (2, 1544.20, 12.50, 1)");
                      s.execute(
          "insert into monthly_sales values (3, 18814.80, 78.65, 1)");
                      
                      s.execute(
          "insert into monthly_sales values (1, 1450.50, 10.65, 2)");
                      s.execute(
          "insert into monthly_sales values (2, 2004.25, 52.10, 2)");
                      s.execute(
          "insert into monthly_sales values (3, 9819.00, 40.65, 2)"); 
                      
                      s.close();
                      conn.commit();            
                  
                  }
           catch (SQLException sqle) {
                      
          // just means the tables already exist
                      sqle.printStackTrace();
                  }
           catch (Exception ex) {
                      ex.printStackTrace();
                  }

                  
              }
              
              
              
          public DAO getDao() {
                  
          return this.dao;
              }

              
              
          public Object lookupService(String serviceBeanName) {
                  
          return appContext.getBean(serviceBeanName);
              }


          }


           

          四、將iBATIS數(shù)據(jù)填入JasperReport

          就通常而言,采用Java Bean作為iBATIS的返回對(duì)象,相比起java.util.Map對(duì)象來(lái)說(shuō),更加的方便與可行。很多的開(kāi)發(fā)人員采用iBATIS的這種方式來(lái)進(jìn)行數(shù)據(jù)的映射,同時(shí),此方法還可以無(wú)縫的將iBATISJapserReport集成起來(lái)。

          JasperReport中,提供了一個(gè)JRDataSource的實(shí)現(xiàn),從而開(kāi)發(fā)人員可以通過(guò)此類(lèi)來(lái)傳遞iBATISlist對(duì)象給JasperReport模板。而JRBeanCollectionDataSource類(lèi)使用JavaBean來(lái)構(gòu)造,從而可以通過(guò)循環(huán)查找collection并獲得相應(yīng)的bean屬性。如下的代碼示例說(shuō)明了如何在調(diào)用JasperReport引擎時(shí)實(shí)例化JRBeanCollectionDataSource對(duì)象。

          import java.io.File;
          import java.util.HashMap;
          import java.util.List;

          import net.sf.jasperreports.engine.JRRuntimeException;
          import net.sf.jasperreports.engine.JasperFillManager;
          import net.sf.jasperreports.engine.JasperPrint;
          import net.sf.jasperreports.engine.JasperReport;
          import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
          import net.sf.jasperreports.engine.util.JRLoader;


          public class SearchBean {
              
              
          private final static String JAVA_BEAN_REPORT = "monthly_sales_java_beans.jasper";
              
          private final static String LIST_OF_MAP_REPORT = "monthly_sales_list_of_maps.jasper"

              
          public String generateFromJavaBeans () {
                  
                  
          try {
                      ServiceLocatorIF sl 
          = (ServiceLocatorIF) FacesUtils
                          .getManagedBean(
          "serviceLocatorBean");
                      
                      List list 
          = sl.getDao().getSqlMapClient().queryForList("salesByJavaBeansSQL", month);
                      
                      FacesUtils.setSessionAttribute(
          "JASPER_PRINT", generateReport (list, JAVA_BEAN_REPORT));
                      
                      viewReport 
          = "true";
                  }
           catch (Exception ex) {
                      ex.printStackTrace();
                  }

                  
                  
          return null;
              }

              
              
          public String generateFromListOfMaps () {
                  
                  
          try {
                      ServiceLocatorIF sl 
          = (ServiceLocatorIF) FacesUtils
                          .getManagedBean(
          "serviceLocatorBean");    
                      
                      List list 
          = sl.getDao().getSqlMapClient().queryForList("salesByListOfMapsSQL", month);
                      
                      FacesUtils.setSessionAttribute(
          "JASPER_PRINT", generateReport (list, LIST_OF_MAP_REPORT));
                      
                      viewReport 
          = "true";
                  }
           catch (Exception ex) {
                      ex.printStackTrace();
                  }

                  
                  
          return null;
              }


              
          private JasperPrint generateReport (List dataList, String reportName) {
                  JasperPrint jasperPrint 
          = null;
                  
                  
          try {
                      
                      String localPath 
          = FacesUtils.getServletContext().getRealPath("/");
                      
                      File reportFile 
          = new File(localPath + "WEB-INF" + File.separator + reportName);
                      
                      
          if (!reportFile.exists())
                          
          throw new JRRuntimeException(".jasper file not found. The report design must be compiled first.");
                                  
                      JasperReport jasperReport 
          = (JasperReport)JRLoader.loadObject(reportFile.getPath());
                      
                      
          if (reportName.equals(JAVA_BEAN_REPORT)) {
                          
                          jasperPrint 
          = JasperFillManager.fillReport(
                                  jasperReport,
                                  
          new HashMap(), 
                                  
          new JRBeanCollectionDataSource (dataList));        
                          
                      }
           else {
                          
                          jasperPrint 
          = JasperFillManager.fillReport(
                                  jasperReport,
                                  
          new HashMap(), 
                                  
          new CustomJRDS (dataList));
                          
                      }

                  
                  }
           catch (Exception ex) {
                      ex.printStackTrace();
                  }

                  
                  
          return jasperPrint;
              }
              

              
          public String getMonth() {
                  
          return month;
              }


              
          public void setMonth(String month) {
                  
          this.month = month;
              }


              
          public String getViewReport() {
                  
          return viewReport;
              }


              
          public void setViewReport(String viewReport) {
                  
          this.viewReport = viewReport;
              }

              
              
          private String month = null;
              
          private String viewReport = null;    
          }


           

          在上面的代碼中,定義的參數(shù)map,是在運(yùn)行時(shí)傳遞相關(guān)的參數(shù)值給JasperReport。例如,可以在報(bào)表模板中定義一個(gè)名為REPORT_TITLE的參數(shù),然后在運(yùn)行時(shí)傳遞這一參數(shù)的值給它,傳遞的方式一般是?。祵?duì)的形式。例如Key=REPORT_TITLEValue=Sale Report。當(dāng)然,參數(shù)是傳遞給fillReport方法。然后,JasperReport會(huì)加載已經(jīng)編譯好的Jasper模板文件(.jasper)。最后調(diào)用靜態(tài)的fillReport方法。

          JasperPrint對(duì)象是在數(shù)據(jù)展示或顯示時(shí)需要用到的。而在本例中,采用了JRPdfExporter來(lái)作為輸出的格式,即輸出為PDF格式文件,請(qǐng)參考PdfServlet.java文件,代碼如下所示:

          import java.io.ByteArrayOutputStream;
          import java.io.IOException;
          import java.util.ArrayList;
          import java.util.List;

          import javax.servlet.ServletException;
          import javax.servlet.ServletOutputStream;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          import net.sf.jasperreports.engine.JRException;
          import net.sf.jasperreports.engine.JRExporterParameter;
          import net.sf.jasperreports.engine.JasperPrint;
          import net.sf.jasperreports.engine.export.JRPdfExporter;


          public class PdfServlet extends HttpServlet {

              
          public void service(HttpServletRequest request, HttpServletResponse response)
                      
          throws IOException, ServletException {

                  JasperPrint jasperPrint 
          = (JasperPrint) request.getSession()
                          .getAttribute(
          "JASPER_PRINT");

                  List jasperPrintList 
          = new ArrayList();

                  jasperPrintList.add(jasperPrint);

                  JRPdfExporter exporter 
          = new JRPdfExporter();
                  exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST,
                          jasperPrintList);

                  ByteArrayOutputStream baos 
          = new ByteArrayOutputStream();
                  exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);

                  
          try {
                      exporter.exportReport();
                  }
           catch (JRException e) {
                      
          throw new ServletException(e);
                  }


                  
          byte[] bytes = baos.toByteArray();

                  
          if (bytes != null && bytes.length > 0{
                      response.setContentType(
          "application/pdf");
                      response.setContentLength(bytes.length);
                      ServletOutputStream ouputStream 
          = response.getOutputStream();

                      
          try {
                          ouputStream.write(bytes, 
          0, bytes.length);
                          ouputStream.flush();
                      }
           finally {
                          
          if (ouputStream != null{
                              
          try {
                                  ouputStream.close();
                              }
           catch (IOException ex) {
                              }

                          }

                      }

                  }

              }

          }


           

          盡管上面的JasperReport機(jī)制可以將iBATIS連接起來(lái),但應(yīng)該根據(jù)項(xiàng)目報(bào)表的需要對(duì)JavaBean進(jìn)行修改與調(diào)整。而JasperReport字段對(duì)象可以很好的與普通的JDBC字段進(jìn)行匹配。例如,JasperReportOraclenumeric字段類(lèi)型對(duì)應(yīng)的轉(zhuǎn)成java.math.BigDecimal對(duì)象類(lèi)型。而在iBATISBean屬性應(yīng)該與JasperReport中定義的字段類(lèi)型進(jìn)行很好的匹配。需要對(duì)字段的類(lèi)型進(jìn)行認(rèn)真仔細(xì)的選擇,因?yàn)椴煌?lèi)型或是不同表達(dá)式對(duì)數(shù)據(jù)的展示有不同的效果。例如,BigDecimal類(lèi)型比String類(lèi)型更加適合貨幣格式。

          五、代碼運(yùn)行效果

          1.系統(tǒng)主界面

           


          3.報(bào)表運(yùn)行主界面

          2.采用JavaBean生成報(bào)表


          4.采用JavaBean生成報(bào)表

          六、小結(jié)

          在本文中,筆者展示了如何使用比較成熟的iBATIS數(shù)據(jù)框架來(lái)對(duì)JasperReport進(jìn)行數(shù)據(jù)填充。iBATIS最大的特點(diǎn)是簡(jiǎn)單,而iBATIS所擁有的易維護(hù)及易配置特性,在JasperReport中充分的體現(xiàn)出來(lái)了。這種簡(jiǎn)單與靈活性,正好彌補(bǔ)了JasperReport在這方面的不足,從而達(dá)到靈活開(kāi)發(fā)Web報(bào)表的目的。



          評(píng)論

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2008-01-25 11:26 by ci
          不錯(cuò)....

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2008-01-25 14:55 by cnfox
          rar文件被破壞?

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2008-01-26 19:48 by julycoolboy
          大概看了一下,博主做的不錯(cuò),我來(lái)談?wù)勎沂褂肑R的心得,JR本身分為推和拉的方式來(lái)填充模板,使用BEAN做為數(shù)據(jù)源,就是先取出數(shù)據(jù)后推到JR中去,我這里返回的是一個(gè)自定義Iterator,里面使用的ResultSet,這個(gè)好處就是不會(huì)一次性把數(shù)據(jù)取出來(lái),生成報(bào)表的時(shí)候會(huì)一條條取,這樣就能突破推方式的數(shù)據(jù)量極限了(正常方式下,一個(gè)萬(wàn)條數(shù)據(jù)的LIST,我們的開(kāi)發(fā)PC都容易內(nèi)存溢出)

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2008-04-30 16:38 by regale
          不錯(cuò)....

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2008-07-02 17:14 by wanxinge
          發(fā)一份給我可以嗎?萬(wàn)分感謝啊,下載rar被破壞。我的郵箱:wangxinge_5689@163.com

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2008-12-05 11:52 by ireport
          發(fā)份我,不勝感激!
          lujuju@qq.com

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2008-12-26 04:09 by renbao
          我也需要,謝謝22624223@qq.com

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2009-10-07 03:00 by Wonner
          千萬(wàn)不要用iBATIS.

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2014-11-26 16:10 by 阿浪
          正在學(xué)習(xí)這個(gè),想?yún)⒖家幌?,能發(fā)一份給我嗎?
          1572669095@qq.com

          # re: 使用JasperReport與iBATIS開(kāi)發(fā)Web報(bào)表  回復(fù)  更多評(píng)論   

          2015-01-16 16:42 by hanck
          學(xué)習(xí)中,望前輩們多多指導(dǎo)啊,可以發(fā)一份給我嗎?不勝感激!
          389610110@qq.com
          主站蜘蛛池模板: 宜君县| 巍山| 平阳县| 齐齐哈尔市| 高安市| 西城区| 南和县| 中阳县| 湘潭县| 民和| 大邑县| 西乌珠穆沁旗| 古田县| 延安市| 东光县| 浦东新区| 文昌市| 保定市| 台东县| 克什克腾旗| 宝山区| 土默特左旗| 桃园县| 弥勒县| 越西县| 尉氏县| 赣州市| 漳浦县| 图木舒克市| 马鞍山市| 枞阳县| 旬阳县| 凤翔县| 无极县| 扎囊县| 海宁市| 宝丰县| 芒康县| 柘荣县| 濉溪县| 荥阳市|