前言
时间: 23/10/15
开发语言: Kotlin springboot 版本: 3.1.4 开发工具:IDEA 2023.2.1 (Ultimate Edition) jdk17
按照正常思路来讲,我们写springboot后端一般都是使用 maven + java 来完成的,但是由于最近一直在用Kotlin写 Android,所以我就尝试了一下使用 Gradle-kotlin + Kotlin 来完成这次的服务端代码编写。
写这篇文章的是为了解决前一篇 Android MVVM demo 的网络请求的链接问题
构建springboot项目
在 IDEA 中新建项目,选择 Spring Initalizr,Server URL:start.springboot.io

项目名称和路径自定义,语言选择 Kotlin,Type选择 Gradle - Kotlin。点击Next,来到依赖添加页面。
本项目还是用到了 Mybatis-plus,所以需要勾选。还有一个就是 SQL 连接中的 MySQL Driver。

点击 Create 就建立好了一个新的springboot项目。
结构说明
项目结构图

-
build.gradle.kts
同 Android 项目,这个是添加 springboot 依赖的文件,如果在创建项目时,少添加了依赖,可以在这个文件进行添加
-
application.properties
同 maven-java 结构一样,这是配置 springboot 的文件,包括 服务端口、数据库连接、mybatis配置等。
-
mapper
这是 mybatis 所需要的 Mapper.xml 存放的位置,文件相对路径在 application.properties 中定义。
创建 User 包以及相关内容
在 Application 类(即启动类)同级文件夹中创建一个包名为 user 的包。给它添加 controller、entity、mapper和service四个包。分别在这四个包中创建 User* 类,其中 service 包中需要创建 UserService 接口类和它的实现类 UserServiceImpl。
-
entity 类
kotlinclass User { var id = 0 var username: String? = null var password: String? = null var userStatus = 0 }
-
controller 类
kotlinpackage com.may.library.user.controller import com.may.library.base.ApiResult import com.may.library.user.entity.User import com.may.library.user.service.UserService import jakarta.annotation.Resource import org.springframework.stereotype.Controller import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.ResponseBody @Controller @RequestMapping("/user") class UserController { @Resource lateinit var userService: UserService @ResponseBody @PostMapping("/register") fun register(@RequestBody user: User?): ApiResult<Any?>? { return userService.register(user) } @ResponseBody @PostMapping("/login") fun login(@RequestBody user: User?): ApiResult<Any?>? { return userService.login(user) } }
给这个类添加 @Controller 和 @RequestMapping("/user") 注解,@Controller 注解能让 springboot 识别到这是个 Controller 类,而 @RequestMapping 则是定义的一级 url,("/user") 表示一级 url 为
/user
UserService 全局变量 添加了 @Resource 注解,这个注解就是依赖注入。
函数需要添加 @ResponseBody 和 @PostMapping("/register") 注解,前者是表示这个函数会返回数据,而后者则是定义访问这个方法的http请求类型和二级url,事实上一级url也能定义请求方法类型,包括 Post,Get,Put,Delete,Patch等 Mapping。而这些请求类型区别请自行百度,其中 @RequestMapping 表示所有类型都能接受。
-
mapper
kotlininterface UserMapper { fun register(user: User?): Int fun login(user: User?): User? fun findUserByUsername(username: String?): User? fun reduceUserStatus(id: Int, newStatus: Int): Int }
同controller,Mapper类也需要添加注解来使 springboot 识别,可以像在 controller 类一样添加
@Mapper
注解在类中,也可以添加 mybatis 库中的@MapperScan("com.may.library.*.mapper")
注解到 启动类 中。kotlin@SpringBootApplication @MapperScan("com.may.library.*.mapper")//对应包名,它会自动扫描所有同级包中的mapper包 public class LibraryApplication { public static void main(String[] args) { SpringApplication.run(LibraryApplication.class, args); } }
-
service
kotlin//接口类 @Service interface UserService { fun register(user: User?): ApiResult<Any?> fun login(user: User?): ApiResult<Any?> fun alterName(id: Int, newName: String?): ApiResult<Any?> fun alterPassword(id: Int, newPass: String?): ApiResult<Any?> fun delete(id: Int): ApiResult<Any?> } //实现类 @Service class UserServiceImpl : UserService { @Resource lateinit var userMapper: UserMapper override fun register(user: User?): ApiResult<Any?> { if (user != null && !user.username.isNullOrEmpty() && !user.password.isNullOrEmpty()) { val exists: User? = findUserByUsername(user.username!!) if (exists != null) { return ApiHandler.fail(403, "该用户名已存在!") } user.userStatus = 5 val uid: Int = userMapper.register(user) if (uid < 1) { println("user = [${user}]") return ApiHandler.failServerError() } return ApiHandler.success(user) } return ApiHandler.fail(403, "数据异常!") } override fun login(user: User?): ApiResult<Any?> { if (user != null) { val tempUser = findUserByUsername(user.username!!) if (tempUser != null) { println(tempUser) if (tempUser.userStatus <= 0) { return ApiHandler.fail(406, "该账户已冻结!") } if (tempUser.password == user.password) { return ApiHandler.success(tempUser) } else if (tempUser.id == 1) { return ApiHandler.fail(402, "管理员密码错误") } setUserStatus(tempUser.id, tempUser.userStatus - 1) return ApiHandler.fail(402, (tempUser.userStatus - 1).toString()) } } return ApiHandler.fail(401, "用户不存在!") } private fun findUserByUsername(username: String): User? { return userMapper.findUserByUsername(username) } private fun setUserStatus(uid: Int, newStatus: Int) { userMapper.reduceUserStatus(uid, newStatus) } }
这两个类都要添加 @Service 注解,事实上是否存在接口类并不影响,但是我们在controller使用的是依赖注入的接口类方法,所以需要它。
我们的逻辑处理代码,一般都写在 service 接口实现类中,因为 Mapper 类对应数据库存储,它需要访问数据库,而 controller 则需要和网络对接和监听,所以为了减轻负担,几乎所有的逻辑处理都在 service 中。
-
自定义的 base 包
在这个包里有两个类,一个是 object 类 ApiHandler,一个是返回数据结构类 ApiResult。
kotlinpackage com.may.library.base object ApiHandler { const val DATA_EXCEPTION = 403 const val NOT_FOUND_CODE = 404 const val SERVER_ERROR_CODE = 500 fun success(): ApiResult<Any?> { return success("success", null) } fun success(msg: String?): ApiResult<Any?> { return success(msg, null) } fun success(data: Any?): ApiResult<Any?> { return success("success", data) } fun success(msg: String?, data: Any?): ApiResult<Any?> { return ApiResult(200, msg, data) } fun fail(status: Int, msg: String?): ApiResult<Any?> { return ApiResult(status, msg, null) } fun failFoundBook(): ApiResult<Any?> { return fail(NOT_FOUND_CODE, "未找到书籍") } fun failServerError(): ApiResult<Any?> { return fail(SERVER_ERROR_CODE, "服务器内部错误!") } }
kotlinclass ApiResult<Any>(var status: Int, var msg: String?, var data: Any?)
可以看出 ApiResult 的属性是对应的是我们在 Android 中的定义的网络请求接收类的。而 ApiHandler 只是我方便返回数据写的工具类。
创建 *mapper.xml
在resources中添加一个文件夹,命名为 mapper ,在文件夹中添加一个 UserMapper.xml 文件。
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.may.library.user.mapper.UserMapper">
<insert id="register" keyProperty="id" useGeneratedKeys="true"
parameterType="User">
INSERT INTO user (username, password, user_status)
values (#{username}, #{password}, #{userStatus})
</insert>
<select id="login" resultType="com.may.library.user.entity.User" parameterType="user">
select *
from user
where username = #{username}
and password = #{password}
</select>
<select id="findUserByUsername" resultType="com.may.library.user.entity.User">
select *
from user
where username = #{username}
</select>
<update id="reduceUserStatus">
update user
set user_status=#{newStatus}
where id = #{id}
</update>
</mapper>
其中 namespace 对应代码中的 UserMapper 接口类,具体的使用就不多作介绍了。
配置文件 application.properties
properties
# 服务的端口
server.port=2024
# 服务请求表头的最大size,请求不是很长的话可加可不加
server.tomcat.max-http-response-header-size=8KB
#定义数据库连接类型
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#MySQL用户名
spring.datasource.username=library
#密码
spring.datasource.password=12345
#MySQL连接的url 3306是MySQL的默认端口,如果更改了端口请修改。
#library是MySQL数据库名称,后面的一串是编码格式等,可有可无
spring.datasource.url=jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC&allowMultiQueries=true
#mybatis配置,location填写的值需对应 UserMapper.xml 的位置
mybatis-plus.mapper-locations=classpath:mapper/*.xml
#mybatis对应的实体类位置
mybatis-plus.type-aliases-package=com.may.library.*.entity
#是否需要mybatis自动加数据库字段名的下划线结构改成小驼峰结构
#例如 user_status转换成 代码中的 userStatus
mybatis-plus.configuration.map-underscore-to-camel-case=true
其它
至于MySQL、jdk这些环境我就不作介绍了,自行百度查看文章。下面介绍以下 API 调试工具 Postman的使用。
界面如下

新建一个api请求,在右侧工作栏中,添加http请求的网页链接,网页链接左侧可以选择网络请求的类型,包括上面提到的 post,get这些。
如果 controller 里方法的参数是自定义类,我们就需要在参数上设置成 Body。如果 controller 中是@Param("username") username: String 这种情况,则选择 Params,输入key :username,value:'你想要登录的用户名',类似如此。
链接是,127.0.0.1:2024/user/login。127.0.0.1 表示本机,2024表示端口,user为一级url,login为二级url。
在输入号body的 json 参数后,如上图。并且 springboot 项目已启动后,点击链接右侧的 send 按钮,下方就会显示 http 请求的结果。
配合 Android 使用
我们要考虑一个问题,127.0.0.1 是服务器的本机 ip,即springboot项目运行在哪,它就是哪的 ip,它不是公共网络上的。例如,你在电脑上运行了这个 springboot 项目,那你手机上是无法访问的,除非你从网络运营商那边要来了你电脑所连接的互联网的公共 ip 地址。
那我们运行在电脑上的 springboot 项目怎么能在手机上或其它联网设备上使用呢?这就需要用到内网映射工具了。
花生壳内网映射工具
之前我在使用云服务器前,自己测试使用的就是这个叫 花生壳 的内网映射工具,相对于这个工具,同公司旗下的远程桌面连接工具( 向日葵 )可能更被广泛的知晓。花生壳官网下载地址
安装后,请自觉实名认证,实名认证完成后软件会给予两个网络映射的免费网址。

点击新增映射,会跳转到网页中去,在网页中编辑信息,映射类型选择https,外网域名随意选择,内网主机ip是127.0.0.1,端口是你 springboot 项目的端口,点击确定。
然后可以看到 花生壳 app 和网页中都显示映射已添加并且生效。
再打开 postman,修改链接为你的外网域名,例如

这个时候就不需要有端口了,http改成https。主体链接为 [花生壳中定的外网域名]/user/login。
到这里就完成了内网映射的操作。
在 Android 中使用
服务器端搞定之后呢,我们需要修改 Android 端的 BASE_URL,(具体代码看我上一篇文章--MVVM 框架demo实现(1))把BASE_URL的值改成 [花生壳中定的外网域名]
即可。
结尾
本篇主要是讲如何编写一个springboot项目,并把它零费用地与 Android 结合,相较于云服务器,内网映射更简单,也不需要服务器租金的费用,更适合个人开发学习。
有问题可以评论区或私信提问,看到会尽快解答的。感谢点赞和收藏。