1. 程式人生 > >手把手教你從零開始搭建SpringBoot後端專案框架

手把手教你從零開始搭建SpringBoot後端專案框架

原料

新鮮的IntelliJ IDEA、一雙手、以及電腦一臺。

搭建框架

新建專案

開啟IDE,點選File -> New Project。在左側的列表中的選擇Maven專案,點選Next。

填寫GroupId和ArtifactId

什麼是GroupId和ArtifactId?大家可以參考一下google出來的定義,可以參考一下。

<!--more-->

GroupID是專案組織唯一的識別符號,實際對應JAVA的包的結構,是main目錄裡java的目錄結構。

ArtifactID就是專案的唯一的識別符號,實際對應專案的名稱,就是專案根目錄的名稱

簡單理解一下,可以理解為GroupId就是你的Github賬號,而ArtifactId就是你的具體某個專案,例如這個例子的原始碼,SpringBootDemo,

detectiveHLH/springbootdemodetectiveHLH就是GroupId,而ArtifactId就是後面的專案名稱。

所以,這裡應該填寫如下(僅供參考)。

GroupId: com.detectivehlh.test
ArtifactId: parent

test為專案的名稱。ArtifactId代表父類,所以就寫parent了。點選Next。

設定Project Name和Project Location

ProjectName就寫專案的名稱就好。Project Location就是專案在你本地的真實路徑。填好之後,點選Next。

然後可以看到IDE已經新建好了專案。

.
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   └── resources
│   └── test
│       └── java
└── test.iml

然後右下角會彈出Maven projects need to be imported,選擇右邊的Enable Auto-Imported.然後刪除src目錄。

新建模組

本次專案的框架一共有四層結構,也可以說是有四個模組。分別是api、core、data、domain.我們從底層開始,自底向上開始構建模組。

domain

存放實體類

點選File -> New -> Module,在左側的列表中選擇Maven,點選Next。在ArtifactId處填 domain,一路Next。

data模組

主要是做一些對資料庫的操作

點選File -> New -> Module,在左側的列表中選擇Maven,點選Next。在ArtifactId處填 data,一路Next。在模組中其實是存在相互依賴關係的。data模組依賴domain模組的實體。所以要在data檔案的配置檔案中實現對domain的依賴。

開啟data目錄中的pom.xml檔案。在<artifactId>下,新增如下程式碼。

<dependencies>
    <dependency>
        <groupId>com.detectivehlh.test</groupId>
        <artifactId>domain</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

core模組

後端主要的業務邏輯都會在core模組中。

點選File -> New -> Module,在左側的列表中選擇Maven,點選Next。在ArtifactId處填 core,一路Next。同上,此處也需要配置依賴關係。core模組的中的service會依賴data模組中的資料。

開啟core目錄下的pom.xml檔案。在<artifactId>下,新增如下程式碼。

<dependencies>
    <dependency>
        <groupId>com.detectivehlh.test</groupId>
        <artifactId>data</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

api模組

主要是存放供前端呼叫的介面。

點選File -> New -> Module,在左側的列表中選擇Maven,點選Next。在ArtifactId處填 api,一路Next。此處的api模組依賴core中的service服務。

開啟api目錄下的pom.xml檔案。在<artifactId>下,新增如下程式碼。

<dependencies>
    <dependency>
        <groupId>com.detectivehlh.test</groupId>
        <artifactId>core</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

讓專案"走兩步"

到此,框架算是搭建好了,下一步就是要讓專案"走兩步"來看看。此時的專案的目錄如下。

.
├── api
│   ├── api.iml
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── java
│       │   └── resources
│       └── test
│           └── java
├── core
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── java
│       │   └── resources
│       └── test
│           └── java
├── data
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── java
│       │   └── resources
│       └── test
│           └── java
├── domain
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── java
│       │   └── resources
│       └── test
│           └── java
├── pom.xml
└── test.iml

定位到/api/src/main/java,在java目錄下新建package,名字為你之前定義的groupid再加上模組名,舉個例子。我這的名字就應該為com.detectivehlh.test.api,然後在該包下新建名為Application的class。然後將程式碼替換成如下程式碼。

package com.detectivehlh.test.api;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

此時會報錯,是因為springboot的各項依賴,都還沒有引入專案的dependences。開啟根目錄下的pom.xml檔案,新增如下依賴。

 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.4.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

然後開啟api目錄下的pom.xml檔案。在dependencies標籤中新增如下依賴。

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

此時Application中就不會報錯了。然後就可以啟動專案了。開啟Application這個類,在SpringBootApplication註解下有個綠色的啟動鍵,點選即可啟動專案。之後可在右上方啟動。

Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback.

Tue Sep 18 19:01:11 CST 2018

There was an unexpected error (type=Not Found, status=404).
No message available

那麼一個簡單的springboot應用就可以啟動成功了。

實現controller層

com.detectivehlh.test.api包下,新建一個名為controller的包。然後新建名為HelloController的class。將其全部替換為如下程式碼(包名根據你的專案命名自行修改)。

package com.detectivehlh.test.api.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello, SpringBoot";
    }
}

重新啟動專案,訪問http://localhost:8080/hello,就可以看到頁面顯示如下資訊。

Hello, SpringBoot

@RestController註解比較適用於Restful風格的API,如果介面只關心資料,不做server render,就可以使用@RestController註解。如果介面需要返回模版頁面,則需要使用@Controller註解。

@GetMapping註解,是將HTTP Get請求對映到我們自定義的hello方法上。

實現service層

新建CoreConfiguration

定位到/core/src/main/java,在java目錄下新建名為com.detectivehlh.test.core的包。然後在該包新建名為CoreConfiguration的Class。將其全部替換為如下程式碼(包名根據你的專案命名自行修改)。

package com.detectivehlh.test.core;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author detectiveHLH
 * @date 2018/09/13
 */
@ComponentScan
@Configuration
public class CoreConfiguration {

}

引入依賴

此時會報錯,同樣是因為依賴沒有引入。在core的pom.xml檔案中的dependencies標籤中新增如下依賴。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

稍等片刻,就不會有報錯提示了。

新建Interface

在com.detectivehlh.test.core包下新建一個名為service的包。在service包下新建一個Class,名字為HelloService,型別選擇Interface。然後修改程式碼如下(包名根據你的專案命名自行修改)。

package com.detectivehlh.test.core.service;

public interface HelloService {
    String sayHello();
}

新建實現類

在service目錄下新建名為impl的包。然後在impl下新建名為HelloServiceImpl的類。修改程式碼如下(包名根據你的專案命名自行修改)。

package com.detectivehlh.test.core.service.impl;

import com.detectivehlh.test.core.service.HelloService;
import org.springframework.stereotype.Service;

@Service
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello() {
        return "Hello, SpringBoot";
    }
}

呼叫實現類

修改HelloController中的 hello 方法的程式碼如下(包名根據你的專案命名自行修改)。

package com.detectivehlh.test.api.controller;

import com.detectivehlh.test.core.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * RestController
 * 定義為Restful風格的API控制器
 */
@RestController
public class HelloController {
    @Autowired
    private HelloService helloService;
    
    @GetMapping("/hello")
    public String hello() {
        return helloService.sayHello();
    }
}

此時helloService會報錯,這是因為我們沒有將HelloService這個新增到Bean容器中來。修改Application類程式碼如下(包名根據你的專案命名自行修改)。

package com.detectivehlh.test.api;

import com.detectivehlh.test.core.CoreConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@Import(CoreConfiguration.class)
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

此時再訪問http://localhost:8080/hello,就可以看到如下正常的輸出了。

Hello, SpringBoot

打通資料庫

實現了簡單的service,下一步就是要連線資料庫。假設現在在你本地已經有了mysql服務。有名為test的資料庫,該資料庫下有名為user_role的表。表結構如下。

資料庫表名和表資料

column_name column_value
id 使用者id
name 使用者名稱

並且有了資料

column_name column_value
id name
1 detectiveHLH

新建實體類

定位到/domain/src/main/java,在java目錄下新建名為com.detectivehlh.test.domain的包。在該包下新建entity包。在entity下新建名為BaseEntity的抽象類。修改程式碼如下。

package com.detectivehlh.test.domain.entity;

public abstract class BaseEntity {

    private long createdAt;

    private String createdBy;

    private long updatedAt;

    private String updatedBy;

    public long getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(long createdAt) {
        this.createdAt = createdAt;
    }

    public String getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(String createdBy) {
        this.createdBy = createdBy;
    }

    public long getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(long updatedAt) {
        this.updatedAt = updatedAt;
    }

    public String getUpdatedBy() {
        return updatedBy;
    }

    public void setUpdatedBy(String updatedBy) {
        this.updatedBy = updatedBy;
    }
}

在entity下新建名為UserRole的類。程式碼如下。

