Kotlin + SpringBoot + MySQL + Ngrok辆亏,你也可以快速上線一個(gè)后臺服務(wù)

文章寫于2017.11月,作者已長時(shí)間沒有再接觸 SpringBoot 了鳖目。
目前更推薦 nestjs扮叨,這里附上一個(gè)代碼倉庫,不同的 commits 增加了不同的功能领迈,供感興趣的同學(xué)參考彻磁。nest-starter

從一開始只有一個(gè)IDEA,到上線一個(gè)外網(wǎng)可訪問的API惦费。最后的效果是這樣的:

外網(wǎng)訪問API

開發(fā)環(huán)境:Win10 + IDEA + Gradle

主要技術(shù):SpringBoot框架 + Kotlin語言 + MySQL數(shù)據(jù)庫

內(nèi)容提要:

  1. 創(chuàng)建一個(gè)基于Gradle的項(xiàng)目
  2. 初始化SpringBoot
  3. 安裝兵迅、配置抢韭、關(guān)聯(lián)MySQL
  4. 構(gòu)建一個(gè)簡單的API
  5. 打包一個(gè)可執(zhí)行文件
  6. 使用ngrok做外網(wǎng)訪問

創(chuàng)建一個(gè)新項(xiàng)目

先用IDEA創(chuàng)建一個(gè)Gradle項(xiàng)目

創(chuàng)建項(xiàng)目

注意:

  1. 基于Gradle
  2. 使用Kotlin
  3. IDEA對JDK做了一些改進(jìn)薪贫,比如把原來的Logging換成了SLF4J,在使用時(shí)有時(shí)會導(dǎo)致重復(fù)導(dǎo)包刻恭。為了避免麻煩瞧省,我們使用原生的JDK。
創(chuàng)建項(xiàng)目
創(chuàng)建項(xiàng)目

接下來一路Next鳍贾。

如果你網(wǎng)絡(luò)沒問題的話鞍匾,最后會是這樣一個(gè)項(xiàng)目結(jié)構(gòu):

項(xiàng)目結(jié)構(gòu)

初始化SpringBoot

修改自動生成的build.gradle如下:

build.gradle

代碼如下:

buildscript {
    ext.kotlin_version = '1.1.51'
    ext.spring_boot_version = '1.5.8.RELEASE'

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version"
    }
}

apply plugin: 'kotlin'
apply plugin: 'org.springframework.boot'


repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
    compile 'org.springframework.boot:spring-boot-starter-web'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

對上邊四個(gè)標(biāo)注解釋:

  • 上邊三條,主要是添加了一個(gè)SpringBootgradle插件骑科,作用如下:
    • 整合類路徑上所有的jar橡淑,并建立一個(gè)單一的,可運(yùn)行的"über-jar"咆爽。(不用管梁棠,就是一個(gè)名字。)
    • 它搜索public static void main()方法來標(biāo)記為可運(yùn)行的類斗埂。
    • 它提供了一個(gè)內(nèi)建的依賴解析器符糊,設(shè)置了版本號,以匹配SpringBoot的依賴呛凶。您可以覆蓋任何你想要的版本男娄,但它會默認(rèn)引導(dǎo)的選擇版本的集合。可以注意到下邊對spring-boot-starter-web的依賴沒有設(shè)置版本模闲。SpringBoot有很多組件建瘫,之后依賴的組件多了,就很很方便的管理版本了围橡。
  • 最后一條暖混,真正的引用。SpringBoot的Web基礎(chǔ)包翁授。

接下來拣播,我們創(chuàng)建一個(gè)入口文件添加一些簡單代碼并運(yùn)行。注意:一定要創(chuàng)建包收擦!

@Controller              //表明這是一個(gè)Controller贮配,控制路由的東西
@EnableAutoConfiguration //告訴SpringBoot開始依據(jù)依賴路徑等添加Beans。
class SampleController {

    @RequestMapping("/") //映射最基礎(chǔ)的URL
    @ResponseBody        //表明這是一個(gè)Resopnse塞赂,而不是一個(gè)視圖名稱
    internal fun home(): String {
        return "Hello World!" //為請求返回一個(gè)字符串泪勒。
    }
}

fun main(args: Array<String>) {
    SpringApplication.run(SampleController::class.java, *args)
}
運(yùn)行

