主頁 > 後端開發 > Spring Boot 學習筆記

Spring Boot 學習筆記

2022-10-29 07:32:29 後端開發

SpringBoot 簡介

  1. 為什么要使用 Spring Boot

    因為 Spring,SpringMVC 需要使用的大量的組態檔 (xml檔案)

    還需要配置各種物件,把使用的物件放入到 spring 容器中才能使用物件

    需要了解其他框架配置規則,

  2. SpringBoot 就相當于 不需要組態檔的 Spring+SpringMVC, 常用的框架和第三方庫都已經配置好了,

    拿來就可以使用了,

  3. SpringBoot開發效率高,使用方便多了

JavaConfig

使用 java 類作為 xml 組態檔的替代, 是配置 spring 容器的純 java 的方式,

在這個 java 類中可以創建 java 物件,把物件放入 spring 容器中(注入到容器),

對于此JavaConfig相關的示例創建的是普通的Java專案,并非SpringBoot專案!

@Configuration

  • 放在類的上面,表示此類作為組態檔使用,相當于一個配置類

@Bean

  • 放在配置類中的方法上面,用來宣告物件,將物件注入到容器中
  • 方法回傳值需要是注入的物件型別
  • 若沒有配置@Bean中的 name 屬性,則從容器中獲取該物件需要用其方法名
  • 若配置了@Bean中的 name 屬性,則從容器中獲取該物件需要用配置的 name 名稱

需要使用到兩個注解:

  • @Configuration:放在一個類的上面,表示這個類是作為組態檔使用的,
  • @Bean:放在配置類中的方法上,宣告物件,把物件注入到容器中,

配置類示例:

/**
 * Configuration:表示當前類是作為組態檔使用的, 就是用來配置容器的
 *       位置:在類的上面
 *
 *  SpringConfig這個類就相當于beans.xml
 */
@Configuration
public class SpringConfig {

    /**
     * 創建方法,方法的回傳值是物件, 在方法的上面加入@Bean
     * 方法的回傳值物件就注入到容器中,
     *
     * @Bean: 把物件注入到spring容器中, 作用相當于<bean>
     *
     *     位置:方法的上面
     *
     *     說明:@Bean,不指定物件的名稱,默認是方法名是 id
     *
     */
    @Bean
    public Student createStudent(){
        Student s1  = new Student();
        s1.setName("張三");
        s1.setAge(26);
        s1.setSex("男");
        return s1;
    }

    /***
     * 指定物件在容器中的名稱(指定<bean>的id屬性)
     * @Bean的name屬性,指定物件的名稱(id)
     */
    @Bean(name = "lisiStudent")
    public Student makeStudent(){
        Student s2  = new Student();
        s2.setName("李四");
        s2.setAge(22);
        s2.setSex("男");
        return s2;
    }
}

測驗:

public class MyTest {

    @Test
    public void test01() {
        // 使用組態檔方式宣告的bean,需要用 ClassPathXmlApplicationContext,引數傳組態檔路徑
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("myStudent");
        System.out.println(student);
    }

    @Test
    public void test02() {
        // 使用配置類方式將物件注入到容器,需要使用 AnnotationConfigApplicationContext,引數傳配置類的class 
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 配置類中方法的Bean設定name屬性,則通過name屬性名獲取物件;否則默認可通過其方法名獲取
        Student s = (Student) ctx.getBean("lisiStudent");
        // Student s = (Student) ctx.getBean("makeStudent");
        // Student s = (Student) ctx.getBean("createStudent");
        System.out.println(s);
    }
}

小結:

  • 使用配置類的方式,需要在配置類上使用@Configuration;需要在配置類中的方法上使用@Bean宣告物件,將物件注入到容器中,
  • 配置類中的方法回傳值型別是需要注入的物件型別;若未配置@Bean中的 name 屬性,則獲取該物件時需要使用方法名獲取;若配置了@Bean中的 name 屬性,則通過配置的 name 名稱獲取該物件,
  • 創建容器物件時,不再使用ClassPathXmlApplicationContext介面實作類,不再通過組態檔來注入到容器物件中;而是使用AnnotationConfigApplicationContext介面實作類,通過配置類的 class 來將物件注入到容器,

@ImportResource

  • 使用在配置類的上面
  • 作用是匯入其他的 xml 組態檔, 等于在 xml 中使用 <import resources="其他組態檔"/>
  • 需要在 value 屬性中指定組態檔的路徑
@Configuration
@ImportResource(value = "https://www.cnblogs.com/luisblog/archive/2022/10/28/classpath:applicationContext.xml")
public class SpringConfig {
}

@PropertySource

  • 使用在配置類的上面
  • 用來讀取 properties 屬性組態檔
  • 使用屬性組態檔可以實作外部化配置 ,在程式代碼之外提供資料,

@ComponentScan:使用在配置類上,掃描指定包中注解,來創建物件以及給屬性賦值

示例:

--配置類--
@Configuration
@ImportResource(value = "https://www.cnblogs.com/luisblog/archive/2022/10/28/classpath:applicationContext.xml")  // 匯入xml組態檔
@PropertySource(value = "https://www.cnblogs.com/luisblog/archive/2022/10/28/classpath:config.properties")  // 讀取屬性組態檔
@ComponentScan(basePackages = "com.luis.vo")  // 宣告組件掃描器,掃描指定包中的注解
public class SpringConfig {
}

--config.properties--
tiger.name=東北虎
tiger.age=3 

--vo資料類--    
@Component("tiger")
public class Tiger {

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

    @Value("${tiger.age}")
    private Integer age;    
}  

--測驗--
@Test
public void test04() {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
    Tiger tiger = (Tiger) ctx.getBean("tiger");
    System.out.println(tiger);
}    

SpringBoot 入門

SpringBoot 是 Spring 中的一個成員,可簡化 Spring,SpringMVC 的使用,

其核心還是 IOC 容器,

SpringBoot 特點

  • Create stand-alone Spring applications

    創建 spring 應用

  • Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)

    有內嵌的 tomcat,jetty,Undertow

  • Provide opinionated 'starter' dependencies to simplify your build configuration

    提供了 starter 起步依賴,簡化應用的配置,

    比如使用 MyBatis 框架,需要在 Spring 專案中,配置 MyBatis 的物件 SqlSessionFactory ,Dao 的代理物件

    如今在 SpringBoot 專案中,在 pom.xml 里面,只需加入一個 mybatis-spring-boot-starter 依賴即可

  • Automatically configure Spring and 3rd party libraries whenever possible

    盡可能去配置 spring 和第三方庫,也叫做自動配置(就是把 spring 中的,第三方庫中的物件都創建好,放到容器中,開發人員可以直接使用)

  • Provide production-ready features such as metrics, health checks, and externalized configuration

    提供了健康檢查,統計,外部化配置

  • Absolutely no code generation and no requirement for XML configuration

    不用生成代碼,不用使用xml,做配置

創建 SpringBoot 專案的三種方式

