第9章 Spring Boot集成Scala混合Java开发

本章我们使用Spring Boot集成Scala混合Java开发一个Web性能测试平台。

使用到的核心技术:

后端:

  • phantomjs
  • scala
  • java
  • springboot
  • velocity
  • jpa
  • maven
  • mysql

前端:

  • jquery
  • bootstrap
  • adminLTE
  • html/css

新建maven工程,配置pom

添加SpringBoot parent依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.3.5.RELEASE</version></parent>

因为我们要使用scala + java混合开发,添加scala依赖

<!-- scala --><dependency><groupId>org.scala-lang</groupId><artifactId>scala-library</artifactId><version>${scala.version}</version></dependency>

然后,我们使用velocity模板引擎,数据库ORM层使用jpa

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-velocity</artifactId></dependency>

构建周期build插件配置:

            <plugin><groupId>org.scala-tools</groupId><artifactId>maven-scala-plugin</artifactId><executions><execution><goals><goal>compile</goal><goal>testCompile</goal></goals></execution></executions><configuration><recompileMode>incremental</recompileMode><scalaVersion>${scala.version}</scalaVersion><launchers><launcher><id>app</id><mainClass>com.light.sword.ylazy.LightSwordApplication</mainClass><args><arg>-deprecation</arg></args><jvmArgs><jvmArg>-Xms256m</jvmArg><jvmArg>-Xmx2048m</jvmArg></jvmArgs></launcher></launchers></configuration><dependencies><!-- spring热部署--><dependency><groupId>org.springframework</groupId><artifactId>springloaded</artifactId><version>1.2.6.RELEASE</version></dependency></dependencies></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><!--<configuration>--><!--<fork>true</fork><!– 如果没有该项配置,肯呢个devtools不会起作用,即应用不会restart –>--><!--</configuration>--></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><executions><execution><phase>package</phase><goals><goal>copy-dependencies</goal></goals></execution></executions><configuration><includeScope>system</includeScope></configuration></plugin>

其中build周期中的maven-scala-plugin是編譯期依賴,scala代碼需要scala的compiler,所以在maven構建過程中,使用一個編譯scala代碼的maven插件.這是typesafe(scala背後的公司)的工程師Josh Suereth開發的,遵循maven插件開發規範.

然後,org.scala-lang:scala-library是Scala應用運行時的依賴.這樣,我們就可以像使用scala來開發SpringBoot应用了。

构建标准maven工程目录

工程目录如下:

配置数据库

我们数据库使用mysql,ORM框架使用spring-jpa,在application.properties配置如下:

#mysql
spring.datasource.url = jdbc:mysql://localhost:3306/ylazy?useUnicode=true&characterEncoding=UTF8
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driverspring.datasource.max-active=0
spring.datasource.max-idle=0
spring.datasource.min-idle=0
spring.datasource.max-wait=10000
spring.datasource.max-wait-millis=31536000# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy# stripped before adding them to the entity manager)
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

写领域实体层代码