不出錯(cuò)的話,這時(shí)候訪問localhost:8080(默認(rèn)的)宴猾,會看到我們剛才設(shè)置的Hello World!

localhost主界面

表明SpringBoot運(yùn)行正常圆存。繼續(xù)下一步。


接入MySQL

首先仇哆,修改依賴沦辙,添加下面的依賴:

compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'mysql:mysql-connector-java'

結(jié)果如圖:

build.gradle

然后,需要連接到MySQL服務(wù)器讹剔。我們?nèi)ハ螺d一個(gè)MySQL油讯。
我是Windows的系統(tǒng),所以按照Windows大致說下流程延欠,很簡單的東西陌兑。推薦使用MySQL InstallerWindows下載地址由捎,只有32位的包兔综,但是安裝的時(shí)候可選安裝64位的組件。

MySQL下載

選擇要安裝的組件狞玛,我選了Custom和下面5個(gè)软驰。不想安裝多的話,可以只安裝Server組件就可以了为居。自己決定選什么碌宴。

MySQL安裝

這個(gè)之后的配置,我只設(shè)置了root的密碼蒙畴。(也可以不設(shè)置贰镣,一路next)呜象。

接下來,配置一下數(shù)據(jù)庫:

先進(jìn)入MySQL Server的目錄下面碑隆,我的是C:\Program Files\MySQL\MySQL Server 5.7\bin恭陡,用的頻繁的話可以加到環(huán)境變量里去,輸入命令mysql -u root -p并輸入密碼進(jìn)入數(shù)據(jù)庫上煤,然后執(zhí)行下邊的數(shù)據(jù)庫命令:

mysql> create database db_example; -- 創(chuàng)建一個(gè)數(shù)據(jù)庫休玩,名字自己設(shè)置。
mysql> create user 'springuser'@'localhost' identified by 'ThePassword'; -- 創(chuàng)建一個(gè)用戶劫狠,專門管理這個(gè)數(shù)據(jù)庫拴疤。也可以不創(chuàng)建用戶,等下直接使用root用戶独泞。
mysql> grant all on db_example.* to 'springuser'@'localhost'; -- 把新建數(shù)據(jù)庫的所有權(quán)限都給到新建用戶

我的配置如下:

MySQL配置

然后在項(xiàng)目里關(guān)聯(lián)上數(shù)據(jù)庫:

resources目錄下呐矾,創(chuàng)建一個(gè)文件application.properties,內(nèi)容如下:

spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:mysql://localhost:3306/(數(shù)據(jù)庫名字)
spring.datasource.username=(用戶名,比如我的是springuser或者root)
spring.datasource.password=(密碼懦砂,沒有就空著)
關(guān)聯(lián)MySQL

另外關(guān)于spring.jpa.hibernate.ddl-auto

  1. 幾個(gè)選項(xiàng)
    • none MySQL默認(rèn)選項(xiàng)蜒犯,不改變數(shù)據(jù)庫結(jié)構(gòu)。
    • update 根據(jù)給定的實(shí)體結(jié)構(gòu)改變數(shù)據(jù)庫荞膘。
    • create 每次都創(chuàng)建數(shù)據(jù)庫罚随,但關(guān)閉的時(shí)候不刪除數(shù)據(jù)庫。
    • create-drop 創(chuàng)建數(shù)據(jù)庫羽资,在SessionFactory關(guān)閉時(shí)刪除數(shù)據(jù)庫淘菩。
  2. 在這里,我們使用create是因?yàn)槲覀儸F(xiàn)在還沒有數(shù)據(jù)庫結(jié)構(gòu)削罩。第一次運(yùn)行之后瞄勾,我們可以根據(jù)需求切換到update或none费奸。要改變數(shù)據(jù)庫結(jié)構(gòu)時(shí)使用update弥激。
  3. H2和其他嵌入式數(shù)據(jù)庫默認(rèn)是create-drop,但對于其他類似MySQL的是none
  4. 數(shù)據(jù)庫處于生產(chǎn)狀態(tài)時(shí)使用none是很好的安全做法愿阐,你設(shè)置none微服,并移除連接到Spring應(yīng)用程序的MySQL用戶的所有特權(quán),然后只給增刪查改的權(quán)限缨历。

開始構(gòu)建一個(gè)簡單的服務(wù)