創建 SpringBoot 專案有三種方式:

  1. 使用 Spring 提供的初始化器,就是使用向導創建 SpringBoot 應用(使用 https://start.spring.io 地址)【聯網】

  2. 使用 Spring 提供的初始化器,就是使用向導創建 SpringBoot 應用(使用國內的 https://start.springboot.io 地址)【聯網】

    還可以選擇使用阿里云的地址進行創建:https://start.aliyun.com

  3. 先直接創建 maven 專案,然后補充相關依賴,補全目錄結構即可【不需聯網】

創建簡單 SpringBoot web 專案示例:(以下選擇向導方式創建)

  1. 新建 SpringBoot 模塊,選擇 Spring Initializr向導創建

  2. 配置專案相關資訊,依賴選擇 Spring Web 進行創建

  3. 整理專案結構以及 pom 檔案

  4. 在主啟動類所在的包下創建 controller 控制器類

    @Controller
    public class HelloSpringBoot {
    
        @RequestMapping("/hello")
        @ResponseBody
        public String helloSpringBoot() {
            return "歡迎使用SpringBoot";
        }
    }
    
  5. 查看是否配置有 Spring Boot 啟動服務,若沒有則進行配置

  6. 運行主啟動類的 main 方法或 IDEA 主面板運行專案

  7. 瀏覽器輸入地址訪問 http://localhost:8080/hello(默認8080埠,無背景關系)

@SpringBootApplication

  • 其自動配置在主類之上,每個 SpringBoot 專案都會有一個主類

    @SpringBootApplication
    public class SpringbootTest03Application {
        public static void main(String[] args) {
            SpringApplication.run(SpringbootTest03Application.class, args);
        }
    }
    
@SpringBootApplication
是一個復合注解,包含以下三個注解(以下注解的功能其全具備)
@SpringBootConfiguration  -----> 該注解標注的類可當做配置類使用
@EnableAutoConfiguration  -----> 啟用自動配置,將常用框架以及第三方物件創建好
@ComponentScan  -----> 可掃描到該注解標注的類的包及其子包下其他注解
    
詳解:    
1.@SpringBootConfiguration
    
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
說明:使用了@SpringBootConfiguration注解標注的類,可以作為組態檔使用,
    可以使用@Bean宣告物件,注入到容器,
    故主類可作為一個配置類使用,在其類中可在方法上使用@Bean宣告物件

2.@EnableAutoConfiguration
啟用自動配置,把java物件配置好,注入到spring容器中;例如可以把mybatis的物件創建好,放入到容器中,
    
3.@ComponentScan 
掃描器,找到注解,根據注解的功能創建物件,給屬性賦值等,
默認掃描的包: @ComponentScan所標注的類所在的包和子包,    

SpringBoot 的組態檔

避免中文亂碼,需要在 IDEA 中設定 encoding 為 UTF-8

組態檔名: application

擴展名有:properties( k=v) 以及 yml ( k: v)

可使用 application.properties,application.yml 兩種檔案格式

創建 SpringBoot 專案時默認創建的是 application.properties 組態檔格式

以下為配置示例:

例1:application.properties 中設定埠和背景關系

# 設定埠
server.port=8888
# 設定訪問應用的背景關系路徑
server.servlet.context-path=/myWeb

例2:application.yml 中設定埠和背景關系(推薦使用

這種格式的組態檔,結構比較清晰

注意:value 值前有一個空格

server:
  port: 8083
  servlet:
    context-path: /myboot

注意:如果同時存在兩種格式的組態檔,即 application.properties 和 application.yml 兩個組態檔同時存在,則默認使用 application.properties 這種格式中的配置!

多環境配置的應用

有開發環境,測驗環境,上線的環境,

每種環境有不同的配置資訊,例如埠,背景關系訪問路徑,資料庫 url,用戶名,密碼等,所以需要多種環境配置,

使用多環境組態檔,可以方便的切換不同的配置,

多環境配置方式

  1. 創建多個組態檔,檔案命名規則:application-環境名稱.properties(yml)【一般環境名使用 dev/test/online 這幾種】

    創建開發環境的組態檔:application-dev.yml

    #專案開發使用的環境
    server:
      port: 8080
      servlet:
        context-path: /mydev
    

    創建測驗環境的組態檔:application-test.yml

    #專案測驗使用的環境
    server:
      port: 8081
      servlet:
        context-path: /mytest
    

    創建上線環境的組態檔:application-online.yml

    #專案上線使用的環境
    server:
      port: 8082
      servlet:
        context-path: /myonline
    
  2. 在主組態檔 application.yml 中激活要使用的環境【激活的配置資訊是根據多環境檔案的命名來確定】

    主組態檔中激活要使用的環境:application.yml

    #激活使用的環境
    spring:
      profiles:
        active: online
    

使用 @Value 讀取組態檔資料

我們可以在主組態檔中使用 key-value 鍵值對的格式進行資料的配置;

因為主組態檔已經由 Spring 自動管理,所以可以直接在自己寫的控制器類的屬性上通過 @Value("${server.port}")讀取組態檔中資料,并對屬性進行賦值,

@Controller
public class MyController {

    @Value("${server.port}")
    private Integer port;
    @Value("${server.servlet.context-path}")
    private String contextPath;
    @Value("${project.name}")
    private String projectName;
    @Value("${project.dev}")
    private String projectDev;

    @RequestMapping("/data")
    @ResponseBody
    public String queryData() {
        return port + "========> port " + contextPath + "========> contextPath "
                + projectName + "========> projectName " + projectDev + "========> projectDev";
    }
}

@ConfigurationProperties

  • 使用位置:類的上面
  • 作用:把組態檔中符合條件的資料映射為 java 物件
  • 需要配置其 prefix 屬性:即組態檔中的某些 key 開頭的內容

使用示例:@ConfigurationProperties(prefix = "school")

使用解釋:類上添加@ConfigurationProperties注解后,其將從屬性組態檔中找以配置的 prefix 屬性值,即school開頭的配置,將所有 school后面的配置引數與該類中的所有屬性相比較,如果匹配成功,則將組態檔中配置的對應的資料賦值給該類中同名屬性,完成資料映射,

使用示例:

  1. 在組態檔 application.properties 中配置自定義資料

    #配置埠號
    server.port=8888
    #配置背景關系訪問路徑
    server.servlet.context-path=/myboot
    
    #自定義資料
    school.name=哈師大
    school.addr=東北
    school.level=2
    
  2. 創建資料物件

    @Component
    @ConfigurationProperties(prefix = "school")
    public class SchoolInfo {
    
        private String name;
        private String addr;
        private Integer level;
        // getter,setter,toString...
    }    
    
  3. 創建控制器類

    @Controller
    public class MyController {
    
        @Resource
        private SchoolInfo info;
    
        @RequestMapping("/info")
        @ResponseBody
        public String querySchoolInfo() {
            return "info = " + info;
        }
    }
    
  4. 運行,訪問測驗

    訪問:http://localhost:8888/myboot/info
    結果:info = SchoolInfo{name='哈師大', addr='東北', level=2}
    

SpringBoot 中使用 JSP(不推薦,了解即可)

SpringBoot 默認不支持 JSP,需要進行相關配置才能使用 JSP,

JSP 技術慢慢被淘汰,有更好的技術替代它,

使用 SpringBoot 框架時不推薦使用 JSP,后面將使用 Thymeleaf 模板技術完全替代 JSP!

使用步驟:

  1. 創建 SpringBoot 專案,整理專案結構和 pom 檔案

  2. 添加一個處理 JSP 的依賴,負責編譯 JSP 檔案(如果需要使用 servlet jsp jstl 功能則需要另外加對應依賴)

    <!--處理JSP的依賴-->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
    </dependency>
    
    <dependency>
    	<groupId>javax.servlet</groupId>
    	<artifactId>jstl</artifactId>
    </dependency>
    
    <dependency>
    	<groupId>javax.servlet</groupId>
    	<artifactId>javax.servlet-api</artifactId>
    </dependency>
    
    <dependency>
    <groupId>javax.servlet.jsp</groupId>
    	<artifactId>javax.servlet.jsp-api</artifactId>
    	<version>2.3.1</version>
    </dependency>
    
  3. 在 main 目錄下創建一個名為 webapp 的目錄(名稱固定);在專案工程結構中設定該目錄為 web 資源目錄(進入專案結構設定后,點擊 Web 選項,從 Web Resource Directories 下添加新創建的 webapp 目錄為 web 資源目錄即可)

  4. 在 webapp 目錄下新建 index.jsp 用來顯示 controller 中的資料

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>jsp</title>
    </head>
    <body>
        SpringBoot中使用JSP顯示資料:${data}
    </body>
    </html>
    
  5. 創建 controller 控制器類,指定資料和視圖

    @Controller
    public class JspController {
    
        @RequestMapping("/myjsp")
        public String doJsp(Model model) {
            // 將資料放到request中(與request.setAttribute作用相同)
            model.addAttribute("data", "SpringBoot使用JSP");
            return "index";
        }
    }
    
  6. 組態檔中配置視圖決議器,埠號以及背景關系等資訊

    #配置埠號
    server.port=7070
    #配置背景關系訪問路徑
    server.servlet.context-path=/myboot
    
    #配置視圖決議器
    # / = src/main/webapp
    spring.mvc.view.prefix=/
    spring.mvc.view.suffix=.jsp
    
  7. 在 pom.xml 中指定 jsp 檔案編譯后的存放目錄【在 pom 的 build 標簽下進行指定】

    修改 pom 檔案后,記得重新加載下,確保 pom 檔案資源完全重繪!

    <!-- 指定jsp編譯后的存放目錄 -->
    <resources>
        <resource>
            <!-- jsp原來的目錄 -->
            <directory>src/main/webapp</directory>
            <!-- 指定編譯后的存放目錄 -->
            <targetPath>META-INF/resources</targetPath>
            <!-- 指定治理后的目錄和檔案 -->
            <includes>
                <include>**/*.*</include>
            </includes>
        </resource>
    </resources>
    
  8. 直接運行并啟動主程式,輸入地址訪問測驗

    http://localhost:7070/myboot/myjsp
    

兩點需要注意下:

  • 必須添加處理 jsp 的依賴
  • 必須指定 jsp 編譯后的存放目錄

原因:因為 SpringBoot 使用的是內嵌的 Tomcat

SpringBoot 使用容器 ApplicationContext

使用場景:不想啟動整個專案,只想測驗某個功能,就可直接通過run方法獲取容器物件,通過容器物件進行相關測驗,

如果想通過代碼,從容器中獲取物件:

通過SpringApplication.run(Application.class, args); 其回傳值即可獲取容器物件,

SpringApplication.run(SpringbootUseJspApplication.class, args)回傳的就是一個 ApplicationContext 容器物件!

決議:SpringApplication.run(SpringbootUseJspApplication.class, args);

點進其run方法:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}   

查看ConfigurableApplicationContext類:
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {...}    

總結:通過run方法獲取的是容器物件ApplicationContext的子類,即也是一個容器物件,

容器使用示例:

  1. 創建 SpringBoot 專案時選擇 Spring Web 依賴,整理專案目錄和 pom 檔案

  2. 創建 service 介面及其實作類,定義測驗方法

    public interface UserService {
        void sayHello(String name);
    }
    
    @Service("userService")
    public class UserServiceImpl implements UserService {
    
        @Override
        public void sayHello(String name) {
            System.out.println("hello " + name);
        }
    }
    
  3. 在主啟動類中直接獲取并使用容器物件進行測驗

    @SpringBootApplication
    public class SpringbootUseContainerApplication {
    
        public static void main(String[] args) {
            // 直接通過run方法獲取容器物件
            ApplicationContext ctx = SpringApplication.run(SpringbootUseContainerApplication.class, args);
            // 從容器中獲取指定物件
            UserService userService = (UserService) ctx.getBean("userService");
            // 呼叫物件的方法進行測驗
            userService.sayHello("luis");
        }
    }
    

CommandLineRunner 和 ApplcationRunner 介面

介紹:這兩個介面都有一個 run 方法,

執行時機:容器物件創建好后自動會執行介面中的 run() 方法

使用場景:需要在容器啟動后執行一些內容,比如讀取組態檔,資料庫連接之類的,

使用方式:實作介面,重寫 run 方法,方法中寫需要在容器啟動后待執行的內容,

@FunctionalInterface
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}

@FunctionalInterface
public interface ApplicationRunner {
    void run(ApplicationArguments args) throws Exception;
}

使用示例:(以下以實作 CommandLineRunner介面為例)

  1. 創建 SpringBoot 專案,不用選擇依賴,整理專案目錄和 pom 檔案

  2. 新建 service 介面以及實作類,定義測驗方法

    public interface UserService {
        void sayHello(String name);
    }
    
    @Service("userService")
    public class UserServiceImpl implements UserService {
        @Override
        public void sayHello(String name) {
            System.out.println("你好," + name);
        }
    }
    
  3. 讓啟動類實作 CommandLineRunner介面,重寫 run 方法進行測驗

    @SpringBootApplication
    public class SpringbootRunApplication implements CommandLineRunner {
    
        @Resource
        private UserService userService;
    
        public static void main(String[] args) {
            System.out.println("main start");
            // 創建容器物件
            SpringApplication.run(SpringbootRunApplication.class, args);
            System.out.println("main end");
        }
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("容器物件創建后執行此run方法");
            // 此方法在容器物件創建后自動執行
            // 可在此呼叫容器物件中的方法
            userService.sayHello("jack");
        }
    }
    
  4. 運行主程式,進行測驗

    運行結果:

    main start
    容器物件創建后執行此run方法
    你好,jack
    main end
    

SpringBoot 和 Web 組件

講三個內容:攔截器、Servlet、Filter

SpringBoot 中使用攔截器

攔截器是 SpringMVC 中的一種物件,能攔截對 Controller 的請求,

在框架中有系統實作好的攔截器, 也可以自定義攔截器,實作對請求的預先處理,

回顧 SpringMVC 中使用攔截器

  1. 創建類實作 SpringMVC 框架的 HandlerInterceptor 介面,重寫對應的方法

    public interface HandlerInterceptor {
     default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         return true;
     }
    
     default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
     }
    
     default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
     }
    }
    
  2. 在 SpringMVC 的組態檔中,宣告攔截器

    <mvc:interceptors>
    	<mvc:interceptor>
        	<mvc:path="url" />
            <bean />
        </mvc:interceptor>
    </mvc:interceptors>
    

SpringBoot 中使用攔截器

示例:

  1. 創建 SpringBoot 專案,選擇 Spring Web 依賴,整理專案目錄和 pom 檔案

  2. 創建攔截器類,實作 HandlerInterceptor介面,重寫相關方法

    public class LoginInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("執行LoginInterceptor攔截器類的preHandle方法");
            return true;
        }
    }
    
  3. 創建自定義配置類實作 WebMvcConfigurer介面,重寫addInterceptors介面方法,在此方法中進行攔截器的相關配置(注入攔截器物件,指定攔截地址等)

    @Configuration // 成為配置類=====
    public class MyAppConfig implements WebMvcConfigurer {
    
        // 重寫addInterceptors方法,添加攔截器物件,注入到容器中
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
    
            // 創建攔截器物件
            HandlerInterceptor loginInterceptor = new LoginInterceptor();
    
            // 指定攔截的請求URI地址
            String[] path = {"/user/**"};
            // 指定不攔截的URI地址
            String[] excludePath = {"/user/login"};
    
            // 添加攔截器物件,指定攔截以及不攔截的URI地址
            registry.addInterceptor(loginInterceptor)
                    .addPathPatterns(path)
                    .excludePathPatterns(excludePath);
        }
    }
    
  4. 創建控制器類,進行資源訪問攔截測驗

    @Controller
    @RequestMapping("/user")
    public class BootController {
    
        @RequestMapping("/account")
        @ResponseBody
        public String userAccount() {
            return "訪問/user/account地址";
        }
    
        @RequestMapping("/login")
        @ResponseBody
        public String userLogin() {
            return "訪問/user/login地址";
        }
    }
    
  5. 運行主程式,進行訪問測驗

    分別訪問下列兩個地址:
    http://localhost:8080/user/account
    http://localhost:8080/user/login
    訪問的測驗結果:
    訪問http://localhost:8080/user/account時,后臺有攔截器攔截資訊輸出【此請求走攔截器,被攔截器攔截】
    訪問http://localhost:8080/user/login時,后臺無攔截器攔截資訊輸出【此請求不走攔截器,不會被攔截器攔截】
    

SpringBoot 中使用 Servlet

使用步驟:

  1. 創建 SpringBoot 專案,選擇 Spring Web 依賴,整理專案目錄和 pom 檔案

  2. 創建 servlet 類,繼承 HttpServlet,重寫相關方法

    public class MyServlet extends HttpServlet {
    
        // 直接重寫service方法,則doGet和doPost請求都直接走此方法
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            // 設定字符編碼
            response.setContentType("text/html;charset=UTF-8");
    
            // 使用應答物件HttpServletResponse,輸出應答結果
            PrintWriter out = response.getWriter();
            out.print("SpringBoot中使用Servlet");
            out.flush();
            out.close();
        }
    }
    
  3. 創建自定義配置類,在類中定義指定回傳值型別的方法,注冊 Servlet 物件

    @Configuration
    public class WebApplicationConfig {
    
        // ====定義指定回傳值型別的方法,注冊servlet物件====
        @Bean
        public ServletRegistrationBean servletRegistrationBean() {
    
            // 兩種方式注冊servlet:
    
            // 方式一:使用ServletRegistrationBean物件的有參構造
            // 下列物件構造方法引數:第一個是需要注冊的servlet物件,第二個是對應servlet的訪問地址
            // ServletRegistrationBean bean = new ServletRegistrationBean(new MyServlet(), "/login1", "/login2");
    
            // 方式二:使用ServletRegistrationBean物件的無參構造
            ServletRegistrationBean bean = new ServletRegistrationBean();
            bean.setServlet(new MyServlet());
            bean.addUrlMappings("/login3", "/login4");
            return bean;
        }
    }
    
  4. 運行主程式,輸入地址訪問測驗

    http://localhost:8080/login1
    http://localhost:8080/login2
    http://localhost:8080/login3
    http://localhost:8080/login4
    

SpringBoot 中使用過濾器

Filter 是 Servlet 規范中的過濾器,可以處理請求,對請求的引數,屬性進行調整,

常常在過濾器中處理字符編碼,

SpringBoot 中使用過濾器 Filter:

使用步驟:

  1. 創建 SpringBoot 專案,選擇 Spring Web 依賴,整理專案目錄和 pom 檔案,重繪 pom

  2. 創建自定義的過濾器類,實作 javax.servlet.Filter 介面,重寫 doFilter 方法(注意實作的是 servlet 中的 Filter 介面)

    public class MyFilter implements Filter {
        
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("執行自定義過濾器類MyFilter中的doFilter方法");
            // 放行
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
    
  3. 創建自定義配置類,在類中定義指定回傳值型別的方法,注冊過濾器物件

    @Configuration
    public class WebApplicationConfig {
    
        @Bean
        public FilterRegistrationBean filterRegistrationBean() {
            
            // 注冊自定義過濾器類,并指定過濾的地址
            FilterRegistrationBean bean = new FilterRegistrationBean();
            bean.setFilter(new MyFilter());
            bean.addUrlPatterns("/user/*");
            return bean;
        }
    }
    
  4. 創建控制器類,進行資源訪問過濾測驗

    @Controller
    public class CustomFilterController {
    
        @RequestMapping("/user/login")
        @ResponseBody
        public String userLogin() {
            return "訪問/user/login";
        }
    
        @RequestMapping("/query")
        @ResponseBody
        public String query() {
            return "訪問/query";
        }
    }
    
  5. 運行主啟動類,輸入訪問地址測驗

    http://localhost:8080/query
    http://localhost:8080/user/login
    

SpringBoot 中使用字符集過濾器

一般,都是使用字符集過濾器 CharacterEncodingFilter解決 post 請求中文亂碼的問題,

CharacterEncodingFilter : 解決 post 請求中文亂碼的問題,

在 SpringMVC 框架, 需要在 web.xml 注冊過濾器并配置其相關屬性,

在SpringBoot 中使用字符集過濾器解決 post 請求亂碼有兩種方式:

使用示例:

  1. 創建 SpringBoot 專案,選擇 Spring Web 依賴,整理專案目錄和 pom 檔案,重繪 pom

  2. 創建自定義 servlet,處理請求

    public class MyServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            response.setContentType("text/html"); // 此處并沒有設定字符編碼方式
    
            PrintWriter out = response.getWriter();
            out.write("沒有設定編碼方式,默認使用ISO-8859-1,會出現中文亂碼");
            out.flush();
            out.close();
        }
    }
    
  3. 創建自定義配置類,注冊 servlet,設定訪問路徑

    @Configuration
    public class WebSystemConfig {
    
        // 注冊servlet,設定訪問路徑
        @Bean
        public ServletRegistrationBean servletRegistrationBean() {
    
            ServletRegistrationBean bean = new ServletRegistrationBean();
            bean.setServlet(new MyServlet());
            bean.addUrlMappings("/myservlet");
            return bean;
        }
    }
    
  4. 啟動主程式,輸入訪問地址進行測驗

    http://localhost:8080/myservlet
    結果:出現中文亂碼
    ?????????????ISO-8859-1????????
    

方式一:配置類中設定字符編碼(不推薦)

不僅需要在配置類中注冊字符集過濾器類,設定字符編碼,還需在組態檔中關閉默認啟用的過濾器,

  1. 在自定義配置類中需創建指定回傳值型別的方法,注冊 CharacterEncodingFilter字符集過濾器類,設定字符編碼
@Configuration
public class WebSystemConfig {

    // 注冊servlet,設定訪問路徑
    @Bean
    public ServletRegistrationBean servletRegistrationBean() {

        ServletRegistrationBean bean = new ServletRegistrationBean();
        bean.setServlet(new MyServlet());
        bean.addUrlMappings("/myservlet");
        return bean;
    }

    // ==================================================================
    // 注冊CharacterEncodingFilter,并設定字符編碼方式
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {

        FilterRegistrationBean reg = new FilterRegistrationBean();

        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        // 設定字符編碼方式
        filter.setEncoding("UTF-8");
        // 指定request,response都使用encoding的值
        filter.setForceEncoding(true);

        reg.setFilter(filter); // 注冊字符集過濾器物件CharacterEncodingFilter
        reg.addUrlPatterns("/*"); // 設定過濾地址

        return reg;
    }
    // ==================================================================    
}
  1. 修改 application.properties 檔案,讓自定義的過濾器起作用

    #SpringBoot中默認已經配置了CharacterEncodingFilter, 編碼默認ISO-8859-1
    #設定enabled=false 作用是關閉系統中配置好的過濾器, 使用自定義的CharacterEncodingFilter
    server.servlet.encoding.enabled=false
    

方式二:組態檔中設定字符編碼(推薦)

只需要通過幾行配置,即可完成字符編碼的設定,

#讓系統的CharacterEncdoingFilter生效(默認為true)
server.servlet.encoding.enabled=true
#指定使用的編碼方式
server.servlet.encoding.charset=UTF-8
#強制request,response都使用charset屬性的值
server.servlet.encoding.force=true

ORM 操作 MySQL

ORM 是“物件-關系-映射”的簡稱,(Object Relational Mapping,簡稱ORM)

使用 MyBatis 框架操作 MySQL,

使用 MyBatis 框架操作資料,使用 SpringBoot 框架集成 MyBatis,

SpringBoot 集成 Mybatis

以下是集成步驟示例,創建 dao 介面的代理物件有好幾種方式可供選擇,以下方式并不完美,注意后續自己修改!

前期準備
資料庫名:springdb
資料庫表:student
欄位:id (int auto_increment) name(varchar) age(int)

步驟:

  1. 創建 SpringBoot 專案,添加 Spring Web、MyBatis、MySQL 依賴,整理專案目錄和 pom 檔案,重繪 pom

  2. 創建物體類 model

    public class Student {
        private Integer id;
        private String name;
        private Integer age;
        // getter,setter,toString...
    }    
    
  3. 寫 dao 介面和 mapper 檔案

    此處 dao 介面上使用了 @Mapper注解,告訴MyBatis這是 dao 介面,創建此介面的代理物件

    @Mapper  // 告訴MyBatis這是dao介面,創建此介面的代理物件
    public interface StudentDao {
    
        Student selectById(@Param("stuId") Integer id);
    }
    
    <?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.luis.dao.StudentDao">
    
        <select id="selectById" resultType="com.luis.model.Student">
            select id,name,age from student where id=#{stuId}
      </select>
    
    </mapper>
    
  4. 創建 service 介面及其實作類

    // 介面
    public interface StudentService {
    
        Student queryStudentById(Integer id);
    }
    
    // 實作類
    @Service
    public class StudentServiceImpl implements StudentService {
    
        @Resource
        private StudentDao studentDao;
    
        @Override
        public Student queryStudentById(Integer id) {
            return studentDao.selectById(id);
        }
    }
    
  5. 創建控制器類

    @Controller
    @RequestMapping("/student")
    public class StudentController {
        
        @Resource
        private StudentService studentService;
    
        @RequestMapping("/queryById")
        @ResponseBody
        public String queryStudentById(Integer id) {
            Student student = studentService.queryStudentById(id);
            return student.toString();
        }
    }
    
  6. 在 pom 檔案的 build 標簽下添加 mapper 檔案的 resources 插件

    <!--   resources插件,將mapper檔案復制到classes目錄下     -->
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    
  7. 在主組態檔中配置埠,背景關系訪問路徑,資料庫連接等資訊

    server.port=8888
    server.servlet.context-path=/orm
    
    #配置資料庫連接資訊 注意mysql新舊版本配置不同
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    spring.datasource.username=root
    spring.datasource.password=luis
    
  8. 運行啟動類,輸入訪問地址測驗【注意:填的id必須資料庫中有,否則會出現空指標例外】

    http://localhost:8888/orm/student/queryById?id=29
    

日志配置

在主組態檔中配置 mybatis 日志:(可選不同的日志列印,如選 log4j 這種的,則另需添加相關依賴)

# 日志配置
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

第一種方式:使用@Mapper(不建議)

  • 使用在類上
  • 作用:告訴 MyBatis 這是 dao 介面,會自動創建此介面的代理物件
  • 缺點:每一個需要創建代理物件的 dao 介面都需要加上該注解,dao 介面多的時候不方便!

示例:

@Mapper  // 告訴MyBatis這是dao介面,創建此介面的代理物件
public interface StudentDao {

    Student selectById(@Param("stuId") Integer id);
}

第二種方式:使用@MapperScan

  • 通常使用在主啟動類上
  • basePackages屬性:通常配置 dao 介面所在包名
  • 作用:找到 Dao 介面以及 Mapper 檔案(可直接掃描到該包下所有的 dao 介面和 mapper 檔案)
  • 優點:使用該注解直接掃描指定包,不用在每一個 dao 介面上分別加 @Mapper注解

示例:

@SpringBootApplication
@MapperScan(basePackages = "com.luis.dao") // 掃描指定包,找到dao介面和mapper檔案,mybatis自動創建介面的代理物件
public class SpringbootMapperApplication {

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

}

第三種方式:Mapper檔案和Dao介面分開管理(開發常用,推薦使用)

之前我們的 dao 目錄下既有 Java 檔案,也有 xml/mapper 檔案;如果希望 Java 目錄下只有 Java 檔案,將 xml/mapper 檔案放到 resources 下分開管理,那么只使用之前的 @MapperScan注解是掃描不到 resources 下的 Mapper 檔案的,此時我們就需要在組態檔中指定 Mapper 檔案的位置,

示例:

操作:在 resources 下創建子目錄(自定義的),例如 mapper,用來存放 mapper 映射檔案,將之前 dao 下的 mapper 檔案全剪切到 mapper 目錄下,

  1. 同樣,我們仍然需要在主啟動類上使用 @MapperScan注解指定 dao 所在的包,掃描 dao 介面:
@SpringBootApplication
@MapperScan(basePackages = "com.luis.dao") // 掃描指定包,找到dao介面和mapper檔案,mybatis自動創建介面的代理物件
public class SpringbootMapperApplication {

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

}
  1. 在主組態檔中指定 mapper 映射檔案的位置:
#指定mapper檔案的位置
mybatis.mapper-locations=classpath:mapper/*.xml
  1. 配置資源插件,確保資源檔案編譯到 classes 目錄下:
<!--   resources插件,將所有資源檔案復制到classes目錄下【配置在pom.xml的build標簽下】     -->
<resources>
    <resource>
        <directory>src/main/resources</directory>
        <includes>
            <include>**/*.*</include>
        </includes>
    </resource>
</resources>

注意:如果專案編譯后 .xml/properties/yml 檔案沒有出現在 classes 目錄下,則需要在 pom 中添加 resources 資源插件,

事務及mybatis自動代碼生成器的使用

回顧 Spring 框架中的事務:

  1. 管理事務的物件:事務管理器(介面,介面有很多的實作類)

    例如:使用 Jdbc 或 mybatis 訪問資料庫,使用的事務管理器:DataSourceTransactionManager

  2. 宣告式事務:使用 xml 組態檔或者使用注解說明事務控制的內容

    控制事務:隔離級別,傳播行為,超時時間

  3. 事務處理方式:

    1. Spring 框架中的 @Transactional
    2. Spring 支持 aspectj 框架的事務配置,可在 xml 組態檔中,宣告事務控制的內容

SpringBoot 中使用事務:上面的兩種方式都可以,

使用步驟:(以下以注解方式演示事務的使用:)

  1. 在業務方法的上面加入 @Transactional ,加注解后,方法就有事務功能

  2. 明確的在主啟動類的上面,加入@EnableTransactionManager,啟用事務管理器(可不用添加此注解

/**
     * @Transactional 表示方法有事務支持,拋出運行時例外,則進行回滾
     * 使用MySQL默認的傳播行為、隔離級別、超時時間
     */
@Transactional // 可通過屬性配置傳播行為、隔離級別、超時時間
@Override
public int addUser(User user) {
    System.out.println("業務方法addUser開始執行");
    int rows = userMapper.insert(user);
    System.out.println("業務方法addUser結束執行");

    // 模擬發生運行時例外
    // int num = 10 / 0;
    return rows;
}

SpringBoot 中通過注解使用事務,一句話說明:直接在需要開啟事務的業務方法上添加 @Transactional 注解即可!

示例:(有mybatis自動代碼生成器的使用示例,可自動生成 model 物體類, dao 介面以及 mapper 映射檔案)

準備資料庫表:
資料庫名:springdb 表名:user
欄位:id(int auto_increment)name(varchar)age(int)
  1. 創建 SpringBoot 專案,添加 Spring Web、MyBatis、MySQL 依賴,整理專案目錄和 pom 檔案

  2. 在 pom 的 plugins 標簽下添加 mybatis 自動代碼生成插件

    <!--mybatis自動代碼生成插件-->
    <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.6</version>
        <configuration>
            <!--組態檔的位置:在專案的根目錄下,和src平級-->
            <configurationFile>GeneratorMapper.xml</configurationFile>
            <verbose>true</verbose>
            <overwrite>true</overwrite>
        </configuration>
    </plugin>
    
  3. 在 pom 的 build 標簽下添加資源插件,處理資源檔案,重繪 pom

    <!--   處理資源檔案     -->
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/**.*</include>
            </includes>
        </resource>
    </resources>
    
  4. 在專案根目錄下創建 GeneratorMapper.xml檔案,其與 src 平級;將下列內容拷貝到檔案中;依照注釋修改配置,修改完后,點開右側 maven 快捷視窗,使用當前專案下 plugins 下 mybatis-genetate 下的 mybatis 自動代碼生成插件進行生成,

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
            PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
            "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    
    <generatorConfiguration>
    
        <!-- 指定連接資料庫的JDBC驅動包所在位置,指定到你本機的完整路徑 -->
        <classPathEntry location="D:\Java\tools\mysql-connector-java-8.0.28.jar"/>
    
        <!-- 配置table表資訊內容體,targetRuntime指定采用MyBatis3的版本 -->
        <context id="tables" targetRuntime="MyBatis3">
    
            <!-- 抑制生成注釋,由于生成的注釋都是英文的,可以不讓它生成 -->
            <commentGenerator>
                <property name="suppressAllComments" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/true" />
            </commentGenerator>
    
            <!-- 配置資料庫連接資訊 -->
            <jdbcConnection driver
                            connectionURL="jdbc:mysql://localhost:3306/springdb?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=GMT%2B8"
                            userId="root"
                            password="luis">
                <!--MySQL 不支持 schema 或者 catalog 所以需要添加這個-->
                <!--設定原因參考:https://blog.csdn.net/qq_40233736/article/details/83314596-->
                <property name="nullCatalogMeansCurrent" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/true" />
            </jdbcConnection>
    
            <!-- 生成model類,targetPackage指定model類的包名, targetProject指定生成的model放在eclipse的哪個工程下面-->
            <javaModelGenerator targetPackage="com.luis.model"
                                targetProject="D:\1a-Projects\springboot-projects\springboot-transactional\src\main\java">
                <property name="enableSubPackages" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/false" />
                <property name="trimStrings" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/false" />
            </javaModelGenerator>
    
            <!-- 生成MyBatis的Mapper.xml檔案,targetPackage指定mapper.xml檔案的包名, targetProject指定生成的mapper.xml放在eclipse的哪個工程下面 -->
            <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
                <property name="enableSubPackages" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/false" />
            </sqlMapGenerator>
    
            <!-- 生成MyBatis的Mapper介面類檔案,targetPackage指定Mapper介面類的包名, targetProject指定生成的Mapper介面放在eclipse的哪個工程下面 -->
            <javaClientGenerator type="XMLMAPPER" targetPackage="com.luis.dao" targetProject="src/main/java">
                <property name="enableSubPackages" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/false" />
            </javaClientGenerator>
    
            <!-- 資料庫表名及對應的Java模型類名 -->
            <table tableName="user" domainObjectName="User"
                   enableCountByExample="false"
                   enableUpdateByExample="false"
                   enableDeleteByExample="false"
                   enableSelectByExample="false"
                   selectByExampleQueryId="false"/>
    
            <table tableName="b_bid_info" domainObjectName="BidInfo"
                   enableCountByExample="false"
                   enableUpdateByExample="false"
                   enableDeleteByExample="false"
                   enableSelectByExample="false"
                   selectByExampleQueryId="false"/>
    
    
            <table tableName="b_income_record" domainObjectName="IncomeRecord"
                   enableCountByExample="false"
                   enableUpdateByExample="false"
                   enableDeleteByExample="false"
                   enableSelectByExample="false"
                   selectByExampleQueryId="false"/>
    
    
            <table tableName="b_recharge_record" domainObjectName="RechargeRecord"
                   enableCountByExample="false"
                   enableUpdateByExample="false"
                   enableDeleteByExample="false"
                   enableSelectByExample="false"
                   selectByExampleQueryId="false"/>
    
    
            <table tableName="u_user" domainObjectName="User"
                   enableCountByExample="false"
                   enableUpdateByExample="false"
                   enableDeleteByExample="false"
                   enableSelectByExample="false"
                   selectByExampleQueryId="false"/>
    
    
            <table tableName="u_finance_account" domainObjectName="FinanceAccount"
                   enableCountByExample="false"
                   enableUpdateByExample="false"
                   enableDeleteByExample="false"
                   enableSelectByExample="false"
                   selectByExampleQueryId="false"/>
        </context>
    
    </generatorConfiguration>
    
  5. 主組態檔配置

    #配置埠
    server.port=9090
    #context-path
    server.servlet.context-path=/mytrans
    
    #資料庫連接配置
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    spring.datasource.username=root
    spring.datasource.password=luis
    
    #配置mapper檔案路徑
    mybatis.mapper-locations=classpath:mapper/*.xml
    #開啟日志
    mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
    
  6. 使用 mybatis 生成器生成的 model、dao、mapper 檔案

    // model
    public class User {
        private Integer id;
        private String name;
        private Integer age;
        // get,set
    }
    
    // dao
    public interface UserMapper {
        int deleteByPrimaryKey(Integer id);
    
        int insert(User record);
    
        int insertSelective(User record);
    
        User selectByPrimaryKey(Integer id);
    
        int updateByPrimaryKeySelective(User record);
    
        int updateByPrimaryKey(User record);
    }
    
    <?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.luis.dao.UserMapper">
        <resultMap id="BaseResultMap" type="com.luis.model.User">
            <id column="id" jdbcType="INTEGER" property="id" />
            <result column="name" jdbcType="VARCHAR" property="name" />
            <result column="age" jdbcType="INTEGER" property="age" />
        </resultMap>
        <sql id="Base_Column_List">
            id, name, age
        </sql>
        <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
            select 
            <include refid="Base_Column_List" />
            from user
            where id = #{id,jdbcType=INTEGER}
        </select>
        <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
            delete from user
            where id = #{id,jdbcType=INTEGER}
        </delete>
        <insert id="insert" parameterType="com.luis.model.User">
            insert into user (id, name, age
            )
            values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}
            )
        </insert>
        <insert id="insertSelective" parameterType="com.luis.model.User">
            insert into user
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="id != null">
                    id,
                </if>
                <if test="name != null">
                    name,
                </if>
                <if test="age != null">
                    age,
                </if>
            </trim>
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="id != null">
                    #{id,jdbcType=INTEGER},
                </if>
                <if test="name != null">
                    #{name,jdbcType=VARCHAR},
                </if>
                <if test="age != null">
                    #{age,jdbcType=INTEGER},
                </if>
            </trim>
        </insert>
        <update id="updateByPrimaryKeySelective" parameterType="com.luis.model.User">
            update user
            <set>
                <if test="name != null">
                    name = #{name,jdbcType=VARCHAR},
                </if>
                <if test="age != null">
                    age = #{age,jdbcType=INTEGER},
                </if>
            </set>
            where id = #{id,jdbcType=INTEGER}
        </update>
        <update id="updateByPrimaryKey" parameterType="com.luis.model.User">
            update user
            set name = #{name,jdbcType=VARCHAR},
            age = #{age,jdbcType=INTEGER}
            where id = #{id,jdbcType=INTEGER}
        </update>
    </mapper>
    
  7. 創建 service 介面及其實作類,在實作類的業務方法上添加 @Transactional注解,開啟事務支持

    public interface UserService {
        int addUser(User user);
    }
    
    @Service
    public class UserServiceImpl implements UserService {
    
        @Resource
        private UserMapper userMapper;
    
        /**
         * @Transactional 表示方法有事務支持,拋出運行時例外,則進行回滾
         * 使用MySQL默認的傳播行為、隔離級別、超時時間
         */
        @Transactional
        @Override
        public int addUser(User user) {
            System.out.println("業務方法addUser開始執行");
            int rows = userMapper.insert(user);
            System.out.println("業務方法addUser結束執行");
    
            // 模擬發生運行時例外
            int num = 10 / 0; // 測驗時通過注釋以及放開觀察事務控制
            return rows;
        }
    }
    
  8. 創建控制器類

    @Controller
    public class UserController {
        
        @Resource
        private UserService userService;
    
        @RequestMapping("/addStudent")
        @ResponseBody
        public String addStudent(String name, Integer age) {
    
            User user = new User();
            user.setName(name);
            user.setAge(age);
            int rows = userService.addUser(user);
            return "添加結果:" + rows;
        }
    }
    
  9. 主啟動類上添加@EnableTransactionManagement注解,啟用事務管理器,與業務方法上的@Transactional配套使用;繼續在主啟動類上添加@MapperScan注解,指定dao所在的包,掃描dao包下dao介面和mapper檔案,

    @SpringBootApplication
    @EnableTransactionManagement // 啟用事務管理器,與業務方法上的@Transactional一起使用
    @MapperScan(basePackages = "com.luis.dao") // 指定dao所在的包,掃描dao包下dao介面和mapper檔案
    public class SpringbootTransactionalApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootTransactionalApplication.class, args);
        }
    }
    
  10. 運行主啟動類,瀏覽器輸入訪問地址;配合業務方法中設定的運行時例外(分別注釋和放開),觀察訪問結果以及資料庫表中資料變化進行測驗

    http://localhost:9090/mytrans/addUser?name=luis&age=5
    測驗結果:發生運行時例外,進行了事務回滾,資料操作撤銷,但主鍵會自增;無運行時例外,資料添加成功
    結論:該業務方法支持了事務
    

