利用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;
- 点击
Next >。 - 选择所有字段
name、author和comment,点击Next >。 - 跳过分组排序部分,点击
Next >,然后点击Finish。 - 移除所有模板标签和字段,仅保留数据库字段。可点击底部的
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;
- 点击
Next >。 - 选择所有字段
name、url,点击Next >。 - 跳过分组排序部分,点击
Next >,然后点击Finish。 - 移除所有标签和字段,仅保留数据适配器中的标签和字段。从右侧面板的
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框架的高级特性,如分布式系统、集群管理等,以满足更复杂的业务需求。
超级会员免费看
3934

被折叠的 条评论
为什么被折叠?