package com.detectivehlh.test.domain.entity;

public class UserRole extends BaseEntity {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

新建dao層

實現與資料庫互動的mapper。

定位到/data/src/main/java,在java目錄下新建名為com.detectivehlh.test.data的包。在該包下新建名為dao的包和名為DataConfiguration的類。然後在dao包下新建名為UserRoleMapper的類。DataConfiguration程式碼如下。

package com.detectivehlh.test.data;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author duzhengkang
 * @date 2018/6/25
 */
@ComponentScan
@Configuration
@MapperScan("com.detectivehlh.test.data.dao")
public class DataConfiguration {

}

將UserRoleMapper的程式碼修改為如下。

package com.detectivehlh.test.data.dao;

import com.detectivehlh.test.domain.entity.UserRole;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
@Repository
public interface UserRoleMapper {
    /**
     * 查詢所有的使用者角色
     * @return
     */
    List<UserRole> all();
}

此時程式碼會報錯,同樣的依賴原因。開啟根目錄下的pom.xml檔案。新增如下依賴。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.10</version>
</dependency>
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.5</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>6.0.6</version>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

新增如上依賴,稍等片刻,就不會報錯了。但是此時執行專案依舊會報錯。是因為我們引入了mybatis但是卻沒有配置檔案。以及沒有將mapper注入到容器中去。

修改Application中的程式碼如下。

package com.detectivehlh.test.api;

import com.detectivehlh.test.core.CoreConfiguration;
import com.detectivehlh.test.data.DataConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@Import({CoreConfiguration.class, DataConfiguration.class})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

mapper就被注入到容器中去了。下一步需要新增配置檔案。定位到/api/src/main/resources,新建application.yaml檔案。修改程式碼如下。

spring:
  application:
    name: test
# 資料庫配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 9687Luohongwei
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
# mapper檔案配置
mybatis:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

修改完畢後,啟動專案,訪問http://localhost:8080/hello,就可以看到正常輸出了。

實現mapper

定位到/data/src/main/resources,新建名為mapper的包。在mapper包下新建名為UserRoleMapper的xml檔案。修改程式碼如下。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.detectivehlh.test.data.dao.UserRoleMapper">
    <!--用於與資料庫欄位作一一對應-->
    <resultMap id="userRoleMap" type="com.detectivehlh.test.domain.entity.UserRole">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
    </resultMap>

    <!--查詢下方列出的所有列-->
    <sql id="allColumns">
        id, name
    </sql>

    <!--定義表名-->
    <sql id="tableName">
        user_role
    </sql>

    <select id="all" resultMap="userRoleMap">
        SELECT
        <include refid="allColumns"/>
        FROM
        <include refid="tableName"/>
        ORDER BY id DESC
    </select>

</mapper>

一定注意namespace是否準確。

呼叫mapper

修改實現類HelloServiceImpl程式碼如下。

package com.detectivehlh.springbootdemo.core.service.impl;

import com.detectivehlh.springbootdemo.core.service.HelloService;
import com.detectivehlh.springbootdemo.data.dao.UserRoleMapper;
import com.detectivehlh.springbootdemo.domain.entity.UserRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class HelloServiceImpl implements HelloService {
    @Autowired
    private UserRoleMapper userRoleMapper;

    @Override
    public List<UserRole> createToken(String key) {
        List<UserRole> data = userRoleMapper.all();
        return data;
    }
}

此時會報錯,是因為實現類中的返回型別已經變成了List<UserRole>,而介面中的返回值還是String型別的。所以只需要修改HelloService程式碼如下即可。

package com.detectivehlh.test.core.service;

import com.detectivehlh.test.domain.entity.UserRole;
import java.util.List;

public interface HelloService {
    List<UserRole> sayHello();
}

讓我們回到controller中,我們發現在HelloController中也有報錯。這個錯誤同樣也是因為返回型別不一致的原因,修改程式碼如下。

package com.detectivehlh.test.api.controller;

import com.detectivehlh.test.core.service.HelloService;
import com.detectivehlh.test.domain.entity.UserRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * RestController
 * 定義為Restful風格的API控制器
 */
@RestController
public class HelloController {
    @Autowired
    private HelloService helloService;

