15、利用Jaspersoft Studio和JasperReports创建自定义报告并集成到Play框架

利用Jaspersoft Studio和JasperReports创建自定义报告并集成到Play框架

在开发应用程序时,生成自定义报告是一项常见需求。本文将详细介绍如何使用Jaspersoft Studio和JasperReports创建自定义报告,并将其集成到Play框架应用程序中。

1. 安装Jaspersoft Studio 6

在安装Jaspersoft Studio 6之前,需要确保已安装Java 8。若未安装,需进行相应安装。Jasper可在多平台运行,但在Windows上表现更佳。若使用Linux系统,需要处理字体问题,因为JasperReports使用了许多微软的核心字体,如Arial和Times New Roman。以下是在Linux上处理字体的方法:
- 若为Linux/Windows双系统,可从Windows驱动器的 WindowsDrive/Windows/Fonts 路径复制所有字体文件到Linux的 /usr/share/fonts 目录,然后运行 $ sudo fc-cache -fv 命令更新字体缓存。此过程可能需要一些时间,例如,Windows系统的字体文件约为300MB。
- 也可在Linux上寻找mscorefonts安装程序。

安装字体后,可从 http://community.jaspersoft.com/project/jasperreports-library/releases 下载Jaspersoft Studio 6的6.2.2版本。若使用Linux系统,强烈建议使用DEB包,否则需安装多个其他依赖项。

2. 配置Jaspersoft Studio中的MySQL数据适配器

安装并打开Jaspersoft Studio 6后,需配置MySQL数据适配器,步骤如下:
1. 点击 File | New | Data Adapter Wizard
2. 将文件名设置为 MYSQL_DATAADAPTER.xml ,然后点击 Next >
3. 选择 Database JDBC Connection ,再点击 Next >
4. 配置连接详细信息:
- Name :MySQL
- JDBC Driver :com.mysql.jdbc.Driver
- JDBC Url :jdbc:mysql://localhost/RWS_DB?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
- Username :root
- Password :若有密码则输入,否则留空。
5. 配置驱动到Jaspersoft Studio类路径。由于应用程序在同一台机器上运行,可将SBT下载的MySQL驱动(路径为 ~/.ivy2/cache/mysql/mysql-connector-java/jars/mysql-connector-java-6.0.3.jar )在 Driver Classpath 选项卡中指定。
6. 测试连接是否正常。

3. 创建报告

配置好数据适配器后,即可开始创建报告。以下分别介绍产品报告、评论报告和图像报告的创建过程。

3.1 创建产品报告

创建产品报告的步骤如下:
1. 点击 File | New | Jasper Report ,选择 Invoice 模板,点击 Next >
2. 将文件名设置为 Products.jrxml ,点击 Next >
3. 选择数据源为 MySQL
4. 运行查询 Select name, details, price from Product; ,点击 Next >
5. 选择报告中要使用的字段,将左侧列表中的所有字段移至右侧列表,点击 Next >
6. 跳过分组排序部分,再次点击 Next >
7. 完成设置后,可预览报告。点击新报告 Products.jxml ,移除不需要的字段和logo,将标题改为 Products ,保留 NAME DETAILS PRICE 表头以及对应的数据库字段 $F{NAME} $F{DETAILS} $F{PRICE}
8. 点击底部的 Preview 选项卡,从屏幕顶部选择 MySQL 作为数据源和导出格式(如Java或PDF)。

3.2 创建评论报告

创建评论报告的步骤如下:
1. 点击 File | New | Jasper Report ,选择 Invoice 模板,点击 Next >
2. 将文件名设置为 Reviews.jrxml ,点击 Next >
3. 选择 MySQL 作为数据适配器,点击 Next >
4. 在 Query(Text) 中输入以下查询代码:

Select p.name, r.author, r.comment 
from Product p, Review r 
where p.id = r.product_id;
  1. 点击 Next >
  2. 选择所有字段 name author comment ,点击 Next >
  3. 跳过分组排序部分,点击 Next > ,然后点击 Finish
  4. 移除所有模板标签和字段,仅保留数据库字段。可点击底部的 Preview 选项卡,选择 MySQL Java 查看报告,但需确保数据库中有数据,否则报告将为空。
3.3 创建图像报告

