[KotlinWeb]-Spring Boot&Hibernate

1 修改記錄

時間 描述
2017-09-26 建檔
2017-09-27 添加第3-6節
2017-09-29 添加第7節

2 簡單Web項目

  • IDE:Eclipse Neon Release (4.6.0)
  • Builder:Maven (3.3.9)
  • Framwork:Spring Boot

2.1 安裝SpringBoot插件

  在Help -> Eclipse Marketplace -> Popular 下搜索Spring Tools(aka Spring IDE and Spring Tool Suite)並安裝。

2.2 創建Maven項目

  右擊Project Explorer的空白區域,new -> other -> Maven -> Maven Project,archetype選擇webapp。

2.3 添加依賴

  • spring-boot-starter-parent:
  • spring-boot-starter-web:
  • kotlin-stdlib-jre8:
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-stdlib-jre8</artifactId>
        <version>1.1.3</version>
    </dependency>
</dependencies>

2.4 設計Controller

 這裏將啓動的入口和Controller類集合到了一個類裏面,後面的章節會把這兩個分開。

  • @RestController:被註解的類會被Spring視作Controller,且該類下所有被@RequestMapping註解的方法還默認被@ResponseBody註解。即@RestController相當於@Controller和@ResponseBody的組合;
  • @EnableAutoConfiguration:允許Spring Boot根據引用的JAR包推斷並自動配置Beans。
package chngzhen.example

import org.springframework.boot.SpringApplication
import org.springframework.web.bind.annotation.RestController
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.web.bind.annotation.RequestMapping

@RestController
@EnableAutoConfiguration
class WebApplication {

    @RequestMapping("/hello")
    fun Hello(): String {
        return "Hello world!"
    }
}

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

2.5 運行

  運行testController類,在瀏覽器中訪問127.0.0.1:8080/hello。

  注意:地址中沒有項目名稱

3 拋棄POM繼承

  利用Maven管理項目時,通常會出現一個父項目下有多個子模塊的情況,Web項目作爲其中一個子模塊,除了會依賴其他子模塊,還會繼承父項目。這時候,就不能使用第2節中繼承的方法來引入Spring Boot。
  可以將spring-boot-starter-parent作爲依賴放在(父項目的)< dependencyManagement >中,但scope和Type都有明確的規定:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.5.6.RELEASE</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

  然後在Web子模塊中,按需求聲明spring-boot-starter-parent中的依賴。例如,聲明引入spring-boot-starter-web:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

4 分離啓動類和控制器

  將第2節的啓動類WebApplication分離出來,放在chngzhen.web.mvc.starter包下。

package chngzhen.web.mvc.starter

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@EnableAutoConfiguration
@ComponentScan(basePackages=arrayOf("chngzhen.web.mvc"))
class WebApllication

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

  將Controller放到chngzhen.web.mvc.controller包下:

package chngzhen.web.mvc.controller

import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class LoginingController {

    @RequestMapping("/register")
    fun register(): String {
        return "register"
    }
}

  重新運行WebApplication,訪問127.0.0.1:8080/register。

5 返回視圖

  上面的Controller返回的都是內容,而不是視圖。
  首先,添加register視圖文件。Spring Boot和標準Spring框架對視圖文件的存放位置要求不盡相同。spring Boot默認要求視圖文件存放在classpath*:/templates/下,但可以重新指定。現在在src/main/resources下新建一個/templates/public文件夾,並在裏面添加了一個register.html文件;
  然後,返回register.html。@RestController註解的Controller返回的都是內容,要想返回視圖,需要創建ModelAndView實例並返回:

package chngzhen.web.mvc.controller

import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.servlet.ModelAndView

@RestController
class LoginingController {

    @RequestMapping("/register")
    fun register(): ModelAndView {
        println("Enter the register Method")
        return ModelAndView("/public/register")
    }
}

  運行WebApplication,然後訪問127.0.0.1:8080/register會報404的錯誤,但控制檯的確輸出了“Enter the register Method”。那是因爲沒有添加模板引擎。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

5.1 拋棄ModelAndView

  像在標準Spring框架中那樣,直接返回字符串,視圖解析器自動添加前綴和後綴後將視圖返回給前端。
  首先,取消@RestController註解,改用@Controller:

package chngzhen.web.mvc.controller

import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.servlet.ModelAndView
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.ResponseBody

@Controller
class LoginingController {