    @GetMapping("/hello")
    public List<UserRole> hello() {
        return helloService.sayHello();
    }
}

然後啟動專案,訪問http://localhost:8080/hello。就可以看到,介面返回了user_role表中的所有資料。

[
    {
        "createdAt": 0,
        "createdBy": null,
        "updatedAt": 0,
        "updatedBy": null,
        "id": 1,
        "name": "Tom"
    }
]

此時雖然能夠正常訪問,但是會在控制檯報如下警告。

Tue Sep 18 20:40:22 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

在com.detectivehlh.test.api包下新建config包,在config包中新建DbConfig檔案。程式碼如下。

package com.detectivehlh.test.api.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
 * DbConfig
 *
 * @author detectiveHLH
 * @date 2018-07-27 10:35
 **/
@Configuration
@ConfigurationProperties
@EnableTransactionManagement
public class DbConfig {
    @Bean
    @ConfigurationProperties("spring.datasource")
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        return dataSource;
    }
    @Bean
    public JdbcTemplate jdbcTemplate(){
        return new JdbcTemplate(dataSource());
    }
    @Bean
    public PlatformTransactionManager transactionManager(){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource());
        return dataSourceTransactionManager;
    }
}

重啟啟動專案,訪問介面時就不會有警告了。

最後的程式碼目錄結構如下。

.
├── api
│   ├── api.iml
│   ├── pom.xml
│   ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   │   └── com
│   │   │   │       └── detectivehlh
│   │   │   │           └── test
│   │   │   │               └── api
│   │   │   │                   ├── Application.java
│   │   │   │                   ├── config
│   │   │   │                   │   └── DbConfig.java
│   │   │   │                   └── controller
│   │   │   │                       └── HelloController.java
│   │   │   └── resources
│   │   │       └── application.yml
│   │   └── test
│   │       └── java
│   └── target
│       ├── classes
│       │   ├── application.yml
│       │   └── com
│       │       └── detectivehlh
│       │           └── test
│       │               └── api
│       │                   ├── Application.class
│       │                   ├── config
│       │                   │   └── DbConfig.class
│       │                   └── controller
│       │                       └── HelloController.class
│       └── generated-sources
│           └── annotations
├── core
│   ├── pom.xml
│   ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   │   └── com
│   │   │   │       └── detectivehlh
│   │   │   │           └── test
│   │   │   │               └── core
│   │   │   │                   ├── CoreConfiguration.java
│   │   │   │                   └── service
│   │   │   │                       ├── HelloService.java
│   │   │   │                       └── impl
│   │   │   │                           └── HelloServiceImpl.java
│   │   │   └── resources
│   │   └── test
│   │       └── java
│   └── target
│       ├── classes
│       │   └── com
│       │       └── detectivehlh
│       │           └── test
│       │               └── core
│       │                   ├── CoreConfiguration.class
│       │                   └── service
│       │                       ├── HelloService.class
│       │                       └── impl
│       │                           └── HelloServiceImpl.class
│       └── generated-sources
│           └── annotations
├── data
│   ├── pom.xml
│   ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   │   └── com
│   │   │   │       └── detectivehlh
│   │   │   │           └── test
│   │   │   │               └── data
│   │   │   │                   ├── DataConfiguration.java
│   │   │   │                   └── dao
│   │   │   │                       └── UserRoleMapper.java
│   │   │   └── resources
│   │   │       └── mapper
│   │   │           └── UserRoleMapper.xml
│   │   └── test
│   │       └── java
│   └── target
│       ├── classes
│       │   ├── com
│       │   │   └── detectivehlh
│       │   │       └── test
│       │   │           └── data
│       │   │               ├── DataConfiguration.class
│       │   │               └── dao
│       │   │                   └── UserRoleMapper.class
│       │   └── mapper
│       │       └── UserRoleMapper.xml
│       └── generated-sources
│           └── annotations
├── domain
│   ├── pom.xml
│   ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   │   └── com
│   │   │   │       └── detectivehlh
│   │   │   │           └── test
│   │   │   │               └── domain
│   │   │   │                   └── entity
│   │   │   │                       ├── BaseEntity.java
│   │   │   │                       └── UserRole.java
│   │   │   └── resources
│   │   └── test
│   │       └── java
│   └── target
│       ├── classes
│       │   └── com
│       │       └── detectivehlh
│       │           └── test
│       │               └── domain
│       │                   └── entity
│       │                       ├── BaseEntity.class
│       │                       └── UserRole.class
│       └── generated-sources
│           └── annotations
├── pom.xml
└── test.iml

寫在後面

寫的比較詳細,如果有不對的地方,大佬儘管懟。本專案的原始碼在 這裡

個人部落格在 這裡

Github在 這裡,歡迎star或follow。