介面架構風格——RESTful

介面的概念

  • 介面: API(Application Programming Interface,應用程式介面)是一些預先定義的介面(如函式、HTTP介面),或指軟體系統不同組成部分銜接的約定, 用來提供應用程式與開發人員基于某軟體或硬體得以訪問的一組例程,而又無需訪問原始碼,或理解內部作業機制的細節,

此介面不是指 Java 中介面 Interface,而是一種應用程式介面,指可訪問 servlet,controller 的 url,呼叫其他程式的函式!

前后端分離

前后端分離的思想:前端從后端剝離,形成一個前端工程,前端只利用Json來和后端進行互動,后端不回傳頁面,只回傳Json資料,前后端之間完全通過public API約定,

前后端分離(解耦)的核心思想是:前端Html頁面通過Ajax呼叫后端的RestFul API并使用Json資料進行互動,

注: 【在互聯網架構中,web服務器:一般指像nginx,apache這類的服務器,他們一般只能決議靜態資源,應用服務器:一般指像tomcat,jetty,resin這類的服務器可以決議動態資源也可以決議靜態資源,但決議靜態資源的能力沒有web服務器好,】

一般只有Web服務器才能被外網訪問,應用服務器只能內網訪問,

————————————————
著作權宣告:本文為CSDN博主「山河遠闊」的原創文章,遵循CC 4.0 BY-SA著作權協議,轉載請附上原文出處鏈接及本宣告,
原文鏈接:https://blog.csdn.net/weixin_37539378/article/details/79956760