我們要做的:

  1. 有一個(gè)User的表
  2. 可以通過請求增加一個(gè)User以蕴,也可以查找所有的User信息

先創(chuàng)建一個(gè)User

package hello

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id


@Entity // 告訴Hibernate依據(jù)這個(gè)類創(chuàng)建一個(gè)表
class User {
    @Id //主鍵
    @GeneratedValue(strategy = GenerationType.AUTO) //自增長
    var id: Int? = null

    var name: String? = null

    var email: String? = null
}

再創(chuàng)建一個(gè)操作數(shù)據(jù)的接口

// Spring會自動生成一個(gè)名為userRepository(注意是首字母小寫)Bean用來操作增刪改查
interface UserRepository : CrudRepository<User, Long>

再創(chuàng)建一個(gè)Controller處理請求

@Controller    // 申明這是一個(gè)Controller
@RequestMapping(path = arrayOf("/demo")) // 匹配路徑以/demo開頭的URL
class MainController(@Autowired private val userRepository: UserRepository) {//@Autowired 使用該注解可自動找到之前Spring自動創(chuàng)建的名為userRepository的Bean來填充數(shù)據(jù)

    val allUsers: Iterable<User>
        @GetMapping(path = arrayOf("/all"))
        @ResponseBody
        get() = userRepository.findAll()

    @GetMapping(path = arrayOf("/add")) 
    @ResponseBody
    fun addNewUser(@RequestParam name: String, @RequestParam email: String): String {
        // @RequestParam 請求參數(shù)

        val n = User()
        n.name = name
        n.email = email
        userRepository.save(n)
        return "Saved"
    }
}

注意:@GetMapping只匹配Get請求,是@RequestMapping(method=GET)的簡寫辛孵。同理還有@PostMapping等丛肮。如果只寫@RequestMapping不指明請求方式表示匹配所有類型的請求。

最后魄缚,修改一下我們的入口類App.kt

@SpringBootApplication
open class Application

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

注意:

  1. 不加open修飾符會報(bào)錯(cuò)宝与。kotlin中不加open修飾符類默認(rèn)為final類焚廊,而SpringBootApplication不能是final類。
  2. 關(guān)于@SpringBootApplication习劫,其實(shí)是以下幾個(gè)注解的簡便寫法咆瘟。
    • @Configuration 標(biāo)記類為bean定義的應(yīng)用程序上下文的來源
    • @EnableAutoConfiguration 之前已經(jīng)提到過了告訴SpringBoot開始依據(jù)依賴路徑等添加Beans。
    • 通常你會添加@EnableWebMvc一個(gè)Spring MVC的應(yīng)用程序诽里,但是當(dāng)它看到春天開機(jī)自動將其添加彈簧webmvc在classpath袒餐。此標(biāo)志的應(yīng)用程序作為Web應(yīng)用程序和激活密鑰的行為,如設(shè)立DispatcherServlet谤狡。
    • @ComponentScan告訴Spring在hello包自動尋找其他組件灸眼,配置,控制器墓懂。

這時(shí)候我們再運(yùn)行一下:

用Get方法傳遞一個(gè)User信息幢炸,它會執(zhí)行保存操作,并返回結(jié)果:

add

獲取所有User信息:

all

奇怪的是一個(gè)請求會執(zhí)行兩次拒贱,在隱身模式下就不會這樣宛徊,我還在找原因。

好了逻澳,現(xiàn)在一個(gè)基本的Api已經(jīng)搭建好了闸天,在本地已經(jīng)能訪問了。接下來斜做,我們看如何打包運(yùn)行苞氮,以及連接外網(wǎng)。

打包運(yùn)行

由于SpringBoot的特性瓤逼,使用Gradle可以方便的生成jar文件笼吟。

打包

生成的文件在這里:

包文件

把生成的文件復(fù)制到桌面上并運(yùn)行,為了方便我給它改了一個(gè)簡單點(diǎn)的名字:

運(yùn)行jar文件

和之前的效果一模一樣的霸旗。


使用ngrok連接外網(wǎng)

我使用的ngrok.cc贷帮,因?yàn)榭梢悦赓M(fèi)綁定自己的域名。

