主頁 > 後端開發 > 【Java】【搬運】SpringBoot系列

【Java】【搬運】SpringBoot系列

2022-03-10 12:59:32 後端開發

搬運鏈接 https://www.cnblogs.com/sam-uncle/category/1196696.html

spring boot 系列之一:spring boot 入門

一、什么是spring boot ? spring boot是干嘛的?

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

二、spring boot 入門實體

創建maven專案

配置pom檔案

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>spring-boot</groupId>
    <artifactId>study</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <!-- 指定parent專案 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
    </parent>

    <properties>
        <!-- spring boot默認的jdk 版本為1.6,我們在這里改為1.8 -->
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <!-- 引入spring-boot-starter-web 依賴 -->
            <!-- 由于在spring boot 頂層POM檔案中定義了相關dependencyManagement,因此這里就不需要配置 <version></version>, 
                相關說明可以參考 https://blog.csdn.net/liutengteng130/article/details/46991829 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>
</project>

創建controller

package com.study.controller;

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

/**
 * 這里@RestController = @ Controller + @ ResponseBody,
 * 
 * 會將方法的回傳結果直接放入http 回傳報文的正文部分,直接顯示到頁面
 *
 */
@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String sayHello() {
        return "hello ,spring boot";
    }
}

創建app啟動類

package com.study;

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

@SpringBootApplication
public class App {

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

測驗

1.上述步驟完成之后,還有一個錯誤需要解決,根據其提示進行修復即可

2.最終的目錄結構如下:

3.運行App的main 方法:Run As-->Java Application

啟動log如下:

4.通過瀏覽器訪問,正常回傳controller中的配置內容

三、總結

從上述例子我們看到spring boot默認替我們做了一些操作

  1. 嵌入的Tomcat,無需部署WAR檔案,默認埠號為8080
  2. 簡化Maven配置,自動為我們引入依賴
  1. 自動配置Spring,省去了我們配置spring xml檔案的麻煩
  2. 默認我們的專案命名空間為"/"
  1. 還有一個比較重要但是例子中未能顯示體現出來的是:spring boot 默認自動掃描 配置了@SpringBootApplication注解的類所在的包及其子包,并且這個類不能放在默認包下,否則會報錯** WARNING ** : Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package. 并且不能正常啟動,

spring boot 系列之二:spring boot 如何修改默認埠號和contextpath

一、問題解決:

在src/main/resources目錄下新建檔案application.properties,并進行配置,來重寫spring boot的默認配置

#指定埠號
server.port=8090
#指定context path
server.context-path=/test

目錄結構如下:

啟動服務,我們發現context和埠號都變了

正常訪問:

二、知識點引申

其實上面application.properties一共有四個目錄可以放置:

  1. 外置,在相對于應用程式運行目錄的/congfig子目錄里
  2. 外置,在應用程式運行的目錄里
  1. 內置,在config包內
  2. 內置,在classpath根目錄(即我們上述實體中的方式)

其中1和2適用于生產環境,打包后由于發布包不能修改,組態檔放在發布包之外,可以很方便的配置,

位置如下:

3和4適用于開發環境,位置如下:

如果同時在四個地方都有組態檔,組態檔的優先級是 1 > 2 > 3 >4,

spring boot 系列之三:spring boot 整合JdbcTemplate

一、代碼實作

修改pom檔案,引入相關依賴

<!-- 引入jdbc 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- 引入 mysql 資料庫連接依賴-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

配置資料庫資訊,在application.properties中添加如下內容:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root

創建物體類并創建資料庫

package com.study.entity;

public class User {
    
    private Integer id;
    private String userName;
    private String password;
    