前后端分離并非僅僅只是一種開發模式,而是一種架構模式(前后端分離架構),
千萬不要以為只有在擼代碼的時候把前端和后端分開就是前后端分離了,需要區分前后端專案!
前端專案與后端專案是兩個專案,放在兩個不同的服務器,需要獨立部署,兩個不同的工程,兩個不同的代碼庫,不同的開發人員,
前后端工程師需要約定互動介面,實作并行開發,開發結束后需要進行獨立部署,前端通過ajax來呼叫http請求呼叫后端的restful api,
前端只需要關注頁面的樣式與動態資料的決議&渲染,而后端專注于具體業務邏輯,
————————————————下面原文很有閱讀價值!
著作權宣告:本文為CSDN博主「山河遠闊」的原創文章,遵循CC 4.0 BY-SA著作權協議,轉載請附上原文出處鏈接及本宣告,
原文鏈接:https://blog.csdn.net/weixin_37539378/article/details/79956760

REST 介紹

  • REST (英文:Representational State Transfer ,簡稱 REST;中文: 表現層狀態轉移 )

  • 一種互聯網軟體架構設計的風格,但它并不是標準,它只是提出了一組客戶端和服務器互動時的架構理念和設計原則,基于這種理念和原則設計的介面可以更簡潔,更有層次,

  • 任何的技術都可以實作這種理念,如果一個架構符合 REST 原則,就稱它為 RESTFul 架構

比如我們要訪問一個 http 介面:http://localhost:8080/boot/order?id=1021&status=1
采用 RESTFul 風格則 http 地址為:http://localhost:8080/boot/order/1021/1

表現層狀態轉移::

  • 表現層就是視圖層,顯示資源的,通過視圖頁面,jsp 等等顯示操作資源的結果,

  • 狀態: 資源變化

  • 轉移:資源是可以變化的,資源能創建,new 狀態,資源創建后可以查詢資源,能看到資源的內容,這個資源內容,可以被修改,修改后,資源和之前的不一樣,

REST中的要素:

  • 用 REST 表示資源和對資源的操作,在互聯網中,表示一個資源或者一個操作,

  • 資源是使用 url 表示的,在互聯網中,使用的圖片,視頻,文本,網頁等等都是資源,

  • 資源用名詞表示

操作方式:

  • 使用 http 中的動作(請求方式)表示對資源的不同操作(CURD)

  • 需要的分頁,排序等引數,依然放在 url 的后面,例如

    http://localhost:8080/myboot/students?page=1&pageSize=20

一句話說明 REST: 使用 url 表示資源 ,使用 http 動作操作資源,

RESTful 優點

  • 輕量,直接基于 http,不再需要任何別的諸如訊息協議
    get/post/put/delete 為 CRUD 操作
  • 面向資源,一目了然,具有自解釋性,
  • 資料描述簡單,一般以 xml,json 做資料交換,
  • 無狀態,在呼叫一個介面(訪問、操作資源)的時候,可以不用考慮背景關系,不用考慮當前狀態,
    極大的降低了復雜度,
  • 簡單、低耦合

REST 操作資源

方式:使用 http 中不同動作(請求方式)表示對資源的不同操作(CURD)

示例:

  • GET:查詢資源 -- sql select

? 處理單個資源:用其單數方式

? http://localhost:8080/myboot/student/1001

? http://localhost:8080/myboot/student/1001/1

? 處理多個資源:使用復數形式

? http://localhost:8080/myboot/students/1001/1002

  • POST:創建資源 -- sql insert

? http://localhost:8080/myboot/student

? 在post請求中傳遞資料

<form action="http://localhost:8080/myboot/student" method="post">
    姓名:<input type="text" name="name" />
    年齡:<input type="text" name="age" />
</form>
  • PUT: 更新資源 -- sql update
<form action="http://localhost:8080/myboot/student/1" method="post">
    姓名:<input type="text" name="name" />
    年齡:<input type="text" name="age" />
    <input type="hidden" name="_method" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/PUT" />
</form>
  • DELETE: 洗掉資源 -- sql delete
<a href="http://localhost:8080/myboot/student/1">洗掉1的資料</a>

需要的分頁,排序等引數,依然放在 url 的后面,例如

http://localhost:8080/myboot/students?page=1&pageSize=20

SpringBoot 開發 RESTful

SpringBoot 開發 RESTful 主要是通過以下幾個注解實作:

  1. @PathVariable :從 url 中獲取簡單型別資料【最重要的一個注解】

  2. @GetMapping:支持的 get 請求方式,等同于@RequestMapping(method=RequestMethod.GET)

  3. @PostMapping :支持 post 請求方式 ,等同于@RequestMapping(method=RequestMethod.POST)

  4. @PutMapping:支持 put 請求方式,等同于@RequestMapping(method=RequestMethod.PUT)

  5. @DeleteMapping:支持 delete 請求方式,等同于@RequestMapping( method=RequestMethod.DELETE)

  6. @RestController:一個復合注解,是@Controller@ResponseBody的組合,

    在類的上面使用@RestController,表示當前類的所有方法都加入了@ResponseBody

使用示例:

  1. 創建 SpringBoot 專案,選擇 Spring Web 依賴,整理 pom 檔案,重繪 pom

  2. 創建控制器類,使用相關注解

    /**
     * @RestController:復合注解,包含@Controller和@ResponseBody
     *      控制器類上加上此注解,則類中所有方法都是回傳物件資料
     */
    @RestController
    public class MyRestController {
    
        /**
         * @GetMapping:接收get請求
         * @PathVariable(路徑變數):獲取url中資料
         *      使用位置:控制器方法的形參前
         *      注解的屬性value:路徑變數名
         * 注意:當@PathVariable的路徑變數名value與形參名相同時,屬性value值可以省略
         * 查詢資源:使用GET請求方式
         * http://localhost:9999/myboot/student/1002
         */
        @GetMapping("/student/{stuId}") // 接收get請求
        public String queryStudent(@PathVariable("stuId") Integer studentId) {
            return "查詢的學生id:" + studentId;
        }
    }
    
  3. 主組態檔中配置埠和背景關系路徑

    server.port=9999
    server.servlet.context-path=/myboot
    
  4. 運行主啟動類,瀏覽器輸入訪問地址進行測驗

    http://localhost:9999/myboot/student/1002
    

基于以上,進行其他請求測驗:

控制器類中添加 post 請求處理方法:

/**
     * 創建資源:使用POST請求方式
     * http://localhost:9999/myboot/student/luis/22
     * 注意:當@PathVariable的路徑變數名value與形參名相同時,屬性value值可以省略
     */
