天天看點

JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法

Spring Boot學習筆記

  • Spring Boot重要用法
    • 多環境選擇
      • 什麼是多環境選擇
        • 相同代碼運作在不同環境
        • 不同環境執行不同實作類
      • 需求
      • 多配置檔案實作方式 02-multi-env
      • 單配置檔案實作方式 02-multi-env-yml
    • 讀取自定義配置
      • 讀取主配置檔案中的屬性
      • 讀取指定配置檔案中的屬性
    • Spring Boot下使用JSP頁面
      • 示範工程 04-jsp-demo
      • 使用實體視圖
      • 使用邏輯視圖
    • Spring Boot中使用MyBatis
      • 示範工程 05-use-mybatis
    • Spring Boot的事務支援
    • Spring Boot對日志的控制
      • 添加配置屬性
      • 添加配置檔案
    • Spring Boot中使用Redis
      • 示範工程 06-use-redis
      • 步驟小結
    • Spring Boot中使用攔截器
      • 示範工程 07-interceptor
      • 步驟小結
    • Spring Boot中使用Servlet
      • 注解方式 08-servlet-annotation
      • 配置類方式 08-servlet-config
    • Spring Boot中使用Filter
      • 注解方式
      • 配置方式

Spring Boot重要用法

多環境選擇

什麼是多環境選擇

  • 以下兩種場景下需要進行“多環境選擇”:

相同代碼運作在不同環境

  • 在開發應用時,通常同一套程式會被運作在多個不同的環境,例如,開發、測試、生産環境等。每個環境的資料庫位址、伺服器端口号等配置都會不同。若在不同環境下運作時将配置檔案修改為不同内容,那麼,這種做法不僅非常繁瑣,而且很容易發生錯誤。
  • 此時就需要定義出不同的配置資訊,在不同的環境中選擇不同的配置。

不同環境執行不同實作類

  • 在開發應用時,有時不同的環境,需要運作的接口的實作類也是不同的。例如,若要開發一個具有短信發送功能的應用,開發環境中要執行的 send()方法僅需調用短信模拟器即可,而生産環境中要執行的 send()則需要調用短信營運商所提供的短信發送接口。
  • 此時就需要開發兩個相關接口的實作類去實作 send()方法,然後在不同的環境中自動選擇不同的實作類去執行。

需求

下面将實作如下功能:存在開發與生産兩種環境,不同環境使用不同配置檔案,不同環境調用不同接口實作類。使用不同端口号對不同的配置檔案加以區分。

多配置檔案實作方式 02-multi-env

  • 複制 01-primary 工程,重命名為 02-multi-env。在 src/main/resources 中再定義兩個配置檔案,分别對應開發環境與生産環境:
# application-dev.properties
# 開發環境
server.port=8888
server.servlet.context-path=/dev

# application-prod.properties
# 生産環境
server.port=80
server.servlet.context-path=/prod
           
  • 說明:在 Spring Boot 中多環境配置檔案名需要滿足 application-{profile}.properties 的格式,其中{profile}為對應的環境辨別,例如:
    • application-dev.properties:開發環境
    • application-test.properties:測試環境
    • application-prod.properties:生産環境
  • 至于哪個配置檔案會被加載,則需要在 application.properties 檔案中通過spring.profiles.active 屬性來設定,其值對應{profile}值。例如,spring.profiles.active=test 就會加載 application-test.properties 配置檔案内容。
  • 在生産環境下,application.properties 中一般配置通用内容,并設定 spring.profiles.active 屬性的值為 dev,即,直接指定要使用的配置檔案為開發時的配置檔案,而對于其它環境的選擇,一般是通過指令行方式去激活。配置檔案 application-{profile}.properties 中則配置各個環境的不同内容。
  • 定義業務接口和實作類:
/**
 * 消息服務接口
 */
public interface MsgService {
    String send();
}
/**
 * 開發環境消息服務實作類
 * 注解@Profile可以用于環境選擇,可以用在類上也可以用在方法上。
 */
@Service
@Profile("dev")
public class DevMsgServiceImpl implements MsgService {

    @Override
    public String send() {
        String ret = "-------- DevMsgServiceImpl -----------";
        System.out.println(ret);
        return ret;
    }
}
/**
 * 生成環境消息服務實作類
 */
@Service
@Profile("prod")
public class ProdMsgServiceImpl implements MsgService {

