前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >第13章 Kotlin 集成 SpringBoot 服务端开发(2)

第13章 Kotlin 集成 SpringBoot 服务端开发(2)

作者头像
一个会写诗的程序员
发布于 2018-08-17 06:19:49
发布于 2018-08-17 06:19:49
58200
代码可运行
举报
运行总次数:0
代码可运行

13.2.10 搜索关键字管理

本节我们开发爬虫爬取的关键字管理的功能。

数据库实体类

首先,新建实体类SearchKeyWord 如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.easy.kotlin.picturecrawler.entity

import java.util.*
import javax.persistence.*


@Entity
@Table(indexes = arrayOf(Index(name = "idx_key_word", columnList = "keyWord", unique = true)))
class SearchKeyWord {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = -1
    @Column(name = "keyWord", length = 50, nullable = false, unique = true)
    var keyWord: String = ""
    @Column(nullable = true)
    var totalImage: Int? = 0
    var gmtCreated: Date = Date()
    var gmtModified: Date = Date()
    var isDeleted: Int = 0  //1 Yes 0 No
    var deletedDate: Date = Date()
}

其中,keyWord 是搜索关键字,有唯一性约束,同时我们给它建立了索引。

dao 层接口

我们来实现插入数据的 dao 层接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Modifying
    @Transactional
    @Query(value = "INSERT INTO `search_key_word` (`deleted_date`, `gmt_created`, `gmt_modified`, `is_deleted`, `key_word`) VALUES (now(), now(), now(), '0', :keyWord) ON DUPLICATE KEY UPDATE `gmt_modified` = now()", nativeQuery = true)
    fun saveOnNoDuplicateKey(@Param("keyWord") keyWord: String): Int

其中,ON DUPLICATE KEY UPDATE 这句表明当遇到重复的键值的时候,执行更新 gmt_modified = now() 的操作。这里nativeQuery = true ,表示使用的是原生 SQL 查询。

系统启动初始化动作

我们在应用启动类PictureCrawlerApplication 中添加初始化动作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.easy.kotlin.picturecrawler

import com.easy.kotlin.picturecrawler.dao.SearchKeyWordRepository
import com.easy.kotlin.picturecrawler.entity.SearchKeyWord
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.stereotype.Component
import java.io.File


@SpringBootApplication
@EnableScheduling
class PictureCrawlerApplication

fun main(args: Array<String>) {
    SpringApplication.run(PictureCrawlerApplication::class.java, *args)
}


@Component
@Order(value = Ordered.LOWEST_PRECEDENCE)
class initSearchKeyWordRunner : CommandLineRunner {
    @Autowired lateinit var searchKeyWordRepository: SearchKeyWordRepository

    override fun run(vararg args: String) {
        var keyWords = File("搜索关键词列表.data").readLines()
        keyWords.forEach {
            val SearchKeyWord = SearchKeyWord()
            SearchKeyWord.keyWord = it
            searchKeyWordRepository.saveOnNoDuplicateKey(it)
        }
    }
}

Spring Boot应用程序在启动后会去遍历 CommandLineRunner 接口的实例并运行它们的run方法。使用@Order注解来指定 CommandLineRunner 实例的运行顺序。

搜索查询接口

查询所有关键字记录接口如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Query("SELECT a from #{#entityName} a where a.isDeleted=0 order by a.id desc")
override fun findAll(pageable: Pageable): Page<SearchKeyWord>

模糊搜索关键字接口如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Query("SELECT a from #{#entityName} a where a.isDeleted=0 and a.keyWord like %:searchText% order by a.id desc")
fun search(@Param("searchText") searchText: String, pageable: Pageable): Page<SearchKeyWord>
模糊搜索 http 接口实现

跟搜索图片分类的逻辑类似,模糊搜索关键字的接口如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @RequestMapping(value = "searchKeyWordJson", method = arrayOf(RequestMethod.GET))
    @ResponseBody
    fun sotuSearchJson(@RequestParam(value = "page", defaultValue = "0") page: Int, @RequestParam(value = "size", defaultValue = "10") size: Int, @RequestParam(value = "searchText", defaultValue = "") searchText: String): Page<SearchKeyWord> {
        return getPageResult(page, size, searchText)
    }

    private fun getPageResult(page: Int, size: Int, searchText: String): Page<SearchKeyWord> {
        val sort = Sort(Sort.Direction.DESC, "id")
        // 注意:PageRequest.of(page,size,sort) page 默认是从0开始
        val pageable = PageRequest.of(page, size, sort)
        if (searchText == "") {
            return searchKeyWordRepository.findAll(pageable)
        } else {
            return searchKeyWordRepository.search(searchText, pageable)
        }
    }
前端列表页面代码

search_keyword_view.ftl 模板页面代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<#include 'common/head.ftl'>
<#include 'common/nav.ftl'>

<form id="add_key_word_form">
    <div class="col-lg-3">
        <div class="input-group">
            <input name="keyWord"
                   id="add_key_word_form_keyWord"
                   type="text"
                   class="form-control"
                   placeholder="输入爬虫抓取关键字">
            <span class="input-group-btn">
                        <button id="add_key_word_form_save_button"
                                class="btn btn-default"
                                type="button">
                             保存
                        </button>
            </span>
        </div><!-- /input-group -->
    </div><!-- /.col-lg-3 -->
</form>
<table id="search_keyword_table"></table>
<#include 'common/foot.ftl'>
<script src="search_keyword_table.js"></script>

search_keyword_table.js 代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$(function () {
    $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['zh-CN'])
    var searchText = $('.search').find('input').val()

    var columns = []

    columns.push(
        {
            title: 'ID',
            field: 'id',
            align: 'center',
            valign: 'middle',
            width: '10%',
            formatter: function (value, row, index) {
                return value
            }
        },
        {
            title: '关键字',
            field: 'keyWord',
            align: 'center',
            valign: 'middle',
            formatter: function (value, row, index) {
                var html = "<a href='sotu_view?keyWord=" + value + "' target='_blank'>" + value + "</a>"
                return html
            }
        },
        {
            title: '图片总数',
            field: 'totalImage',
            align: 'center',
            valign: 'middle',
            formatter: function (value, row, index) {
                var html = "<a href='sotu_view?keyWord=" + row.keyWord + "' target='_blank'>" + row.totalImage + "</a>"
                return html
            }
        })

    $('#search_keyword_table').bootstrapTable({
        url: 'searchKeyWordJson',
        sidePagination: "server",
        queryParamsType: 'page,size',
        contentType: "application/x-www-form-urlencoded",
        method: 'get',
        striped: false,     //是否显示行间隔色
        cache: false,      //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
        pagination: true,  //是否显示分页(*)
        paginationLoop: true,
        paginationHAlign: 'right', //right, left
        paginationVAlign: 'bottom', //bottom, top, both
        paginationDetailHAlign: 'left', //right, left
        paginationPreText: ' 上一页',
        paginationNextText: '下一页',
        search: true,
        searchText: searchText,
        searchTimeOut: 500,
        searchAlign: 'right',
        searchOnEnterKey: false,
        trimOnSearch: true,
        sortable: true,    //是否启用排序
        sortOrder: "desc",   //排序方式
        sortName: "id",
        pageNumber: 1,     //初始化加载第一页,默认第一页
        pageSize: 10,      //每页的记录行数(*)
        pageList: [8, 16, 32, 64, 128], // 可选的每页数据
        totalField: 'totalElements', // 所有记录 count
        dataField: 'content', //后端 json 对应的表格List数据的 key
        columns: columns,
        queryParams: function (params) {
            return {
                size: params.pageSize,
                page: params.pageNumber - 1,
                sortName: params.sortName,
                sortOrder: params.sortOrder,
                searchText: params.searchText
            }
        },
        classes: 'table table-responsive full-width',
    })


    $(document).on('keydown', function (event) {
        // 键盘翻页事件
        var e = event || window.event || arguments.callee.caller.arguments[0];
        if (e && e.keyCode == 38 || e && e.keyCode == 37) {//上,左
            // 上一页
            $('.page-pre').click()
        }
        if (e && e.keyCode == 40 || e && e.keyCode == 39) {//下,右
            // 下一页
            $('.page-next').click()
        }

    })

    $('#add_key_word_form_save_button').on('click', function () {
        var keyWord = $('#add_key_word_form_keyWord').val()
        $.ajax({
            url: 'save_keyword',
            type: 'get',
            data: {keyWord: keyWord},
            success: function (response) {
                if (response == "1") {
                    alert("保存成功")
                } else {
                    alert("保存失败")
                }

            },
            error: function (error) {
                alert(JSON.stringify(error))
            }
        })
    })

})
添加爬取关键字