@PostMapping("/student/{name}/{age}") // 接收post請求
public String addStudent(@PathVariable String name,
                         @PathVariable Integer age) {
    return "創建student資訊:" + name + " " + age;
}

在 resources/static 下創建 addStudent.html 頁面發送 post 請求:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>post請求創建資源</title>
</head>
<body>
    <p>創建學生資訊</p>
    <form action="student/luis/22" method="post">
        <input type="submit" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/提交post創建學生資訊">
    </form>
</body>
</html>

運行主啟動類,先訪問頁面,在頁面上發送 post 請求:

http://localhost:9999/myboot/addStudent.html

可以發現,開發中模擬各種 post 請求,都需要自己創建表單頁面,十分不便!

可以使用 Postman 工具,可模擬發送各種請求,使用王媽媽提供的漢化版本,免安裝,免登陸!

控制器類中分別創建更新資源和洗掉資源的處理方法,啟動專案,在 Postman 上進行訪問測驗:

/**
     * 修改資源:使用PUT請求方式,瀏覽器使用POST處理PUT請求
     * http://localhost:9999/myboot/student/luis/24
     * 注意:當@PathVariable的路徑變數名value與形參名相同時,屬性value值可以省略
     */
@PutMapping("/student/{name}/{age}") // 修改資源使用@PutMapping
public String modifyStudent(@PathVariable String name,
                            @PathVariable Integer age) {
    return "修改資訊:" + name + " " + age;
}

/**
     * 洗掉資源:使用DELETE請求方式,瀏覽器使用POST處理DELETE請求
     * http://localhost:9999/myboot/student/3
     * 注意:當@PathVariable的路徑變數名value與形參名相同時,屬性value值可以省略
     */
@DeleteMapping("/student/{id}")
public String removeStudentById(@PathVariable Integer id) {
    return "洗掉資訊:id = " + id;
}

在頁面或ajax中支持put和delete請求

瀏覽器是不支持 PUT 和 DELETE 請求的,只支持 GET 和 POST;即在表單中只支持 get 和 post!

在 SpringMVC 中有一個過濾器,支持 post 請求轉為 put 和 delete

過濾器:org.springframework.web.filter.HiddenHttpMethodFilter

作用:把請求中的 post 請求轉為 put 或 delete

使用說明:在表單中想發送 put 或 delete 請求,需配置請求方式為 post,然后在表單的隱藏域標簽中指定name=_methodvalue=https://www.cnblogs.com/luisblog/archive/2022/10/28/put/delete;在 SpringBoot 的組態檔中啟用 SpringMVC 的過濾器后,會自動將 post 請求轉為指定的 put 或 delete,

實作步驟:

  1. application.properties(yml) 開啟使用 HiddenHttpMethodFilter 過濾器

    #啟用過濾器,支持put和delete請求
    spring.mvc.hiddenmethod.filter.enabled=true
    
  2. 在請求頁面中,包含 _method 引數,其值是 put 或 delete,發起這個請求需使用 post 方式

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>測驗表單提交方式</title>
    </head>
    <body>
        <form action="student/test" method="post">
            <!--    在隱藏域標簽中指定將post轉化為何種請求方式    -->
            <input type="hidden" name="_method" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/put"/>
            <input type="submit" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/表單提交put請求"/>
        </form>
    
        <form action="student/test" method="post">
            <!--    在隱藏域標簽中指定將post轉化為何種請求方式    -->
            <input type="hidden" name="_method" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/delete"/>
            <input type="submit" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/表單提交delete請求"/>
        </form>
    </body>
    </html>
    

附控制器測驗方法:

@RestController
public class MyRestController {

    @PutMapping("/student/test")
    public String testPut() {
        return "put請求成功";
    }

    @DeleteMapping("/student/test")
    public String testDelete() {
        return "delete請求成功";
    }
}

使用REST注意

使用 REST 注意,必須保證請求地址 URL 加上請求方式唯一,不然會出現沖突,

如下面兩個請求處理方法,在請求時就會出現沖突,無法確定用哪個方法處理請求!

@GetMapping("/student/{id}")
public String queryId(@PathVariable Integer id) {
    return "查詢的學生id:" + id;
}

@GetMapping("/student/{age}")
public String queryAge(@PathVariable Integer age) {
    return "查詢的學生age:" + age;
}

SpringBoot 集成 Redis

  • Redis:一個NoSQL資料庫,常用作快取使用(cache)

  • Redis 的五種資料型別:string、hash、set、zset、list

  • Redis 是一個中間件,是一個獨立的服務器,

  • Java 中著名的客戶端:Jedis,lettuce,Redisson

SpringBoot 中有 RedisTemplate 和 StringRedisTemplate,都可以處理和 redis 的資料互動,

PS:其實使用的 RedisTemplate,其底層還是呼叫的 lettuce 客戶端方法來處理資料,

配置 Windows 版本的 redis

臨時性使用 redis ,可直接在 Windows 上使用解壓后的安裝包,啟動服務端和客戶端即可!(網盤有壓縮包,解壓即可使用)

Redis-x64-3.2.100.rar 解壓縮到一個非中文的目錄

redis-server.exe:服務端,啟動后,不要關閉

redis-cli.exe:客戶端,訪問 redis 中的資料

redisclient-win32.x86_64.2.0.jar:Redis 的一個圖形界面客戶端

執行方式:在這個檔案所在的目錄,執行 java -jar redisclient-win32.x86_64.2.0.jar 即可

SpringBoot 集成 Redis

步驟:

  1. 創建 SpringBoot 專案,選擇 Spring Web 和 Redis 依賴,整理 pom 并重繪

  2. application.properties/yml 中配置連接 redis 的相關引數

    server.port=7777
    server.servlet.context-path=/myredis
    
    #配置redis:host ip password
    spring.redis.host=localhost
    spring.redis.port=6379
    #spring.redis.password=123
    
  3. 創建控制器類,創建請求處理方法,獲取操作 redis 資料的物件,處理資料互動

    @RestController
    public class RedisController {
    
        /**
         * 注入RedisTemplate(處理和redis的資料互動)
         * 其默認使用的jdk序列化,可讀性差(查看資料庫中資料有類似亂碼問題)
         * 三種泛型情況:
         *      RedisTemplate<String,String>
         *      RedisTemplate<Object,Object>
         *      RedisTemplate
         */
        @Resource
        private RedisTemplate redisTemplate;
    
        /**
         * 注入StringRedisTemplate(處理和redis的資料互動)
         * 其默認使用的String序列化,可讀性好(資料庫中資料正常顯示)
         */
        @Resource
        private StringRedisTemplate stringRedisTemplate;
    
        @PostMapping("/redis/addstring")
        public String addToRedis(String key, String value) { // 使用傳統風格
            // 添加資料到redis(使用RedisTemplate物件)
            ValueOperations valueOperations = redisTemplate.opsForValue(); // 獲取redis中操作string型別資料的物件
            valueOperations.set(key, value);
            return "成功添加資料到redis";
        }
    
        @GetMapping("/redis/getstring")
        public String getKFromRedis(String key) { // 使用傳統風格
            // 從redis獲取資料(使用RedisTemplate物件)
            ValueOperations valueOperations = redisTemplate.opsForValue(); // 獲取redis中操作string型別資料的物件
            Object o = valueOperations.get(key);
            return key + " = " + key + ", value = "https://www.cnblogs.com/luisblog/archive/2022/10/28/+ o;
        }
    
        @PostMapping("/redis/{k}/{v}")
        public String addStringKV(@PathVariable String k,
                                  @PathVariable String v) { // 使用RESTful風格
            // 添加資料到redis(使用StringRedisTemplate物件)
            ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
            stringStringValueOperations.set(k, v);
            return "成功添加資料到redis";
        }
    
        @GetMapping("/redis/{k}")
        public String getK(@PathVariable String k) { // 使用RESTful風格
            // 從redis獲取資料(使用StringRedisTemplate物件)
            ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
            String v = stringStringValueOperations.get(k);
            return k + " = " + k + ", v = " + v;
        }
    }
    
  4. 運行主啟動類,使用 Postman 進行請求測驗

對比 RedisTemplate 和 StringRedisTemplate

  • StringRedisTemplate:使用的是 String 的序列化方式,把 k,v 都是作為 String 處理,可讀性好,

    但是有局限性,只能存 String 型別,且只能是 String 的序列化方式,無法修改為其他的序列化方式,

  • RedisTemplate:默認使用的是 JDK 的序列化方式,把 k,v 經過了 JDK 序列化存到 redis;

    經過了 JDK 序列化的 k,v 在資料庫中不能直接識別,

    其默認使用的 jdk 序列化,但可以修改為其他的序列化方式,

    其使用比 StringRedisTemplate 更加廣泛,可修改為其他的序列化方式,不僅僅只能存字串,

序列化概述

序列化和反序列化:

  • 序列化:把物件轉化為可傳輸的位元組序列的程序稱為序列化,

  • 反序列化:把位元組序列還原為物件的程序稱為反序列化,

為什么需要序列化?

  • 序列化最終目的是為了物件可以跨平臺存盤以及進行網路傳輸,我們進行跨平臺存盤和網路傳輸的方式就是 IO,而我們的 IO支持的資料格式就是位元組陣列,我們必須在把物件轉成位元組陣列的時候就制定一種規則(序列化),以便我們從 IO 流里面讀出資料的時候以這種規則把物件還原回來(反序列化),

什么情況下需要序列化?

  • 凡是需要進行“跨平臺存盤”和”網路傳輸”的資料,都需要進行序列化,

本質上存盤和網路傳輸都需要經過把一個物件狀態保存成一種跨平臺識別的位元組格式,然后其他的平臺才可以通過位元組資訊決議還原物件資訊,

序列化的方式:

序列化只是一種拆裝和組裝物件的規則,這種規則有多種多樣,比如現在常見的序列化方式有:

JDK(不支持跨語言)、JSON、XML、Hessian、Kryo(不支持跨語言)、Thrift、Protofbuff 等

例如:

java 的序列化:把 java 物件轉為 byte[] 二進制資料

json 的序列化:就是將物件轉換為 JSON 字串格式

json 的反序列化:就是將JSON 字串格式轉換為物件

Student( name=zs, age=20) ---- { "name":"zs", "age":20 }

設定 RedisTemplate 的序列化方式

@PostMapping("/redis/addData")
public String addData(String k, String v) {

    // 設定key,value均使用String序列化方式(在進行存取值之前設定)
    // 注意,key 和 value 的序列化方式可分別設定
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(new StringRedisSerializer());

    // 獲取redis中操作string型別資料的物件
    ValueOperations valueOperations = redisTemplate.opsForValue();
    // 向redis中添加資料
    valueOperations.set(k, v);
    return "設定RedisTemplate序列化方式,并向redis中添加資料";
}

設定為 json 序列化方式

設定 json 序列化,存盤時把物件轉為 json 格式字串進行存盤;獲取時將 json 字串格式轉為物件,

如果是 String 序列化方式,則只能存盤字串型別,無法存盤物件,

示例:

  1. 準備 vo 資料物件 Student(需要進行序列化

    public class Student implements Serializable {
        private static final long serialVersionUID = 684647176563341892L; // 添加后就不要再改動!
        private Integer id;
        private String name;
        private Integer age;
        // getter,setter,toString
    }    
    
  2. 寫處理請求的處理器方法

    @PostMapping("/redis/addjson")
    public String addJson() {
    
        // 準備物件資料
        Student student = new Student();
        student.setId(111);
        student.setName("luis");
        student.setAge(22);
    
        // 設定key的序列化方式為String(默認的是jdk方式)
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 設定value的序列化方式為json(默認的是jdk方式)
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Student.class));
        // 獲取redis中操作string型別資料的物件
        ValueOperations valueOperations = redisTemplate.opsForValue();
        // 向redis中存資料
        // 會依據value設定的json序列化方式自動將Student物件轉換為json格式字串
        valueOperations.set("mystudent", student);
        return "key-string序列化,value-json序列化";
    }
    
    @GetMapping("/redis/getjson")
    public String getJson() {
    
        // 設定key的序列化方式為String(默認的是jdk方式)
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 設定value的序列化方式為json(默認的是jdk方式)
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Student.class));
        // 獲取redis中操作string型別資料的物件
        ValueOperations valueOperations = redisTemplate.opsForValue();
        // 從redis中獲取資料
        // 會依據value設定的json序列化方式自動將json格式字串轉換為Student物件,反序列化回來
        Object o = valueOperations.get("mystudent");
        return "json反序列化:" + o;
    }
    
  3. 使用 Postman 發請求測驗

小結

  • 臨時性使用 redis 或小測驗,可直接在 Windows 上使用 redis 的安裝包,解壓即可使用
  • SpringBoot 中使用 Redis 主要是合理選擇 RedisTemplate 或 StringRedisTemplate 來處理和 Redis 的互動
  • 處理單純的字串資料,可直接使用 RedisTemplate 物件處理資料互動,其采用 String 序列化方式,
  • 處理物件型別的資料,需要選擇 StringRedisTemplate 來處理和 Redis 的互動,其默認采用 JDK 序列化方式;需手動設定改變其序列化方式為 json;還可設定成其他的序列化方式,
  • 資料在網路上傳輸,或者跨平臺傳輸都需要進行序列化!所以將需要傳輸的資料,如物件型別的,進行實作序列化介面的操作,并設定序列化版本號!序列化版本號設定后不要再改動!
  • 創建資源使用 POST 請求;獲取資源使用 GET 請求;修改資源使用 PUT 請求;洗掉資源使用 DELETE 請求,
  • 熟悉 Postman 測驗工具:熟練選擇請求方式、根據傳統風格以及 RESTful 風格的快速準確填充資料

SpringBoot 集成 Dubbo

開發中使用 SpringBoot 集成 Dubbo 進行分布式開發!

公共工程負責提供物體 bean 以及業務介面;