    @Override
    public String send() {
        String ret = "-------- ProdMsgServiceImpl -----------";
        System.out.println(ret);
        return ret;
    }
}
           
  • 說明:在實作類上添加@Profile 注解,并在注解參數中指定前述配置檔案中的{profile}值,用于指定該實作類所适用的環境。
  • 定義處理器:
/**
 * 消息處理器
 */
@RestController
public class MsgController {
    @Autowired
    private MsgService msgService;

    @GetMapping("/send")
    public String sendHandle() {
        return msgService.send();
    }
}
           
  • 運作測試:打開主類在 Idea 中直接運作,即可在控制台看到預設使用的是開發環境,即端口号使用的是 8888,而工程的根路徑為/dev。
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法
  • 如果要運作生産環境,需要修改 application.properties
spring.profiles.active=prod
           
  • 将工程打為 Jar 包後,在指令行運作。若要想切換運作環境,必須要修改主配置檔案嗎?答案是否定的。隻需添加一個指令參數即可動态指定。
  • 在指令行下運作 Jar 包,例如,現在的主配置檔案中指定的是 dev 環境。将目前工程打為 Jar 包後,在指令行運作時添加如下參數:
java -jar 02-multi-env-1.0.jar --spring.profiles.active=prod
           
  • 說明:在指令行中添加的參數可以是寫在配置檔案中的任意屬性。其原理是指令行設定的屬性值的優選級高于配置檔案的。

單配置檔案實作方式 02-multi-env-yml

  • 這種實作方式隻能使用 application.yml 檔案,使用 application.properties 檔案本身就會出錯。
  • 複制 02-multi-env 工程,并重命名為 02-multi-env-yml,在此基礎上修改。
  • 将原有的配置檔案全部删除,然後定義 application.yml 檔案。
spring:
  profiles:
    # 選擇執行開發環境
    active: dev

---
# 配置開發環境下目前應用的端口号與上下文路徑
spring:
  profiles: dev
server:
  port: 8888
  servlet:
    context-path: /dev

---
# 配置生産環境下目前應用的端口号與上下文路徑
spring:
  profiles: prod
server:
  port: 80
  servlet:
    context-path: /prod
           

讀取自定義配置

  • 自定義配置,可以是定義在主配置檔案 application.properties 或 application.yml 中的自定義屬性,也可以是自定義配置檔案中的屬性。

讀取主配置檔案中的屬性

  • 複制 01-primary 工程,重命名為 03-custom-config。
  • 修改主配置檔案:
# 目前應用系統的端口号與上下文
server.port=8888
server.servlet.context-path=/yw

# 自定義屬性
company.name=veli.com
           
  • 修改控制器類 SomeController:
@RestController
public class SomeController {
	// 在@Value 注解中通過${ }符号可以讀取指定的屬性值。
    @Value("${company.name}")
    private String companyName;

    @GetMapping("/some")
    public String someHandle() {
        return companyName;
    }
}
           
  • 啟動程式,測試接口:http://localhost:8888/yw/some

讀取指定配置檔案中的屬性

  • 一般情況下,主配置檔案中存放系統中定義好的屬性設定,而自定義屬性一般會寫入自定義的配置檔案中。也就是說,Java 代碼除了可以讀取主配置檔案中的屬性外,還可以讀取指定配置檔案中的屬性,可以通過 @PropertySource 注解加載指定的配置檔案。
  • 不能自定義 yml 檔案:spring boot 官網給出說明,@PropertySource 注解不能加載 yml 檔案。是以其建議自定義配置檔案就使用屬性檔案。
  • 繼續在工程 03-custom-config 上修改,自定義配置檔案custom.properties,檔案名随意,存放在 src/main/resources 目錄中。
# 自定義屬性
city.name=shenzhen

# 自定義對象屬性
student.name=張三
student.age=23
student.score=96.5

# 自定義數組屬性
country.cities[0]=beijing
country.cities[1]=shanghai
country.cities[2]=guangzhou

# 自定義對象數組屬性
group.users[0].name=zhangsan
group.users[0].age=23
group.users[1].name=lisi
group.users[1].age=24
group.users[2].name=wangwu
group.users[2].age=25
           
  • 定義自定義屬性的DTO對象:
