零、版本说明:
springboot: 2.7.18
使用log4j2,不使用springboot自带的logback
scala版本:2.11
jackson版本:2.16.0
一、依赖:
buildscript {
dependencies {
// using spring-boot-maven-plugin as package tool
classpath("org.springframework.boot:spring-boot-maven-plugin:2.7.18")
}
}
plugins {
id 'idea'
id 'scala'
id 'org.springframework.boot' version '2.7.18'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}
// 指定java版本
sourceCompatibility = 1.8
targetCompatibility = 1.8
// 尽量使用2.16.0版本的jackson对scala支持更好。
ext {
jackson_version = '2.16.0'
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web") {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
implementation("org.springframework.boot:spring-boot-starter-log4j2")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude group: 'org.junit.jupiter'
}
testImplementation 'io.projectreactor:reactor-test:3.4.29'
implementation("com.fasterxml.jackson.core:jackson-core:${jackson_version}")
implementation("com.fasterxml.jackson.core:jackson-annotations:${jackson_version}")
implementation("com.fasterxml.jackson.core:jackson-databind:${jackson_version}")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson_version}")
implementation("com.fasterxml.jackson.module:jackson-module-scala_2.11:${jackson_version}")
testImplementation "com.fasterxml.jackson.core:jackson-core:${jackson_version}"
testImplementation("com.fasterxml.jackson.core:jackson-annotations:${jackson_version}")
testImplementation("com.fasterxml.jackson.core:jackson-databind:${jackson_version}")
testImplementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson_version}")
testImplementation("com.fasterxml.jackson.module:jackson-module-scala_2.11:${jackson_version}")
}
configurations {
all*.exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
主启动类
此处也可以继承scala的App
但需要注意要重新App
中的main方法。
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.{ SpringBootApplication}
@SpringBootApplication
class AppServe
object AppServer {
private val log = org.slf4j.LoggerFactory.getLogger(classOf[AppServer])
def main(args: Array[String]): Unit = {
log.info(s"${getClass.getName} get args: ${args.toList.toString()}")
SpringApplication.run(classOf[AppServer], args: _*)
}
}
scala常用获取jackson objectMapper参考:
// scala
def getMapper: ObjectMapper = {
var mapper: ObjectMapper = JsonMapper.builder()
.addModule(DefaultScalaModule)
.build() :: ClassTagExtensions
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
mapper
springboot序列化使用的是jackson,而自带的jackson版本较低,且不支持scala。
import com.fasterxml.jackson.databind.Module
import com.fasterxml.jackson.module.scala.{ClassTagExtensions, DefaultScalaModule}
import org.springframework.context.annotation.{Bean, Configuration}
import lombok.extern.slf4j.Slf4j
/**
* https://blog.csdn.net/beibaozhou1656/article/details/100966023
*/
@Configuration
class JacksonConfiguration {
@Bean
def defaultScalaModule(): Module = {
// 暂没有办法加:ClassTagExtensions
DefaultScalaModule
}
}
controller类
注意:@Resource()
(@Autowire
)使用方法。
import org.springframework.web.bind.annotation.{PostMapping, PutMapping, RequestBody, RequestMapping, RestController}
import lombok.extern.slf4j.Slf4j
@RestController
@RequestMapping(Array("/v1"))
class BatchController @Resource()(batchService: BatchSaveService) {
@PostMapping(Array("/batch/save"))
def batchSave(@RequestBody tbls: java.util.List[Element]): Unit = {
batchService.batch(tbls.asScala)
}
}
配置文件值获取
application.properties,application.yml,application.yaml文件
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import javax.annotation.PostConstruct
@Component
class EnvConfiguration() {
// 注意:要去除value=s"${}"的`s`。
@Value(value = "${udf.kafka.consumer.krb5-conf}") var krb5Conf: String = _
@Value(value = "${udf.kafka.topic}") var topic: String = _
@PostConstruct
def init(): Unit = {
// 使用在post construct之后可以使用krb5Conf变量
System.setProperty( ... )
}
def getTopic():String={
topic
}
}
import lombok.extern.slf4j.Slf4j
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.springframework.kafka.annotation.KafkaListener
import org.springframework.stereotype.{Component}
import javax.annotation.Resource
/**
* kerberos整合kafka、springboot
* https://blog.csdn.net/weixin_40496191/article/details/124056953
* SpringBoot集成Kafka详解
* https://blog.csdn.net/qq_20865839/article/details/13394898
*/
@Component
class KafkaTableService @Resource()(service: CommonServiceImpl) extends Logging {
val mapper = JsonUtils.getMapper
// 可以使用#{}在注解中使用被@Component的的方法。
@KafkaListener(topics = Array("#{EnvConfiguration.getTopic()}"))
def onMessage(record: ConsumerRecord[String, String]) = {
// do nothing
}
}
注意:
1、springboot打包必须使用spring-boot-maven-plugin
,不能使用gradle的shadowJar
(com.github.johnrengelman.shadow
)
正确的jar应如下目录结构:
2、idea中debug
将所有application.yml等配置文件放在test/resources目录下,可以避免jar中含有配置文件,但测试时候会发现找不到配置文件。如果此时在点击object前的run或者debug,不是以test
方式run的不会触发gradle的test
,不会有如下test目录和不会触发gradle resource copy任务,当然即使触发了也没用,因为此处我们直接run main方法,不是test任务,classpath不会包含build/resources/test
目录,只会包含build/resources/main
。
解决办法:
在idea启动参数添加如下,注意下resources/
以结尾,/
告知spring此路径是个目录,不是文件。
另使用--spring.config.additional-location=
也是可以的。
--spring.config.location=D:/projects/my-project/my-moudel/src/test/resources/
从而实现打包没有配置文件,但run springboot可以加载到test/resources配置文件。
3、无需设置main-class,springboot的插件设置。
4、生产环境启动 nohub java -jar xxx.jar 2>&1 &
5、jackson版本最好高于2.16.0
jackson-module-scala 官方文档:
6、java语言动态参数如下,入参使用可以直接使用sum(1)
,即一个参数也可以使用。
但scala是不行的。需要明确指定类型是Array
如下:
7、@Slf4j
注解无法使用,此注解应该被idea lombok插件并在编译添加如下添加代码:
解决很简单,手动添加如下代码即可:
import org.slf4j.Logger
// class 适用
val LOG: Logger = org.slf4j.LoggerFactory.getLogger(this.getClass)
// object 适用
val LOG: Logger = org.slf4j.LoggerFactory.getLogger(classOf[类名称])
8、
参考文章:
Spring Boot 实践折腾记
Scala篇:整合springboot