服務提供者工程負責實作公共工程中的業務介面,提供并暴露服務,供消費者呼叫;

服務消費者工程負責呼叫服務提供者提供的服務,

需要三個工程:介面工程【java】、服務提供者工程【可web】、服務消費者工程【web】
介面工程【java】:負責物體 bean 以及業務介面(提供者和消費者均依賴于它)
服務提供者工程【可web】:負責實作介面工程中的服務介面,提供服務,暴露服務,供消費者呼叫
服務消費者工程【web】:負責呼叫提供者提供的服務   

示例:

1.創建介面/公共工程

  1. 創建一個 maven 專案,無需選擇模板,名為 interface-api(公共的介面工程)

  2. 創建 vo 資料類 Student,進行序列化

    public class Student implements Serializable {
        private static final long serialVersionUID = -3498691273686241331L;
        private Integer id;
        private String name;
        private Integer age;
        // getter,setter,toString
    }    
    
  3. 定義服務介面(業務介面)

    public interface StudentService {   
        Student queryStudent(Integer id);
    }
    

2.創建服務提供者工程

  1. 創建 SpringBoot 專案,無需添加其他依賴,專案命名 springboot-service-provider(服務提供者工程)

  2. 在其 pom 檔案中加入公共工程依賴、dubbo 起步依賴和 Zookeeper 依賴,整理 pom,重繪

    <!--公共專案(介面工程)的gav-->
    <dependency>
        <groupId>com.luis</groupId>
        <artifactId>interface-api</artifactId>
        <version>1.0.0</version>
    </dependency>
    <!--dubbo起步依賴-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>2.7.8</version>
    </dependency>
    <!--zookeeper依賴-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-dependencies-zookeeper</artifactId>
        <version>2.7.8</version>
        <type>pom</type>
        <exclusions>
            <!-- 排除log4j依賴,解決多次引入 -->
            <exclusion>
                <artifactId>slf4j-log4j12</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    

    注意:服務提供者中如果要使用到redis,并涉及json序列化操作,在不添加web起步依賴下,必須加下列jackson依賴!

    <!--單獨添加下面四個Jackson的依賴(或者直接將web起步依賴加上)-->
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.2.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jdk8 -->
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jdk8</artifactId>
        <version>2.13.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.13.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-parameter-names -->
    <dependency>
        <groupId>com.fasterxml.jackson.module</groupId>
        <artifactId>jackson-module-parameter-names</artifactId>
        <version>2.13.2</version>
    </dependency>
    
  3. 實作介面工程中的業務方法,使用 dubbo 中的注解暴露服務

    // @Component 可不用加此注解創建物件!加@DubboService后,該注解可自行創建該類物件,
    //@DubboService(interfaceClass = StudentService.class, version = "1.0", timeout = 5000)//暴露服務
    @DubboService(version = "1.0", timeout = 5000) // 暴露服務(interfaceClass屬性可不加)
    public class StudentServiceImpl implements StudentService {
        @Override
        public Student queryStudent(Integer id) {
    
            Student student = new Student();
            if (1001 == id) {
                student.setId(1001);
                student.setName("1001-luis");
                student.setAge(22);
            } else {
                student.setId(1002);
                student.setName("1002-jack");
                student.setAge(24);
            }
            return student;
        }
    }
    
  4. 配置 application.properties/yml 檔案

    #配置服務名稱
    spring.application.name=studentservice-provider
    
    #配置掃描的包,掃描@DubboService
    dubbo.scan.base-packages=com.luis.service
    
    #配置dubbo協議(使用zookeeper注冊中心就不用配置)
    #dubbo.protocol.name=dubbo
    #dubbo.protocol.port=20881
    
    #配置zookeeper注冊中心
    dubbo.registry.address=zookeeper://localhost:2181
    
  5. 在主啟動類上添加注解啟用dubbo

    @SpringBootApplication
    @EnableDubbo // 啟用dubbo,該注解包含@EnableDubboConfig和@DubboComponentScan
    public class SpringbootServiceProviderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootServiceProviderApplication.class, args);
        }
    }
    

3.創建服務消費者工程

  1. 創建 SpringBoot 專案,添加 Spring Web 依賴,專案命令為 springboot-consumer(服務消費者工程)

  2. 在其 pom 檔案中加入公共工程依賴、dubbo 起步依賴和 Zookeeper 依賴,整理 pom,重繪,

    其需要的依賴和服務消費者工程所需相同!

    <!--公共專案(介面工程)的gav-->
    <dependency>
        <groupId>com.luis</groupId>
        <artifactId>interface-api</artifactId>
        <version>1.0.0</version>
    </dependency>
    <!--dubbo起步依賴-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>2.7.8</version>
    </dependency>
    <!--zookeeper依賴-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-dependencies-zookeeper</artifactId>
        <version>2.7.8</version>
        <type>pom</type>
        <exclusions>
            <!-- 排除log4j依賴 -->
            <exclusion>
                <artifactId>slf4j-log4j12</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    
  3. 創建控制器類,寫請求處理方法,進行遠程介面呼叫

    @RestController
    public class DubboController {
    
        // 參考遠程服務,將創建好的代理物件,注入給studentService
        //@DubboReference(interfaceClass = StudentService.class, version = "1.0")
        @DubboReference(version = "1.0") // 如果不指定interfaceClass,則默認采用參考型別的class
        private StudentService studentService;
    
        @GetMapping("/query")
        public String queryStudent() {
            // 呼叫遠程介面,獲取物件
            Student student = studentService.queryStudent(1001);
            return "呼叫遠程介面獲取的物件:" + student;
        }
    }
    
  4. 在主啟動類上添加啟用dubbo的注解

    @SpringBootApplication
    @EnableDubbo // 啟用Dubbo
    public class SpringbootConsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootConsumerApplication.class, args);
        }
    }
    
  5. 配置 application.properties/yml

    #指定服務名稱
    spring.application.name=consumer-application
    #指定注冊中心
    dubbo.registry.address=zookeeper://localhost:2181
    

4.啟動 zookeeper 和服務

  1. 啟動 zookeeper 注冊中心(雙擊 zookeeper/bin 目錄下的 zkServer.cmd)

  2. 運行服務提供者模塊的主啟動類

  3. 運行服務消費者模塊的主啟動類

  4. 根據服務消費者提供的訪問介面進行服務訪問測驗

    http://localhost:8080/query
    

SpringBoot 專案打包

打包為 war 檔案

示例:

  1. 創建 SpringBoot 專案,選擇 Spring Web 依賴,整理專案目錄

  2. 此處直接列舉整個 pom,依據注釋的內容進行添加,然后重繪 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.6.6</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <groupId>com.luis</groupId>
        <artifactId>springboot-war</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <!--指定打包型別-->
        <packaging>war</packaging>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <!--處理jsp的依賴-->
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
            </dependency>
            <!--servlet,jsp,jstl需要用再加-->
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <!--打包后的檔案名稱-->
            <finalName>myboot</finalName>
            
            <!--resources插件-->
            <resources>
                <!--將jsp編譯到指定的目錄-->
                <resource>
                    <directory>src/main/webapp</directory>
                    <targetPath>META-INF/resources</targetPath>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </resource>
                <!--將src/main/java下的檔案包含到classes下-->
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </resource>
                <!--將src/main/resources下的檔案包含到classes下-->
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </resource>
            </resources>
    
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
  3. 在 main 目錄下,與 java 和 resources 目錄平級,創建名為 webapp 的目錄;在專案工程結構中指定該目錄為 web 資源目錄

  4. 在 webapp 目錄下創建 index.jsp 頁面,用來顯示 controller 中的資料

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>index.jsp</title>
    </head>
    <body>
        index.jsp,顯示controller中的資料:${data}
    </body>
    </html>
    
  5. 創建 controller 控制器類,處理請求

    @Controller
    public class JspController {
    
        @RequestMapping("/main")
        public String main(Model model) {
            model.addAttribute("data", "SpringBoot打包為war檔案");
            return "index";
        }
    }
    
  6. 配置 application.properties/yml

    server.port=9001
    server.servlet.context-path=/myjsp
    
    #指定視圖決議器
    spring.mvc.view.prefix=/
    spring.mvc.view.suffix=.jsp
    
  7. 讓主啟動類繼承 SpringBootServletInitializer并重寫 configure 方法,修改回傳內容,

    /**
     * 讓主啟動類繼承 SpringBootServletInitializer 并重寫重寫 configure 方法才可以使用外部 Tomcat!
     * SpringBootServletInitializer 就是原有 web.xml 的替代,
     */
    @SpringBootApplication
    public class SpringbootWarApplication extends SpringBootServletInitializer {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootWarApplication.class, args);
        }
    
        // 重寫此configure方法,修改回傳內容!
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            return builder.sources(SpringbootWarApplication.class);
        }
    }
    
  8. 運行主啟動類,瀏覽器輸入訪問地址,測驗

    http://localhost:9001/myjsp/main
    
  9. 測驗正常后,使用 maven 的 lifecycle 中 package 打包命令進行打包(右側 maven 視窗中);【建議先clean再package】

    在 target 目錄下即可看到打包完成的 war 包,

  10. 將打包好的 war 包放到 Tomcat 的 webapps 目錄下,啟動 Tomcat;

    若是本地 Tomcat,則通過http://localhost:8080/myboot/main可訪問該專案,

重點小結

  • 指定打包型別為 war
  • 指定打包后名稱
  • 添加資源插件
  • 主啟動類繼承 SpringBootServletInitializer并重寫 configure 方法,修改回傳內容,
  • 使用 package 命令打包

打包為 jar 檔案

示例:

  1. 創建 SpringBoot 專案,選擇 Spring Web 依賴,整理專案目錄

  2. 此處直接列舉整個 pom,依據注釋的內容進行添加,然后重繪 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.6.6</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <groupId>com.luis</groupId>
        <artifactId>springboot-jar</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
    
            <!--處理jsp的依賴-->
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
            </dependency>
            <!--servlet,jsp,jstl需要用再加-->
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <!--打包后的檔案名稱-->
            <finalName>myboot</finalName>
    
            <!--resources插件-->
            <resources>
                <!--將jsp編譯到指定的目錄-->
                <resource>
                    <directory>src/main/webapp</directory>
                    <targetPath>META-INF/resources</targetPath>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </resource>
                <!--將src/main/java下的mapper檔案包含到classes下-->
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                    </includes>
                </resource>
                <!--將src/main/resources下的檔案包含到classes下-->
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                </resource>
            </resources>
    
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <!--  打包jar,有jsp檔案時,必須指定maven-plugin插件版本為 1.4.2.RELEASE  -->
                    <version>1.4.2.RELEASE</version>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
  3. 在 main 目錄下,與 java 和 resources 目錄平級,創建名為 webapp 的目錄;在專案工程結構中指定該目錄為 web 資源目錄

  4. 在 webapp 目錄下創建 main.jsp 頁面,用來顯示 controller 中的資料

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
      main.jsp,顯示資料:${data}
    </body>
    </html>
    
  5. 創建控制器類,處理請求

    @Controller
    public class HelloController {
    
        @RequestMapping("/hello")
        public ModelAndView hello() {
            ModelAndView mv = new ModelAndView();
            mv.addObject("data", "SpringBoot打包為jar檔案");
            mv.setViewName("main");
            return mv;
        }
    }
    
  6. 配置 application.properties/yml

    server.port=9002
    server.servlet.context-path=/myboot
    
    #視圖決議器
    spring.mvc.view.prefix=/
    spring.mvc.view.suffix=.jsp
    
  7. 運行主啟動類,瀏覽器輸入地址訪問測驗

    http://localhost:9002/myboot/hello
    
  8. 測驗正常后,使用 maven 的 lifecycle 中 package 打包命令進行打包(右側 maven 視窗中);【建議先clean再package】

    在 target 目錄下即可看到打包完成的 jar 包,

  9. 在 jar 包所在目錄,開啟 cmd 視窗,輸入 java -jar myboot.jar,回車,即可獨立運行專案;

    (可以將java -jar myboot.jar這段命令寫進一個檔案,改后綴為 .bat,放在 jar 包同級下,雙擊即可運行專案)

    后臺資訊列印可看到埠和專案訪問背景關系路徑;

    此時使用的是內嵌的 tomcat,輸入http://localhost:9002/myboot/hello即可訪問,

重點小結

  • 指定打包名稱
  • 添加資源插件
  • 指定 maven-plugin 插件版本
  • 使用 package 命令打包

Thymeleaf 模板引擎

Thymeleaf 介紹

  • Thymeleaf 是一個流行的模板引擎,該模板引擎采用 Java 語言開發
  • 模板引擎是一個技術名詞,是跨領域跨平臺的概念,在 Java 語言體系下有模板引擎,在
    C#、PHP 語言體系下也有模板引擎,甚至在 JavaScript 中也會用到模板引擎技術,Java 生態下
    的模板引擎有 Thymeleaf 、Freemaker、Velocity、Beetl(國產) 等
  • Thymeleaf 對網路環境不存在嚴格的要求,既能用于 Web 環境下,也能用于非 Web 環境
    下,在非 Web 環境下,他能直接顯示模板上的靜態資料;在 Web 環境下,它能像 Jsp 一樣從
    后臺接收資料并替換掉模板上的靜態資料,它是基于 HTML 的,以 HTML 標簽為載體,
    Thymeleaf 要寄托在 HTML 標簽下實作
  • Spring Boot 集成了 Thymeleaf 模板技術,并且 Spring Boot 官方也推薦使用 Thymeleaf 來
    替代 JSP 技術
    ,Thymeleaf 是另外的一種模板技術,它本身并不屬于 Spring Boot,Spring Boot
    只是很好地集成這種模板技術,作為前端頁面的資料展示,在過去的 Java Web 開發中,我們
    往往會選擇使用 Jsp 去完成頁面的動態渲染,但是 jsp 需要翻譯編譯運行,效率低,