添加爬取关键字 http 接口代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RequestMapping(value = "save_keyword", method = arrayOf(RequestMethod.GET,RequestMethod.POST))
@ResponseBody
fun save(@RequestParam(value = "keyWord")keyWord:String): String {
    if(keyWord==""){
        return "0"
    }else{
        searchKeyWordRepository.saveOnNoDuplicateKey(keyWord)
        return "1"
    }
}

前端输入框表单代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<form id="add_key_word_form">
    <div class="col-lg-3">
        <div class="input-group">
            <input name="keyWord"
                   id="add_key_word_form_keyWord"
                   type="text"
                   class="form-control"
                   placeholder="输入爬虫抓取关键字">
            <span class="input-group-btn">
                        <button id="add_key_word_form_save_button"
                                class="btn btn-default"
                                type="button">
                             保存
                        </button>
            </span>
        </div><!-- /input-group -->
    </div><!-- /.col-lg-3 -->
</form>

对应的 js 代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$('#add_key_word_form_save_button').on('click', function () {
    var keyWord = $('#add_key_word_form_keyWord').val()
    $.ajax({
        url: 'save_keyword',
        type: 'get',
        data: {keyWord: keyWord},
        success: function (response) {
            if (response == "1") {
                alert("保存成功")
                $('#search_keyword_table').bootstrapTable('refresh')
            } else {
                alert("数据不能为空")
            }

        },
        error: function (error) {
            alert(JSON.stringify(error))
        }
    })
})

其中, $('#search_keyword_table').bootstrapTable('refresh') 是当保存成功后,刷新表格内容。

定时更新该关键字的图片总数任务

最终的效果如下

爬取关键字管理页面

模糊搜索“秋”

更新 search_key_word 表 total_image 字段的 SQL 逻辑如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Modifying
@Transactional
@Query("update search_key_word a set a.total_image = (select count(*) from image i where i.is_deleted=0 and i.category like concat('%',a.key_word,'%'))", nativeQuery = true)
fun batchUpdateTotalImage()

表示该对应关键字包含的图片总数。

然后,我们用一个定时任务去执行它

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.easy.kotlin.picturecrawler.job

import com.easy.kotlin.picturecrawler.dao.SearchKeyWordRepository
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.runBlocking
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import java.util.*

@Component
class BatchUpdateJob {

    @Autowired lateinit var searchKeyWordRepository: SearchKeyWordRepository

    @Scheduled(cron = "0 */5 * * * ?")
    fun job() {
        println("开始执行定时任务 batchUpdateTotalImage: ${Date()}")
        searchKeyWordRepository.batchUpdateTotalImage()
    }
}

13.2.11 使用协程实现异步爬虫任务

上面我们的定时任务都是同步的。当我们想用 http 接口去触发任务执行的时候,可能并不想一直等待,这个时候可以使用异步的方式。这里我们使用 Kotlin 提供的轻量级线程——协程来实现。在常用的并发模型中,多进程、多线程、分布式是最普遍的,不过近些年来逐渐有一些语言以first-class或者library的形式提供对基于协程的并发模型的支持。其中比较典型的有Scheme、Lua、PythonPerl、Go等以first-class的方式提供对协程的支持。同样地,Kotlin也支持协程。(关于协程的更多介绍,可参考《Kotlin 极简教程》第9章 轻量级线程:协程 )

