一、为什么学习
1.1 初衷
1、经过调研很多培训机构大量投入课程的产出,说明在新一代的编程领域有一定的地位,它前程应用一定会有更好的广泛的使用。
2、阿里p3c扫描代码ReView插件底层大量使用了Kotlin进行实际开发
3、经过调研SpringBoot2.以上的全家桶很多组件底层框架和Spring5.x版本用到kotlin支持开发(拥抱Kotlin)。
5、当然了现在学习和了解它,不一定现在就要用它,主要目的是为以后做准备。
6、作为技术人员,希望为kotlin的生态作出一份渺小的贡献。
7、华为鸿蒙操作系统发布会都提到kotlin!
1.2 应用场景
阿里p3c扫描代码ReView插件
p3c
Spring5.x暗示什么呢? Kotlin&Spring5.x
Kotlin&Spring5.x
鸿蒙发布会
鸿蒙发布会
二、技术选型
技术选型
三、kotlin背景简要描述
Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。
立太子:在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言
Kotlin支持表达式语法编程非常友好,以简洁代码等众多方面强大功能,吸引很多开发者的青睐。
官方网站 https://kotlinlang.org/
kotlin手册 https://kotlinlang.org/docs/tutorials/
四、Spring Boot 发展路线简要描述
随着动态语言的流行 (Ruby、Groovy、Scala、Node.js),Java 的开发显得格外的笨重:繁多的配置、低下的开发效率、复杂的部署流程以及第三方技术集成难度大。
在上述环境下,Spring Boot 应运而生。它使用“习惯优于配置”(项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速的运行起来。使用 Spring Boot 很容易创建一个独立运行(运行 Jar,内嵌 Servlet 容器)准生产级别的基于 Spring框架的项目,使用 Spring Boot 你可以不用或者只需很少的 Spring 配置。
4.1 SpringBoot插件使用
spring-boot-starter-actuator actuator是监控系统健康情况的工具spring-boot-devtools 实现热部署,实际开发过程中,修改应用的业务逻辑时常常需要重启应用,这显得非常繁琐,降低了开发效率,所以热部署对于开发来说显得十分必要了spring-boot-starter-aop 此插件没什么好说的了,aop是spring的两大功能模块之一,功能非常强大,为解耦提供了非常优秀的解决方案。如:面向方面编程spring-boot-starter-tomcat spring boot 内置Tomcat插件spring-boot-starter-test 测试工具mybatis-spring-boot-starter spring boot整合MyBatis的jar
spring-boot-maven-plugin Spring Boot Maven plugin能够将Spring Boot应用打包为可执行的jar或war文件,然后以通常的方式运行Spring Boot应用。
五、Kotlin插件
kotlin-stdlib-jdk8 这个是kotlin的标准jar,也就是最基础的一个工程,底层封装了大量kotlin的语法和实现调用逻辑,也是最复杂的一个工程'引入工程会出现这三个jar工程
kotlin-stdlib-jdk8-1.2.20.jar
kotlin-stdlib-1.2.20.jar
kotlin-stdlib-jdk7-1.2.20.jar
kotlin-reflect reflect 顾名思义就是反射工程了
六、jsoup简要
jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。个人认为jsoup是 最好的解析器 ,在很多场景都能见到他的影子,不单只可以解析HTML所有结构,还可以解析XML,在做爬虫器最为广泛。
官方网站 https://jsoup.org/
七、fastJson
阿里JSON解析器,详细文档请看官方 https://github.com/alibaba/fastjson
八、HttpClient
HttpClient 是Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本。
九、Maven
Apache Maven是一个软件项目管理和理解工具。 基于项目对象模型(POM)的概念,Maven可以从中央信息管理项目的构建,报告和文档。https://yq.aliyun.com/articles/28591
十、MyBatis-Plus
为简化开发而生,官方文档 https://mp.baomidou.com/
十一、工程准备
方法一、打开Eclipse Marketplace-->>输入kotlin在线安装即可
kotlin
方法二、下载离线安装包(不提供教程,说明有这种方式)
方法三、可以使用优秀的kotlin编辑器
https://www.jetbrains.com/idea/
十二、工程结构
工程结构
十三、工程代码结构
SpringBoot与Druid配置数据库连接池数据源
@Configuration@MapperScan(basePackages = arrayOf(DataSourceConfig.PACKAGE), sqlSessionFactoryRef = "sessionFactory")open class DataSourceConfig { //半生对象,静态常量 companion object { //const 关键字用来修饰常量,且只能修饰 val,不能修饰var, companion object 的名字可以省略,可以使用 Companion来指代 const val PACKAGE = "com.flong.kotlin.*.mapper"; const val TYPEALIASESPACKAGE = "com.flong.kotlin.modules.entity"; } final var MAPPERLOCATIONS = "classpath*:mapper/*.xml"; @Primary @Bean("dataSource") @ConfigurationProperties(prefix = "spring.datasource") open fun dataSource(): DataSource { return DruidDataSource(); } @Bean open fun transactionManager(@Qualifier("dataSource") dataSource: DataSource): DataSourceTransactionManager { return DataSourceTransactionManager(dataSource); } @Bean open fun sessionFactory(dataSource: DataSource):SqlSessionFactory { //===1.mybatis-plus globalConfig配置 var cfg = GlobalConfiguration(); // 字段的驼峰下划线转换 cfg.setDbColumnUnderline(true); // 全局主键策略 cfg.setIdType(IdType.AUTO.key); // 全局逻辑删除 cfg.sqlInjector = LogicSqlInjector() cfg.logicDeleteValue = "1" cfg.logicNotDeleteValue = "0" //===2.构造sessionFactory(mybatis-plus) var sf = MybatisSqlSessionFactoryBean(); sf.setDataSource(dataSource); sf.setMapperLocations(PathMatchingResourcePatternResolver().getResources(MAPPERLOCATIONS)); sf.setGlobalConfig(cfg); sf.setTypeAliasesPackage(TYPEALIASESPACKAGE) // 分页插件 sf.setPlugins(arrayOf(PaginationInterceptor())) //请注意:这种return sf.getObject();与return sf.`object`写法完全一样,但是object是kotiln的关键字,所以要用 【单引号】引起来 return sf.`object` } /** * @Description 初始化druid * @Author liangjl * @Date 2018年1月17日 下午4:52:05 * @return 参数 * @return ServletRegistrationBean 返回类型 */ @Bean open fun druidServlet() : ServletRegistrationBean<Servlet>{ var bean:ServletRegistrationBean<Servlet> = ServletRegistrationBean(StatViewServlet(), "/druid/*") ; /** 初始化参数配置,initParams**/ //登录查看信息的账号密码. bean.addInitParameter("loginUsername", "root"); bean.addInitParameter("loginPassword", "root"); //IP白名单 (没有配置或者为空,则允许所有访问) bean.addInitParameter("allow", ""); //IP黑名单 (共存时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page. bean.addInitParameter("deny", "192.88.88.88"); //禁用HTML页面上的“Reset All”功能 bean.addInitParameter("resetEnable", "false"); return bean; } @Bean open fun filterRegistrationBean() : FilterRegistrationBean<Filter>{ var filterRegistrationBean = FilterRegistrationBean<Filter>() filterRegistrationBean.setFilter(WebStatFilter()); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"); return filterRegistrationBean; }}
SpringBoot入口类
@EnableAsync@Configuration@EnableScheduling@EnableAutoConfiguration //启用读取配置@ComponentScan("com.flong.kotlin") //扫描com.flong文件目录下//@SpringBootApplication(scanBasePackages = ["com.flong.kotlin"] )// 这种写法也OK@SpringBootApplication(scanBasePackages = arrayOf("com.flong.kotlin"))open class Application {@Beanopen fun jspViewResolver(): InternalResourceViewResolver {var resolver = InternalResourceViewResolver()resolver.setPrefix("/WEB-INF/views/")resolver.setSuffix(".jsp")return resolver}//静态类companion object {/**启动SpringBoot的主入口.*/@JvmStatic fun main(args: Array<String>) {//*args的星号表示引用相同类型的变量SpringApplication.run(Application::class.java, *args)}}}
实体类
@TableName("t_user")data class User constructor(@TableId(value = "user_id", type = IdType.ID_WORKER)var userId: Long?= null,//用户Id主键,IdWork生成var userName: String? = null,//用户名var passWord: String? = null,//密码@TableLogic //mybatisplus的逻辑删除标识//指定表字段进行绑定实体字段属性,is_deleted表示在表实在存在的字段.@TableField(value="is_deleted")//转换成跟数据库表一样的属性字段@field:JSONField(name="isDeleted")var delFlag: String? = null,//删除var createTime: Date? = null //创建时间,允许为空,让数据库自动生成即可 ) :Serializable{ //手动重写toString方法override fun toString(): String {return "[User(userId = $userId,userName = $userName, passWord=$passWord,isDeleted=$delFlag,createTime=$createTime)]"}}
IUserMapper.kt 代码
interface IUserMapper : BaseMapper<User>{//这里的?表示当前是否对象可以为空 @see http://blog.csdn.net/android_gjw/article/details/78436707fun getUserList(query : UserQuery , page : Page<Any>): List<UserRespVo>?}
IUserMapper对应的MyBatis的XMl
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.flong.kotlin.modules.mapper.IUserMapper"> <!-- 抽取公共字段 --> <sql id="find_AS_R"> <![CDATA[ SELECT A.user_Id as userId, A.USER_NAME as userName, A.PASS_WORD as passWord,is_deleted as delFlag, A.create_time as createTime ]]> </sql> <!-- 用户查询 --> <select id="getUserList" resultType="com.flong.kotlin.modules.vo.resp.UserRespVo" > <include refid="find_AS_R" /> FROM T_USER A <where> <if test="userId != null"> and A.user_Id = #{userId}</if> <if test="userName != null and userName !='' ">and A.USER_NAME = #{userName}</if> </where> </select></mapper>
UserService.kt 代码
@Serviceopen class UserService : BaseService<IUserMapper,User,UserQuery>() {//Kotlin lateinit 和 by lazy 的区别//http://blog.csdn.net/Sherlbon/article/details/72769843@Autowired lateinit var userMapper: IUserMapper;//根据open fun queryAllUser(): List<User>? {var wrapper = createWrapper();return this.selectList(wrapper);}open fun listPage(query : UserQuery) : PageVO<UserRespVo> ? {var page = PageUtil().getPage(query) ;// 设置分页var dataList = userMapper.getUserList(query, page!!);//page!!强制告诉编辑器不可能为空var json = JSON.toJSONString(dataList);println(json)return PageVO(dataList, page);// 获取分页数和总条数}open fun getUserId(userId: Long): User? {return get(userId);}//插入用户open fun addUser() {var userId = IdWorker.getId();var u = User(userId, "liangjl", "123456",null, Date());var json = JSON.toJSONString(u);println(json)add(u);}fun createWrapper(): Wrapper<User> {var wrapper = EntityWrapper<User>();wrapper.setEntity(User());//设置实体return wrapper;}}
Controller代码的CRUD的代码实现
Controller@RequestMapping("/rest")open class UserController : BaseController(){ @Autowired private lateinit var userService: UserService @RequestMapping("/list1") fun list1(): String{ return "NewFile" //跳转页面 } //添加 @RequestMapping("/add") fun add(): Unit{ userService.addUser() } //根据用户Id进行删除用户信息 @RequestMapping("/deletedById") fun deletedById(userId : Long): Unit{ userService.deleteById(userId); } //更新用户信息,通过Id唯一主键进行操作。 @RequestMapping("/update") fun update(user : User): Unit{ userService.updateById(user) } //根据Id查询用户 @RequestMapping("/getUserId") fun getUserId(userId :Long):Any?{ var user = userService.getUserId(userId); if(user ==null){ var msgCode = UserMsgCode.FIND_NOT_USER; throw BaseException(msgCode.code!! ,msgCode.message!!) } return userService.getUserId(userId) } //查询所有用户信息 @RequestMapping("/queryAllUser") fun queryAllUser():List<User>?{ return userService.queryAllUser() } //分页查询 @RequestMapping("listPage") fun listPage(query :UserQuery) :PageVO<UserRespVo> ? { var listPage = userService.listPage(query); return listPage; } @RequestMapping("/getBody") fun getBody(@RequestBody jsonText:UserRespVo){ println(jsonText.component2()) println(jsonText.userName) }}
properties数据库配置
logging.evel.root=infologging.evel.com.flong.kotlin=debug# =======mybatis_config===== ## 指定是开发文件spring.profiles.active=dev#=======datasource========#spring.datasource.name=naspring.datasource.url=jdbc:mysql://localhost:3306/kotlin?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTCspring.datasource.username=rootspring.datasource.password=rootspring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.initialSize=5spring.datasource.minIdle=5spring.datasource.maxActive=20spring.datasource.maxWait=60000spring.datasource.timeBetweenEvictionRunsMillis=60000spring.datasource.minEvictableIdleTimeMillis=300000spring.datasource.validationQuery=SELECT 1 FROM DUALspring.datasource.testWhileIdle=truespring.datasource.testOnBorrow=falsespring.datasource.testOnReturn=falsespring.datasource.poolPreparedStatements=truespring.datasource.maxPoolPreparedStatementPerConnectionSize=20#spring.datasource.filters=stat,wall,log4j,slf4j##配置支持【emoji表情】与【不合法输入参数】##作用:用于处理请求与响应一些不可信的字符串spring.datasource.connectionInitSqls=set names utf8mb4spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000spring.devtools.restart.enabled=falsespring.mvc.view.prefix=/WEB-INF/views/spring.mvc.view.suffix=.jsp
数据库脚本(t_user)以用户表为代表
DROP TABLE IF EXISTS `t_user`;CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id', `user_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户Id主键,IdWork生成', `user_name` varchar(255) DEFAULT '' COMMENT '用户名', `pass_word` varchar(255) DEFAULT '' COMMENT '密码', `is_deleted` int(2) unsigned NOT NULL DEFAULT '0' COMMENT '是否删除,0-不删除,1-删除', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`user_id`), UNIQUE KEY `id` (`id`))ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
Jsoup 防止 XSS 攻击工具类
/** * Jsoup 防止 XSS 攻击 工具类 */object Jsoup2XssUtils { /** * 使用自带的 basicWithImages 白名单 * 允许的便签有 a,b,blockquote,br,cite,code,dd,dl,dt,em,i,li,ol,p,pre,q,small,span, * strike,strong,sub,sup,u,ul,img * 以及 a 标签的 href,img 标签的 src,align,alt,height,width,title 属性 */ private val whitelist: Whitelist = Whitelist.basicWithImages() /** * 配置过滤化参数 不对代码进行格式化 */ private val outputSettings: Document.OutputSettings = Document.OutputSettings().prettyPrint(false) init { // 富文本编辑时一些样式是使用style来进行实现的 // 比如红色字体 style="color:red;" // 所以需要给所有标签添加 style 属性 whitelist.addAttributes(":all", "style") } /** * 清除 * @param content 内容 */ fun clean(content: String): String { var contentStr: String = content if (contentStr.isNotBlank()) { contentStr = content.trim { it <= ' ' } } return Jsoup.clean(contentStr, "", whitelist, outputSettings) }}
工程启动类Appalachian.kt与运行结果
// 访问路径 :http://localhost:8080/rest/listPage//访问结果{ "code": "200", "data": { "page": "1", "pageSize": "20", "records": [ { "createTime": "2019-01-04 16:01:34", "passWord": "123456", "userId": "1081098298906394625", "userName": "liangjl" }, { "createTime": "2019-01-04 16:14:50", "passWord": "123456", "userId": "1081101635991232513", "userName": "liangjl" } ], "total": "2", "totalPage": "1" }, "msg": "", "timestamp": "1552964058194"}
十四、为什么记录笔记
1、在平时工作下来,一天认真工作下来,脑子肯定非常很疲倦,故容易导致脑子健忘。也许跟年龄的岁数增大有关系。人精力与体力等各方面都有限的,毕竟人不是机器。
2、常言道:好记性不如烂笔头。切记千万别以自己有点小聪明对自己懒惰。
3、如果经常健忘的时候,不妨借助一些软件工具或者云服务进行帮助存储生活中的痕迹。比如:思维导图( XMind, MindManager,FreeMind )云道笔记等等方式。
十五、总结与推荐学习
15.1 总结
1 、以上问题都是根据自己学习实际情况进行总结整理,除了技术问题查很多网上资料通过进行学习之后梳理。
2、 在学习过程中也遇到很多困难和疑点,如有问题或误点,望各位老司机多多指出或者提出建议。本人会采纳各种好建议和正确方式不断完善现况,人在成长过程中的需要优质的养料。
3、 导入代码的时候遇到最多的问题,我想应该是Maven较多,此时不懂maven的童鞋们可以通过自身情况,进行网上查资料学习。如通过网上找资料长时间解决不了,或者框架有不明白可以通过博客留言,在能力范围内会尽力帮助大家解决问题所在,希望在过程中一起进步,一起成长。
4 、当遇到问题的时候建议多问 『谷歌 、必应、stackoverflow、度娘』 这些大神。
15.2 源代码与其他说明
工程源代码 https://github.com/jilongliang/kotlin
个人简书文章 https://www.jianshu.com/p/0acd593fd11e
用户评论
这个标题听起来像是开发者的专属,有关于技术细节的介绍呢!
有13位网友表示赞同!
用Kotlin写前端感觉效率挺高的,有人试试看吗?
有20位网友表示赞同!
SpringBoot和MyBatisPlus组合确实不错,前后端分离更简洁,支持开发者吧!
有11位网友表示赞同!
搭建框架还能如此高效,看来这款工具很实用啊!
有7位网友表示赞同!
对于刚入门的后端开发来说,这个框架可以帮助快速提升技能。
有15位网友表示赞同!
前后端的逻辑分开确实方便调试和维护,这样代码会更清晰。
有12位网友表示赞同!
MyBatisPlus的查询功能听起来很强,不知道具体操作起来如何?
有14位网友表示赞同!
Kotlin作为静态类型语言,用它写前端感觉效率更上一层楼。
有20位网友表示赞同!
SpringBoot简化了部署流程,节省了很多时间。
有5位网友表示赞同!
分离前后端,数据交互更加直接,开发体验好多了。
有6位网友表示赞同!
这个框架应该很适合需要快速迭代的项目。
有14位网友表示赞同!
喜欢简洁的东西,这样的框架让人感觉很舒服。
有10位网友表示赞同!
如果配合其他模块,这个框架会更加强大。
有8位网友表示赞同!
Kotlin的协程功能在前端应用中可能有大作用。
有5位网友表示赞同!
听说SpringBoot性能很好,结合MyBatisPlus更是如虎添翼。
有13位网友表示赞同!
前后端分离让项目重构起来方便多了。
有19位网友表示赞同!
学了这个框架,开发前端项目更有信心了。
有15位网友表示赞同!
这个框架的文档应该会很有帮助吧?
有20位网友表示赞同!
如果还有社区支持,那简直就是完美了!
有9位网友表示赞同!
这样的框架应该能提升团队的开发效率。
有11位网友表示赞同!