文章寫于2017.11月,作者已長時(shí)間沒有再接觸 SpringBoot 了鳖目。
目前更推薦 nestjs扮叨,這里附上一個(gè)代碼倉庫,不同的 commits 增加了不同的功能领迈,供感興趣的同學(xué)參考彻磁。nest-starter
從一開始只有一個(gè)IDEA,到上線一個(gè)外網(wǎng)可訪問的API惦费。最后的效果是這樣的:
開發(fā)環(huán)境:Win10
+ IDEA
+ Gradle
主要技術(shù):SpringBoot框架
+ Kotlin語言
+ MySQL數(shù)據(jù)庫
內(nèi)容提要:
- 創(chuàng)建一個(gè)基于
Gradle
的項(xiàng)目 - 初始化
SpringBoot
- 安裝兵迅、配置抢韭、關(guān)聯(lián)
MySQL
- 構(gòu)建一個(gè)簡單的API
- 打包一個(gè)可執(zhí)行文件
- 使用
ngrok
做外網(wǎng)訪問
創(chuàng)建一個(gè)新項(xiàng)目
先用IDEA創(chuàng)建一個(gè)Gradle項(xiàng)目
注意:
- 基于Gradle
- 使用Kotlin
- IDEA對JDK做了一些改進(jìn)薪贫,比如把原來的
Logging
換成了SLF4J
,在使用時(shí)有時(shí)會導(dǎo)致重復(fù)導(dǎo)包刻恭。為了避免麻煩瞧省,我們使用原生的JDK。
接下來一路Next鳍贾。
如果你網(wǎng)絡(luò)沒問題的話鞍匾,最后會是這樣一個(gè)項(xiàng)目結(jié)構(gòu):
初始化SpringBoot
修改自動生成的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è)
SpringBoot
的gradle
插件骑科,作用如下:- 整合類路徑上所有的
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)
}
不出錯(cuò)的話,這時(shí)候訪問localhost:8080
(默認(rèn)的)宴猾,會看到我們剛才設(shè)置的Hello World!
:
表明SpringBoot
運(yùn)行正常圆存。繼續(xù)下一步。
接入MySQL
首先仇哆,修改依賴沦辙,添加下面的依賴:
compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'mysql:mysql-connector-java'
結(jié)果如圖:
然后,需要連接到MySQL
服務(wù)器讹剔。我們?nèi)ハ螺d一個(gè)MySQL
油讯。
我是Windows的系統(tǒng),所以按照Windows大致說下流程延欠,很簡單的東西陌兑。推薦使用MySQL Installer
,Windows下載地址由捎,只有32位的包兔综,但是安裝的時(shí)候可選安裝64位的組件。
選擇要安裝的組件狞玛,我選了Custom
和下面5個(gè)软驰。不想安裝多的話,可以只安裝Server
組件就可以了为居。自己決定選什么碌宴。
這個(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)限都給到新建用戶
我的配置如下:
然后在項(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)于spring.jpa.hibernate.ddl-auto
:
- 幾個(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ù)庫淘菩。
-
- 在這里,我們使用create是因?yàn)槲覀儸F(xiàn)在還沒有數(shù)據(jù)庫結(jié)構(gòu)削罩。第一次運(yùn)行之后瞄勾,我們可以根據(jù)需求切換到update或none费奸。要改變數(shù)據(jù)庫結(jié)構(gòu)時(shí)使用update弥激。
- H2和其他嵌入式數(shù)據(jù)庫默認(rèn)是create-drop,但對于其他類似MySQL的是none
- 數(shù)據(jù)庫處于生產(chǎn)狀態(tài)時(shí)使用
none
是很好的安全做法愿阐,你設(shè)置none微服,并移除連接到Spring應(yīng)用程序的MySQL用戶的所有特權(quán),然后只給增刪查改的權(quán)限缨历。
開始構(gòu)建一個(gè)簡單的服務(wù)
我們要做的:
- 有一個(gè)
User
的表 - 可以通過請求增加一個(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)
}
注意:
- 不加
open
修飾符會報(bào)錯(cuò)宝与。kotlin中不加open
修飾符類默認(rèn)為final
類焚廊,而SpringBootApplication
不能是final
類。 - 關(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é)果:
獲取所有User
信息:
奇怪的是一個(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)的名字:
和之前的效果一模一樣的霸旗。
使用ngrok連接外網(wǎng)
我使用的ngrok.cc
贷帮,因?yàn)榭梢悦赓M(fèi)綁定自己的域名。
流程如下:
- 注冊賬戶
- 開通一個(gè)隧道诱告,選第三個(gè)免費(fèi)的撵枢。
- 選http
- 隧道名稱隨便起
- 前置域名[***.free.ngrok.cc]
- 本地端口,比如我們使用的
127.0.0.1:8080
- http用戶名密碼精居,先不用管
- 添加
- 照簡單教程下載對應(yīng)版本的軟件锄禽,啟動。
- 開啟你的
SpringBoot
服務(wù)靴姿,把之前的localhost:8080
換成***.free.ngrok.cc
即可訪問沃但。***換自己起的前置域名。
如果你有一個(gè)域名佛吓,可以來替換掉這個(gè)免費(fèi)域名:
點(diǎn)擊隧道管理 -> 選中隧道 -> 修改
按規(guī)定設(shè)置域名解析宵晚,比如我的是阿里云的域名:
設(shè)置好等一會即可恨旱。另外注意,ngrok.cc
目前還不支持https訪問坝疼,所以使用自己的域名時(shí)也要注意使用http進(jìn)行訪問搜贤。
除了上邊提到的錯(cuò)誤,我還遇到了另外一個(gè)錯(cuò)誤钝凶,顯示端口占用仪芒。解決方法如下。
先打開CMD
命令行命令netstat ?ano
耕陷,找到占用8080端口的進(jìn)程的PID
:
去進(jìn)程詳情里找到該進(jìn)程掂名,結(jié)束掉,重新啟動SpringBoot
服務(wù)哟沫。
相關(guān)文檔
本文內(nèi)容主要來自:
最后饺蔑,SpringBoot
能做的東西還很多,本文只是和你一起搭了一個(gè)很基本的框架嗜诀,你可以不斷的去添加新的內(nèi)容進(jìn)去猾警,去嘗試構(gòu)造你自己的優(yōu)雅的API,做更多的事隆敢。