创建图像报告的步骤如下:
1. 点击 File | New | Jasper Report ,选择 Invoice 模板,点击 Next
2. 将文件名设置为 Images.jrxml ,点击 Next
3. 选择 MySQL 作为数据适配器,点击 Next >
4. 在 Query(Text) 中输入以下查询代码:

Select p.name, i.url 
from Image i, Product p 
where p.id = i.product_id;
  1. 点击 Next >
  2. 选择所有字段 name url ,点击 Next >
  3. 跳过分组排序部分,点击 Next > ,然后点击 Finish
  4. 移除所有标签和字段,仅保留数据适配器中的标签和字段。从右侧面板的 Basic Elements 中找到 Image 组件,将其拖放到详细信息区域,选择自定义表达式并输入 $F{url}
4. 集成JasperReports到Play框架

创建好报告后,需要将JasperReports集成到Play框架应用程序中。具体步骤如下:

4.1 创建文件夹并复制文件

ReactiveWebStore/app 目录下创建一个名为 reports 的新文件夹,将Jaspersoft Studio中创建的三个 .jrxml 文件复制到该文件夹。

4.2 配置build.sbt文件

build.sbt 文件中添加JasperReports依赖项和解析器,代码如下:

libraryDependencies ++= Seq( 
  // .... Other dependencies .... 
  "net.sf.jasperreports" % "jasperreports" % "6.2.2"  withSources(),
  "net.sf.jasperreports" % "jasperreports-functions" % "6.2.2", 
  "net.sf.jasperreports" % "jasperreports-chart-themes" % "6.2.2" 
) 
resolvers += "Jasper" at 
"https://jaspersoft.artifactoryonline.com/jaspersoft/repo/" 
resolvers += "JasperSoft" at 
"https://jaspersoft.artifactoryonline.com/jaspersoft/jaspersoft-repo/" 
resolvers += "Jasper3rd" at 
"https://jaspersoft.artifactoryonline.com/jaspersoft/jaspersoft-3rd-party/" 
resolvers += "mondrian-repo-cache" at 
"https://jaspersoft.artifactoryonline.com/jaspersoft/mondrian-repo-cache/" 
resolvers += "spring-mil" at "http://repo.spring.io/libs-milestone" 
resolvers += "spring-rel" at "http://repo.spring.io/libs-release" 
resolvers += "oss" at 
"https://oss.sonatype.org/content/groups/public/" 

配置完成后,在控制台运行 $ activator compile 命令重新加载新依赖项,运行该命令后,还需运行 $ activator eclipse 重新生成Eclipse文件。

5. 创建通用报告生成器

接下来,使用Scala创建一个通用报告生成器。在 ReactiveWebStore/app/reports 目录下创建一个名为 ReportBuilder.scala 的新Scala类,代码如下:

package reports 
object ReportBuilder { 
  private var reportCache:scala.collection.Map[String,Boolean] =  
  new scala.collection.mutable.HashMap[String,Boolean].empty 
  def generateCompileFileName(jrxml:String): String =  
  "/tmp/report_" + jrxml + "_.jasper" 
  def compile(jrxml:String){ 
    if(reportCache.get(jrxml).getOrElse(true)){ 
      JasperCompileManager.compileReportToFile( new  
      File(".").getCanonicalFile +     "/app/reports/" + jrxml ,  
      generateCompileFileName(jrxml)) 
      reportCache += (jrxml -> false) 
    } 
  } 
  def toPdf(jrxml:String):ByteArrayInputStream = { 
    try { 
      val os:OutputStream = new ByteArrayOutputStream() 
      val reportParams:java.util.Map[String,Object] = new  
      java.util.HashMap() 
      val con:Connection = DriverManager.getConnection 
      ("jdbc:mysql://localhost/RWS_DB?user=root&password=&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC") 
      compile(jrxml) 
      val jrprint:JasperPrint = JasperFillManager.fillReport 
      (generateCompileFileName(jrxml),  reportParams, con) 
      val exporter:JRPdfExporter = new JRPdfExporter() 
      exporter.setExporterInput(new SimpleExporterInput(jrprint)) 
      exporter.setExporterOutput 
      (new SimpleOutputStreamExporterOutput(os)); 
      exporter.exportReport() 
      new ByteArrayInputStream 
      ((os.asInstanceOf[ByteArrayOutputStream]).toByteArray()) 
    }catch { 
      case e:Exception => throw new RuntimeException(e) 
    } 
  } 
} 