@Component
@PropertySource(value = "classpath:custom.properties", encoding = "utf8")
@ConfigurationProperties("student")
@Data
public class StudentDto {
    private String name;
    private int age;
    private double score;
}
@Component
@PropertySource(value = "classpath:custom.properties", encoding = "utf8")
@ConfigurationProperties("country")
@Data
public class CountryDto {
    private List<String> cities;
}
@Component
@PropertySource(value = "classpath:custom.properties", encoding = "utf8")
@ConfigurationProperties("group")
@Data
public class GroupDto {
    private List<User> users;
}
           
  • 修改 SomeController:若屬性的值存在中文,則需要添加 encoding 屬性解決中文亂碼問題。
@RestController
@PropertySource(value = "classpath:custom.properties", encoding = "UTF-8")
public class SomeController {

    @Value("${company.name}")
    private String companyName;

    @Value("${city.name}")
    private String cityName;

    @Autowired
    private StudentDto student;

    @Autowired
    private CountryDto country;

    @Autowired
    private GroupDto group;

    @GetMapping("/some")
    public String someHandle() {
        return companyName;
    }

    @GetMapping("/custom")
    public String customHandle() {
        return Arrays.asList(cityName, student.toString(), country.toString(), group.toString()).toString();
    }
}
           
  • 啟動程式,并通路接口:http://localhost:8888/yw/custom
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法

Spring Boot下使用JSP頁面

  • 在 Spring Boot 下直接使用 JSP 檔案,其是無法解析的,需要做專門的配置。

示範工程 04-jsp-demo

  • 定義工程:複制 01-primary 工程,并重命名為 04-use-jsp。在 src/main 下建立 webapp 目錄,用于存放 jsp 檔案。打開 Project Structrue 視窗,将 webapp 目錄指定為 web 資源目錄,然後才可以建立 jsp 檔案。
  • 在 src/main/webapp 下建立一個 index.jsp 檔案:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="test/register" method="post">
    姓名:<input type="text" name="name"> <br>
    年齡:<input type="text" name="age"> <br>
    <input type="submit" value="注冊">
</form>
</body>
</html>
           
  • 啟動程式,此時在浏覽器直接通路 http://localhost:8080/ ,發現其并沒有顯示 index 頁面。因為目前工程不能識别 jsp 檔案。
    JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法

使用實體視圖

  • 添加 jasper 依賴:在 pom 中添加一個 Tomcat 内嵌的 jsp 引擎 jasper 依賴。jsp 引擎是用于解析 jsp 檔案的,即将 jsp 檔案解析為 Servlet 是由 jsp 引擎完成的。embed,嵌入。
<dependency>
 <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-jasper</artifactId>
</dependency>
           
  • 注冊資源目錄:
<resources>
  <resource>
    <directory>src/main/weapp</directory>
    <targetPath>META-INF/resources</targetPath>
    <includes>
      <include>**/*.*</include>
    </includes>
  </resource>
</resources>
           
  • 建立 welcome.jsp:在 webapp 目錄下再建立一個子目錄 jsp,在其中建立 welcome.jsp 檔案。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    name = ${name} <br>
    age = ${age} <br>
</body>
</html>
           
  • 修改SomeController:
@Controller
@RequestMapping("/test")
public class SomeController {
    @RequestMapping("/register")
    public String registerHandle(String name, int age, Model model) {
        model.addAttribute("name", name);
        model.addAttribute("age", age);
        return "jsp/welcome";
    }
}
           
  • 重新開機程式,通路:http://localhost:8080/index.jsp
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法

使用邏輯視圖

  • 修改主配置檔案:
# 視圖的字首字尾
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
           
  • 修改處理器:
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法

Spring Boot中使用MyBatis

  • 需求:完成一個簡單的注冊功能。

示範工程 05-use-mybatis

  • 複制 04-use-jsp 工程,重命名為 05-use-mybatis,在此基礎上修改。添加依賴:
<!-- 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>
  <version>5.1.47</version>
</dependency>
<!-- druid驅動 -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.12</version>
</dependency>
           
  • 注冊資源目錄:在 pom.xml 檔案中将 dao 目錄注冊為資源目錄。
<build>
 <resources>
   <!-- 注冊dao包下mybatis映射檔案為資源目錄 -->
   <resource>
     <directory>src/main/java</directory>
     <includes>
       <include>**/*.xml</include>
     </includes>
   </resource>
 </resources>
</build>
           
  • 修改主配置檔案,在主配置檔案中主要完成以下幾件工作:
    • 注冊映射檔案
    • 注冊實體類别名
    • 注冊資料源
mybatis.mapper-locations=classpath:com/yw/springboot/example/dao/mapper/*Mapper.xml
mybatis.type-aliases-package=com.yw.springboot.example.dao.po

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.254.128/ssm?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
           
  • 定義實體類及DB表,在 DB 的 test 資料庫中定義 student 表
@Data
public class Student {
    private Integer id;
    private String name;
    private int age;
}
           
  • 定義Mapper接口和映射檔案,Mapper 接口上要添加 @Mapper、@Repository 注解。
@Mapper
@Repository
public interface StudentMapper {
    int insertStudent(Student student);
}
           
<?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.yw.springboot.example.dao.mapper.StudentMapper">
  <insert id="insertStudent">
    insert into student(`name`, age) values(#{name}, #{age})
  </insert>
</mapper>
           
  • 定義Service接口和實作類:
public interface StudentService {
    boolean addStudent(Student student);
}
@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentMapper studentMapper;

    @Override
    public boolean addStudent(Student student) {
        int result = studentMapper.insertStudent(student);
        return result >= 1;
    }
}
           
  • 定義控制器 StudentController
@RestController
@RequestMapping("stu")
public class StudentController {
    @Autowired
    private StudentService studentService;

    @RequestMapping(value = "register", method = RequestMethod.POST)
    public String registerHandle(@RequestBody Student student) {
        boolean result = studentService.addStudent(student);
        return "注冊" + (result ? "成功" : "失敗");
    }
}
           
  • 啟動項目,使用 postman 進行接口測試:
    JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法

Spring Boot的事務支援

  • 若工程直接或間接依賴于 spring-tx,則架構會自動注入 DataSourceTransactionManager 事務管理器;若依賴于 spring-boot-data-jpa,則會自動注入 JpaTransactionManager。
  • 在工程 05-use-mybatis 完成功能示範,假設使用者注冊時一次插入到 DB 中兩條注冊資訊。若在插入過程中有發生異常,則已完成插入的記錄復原。
  • 修改啟動類開啟事務:添加注解 @EnableTransactionManagement
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法

\

  • 修改Service實作類:手動增加點異常
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法
  • 啟動項目,測試接口:http://localhost:8080/stu/register,服務端 500 報錯,資料庫復原未成功插入。
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法

Spring Boot對日志的控制

  • Spring Boot 中使用的日志技術為 logback。其與 Log4J 都出自同一人,性能要優于 Log4J,是 Log4J 的替代者。
  • 在 Spring Boot 中若要使用 logback,則需要具有 spring-boot-starter-logging 依賴,而該依賴被 spring-boot-starter-web 所依賴,即不用直接導入 spring-boot-starter-logging 依賴。
  • 在 Spring Boot 中使用 logback 日志,有兩種方式:

添加配置屬性

  • 隻需在核心配置檔案中添加如下配置即可。
# 控制日志顯示格式
logging.pattern.console=logs-%level %msg%n
logging.level.root=warn,info
logging.level.com.yw.springboot.example.dao=debug
           

注意:在日志顯示格式的屬性值前面的 logs-是随意内容。在 yml 檔案中的屬性值若以%開頭會報錯,是以添加一些随意字元。在 properties 檔案中不存在該問題。

添加配置檔案

  • 配置檔案名為 logback.xml,且必須要放在 src/main/resources 類路徑下。内容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%-5level - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="WARN,INFO">
    <appender-ref ref="STDOUT"/>
  </root>

  <logger name="com.yw.springboot.example.dao" level="DEBUG"/>
</configuration>
           

Spring Boot中使用Redis

  • 使用 Redis 緩存的資料可以劃分為兩類:
    • DB 更新後,Redis 緩存中的資料就要馬上清除,以保證将來緩存中的資料與 DB 中的資料的絕對一緻性;
    • 對資料準确性要求不是很高,隻要與 DB 中的資料差别不大就可以,是以這類資料一般會為其設定過期時效。
  • 需求:
    • 使用者在頁面中輸入要查詢學生的 id,其首先會檢視 Redis 緩存中是否存在,若存在,則直接從 Redis 中讀取;若不存在,則先從 DB 中查詢出來,然後再存放到 Redis 緩存中。
    • 使用者也可以通過頁面注冊學生,一旦有新的學生注冊,則需要将緩存中的學生資訊清空。根據 id 查詢出的學生資訊要求必須是實時性的,其适合使用注解方式的 Redis 緩存。
    • 同時,通過頁面還可以檢視到總學生數,但對其要求是差不多就行,無需是實時性的。對于 Spring Boot 工程,其适合使用 API 方式的 Redis 緩存,該方式友善設定緩存的到期時限。

示範工程 06-use-redis

  • 複制 05-use-mybatis 工程,重命名為 06-use-redis,在此基礎上修改。
  • 添加依賴:
<!-- spring boot與redis整合依賴 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
           
  • 修改主配置檔案:配置redis
# 連接配接單機Redis
spring.redis.host=192.168.254.128
spring.redis.port=6379
spring.redis.password=

# 連接配接redis高可用叢集
# spring.redis.sentinel.master=mymaster
# spring.redis.sentinel.nodes=sentinel1:26379,sentinel2:26379,sentinel3:26379

spring.cache.type=redis
spring.cache.cache-names=realTimeCache
# 過期時間5分鐘
spring.cache.redis.time-to-live=300000
           
  • 啟動類開啟緩存
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法
  • 修改實體類Student:由于要将查詢的實體類對象緩存到 Redis,Redis 要求實體類必須序列化。是以需要實體類實作序列化接口。
@Data
public class Student implements Serializable {
    private Integer id;
    private String name;
    private int age;
}
           
  • 添加 index.jsp 注冊頁面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>Title</title>
</head>
<body>
<form action="stu/register" method="post">
  姓名:<input type="text" name="name"> <br>
  年齡:<input type="text" name="age"> <br>
  <input type="submit" value="注冊">
</form>

<form action="stu/find" method="get">
  學生id:<input type="text" name="id"><br>
  <input type="submit" value="查詢">
</form>
<hr>
<a href="stu/studentsCount">查詢學生總人數</a>
</body>
</html>
           
  • 修改Mapper接口和映射檔案:在其中添加兩個方法
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法
  • 修改 Service 接口和實作類:在其中添加兩個業務方法
@Service
public class StudentServiceImpl implements StudentService {
    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @CacheEvict(value = "realTimeCache", allEntries = true)
    // 采用spring預設的事務送出方式:發生運作時異常復原
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addStudent(Student student) {
        int result = studentMapper.insertStudent(student);
//        int i = 3 / 0;
//        studentMapper.insertStudent(student);
        if(result>=1){
            return true;
        }else {
            return false;
        }
    }

    @Cacheable(value = "realTimeCache", key = "'student_'+#id")
    @Override
    public Student findStudentById(int id) {
        System.out.println("從DB中查詢student");
        return studentMapper.selectStudentById(id);
    }

    // 使用雙重檢測鎖解決熱點緩存問題
    @Override
    public Integer findStudentsCount() {
        // 擷取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 = studentMapper.selectStudentsCount();
                    // 将資料寫入到緩存,并設定到期時限
                    ops.set(count, 10, TimeUnit.SECONDS);
                }
            }
        }
        return (Integer) count;
    }
}
           
  • 修改StudentController:在其中添加兩個處理器方法
@RestController
@RequestMapping("stu")
public class StudentController {
    @Autowired
    private StudentService studentService;
	
	// ...略
	
    @GetMapping("/find")
    public Student findHandle(int id) {
        return studentService.findStudentById(id);
    }

    @GetMapping("studentsCount")
    public Integer countHandle() {
        return studentService.findStudentsCount();
    }
}
           
  • 測試接口:http://localhost:8080/stu/find?id=1

步驟小結

  • 在pom中添加Redis與SpringBoot整合依賴;
  • 在配置檔案中注冊Redis連接配接資訊;
  • 實體類實作序列化接口;
  • 在啟動類上添加@EnableCaching;
  • 在查詢方法上添加@Cacheble,在增删改方法上添加@CacheEvict;
  • 若使用API方式操作Redis,則需要注入RedisTemplate,然後通過RedisTemplate擷取到Redis 操作對象後就可以對 Redis 進行操作了。

Spring Boot中使用攔截器

  • 在非 Spring Boot 工程中若要使用 SpringMVC 的攔截器,在定義好攔截器後,需要在 Spring 配置檔案中對其進行注冊。但 Spring Boot 工程中沒有了 Spring 配置檔案,那麼如何使用攔截器呢?
  • Spring Boot 對于原來在配置檔案配置的内容,現在全部展現在一個類中,該類需要繼承自 WebMvcConfigurationSupport 類,并使用@Configuration 進行注解,表示該類為一個 JavaConfig 類,其充當配置檔案的角色。

示範工程 07-interceptor

  • 建立一個 Spring Boot 的 Web 工程,命名為 07-interceptor。
  • 定義攔截器
public class SomeInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
                             Object handler) throws Exception{
        System.out.println("執行攔截器" + request.getRequestURI());
        return false;
    }
}
           
  • 定義處理器
@RestController
public class SomeController {
    @RequestMapping("/first/some")
    public String firstHandle() {
        return "/first/some";
    }

    @RequestMapping("/second/some")
    public String secondHandle() {
        return "/second/some";
    }
}
           
  • 定義配置檔案類
// 表示該檔案充當配置檔案
@Configuration
public class SomeWebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addInterceptors(InterceptorRegistry registry){
        SomeInterceptor interceptor = new SomeInterceptor();
        registry.addInterceptor(interceptor)
                // 攔截first開頭的路徑
                .addPathPatterns("/first/**")
                // 不攔截second開頭的路徑
                .excludePathPatterns("/second/**");
    }
}
           
  • 測試接口:http://localhost:8080/first/some【被攔截】、http://localhost:8080/second/some【不被攔截】

步驟小結

  • 定義攔截器
  • 定義WebMvc配置類,其需要繼承自WebMvcConfigurationSupport,且需要使用 @Configuration 進行注解

Spring Boot中使用Servlet

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

注解方式 08-servlet-annotation

  • 複制 07-interceptor 工程,重命名為 08-servlet-annotation,在此基礎上進行修改。
  • 建立Servlet:通過建立一個 class,讓其繼承自 HttpServlet 方式建立,然後在 Servlet 上添加@WebServlet 注解。
/**
 * 該方案僅适用于3.0+版本
 */
@WebServlet(name = "/some")
public class SomeServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws IOException {
        response.getWriter().println("Hello Servlet");
    }
}
           
  • 修改啟動類:在入口類中添加 Servlet 掃描注解。
JavaEE 企業級分布式進階架構師(十一)Spring Boot學習筆記(2)Spring Boot重要用法
  • 啟動項目,測試接口:http://localhost:8080/some

配置類方式 08-servlet-config

  • 複制 08-servlet-annotation 工程,重命名為 08-servlet-config,在此基礎上進行修改。
  • 定義Servlet:
public class SomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws IOException {
        PrintWriter writer = response.getWriter();
        writer.println("Hello Spring Boot Servlet");
    }
}
           
  • 定義配置類:
// 表示其為配置類,相當于applicationContext.xml檔案
@Configuration
public class MyApplicationContext {
    // 表示該方法傳回的對象即為Spring容器中的Bean,方法名随意
    @Bean
    public ServletRegistrationBean<SomeServlet> getServletBean(){
        // 建立Servlet
        SomeServlet servlet = new SomeServlet();
        // 注冊Servlet
        return new ServletRegistrationBean<>(servlet, "/some");
    }
}
           
  • 啟動項目,測試接口:http://localhost:8080/some

Spring Boot中使用Filter

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

注解方式

  • 在 08-servlet-annotation 工程上進行修改,建立 Filter 需要通過建立一個 class,讓其實作 Filter 接口方式建立。然後在 Filter 上添加 @WebFilter 注解。
@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() {
    }
}
           
  • 修改啟動類:在 @ServletComponentScan 注解中注冊 Filter 所在的包,當然 Spring Boot 也支援通配符的使用。

配置方式

  • 在 08-servlet-config 工程上進行,建立Filter:
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() {
    }
}
           
  • 修改配置類:在配置類中添加如下方法。
// 表示其為配置類,相當于applicationContext.xml檔案
@Configuration
public class MyApplicationContext {
    // ...
    @Bean
    public FilterRegistrationBean<SomeFilter> getFilterBean(){
        // 建立Filter
        SomeFilter filter = new SomeFilter();
        // 建立注冊對象
        FilterRegistrationBean<SomeFilter> registrationBean = new FilterRegistrationBean<>(filter);
        // 添加過濾條件
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
}
           
  • github位址:https://github.com/shouwangyw/ssm/tree/main/springboot-example-parent

繼續閱讀