Thymeleaf 的官方網站:http://www.thymeleaf.org
Thymeleaf 官方手冊:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html

完善 Thymeleaf 語法提示

  • 添加了 Thymeleaf 依賴后,在創建的 html 標簽中使用其相關語法,若想使用 IDEA 的語法提示,還需進行以下設定:

    在默認創建的 html 的 <html lang="en">中補充xmlns:th="http://www.thymeleaf.org",如下:

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

使用示例

  1. 創建 SpringBoot 專案,選擇 Spring Web 和 Thymeleaf 依賴,整理 pom,并重繪

  2. 寫控制器類,處理請求,轉發頁面到指定的 Thymeleaf 頁面,顯示資料

    @Controller
    public class MyController {
    
        @GetMapping("/hello")
        public String helloThymeleaf(HttpServletRequest request, Model model) {
    
            // 將資料放到request作用域
            request.setAttribute("data1", "歡迎使用Thymeleaf模板引擎");
            // 將資料放到request作用域
            model.addAttribute("data2", "我是后臺的資料");
    
            // 指定轉發的邏輯視圖(使用Thymeleaf模板引擎,其通常使用的html)
            // 模板引擎默認配置了resources/tmeplates下的以.html結尾檔案的視圖決議
            return "hello";
        }
    }
    
  3. 在 resources/templates 下,創建 hello.html 頁面顯示資料(可在 html 標簽中使用 Thymeleaf)

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <!-- xmlns:th="http://www.thymeleaf.org" 是手動加的,加上后idea使用Thymeleaf會有相關提示 -->
    <head>
        <meta charset="UTF-8">
        <title>hello.html</title>
    </head>
    <body>
        <h3>Thymeleaf使用示例</h3>
        <!--  后臺有資料填充,則替換p標簽的value內容;沒有,則不替換  -->
        <p th:text="${data1}">想顯示資料</p>
        <p th:text="${data2}">靜態展示資料</p>
    </body>
    </html>
    
  4. 配置 application.properties/yml

    #關閉模板快取,開發階段配置,讓修改立即生效(專案上線后需修改為false,效率更高)
    spring.thymeleaf.cache=false
    # 去掉html5的語法驗證(thymeleaf對html的標簽約束非常嚴格,所有的標簽必須有開有閉,比如<br></br>或者<br/>是可以的,但是<br>會報錯,
    # 配置spring.thymeleaf.mode=LEGACYHTML5 目的就是為了解決這個問題,可以使頁面松校驗,)
    spring.thymeleaf.mode=LEGACYHTML5
    
    
    #以下是一些可能用到的配置,需要改變時配置即可,一般不需要配置,使用默認即可
    #-------------------------------------------------
    #編碼格式(默認是UTF-8)
    spring.thymeleaf.encoding=UTF-8
    #模板的型別(默認是HTML)
    spring.thymeleaf.mode=HTML
    #模板的前綴(默認是classpath:/templates/,其下html檔案不用配置視圖決議器,直接可用邏輯名稱)
    spring.thymeleaf.prefix=classpath:/templates/
    #模板的后綴(默認是.html)
    spring.thymeleaf.suffix=.html
    #-------------------------------------------------
    
  5. 運行主啟動類,瀏覽器輸入地址訪問測驗;

    然后不通過地址,直接在 idea 中點擊右上角瀏覽器標識,打開 hello.html,查看效果

    http://localhost:8080/hello
    

    結果:后臺沒有資料傳過來時,顯示的是頁面原有資料;后臺有資料傳過來,則覆寫原有資料進行顯示!

    使用 Thymeleaf 可實作前后端同時有效開發,互不影響;前端可用自己的示例資料,后端只需進行資料替換!

運算式

1.標準變數運算式

  • 語法:${key}

  • 作用:從 request 作用域中獲取 key 對應的文本資料;

    可使用request.setAttribute()model.addAttribute()向 request 中存資料

  • 使用:在頁面的 html 標簽中,使用th:text="${key}"運算式

  • 示例:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>expression1</title>
    </head>
    <body>
        <p3>標準變數運算式:${key}</p3>
        <div>
            <p>獲取相關資料:</p>
            <p th:text="${msg}">msg</p>
            <p th:text="${myuser.id}">id</p>
            <p th:text="${myuser.name}">name</p>
            <p th:text="${myuser.sex}">sex</p>
            <p th:text="${myuser.age}">age</p>
        </div>
    </body>
    </html>
    

2.選擇/星號變數運算式

  • 語法: *{key}

  • 作用:獲取這個 key 對應的資料;*{key}需要和th:object這個屬性一起使用,簡化物件屬性值的獲取,

  • 示例:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>expression2</title>
    </head>
    <body>
        <p3>選擇變數運算式:*{key}</p3>
        <p>獲取物件相關資料:</p>
        <div th:object="${myuser}">
            <p th:text="*{id}">id</p>
            <p th:text="*{name}">name</p>
            <p th:text="*{sex}">sex</p>
            <p th:text="*{age}">age</p>
        </div>
        <p>使用*{}完整表示物件的屬性值,此用法其實和${key}作用相同,了解即可</p>
        <p th:text="*{myuser.name}">name</p>
    </body>
    </html>
    

3.鏈接運算式

  • 語法:@{url}

  • 作用:表示鏈接,可使用在如下等情境中

    <script src="https://www.cnblogs.com/luisblog/archive/2022/10/28/...">,<link href="https://www.cnblogs.com/luisblog/archive/2022/10/28/...">,<a href="https://www.cnblogs.com/luisblog/archive/2022/10/28/..">,<form action="...">,<img src="https://www.cnblogs.com/luisblog/archive/2022/10/28/...">
    
  • 示例:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>鏈接運算式</title>
    </head>
    <body>
        <p3>鏈接絕對路徑</p3><br/>
        <a th:href="https://www.cnblogs.com/luisblog/archive/2022/10/28/@{http://www.baidu.com}">鏈接到百度</a><br/>
    
        <p3>鏈接的是相對路徑</p3><br/>
        <a th:href="https://www.cnblogs.com/luisblog/archive/2022/10/28/@{/tpl/queryAccount}">相對地址,沒有引數</a><br/>
        <p3>鏈接的相對地址,使用字串鏈接傳遞引數</p3><br/>
        <a th:href="https://www.cnblogs.com/luisblog/archive/2022/10/28/@{'/tpl/queryAccount?id=' + ${userId}}">獲取model中的資料添加到鏈接地址中(不推薦此種拼接方式)</a><br/>
    
        <p3>推薦使用的傳參方式:</p3><br/>
        <a th:href="https://www.cnblogs.com/luisblog/archive/2022/10/28/@{/tpl/queryAccount(id=${userId})}">傳遞一個引數(引數值可自己設定,也可從作用域中獲取)</a><br/>
        <a th:href="https://www.cnblogs.com/luisblog/archive/2022/10/28/@{/tpl/queryUser(name='李四',age=20)}">傳遞多個引數(引數值可自己設定)</a><br/>
        <a th:href="https://www.cnblogs.com/luisblog/archive/2022/10/28/@{/tpl/queryUser(name=${name},age=${age})}">傳遞多個引數(引數值可自己設定,也可從作用域中獲取)</a><br/>
    </body>
    </html>
    

Thymeleaf 屬性

  • 大部分屬性和 html 的一樣,只不過前面加了一個 th 前綴;加了 th 前綴,表示經過了模板引擎處理;經過了模板引擎處理的屬性,就可以使用其相關運算式,可獲取動態變數,

  • th:actionth:methodth:hrefth:srcth:textth:styleth:nameth:value

  • 基本屬性示例:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>模板屬性</title>
        <!--  引入jQuery  -->
        <script th:src="https://www.cnblogs.com/luisblog/archive/2022/10/28/@{/js/jquery-3.4.1.js}" type="text/javascript"></script>
    
        <script type="text/javascript">
            $(function() {
                $("#btn").click(function(){
                    alert("按鈕單擊系結======");
                })
            })
            function btnClick() {
                alert("按鈕單擊回呼");
            }
        </script>
    
    </head>
    <body>
        <p3>使用模板屬性可獲取動態變數</p3>
        
        <form th:action="@{/login}" th:method="${methodAttr}">
            <input th:type="text" th:name="${paramname}" th:value="https://www.cnblogs.com/luisblog/archive/2022/10/28/${paramvalue}" />
            <input type="button" value="https://www.cnblogs.com/luisblog/archive/2022/10/28/按鈕" id="btn" th:onclick="btnClick()" />
        </form>
    
        <p th:style="${textcolor}">獲取動態變數,改變字體顏色</p>
        <p th:style="'color:skyblue'">此處經過模板處理,若仍手動設定,需要使用字串</p>
        <p style="color: red">原版的改變字體顏色</p>
    
    </body>
    </html>
    

th:each

  • each 回圈,可以回圈 List 集合,Array 陣列,Map 集合
  • 其實整體回圈方式差不多,只不過資料存盤方式不一樣,存取方式有一些差異,

th:each回圈List/Array

each 回圈集合 List 和回圈陣列 Array 語法相同!

語法:在一個 html 標簽中,如下列方式使用 th:each(以下以 div 為例,實際多回圈表格標簽)

<div th:each="集合回圈成員,回圈狀態變數:${key}">
    <p th:text="${集合回圈成員}"></p>
</div>

集合回圈成員,回圈狀態變數:兩個名稱都是自定義的, 
“回圈狀態變數”這個名稱可不定義,默認名稱是"集合回圈成員Stat"

如果不定義“回圈狀態變數”,則直接可這樣寫:(但要使用其時,直接使用"集合回圈成員Stat"這個默認的名稱即可)
<div th:each="集合回圈成員:${key}">
    <p th:text="${集合回圈成員}"></p>
</div>

具體語法說明:

th:each="user,iterStat:${userlist}"中的${userList}是后臺傳過來的集合
?  user
定義變數,去接收遍歷${userList}集合中的一個資料
?  iterStat
${userList} 回圈體的資訊
?  其中 user 及 iterStat 自己可以隨便取名
?  interStat 是回圈體的資訊,通過該變數可以獲取如下資訊
index: 當前迭代物件的 index(從0開始計算)
count: 當前迭代物件的個數(從1開始計算)這兩個用的較多
size: 被迭代物件的大小
current: 當前迭代變數
even/odd: 布林值,當前回圈是否是偶數/奇數(從0開始計算)
first: 布林值,當前回圈是否是第一個
last: 布林值,當前回圈是否是最后一個
注意:回圈體資訊 interStat 也可以不定義,則默認采用迭代變數加上 Stat 后綴,即 userStat

示例:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>eachList.html</title>
</head>
<body>
    <p3>each回圈List</p3>
    <table border="1">
        <thead>
            <tr>
                <th>id</th>
                <th>name</th>
                <th>sex</th>
                <th>age</th>
                <th>userStat</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="user,userStat:${myusers}">
                <td th:text="${user.id}"></td>
                <td th:text="${user.name}"></td>
                <td th:text="${user.sex}"></td>
                <td th:text="${user.age}"></td>
                <td th:text="${userStat}"></td>
            </tr>
        </tbody>
    </table>

    <br/>

    <table border="1">
        <thead>
        <tr>
            <th>id</th>
            <th>name</th>
            <th>sex</th>
            <th>age</th>
        </tr>
        </thead>
        <tbody>
        <!-- 可不寫回圈體資訊userStat,默認會自動加上去 -->
        <tr th:each="user:${myusers}">
            <td th:text="${user.id}"></td>
            <td th:text="${user.name}"></td>
            <td th:text="${user.sex}"></td>
            <td th:text="${user.age}"></td>
        </tr>
        </tbody>
    </table>

</body>
</html>

th:each回圈Map

語法:在一個 html 標簽中,如下列方式使用 th:each(以下以 div 為例,實際多回圈表格標簽)

<div th:each="集合回圈成員,回圈的狀態變數:${key}">
    <p th:text="${集合回圈成員.key}" ></p>
    <p th:text="${集合回圈成員.value}"></p>
</div>

集合回圈成員,回圈的狀態變數:兩個名稱都是自定義的, 
“回圈的狀態變數”這個名稱可以不定義,默認是"集合回圈成員Stat"

key:map集合中的key
value:map集合key對應的value值

回圈 List-Map 示例

示例回圈一個稍復雜點的資料型別如:List<Map<String,Student>>

第一次回圈,取出每一個 Map;

第二次回圈,取出每一個 Map 中的 key 和 value,

<div th:each="lm:${listMap}">
    <div th:each="map:${lm}">
        <p th:text="${map.key}"></p>
        <p th:text="${map.value}"></p>        
    </div>
</div>

th:ifth:unless

th:if:判斷陳述句,當條件為 true,顯示 html 標簽體內容,反之不顯示;沒有 else 陳述句

示例:

<div th:if="10 > 0">條件為true才顯示此內容</div>

<p th:if="${sex=='m'}">性別是男才顯示</p>
<p th:if="${isLogin}">isLogin為true才顯示</p>
<p th:if="${age>18}">年齡大于18才顯示</p>
<!--""空字符是true-->
<p th:if="${str}">當str為空串表示true,會顯示</p>
<!--null是false-->
<p th:if="${str}">當str為null表示false,不會顯示</p>

th:unless:判斷陳述句,當條件為 false,顯示 html 標簽體內容,反之不顯示;沒有 else 陳述句

示例:

<div th:unless="10 < 0">條件為false才顯示此內容</div>
動態變數控制的示例此處省略,和if的使用相同,就是顯示條件相反!

th:swithth:case

th:switch 和 Java 中的 switch 是一樣的;

進行條件匹配,按上下順序匹配,一旦匹配成功則結束;否則使用默認的;無論如何,最終只有一個匹配上!

  • 語法:
<div th:switch="要比對的值">
    <p th:case="值1">
        結果1
    </p>
    <p th:case="值2">
        結果2
    </p>
    <p th:case="*">
        默認結果
    </p>
    以上的case只有一個陳述句執行
    
</div>

示例:

<div th:switch="${sex}">
    <p th:case="m">男</p>
    <p th:case="f">女</p>
    <p th:case="*">性別未知</p>
</div>

th:inline

  • 作用:不依賴于 html 標簽,直接通過行內運算式[[${key}]]來獲取動態資料

  • th:inline有三個取值型別 (text, javascript 和 none),通常使用 text 和 javascript 這兩個

  • 語法:th:inline="text/javascript"

  • 行內運算式:[[${key}]]

行內 text

  • 作用:在 html 標簽外,獲取動態資料,

  • 語法:th:line="text",不指定則默認使用行內 text!

  • 特點:可顯示的指定使用行內 text,不指定則默認使用行內 text!

  • 示例:

    <!-- 可顯示的指定使用行內text -->
    <div th:inline="text">
        <p>性別:[[${sex}]],年齡[[${age}]]</p>
    </div>
    
    <!-- 沒有指定行內型別,默認使用行內text -->
    <div>
        <p>性別:[[${sex}]],年齡[[${age}]]</p>
    </div>
    

行內 javascript

  • 作用:可以在 js 中,獲取模版中的資料

  • 語法:th:inline="javascript",必須指定!

  • 示例:

    <button onclick="fun()">單擊按鈕</button>
    
    <script type="text/javascript" th:inline="javascript">
        var name = [[${myuser.name}]];
        var id = [[${myuser.id}]];
        
        function fun() {
            alert("click 用戶是"+name+",他的 id 是"+id);
        }
    </script>
    

自面量

  • 指在模板檔案的運算式中使用的一些資料,如文本、數字、boolean、null
 <div style="margin-left: 400px">
     <h3>文本字面量: 使用單引號括起來的字串</h3>
     <p th:text="'我是'+${name}+',我所在的城市是'+${city}">資料顯示</p>

     <h3>數字字面量</h3>
     <p th:if="${20>5}"> 20大于 5</p>

     <h3>boolean字面量</h3>
     <p th:if="${isLogin == true}">用戶已經登錄系統</p>

     <h3>null字面量</h3>
     <p th:if="${myuser != null}">有myuser資料</p>
</div>

字串連接

在模板檔案的運算式中連接字串有兩種語法:

  1. 將字串使用單引號括起來,使用加號連接其他的字串或者運算式:
<p th:text="'我是'+${name}+',我所在的城市是'+${city}">資料顯示</p>
  1. 使用雙豎線,將需要拼接的字串和表達時候寫在雙豎線中即可:|字串和運算式|
<p th:text="|我是${name},我所在城市是${city}|">
    顯示資料
</p>

運算子

  • 算術運算:+ , - , * , / , %
  • 關系比較:> , < , >= , <= ( gt , lt , ge , le )
  • 相等判斷:== , != ( eq , ne )

使用示例:

<div style="margin-left: 400px">
    <h3>使用運算子</h3>
    <p th:text="${age > 10}">年齡大于 10 </p>
    <p th:text="${20 + 30}">顯示運算結果</p>
    <p th:if="${myuser == null}">myuser是null</p>
    <p th:if="${myuser eq null}">myuser是null</p>
    <p th:if="${myuser ne null}">myuser不是null</p>

    <p th:text="${isLogin == true ? '用戶已經登錄' : '用戶需要登錄'}"></p>
    <p th:text="${isLogin == true ? (age > 10 ? '年齡大于10' : '年齡小于10') : '用戶需要登錄'}"></p>
</div>

三元運算子:
	運算式  ? true的結果 : false的結果

三元運算子可以嵌套

Thymeleaf 基本物件

  • 模板引擎提供了一組內置物件,可以直接在模板檔案中使用,
  • 檔案地址:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#web-context-objects

常用的內置物件有以下幾個:

  1. #request:表示 HttpServletRequest 物件

  2. #session:表示 HttpSession 物件

  3. session:表示一個 Map 物件,是 #session的簡單表示方式,用來便捷獲取 session 中指定 key 的值,

    #session.getAttribute("loginname") 等同 session.loginname
    

使用示例:

 <div style="margin-left: 350px">
     <h3>內置物件 #request,#session,session 的使用</h3>
     <p>獲取作用域中的資料</p>
     <p th:text="${#request.getAttribute('requestData')}"></p>
     <p th:text="${#session.getAttribute('sessionData')}"></p>
     <p th:text="${session.loginname}"></p>

     <br/>
     <br/>
     <h3>使用內置物件的方法</h3>
     getRequestURL=<span th:text="${#request.getRequestURL()}"></span><br/>
     getRequestURI=<span th:text="${#request.getRequestURI()}"></span><br/>
     getQueryString=<span th:text="${#request.getQueryString()}"></span><br/>
     getContextPath=<span th:text="${#request.getContextPath()}"></span><br/>
     getServerName=<span th:text="${#request.getServerName()}"></span><br/>
     getServerPort=<span th:text="${#request.getServerPort()}"></span><br/>
</div>

Thymeleaf 內置工具類物件

內置工具類:Thymeleaf 自己的一些類,提供對日期、數字、字串、list集合等的一些處理方法,

下面是一些常用的內置工具類物件:

  • #dates:處理日器的工具類

  • #numbers:處理數字的工具類

  • #strings:處理字串的工具類

  • #lists:處理 list 集合的工具類

使用示例:

<div style="margin-left: 350px">
    <h3>日期類物件 #dates</h3>
    <p th:text="${#dates.format(mydate )}"></p>
    <p th:text="${#dates.format(mydate,'yyyy-MM-dd')}"></p>
    <p th:text="${#dates.format(mydate,'yyyy-MM-dd HH:mm:ss')}"></p>
    <p th:text="${#dates.year(mydate)}"></p>
    <p th:text="${#dates.month(mydate)}"></p>
    <p th:text="${#dates.monthName(mydate)}"></p>
    <p th:text="${#dates.createNow()}"></p>
    <br/>

    <h3>內置工具類 #numbers,運算元字的</h3>
    <p th:text="${#numbers.formatCurrency(mynum)}"></p>
    <p th:text="${#numbers.formatDecimal(mynum,5,2)}"></p>

    <br/>
    <h3>內置工具類 #strings, 操作字串</h3>
    <p th:text="${#strings.toUpperCase(mystr)}"></p>
    <p th:text="${#strings.indexOf(mystr,'power')}"></p>
    <p th:text="${#strings.substring(mystr,2,5)}"></p>
    <p th:text="${#strings.substring(mystr,2)}"></p>
    <p th:text="${#strings.concat(mystr,'---java開發的黃埔軍校---')}"></p>
    <p th:text="${#strings.length(mystr)}"></p>
    <p th:text="${#strings.length('hello')}"></p>
    <p th:unless="${#strings.isEmpty(mystr)}"> mystring 不是 空字串  </p>

    <br/>
    <h3>內置工具類 #lists, 操作list集合</h3>
    <p th:text="${#lists.size(mylist)}"></p>
    <p th:if="${#lists.contains(mylist,'a')}">有成員a</p>
    <p th:if="!${#lists.isEmpty(mylist)}"> list 集合有多個成員</p>

    <br/>
    <h3>處理null</h3>
    <!-- 物件前加問號,會自動查詢其是否為null,不是null則繼續獲取;是null則不獲取, -->
    <p th:text="${zoo?.dog?.name}"></p>

</div>

自定義模板

  • 作用:內容復用,定義一次,在其他的模板檔案中可多次使用,

1.自定義模板

  • 模板定義語法:th:fragment="模板自定義名稱"

  • 示例:(在 head.html 中創建下列模板)

    <div th:fragment="top">
        <p>百度地址</p>
        <p>www.baidu.com</p>
    </div>
    

2.使用自定義模板

有兩種使用的語法格式:

  1. ~{檔案名稱 :: 自定義的模板名}
  2. 檔案名稱 :: 自定義的模板名

PS:檔案名稱指的自定義的模板所在的 html 檔案名,不含后綴

對于模板,有兩種常用的使用方式:包含模板(th:include),插入模板(th:insert)

a.插入模板
  • 解釋:是在原有標簽中,將自定義的模板添加進來,不會失去原有標簽,但原有標簽下的內容將失去,

  • 語法

    • 格式1:th:insert="~{檔案名稱 :: 自定義的模板名}"
    • 格式2:th:insert="檔案名稱 :: 自定義的模板名"
  • 示例:(在 test.html 中,將 head.html 中名為 top 的模板插入到指定標簽中)

    使用格式1:

    <div th:insert="~{head :: top}">
        此div標簽下內容將會丟失,但div標簽仍然存在!
    </div>
    

    使用格式2:

    <div th:insert="head :: top">
        此div標簽下內容將會丟失,但div標簽仍然存在!
    </div>
    
b.包含模板
  • 解釋:用自定義的模板替換原有標簽,原有標簽將不存在

  • 語法

    • 格式1:th:include="~{檔案名稱 :: 自定義的模板名}"
    • 格式2:th:include="檔案名稱 :: 自定義的模板名"
  • 示例:(在 test.html 中,將 head.html 中名為 top 的模板包含(替換)到指定的標簽)

    使用格式1:

    <div th:include="~{head :: top}">
        整個div標簽將被完全替換為自定義的模板!
    </div>
    

    使用格式2:

    <div th:include="head :: top">
        整個div標簽將被完全替換為自定義的模板!
    </div>
    

3.整個 html 作為模板

如果要將整個 html 的內容作為模板插入(insert)或包含(include)到指定的標簽中,可使用下列幾種方式:

示例:將整個 head.html 作為模板,插入到指定標簽處

a.插入整個 html 模板
方式一:
<div th:insert="head :: html">
    將整個 head.html 作為模板,插入到此標簽處!
</div>

方式二:
<div th:insert="head">
    將整個 head.html 作為模板,插入到此標簽處!
</div>

示例:將整個 head.html 作為模板,包含(替換)到指定標簽處

b.包含整個 html 模板
方式一:
<div th:include="head :: html">
    將整個 head.html 作為模板,包含(替換)到此標簽處!
</div>

方式二:
<div th:include="head">
    將整個 head.html 作為模板,包含(替換)到此標簽處!
</div>

4.使用其他目錄中的模板

說明:如果要使用的自定義模板或要使用的整個 html 模板與當前頁面不在同一目錄下,則在指定使用模板的檔案名時需要使用相對路徑即可!

例如:在 test.html 某標簽中要將同級 common 目錄下 left.html 作為整個模板來使用:

方式一:插入
<div th:insert="common/left :: html"></div>
方式二:插入
<div th:insert="common/left"></div>

方式一:包含
<div th:include="common/left :: html"></div>
方式二:包含
<div th:include="common/left"></div>

以上是使用其他目錄中的整個 html 作為模板示例;使用其他目錄中指定 html 頁面中的某個自定義模板用法和其相同,

注解總結

Spring + SpringMVC + SpringBoot

創建物件的:
@Controller:放在類的上面,創建控制器物件,注入到容器中
@RestController:放在類的上面,創建控制器物件,注入到容器中,
             作用:復合注解,含@Controller,@ResponseBody,使用這個注解類的,里面的控制器方法的回傳值都是資料,

@Service:放在業務層的實作類上面,創建service物件,注入到容器
@Repository:放在dao層的實作類上面,創建dao物件,放入到容器,沒有使用這個注解,是因為現在使用MyBatis框架,dao物件				是MyBatis通過代理生成的,不需要使用@Repository,所以沒有使用,
@Component:放在類的上面,創建此類的物件,放入到容器中, 

賦值的:
@Value:簡單型別的賦值,例如在屬性的上面使用@Value("李四") private String name
          還可以使用@Value獲取組態檔者的資料(properties或yml), 
          @Value("${server.port}") private Integer port

@Autowired:參考型別賦值自動注入的,支持byName, byType. 默認是byType , 放在屬性的上面,也可以放在構造         		    方法的上面, 推薦是放在構造方法的上面
@Qualifer:給參考型別賦值,使用byName方式,   
            @Autowird, @Qualifer都是Spring框架提供的,

@Resource:來自jdk中的注解,javax.annotation, 實作參考型別的自動注入, 支持byName, byType.
             默認是byName, 如果byName失敗,再使用byType注入;在屬性上面使用,

其他:
@Configuration:放在類的上面,表示這是個配置類,相當于xml組態檔

@Bean:放在方法的上面,把方法的回傳值物件,注入到spring容器中,

@ImportResource:加載其他的xml組態檔,把檔案中的物件注入到spring容器中,

@PropertySource:讀取其他的properties屬性組態檔

@ComponentScan:掃描器,指定包名,掃描注解的

@ResponseBody:放在方法的上面,表示方法的回傳值是資料,不是視圖
@RequestBody:把請求體中的資料,讀取出來,轉為java物件使用,

@ControllerAdvice:控制器增強,放在類的上面,表示此類提供了方法,可以對controller增強功能,

@ExceptionHandler:處理例外的,放在方法的上面

@Transactional:處理事務的, 放在service實作類的public方法上面,表示此方法有事務

SpringBoot中使用的注解:
@SpringBootApplication:放在啟動類上面,包含了@SpringBootConfiguration
                          @EnableAutoConfiguration,@ComponentScan
    
MyBatis相關的注解:
@Mapper:放在類的上面,讓MyBatis找到介面,創建他的代理物件    
@MapperScan:放在主類的上面,指定掃描的包,把這個包中的所有介面都創建代理物件,將物件注入到容器中
@Param:放在dao介面的方法的形參前面,作為命名引數使用的,
    
Dubbo注解:
@DubboService:在提供者端使用的,暴露服務的,放在介面的實作類上面
@DubboReference:在消費者端使用的,參考遠程服務,放在屬性上面使用,
@EnableDubbo:放在主類上面,表示當前參考啟用Dubbo功能,

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

標籤:其他

上一篇:OpenGL ES EGL eglGetError

下一篇:淺談PHP設計模式的觀察者模式

標籤雲
其他(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