我们在 build.gradle 中添加kotlinx-coroutines-core 依赖

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '0.19.2'

然后把我们的定时任务代码改写为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Component
class BatchUpdateJob {

    @Autowired lateinit var searchKeyWordRepository: SearchKeyWordRepository

    @Scheduled(cron = "0 */5 * * * ?")
    fun job() {
        doBatchUpdate()
    }

    fun doBatchUpdate() = runBlocking {
        launch(CommonPool) {
            println("开始执行定时任务 batchUpdateTotalImage: ${Date()}")
            searchKeyWordRepository.batchUpdateTotalImage()
        }
    }
}

同样的爬虫抓取图片的任务也可以改写成

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fun doCrawJob() = runBlocking {
    val list = searchKeyWordRepository.findAll()
    for (i in 1..1000) {
        list.forEach {
            launch(CommonPool) {
                saveImage(it.keyWord, i)
            }
        }
    }
}

其中,launch函数会以非阻塞(non-blocking)当前线程的方式,启动一个新的协程后台任务,并返回一个Job类型的对象作为当前协程的引用。我们把真正要执行的代码逻辑放到 launch(CommonPool) { } 中。这样我们就可以手动启动任务异步执行了。

13.2.12 图片存入数据库并在前端展现

数据库实体类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.easy.kotlin.picturecrawler.entity

import java.util.*
import javax.persistence.*

@Entity
@Table(indexes = arrayOf(
        Index(name = "idx_url", unique = true, columnList = "url"),
        Index(name = "idx_category", unique = false, columnList = "category")))
class Image {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = -1
    @Version
    var version: Int = 0

    @Column(length = 255, unique = true, nullable = false)
    var category: String = ""
    var isFavorite: Int = 0

    @Column(length = 255, unique = true, nullable = false)
    var url: String = ""

    var gmtCreated: Date = Date()
    var gmtModified: Date = Date()
    var isDeleted: Int = 0  //1 Yes 0 No
    var deletedDate: Date = Date()

    @Lob
    var imageBlob: ByteArray = byteArrayOf()
    /* 0-Baidu  1-Gank */
    var sourceType: Int = 0

    override fun toString(): String {
        return "Image(id=$id, version=$version, category='$category', isFavorite=$isFavorite, url='$url', gmtCreated=$gmtCreated, gmtModified=$gmtModified, isDeleted=$isDeleted, deletedDate=$deletedDate)"
    }
}

其中 @Lob var imageBlob: ByteArray = byteArrayOf() 这个字段存储图片的 Base64内容。

图片比特流数组存入数据库代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val image = Image()
image.category = "干货集中营福利"
image.url = url
image.sourceType = 1
image.imageBlob = getByteArray(url)
logger.info("Image = ${Image}")
imageRepository.save(Image)

其中的getByteArray(url) 函数实现代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private fun getByteArray(url: String): ByteArray {
        val urlObj = URL(url)
        return urlObj.readBytes()
    }

前端 html 展示图片代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
        title: '图片',
        field: 'imageBlob',
        align: 'center',
        valign: 'middle',
        formatter: function (value, row, index) {
            // var html = "<img onclick=downloadImage('" + value + "') width='100%' src='" + value + "'>"
            var html = '<img onclick="downBase64Image(this.src)" width="100%" src="data:image/jpg;base64,' + value + '"/>'
            return html
        }
    }

点击下载 js :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function downloadImage(src) {
    var $a = $("<a></a>").attr("href", src).attr("download", "sotu.png");
    $a[0].click();
}


function downBase64Image(url) {
    var blob = base64Img2Blob(url);
    url = window.URL.createObjectURL(blob);
    var $a = $("<a></a>").attr("href", url).attr("download", "sotu.png");
    $a[0].click();
}