该代码实现了以下功能:
- generateCompileFileName 函数用于生成Jasper编译文件的临时文件名。
- compile 函数用于编译JRXML报告文件,并使用缓存机制避免重复编译。
- toPdf 函数用于将JRXML报告转换为PDF格式,通过 JasperFillManager 填充报告数据,并使用 JRPdfExporter 导出为PDF,最后返回一个 ByteArrayInputStream 对象。

6. 修改控制器以生成报告

为了能够生成产品、评论和图像报告,需要修改相应的控制器。

6.1 修改产品控制器

ProductController.scala 文件中添加报告生成函数,代码如下:

@Singleton 
class ProductController @Inject() (val messagesApi:MessagesApi,val 
service:IProductService) extends Controller with I18nSupport { 
  //... rest of the controller code... 
  def report() = Action { 
    import play.api.libs.concurrent. 
    Execution.Implicits.defaultContext 
    Ok.chunked( Enumerator.fromStream(  
    ReportBuilder.toPdf("Products.jrxml") ) ) 
    .withHeaders(CONTENT_TYPE -> "application/octet-stream") 
    .withHeaders(CONTENT_DISPOSITION -> "attachment;  
      filename=report-products.pdf" 
    ) 
  }
}
6.2 修改评论控制器

ReviewController.scala 文件中添加报告生成函数,代码如下:

