《Spring Boot极简教程》第9章 Spring Boot集成Scala混合Java开发
第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开发相关推荐
- 《React极简教程》第一章 Hello,World!
react React 是一个用于构建用户界面的 JAVASCRIPT 库. React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图). React 起源于 Facebook ...
- 《Spring Boot极简教程》第8章 Spring Boot集成Groovy,Grails开发
第8章 Spring Boot集成Groovy,Grails开发 本章介绍Spring Boot集成Groovy,Grails开发.我们将开发一个极简版的pms(项目管理系统). Groovy和Gra ...
- 《MongoDB极简教程》第一章 NoSQL简史 amp; MongoDB安装amp;环境配置
MongoDB 是一款开源的文档数据库,并且是业内领先的 NoSQL 数据库,用 C++ 编写而成. NoSQL (NoSQL = Not Only SQL ),意即"不仅仅是SQL&quo ...
- 《MongoDB极简教程》第一章 NoSQL简史 MongoDB安装环境配置
MongoDB 是一款开源的文档数据库,并且是业内领先的 NoSQL 数据库,用 C++ 编写而成. NoSQL (NoSQL = Not Only SQL ),意即"不仅仅是SQL&quo ...
- 《Spring Boot极简教程》附录3 编程简史
附录3 编程简史 1940之前 提花织布机 1801,Joseph Marie Jacquard用打孔卡为一台织布机编写指令,在提花织布机(或称甲卡提花织布机,Jacquard loom)上,运用打孔 ...
- 《Spring Boot极简教程》附录4 Java编程简史
附录4 Java编程简史 从GOTO到OOP 在20世纪60年代,软件曾出现过严重危机,由软件错误而引起的信息丢失.系统报废事件屡有发生.为此,1968年,荷兰E.W.Dijkstra提出了程序设计中 ...
- LLVM极简教程: 第三章 LLVM IR代码生成
第三章 LLVM IR代码生成 原文: Code generation to LLVM IR 本章简介 欢迎进入"用LLVM开发新语言"教程的第三章.本章将介绍如何把第二章中构造的 ...
- 【抽象代数】第一章 代数系统《抽象代数极简教程》/ By 禅与计算机程序设计艺术ChatGPT
<抽象代数极简教程> 文章目录 <抽象代数极简教程> 第一章 代数系统 1.1 集合的基本概念 1.2 二元运算 1.3 代数系统的定义 什么是代数? 抽象代数和初等代数有什么 ...
- 《Kotin 极简教程》第13章 使用 Kotlin 和 Anko 的Android 开发
第13章 使用 Kotlin 和 Anko 的Android 开发 最新上架!!!< Kotlin极简教程> 陈光剑 (机械工业出版社) 可直接打开京东,淘宝,当当===> 搜索: ...
- 《Kotin 极简教程》第14章 使用 Kotlin DSL
第14章 使用 Kotlin DSL 最新上架!!!< Kotlin极简教程> 陈光剑 (机械工业出版社) 可直接打开京东,淘宝,当当===> 搜索: Kotlin 极简教程 htt ...
最新文章
- python除号的乘法加括号_乘除法添加括号规则
- 2_1 AdpterMode.cpp 适配器模式
- mysql创建定时器(event),查看定时器,打开定时器,设置定时器时间
- 尬出天际!和导师微信聊天大型翻车现场!
- 2048java课程设计报告_2048小游戏-Java-课程设计报告书
- Mr.J-- jQuery学习笔记(七)--CSS类操作文本值操作
- JAVA开发血泪之路:一步步搭建spring框架
- 后台代码之买票和查找核实航班的代码
- SpringBoot 下 Mybatis 的缓存
- Python 数据分析 —— Matplotlib ①
- 在安装软件CAJViewer时出现,“错误1327。无效驱动器:F:
- 使用Python实现一个简单的聊天室
- SEUS 转换XML到JAVA
- 站内信系统数据库设计
- 虎跃后台管理系统,数据分发+授权管理+权限管理
- Conflux CTO 伍鸣博士出席 2019 CAN 大会
- 【Unity3D】学习笔记(第2记) 2D游戏开发基本技巧之背景制作
- 《软件体系结构》知识点整理
- 深度学习入门笔记(九):深度学习数据处理
- 网易云课堂Java进阶学习笔记系列03 -- 第7周 抽象与接口