    @RequestMapping("/hello")
    @ResponseBody
    fun hello(): String {
        return "hello"
    }

    @RequestMapping("/register")
    fun register(): String {
        return "register"
    }
}

  然後,在src/main/resources下新建一個application.properties文件,利用spring.thymeleaf.prefix指定視圖文件的路徑,spring.thymeleaf.suffix指定視圖文件的後綴名:

spring.thymeleaf.prefix=classpath:/templates/public/
spring.thymeleaf.suffix=.html

運行訪問。

6 訪問靜態文件

  Spring Boot默認攔截/**格式的請求,並映射到”classpath:/META-INF/resources/”、 “classpath:/resources/”、”classpath:/static/”和 “classpath:/public/”四個路徑下。即攔截所有請求,然後去以上四個地址下按URL尋找靜態資源。
  在src/main/resources下新建一個static文件夾,向裏面添加一個1.jpg圖片文件。然後在瀏覽器中輸入127.0.0.1:8080/1.jpg訪問。

6.1 自定義

  靜態文件的請求URL格式和映射路徑是通過org.springframework.boot.autoconfigure.web.WebMvcProperties中的staticPathPattern與org.springframework.boot.autoconfigure.web.ResourceProperties中的staticLocations指定的。這兩個屬性均可以在application.properties中設置:

spring.mvc.static-path-pattern=/assets/**
spring.resources.static-locations=classpath:/templates/assets/

  將圖片放在src/main/resources/templates/assets下,在瀏覽器中輸入127.0.0.1:8080/assets/1.jpg訪問。

6.2 HTML引用

  在HTML中引用靜態文件時無須指定IP、端口和項目名稱:

<link rel="stylesheet" href="/assets/plugins/bootstrap/css/bootstrap.min.css"/>
<style type="text/css">
    .icontainer{
        background:url(/assets/images/bg002.jpg);
    }
</style>
<script src="/assets/plugins/jquery/jquery-3.2.1.min.js"></script>

7 數據庫訪問

7.1 添加依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
錯誤 方案
At least one JPA metamodel must be present! 可能是缺少了spring-boot-devtools依賴

7.2 實體類

package chngzhen.web.mvc.model.domain

import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.persistence.Table
import javax.persistence.Transient

@Entity
@Table(name="user_info")
class UserInfo() {
    companion object{
        // Alias Begin
        val ALIAS_ID = "ID"
        val ALIAS_USER_NAME = "用戶賬號"
        val ALIAS_USER_PSWD = "登陸密碼"
        val ALIAS_REGISTER_TIME = "註冊時間"
    }

    // Property Begin
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private var id: Int? = null

    @Column(name="user_name")
    private var userName: String? = null

    @Column(name="user_pswd")
    private var userPswd: String? = null

    @Column(name="register_time")
    private var registerTime: java.util.Date? = null

    @Transient
    private var registerTimeString: String? = null

    // Getter/Setter Begin
    fun getId() = id

    fun setId(id: Int) {
        this.id = id
    }

    fun getUserName() = userName

    fun setUserName(userName: String) {
        this.userName = userName
    }

    fun getUserPswd() = userPswd

    fun setUserPswd(userPswd: String) {
        this.userPswd = userPswd
    }

    fun getRegisterTime() = registerTime

    fun setRegisterTime(registerTime: java.util.Date) {
        this.registerTime = registerTime;
        this.registerTimeString = getRegisterTimeString()
    }

    fun getRegisterTimeString(): String? = 
        if (null == registerTime) null
        else java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(registerTime)

    fun setRegisterTimeString(registerTimeString: String) {
        setRegisterTime(java.text.SimpleDateFormat().parse(registerTimeString))
    }
}

7.3 數據庫操作接口

package chngzhen.web.mvc.service

import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository

import chngzhen.web.mvc.model.domain.UserInfo
import org.springframework.beans.factory.annotation.Qualifier
import javax.persistence.Table

@Repository
interface UserInfoService: CrudRepository<UserInfo, Int> {

    fun getById(id: Int): UserInfo
}

7.4 調用

package chngzhen.web.mvc.controller

import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.servlet.ModelAndView
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.beans.factory.annotation.Autowired

import chngzhen.web.mvc.service.UserInfoService

@Controller
class LoginingController {

    @Autowired
    lateinit var userInfoService: UserInfoService

    @RequestMapping("/register")
    fun register(): String {
        println(userInfoService.getById(1).getUserName())
        return "register"
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章