@Singleton 
class ReviewController @Inject() 
(val messagesApi:MessagesApi, 
  val productService:IProductService, 
val service:IReviewService) 
extends Controller with I18nSupport { 
  //... rest of the controller code... 
  def report() = Action { 
    import play.api.libs.concurrent.Execution. 
    Implicits.defaultContext 
    Ok.chunked( Enumerator.fromStream(  
    ReportBuilder.toPdf("Reviews.jrxml") ) ) 
    .withHeaders(CONTENT_TYPE -> "application/octet-stream") 
    .withHeaders(CONTENT_DISPOSITION -> "attachment;  
    filename=report-reviews.pdf") 
  } 
} 
6.3 修改图像控制器

ImageController.scala 文件中添加报告生成函数,代码如下:

@Singleton 
class ImageController @Inject() 
(val messagesApi:MessagesApi, 
  val productService:IProductService, 
val service:IImageService) 
extends Controller with I18nSupport { 
  // ... rest of the controller code ... 
  def report() = Action { 
    import play.api.libs.concurrent.Execution. 
    Implicits.defaultContext 
    Ok.chunked( Enumerator.fromStream(  
      ReportBuilder.toPdf("Images.jrxml") ) ) 
    .withHeaders(CONTENT_TYPE -> "application/octet-stream") 
    .withHeaders(CONTENT_DISPOSITION -> "attachment;  
      filename=report-images.pdf") 
  } 
} 
7. 配置路由

修改完控制器后,需要配置路由才能调用这些控制器。编辑 conf/routes 文件,添加以下路由信息:

GET     /reports           controllers.HomeController.reports  
# 
# Reports 
# 
GET  /product/report       controllers.ProductController.report 
GET  /review/report        controllers.ReviewController.report 
GET  /image/report         controllers.ImageController.report 
8. 创建新的集中式报告UI

为了方便用户访问报告,需要创建一个新的视图来集中显示所有报告。在 ReactiveWebStore/views 目录下创建一个名为 reports_index.scala.html 的新视图文件,代码如下:

@()(implicit flash: Flash) 
@main("Reports") { 
  <a href="/product/report"><img height="42" width="42"   
  src="@routes.Assets.at("images/product.png")"> Products  
  Report</a><BR> 
  <a href="/review/report"><img height="42" width="42"  
  src="@routes.Assets.at("images/review.png")"> Reviews Report  
  </a><BR> 
  <a href="/image/report"><img height="42" width="42"  
  src="@routes.Assets.at("images/image.png")"> Images  
  Report</a><BR> 
} 
9. 为每个视图添加报告按钮

最后,需要在产品、评论和图像视图中添加报告按钮,方便用户直接访问报告。

9.1 修改产品视图

product_index.scala.html 文件中添加报告按钮,代码如下:

@(products:Seq[Product])(implicit flash: Flash) 
@main("Products") { 
  // ... rest of the ui code ... 
  <p> 
    <a href="@routes.ProductController.blank" class="btn btn- 
    success"> 
    <i class="icon-plus icon-white"></i>Add Product</a>  
    <a href="@routes.ProductController.report" class="btn btn- 
    success"> 
    <i class="icon-plus icon-white"></i>Products Report</a> 
  </p> 
} 
9.2 修改评论视图

review_index.scala.html 文件中添加报告按钮,代码如下:

@(reviews:Seq[Review])(implicit flash: Flash) 
@main("Reviews") { 
  // ... rest of the ui code ... 
  <p> 
    <a href="@routes.ReviewController.blank" class="btn btn- 
    success"><i class="icon-plus icon-white"></i>Add Review</a>  
    <a href="@routes.ReviewController.report" class="btn btn- 
    success"><i class="icon-plus icon-white"></i>Review Report</a>  
  </p> 
} 
9.3 修改图像视图

image_index.scala.html 文件中添加报告按钮,代码如下:

@(images:Seq[Image])(implicit flash:Flash) 
@main("Images") { 
  // ... rest of the ui template ... 
  <p> 
    <a href="@routes.ImageController.blank" class=
    "btn btn-success"><i class="icon-plus icon-white"></i>Add 
    Image</a>  
    <a href="@routes.ImageController.report" class=
    "btn btn-success"><i class="icon-plus icon-white"></i>
    Images Report</a>  
  </p> 
} 

完成以上步骤后,运行 $ activator run 命令启动应用程序,访问 http://localhost:9000/ 即可看到新的UI和报告按钮。点击相应的报告链接,即可下载PDF格式的报告。

通过以上步骤,我们成功使用Jaspersoft Studio和JasperReports创建了自定义报告,并将其集成到Play框架应用程序中。

10. 后续展望 - 使用Akka框架开发聊天功能

除了生成报告,我们还可以使用Akka框架为应用程序添加更多功能。在后续开发中,我们将学习如何使用Akka框架创建Actor,并结合Play框架和WebSockets实现聊天功能。具体将涵盖以下内容:
- 理解Actor模型
- Actor系统、Actor路由和调度器
- 邮箱、Actor配置和持久化
- 创建聊天应用程序
- 测试Actor

通过使用Akka框架,我们可以进一步扩展应用程序的功能,为用户提供更丰富的体验。

利用Jaspersoft Studio和JasperReports创建自定义报告并集成到Play框架

11. 深入理解Akka框架在聊天功能开发中的应用
11.1 Actor模型概述

Actor模型是一种并发编程模型,它将系统中的各个组件抽象为独立的Actor。每个Actor都有自己的状态和行为,它们之间通过消息传递进行通信。在我们的应用中,使用Actor模型可以更好地处理并发请求,实现高效的聊天功能。

例如,在聊天应用中,每个用户可以看作一个Actor。当一个用户发送消息时,这个消息会被发送到另一个用户对应的Actor的邮箱中,然后该Actor会根据消息内容进行相应的处理。

11.2 Actor系统、路由和调度器
  • Actor系统 :是一组Actor的集合,它为Actor提供了运行环境。在我们的应用中,需要创建一个Actor系统来管理所有与聊天相关的Actor。
  • Actor路由 :用于将消息分发到合适的Actor。在聊天应用中,路由可以根据消息的接收者将消息准确地发送到对应的用户Actor。
  • 调度器 :负责决定何时执行Actor的行为。它可以根据系统的负载和Actor的优先级来合理分配资源。

以下是一个简单的创建Actor系统的示例代码:

import akka.actor.ActorSystem

object ChatActorSystem {
  val system = ActorSystem("ChatSystem")
}
11.3 邮箱、Actor配置和持久化
  • 邮箱 :每个Actor都有一个邮箱,用于存储接收到的消息。邮箱的类型和配置会影响消息的处理顺序和性能。
  • Actor配置 :可以对Actor的行为进行定制,例如设置Actor的生命周期、消息处理策略等。
  • 持久化 :在聊天应用中,为了保证消息的可靠性和可恢复性,需要对消息进行持久化存储。Akka提供了持久化机制,可以将Actor的状态和消息存储到数据库中。

以下是一个简单的Actor配置示例:

import akka.actor.Props

val chatActorProps = Props[ChatActor]
  .withDispatcher("my-dispatcher")
  .withMailbox("my-mailbox")
12. 创建聊天应用程序
12.1 定义Actor

首先,我们需要定义聊天相关的Actor。以下是一个简单的聊天Actor的示例代码:

import akka.actor.{Actor, ActorRef}

class ChatActor(receiver: ActorRef) extends Actor {
  def receive = {
    case message: String =>
      println(s"Received message: $message")
      receiver ! s"Reply: $message"
  }
}
12.2 集成WebSockets

为了实现实时聊天功能,我们需要将Actor与WebSockets集成。Play框架提供了对WebSockets的支持,我们可以通过WebSockets将用户的消息发送到对应的Actor,并将Actor的回复发送回用户。

以下是一个简单的WebSockets控制器示例:

import akka.actor.ActorSystem
import akka.stream.Materializer
import javax.inject._
import play.api.mvc._

import scala.concurrent.ExecutionContext

@Singleton
class ChatController @Inject()(cc: ControllerComponents)(implicit system: ActorSystem, mat: Materializer, ec: ExecutionContext) extends AbstractController(cc) {
  def chat = WebSocket.accept[String, String] { request =>
    val chatActor = system.actorOf(Props[ChatActor])
    Flow.fromSinkAndSource(
      Sink.actorRef(chatActor, "Completed"),
      Source.actorRef(10, OverflowStrategy.fail)
    )
  }
}
12.3 配置路由

conf/routes 文件中添加WebSockets路由:

GET     /chat           controllers.ChatController.chat
13. 测试Actor

为了确保Actor的正确性和稳定性,我们需要对其进行测试。可以使用Akka提供的测试工具来编写单元测试。

以下是一个简单的Actor测试示例:

import akka.actor.{ActorSystem, Props}
import akka.testkit.{ImplicitSender, TestKit}
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}

class ChatActorSpec extends TestKit(ActorSystem("TestSystem")) with ImplicitSender
  with WordSpecLike with Matchers with BeforeAndAfterAll {

  override def afterAll(): Unit = {
    TestKit.shutdownActorSystem(system)
  }

  "A ChatActor" must {
    "reply to a message" in {
      val chatActor = system.actorOf(Props[ChatActor])
      chatActor ! "Hello"
      expectMsg("Reply: Hello")
    }
  }
}
14. 总结与回顾

通过以上步骤,我们不仅成功地使用Jaspersoft Studio和JasperReports创建了自定义报告,并将其集成到Play框架应用程序中,还进一步探索了如何使用Akka框架开发聊天功能。

在报告生成部分,我们详细介绍了从安装Jaspersoft Studio、配置数据适配器、创建各种报告,到集成到Play框架的完整流程。通过编写Scala代码,实现了通用报告生成器,并对控制器、路由和UI进行了相应的修改。

在聊天功能开发部分,我们深入理解了Actor模型,学习了Actor系统、路由、调度器、邮箱、配置和持久化等概念,并通过代码示例展示了如何创建聊天应用程序和测试Actor。

以下是整个开发流程的mermaid流程图:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px

    A([开始]):::startend --> B(安装Jaspersoft Studio):::process
    B --> C(配置MySQL数据适配器):::process
    C --> D(创建报告):::process
    D --> E(集成到Play框架):::process
    E --> F(创建通用报告生成器):::process
    F --> G(修改控制器):::process
    G --> H(配置路由):::process
    H --> I(创建报告UI):::process
    I --> J(添加报告按钮):::process
    J --> K(完成报告集成):::process
    K --> L(学习Akka框架):::process
    L --> M(理解Actor模型):::process
    M --> N(创建聊天应用):::process
    N --> O(测试Actor):::process
    O --> P([结束]):::startend

通过不断学习和实践,我们可以进一步优化应用程序的性能和功能,为用户提供更好的体验。在未来的开发中,还可以探索更多关于Akka框架和Play框架的高级特性,如分布式系统、集群管理等,以满足更复杂的业务需求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值