直接上手SpringBoot创建Web项目
  Bp84FnUMsDVM 2023年11月02日 47 0

SpringBoot

SpringBoot声称可以很简单地创建独立的生产级的直接运行的Spring应用,那我们就来手撕一个试试。

创建项目

打开IntelliJ IDEA,新建项目:Spring Initializr。

配置: Name: InitProj Language: Kotlin Type: Gradle Sdk: jbr-11 Java: 11 SpringBoot: 2.7.3 Dependences: Web>SpringWeb

​start.spring.io​​ 打不开?你可能需要一点上网技术。

配置阿里云仓库

如果你想依赖包下载快一点,建议配置阿里云仓库。 打开 build.gradle.kts 在 repositories 中添加两具仓库:

maven {
setUrl("https://maven.aliyun.com/repository/public/")
}
maven {
setUrl("https://maven.aliyun.com/repository/spring/")
}

HelloWord

创建Kolin类HelloController

@RestController
class HelloController {
@GetMapping("/hello")
fun hello(): String{
return "hello"
}
}

运行启动项目 浏览器输入 ​​http://localhost:8080/hello​​ Ok,小试水果刀,前菜结束。

响应数据结构化

新需求:返回数据是这样 json

{"code":0,"message":"success","data":"hello"}

我们需要: 一个定义错误信息的 Data Class

data class AError(val code: Int, val msg: String)

一些常见的错误信息

inline val SUCCESS
get() = AError(0, "success")
inline val ERROR_UNKNOWN
get() = AError(-1, "unknown")
inline val PARAMS_NULL
get() = AError(-2, "缺少必填参数")
inline val SESSION_ERROR
get() = AError(-3, "session失效")

一个存储响应结果的 Data Class

data class Result(
var code: Int = 0,
var message: String = "",
var data: Any? = null
)

一些常见的结果

fun succeed(data: Any?) = Result(SUCCESS.code, SUCCESS.msg, data)
fun succeed() = succeed(null)
fun failed(err: AError) = Result(err.code, err.msg, null)

然后修改一下 hello 处理函数

@GetMapping("/hello")
fun hello(): Result{
return succeed("hello")
}

再次运行一下,结果是我们想要的。SpringBoot 帮我们做了比较多的处理,这里不作细论。

异常处理

如果程序发生错误,前端会得到这样的结果:

{
"timestamp": "2022-08-26T14:34:48.440+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/hello"
}

我们希望得到这样的结果:

{"code":-1,"message":"unknown","data":null}

前端的格式比较统一,方便处理。 首先自定义一个异常

class MyException(val err: AError) : RuntimeException(err.msg)

然后添加一个异常处理组件,SpringBoot 会在异常发生时调用它来处理。

@ControllerAdvice
class ExceptionHandler {

companion object {
private const val TAG = "ExceptionHandler"
}

@ExceptionHandler(Exception::class)
@ResponseBody
fun handle(e: Exception): Result {
val result = if (e is MyException) {
failed(e.err)
} else {
failed(ERROR_UNKNOWN)
}
Log.e(TAG, e)
return result
}

}

这样如果发生我们定义的错误,会返回对应信息;其他错误则返回未知。 测试一下Hello:

@GetMapping("/hello")
fun hello(): Int{
// return 2/0
return failed(PARAMS_NULL)
}

结果是我们想要的。

参数校验

请求参数需要先过滤一遍,防止引入未知错误。 虽然 Spring 有@Valid 注解可以很方便地验证请求参数的合法性,但是我更倾向于自定义验证内容。 首先定义一个抽象类 ARequest,作为所有请求参数的父类。

abstract class ARequest {
// 验证参数
abstract fun validate()

// 检验参数是否为空
fun paramsNotBlank(vararg params: String){
params.forEach {
if(it.isBlank()){
throw MyException(PARAMS_NULL)
}
}
}
}

然后定义一个切面,在特定函数执行前进行参数校验。

@Aspect
@Component
class RequestAspect {

companion object{
private const val TAG = "RequestAspect"
}

@Pointcut("execution(public * *(ARequest+,..))")
fun point(){}

@Before("point()")
fun checkRequest(join: JoinPoint){
join.args.forEach {
if(it is ARequest){
it.validate()
}
}
}

}

面向切面编程需要引入依赖 implementation("org.springframework.boot:spring-boot-starter-aop:2.7.3")

切点"execution(public * *(ARequest+,..))"的意思是:在任何类型为public,第一个参数是ARequest的子类的函数处作切点。

本例中如果需要指定打招呼的人名,可以这样定义请求参数:

data class HelloRequest(
var name: String = "",
): ARequest(){
override fun validate() {
paramsNotBlank(name)
}
}

修改 Hello 函数:

@GetMapping("/hello")
fun hello(request: HelloRequest): Result{
return succeed("Hello ${request.name}")
}

不指定name参数时,返回:

{"code":-2,"message":"缺少必填参数","data":null}

指定name 为 Tom , 返回:

{"code":0,"message":"success","data":"Hello Tom"}

总结

SpringBoot 为我们做了相当多的配置工作,使用起来很便捷。本篇文章没有原理解释,更像一道练习题,用来熟悉 SpringBoot 的起手式,更多细节以后探讨。

源码:​​https://gitee.com/yoshii_x/init-proj.git​

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

Bp84FnUMsDVM