流程如下:

  1. 注冊賬戶
  2. 開通一個(gè)隧道诱告,選第三個(gè)免費(fèi)的撵枢。
    1. 選http
    2. 隧道名稱隨便起
    3. 前置域名[***.free.ngrok.cc]
    4. 本地端口,比如我們使用的127.0.0.1:8080
    5. http用戶名密碼精居,先不用管
    6. 添加
  3. 簡單教程下載對應(yīng)版本的軟件锄禽,啟動。
  4. 開啟你的SpringBoot服務(wù)靴姿,把之前的localhost:8080換成***.free.ngrok.cc即可訪問沃但。***換自己起的前置域名。

如果你有一個(gè)域名佛吓,可以來替換掉這個(gè)免費(fèi)域名:

點(diǎn)擊隧道管理 -> 選中隧道 -> 修改

修改隧道

按規(guī)定設(shè)置域名解析宵晚,比如我的是阿里云的域名:

設(shè)置解析

設(shè)置好等一會即可恨旱。另外注意,ngrok.cc目前還不支持https訪問坝疼,所以使用自己的域名時(shí)也要注意使用http進(jìn)行訪問搜贤。


除了上邊提到的錯(cuò)誤,我還遇到了另外一個(gè)錯(cuò)誤钝凶,顯示端口占用仪芒。解決方法如下。

先打開CMD命令行命令netstat ?ano耕陷,找到占用8080端口的進(jìn)程的PID

找到占用8080端口的進(jìn)程PID

去進(jìn)程詳情里找到該進(jìn)程掂名,結(jié)束掉,重新啟動SpringBoot服務(wù)哟沫。

找到占用8080端口的進(jìn)程

相關(guān)文檔

本文內(nèi)容主要來自:

  1. 實(shí)現(xiàn)簡單的Web服務(wù)
  2. 訪問MySQL

推薦:一個(gè)比較完整的REST服務(wù)


最后饺蔑,SpringBoot能做的東西還很多,本文只是和你一起搭了一個(gè)很基本的框架嗜诀,你可以不斷的去添加新的內(nèi)容進(jìn)去猾警,去嘗試構(gòu)造你自己的優(yōu)雅的API,做更多的事隆敢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末发皿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拂蝎,更是在濱河造成了極大的恐慌穴墅,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件温自,死亡現(xiàn)場離奇詭異玄货,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)悼泌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門松捉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人券躁,你說我怎么就攤上這事惩坑〉糁眩” “怎么了也拜?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長趾痘。 經(jīng)常有香客問我慢哈,道長,這世上最難降的妖魔是什么永票? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任卵贱,我火速辦了婚禮滥沫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘键俱。我一直安慰自己兰绣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布编振。 她就那樣靜靜地躺著缀辩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪踪央。 梳的紋絲不亂的頭發(fā)上臀玄,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音畅蹂,去河邊找鬼健无。 笑死,一個(gè)胖子當(dāng)著我的面吹牛液斜,可吹牛的內(nèi)容都是我干的累贤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼少漆,長吁一口氣:“原來是場噩夢啊……” “哼畦浓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起检疫,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤讶请,失蹤者是張志新(化名)和其女友劉穎钦铺,沒想到半個(gè)月后嚷狞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兆衅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年烛谊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了风响。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丹禀,死狀恐怖状勤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情双泪,我是刑警寧澤持搜,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站焙矛,受9級特大地震影響葫盼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜村斟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一贫导、第九天 我趴在偏房一處隱蔽的房頂上張望抛猫。 院中可真熱鬧,春花似錦孩灯、人聲如沸闺金。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掖看。三九已至,卻和暖如春面哥,著一層夾襖步出監(jiān)牢的瞬間哎壳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工尚卫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留归榕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓吱涉,卻偏偏與公主長得像刹泄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子怎爵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評論 6 342
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理特石,服務(wù)發(fā)現(xiàn),斷路器鳖链,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,114評論 25 707
  • 人生最大的敵人其實(shí)是自己姆蘸,無論在哪個(gè)方面,只有自己才能毀了自己芙委,又或者讓自己的潛力發(fā)揮到最高點(diǎn)逞敷,所以我們在一...
    元寶_H閱讀 738評論 0 2
  • 從鐮倉離開后的每一個(gè)風(fēng)輕云淡的夜晚,那些關(guān)于鐮倉的細(xì)微畫面總會跳出腦海灌侣,每一個(gè)細(xì)枝末節(jié)都可以像日劇電影一樣被一幀幀...
    金日成閱讀 608評論 2 2