    public Integer getId() {
        return id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    
    public String getUserName() {
        return userName;
    }
    
    public void setUserName(String userName) {
        this.userName = userName;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
}

實作dao層

@Repository
public class UserDao {

    @Autowired
    JdbcTemplate jdbcTemplate;

    public void save(User user) {
        String sql = "insert into t_user(user_name, password) values(?,?)";
        jdbcTemplate.update(sql, user.getUserName(), user.getPassword());
    }
}

實作service

介面

public interface UserService {

    public void save(User user);
}

實作類

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserDao userDao;
    
    public void save(User user){
        userDao.save(user);
    }
    
}

實作controller

@RestController
public class UserController {
    @Autowired
    UserService service;

    @RequestMapping("/saveUser")
    public String saveUser(User user) {

        service.save(user);
        return "save user successful";
    }
}

測驗

二、總結

由此我們發現,spring boot 只是簡化了xml的配置麻煩,并沒有減少我們java代碼的撰寫量,

spring boot 不是spring 功能的增強,而是提供了一種快速使用spring 的方式:開箱即用,沒有代碼生成,也無需XML配置,

spring boot 系列之四:spring boot 整合JPA

一、代碼實作

修改pom,引入依賴

<!-- 引入jpa 依賴 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

修改application.proerties,配置相關資訊

#修改tomcat默認埠號
server.port=8090
#修改context path
server.context-path=/test

#配置資料源資訊
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
#配置jpa
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true

創建物體類

package com.study.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="t_user")
public class User {
    
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String userName;
    private String password;
    
    public Integer getId() {
        return id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    
    public String getUserName() {
        return userName;
    }
    
    public void setUserName(String userName) {
        this.userName = userName;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
}

創建repository介面并繼承CrudRepository

package com.study.repository;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;

import com.study.entity.User;

/**
 * 注意:
 * 1.這里這里是interface,不是class
 * 
 * 2.CrudRepository里面的泛型,第一個是物體類,第二個是主鍵的型別
 * 
 * 3.由于crudRepository 里面已經有一些介面了,如deleteAll,findOne等, 我們直接呼叫即可
 * 
 * 4.當然,我們也可以根據自己的情況來實作自己的介面,如下面的getUser()方法,jpql陳述句和hql陳述句差不多
 * 
 * */
public interface UserRepository extends CrudRepository<User, Integer> {

    /**
     * 我們這里只需要寫介面,不需要寫實作,spring boot會幫忙自動實作
     * 
     * */
    
    @Query("from User where id =:id ")
    public User getUser(@Param("id") Integer id);
}

創建service

介面

package com.study.service;

import com.study.entity.User;


public interface UserService {
    public User getUser(Integer id);
}

實作

package com.study.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.study.entity.User;
import com.study.repository.UserRepository;
import com.study.service.UserService;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserRepository repository;
    
    @Override
    public User getUser(Integer id) {
        //有兩種方式:
        //1.呼叫crudRepository的介面
//        return repository.findOne(id);
        //2.呼叫我們自己寫的介面
        return repository.getUser(id);
    }

    
}

創建controller

package com.study.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.study.entity.User;
import com.study.service.UserService;

@RestController
public class UserController {
    @Autowired
    UserService service;
    
    @RequestMapping("/getUser/{id}")
    public User getUser(@PathVariable("id") Integer id){
        
        return service.getUser(id);
    }
}

測驗頁面以json格式顯示資料庫值

二、知識點引申

關于Repository知識點,可以去看下下面這篇文章

https://segmentfault.com/a/1190000012346333

spring boot 系列之五:spring boot 通過devtools進行熱部署

在上述代碼操作的程序中肯定也發現了一個問題:哪怕是一個個小小的修改,都必須要重新啟動服務才能使修改生效,

那能不能通過配置實作spring boot的熱部署呢?答案是肯定的,

接下來我們來一起看下怎么通過devtools實作spring boot的熱部署,很簡單,只需要簡單幾步:

引入依賴

<!-- 引入devtools 依賴 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-devtools</artifactId>
  <!-- optional=true,依賴不會傳遞-->
  <optional>true</optional>
        </dependency>

對于eclipse,還需要加上maven-plugin插件

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <fork>true</fork>
      </configuration>
    </plugin>
  </plugins>
    </build>

Project --> Build Automatically 要勾上

spring boot 系列之六:深入理解spring boot的自動配置

我們知道,spring boot自動配置功能可以根據不同情況來決定spring配置應該用哪個,不應該用哪個,舉個例子:

  • Spring的JdbcTemplate是不是在Classpath里面?如果是,并且DataSource也存在,就自動配置一個JdbcTemplate的Bean
  • Thymeleaf是不是在Classpath里面?如果是,則自動配置Thymeleaf的模板決議器、視圖決議器、模板引擎

那個這個是怎么實作的呢?原因就在于它利用了Spring的條件化配置,條件化配置允許配置存在于應用中,但是在滿足某些特定條件前會忽略這些配置,

要實作條件化配置我們要用到@Conditional條件化注解,

本篇隨筆從如下三個方面進行展開:

  1. @Conditional小例子,來說明條件化配置的實作方式
  2. spring boot 的條件化配置詳解
  1. spring boot 自動配置原始碼分析
  2. 自己動手實作spring boot starter pom

一、@Conditional小例子

我們知道在windows下顯示串列的命令是dir,而在linux系統下顯示串列的命令是ls,基于條件配置,我們可以實作在不同的作業系統下回傳不同的值,

判斷條件定義

a.windows下的判定條件

/**
* 實作spring 的Condition介面,并且重寫matches()方法,如果作業系統是windows就回傳true
*
*/
public class WindowsCondition implements Condition{
    
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        
        return context.getEnvironment().getProperty("os.name").contains("Windows");
    }
    
    
}

b.linux下的判定條件

/**
 * 實作spring 的Condition介面,并且重寫matches()方法,如果作業系統是linux就回傳true
 *
 */
public class LinuxCondition implements Condition{

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        
        return context.getEnvironment().getProperty("os.name").contains("Linux");
    }

    
}

不同系統下的bean的類

介面

public interface ListService {

    public String showListLine();
}

windows下的bean類

public class WindowsListService implements ListService{

    @Override
    public String showListLine() {
        return "dir";
    }

}

linux下的bean的類

public class LinuxListService implements ListService{

    @Override
    public String showListLine() {
        return "ls";
    }

}

配置類

@Configuration
public class ConditionConfig {

    /**
     * 通過@Conditional 注解,符合windows條件就回傳WindowsListService實體
     * 
     */
    @Bean
    @Conditional(WindowsCondition.class)
    public ListService windonwsListService() {
        return new WindowsListService();
    }

    /**
     * 通過@Conditional 注解,符合linux條件就回傳LinuxListService實體
     * 
     */
    @Bean
    @Conditional(LinuxCondition.class)
    public ListService linuxListService() {
        return new LinuxListService();
    }
}

測驗類

public class ConditionTest {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);
        ListService listService = context.getBean(ListService.class);
        System.out
                .println(context.getEnvironment().getProperty("os.name") + " 系統下的串列命令為: " + listService.showListLine());
    }
}

運行測驗類,由于我的是windows7 系統,因此結果是

Windows 7 系統下的串列命令為: dir

如果你的是linux系統,則結果就會是

Linux 系統下的串列命令為: ls

二、spring boot 的條件化配置

在spring boot專案中會存在一個名為spring-boot-autoconfigure的jar包

條件化配置就是在這個jar里面實作的,它用到了如下的條件化注解,這些注解都是以@ConditionalOn開頭的,他們都是應用了@Conditional的組合注解:

接下來我們看個原始碼的列子:

以JdbcTemplateAutoConfiguration為例,它里面有這段代碼:

@Bean
    @Primary
    @ConditionalOnMissingBean(JdbcOperations.class)
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(this.dataSource);
    }

只有在不存在JdbcOperations(如果查看JdbcTemplate的原始碼,你會發現JdbcTemplate類實作了JdbcOperations介面)實體的時候,才會初始化一個JdbcTemplate 的Bean,

基于以上內容,我們就可以閱讀自動配置相關的原始碼了,

三、spring boot 自動配置原始碼分析

spring boot專案的啟動類用的注解--@SpringBootApplication是一個組合注解,其中@EnableAutoConfiguration是自動配置相關的,

而這個@EnableAutoConfiguration注解里面有個@Import注解匯入了EnableAutoConfigurationImportSelector用來實作具體的功能

(注:由于我本地的spring boot版本不是最新的,這里的EnableAutoConfigurationImportSelector已經不建議使用了,新版本可能已經換成了其他類,但是不影響我們看代碼)

這個類繼承了AutoConfigurationImportSelector

進入父類,里面有個方法selectImports()呼叫了方法getCandidateConfigurations(),進而呼叫了SpringFactoriesLoader.loadFactoryNames()方法

在SpringFactoriesLoader.loadFactoryNames()方法里面,我們看到會查詢META-INF/spring.factories這個組態檔

SpringFactoriesLoader.loadFactoryNames方法會掃描具有META-INF/spring.factories檔案的jar包,而我們的spring-boot-autoconfigure.jar里面就有一個這樣的檔案,此檔案中宣告了具體有哪些自動配置:

我們上面提到的JdbcTemplateAutoConfiguration自動配置類就在里面,

四、撰寫自己的spring boot starter pom

接下來,我們就來寫一個簡單的spring boot starter pom,

步驟如下:

  1. 新建starter maven專案spring-boot-starter-hello
  2. 修改pom檔案
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.sam</groupId>
  <artifactId>spring-boot-starter-hello</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  
  <dependencies>
    <!-- 這里需要引入spring boot的自動配置作為依賴 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>1.5.1.RELEASE</version>
    </dependency>
    
    
  </dependencies>
</project>
  1. 屬性配置
/**
* @ConfigurationProperties
* 自動匹配application.properties檔案中hello.msg的值,然后賦值給類屬性msg,這里的msg默認值為“spring boot”
*
*/
@ConfigurationProperties(prefix="hello")
public class HelloServiceProperties {
    
    private static final String MSG = "spring boot";
    
    private String msg = MSG;
    
    public String getMsg() {
        return msg;
    }
    
    public void setMsg(String msg) {
        this.msg = msg;
    }
    
    
}
  1. 判定依據類
/**
 * 后面的代碼會依據此類是否存在,來決定是否生產對應的Bean
 *
 */
public class HelloService {

    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String sayHello() {
        return "hello " + msg;
    }
}
  1. 自動配置類
@Configuration
@EnableConfigurationProperties(HelloServiceProperties.class)
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix = "hello", matchIfMissing = true, value = "https://www.cnblogs.com/yyyyfly1/p/enabled")
public class HelloServiceAutoConfiguration {
    
    @Autowired
    HelloServiceProperties helloServiceProperties;
    
    @Bean
    @ConditionalOnMissingBean(HelloService.class)
    public HelloService helloService() {
        HelloService service = new HelloService();
        service.setMsg(helloServiceProperties.getMsg());
        return service;
    }
}
  1. 注冊配置,需要到META-INF/spring.factories檔案中注冊改自動配置類:在src/main/source目錄下新建改檔案,然后進行配置,
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sam.spring_boot_starter_hello.HelloServiceAutoConfiguration
  1. 對該工程進行mvn clean install,將jar推送到本地maven倉庫,供后續使用,

使用starter ,使用我們這個starter 需要新建一個或使用既存的一個spring boot工程(這里我用的是既存的),然后

修改pom,引入上述的依賴

<dependency>
  <groupId>com.sam</groupId>
  <artifactId>spring-boot-starter-hello</artifactId>
  <version>0.0.1-SNAPSHOT</version>
        </dependency>

實作controller

@RestController
public class HelloController {
    //代碼中沒有配置這個helloService Bean,但是自動配置能夠幫忙實體化,因此可以直接注入
    @Autowired
    HelloService helloService;
    
    @RequestMapping(value="https://www.cnblogs.com/helloService")
    public String sayHello() {
        return helloService.sayHello();
    }
}

頁面訪問/helloService介面

在application.properties里面配置hello.msg=sam,然后再次訪問/helloService介面

spring boot 系列之七:SpringBoot整合Mybatis

springboot已經很流行,但是它仍需要搭配一款ORM框架來實作資料的CRUD,之前已經分享過JdbcTempleteJPA的整合,本次分享下Mybatis的整合,
對于mybatis的使用,需要創建mapper類和mapper.xml檔案,這種創建比較煩,并且基本都是模板樣式的,可以通過之前分享的
《IDEA中mybatis generator使用》來自動創建完整的檔案,由于本次deom中只有一個查詢方法,就直接手寫了,不再使用該插件了,
代碼整體結構:

1.pom配置

<?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.5.4</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.sam</groupId>
  <artifactId>springboot</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>springboot</name>
  <description>Demo project for Spring Boot</description>
  
  
  <properties>
    <java.version>1.8</java.version>
  </properties>
  
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--mybatis依賴-->
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.2.0</version>
    </dependency>
    
    <!--mysql db連接-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    
    <!--連接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.14</version>
    </dependency>
    
    <!--熱部署-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <fork>true</fork>
        </configuration>
      </plugin>
    </plugins>
  </build>
  
</project>

2.application.propertis

# jdbc配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

# 連接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

#mybatis的package別名
#mybatis.type-aliases-package=com.sam.springboot.pojo

#指定mybatis映射檔案的路徑
mybatis.mapper-locations=classpath:com/sam/springboot/mapper/*.xml

3.啟動器

@SpringBootApplication
@MapperScan("com.sam.springboot.mapper") //掃描該包下的mapper檔案
public class SpringbootApplication {

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

}

4.db腳本

CREATE TABLE `users`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
);

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (1, 'sam', 32);
INSERT INTO `users` VALUES (2, 'hah ', 10);

5.pojo類

package com.sam.springboot.pojo;

/**
 * @description:
 * @author JAVA開發老菜鳥
 * @date: 2021-09-05 19:31
 */
public class User {
    private Integer id;

    private String name;

    private Integer age;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

6.mapper檔案和mapper.xml

/**
 * @description:
 * @author: JAVA開發老菜鳥
 * @date: 2021-09-05 19:34
 */
public interface UserMapper {

    public List<User> getUserList(User user);
}
<?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.sam.springboot.mapper.UserMapper">
    <select id="getUserList" resultType="com.sam.springboot.pojo.User">
        select * from users
    </select>
</mapper>

7.service介面和實作

public interface UserService {

    List<User> getUserList(User user);
}
/**
 * @description:
 * @author: JAVA開發老菜鳥
 * @date: 2021-09-05 19:39
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    @Override
    public List<User> getUserList(User user) {
        return userMapper.getUserList(user);
    }
}

8.controller

@RestController
public class UserController {

    @Autowired
    UserService userService;

    @GetMapping("/getUserList.do")
    public void getUser() {
        List<User> list = userService.getUserList(new User());
        for (User user :list ){
            System.out.println(user.toString());
        }
    }
}

9.除錯

瀏覽器訪問http://localhost:8080/getUserList.do后查看控制臺

spring boot 系列之八:SpringBoot處理定時任務

一、cron運算式

無論上面說的哪種實作方式,都需要用到cron運算式,因此不得不先介紹下它,

Cron運算式是一個字串,由6或7個域組成,每個域有不同的含義,每個域之間用空格隔開,有2中格式:

Seconds Minutes Hours DayofMonth Month DayofWeek Year (7個域)
Seconds Minutes Hours DayofMonth Month DayofWeek (6個域)

每個域可能出現的值:

Seconds:有效范圍為0-59的整數

Minutes:有效范圍為0-59的整數

Hours:有效范圍為0-23的整數

DayofMonth:有效范圍為0-31的整數

Month:有效范圍為1-12的整數或JAN-DEC DayofWeek:有效范圍為1-7的整數或SUN-SAT兩個范圍,1表示星期天,2表示星期一, 依次類推

Year:有效范圍為1970-2099年

除了以上內容外,還可能出現一些特殊字符:

(1)*:表示匹配該域的任意值,假如在Minutes域使用*, 即表示每分鐘都會觸發事件,

(2)?:只能用在DayofMonth和DayofWeek兩個域,它也匹配域的任意值,但實際不會,因為DayofMonth和DayofWeek會相互影響,例如想在每月的10日觸發調度,不管10日到底是星期幾,則只能使用如下寫法: 13 13 15 10 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期幾都會觸發,實際上并不是這樣,

(3)-:表示范圍,例如在Minutes域使用5-20,表示從5分到20分鐘每分鐘觸發一次

(4)/:表示起始時間開始觸發,然后每隔固定時間觸發一次,例如在Minutes域使用5/20,則意味著5分鐘觸發一次,而25,45等分別觸發一次.

(5),:表示列出列舉值值,例如:在Minutes域使用5,20,則意味著在5和20分每分鐘觸發一次,

(6)L:表示最后,只能出現在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味著在最后的一個星期四觸發,

(7)W:表示有效作業日(周一到周五),只能出現在DayofMonth域,系統將在離指定日期的最近的有效作業日觸發事件,例如:在 DayofMonth使用5W,如果5日是星期六,則將在最近的作業日:星期五,即4日觸發,如果5日是星期天,則在6日(周一)觸發;如果5日在星期一到星期五中的一天,則就在5日觸發,另外一點,W的最近尋找不會跨過月份

(8)LW:這兩個字符可以連用,表示在某個月最后一個作業日,即最后一個星期五,

(9)#:用于確定每個月第幾個星期幾,只能出現在DayofMonth域,例如在4#2,表示某月的第二個星期三,

舉例

@Scheduled(cron = “0 0 1 1 1 ?”)//每年一月的一號的 1:00:00 執行一次

@Scheduled(cron = “0 0 1 1 1,6 ?”) //一月和六月的一號的 1:00:00 執行一次

@Scheduled(cron = “0 0 1 1 1,4,7,10 ?”) //每個季度的第一個月的一號的 1:00:00 執行一次

@Scheduled(cron = “0 0 1 1 * ?”)//每月一號 1:00:00 執行一次

@Scheduled(cron=“0 0 1 * * *”) //每天凌晨 1 點執行一次

以上看上去有點復雜,不過不用擔心,記住常用的就行了,另外,現在網上還有 在線Cron運算式生成器可以幫助我們設定確定相關運算式內容,

二、@Schedule實作

1.引入依賴

<!--添加schedule依賴-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>

2.代碼實作

新建類JdkSchedule

@Component
public class JdkSchedule {
    
    @Autowired
    UserService userService;
    
    @Scheduled(cron = "0/2 * * * * ?") //每個兩秒觸發一次
    public void scheduleGetUserList() {
        System.out.println("**觸發JDK 定時器***");
        List<User> list = userService.getUserList(new User());
        for (User user :list ){
            System.out.println(user.toString());
        }
    }
}

里面userService為上一次添加的內容

啟動類添加注解,啟動定時任務

@EnableScheduling

3.測驗效果

每隔兩秒列印一次:

**觸發JDK 定時器***

User{id=1, name='sam', age=32}

User{id=2, name='hah ', age=10}

三、Quartz實作

1.Quartz介紹

Quartz是一個完全由Java撰寫的開源任務調度的框架,通過觸發器設定作業定時運行規則,控制作業的運行時間,它包括調度器、觸發器、作業,

組成

描述

Job--任務

做什么事?

Trigger--觸發器

什么時候做?

Scheduler--調度器

什么時候需要去做什么事情?

2.基本使用

引入依賴

<!--引入quartz依賴-->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
</dependency>

創建job類

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("...quartz job 觸發執行...");
    }
}

需要實作Quarz的Job介面

撰寫測驗類

/**
 * quartz原生態用法
 */
public class JobTestMain {
    public static void main(String[] args) throws SchedulerException {
        //1.創建job
        JobDetail job = JobBuilder.newJob(MyJob.class).build();

        //2.創建trigger
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
                .build();

        //3.創建schedule
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.scheduleJob(job, trigger);
        scheduler.start();
    }
}

3.springboot整合使用

引入依賴

<!--添加schedule依賴-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>

<!--引入quartz依賴-->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
</dependency>
<!--引入spring tx依賴-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
</dependency>

Springboot整合的時候,需要添加這三個依賴

撰寫配置類

/**
* springboot整合quartz使用方法
*/
@Configuration
public class QuartzConfig {
    
    /**
    * 創建job物件
    * @return
    */
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean() {
        JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
        jobDetailFactoryBean.setJobClass(MyJob.class);
        return jobDetailFactoryBean;
    }
    
    /**
    * 創建trigger物件 - cron運算式物件
    * @param jobDetailFactoryBean
    * @return
    */
    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        cronTriggerFactoryBean.setCronExpression("0/5 * * * * ?");
        // 關聯JobDetail物件
        cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        return cronTriggerFactoryBean;
    }
    
    /**
    * 創建trigger物件 - 一般物件
    * @param jobDetailFactoryBean
    * @return
    */
    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
        SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
        // 關聯JobDetail物件
        simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        // 設定重復次數,這里配置的是重復次數,而不是總次數; 總次數=重復次數+1,也就是說這里配置的次數是:執行完一次之后,再重復執行的次數
        simpleTriggerFactoryBean.setRepeatCount(1);
        // 設定間隔時間
        simpleTriggerFactoryBean.setRepeatInterval(2000);
        return simpleTriggerFactoryBean;
    }
    
    /**
    * 創建schedule物件
    * @param triggerFactoryBean
    * @return
    */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean triggerFactoryBean){
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setTriggers(triggerFactoryBean.getObject());
        return schedulerFactoryBean;
    }
}

這里需要注意下,schedulerFactoryBean()方法中傳入的引數如果是CronTriggerFactoryBean,則執行的是cronTriggerFactoryBean()對應的設定;引數如果是SimpleTriggerFactoryBean,則執行的是simpleTriggerFactoryBean()對應的設定,

啟動類添加注解

@EnableScheduling

測驗效果

每5秒鐘執行一次:...quartz job 觸發執行...

如果前面的@Schedule和這里的Quartz的定時任務放在一起了,則執行效果為兩個Job一起執行:

...quartz job 觸發執行...
User{id=1, name='sam', age=32}
User{id=2, name='hah ', age=10}
**觸發JDK 定時器***
User{id=1, name='sam', age=32}
User{id=2, name='hah ', age=10}
**觸發JDK 定時器***
User{id=1, name='sam', age=32}
User{id=2, name='hah ', age=10}
**觸發JDK 定時器***
...quartz job 觸發執行...
User{id=1, name='sam', age=32}
User{id=2, name='hah ', age=10}
**觸發JDK 定時器***
User{id=1, name='sam', age=32}
User{id=2, name='hah ', age=10}
**觸發JDK 定時器***
User{id=1, name='sam', age=32}
User{id=2, name='hah ', age=10}
...quartz job 觸發執行...
在黑夜里夢想著光,心中覆寫悲傷,在悲傷里忍受孤獨,空守一絲溫暖, 我的淚水是無底深海,對你的愛已無言,相信無盡的力量,那是真愛永在, 我的信仰是無底深海,澎湃著心中火焰,燃燒無盡的力量,那是忠誠永在

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/440341.html

標籤:Java

上一篇:Golang開源流媒體服務器(RTMP/RTSP/HLS/FLV等協議)

下一篇:面對科技公司的制裁,俄羅斯放出封印7年的神獸:RuTracker

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more