8.3 Spring Boot集成Scala混合Java开发
2017-09-13 14:29
381 查看
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.Driver spring.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.entity import 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) @BeanProperty var id: Integer = _ @BeanProperty var url: String = _ @BeanProperty var name: String = _ //用例状态: -1未执行 0失败 1成功 @BeanProperty var state: Integer = _ @BeanProperty var owner: String = _ @BeanProperty var resultJson: String = _ @BeanProperty var executeTimes: Integer = _ @BeanProperty var executor: Integer = _ @BeanProperty var gmtCreate: Date = _ @BeanProperty var 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.dao import java.util.List import com.light.sword.ylazy.entity.LazyTask import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.CrudRepository // JavaConversions import scala.language.implicitConversions trait LazyTaskDao extends CrudRepository[LazyTask, Integer] { def findAll(): List[LazyTask] def save(t: LazyTask): LazyTask def 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.controller import java.util.Date import 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)) @ResponseBody def newTask(@ModelAttribute lazyTask: LazyTask) = { lazyTask.gmtCreate = new Date lazyTask.gmtModify = new Date lazyTask.executeTimes = 0 lazyTask.state = -1 lazyTaskDao.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)) @ResponseBody def findOne(@RequestParam(value = "id") id: Integer) = lazyTaskDao.findOne(id) /** * 获取一条任务记录的返回json * * @param id * @return */ @RequestMapping(value = { Array("/result/{id}") }, method = Array(RequestMethod.GET)) @ResponseBody def findResultJson(@PathVariable(value = "id") id: Integer) = lazyTaskDao.findOne(id).resultJson /** * 执行任务 * @param id * @return */ @RequestMapping(value = { Array("/ylazy/runTask") }, method = Array(RequestMethod.GET)) @ResponseBody def runTask(@RequestParam(value = "id") id: Integer) = { phantomjsExecutor.ylazyById(id) } @RequestMapping(value = { Array("/ylazy") }, method = Array(RequestMethod.GET)) @ResponseBody def 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(); } }] }); } } }); }); //任务列表datatables var 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相关文章推荐
- 《Spring Boot极简教程》第9章 Spring Boot集成Scala混合Java开发
- 8.1 Spring Boot集成Groovy混合Java开发
- IntelliJ IDEA开发Scala代码,与java集成,maven打包编译
- Kotlin集成 SpringBoot 混合Java库开发
- Scala java maven 混合开发 pom配置
- 《Spring Boot极简教程》第8_章: Spring Boot集成Groovy混合Java开发
- maven环境下使用java、scala混合开发spark应用
- Scala java maven 混合开发 pom配置
- flex与java集成开发(基于eclipse)
- PHP和Java 集成开发详解分析 强强联合第1/4页
- java集成开发工具Eclipse与netbeans比较
- 基于SOA的java语言开发环境-交付前持续集成
- JAVA集成开发工具之MyEclipse
- flex与java集成开发(基于eclipse)
- (转载)面向 Java 开发人员的 Scala 指南: 类操作
- PHP和Java强强联合 PHP与Java集成开发详解
- Eclipse安装CXF插件开发java web service 集成Spring
- PHP和Java 集成开发详解分析 强强联合第1/4页
- 面向 Java 开发人员的 Scala 指南:包和访问修饰符
- flex与java集成开发(基于eclipse)