简体   繁体   English

如何在Grails Jasper插件中使用jasperreports子报表?

[英]How to use jasperreports subreports with grails jasper plugin?

I would like to use subreports with grails jasper plugins, I followed the manual at this url ( http://www.grails.org/plugin/jasper ). 我想将子报表与grails jasper插件一起使用,我在此URL( http://www.grails.org/plugin/jasper )上遵循了手册。 Here is my code : 这是我的代码:

Domain Book : 领域书:

class Book {

  static belongsTo = Library

    Library library

    String title
    String author
    String publisher
    String category

    static constraints={
        title()
        author()
        publisher()
        category()
    }
}

Domain Library : 域库:

class Library {

  static hasMany = [ books : Book ]

  String name
  String adresse
  Date dateMaturity

    static constraints = {
    }

        String toString()
    {
        return name
    }
}

In my BookController, I have : 在我的BookController中,我有:

def createReport = {
    def books = Book.list()
    chain(controller:'jasper',action:'index',model:[data:books],params:params)
}

In my LibraryController, I have : 在我的LibraryController中,我有:

def createReport = {
    def library = Library.list()
    chain(controller:'jasper',action:'index',model:[data:library],params:params)
}

My jasper part is : 我的碧玉部分是:

I have a SubReport file : books.jasper (get a list of books). 我有一个SubReport文件:books.jasper(获取书籍列表)。
Also a MasterReport : library.jasper (get a list of library). 也是MasterReport:library.jasper(获取库列表)。

In my MasterReport(library), I added subreport, I would like, for each library, show list of books it contains ; 在我的MasterReport(库)中,我添加了子报表,我希望针对每个图书馆,显示其中包含的图书清单; here is my library code : 这是我的图书馆代码:

<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
...
<field name="books" class="java.util.Collection"/>
...
<subreport isUsingCache="true">
<reportElement x="0" y="25" width="437" height="100"/>
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{books})]]></dataSourceExpression>
<subreportExpression class="java.lang.String"><![CDATA[$P{SUBREPORT_DIR} + "books.jasper"]]>
</subreportExpression>
</subreport>

And I have this error : 我有这个错误:

Error 500: Executing action [index] of controller [JasperController] in plugin [jasper] caused exception: net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression : Source text : new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{books}) 错误500:在插件[jasper]中执行控制器[JasperController]的操作[index]导致异常:net.sf.jasperreports.engine.fill.JRExpressionEvalException:错误评估表达式:源文本:新的net.sf.jasperreports.engine.data .JRBeanCollectionDataSource($ F {books})
Exception Message: failed to lazily initialize a collection of role: bookshelf.Library.books, no session or session was closed 异常消息:无法延迟初始化角色集合:bookshelf.Library.books,没有会话或会话被关闭

Thank you for help. 谢谢你的帮助。

Jasper reports just expects the list of objects. Jasper报告只需要对象列表。 It doesn't understand GORM queries. 它不理解GORM查询。 So the way we do is by creating a separate list of objects which we name as 'View Objects' and then send them to jasper reports instead of domain classes. 因此,我们的方法是创建一个单独的对象列表,将其命名为“查看对象”,然后将其发送到jasper报告而不是域类。

 class LibraryVO {
   List books
   String name
   String adresse
   Date dateMaturity
  }

 class bookVO {
  String title
    String author
    String publisher
    String category
  }

You can initializ the list like 您可以像这样初始化列表

 List data=[]

 LibraryVo libVo= new LibraryVO(...) // inalise it here
 libVo.books = [new BookVO(),new BookVO()]

 data << libVO

And pass the list to jasper controller 并将列表传递给Jasper Controller

(chain(controller:'jasper',action:'index',model:[data:data],params:params).

I have a *.jasper (DataSource XML. I used iReport). 我有一个* .jasper(数据源XML。我使用了iReport)。 How can pass it (book as XML)?? 如何传递它(作为XML的书)?

Thanks beforehand 预先感谢

I find the issue : 我发现问题:

In my Library domain, I just add a mapping with "books lazy: false" : 在我的图书馆域中,我只添加了一个带有“ books lazy:false”的映射:

class Library {

  static hasMany = [ books : Book ]

  String name
  String adresse
  Date dateMaturity

    static constraints = {
    }

    static mapping = {
    books lazy: false
  }

        String toString()
    {
        return name
    }
}

And now, I have my report witout troubles ! 现在,我有麻烦的报告了!


The grails jasper plugin use chain to chains the model from one action to the next ( chain(controller:'jasper',action:'index',model:[data:library],params:params ). grails jasper插件使用链将模型从一个动作链接到另一个动作( chain(controller:'jasper',action:'index',model:[data:library],params:params )。

After, in jasper controller we get the model by this line : 之后,在jasper控制器中,我们通过以下代码获取模型:

def testModel = this.getProperties().containsKey('chainModel')?chainModel:null

For some reason, in Library collection, we have an error on books list, eg : org.hibernate.LazyInitializationException: failed to lazily initialize a collection - no session or session was closed 由于某种原因,在图书馆藏书中,我们在书单上有一个错误,例如:org.hibernate.LazyInitializationException:无法延迟初始化藏书-没有会话或会话被关闭

By using "lazy: false", we pull all other instances of the domain class. 通过使用“ lazy:false”,我们提取域类的所有其他实例。

Is there another way to fix this issue ? 还有另一种方法可以解决此问题?

You can use a jasper report to call your gorm but you need to set the language for the report to groovy not java as it's default. 您可以使用jasper报告来调用gorm,但是您需要将报告的语言设置常规而不是Java,因为它是默认语言。 Then if you use subreports you need to disable jasper report multithreading and add additional jars. 然后,如果您使用子报表,则需要禁用jasper报表多线程并添加其他jar。 It's just work perfectly. 完美地工作了。

The LazyInitializationException is because the objects in testModel are not attached to the current hibernate session. LazyInitializationException是因为testModel中的对象未附加到当前的休眠会话。 I've just got around this by hacking the JasperController as follows: 我只是通过如下方式入侵JasperController来解决这个问题:

class JasperController {
    JasperService jasperService

    // We need this to access the current hibernate session
    def sessionFactory

    def index = {
        println(params)

        def testModel = this.getProperties().containsKey('chainModel') ? chainModel : null

        // Re-attach model objects to avoid LazyInitializationException.
        def session = sessionFactory.getCurrentSession()
        testModel?.data?.each
        {
            session.update(it)
        }

        JasperReportDef report = jasperService.buildReportDefinition(params,            request.getLocale(), testModel)
        generateResponse(report)
    }

... and so on. ... 等等。 This re-attaches the model objects, avoiding the LIE (without having to eager fetch) 这样就重新附加了模型对象,从而避免了LIE(不必急于获取)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM