快速開發架構Spring Boot 從入門到精通 附源碼


導讀

  篇幅較長,干貨十足,閱讀需花費點時間。珍惜原創,轉載請注明出處,謝謝!

Spring Boot基礎

Spring Boot簡介

  Spring Boot由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Spring Boot致力於在蓬勃發展的快速應用開發領域(rapid application development)成為領導者。

  簡單來說,SpringBoot可以簡化應用程序的開發,使我們再需要spring配置文件及web.xml

SpringBoot工程和創建

IDEA中的創建

工程編輯

  系統會在前面設置的包中自動生成一個啟動類

  在啟動類所在的包下創建一個子包,在其中編寫SpringMvc的處理器類。

  注意,要求代碼所在的包必須啟動類所在的包的子孫寶不能是同級包。 

啟動

ide方式

mac控制台方式(需maven打包)

官網創建

地址:https://start.spring.io/

配置及生成

  配置項配置完成后,點擊Generate按鈕后,即可打開一個下載對話框。官網將配置好的Spring Boot工程生成一個zip壓縮文件,只要我們將下載后的文件解壓並添加到工程即可使用

基於war的Spring Boot工程

  前面2種方式創建的Spring Boot工程最終被打為了jar包,是以可執行文件的形式出現的,他們都使用了Spring Boot內嵌的Tomcat作為web服務器來運行web應用的。新版的Dubbo的監控中心工程就是典型的應用。但在實際生產環境下,對於web工程,很多時候我們需要的是war包,然后部署到企業級web服務器中。下面來演示如何使用Spring Boot將工程打為war包。

工程創建

我們看一下pom.xml文件,可以知道,Tomcat打包的時候不打進去

將項目打包后,仍到Tomcat的wabapps目錄下

啟動Tomcat

接下來我們查看Tomcat目錄

打開網頁,注意加上項目名

 

注:mac啟動Tomcat過程中遇到點麻煩,1、需要賦予文件夾權限;2、執行shell腳本報錯:Operation not permitted,博主參考了下面2個鏈接配成成功噠

大概配置步驟

1、切換Tomcat的bin目錄下
    sudo chmod 755 *.sh

