8.3 Spring Boot集成Scala混合Java开发

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

使用到的相关技术:

后端:

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

前端:

  • jquery
  • bootstrap
  • adminLTE
  • html/css

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

新建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></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></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应用的开发实例。

关于SpringBoot集成Scala开发,还可以参考本书中的另外的工程实例源码:

HTTP接口测试平台:
https://github.com/EasySpringBoot/lightsword

Teda自动化用例调度执行平台:
https://github.com/EasySpringBoot/teda

参考资料

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

8.3 Spring Boot集成Scala混合Java开发相关推荐

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

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

  2. Java微服务之Spring Boot on Docker,java开发面试笔试题

    我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家. 扫描二维码或搜索下图红色VX号,加VX好友,拉你进[程序员面试学习交流群]免费领取.也欢迎各位一起 ...

  3. 【Java进阶】Spring Boot集成ES

    目录 spring boot集成ES ElasticSearchConfig 测试文档的基本操作 Elasticsearch Clients 文档 spring boot集成ES Java REST ...

  4. 6.3 Spring Boot集成mongodb开发

    6.3 Spring Boot集成mongodb开发 本章我们通过SpringBoot集成mongodb,Java,Kotlin开发一个极简社区文章博客系统. 0 mongodb简介 Mongo 的主 ...

  5. Kafka 入门和 Spring Boot 集成

    2019独角兽企业重金招聘Python工程师标准>>> Kafka 入门和 Spring Boot 集成 概述 kafka 是一个高性能的消息队列,也是一个分布式流处理平台(这里的流 ...

  6. Spring Boot集成Swagger导入YApi@无界编程

    接口APi开发现状 现在开发接口都要在类似YApi上写文档,这样方便不同的团队之间协作,同步更新接口,提高效率. 但是如果接口很多,你一个个手工在YApi去录入无疑效率很低. 如果是使用Spring ...

  7. Spring Boot集成Hazelcast实现集群与分布式内存缓存

    2019独角兽企业重金招聘Python工程师标准>>> Hazelcast是Hazelcast公司开源的一款分布式内存数据库产品,提供弹性可扩展.高性能的分布式内存计算.并通过提供诸 ...

  8. Spring Boot 集成 Swagger 生成 RESTful API 文档

    原文链接: Spring Boot 集成 Swagger 生成 RESTful API 文档 简介 Swagger 官网是这么描述它的:The Best APIs are Built with Swa ...

  9. Spring Boot集成CKFinder

    2019独角兽企业重金招聘Python工程师标准>>> Spring Boot集成CKFinder,实现浏览功能. 前言 上一篇记录了Spring Boot集成CKEditor,这里 ...

  10. Spring Boot 集成 Druid 监控数据源

    关注"Java后端技术全栈" 回复"面试"获取全套大厂面试资料 Druid 介绍 Druid 是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池.插件框架和 ...

最新文章

  1. Tensorflow函数——tf.variable_scope()
  2. Nginx之简介与安装(一)
  3. js中console在一行内打印字符串和对象
  4. 蚂蚁王旭:开源协作如何提升业界的安全?
  5. psp中java,PSP编程概述
  6. python中的装饰器怎么运行_Python 装饰器入门(上)
  7. 曾365天排队,如今被嫌弃!火了13年的网红鼻祖,要过气了吗?
  8. PHP之安装Pear
  9. rs232 485 ttl区别
  10. 软件开发测试基础知识
  11. A股市股票行情实时数据最简封装API接口的python实现
  12. 如何为YouTube启用暗模式
  13. 蓝桥杯算法训练之印章
  14. 分布式系统限流策略(一)
  15. 淘宝直播医美,颜值经济崛起,如何抢占流量风口
  16. 最新边信息推荐系统综述Research Commentary on Recommendations with Side Information: A Survey and Research Direc
  17. 数据库三范式设计习题
  18. IDA动态调试so 指南
  19. 稿费计算机在线,稿酬个税计算器2017
  20. Linux内存管理第十一章 -- Swap Management

热门文章

  1. Pycharm中文设置教程
  2. 北斗导航 | RAIM:基于速率监测的GNSS/INS完好性监测
  3. ebay html描述模板,ebay产品描述模板
  4. java android开发框架_android开发的三大框架是什么?
  5. Cron 表达式解析,crontab表达式解析
  6. 项目管理(PMP)你要的干货都在这!
  7. 微信 小程序 python 渲染_两小时快速构建微信小程序
  8. mybatis连接oracle
  9. 深度优先搜索 - 最短路径
  10. tftp命令linux,tftp命令使用详解