function base64Img2Blob(code) {
    var parts = code.split(';base64,');
    var contentType = parts[0].split(':')[1];
    var raw = window.atob(parts[1]);
    var rawLength = raw.length;

    var uInt8Array = new Uint8Array(rawLength);

    for (var i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
    }

    return new Blob([uInt8Array], {type: contentType});
}

13.2.13 IDEA 的数据库客户端工具

IDEA 的数据库客户端工具

本节完整的项目源码:https://github.com/EasySpringBoot/picture-crawler

本章小结

Spring Framework 5.0中已经添加了对 Kotlin 的支持。使用 Kotlin 集成 SpringBoot 开发非常流畅自然,几乎不需要任何迁移成本。所以,Kotlin 在未来的 Java 服务端领域也必将受到越来越多的程序员的关注。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.10.26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
第13章 Kotlin 集成 SpringBoot 服务端开发(1)第13章 Kotlin 集成 SpringBoot 服务端开发
本章介绍Kotlin服务端开发的相关内容。首先,我们简单介绍一下Spring Boot服务端开发框架,快速给出一个 Restful Hello World的示例。然后,我们讲下 Kotlin 集成 Spring Boot 进行服务端开发的步骤,最后给出一个完整的 Web 应用开发实例。
一个会写诗的程序员
2018/08/17
2.8K0
第13章 Kotlin 集成 SpringBoot 服务端开发(1)第13章 Kotlin 集成 SpringBoot 服务端开发
解决Spring Spring Data JPA 错误: Page 1 of 1 containing UNKNOWN instances解决Spring Spring Data JPA 错误:
后台得不到数据, 并提示 Page 1 of 1 containing UNKNOWN instances
一个会写诗的程序员
2018/08/17
3.5K0
spring-data-jpa + SpringBoot + bootstrapTable 后端分页 模糊查询spring-data-jpa + SpringBoot + bootstrapTab
需要注意的是,bootstrap-table与bootstrap 3是兼容的。但是bootstrap 4还不行。
一个会写诗的程序员
2018/08/17
1.7K0
《Kotin 极简教程》第11章 使用Kotlin 集成 SpringBoot开发Web服务端第11章 使用Kotlin集成SpringBoot开发Web服务端《Kotlin极简教程》正式上架:
我们在前面第2章 “ 2.3 Web RESTFul HelloWorld ” 一节中,已经介绍了使用 Kotlin 结合 SpringBoot 开发一个RESTFul版本的 Hello World。当然,Kotlin与Spring家族的关系不止如此。在 Spring 5.0 M4 中引入了一个专门针对Kotlin的支持。
一个会写诗的程序员
2018/08/17
3.2K0
《Kotin 极简教程》第11章 使用Kotlin 集成 SpringBoot开发Web服务端第11章 使用Kotlin集成SpringBoot开发Web服务端《Kotlin极简教程》正式上架:
spring data jpa @Query注解中delete语句报错 : @Modifying注解的使用spring data jpa @Query注解中delete语句报错
spring data jpa @Query注解中delete语句报错 项目中需要删除掉表中的一些数据 @Query("delete from EngineerServices es where es
一个会写诗的程序员
2018/08/17
2.2K0
【Spring Boot + Kotlin 实战教程】Spring Data JPA 多表关联查询 映射到 Dto 的方法【Spring Boot + Kotlin 实战教程】Spring Data
https://github.com/AK-47-D/cms/tree/picture_2017.11.11
一个会写诗的程序员
2018/08/17
9400
《Springboot极简教程》 第11章 Springboot集成mongodb开发小结
本章我们通过SpringBoot集成mongodb,Java,Kotlin开发一个极简社区文章博客系统。
一个会写诗的程序员
2018/08/20
1.8K0
《Springboot极简教程》 第11章 Springboot集成mongodb开发小结
《Kotlin极简教程》第五章 Kotlin面向对象编程(OOP)一个OOP版本的HelloWorld构造函数传参Data Class定义接口&实现之写pojo bean定一个Rectangle对象封
We frequently create a class to do nothing but hold data. In such a class some standard functionality is often mechanically derivable from the data. In Kotlin, this is called a data class and is marked as data
一个会写诗的程序员
2018/08/20
1.6K0
Kotlin + Spring Boot (Gradle) + React.js (Nowa) 集成 Web 开发
Kotlin + Spring Boot (Gradle) + React.js (Nowa) 集成 Web 开发
一个会写诗的程序员
2018/08/17
8400
Kotlin + Spring Boot (Gradle) + React.js (Nowa) 集成 Web 开发
6.3 Spring Boot集成mongodb开发小结
本章我们通过SpringBoot集成mongodb,Java,Kotlin开发一个极简社区文章博客系统。
一个会写诗的程序员
2018/08/20
4.2K0
6.3 Spring Boot集成mongodb开发小结
SpringBoot-Kotlin
Kotlin(科特林)是一个用于现代多平台应用的静态编程语言 ,由 JetBrains 开发。
是小张啊喂
2021/08/09
1.2K0
8.4 Spring Boot集成Kotlin混合Java开发
本章介绍Spring Boot集成Kotlin混合Java开发一个完整的spring boot应用:Restfeel,一个企业级的Rest API接口测试平台(在开源工程restfiddle[1]基础上开发而来)。
一个会写诗的程序员
2018/08/20
1.8K0
8.4 Spring Boot集成Kotlin混合Java开发
MySQL 直接存储图片并在 html 页面中展示,点击下载
数据库实体类: package com.easy.kotlin.picturecrawler.entity import java.util.* import javax.persistence.* @Entity @Table(indexes = arrayOf( Index(name = "idx_url", unique = true, columnList = "url"), Index(name = "idx_category", unique = false,
一个会写诗的程序员
2018/08/17
1.9K0
使用 Kotlin + WebFlux/RxJava 2 实现响应式以及尝试正式版本的协程WebFluxRxJava 2Kotlin 1.3 的 Coroutines总结
在前一篇文章《使用 Kotlin + Spring Boot 进行后端开发》中,曾介绍过尝试使用 Kotlin 来做后端开发。这一次,尝试 WebFlux 以及协程。
fengzhizi715
2018/12/17
1.2K0
使用 Kotlin + WebFlux/RxJava 2 实现响应式以及尝试正式版本的协程WebFluxRxJava 2Kotlin 1.3 的 Coroutines总结
《Kotin 极简教程》第14章 使用 Kotlin DSL第14章 使用 Kotlin DSL《Kotlin极简教程》正式上架:
我们在前面的章节中,已经看到了 Kotlin DSL 的强大功能。例如Gradle 的配置文件 build.gradle (Groovy),以及前面我们涉及到的Gradle Script Kotlin(Kotlin)、Anko(Kotlin)等,都是 DSL。我们可以看出,使用DSL的编程风格,可以让程序更加简单干净、直观简洁。当然,我们也可以创建自己的 DSL。
一个会写诗的程序员
2018/08/17
2.3K0
《Kotin 极简教程》第14章 使用 Kotlin DSL第14章 使用 Kotlin  DSL《Kotlin极简教程》正式上架:
《Kotlin 程序设计》第十二章 Kotlin的多线程
Kotlin 1.1 introduced coroutines, a new way of writing asynchronous, non-blocking code (and much more). In this tutorial we will go through some basics of using Kotlin coroutines with the help of the kotlinx.coroutines library, which is a collection of helpers and wrappers for existing Java libraries.
一个会写诗的程序员
2018/08/17
3.5K0
全文检索工具:第一章:Spring-data-elasticSearch搜索
@Document(indexName = "search11", type = "article",shards = 1,replicas = 0)
Java廖志伟
2022/09/28
4310
全文检索工具:第一章:Spring-data-elasticSearch搜索
第14章 使用Kotlin 进行 Android 开发(2)
我们使用 fastjson 来解析这个数据。在 app 下面的 build.gradle中添加依赖
一个会写诗的程序员
2018/08/17
1.2K0
第14章 使用Kotlin 进行 Android 开发(2)
JPA 执行update/delete query 需要加上事务
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
一个会写诗的程序员
2018/08/17
9660
第16章 Spring Boot + Kotlin: 下一代 Java 服务端开发
2017-11-22 11:55:17.205 INFO 14721 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.2.12.Final} 2017-11-22 11:55:17.208 INFO 14721 --- [ main] org.hibernate.cfg.Environment : HHH000205: Loaded properties from resource hibernate.properties: {hibernate.connection.driver_class=com.mysql.jdbc.Driver, hibernate.format_sql=true, hibernate.dialect=org.hibernate.dialect.MySQLDialect, hibernate.bytecode.use_reflection_optimizer=false, hibernate.max_fetch_depth=1, hibernate.connection.pool_size=1} 2017-11-22 11:55:17.261 INFO 14721 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final} 2017-11-22 11:55:17.449 INFO 14721 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect 2017-11-22 11:55:17.665 INFO 14721 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
一个会写诗的程序员
2018/08/17
1.2K0
第16章 Spring Boot + Kotlin: 下一代 Java 服务端开发
推荐阅读
第13章 Kotlin 集成 SpringBoot 服务端开发(1)第13章 Kotlin 集成 SpringBoot 服务端开发
2.8K0
解决Spring Spring Data JPA 错误: Page 1 of 1 containing UNKNOWN instances解决Spring Spring Data JPA 错误:
3.5K0
spring-data-jpa + SpringBoot + bootstrapTable 后端分页 模糊查询spring-data-jpa + SpringBoot + bootstrapTab
1.7K0
《Kotin 极简教程》第11章 使用Kotlin 集成 SpringBoot开发Web服务端第11章 使用Kotlin集成SpringBoot开发Web服务端《Kotlin极简教程》正式上架:
3.2K0
spring data jpa @Query注解中delete语句报错 : @Modifying注解的使用spring data jpa @Query注解中delete语句报错
2.2K0
【Spring Boot + Kotlin 实战教程】Spring Data JPA 多表关联查询 映射到 Dto 的方法【Spring Boot + Kotlin 实战教程】Spring Data
9400
《Springboot极简教程》 第11章 Springboot集成mongodb开发小结
1.8K0
《Kotlin极简教程》第五章 Kotlin面向对象编程(OOP)一个OOP版本的HelloWorld构造函数传参Data Class定义接口&实现之写pojo bean定一个Rectangle对象封
1.6K0
Kotlin + Spring Boot (Gradle) + React.js (Nowa) 集成 Web 开发
8400
6.3 Spring Boot集成mongodb开发小结
4.2K0
SpringBoot-Kotlin
1.2K0
8.4 Spring Boot集成Kotlin混合Java开发
1.8K0
MySQL 直接存储图片并在 html 页面中展示,点击下载
1.9K0
使用 Kotlin + WebFlux/RxJava 2 实现响应式以及尝试正式版本的协程WebFluxRxJava 2Kotlin 1.3 的 Coroutines总结
1.2K0
《Kotin 极简教程》第14章 使用 Kotlin DSL第14章 使用 Kotlin DSL《Kotlin极简教程》正式上架:
2.3K0
《Kotlin 程序设计》第十二章 Kotlin的多线程
3.5K0
全文检索工具:第一章:Spring-data-elasticSearch搜索
4310
第14章 使用Kotlin 进行 Android 开发(2)
1.2K0
JPA 执行update/delete query 需要加上事务
9660
第16章 Spring Boot + Kotlin: 下一代 Java 服务端开发
1.2K0
相关推荐
第13章 Kotlin 集成 SpringBoot 服务端开发(1)第13章 Kotlin 集成 SpringBoot 服务端开发
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验