package com.light.sword.ylazy.entityimport java.util.Date
import javax.persistence.{Entity, GeneratedValue, GenerationType, Id}import scala.beans.BeanProperty
import scala.language.implicitConversions@Entity
class LazyTask {@Id@GeneratedValue(strategy = GenerationType.AUTO)@BeanPropertyvar id: Integer = _@BeanPropertyvar url: String = _@BeanPropertyvar name: String = _//用例状态: -1未执行 0失败 1成功@BeanPropertyvar state: Integer = _@BeanPropertyvar owner: String = _@BeanPropertyvar resultJson: String = _@BeanPropertyvar executeTimes: Integer = _@BeanPropertyvar executor: Integer = _@BeanPropertyvar gmtCreate: Date = _@BeanPropertyvar gmtModify: Date = _}

Scala中可以为类、方法、字段、局部变量和参数添加注解,与Java一样。可以同时添加多个注解,先后顺序没有影响。 在Scala中,注解可以影响编译过程,比如@BeanProperty注解。

我们使用@Entity注解标记数据库实体类LazyTask,jpa会自动对应到数据表lazy_task, 同时我们使用@BeanProperty标记实体bean里面的属性字段,jpa会自动映射到表里面的字段,自动映射对应的类型。用scala的@BeanProperty注解,会自动生成JavaBeans的getter,setter方法。

Dao层代码

package com.light.sword.ylazy.daoimport java.util.Listimport com.light.sword.ylazy.entity.LazyTask
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.CrudRepository// JavaConversions
import scala.language.implicitConversionstrait LazyTaskDao extends CrudRepository[LazyTask, Integer] {def findAll(): List[LazyTask]def save(t: LazyTask): LazyTaskdef findOne(id: Integer): LazyTask@Query(value = "SELECT * FROM lazy_task where url like '%?1%'", nativeQuery = true)def listByUrl(url: String): List[LazyTask]@Query(value = "SELECT * FROM lazy_task where name like '%?1%'", nativeQuery = true)def listByName(name: String): List[LazyTask]}

Controller层代码

package com.light.sword.ylazy.controllerimport java.util.Dateimport com.light.sword.ylazy.config.DomainConfig
import com.light.sword.ylazy.dao.LazyTaskDao
import com.light.sword.ylazy.engine.PhantomjsExecutor
import com.light.sword.ylazy.entity.LazyTask
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.ui.Model
import org.springframework.web.bind.annotation._
import org.springframework.web.servlet.ModelAndView@RestController
class LazyTaskController @Autowired()(val lazyTaskDao: LazyTaskDao,val phantomjsExecutor: PhantomjsExecutor,val domainConfig: DomainConfig) {@RequestMapping(value = {Array("/newTask.do")})def newTask_do() = {new ModelAndView("ylazy/newTask")}@RequestMapping(value = {Array("/ylazy/newTask")}, method = Array(RequestMethod.POST))@ResponseBodydef newTask(@ModelAttribute lazyTask: LazyTask) = {lazyTask.gmtCreate = new DatelazyTask.gmtModify = new DatelazyTask.executeTimes = 0lazyTask.state = -1lazyTaskDao.save(lazyTask)}@RequestMapping(value = {Array("/list.do")})def list_do(model: Model) = {model.addAttribute("lazyTaskList", lazyTaskDao.findAll())model.addAttribute("domainName", domainConfig.getDomainName)model.addAttribute("port", domainConfig.getPort)new ModelAndView("ylazy/list")}/*** 获取一条任务记录** @param id* @return*/@RequestMapping(value = {Array("/lazytask")}, method = Array(RequestMethod.GET))@ResponseBodydef findOne(@RequestParam(value = "id") id: Integer) = lazyTaskDao.findOne(id)/*** 获取一条任务记录的返回json** @param id* @return*/@RequestMapping(value = {Array("/result/{id}")}, method = Array(RequestMethod.GET))@ResponseBodydef findResultJson(@PathVariable(value = "id") id: Integer) = lazyTaskDao.findOne(id).resultJson/*** 执行任务* @param id* @return*/@RequestMapping(value = {Array("/ylazy/runTask")}, method = Array(RequestMethod.GET))@ResponseBodydef runTask(@RequestParam(value = "id") id: Integer) = {phantomjsExecutor.ylazyById(id)}@RequestMapping(value = {Array("/ylazy")}, method = Array(RequestMethod.GET))@ResponseBodydef ylazy(@RequestParam(value = "url") url: String) = phantomjsExecutor.ylazy(url)}

前端代码

对应的前端模板代码我们放在src/main/resources/templates/ylazy/list.html

#parse("/common/header.html")
#parse("/common/aside.html")<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper"><!-- Content Header (Page header) --><section class="content-header"><h1>YLazy<small>Web性能测试平台</small></h1><!--<ol class="breadcrumb">--><!--<li><a href="#"><i class="fa fa-dashboard"></i> Home</a></li>--><!--<li class="active">Dashboard</li>--><!--</ol>--></section><section class="content"><div class="row"><div class="box box-success"><div class="box-header"><i class="fa fa-sticky-note-o"></i><h3 class="box-title">新增任务</h3></div><form class="box-body" id="newTaskForm"><div class="form-group"><label>任务名称</label><input name='name' class="form-control"></div><div class="form-group"><label>URL</label><input name='url' class="form-control"></div><div class="form-group"><button id='newTaskBtn' type="button" class="btn-sm btn-success"><i class="fa fa-plus"></i>添加</button></div></form></div></div><div class="row"><div class="box box-success"><div class="box-header"><i class="fa fa-list-alt"></i><h3 class="box-title">任务列表</h3></div><div class="box-body"><table id="dataTable"class="table table-hover table-condensed table-responsive"><thead><tr><th>Id</th><th>名称</th><th>URL</th><th>运行次数</th><th>更新时间</th><th>执行结果</th><th>操作</th><th>运行状态</th></tr></thead><tbody>#foreach ($t in $lazyTaskList)<tr><td>$!t.id</td><td>$!t.name</td><td><a target="_blank" href="$!t.url">$!t.url</a></td><td>$!t.executeTimes</td>#set($testTime=$!DateTool.format('yyyy-MM-dd HH:mm:ss', $t.gmtModify))<td>$testTime</td><td><button onclick='reportDetail("$testTime","$t.url",$t.id)' type="button"class="btn-sm btn-link">查看</button></td><td><button id='btn-$t.id'type="button"data-loading-text="执行中"class='btn-sm btn-success text-center'autocomplete="off"onclick='runTest($t.id,this)'>运行</button><p id="msg-$t.id"></p></td><td id="result-$t.id"></td></tr>#end</tbody></table></div></div></div></section>
</div><script>function reportDetail(testTime, url, id) {var detailUrl = "harviewer/index.htm?testTime=" + encodeURIComponent(testTime) +"&testUrl=" + url +"&path=http://$domainName:$port/result/" + id;window.open(detailUrl, "_blank");}function runTest(id, thisBtn) {$(thisBtn).button('loading');$(thisBtn).attr('disabled', 'disabled');var resultId = '#result-' + id;/*** 运行任务*/var url = 'ylazy/runTask?id=' + id;$.ajax({url: url,success: function (data) {if (data) {$(thisBtn).button('reset');$(resultId).html('<p style="color: #00a65a;font-size: 12px;">执行成功</p>');} else {$(thisBtn).button('reset');$(resultId).html('<p style="color:red;font-size: 12px;">执行失败</p>');}}});}$(function () {$('#newTaskBtn').on('click', function () {var data = $('#newTaskForm').serialize();var url = 'ylazy/newTask';//新增任务$.ajax({url: url,data: data,type: 'POST',success: function (result) {if (result) {BootstrapDialog.show({title: '新增任务',message: '响应结果:' + JSON.stringify(result, null, 2),type: BootstrapDialog.TYPE_SUCCESS,closable: false,cssClass: 'dialog_mar',buttons: [{label: '确认',cssClass: 'con_btn',action: function (dialogRef) {dialogRef.close();location.reload();}}, {label: '取消',action: function (dialogRef) {dialogRef.close();}}]});} else {BootstrapDialog.show({title: '新增任务',message: '添加失败', type: BootstrapDialog.TYPE_DANGER,closable: false,cssClass: 'dialog_mar',buttons: [{label: '确认',cssClass: 'con_btn',action: function (dialogRef) {dialogRef.close();location.reload();}}, {label: '取消',action: function (dialogRef) {dialogRef.close();}}]});}}});});//任务列表datatablesvar dataTableOptions = {"bDestroy": true,dom: 'lfrtip',"paging": true,"lengthChange": true,"searching": true,"ordering": true,"info": true,"autoWidth": true,"processing": true,"stateSave": true,responsive: true,fixedHeader: false,order: [[3, "desc"]],"aLengthMenu": [7, 10, 20, 50, 100, 200],language: {"search": "<div style='border-radius:10px;margin-left:auto;margin-right:2px;width:760px;'>_INPUT_  <span class='btn-sm btn-success'>搜索</span></div>",paginate: {//分页的样式内容previous: "上一页",next: "下一页",first: "第一页",last: "最后"}},zeroRecords: "没有内容",//table tbody内容为空时,tbody的内容。//下面三者构成了总体的左下角的内容。info: "总计 _TOTAL_ 条,共 _PAGES_ 页,_START_ - _END_ ",//左下角的信息显示,大写的词为关键字。infoEmpty: "0条记录",//筛选为空时左下角的显示。infoFiltered: ""//筛选之后的左下角筛选提示};$('#dataTable').DataTable(dataTableOptions);})
</script>#parse("/common/footer.html")

完整的工程源代码:

https://github.com/EasySpringBoot/ylazy

运行测试

在pom.xml所在目录,命令行运行:

mvn clean scala:compile scala:run -Dlauncher=app

浏览器访问:http://localhost:9050/list.do

你将看到如下页面:

小结

本章给出了一个使用Scala进行SpringBoot应用的开发实例。

Scala是一门JVM上的语言。它精心整合了面向对象和函数式编程语言,支持面向对象编程范式,支持函数式编程范式,语法动态简洁表达力丰富,具备静态强类型和丰富的泛型。

参考资料

http://www.jianshu.com/p/51535e85bae5

《Spring Boot极简教程》第9章 Spring Boot集成Scala混合Java开发相关推荐

  1. 《React极简教程》第一章 Hello,World!

    react React 是一个用于构建用户界面的 JAVASCRIPT 库. React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图). React 起源于 Facebook ...

  2. 《Spring Boot极简教程》第8章 Spring Boot集成Groovy,Grails开发

    第8章 Spring Boot集成Groovy,Grails开发 本章介绍Spring Boot集成Groovy,Grails开发.我们将开发一个极简版的pms(项目管理系统). Groovy和Gra ...

  3. 《MongoDB极简教程》第一章 NoSQL简史 amp; MongoDB安装amp;环境配置

    MongoDB 是一款开源的文档数据库,并且是业内领先的 NoSQL 数据库,用 C++ 编写而成. NoSQL (NoSQL = Not Only SQL ),意即"不仅仅是SQL&quo ...

  4. 《MongoDB极简教程》第一章 NoSQL简史 MongoDB安装环境配置

    MongoDB 是一款开源的文档数据库,并且是业内领先的 NoSQL 数据库,用 C++ 编写而成. NoSQL (NoSQL = Not Only SQL ),意即"不仅仅是SQL&quo ...

  5. 《Spring Boot极简教程》附录3 编程简史

    附录3 编程简史 1940之前 提花织布机 1801,Joseph Marie Jacquard用打孔卡为一台织布机编写指令,在提花织布机(或称甲卡提花织布机,Jacquard loom)上,运用打孔 ...

  6. 《Spring Boot极简教程》附录4 Java编程简史

    附录4 Java编程简史 从GOTO到OOP 在20世纪60年代,软件曾出现过严重危机,由软件错误而引起的信息丢失.系统报废事件屡有发生.为此,1968年,荷兰E.W.Dijkstra提出了程序设计中 ...

  7. LLVM极简教程: 第三章 LLVM IR代码生成

    第三章 LLVM IR代码生成 原文: Code generation to LLVM IR 本章简介 欢迎进入"用LLVM开发新语言"教程的第三章.本章将介绍如何把第二章中构造的 ...

  8. 【抽象代数】第一章 代数系统《抽象代数极简教程》/ By 禅与计算机程序设计艺术ChatGPT

    <抽象代数极简教程> 文章目录 <抽象代数极简教程> 第一章 代数系统 1.1 集合的基本概念 1.2 二元运算 1.3 代数系统的定义 什么是代数? 抽象代数和初等代数有什么 ...

  9. 《Kotin 极简教程》第13章 使用 Kotlin 和 Anko 的Android 开发

    第13章 使用 Kotlin 和 Anko 的Android 开发 最新上架!!!< Kotlin极简教程> 陈光剑 (机械工业出版社) 可直接打开京东,淘宝,当当===> 搜索: ...

  10. 《Kotin 极简教程》第14章 使用 Kotlin DSL

    第14章 使用 Kotlin DSL 最新上架!!!< Kotlin极简教程> 陈光剑 (机械工业出版社) 可直接打开京东,淘宝,当当===> 搜索: Kotlin 极简教程 htt ...

最新文章

  1. python除号的乘法加括号_乘除法添加括号规则
  2. 2_1 AdpterMode.cpp 适配器模式
  3. mysql创建定时器(event),查看定时器,打开定时器,设置定时器时间
  4. 尬出天际!和导师微信聊天大型翻车现场!
  5. 2048java课程设计报告_2048小游戏-Java-课程设计报告书
  6. Mr.J-- jQuery学习笔记(七)--CSS类操作文本值操作
  7. JAVA开发血泪之路:一步步搭建spring框架
  8. 后台代码之买票和查找核实航班的代码
  9. SpringBoot 下 Mybatis 的缓存
  10. Python 数据分析 —— Matplotlib ①
  11. 在安装软件CAJViewer时出现,“错误1327。无效驱动器:F:
  12. 使用Python实现一个简单的聊天室
  13. SEUS 转换XML到JAVA
  14. 站内信系统数据库设计
  15. 虎跃后台管理系统,数据分发+授权管理+权限管理
  16. Conflux CTO 伍鸣博士出席 2019 CAN 大会
  17. 【Unity3D】学习笔记(第2记) 2D游戏开发基本技巧之背景制作
  18. 《软件体系结构》知识点整理
  19. 深度学习入门笔记(九):深度学习数据处理
  20. 网易云课堂Java进阶学习笔记系列03 -- 第7周 抽象与接口

热门文章

  1. Anaconda 安装步骤
  2. matlab俄罗斯方块说明,俄罗斯方块MATLAB版的代码
  3. Mac安装mysql 8.0.21
  4. 离散数学经典教材及资料(整理)
  5. python与机械教育初探_《Python与机器人程序设计》
  6. Java学到什么程度可以面试工作?
  7. Python多线程实例
  8. JDK API 1.6.0中文版纯分享
  9. 【精品】好用的验证码工具类VerifyCodeUtils
  10. java2实用教程 第四版 上机实践4代码_Java2实用教程实验指导模版代码