2、解決Operation not permitted
    xattr -d com.apple.quarantine ./*

3、啟動Tomcat
    sudo sh ./startup.sh

4、停止Tomcat
  sudo sh ./shutdown.sh
參考鏈接: 注:第一、二鏈接,賦權限,第三個鏈接解決Operation not permitted

https://blog.csdn.net/caoxiaohong1005/article/details/53463443

https://blog.csdn.net/F_Feng0628/article/details/60583250

https://blog.csdn.net/default7/article/details/80172340

工程解析

   創建Spring Boot工程后,會自動生成工程的啟動類Application

   跟蹤@SpringBootApplication注解源碼可以看到,可以完成Spring Boot的自動配置

   繼續跟蹤@SpringBootConfiguration源碼可以看到,其本質是一個@Configuration,使用Java類充當Spring配置文件

 src/main/resources目錄

  1. static:存放靜態資源,如:css,js,images等 
  2. templates目錄:存放動態資源。Spring Boot不建議使用jsp作為動態數據展示頁面,而是建議使用ThymeleafThymeleaf是一種Java模板引擎,可以顯示動態數據。Thymeleaf文件的擴展名為html,是對html的擴展。該目錄用於存放Thymeleaf文件。
  3. 兩個目錄中存放的資源相當於存放當前web應用的根下。一般不適用他們存放資源。
  4. application.properties:SpringBoot的主配置文件

查看當前工程

  在pom.xml文件中包含SpringBoot兩個核心依賴一個核心插件一個是SpringBoot的Web啟動依賴一個是SpringBoot的測試啟動依賴;而這個核心插件是用於完成對SpringBoot工程打包結果的再打包

  注:他們都沒有版本號,這是為什么呢?

   雖然他們都沒有版本號,打開maven可以看到,他們版本均為2.2.2

   他們的版本號均繼承自父工程。從pom文件中可以看到,其父工程spring-boot-starter-parent

更換默認springframework的版本(視生產環境降默認版本)

查看spring-boot-starter-parent工程

  打開Maven本地倉庫,在org.springframework中找到工程spring-boot-starter-parent。

打開spring-boot-starter-parent-2.2.2.RELEASE.pom文件,發現該工程的<pluginManagement>中有對該插件的配置信息。

注:<pluginManagement>中聲明的插件是選擇性繼承插件,而非全部繼承插件。

    從該插件的配置信息可以得出,其執行的目標是repackage,即對工程進行重新打包。

  首次打包是由Maven的package插件完成,其打包的結果僅僅是將當前工程中自定義的類打包成了一個普通的jar包,沒有Spring Boot的相關資源,無法直接運行。當然,其打包的結果是.jar文件。

  重新打包是由spring-boot-maven-plugin插件完成的,其實將前面打成的jar包進行了二次打包,將原來的軟件包變為了Spring Boot可執行包,在其中不僅添加了Spring Boot依賴,還添加了很多其他配置。同時,其還將原來的.jar文件擴展名變為了.orininal,而而二次打包后的文件擴展名成為了.jar。

  可以打開01-primary-0.0.1-SNAPSHOT.jar

BOOT-INF目錄:存的是當前應用程序的類及其所依賴的類

META-INF目錄:存的是Maven相關的配置文件

org目錄:存的是SpringBoot啟動所需的類

  打開META-INF/MANIFEST.MF,不僅可以看到主類Main-Class,還可以看到當前工程的啟動類Start-Class。

maven打包

Spring Boot熱部署

  idea中的Spring Boot工程若要使用熱部署,需要2不操作:

  1. 導入devtools依賴
  2. 編輯工程的配置信息

  注:Spring Boot工程在idea和Eclipse中的重啟時機不同。Eclipse只要修改的文件保存過了,工程會立馬重新部署。而idea則對文件修改后的保存是自動的,所以其重新部署的時機是idea整個ide窗口被鈍化時,即窗口切換到其他窗口時,工程會重新部署。

添加依賴

pom.xml

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

配置

  當idea被鈍化時,即當idea窗口被切換時,更新類與資源。

  在開發調試過程中,已經啟動了工程的運行。此時又修改了代碼或配置文件,若要使修改生效,則需要重新啟動工程。這種方式降低了開發效率。

  熱部署,即修改了代碼或配置文件后,一旦保存,系統馬上對工程進行自動重啟,無需手工重啟。若要實現熱部署,只需要在pom.xml中添加一個依賴即可。

  熱部署的使用有利有弊。利:無需手動重啟工程;弊:在修改代碼或配置后,只要保存系統就會重啟工程,即使這個修改還未完畢,其他的會重啟,從而導致代碼重啟后報錯。

1、添加依賴

pom.xml

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

2、設置自動生成項目

3、Ctrl+Shift+A,打開搜索框,輸入:Registry

4、勾選即可 

Spring Boot主配置文件

配置文件形式一

  Spring Boot的主配置文件是src/main/resources中默認創建的application.properties文件。

 

  編輯配置文件

  啟動

注意事項

   注:這里指定的Tomcat端口號,僅僅只針對內置Tomcat的,是測試時使用的。將工程打為war包后部署到真正的Tomcat,這些配置是不起作用的。

配置文件形式二

  Spring Boot的主配置文件也可以使用application.yml文件。.yml也可以寫成.yaml

  在開發之初YAML的本意是Yet Another Markup Language(仍是一種標記語言)。后來為了強調這種語言是以數據為中心,而不是以標記為中心,所以將標記為中心,所以將YAML解釋為Yaml Ain't Markup Language(Yaml不是一種標記語言)。它是一種直觀的能夠被電腦識別的數據序列化格式,是一個可讀性高並且容易被人閱讀,容易和腳本語言交互,用來表達多級資源序列的編程語言。

  yml與properties文件的主要區別是對於多級屬性,即key的顯示方式不同。yml文件在輸入時,只需按照點(.)的方式輸出key既可,輸入完畢后回車即出現了如下形式。該形式要求冒號后與值之間有一個空格(語法格式)。

 注意事項

  注:application.properties與application.yml這兩個文件只能有一個。要求文件名必須是:application。

Actuator

  Actuator是Spring Boot提供的對應用系統的自省和監控的集成功能,可以對應用系統進行配置查看、相關功能統計等。在Spring Colud中主要是完成微服務的監控,完成監控治理。可以查看微服務間的數據處理和調用,當它們之間出現異常,就可以快速定位到出現問題的地方

  其功能與Dubbo的監控中心類似,不同的是,Dubbo的監控中心是需要專門部署的,而Spring Boot的Actuator是存在於每個工程中。

環境搭建

  隨便一個Spring Boot工程中都可以使用Actuator對其進行監控。

添加依賴

pom.xml

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

修改配置文件

application.properties

# 當前應用的端口與上下文路徑
server.port=8888
server.servlet.context-path=/cyb

# Actuator監控的端口號與上下文路徑
management.server.port=9999
management.server.servlet.context-path=/cyb2

# 指定監控終端的基本路徑,默認為actuator
management.endpoints.web.base-path=/base

啟動項目並測試

添加Info信息

修改配置文件

  在配置文件中添加如下Info信息,則可以通過Info控制終端查看到。

測試

注:博主瀏覽器安裝了JSON格式化工具,所以顯示的是JSON格式化后的狀態

開發其他監控終端

  默認情況下,Actuator僅開放了health與Info兩個監控終端,但它還有很多終端可以監控,需手動開放。

修改配置文件

mappings終端

  mappings可以看到當前工程中所有的URI與處理器映射關系,及詳細的處理器方法以及其映射規則。很實用!!!

beans終端

evn終端

  可以到當前應用程序運行主機的所有軟硬件環境信息

單獨關閉某些監控終端

  在開放了所有監控終端的情況下,有些終端顯示的信息並不想公開,此時可以單獨關閉這些終端。

修改配置文件

測試

  其他的監控終端不受影響。

其他常用的監控終端如下

  若沒有你需要的,可以自行百度搜“springboot actuator”

Spring Boot重要用法

自定義異常頁面

  對於404、405、500等異常頁面,而這些異常頁面一般都是英文的,非常不友好。我們可以通過簡單方式使用自定義異常頁面,並將默認狀態碼頁面進行替換

定義目錄

  在src/main/resources目錄下新建目錄:public/error。

定義異常頁面

  在error目錄定義異常頁面。這些異常頁面的名稱必須為相應的狀態碼,擴展名為html。

單元測試

添加依賴

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

接口類

ISomeService.java

package com.cyb.webdemo.controller;

public interface ISomeService {
    void doSome();
}

接口實現類

SomeServiceImpl.java

package com.cyb.webdemo.controller;

import org.springframework.stereotype.Service;

@Service
public class SomeServiceImpl implements ISomeService{
    @Override
    public void doSome() {
        System.out.println("執行Service的doSome");
    }
}

測試類

  類上需添加兩個注解:

    1、@RunWith(SpringRunner.class)

    2、@SpringBootTest(classes = Spring Boot啟動類.class)

多環境選擇

什么是多環境選擇?

  在開發應用時,通常同一套程序運行多個環境,例如,開發、測試、生產環境等。每個環境的數據庫地址、服務器端口號等配置都會不同。若在不同環境下運行時將配置文件修改為不同內容。那么,這種做法不僅非常繁瑣,而且很容易發生錯誤

  在開發應用時,有時不同的環境,其需要運行的接口的實現類也是不同的。例如,若要開發一個具有短信發送功能的應用,開發環境中要執行的send()方法僅需要調用短信模擬器即可,而生產環境中要執行的send()則需要調用短信運營商所提供的短信發送接口。這種情況下,就需要開發兩個相關接口的實現類去實現send()方法。

  不同的環境,需使用不同的配置文件執行不同的類。而這個選擇只需要Spring Boot的主配置文件中指定即可

  下面以不同環境使用配置有不同的端口號的配置文件,以及調用不同的接口實現類”為例演示多環境選擇問題的解決。

Example

1、創建幾個配置文件,格式:application-xxxxx.properties

2、創建一個包,並創建一個接口,內容如下

2、創建DevMsgServiceImpl開發環境類

注:@Profile("xxx")中的值要和application-xxx.properties對應上

3、創建ProMsgServiceImpl生產環境

注:@Profile("xxx")中的值要和application-xxx.properties對應上

4、創建處理器:MsgController

5、測試

正確請求

錯誤請求

說明

  在Spring Boot中多環境配置文件名需滿足application-[profile].properties格式,其中[profile]為對應的環境標識,例如

  1. application-dev.properties:開發環境
  2. application-pro.properties:生產環境

  至於那個配置文件會被加載取決於application.properties中的spring.profiles.active屬性來設置,其值對應[profile]。例如spring.profiles.active=dev就會加載application-dev.properties配置文件內容

  在實現類上加@Profile注解,並在注解參數中指定前述配置文件中的[profile]值用於指定該實現類所使用的環境

  以上開發過程中碰到的問題都解決啦~~~~

6、在命令行下選擇環境

  將工程打為Jar包后,在命令行運行。若要想切換運行環境,必須要修改主配置文件嗎?答案是否定的。只需添加一個命令參數即可動態指定。

  例如,現在的主配置文件中指定的是dev環境

   將當前工程打為Jar包后,在命令行運行時添加如下參數

 

  此時執行的就是生產環境,調用的就是ProduceServiceImpl類

讀取自定義配置

  自定義配置,可以是定義在主配置文件:application.properties中的自定義屬性,也可以是自定義配置文件中的屬性。

讀取主配置文件中的屬性

application.properties

SomeController.java

實現

讀取指定配置文件中的屬性

創建配置文件:cybApplication.properties

SomeController.java 

實現 

讀取對象屬性

cybApplication.properties

實體類:cyb.java

說明

  1. @PropertySource:用於指定要讀取的配置文件。
  2. @ConfigurationProperties:用於指定要讀取配置文件中的對象屬性。
  3. @Component:當前從配置文件讀取來的對象,由Spring容器創建。

SomeController.java

實現

讀取List屬性1

cybApplication.properties

實體類:UserName

SomeController.java

實現

讀取List屬性2

cybApplication.properties

Group.java

students.java

SomeController.java

實現

補充知識(lombok)

  lombok方式配置實體類。沒用過的小伙伴,可以參考Lombok介紹、使用方法和總結進行腦補,這里只演示使用

1、idea安裝lombok

2、添加依賴

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

3、實體類上加@Data即可

package com.cyb.webdemo.controller;

import lombok.Data;

@Data
public class studens {
    private String name;
    private int age;

//    public String getName() {
//        return name;
//    }
//
//    public void setName(String name) {
//        this.name = name;
//    }
//
//    public int getAge() {
//        return age;
//    }
//
//    public void setAge(int age) {
//        this.age = age;
//    }
}

注:lombok省去了get/set,讓代碼更簡潔。

Spring Boot下使用JSP頁面

添加JSP解析依賴

pom.xml

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>

創建webapp目錄

  在src/main下建webapp目錄,用於存放jsp文件。創建的是一個普通目錄指定為web資源目錄,然后才可以創建jsp文件。File->Project Structure

添加JSP注冊資源目錄

pom.xml

    <build>
        <resources>
            <!--注冊dao包下mybatis映射文件為資源目錄-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <!--注冊webapp目錄為資源目錄-->
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

創建JSP頁面

實現

 

創建welcome.jsp

創建home.jsp

SomeController.java

實現

關於靜態資源請求

  Spring Boot已經處理好了靜態資源訪問問題。

視圖前/后綴

Spring Boot中使用MyBatis

添加依賴項

MyBatis與Spring Boot整合依賴

pom.xml

        <!--Mybatis與Spring Boot整合依賴,必須要版本號-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

MySql驅動依賴

pom.xml

        <!--mysql驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

Druid連接池依賴

pom.xml

        <!--Druid連接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

lombok依賴(可忽略,用於實體類)

pom.xml

        <!--lombok依賴-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

  注:若使用lombok需配置ide。

注冊資源目錄文件

pom.xml

    <build>
        <resources>
            <!--注冊dao包下mybatis映射文件為資源目錄-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <!--注冊webapp目錄為資源目錄-->
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

  注:若不注冊dao包下的mybatis映射文件,需將xxx.xml文件放到:/resource,並且修改application.properties文件中的mybatis.mapper-locations映射路徑!!!!!!!

資源文件

application.properties

# 視圖的前綴和后綴
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

# 注冊映射文件
mybatis.mapper-locations=classpath:com/cyb/webdemo/dao/EmployeeDao.xml
# 注冊實體類別名
mybatis.type-aliases-package=com.cyb.webdemo.bean.EmployeePo
# 注冊數據源類型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 數據庫連接字符串
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/cyb
spring.datasource.username=root
spring.datasource.password=root

創建jsp

index.jsp

實體類(Po)

EmployeePo.java

注意

  案例中使用了lombok依賴(idea中需要配置,可以參考前面講解lombok配置環境方法),所以實體類中可以不設置get/set方法

dao層(數據訪問層)

EmployeeDao.java

EmployeeDao.xml

  注:mybatis映射文件的存放位置!!!!!

代碼拷貝區

package com.cyb.webdemo.dao;

import com.cyb.webdemo.bean.EmployeePo;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface EmployeeDao {
    void insertEmployee(EmployeePo employeePo);
}
<?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.cyb.webdemo.dao.EmployeeDao">
<insert id="insertEmployee">
    insert into employee (name,age) values (#{name},#{age})
</insert>
</mapper>

service層(業務層)

EmployeeService.java(接口)

EmployeeServiceImpl.java(接口實現類)

代碼拷貝區

package com.cyb.webdemo.service;

import com.cyb.webdemo.bean.EmployeePo;

public interface EmployeeService {
    void addEmployee(EmployeePo employee);
}
package com.cyb.webdemo.service;

import com.cyb.webdemo.bean.EmployeePo;
import com.cyb.webdemo.dao.EmployeeDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class EmployeeServiceImpl implements EmployeeService{

    @Autowired(required = false)
    private EmployeeDao dao;
    @Override
    public void addEmployee(EmployeePo employee) {
        dao.insertEmployee(employee);
    }
}

Controller層

package com.cyb.webdemo.controller;

import com.cyb.webdemo.bean.EmployeePo;
import com.cyb.webdemo.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RegisterHandler {
    @Autowired(required = false)
    private EmployeeService service;
    @PostMapping("register")
    public String RegisterHandler(EmployeePo employee){
        service.addEmployee(employee);
        return "ok";
    }
}

掃描dao層(可忽略

數據庫表結構

實現

項目源碼

直接下載

Spring Boot事務支持

步驟

  1. 啟動類上添加@EnableTransactionManagement
    注解,開啟事務
  2. Service實現類方法上加@Transactional
    注解

啟動類

 業務層接口實現類

Spring Boot對日志的控制 

logback日志技術

  Spring Boot中使用日志技術為logback。其與Log4J都出自一人性能優於Log4J,是Log4J的替代者

  在Spring Boot中若要使用logback,則需要具有spring-boot-starter-logging依賴,而該依賴被spring-boot-starter-web依賴,即不用直接導入spring-boot-starter-logging依賴(間接依賴)。

方式一

xml方式

  必須放到src/main/resources類路徑下!!!

代碼拷貝區

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appender name="myConsole" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%-5level - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="WARN">
        <appender-ref ref="myConsole"></appender-ref>
    </root>
    <logger name="com.cyb.webdemo.dao.EmployeeDao" level="DEBUG"></logger>
</configuration>

方式二

application.properties

 

代碼拷貝區

application.properties

# 控制日志顯示格式
logging.pattern.console=%leven %msg%n
logging.level.root=warn
# 格式:logging.level.dao層命名空間
logging.level.com.cyb.webdemo.dao.EmployeeDao=debug

實現

Spring Boot中使用Redis(解決高並發,重點!!)

注意

  案例從頭到尾,使用都是同一個項目,代碼配置結構復雜,看紅色圈中的代碼,敲黑板划重點!!!!!

學前預習

  Redis還不會的小伙伴,請先預習:分布式架構-Redis 從入門到精通 。

應用場景

  使用Redis緩存的數據划分為兩類:

  1. DB表中的數據更新后,Redis緩沖的相關數據要清除,要不然客戶端獲取的不是最新數據。
  2. 對數據准確性要求不高的數據,可以與DB表中的數據不一致,但差別不能太大,所以該類數據一般會設置過期1時效

啟動redis服務器

Spring Boot與Redis整合依賴

完整pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cyb</groupId>
    <artifactId>webdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>webdemo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>13</java.version>
    </properties>

    <dependencies>
        <!--Mybatis與Spring Boot整合依賴,必須要版本號-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!--mysql驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--Druid連接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

        <!--lombok依賴-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--Spring Boot與redis依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <resources>
            <!--注冊dao包下mybatis映射文件為資源目錄-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <!--注冊webapp目錄為資源目錄-->
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

修改主配置文件

application.properties

代碼拷貝區

# 視圖的前綴和后綴
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

# 注冊映射文件
mybatis.mapper-locations=classpath:com/cyb/webdemo/dao/EmployeeDao.xml
# 注冊實體類別名
mybatis.type-aliases-package=com.cyb.webdemo.bean.EmployeePo
# 注冊數據源類型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 數據庫連接字符串
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/cyb
spring.datasource.username=root
spring.datasource.password=root

# 控制日志顯示格式
logging.pattern.console=%leven %msg%n
logging.level.root=warn
# 格式:logging.level.dao層命名空間
logging.level.com.cyb.webdemo.dao.EmployeeDao=debug

# 連接redis
spring.redis.host=192.168.31.200
spring.redis.port=6379
spring.redis.password=root
# 連接redis集群,redis利用哨兵機制實現高可用
# spring.redis.sentinel.master=mymaster
# spring.redis.sentinel.nodes=sentinel1:6370,sentinel2:6371,sentinel3:6372

# 指定緩存類型
spring.cache.type=redis
# 設置緩存名稱
spring.cache.cache-names=realTimeCache

JSP頁面

index.jsp

代碼拷貝區

<%--
  Created by IntelliJ IDEA.
  User: chenyanbin
  Date: 2020/1/6
  Time: 7:13 下午
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="register" method="post">
    姓名:<input type="text" name="name"><br/>
    年齡:<input type="number" name="age"><br/>
    <input type="submit" value="注冊">
</form>
<hr>
<form action="find" method="post">
    id:<input type="text" name="id">
    <input type="submit" value="查詢">
</form>
<a href="count">查看員工總數</a>
</body>
</html>

實體類

EmployeePo.java

數據庫表字段

Dao層(數據訪問層)

EmployeeDao.java

映射文件

EmployeeDao.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.cyb.webdemo.dao.EmployeeDao">
    <insert id="insertEmployee">
    insert into employee (name,age) values (#{name},#{age})
</insert>
    <select id="selectEmployeeById" resultType="com.cyb.webdemo.bean.EmployeePo">
        select id,name,age from employee where id=#{id}
    </select>
    <select id="selectEmployeeCount" resultType="int">
        select count(1) from employee
    </select>
</mapper>

Service(業務層)

EmployeeService.java(接口)

EmployeeServiceImpl.java(接口實現類)

  注:雙重檢測鎖非常重要!!!!

代碼拷貝區

package com.cyb.webdemo.service;
import com.cyb.webdemo.bean.EmployeePo;
import com.cyb.webdemo.dao.EmployeeDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.TimeUnit;
@Service
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired(required = false)
    private EmployeeDao dao;
    @CacheEvict(value = "realTimeCache", allEntries = true)
    // 清除緩存,實際生產環境就這樣玩,因為每個實體類設置不同的緩存區空間,范圍小,清除緩存好操作
    @Transactional
    @Override
    public void addEmployee(EmployeePo employee) {
        dao.insertEmployee(employee);
    }
    @Cacheable(value = "realTimeCache", key = "'employee_'+#id")
    // 先會去緩存中查下key是否存在,存在:則直接拿緩存中的數據;不存在:去數據庫中查,查完將結果放入緩存中
    @Override
    public EmployeePo findEmployeeById(int id) {
        return dao.selectEmployeeById(id);
    }
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    //使用雙重檢測鎖,解決熱點緩存問題
    //雙重檢測鎖,解決了高並發下,對數據庫訪問的壓力!!!!
    //熱點緩存腦補,請參考:https://www.jianshu.com/p/6e37a1a9c160
    @Override
    public int findEmployeeCount() {
        //獲取Redis操作對象
        BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");
        //從緩存中讀取數據
        Object count = ops.get();
        if (count == null) {
            synchronized (this) {
                count = ops.get();
                if (count == null) {
                    //從DB中查詢
                    count = dao.selectEmployeeCount();
                    //將查詢的數據,寫入Redis緩存,並設置到期時限
                    ops.set(count,10, TimeUnit.SECONDS);
                }
            }
        }
        return (int) count;
    }
}

實現

注:細心的小伙伴發現,一個問題,根據id查詢數據庫的時候,為什么控制台沒有打印sql語句呢???對表進行增刪改時,清除緩存,查詢時設置緩存,因為之前演示的時候,已經將緩存寫入到redis服務器中了,查詢的時候,拿的是緩存數據!!

完整項目

直接下載

Redis自動生成key(高級用法)

自動生成類

RedisCacheConfig.java

package com.cyb.webdemo.controller;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {
    // 自定義生成key結構:類名_方法名_參數值
    // 本例:EmployeeServiceImpl_findEmployeeById_1
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            //獲取注解所標的方法所在類的類名
            String className = target.getClass().getName();
            //獲取注解所標注的方法的方法名
            String methodName = method.getName();
            return className + "_" + methodName + "_" + params[0].toString();
        };
    }
}

實現

Spring Boot攔截器

  在非Spring Boot工程中若要使用Spring Mvc的攔截器,在定義好攔截器后,需要在Spring配置文件中對其進行注冊。但在Spring Boot工程中沒有Spring的配置文件,那么如何使用攔截器呢?

  Spring Boot對於原來在配置文件配置的內容,現在全部體現在一個類中,該要繼承WebMvcConfigurationSupport類,並使用@Configuration進行注冊,表示該類為一個JavaConfig/codeConfig類,充當配置文件的角色。

定義攔截器

SomeInterceptor.java

package com.cyb.webdemo.controller;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SomeInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("攔截器:"+request.getRequestedSessionId());
        return true;
    }
}

  注:返回值 true:不攔截;false:攔截

配置文件類

MyMvcConfiguration.java

package com.cyb.webdemo.controller;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration //表示該類充當配置文件
public class MyMvcConfiguration extends WebMvcConfigurationSupport {
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        SomeInterceptor someInterceptor = new SomeInterceptor();
        registry.addInterceptor(someInterceptor)
                .addPathPatterns("/one/**") //攔截one開頭請求
                .excludePathPatterns("/two/**"); //允許two開頭的請求
    }
}

  注:**:代表多級目錄;*:只有一級目錄;

一般設置全部攔截addPathPatterns("/**");再設置局部的不攔截excludePathPatterns("/xx/**")

定義處理器

package com.cyb.webdemo.controller;

import com.cyb.webdemo.bean.EmployeePo;
import com.cyb.webdemo.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@Controller
public class SomeController {
    @RequestMapping("/two/index")
    public String RegisterHandler(){
        return "two";
    }
    @RequestMapping("/one/index")
    public String RegisterHandler2(){
        return "one";
    }
}

Spring Boot中使用Servlet

  在Spring Boot使用Servlet,根據Servlet注冊方式的不同,有兩種使用方式。若使用的是Servlet3.0+版本,則兩種方式均可使用;若使用的是Servlet2.5版本,則只能使用配置類方式。

注解方式

  若使用Servlet3.0+版本,可以使用注解方式,分兩步。

  1. 在定義好的Servlet上使用@WebServlet注解
  2. 在入口類上添加@ServletComponentScan注解

cybServlet.java

package com.cyb.webdemo.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "/cyb")
public class cybServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().println("hello spring boot servlet!");
    }
}

入口類

WebdemoApplication

 

實現

 

配置類方式

  若使用的是Servlet2.5版本,沒有Servlet注解,此時只能使用配置類方式。其總步驟有兩步,無需再入口類上添加@ServletComponentScan注解

定義Servlet

package com.cyb.webdemo.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("servlet");
    }
}

定義配置類

package com.cyb.webdemo.servlet;

import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //表示其為配置類,相當於applicationContext.xml文件
public class MyApplicationContext {
    @Bean //表示該方法返回的對象即為Spring容器中的Bean,方法名隨意
    public ServletRegistrationBean<SomeServlet> getServletBean(){
        // 創建Servlet
        SomeServlet someServlet=new SomeServlet();
        // 注冊Servlet
        return new ServletRegistrationBean<SomeServlet>(someServlet,"/cyb");
    }
}

實現

 

 Spring Boot中使用Filter

  在Spring Boot中使用Filter前面的使用Servlet相似,根據Filter注冊方式的不同,有兩種使用方式。若使用的是Servlet3.0+版本,則兩種方式均可使用;若使用的是Servlet2.5版本,則只能使用配置類方式

注解方式

  若使用的是Servlet3.0+版本,可以直接使用Filter的注解對Filter進行注冊。有兩步

  1. 在定義好的Filter上使用@WebFilter注解
  2. 在入口類添加@ServletComponentScan注解

 

SomeFilter.java

package com.cyb.webdemo.file;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")
public class SomeFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("信息已被過濾");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

修改入口類

package com.cyb.webdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement //開啟事務
@EnableCaching //開啟緩存
@ServletComponentScan("com.cyb.webdemo.file") //注意是包名
public class WebdemoApplication {

    public static void main(String[] args) {

        SpringApplication.run(WebdemoApplication.class, args);
    }
}

配置方式

  若使用的是Servlet2.5版本,沒有Filter注解,此時只能使用配置類方式。有兩步,與@ServletComponentScan注解無關

定義Filter

package com.cyb.webdemo.file;

import javax.servlet.*;
import java.io.IOException;

public class SomeFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("信息已被過濾");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

修改配置類

package com.cyb.webdemo.file;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyFilter {
    @Bean
    public FilterRegistrationBean<SomeFilter> getFilterBean(){
        FilterRegistrationBean<SomeFilter> registrationBean=new FilterRegistrationBean<SomeFilter>(new SomeFilter());
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
}

Thymeleaf

  Thymeleaf,百里香葉。Thymeleaf是一個流行的模板引擎,該模板引擎采用Java語言開發。模板引擎為了使用戶界面與業務數據(內容)分離而產生,它可以生成特定格式的文檔。例如,用於網站的模板引擎就會生成一個標准的HTML文檔。不同的語言體系中都有自己的模板引擎,例如,Java中常見的模板引擎有Velocity、Freemaker、Thymeleaf等。不同的模板引擎都會具有自己的特定的標簽體系,而Thymeleaf以HTML標簽為載體,在HTML的標簽下實現對數據的展示。

  Thymeleaf本身與Spring Boot沒有關系,但Spring Boot官方推薦使用Thymeleaf作為前端頁面的數據展示技術,Spring Boot很好地集成了這種模板技術。

  官網:https://www.thymeleaf.org/

Spring Boot集成Thymeleaf

創建項目

配置文件

application.properties

處理器

 

index.html

  在頁面的<html>標簽中添加Thymeleaf的命名空間屬性:

<html lang="en" xmlns:th="https://www.thymeleaf.org/">

 

實現

 

Thymeleaf標准表達式

  常用的Thymeleaf標准表達式有三種。標准表達式都是用於獲取代碼中存放到Model中的屬性值,只不過獲取方式不同罷了

變量表達式:${...}

  使用${...}的表達式,稱為變量表達式。該表達式的內容會顯示在HTML標簽體文本處

  該表達式一般都是通過th:text標簽屬性進行展示的。

實體類(Po)

 

處理器

 

index.html

方式一,直接使用實體類屬性

 

方式二:使用實體類get方法獲取值

 

  注:兩種獲取值的方式效果都是一樣的。

實現

 

選擇表達式:*{...}

  選擇表達式,也稱為星號表達式。一般用於展示對象的屬性。該表達式的內容會顯示在HTML標簽體文本處。但其需要與th:object標簽屬性聯用,先使用th:object標簽選擇了對象,再使用*{...}選擇要展示的對象屬性。該表達式可以有效降低頁面中代碼的冗余

  也可以不與th:object聯用,在*{...}中直接使用“對象.屬性”方式,這種寫法與變量表達式相同

  該表達式一般都是通過th:text標簽屬性進行展示

index.html修改

 

實現

 

URL表達式:@{...}

  其中只能寫一個絕對URL或相對URL地址的表達式,稱為URL表達式。這個絕對/相對URL地址中一般包含有動態參數的需要結合變量表達式${...}進行字符串拼接

  @{...}中的URL地址有3種寫法。

以Http協議開頭的絕對地址

  在進行字符串拼接時使用“+”連接,容易出錯。但使用雙豎線則無需字符串拼接,簡單易讀。但是,在idea中的問號會報錯,不影響程序運行,可能是idea的bug吧。

index.html

 

查看網頁源碼

 

以/開頭的相對地址

  在URL表達式中,Thymeleaf會將/解析為當前工程的上下文路徑ContextPath,而瀏覽器會自動為其添加"http://主機名:端口號",即為一個絕對路徑

 

不以/開頭的相對地址

 

  查看頁面源碼可以看到解析結果是沒有添加任何東西的,沒有上下文路徑,其實相對於當前請求路徑的一個絕對地址。

自行學習

  授人以魚不如授人以漁,其他具體的使用用法,請參照官網API:https://www.thymeleaf.org/documentation.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM