Spring Boot(Kotlin)的第一步

目标

因为有朋友向我请求提供学习Spring Boot的契机,所以我创建了这份资料,以便我们可以一起进行实际的编程训练。

Spring Boot (Kotlin)入门
– 模型-视图-控制器(MVC)
– RESTful API
– 数据库访问

用于使用的东西

    • JDK 8

 

    • IntelliJ Idea

 

    • Kotlin

 

    • Gradle

 

    • Spring Boot

 

    Doma2 (JPAのほうが最初の設定は楽だった・・)

※STS + Kotlin Plugin也可以替代IntelliJ Idea,但是没有提供具体步骤。
※对于Maven,需要将dependency等内容翻译成适用于pom文件的形式。
※Doma2的Entity / Dao实现是使用Java而不是Kotlin。

环境建设

安装 IntelliJ Idea。

请点击以下链接
https://www.jetbrains.com/idea/

创建Spring Boot项目的模板

使用Spring Initializr创建模板

产生下列内容。

    • Gradle Project

 

    • Kotlin

 

    • Spring Boot 1.5.9

 

    Dependencies => Web
SpringInitializer.PNG

根据您的喜好,可以选择加入小组或使用工具。 Group / Artifact kě yǐ āi wǒ zhù nǐ zuò yī xià zé.

当下载完成雏形的zip文件后,请将其解压到任意位置。

打开项目

打开IntelliJ并导入项目。

Idea.PNG

指定展开项目中的build.gradle文件作为雏形。

import.PNG

请勾选“自动导入”并确认。

use_auto_import.PNG

开始构建,如果成功同步则没问题。

build.PNG

打开视图 – 工具窗口 – 选择Gradle,然后打开Gradle工具窗口。
在Gradle工具窗口中,右键点击demo -> 任务 -> 应用程序 -> bootRun,选择运行 ‘demo[boot Run]’ 来启动。

bootRun.PNG
14:44:18: Executing task 'bootRun'...

:compileKotlin
:compileJava NO-SOURCE
:copyMainKotlinClasses
:processResources
:classes
:findMainClass
:bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.9.RELEASE)

・
・
・

s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-01-20 14:44:28.125  INFO 13432 --- [           main] com.example.demo.DemoApplicationKt       : Started DemoApplicationKt in 2.45 seconds (JVM running for 2.75)

由于没有控制器等设备,此时无法进行任何操作。

在Spring Boot启动期间,在IntelliJ中进行代码修改时,需要调整build.gradle文件的设置,以确保修改能够反映出来。

在插件的定义中添加以下内容

 apply plugin: 'idea'
 idea {
   module {
     outputDir file('build/classes/main')
     testOutputDir file('build/classes/test')
   }
 }
 if(project.convention.findPlugin(JavaPluginConvention)) {
    // Change the output directory for the main and test source sets back to the old path
    sourceSets.main.output.classesDir = new File(buildDir, "classes/main")
    sourceSets.test.output.classesDir = new File(buildDir, "classes/test")
 }

在最底部的依赖中,添加以下内容。

    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.springframework.boot:spring-boot-devtools")
    • thymeleaf => テンプレートエンジンのthymeleafを使う

 

    spring-boot-devtools => オートリロードを有効にする

自动重新加载设置

在设置中,进入构建选项,打开编译器,勾选“自动构建项目”并应用。

buildProjectAutomatically.PNG

在Windows情况下:按住Shift键 + Ctrl键 -> A 键
在Mac情况下:按住Command键 + Ctrl键 + A 键
以打开窗口,然后在Registry中搜索。

在打开的窗口中,勾选 compiler.automake.allow.when.app.running。

compiler.PNG

用Thymeleaf返回HTML页面

创建控制器

在com.example.demo下创建一个controller包。
在controller包下创建一个GreetingController.kt文件。

package com.example.demo.controller

import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam

@Controller
@RequestMapping("greeting")
class GreetingController {

    @GetMapping("/hello")
    fun hello(
            @RequestParam(value = "name", required = false, defaultValue = "world") name: String,
            model: Model): String {
        model.addAttribute("name", name)
        return "greeting"
    }
}

使用HTML(Thymeleaf)进行编写

在src/main/resources/templates目录下创建greeting.html。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" http-equiv="Content-Type" content="text/html" />
    <title>Getting Started: Saving Web Content</title>
</head>
<body>
    <p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>

确认动作

再次执行Spring Boot

使用网络浏览器访问http://localhost:8080/greeting/hello。

helloworld.PNG

当将URL更改为http://localhost:8080/greeting/hello?name=hoge时,显示会变为”Hello, Hoge!”。

数据库环境准备

安装Virtual Box / Vagrant。

因为使用的是 Windows10 Home,所以无法使用 Docker for Windows,只能使用 Virtual Box / Vagrant。对于 Windows10 Pro 或者 Mac用户来说,使用 Docker 构建更为方便,可以跳过 VirtualBox / Vagrant 部分,直接从 docker-compose 开始就可以了。

Virtual Box
https://www.virtualbox.org/

虚拟盒子
https://www.virtualbox.org/

流浪者
https://www.vagrantup.com/downloads.html

安装插件

$ vagrant plugin install vagrant-vbguest

安装和启动CentOS7的虚拟机

cd [任意のディレクトリ]
vagrant init centos/7

生成Vagrantfile后,设置端口转发和IP地址绑定。

# 以下の設定を追加する
  config.vm.network "forwarded_port", guest: 3306, host: 3306
  config.vm.network "private_network", ip: "192.168.33.10"
vagrant up

# 終わったら↓でrunningになっていることを確認
vagrant status

# vagrantに接続する
vagrant ssh

在Vagrant上安装CentOS7上的Docker。

# インストール確認
docker -v
# docker起動
sudo systemctl start docker
# 動作確認
sudo docker run hello-world
# vagrant起動時にdockerが起動するように
sudo systemctl enable docker

让普通用户也能够使用Docker命令。

sudo gpasswd -a $USER docker
sudo systemctl restart docker

# 一度再ログインする
exit

接下来安装docker-compose
※对于Docker for Mac (Windows)用户,它会同时安装,所以可以跳过.

$ sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

$ sudo chmod +x /usr/local/bin/docker-compose

$ docker-compose --version

创建docker-compose.yml文件

db:
  image: mysql:5.7
  ports:
    - "3306:3306"
  environment:
    MYSQL_ROOT_PASSWORD: root
  volumes_from:
    - data

data:
  image: busybox:1
  volumes:
    - /var/lib/mysql:/var/lib/mysql # macの場合、適当なディレクトリを指定する

创造图像

$ docker-compose up -d
$ docker-compose ps
[vagrant@localhost ~]$ docker-compose ps
     Name                  Command             State            Ports
------------------------------------------------------------------------------
vagrant_data_1   sh                            Exit 0
vagrant_db_1     docker-entrypoint.sh mysqld   Up       0.0.0.0:3306->3306/tcp

检查与MySQL的连接

$ docker exec -it vagrant_db_1 bash
# mysql -uroot -proot

# 適当にデータベースを作成しておく
mysql> create database test;

尝试从主机(Windows/Mac)连接到MySQL。

设置的方法取决于客户端,但应该是这样连接的。
※如果不使用Vagrant,主机将是172.0.0.1。

項目設定値Host192.168.33.10DatabasetestUserrootPasswordroot

适当地准备一张桌子

CREATE TABLE anything(
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255),
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

设定Doma2到项目中。

# repositoriesに↓を追加
    maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }

# compileKotlinの前に↓を追加
processResources.destinationDir = compileJava.destinationDir
compileJava.dependsOn processResources

# dependenciesに↓を追加
    compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'
    compile('org.seasar.doma.boot:doma-spring-boot-starter:1.0.2')

应用程序的配置文件 application.properties 的设置。

# JDBC
spring.datasource.url=jdbc:mysql://192.168.33.10:3306/test
# vagrantを使わない場合はこちら
# spring.datasource.url=jdbc:mysql://172.0.0.1:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# DOMA
doma.dialect=mysql
doma.naming=snake_lower_case

数据库访问的实现

在src/main下创建一个java目录。
在src/main/java下创建com.example.demo.entity和com.example.demo.dao包。

创建以下类

package com.example.demo.entity;

import org.seasar.doma.Entity;
import org.seasar.doma.GeneratedValue;
import org.seasar.doma.GenerationType;
import org.seasar.doma.Id;
import org.seasar.doma.Table;

import java.sql.Timestamp;

@Entity
@Table(name = "anything")
public class AnythingEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Integer id;

    public String name;

    public Timestamp createdAt;

    public Timestamp updatedAt;
}
package com.example.demo.dao;

import com.example.demo.entity.AnythingEntity;
import org.seasar.doma.Dao;
import org.seasar.doma.Insert;
import org.seasar.doma.Select;
import org.seasar.doma.boot.ConfigAutowireable;

import java.util.List;

@ConfigAutowireable
@Dao
public interface AnythingDao {

    @Select
    List<AnythingEntity> selectAll();

    @Insert
    int insert(AnythingEntity anything);
}

从这里开始,进入Kotlin目录。

创建com.example.demo.service包。

创建下面的类

package com.example.demo.service

import com.example.demo.dao.AnythingDao
import com.example.demo.entity.AnythingEntity
import org.springframework.stereotype.Service

@Service
class AnythingService(
        val anythingDao: AnythingDao
) {

    fun findAll(): List<AnythingEntity> {
        return this.anythingDao.selectAll()
    }

    fun insert(anything: AnythingEntity): Int {
        return this.anythingDao.insert(anything)
    }
}
package com.example.demo.controller

import com.example.demo.entity.AnythingEntity
import com.example.demo.service.AnythingService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("anything")
class AnythingController(
        val anythingService: AnythingService
) {

    @GetMapping("/findAll")
    fun findAll(): List<AnythingEntity> {
        return this.anythingService.findAll()
    }

    // 本当はGetにするべきではないですが、面倒なので・・・
    @GetMapping("/insert")
    fun insert(@RequestParam(value = "name", required = false, defaultValue = "doma") name: String): String {

        val entity = AnythingEntity()
        entity.name = name
        this.anythingService.insert(entity)

        return "success"
    }
}

创建一个SQL文件

SELECT
  *
FROM
  anything

确认行动

使用curl或浏览器执行以下操作:
http://localhost:8080/anything/insert
http://localhost:8080/anything/insert?name=fuga
http://localhost:8080/anything/findAll

如果返回以下类似的结果就可以了
※在前两行我们正在向数据库插入数据,在最后一行我们正在获取插入的结果。

[{“id”:1,”name”:”doma”,”createdAt”:1516459862000,”updatedAt”:1516459862000},{“id”:2,”name”:”fuga”,”createdAt”:1516459895000,”updatedAt”:1516459895000}]

[{ “id”:1, “name”:”doma”, “createdAt”: 1516459862000, “updatedAt”: 1516459862000 }, { “id”:2, “name”:”fuga”, “createdAt”: 1516459895000, “updatedAt”: 1516459895000 }]

总结

这次写了关于开始使用Spring Boot开发的第一步。
之所以使用Doma2,是因为我想试试看。
如果有时间,也许会写续集。

最终的代码在这里。

广告
将在 10 秒后关闭
bannerAds