SpringMVC學習筆記 - 第一章 - 工作流程、Bean載入控制、請求與響應(參數接收與內容返回)、RESTful

来源:https://www.cnblogs.com/dandelion-000-blog/archive/2023/01/26/17067954.html
-Advertisement-
Play Games

【前置內容】Spring 學習筆記全系列傳送門: Spring學習筆記 - 第一章 - IoC(控制反轉)、IoC容器、Bean的實例化與生命周期、DI(依賴註入) Spring學習筆記 - 第二章 - 註解開發、配置管理第三方Bean、註解管理第三方Bean、Spring 整合 MyBatis 和 ...


【前置內容】Spring 學習筆記全系列傳送門:

SpingMVC 學習筆記全系列傳送門:

目錄

1、SpringMVC概述

  • SpringMVC是一種基於Java實現MVC模型的輕量級Web框架

  • 優點

    • 使用簡單、開發便捷(相比於Servlet)
    • 靈活性強
  • SpringMVC主要負責的就是

    • controller如何接收請求和數據
    • 如何將請求和數據轉發給業務層
    • 如何將響應數據轉換成json發回到前端
  • 三層架構與MVC模式

    三層架構與MVC模式

    • 瀏覽器發送一個請求給後端伺服器,後端伺服器現在是使用Servlet來接收請求和數據

      如果所有的處理都交給Servlet來處理的話,所有的東西都耦合在一起,對後期的維護和擴展極為不利

    • 將後端伺服器Servlet拆分成三層,分別是webservicedao

      • web層主要由servlet來處理,負責頁面請求和數據的收集以及響應結果給前端
      • service層主要負責業務邏輯的處理
      • dao層主要負責數據的增刪改查操作

      servlet處理請求和數據的時候,存在的問題是一個servlet只能處理一個請求

    • 針對web層進行了優化,採用了MVC設計模式,將其設計為controllerviewModel

      • controller負責請求和數據的接收,接收後將其轉發給service進行業務處理
      • service根據需要會調用dao對數據進行增刪改查
      • dao把數據處理完後將結果交給service,service再交給controller
      • controller根據需求組裝成Model和View,Model和View組合起來生成頁面轉發給前端瀏覽器
      • 這樣做的好處就是controller可以處理多個請求,並對請求進行分發,執行不同的業務操作。

    三層架構與MVC模式傳遞

    • 隨著互聯網的發展,上面的模式因為是同步調用,性能慢慢的跟不是需求,所以非同步調用慢慢的走到了前臺,是現在比較流行的一種處理方式

      • 因為是非同步調用,所以後端不需要返回view視圖,將其去除
      • 前端如果通過非同步調用的方式進行交互,後臺就需要將返回的數據轉換成json格式進行返回

2、SpringMVC入門案例

2.1 註意事項

  • SpringMVC是基於Spring的,在pom.xml只導入了spring-webmvcjar包的原因是它會自動依賴spring相關坐標
  • AbstractDispatcherServletInitializer類是SpringMVC提供的快速初始化Web3.0容器的抽象類
  • AbstractDispatcherServletInitializer提供了三個介面方法供用戶實現
    • createServletApplicationContext方法,創建Servlet容器時,載入SpringMVC對應的bean並放入WebApplicationContext對象範圍中,而WebApplicationContext的作用範圍為ServletContext範圍,即整個web容器範圍
    • getServletMappings方法,設定SpringMVC對應的請求映射路徑,即SpringMVC攔截哪些請求
    • createRootApplicationContext方法,如果創建Servlet容器時需要載入非SpringMVC對應的bean,使用當前方法進行,使用方式和createServletApplicationContext相同。
    • createServletApplicationContext用來載入SpringMVC環境
    • createRootApplicationContext用來載入Spring環境

2.2 案例製作

  1. 創建 Maven-webapp 項目,整理包結構

    image-20221228060317972

  2. 導入依賴

    <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>priv.dandelion</groupId>
      <artifactId>01_quickstart</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.2.10.RELEASE</version>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.1</version>
            <configuration>
              <port>80</port>
              <path>/</path>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    
    
  3. 創建 Controller

    // 定義Controller,聲明為Spring的bean
    @Controller
    public class UserController {
    
        // 設置當前操作的訪問路徑
        @RequestMapping("/save")
        // 設置當前操作的返回值類型
        @ResponseBody
        public String save() {
            System.out.println("user----save");
            // 相應的內容直接返回
            return "{'hello':'springmvc'}";
        }
    }
    
  4. 創建配置類

    // 創建SpringMVC的配置文件,載入controller對應的bean
    @Configuration
    @ComponentScan("priv.dandelion.controller")
    public class SpringMvcConfig {
    }
    
  5. 定義 Servlet 容器啟動的配置類(代替 web.xml

    // 定義一個servlet容器啟動的配置類,在此處載入spring配置
    public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    
        // 載入SpringMVC容器配置
        @Override
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            // 註冊配置
            ctx.register(SpringMvcConfig.class);
            // tomcat伺服器啟動時就可以載入到SpringMvcConfig.class
            return ctx;
        }
    
        // 設置那些請求歸屬於SpringMVC處理
        @Override
        protected String[] getServletMappings() {
            // 將所有請求交給SpringMVC處理
            return new String[]{"/"};
        }
    
        // 載入Spring容器配置,此處暫時未用到
        @Override
        protected WebApplicationContext createRootApplicationContext() {
            return null;
        }
    }
    

2.3 相關知識點

  • @Controller

    名稱 @Controller
    類型 類註解
    位置 SpringMVC控制器類定義上方
    作用 設定SpringMVC的核心控制器bean
  • @RequestMapping

    名稱 @RequestMapping
    類型 類註解或方法註解
    位置 SpringMVC控制器類或方法定義上方
    作用 設置當前控制器方法請求訪問路徑
    相關屬性 value(預設),請求訪問路徑
  • @ResponseBody

    名稱 @ResponseBody
    類型 類註解或方法註解
    位置 SpringMVC控制器類或方法定義上方
    作用 設置當前控制器方法響應內容為當前返回值,無需解析

2.4 工作流程解析

包含關係:

  • Web容器
    • ServletContext
      • WebApplicationContext
        • UserController
          • /save -> save() 【SpringMVC 的映射並不是放在 bean 中管理的】

2.4.1 啟動伺服器初始化過程

  1. 伺服器啟動,執行 web 伺服器配置類 ServletContainersInitConfig,初始化web容器

    • 功能類似於以前的web.xml
  2. 執行createServletApplicationContext方法,創建了WebApplicationContext對象(存在於 ServletContext 中)

    • 該方法載入SpringMVC的配置類SpringMvcConfig來初始化SpringMVC的容器

      // 載入SpringMVC容器配置
      @Override
      protected WebApplicationContext createServletApplicationContext() {
          AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
          // 註冊配置
          ctx.register(SpringMvcConfig.class);
          // tomcat伺服器啟動時就可以載入到SpringMvcConfig.class
          return ctx;
      }
      
  3. 載入SpringMvcConfig配置類,以在下一步載入所需的bean

    // 創建SpringMVC的配置文件,載入controller對應的bean
    @Configuration
    @ComponentScan("priv.dandelion.controller")
    public class SpringMvcConfig {
    }
    
  4. 執行@ComponentScan載入對應的bean

    掃描指定包及其子包下所有類上的註解,如Controller類上的@Controller註解

  5. 載入UserController,每個@RequestMapping的名稱對應一個具體的方法

    • 此時就建立了 /save 和 save() 方法的對應關係

      // 定義Controller,聲明為Spring的bean
      @Controller
      public class UserController {
                      
          // 設置當前操作的訪問路徑
          @RequestMapping("/save")
          // 設置當前操作的返回值類型
          @ResponseBody
          public String save() {
              System.out.println("user----save");
              // 相應的內容直接返回
              return "{'hello':'springmvc'}";
          }
      }
      
  6. 執行getServletMappings方法,設定SpringMVC攔截請求的路徑規則

    • /代表所攔截請求的路徑規則,只有被攔截後才能交給SpringMVC來處理請求/代表所攔截請求的路徑規則,只有被攔截後才能交給SpringMVC來處理請求

      // 設置那些請求歸屬於SpringMVC處理
      @Override
      protected String[] getServletMappings() {
          // 將所有請求交給SpringMVC處理
          return new String[]{"/"};
      }
      

2.4.2 單次請求過程

  1. 發送請求http://localhost/save

  2. web容器發現該請求滿足SpringMVC攔截規則,將請求交給 SpringMVC 處理

  3. 解析請求路徑 /save

  4. 由 /save 匹配執行對應的方法 save()

    • 上面的第五步已經將請求路徑和方法建立了對應關係,通過 /save 就能找到對應的save方法
  5. 執行 save()

  6. 檢測到有 @ResponseBody 直接將 save() 方法的返回值作為響應體返回給請求方

2.5 bean 載入控制

2.5.1 問題分析

問題:

  • 哪些 bean 交給 SpringMVC 管理,哪些包交給 Spring 管理
  • 因為功能不同,如何避免 Spring 錯誤載入到 SpringMVC 的 bean
  • 包結構

    • config目錄存入的是配置類,本篇和前面的內容已經寫過的配置類有:

      • ServletContainersInitConfig
      • SpringConfig
      • SpringMvcConfig
      • JdbcConfig
      • MybatisConfig
    • controller 目錄存放的是 SpringMVC 的 controller 類

    • service 目錄存放的是 service 介面和實現類

    • dao 目錄存放的是 dao/Mapper 介面

  • 管理

    • SpringMVC載入其相關bean
      • 表現層 bean(Controller),也就是controller包下的類
    • Spring控制的bean
      • 業務 bean(Service)
      • 功能 bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)

2.5.2 思路分析

載入Spring控制的bean的時候排除掉 SpringMVC 控制的 bean

  • 方式一:Spring載入的bean設定掃描範圍為精準範圍,例如service包、dao包等
  • 方式二:Spring載入的bean設定掃描範圍為priv.dandelion,排除掉controller包中的bean
  • 方式三:不區分Spring與SpringMVC的環境,載入到同一個環境中[瞭解即可]

2.5.3 環境準備

  • 創建 Web 的 Maven 項目,刪除 web.xml 配置文件

  • 依賴

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>priv.dandelion</groupId>
        <artifactId>02_bean_load</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
    
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.6</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.0</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <port>80</port>
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
  • 創建對應的配置類

    • 替代 web.xml 的 web 伺服器配置類 ServletContainersInitConfig

      public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
          protected WebApplicationContext createServletApplicationContext() {
              AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
              ctx.register(SpringMvcConfig.class);
              return ctx;
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected WebApplicationContext createRootApplicationContext() {
              return null;
          }
      }
      
    • SpringMVC 配置類

      @Configuration
      @ComponentScan("priv.dandelion.controller")
      public class SpringMvcConfig {
      }
      
    • Spring 配置類

      @Configuration
      @ComponentScan("priv.dandelion")
      public class SpringConfig {
      }
      
  • 實體類

    public class User {
        private Integer id;
        private String name;
        private Integer age;
        // Getter
        // Settrt
        // toString
    }
    
  • Dao 介面

    public interface UserDao {
        @Insert("insert into tbl_user(name,age)values(#{name},#{age})")
        public void save(User user);
    }
    
  • Service 實現類 (介面不表)

    @Service
    public class UserServiceImpl implements UserService {
        public void save(User user) {
            System.out.println("user service ...");
        }
    }
    
  • Controller

    @Controller
    public class UserController {
    
        @RequestMapping("/save")
        @ResponseBody
        public String save(){
            System.out.println("user save ...");
            return "{'info':'springmvc'}";
        }
    }
    

2.5.4 設置 bean 載入控制

  • web伺服器啟動時載入配置類的相關配置

    • 標準方式

      • 方式
        • 修改 createRootApplicationContext() 方法中的內容
          • 與 createServletApplicationContext() 基本相同但是載入 SpringConfig.class
      • 說明
        • createServletApplicationContext() 載入的是 SpringMVC 環境配置
        • createRootApplicationContext() 載入的是 Spring 環境配置
      public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
          protected WebApplicationContext createServletApplicationContext() {
              AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
              ctx.register(SpringMvcConfig.class);
              return ctx;
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected WebApplicationContext createRootApplicationContext() {
              AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
              ctx.register(SpringConfig.class);
              return ctx;
          }
      }
      
    • 簡化方式

      說明:

      • AbstractDispatcherServletInitializer 類包含一個子類 AbstractAnnotationConfigDispatcherServletInitializer 可以簡化配置
      • 方法名中包含 RootConfig 的是 Spring 的配置,包含 ServletConfig 的是對 SpringMVC 的配置,與標準方式中的相同
      public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          @Override
          protected Class<?>[] getRootConfigClasses() {
              return new Class[]{SpringConfig.class};
          }
      
          @Override
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
      
          @Override
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
      }public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          @Override
          protected Class<?>[] getRootConfigClasses() {
              return new Class[]{SpringConfig.class};
          }
      
          @Override
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
      
          @Override
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
      }
      
  • bean 載入控制方式

    • 方案一:修改Spring 配置類,精準掃描

      說明:

      • 此處使用了MyBatis技術且是自動代理,所以可以不掃Dao
      • 但是建議按照標準開發規則書寫,通用性強
      @Configuration
      @ComponentScan({"priv.dandelion.service","priv.dandelion.dao"})
      public class SpringConfig {
      }
      
    • 方案二

      說明:

      • 掃描所有的包

      • 但是使用過濾器進行排除

        • 過濾的類型是按註解過濾,過濾Controller註解

      使用到的屬性:

      • excludeFilters屬性:設置掃描載入bean時,排除的過濾規則

      • type屬性:設置排除規則,當前使用按照bean定義時的註解類型進行排除

        • ANNOTATION:按照註解排除
        • ASSIGNABLE_TYPE:按照指定的類型過濾
        • ASPECTJ:按照Aspectj表達式排除,基本上不會用
        • REGEX:按照正則表達式排除
        • CUSTOM:按照自定義規則排除

        大家只需要知道第一種ANNOTATION即可

      • classes屬性:設置排除的具體註解類,當前設置排除@Controller定義的bean

      @Configuration
      @ComponentScan(
              value = "priv.dandelion",
              excludeFilters = @ComponentScan.Filter(
                      type = FilterType.ANNOTATION,
                      classes = Controller.class
              )
      )
      public class SpringConfig {
      }
      
    • 方式三(不區分 Spring 與 SpringMVC 的環境)【此處不做詳細說明】

2.5.5 相關知識點:@ComponentScan

名稱 @ComponentScan
類型 類註解
位置 類定義上方
作用 設置spring配置類掃描路徑,用於載入使用註解格式定義的bean
相關屬性 excludeFilters:排除掃描路徑中載入的bean,需要指定類別(type)和具體項(classes)
includeFilters:載入指定的bean,需要指定類別(type)和具體項(classes)

3、請求與相應

3.1 設置請求映射路徑

本小節註意:

  • 當類上和方法上都添加了@RequestMapping註解,前端發送請求的時候,要和兩個註解的value值相加匹配才能訪問到。
  • @RequestMapping註解value屬性前面加不加/都可以

3.1.1 環境準備

  • 依賴

    <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>priv.dandelion</groupId>
        <artifactId>03_request_mapping</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <port>80</port>
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
  • 配置類

    • Spring 配置類(此處未使用到)

      @Configuration
      @ComponentScan(value = "priv.dandelion",
              excludeFilters = @ComponentScan.Filter(
                      type = FilterType.ANNOTATION,
                      classes = Controller.class
              )
      )
      public class SpringConfig {
      }
      
    • SpringMVC 配置類

      @Configuration
      @ComponentScan("priv.dandelion.controller")
      public class SpringMvcConfig {
      }
      
    • web伺服器配置類 (簡化配置)

      public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected Class<?>[] getRootConfigClasses() {
              return new Class[0];
          }
      }
      
  • Controller

    • UserController

      @Controller
      public class UserController {
      
          @RequestMapping("/save")
          @ResponseBody
          public String save(){
              System.out.println("user save ...");
              return "{'module':'user save'}";
          }
      
          @RequestMapping("/delete")
          @ResponseBody
          public String delete(){
              System.out.println("user delete ...");
              return "{'module':'user delete'}";
          }
      }
      
    • BookController

      @Controller
      public class BookController {
      
          @RequestMapping("/save")
          @ResponseBody
          public String save(){
              System.out.println("book save ...");
              return "{'module':'book save'}";
          }
      }
      

3.1.2 問題分析

  • 以上環境準備完成後,啟動伺服器時會報錯

    [INFO] Initializing Servlet 'dispatcher'
    [WARNING] Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'userController' method 
    priv.dandelion.controller.UserController#save()
    to { /save}: There is already 'bookController' bean method
    priv.dandelion.controller.BookController#save() mapped.
    [ERROR] Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'userController' method 
    priv.dandelion.controller.UserController#save()
    to { /save}: There is already 'bookController' bean method
    priv.dandelion.controller.BookController#save() mapped.
        at ...
        at ...
        ...
    
  • 從錯誤信息可知

    • UserController有一個save方法,訪問路徑為http://localhost/save
    • BookController也有一個save方法,訪問路徑為http://localhost/save
    • 當訪問http://localhost/saved的時候,到底是訪問 UserController 還是 BookController,就會出現衝突
  • 解決方案:為不同模塊設置模塊名作為請求路徑前置

    • 對於Book模塊的save,將其訪問路徑設置http://localhost/book/save
    • 對於User模塊的save,將其訪問路徑設置http://localhost/user/save

3.1.3 設置映射路徑

  • 方案一(耦合度高不推薦):對每一個資源的 RequestMapping 進行修改

    • UserController

      @Controller
      public class UserController {
      
          @RequestMapping("/user/save")
          @ResponseBody
          public String save(){
              System.out.println("user save ...");
              return "{'module':'user save'}";
          }
      
          @RequestMapping("/user/delete")
          @ResponseBody
          public String delete(){
              System.out.println("user delete ...");
              return "{'module':'user delete'}";
          }
      }
      
    • BookController(不表)

  • 方案二:為 Controller 添加一個整體的 RequestMapping(稱為請求路徑首碼),其他不變

    • UserController

      @Controller
      @RequestMapping("/user")
      public class UserController {
      
          @RequestMapping("/save")
          @ResponseBody
          public String save(){
              System.out.println("user save ...");
              return "{'module':'user save'}";
          }
      
          @RequestMapping("/delete")
          @ResponseBody
          public String delete(){
              System.out.println("user delete ...");
              return "{'module':'user delete'}";
          }
      }
      
    • BookController(不表)

3.2 請求參數

3.2.1 環境準備

  • 依賴、配置類見 3.1.1

  • 實體類

    • Address

      public class Address {
          private String province;
          private String city;
          
          // Getter,Setter,toString不表
      }
      
    • User

      public class User {
          private String name;
          private int age;
      
          // Getter,Setter,toString不表
      }
      
  • Controller

    @Controller
    public class UserController {
    
        @RequestMapping("/commonParam")
        @ResponseBody
        public String commonParam(){
            return "{'module':'commonParam'}";
        }
    }
    

3.2.2 參數傳遞及中文亂碼處理方案

Get請求與參數:

http://localhost/commonParam?name=dandelion&age=18

POST請求與參數:

  • 發送Post請求時,參數放在請求體中,若使用PostMan工具,參數需要寫在Body模塊中,發送表單數據時使用 x-www-from-urlencodedform-data除了發送表單之外還可以發送文件)
  • GET請求

    • 接收參數

      @Controller
      public class UserController {
      
          @RequestMapping("/commonParam")
          @ResponseBody
          public String commonParam(String name, int age){
              System.out.println("普通參數name:"+ name);
              System.out.println("普通參數age:"+ age);
              return "{'module':'commonParam'}";
          }
      }
      
    • GET中文亂碼:配置pom.xml

      Tomcat8.5以後的版本已經處理了中文亂碼的問題,但是IDEA中的Tomcat插件目前只到Tomcat7,所以需要修改pom.xml來解決GET請求中文亂碼問題

      <build>
          <plugins>
              <plugin>
                  <groupId>org.apache.tomcat.maven</groupId>
                  <artifactId>tomcat7-maven-plugin</artifactId>
                  <version>2.1</version>
                  <configuration>
                      <port>80</port><!--tomcat埠號-->
                      <path>/</path> <!--虛擬目錄-->
                      <uriEncoding>UTF-8</uriEncoding><!--訪問路徑編解碼字元集-->
                  </configuration>
              </plugin>
          </plugins>
      </build>
      
  • POST請求

    • 接收參數

      POST請求接收參數代碼與GET請求一致

    • POST中文亂碼問題:設置過濾器

      • 在web伺服器配置類 ServletContainersInitConfig 中重寫 getServletFilters() 方法,創建所需的過濾器對象,並設置編碼字元集為UTF-8

      • CharacterEncodingFilter 是在 spring-web 包中,所以用之前需要導入對應的 jar 包

        import org.springframework.web.filter.CharacterEncodingFilter;
        
      @Override
      protected Filter[] getServletFilters() {
          CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
          characterEncodingFilter.setEncoding("UTF-8");
          return new Filter[]{characterEncodingFilter};
      }
      

3.3 五種類型參數傳遞

3.3.1 普通參數

普通參數的基本使用已經實現過,詳見 3.2.2 參數傳遞及中文亂碼處理方案

  • 解決請求中的參數名稱和 Controller 方法的參數不一致問題

    • 當出現請求中的參數名稱和Controller中方法的參數名不匹配時,無法正常接收到參數
    • 使用 @RequestPaam() 註解修飾不一致的參數,為其指定需要匹配的請求參數
    @Controller
    public class UserController {
    
        // `http://localhost/commonParam?username=dandelion&age=12`
        @RequestMapping("/commonParam")
        @ResponseBody
        public String commonParam(@RequestParam("username") String name, int age){
            System.out.println("普通參數name:"+ name);
            System.out.println("普通參數age:"+ age);
            return "{'module':'commonParam'}";
        }
    }
    

3.3.2 POJO 數據類型

  • 直接使用一個實體類作為形參,框架會使用 setter 自動將數據進行寫入
  • 實體類中的屬性名稱需要和請求參數的名稱保持一致,否則接收不到
  • 若實體類中沒有對應的 setter 可以和請求參數的參數名匹配,則預設零假空(未進行寫入),可以使用該特性在實際開發中減少工作量
  • 實體類

    public class User {
        private String name;
        private int age;
    
        // Getter,Setter,toString不表
    }
    
  • Controller

    @Controller
    public class UserController {
    
        @RequestMapping("/pojoParam")
        @ResponseBody
        public String pojoParam(User user){
            System.out.println("POJO參數:"+ user);
            return "{'module':'pojoParam'}";
        }
    }
    

3.3.3 嵌套 POJO 類型參數

對於嵌套的POJO類型,在進行參數傳遞時,也要使用嵌套的形式來書寫請求參數名稱

http://localhost/pojoParam?name=dandelion&age=12&address.province=hubei&address.city=wuhan

  • 實體類

    • User

      public class User {
          private String name;
          private int age;
          
          private Address address;
      
          // Getter,Setter,toString不表
      }
      
    • Address

      public class Address {
          private String province;
          private String city;
          
          // Getter,Setter,toString不表
      }
      
  • Controller

    Controller 部分代碼與 3.3.3 嵌套 POJO 類型參數一致

3.3.4 數組類型參數

  • 請求參數為數組時,不同的數組元素使用相同的請求參數名稱
  • 接收請求參數時,使用數組作為形參
  • 請求

    http://localhost/arrayParam?person=zhangsan&person=lisi&person=wangwu
    
  • 接收

    @Controller
    public class UserController {
    
        @RequestMapping("/arrayParam")
        @ResponseBody
        public String arrayParam(String[] person){
            System.out.println("數組參數:"+ Arrays.toString(person));
            return "{'module':'arrayParam'}";
        }
    }
    

3.3.5 集合類型參數

  • 請求

    與數組參數的請求方式相同

  • 接收

    • 錯誤案例

      以下代碼段運行時會報錯:NoSuchMethodException: java.util.List.<init>(),缺少構造,(內心:廢話 List 介面哪來的構造)

      嚴重: Servlet.service() for servlet [dispatcher] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface java.util.List] with root cause
      java.lang.NoSuchMethodException: java.util.List.<init>()
      
      @Controller
      public class UserController {
      
          @RequestMapping("/listParam")
          @ResponseBody
          public String listParam(List<String> person){
              System.out.println("集合參數:"+ person);
              return "{'module':'listParam'}";
          }
      }
      
    • 原因及解決方案

      • 問題原因

        SpringMVC 將 List 看做是一個 POJO 對象來處理,將其創建一個對象並準備把前端的數據封裝到對象中,但是 List 是一個介面無法創建對象,所以報錯。

      • 解決方案:使用@RequestParam註解

        • 集合保存普通參數:請求參數名與形參集合對象名相同且請求參數為多個,@RequestParam 綁定參數關係
        • 顯而易見,對於簡單數據類型使用數組會比集合更簡單些。
        @Controller
        public class UserController {
        
            @RequestMapping("/listParam")
            @ResponseBody
            public String listParam(@RequestParam List<String> person){
                System.out.println("集合參數:"+ person);
                return "{'module':'listParam'}";
            }
        }
        

3.3.6 相關知識點:@RequestParam

名稱 @RequestParam
類型 形參註解
位置 SpringMVC控制器方法形參定義前面
作用 綁定請求參數與處理器方法形參間的關係
相關參數 required:是否為必傳參數
defaultValue:參數預設值

3.4 JSON 數據傳輸參數

  • 參數放在請求體中,若使用 PostMan 工具,參數需要寫在Body模塊中,發送表單數據時使用 raw,並將數據格式修改為 JSON

3.4.1 JSON 數據傳輸參數分類與準備工作

  • 參數分類

    // json普通數組
    ["value1","value2","value3",...]
    // json對象
     {"key1":"value1","key2":"value2",...}
    // json對象數組
    [{"key11":"value11",...},{"key21":"value21",...}]
    
  • 準備工作

    • 添加依賴

      <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.0</version>
      </dependency>
      
    • 開啟SpringMVC註解驅動,用於開啟 json 數據類型自動轉換:@EnableWebMvc

      @Configuration
      @ComponentScan("priv.dandelion.controller")
      @EnableWebMvc
      public class SpringMvcConfig {
      }
      
    • 參數前添加@RequestBody

      • 使用@RequestBody註解將外部傳遞的json數組數據映射到形參的集合對象中作為數據
      • 區別於 @RequestParam,本小節總結部分會進行說明
      • 區別於 @ResponseBody,書寫要正確
      • 下文中展示

3.4.2 三種參數傳輸格式

3.4.2.1 json普通數組
  • JSON

    ["zhangsan","lisi","wangwu"]
    
  • 接收

    @RequestMapping("/listParamForJson")
    @ResponseBody
    // //使用@RequestBody註解將外部傳遞的json數組數據映射到形參的集合對象中作為數據
    public String listParamForJson(@RequestBody List<String> person){
        System.out.println("list common(json)參數傳遞 list:" + person);
        return "{'module':'list common for json param'}";
    }
    
3.4.2.2 json對象
  • 若 JSON 對象中的 key 與實體類中的 setter 名稱(標準書寫)不能匹配時,不執行 setter ,實體類中的數據不變(不進行其他操作時預設為零假空)
  • 同理,若不傳遞某一屬性的值,實體類中的數據不變(不進行其他操作時預設為零假空)
  • JSON

    // 單個POJO
    {
    	"name":"dandelion",
    	"age":12
    }
    
    // 嵌套POJO
    {
    	"name1":"dandelion",
    	"age":12,
        "address":{
            "province":"provinceName",
            "city":"cityName"
        }
    }
    
  • 實體類

    見 3.3.3

  • 接收

    @RequestMapping("/pojoParamForJson")
    @ResponseBody
    public String pojoParamForJson(@RequestBody User user){
        System.out.println("pojo(json)參數傳遞 user:"+user);
        return "{'module':'pojo for json param'}";
    }
    
3.4.2.3 json對象數組
  • JSON

    [
        {"name":"dandelion","age":15,"address":{"province":"provinceName","city":"cityName"}},
        {"name":"dandelion000","age":12}
    ]
    
  • 接收

    @RequestMapping("/listPojoParamForJson")
    @ResponseBody
    public String listPojoParamForJson(@RequestBody List<User> list){
        System.out.println("list pojo(json)參數傳遞 list:"+list);
        return "{'module':'list pojo for json param'}";
    }
    

3.4.3 相關知識點

  • 知識點1:@EnableWebMvc

    名稱 @EnableWebMvc
    類型 配置類註解
    位置 SpringMVC配置類定義上方
    作用 開啟SpringMVC多項輔助功能
  • 知識點2:@RequestBody

    • 整理

      名稱 @RequestBody
      類型 形參註解
      位置 SpringMVC控制器方法形參定義前面
      作用 將請求中請求體所包含的數據傳遞給請求參數,此註解一個處理器方法只能使用一次
    • @RequestBody與@RequestParam區別

      • 區別

        • @RequestParam用於接收url地址傳參,表單傳參【application/x-www-form-urlencoded】
        • @RequestBody用於接收json數據【application/json】
      • 應用

        • 後期開發中,發送json格式數據為主,@RequestBody應用較廣
        • 如果發送非json格式數據,選用@RequestParam接收請求參數

3.5 日期類型參數傳遞

  • 接收案例

    • 請求

      http://localhost/dataParam?date=2022/02/22
      
    • 接收

      @RequestMapping("/dataParam")
      @ResponseBody
      public String dataParam(Date date, Date date1){
          System.out.println("參數傳遞 date:"+date);
          System.out.println("參數傳遞 date1:"+date1);
          return"{'module':'data param'}";
      }
      
    • 結果

      • 發送請求後會發現該部分代碼會報錯,但若請求參數中只有date而沒有date1時則正常接收

      • 報錯信息:

        方法參數類型不匹配,在將 String 轉換為 Date 時出現問題,轉換失敗

        [WARNING] Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2022-02-22'; nested exception is java.lang.IllegalArgumentException]
        
        
  • 解決方案(接收任意日期格式的方法):使用 @DateTimeFormat 指定日期格式

    • 請求

      http://localhost/dataParam?date=2022/02/22&date1=22-02-2022&date2=2022-02-22 22:22:22
      
    • 接收

      @RequestMapping("/dataParam")
      @ResponseBody
      public String dataParam(Date date,
                              @DateTimeFormat(pattern = "dd-MM-yyyy") Date date1,
                              @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date2){
          System.out.println("參數傳遞 date:"+ date);
          System.out.println("參數傳遞 date1(dd-MM-yyyy):"+ date1);
          System.out.println("參數傳遞 date2(yyyy-MM-dd HH:mm:ss):"+ date2);
          return"{'module':'data param'}";
      }
      
  • 相關知識點

    • @DateTimeFormat

      名稱 @DateTimeFormat
      類型 形參註解
      位置 SpringMVC控制器方法形參前面
      作用 設定日期時間型數據格式
      相關屬性 pattern:指定日期時間格式字元串
    • 內部實現原理

      SpringMVC中提供了很多類型轉換介面和實現類,其中有 Converter 介面

      • Converter 介面

        • Converter所屬的包為org.springframework.core.convert.converter

        • 框架中有提供很多對應Converter介面的實現類,用來實現不同數據類型之間的轉換,如:

        • 請求參數年齡數據(String→Integer)

        • 日期格式轉換(String → Date)

        /**
        *	S: the source type
        *	T: the target type
        */
        public interface Converter<S, T> {
            @Nullable
            //該方法就是將從頁面上接收的數據(S)轉換成我們想要的數據類型(T)返回
            T convert(S source);
        }
        
      • HttpMessageConverter 介面

        該介面是實現對象與 JSON 之間的轉換工作,使用時在SpringMVC的配置類把@EnableWebMvc當做標配配置上去,不省略

3.6 響應

3.6.1 環境準備

  • 依賴

    <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>priv.dandelion</groupId>
        <artifactId>05_response</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.0</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <port>80</port>
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
  • 配置類

    • 伺服器配置類

      public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected Class<?>[] getRootConfigClasses() {
              return new Class[0];
          }
      
          @Override
          protected Filter[] getServletFilters() {
              CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
              characterEncodingFilter.setEncoding("UTF-8");
              return new Filter[]{characterEncodingFilter};
          }
      }
      
    • SpringMVC 配置類

      @Configuration
      @ComponentScan("priv.dandelion.controller")
      public class SpringMvcConfig {
      }
      
  • 實體類

    public class User {
        private String name;
        private int age;
        //getter...setter...toString省略
    }
    
  • webapp下創建頁面 page.jsp

    <html>
    <body>
    <h2>Hello Spring MVC!</h2>
    </body>
    </html>
    
  • Controller

    @Controller
    public class UserController {
    
    }
    

3.6.2 響應頁面(瞭解)

  • 註意此處不能使用@ResponseBody,否則會將返回值內容作為字元串返回給前端
  • 註意進行頁面跳轉時,返回值為頁面名稱,返回值類型為字元串
@RequestMapping("/toJumpPage")
public String toJumpPage() {
    System.out.println("跳轉頁面");
    return "page.jsp";
}

3.6.3 返迴文本數據(瞭解)

  • 註意此處 @ResponseBody 註解就不能省略
  • 如果省略了會把response text當前頁面名稱去查找,如果沒有回報404
@RequestMapping("/toText")
@ResponseBody
public String toText() {
    System.out.println("返回純文本數據");
    return "response text";
}

3.6.4 響應 JSON 數據

準備工作:

  • 開啟SpringMVC註解驅動,用於開啟 json 數據類型自動轉換:@EnableWebMvc

    @Configuration
    @ComponentScan("priv.dandelion.controller")
    @EnableWebMvc
    public class SpringMvcConfig {
    }
    
3.6.4.1 響應 POJO 對象
@RequestMapping("/toJsonPOJO")
@ResponseBody
public User toJsonPOJO() {
    System.out.println("返回JSON數據對象");
    User user = new User();
    user.setName("dandelion");
    user.setAge(12);
    return user;
}
3.6.4.2 響應 POJO 集合對象

此處返回的是POJO的集合,基本數據類型的集合同理

@RequestMapping("/toJsonList")
@ResponseBody
public List<User> toJsonList() {
    System.out.println("返回JSON數據對象");
    User user1 = new User();
    user1.setName("dandelion");
    user1.setAge(12);

    User user2 = new User();
    user2.setName("dandelion000");
    user2.setAge(15);

    List<User> users = new ArrayList<>();
    users.add(user1);
    users.add(user2);
    return users;
}
3.6.4.3 相關知識點:@ResponseBody
  • 整理

    名稱 @ResponseBody
    類型 方法\類註解
    位置 SpringMVC控制器方法定義上方和控制類上
    作用 設置當前控制器返回值作為響應體,
    寫在類上,該類的所有方法都有該註解功能
    相關屬性 pattern:指定日期時間格式字元串
  • 說明

    • 該註解可以寫在類上或者方法上

    • 寫在類上就是該類下的所有方法都有@ReponseBody功能

    • 當方法上有@ReponseBody註解後

      • 方法的返回值為字元串,會將其作為文本內容直接響應給前端
      • 方法的返回值為對象,會將對象轉換成JSON響應給前端
    • 此處又使用到了類型轉換,內部還是通過Converter介面的實現類完成的,所以Converter除了前面所說的功能外,它還可以實現:

      • 對象轉Json數據(POJO -> json)

      • 集合轉Json數據(Collection -> json)

4、REST風格

4.1 REST 簡介

  • REST(Representational State Transfer),表現形式狀態轉換,它是一種軟體架構風格

  • REST風格與傳統風格的區別

    • 傳統風格資源描述形式

      • http://localhost/user/getById?id=1 查詢id為1的用戶信息
      • http://localhost/user/saveUser 保存用戶信息
    • REST風格描述形式

      • http://localhost/user/1
      • http://localhost/user
  • REST風格的優點

    • 隱藏資源的訪問行為,無法通過地址得知對資源是何種
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Lspatch的使用。xp模塊可以使用戶獲得應用原本所沒有的功能。使用模塊需要修改應用。Lspatch實現了無需Root修改應用。 ...
  • 前端面試題學習-HTML-個人總結 這是看別人總結的基礎上再度總結的,總結的鏈接如下 鏈接 1. DOCTYPE 的作用? 告知瀏覽器解析器用何標準解析文檔,若不指定則按相容模式進行解析(向後相容模擬老瀏覽器)。 IE5.5 引入的概念。 HTML5 之後無需指定,因為在之前的都是基於 SGML 的 ...
  • JavaScript 中有兩種類型轉換:隱式類型轉換和顯式類型轉換。 隱式類型轉換指 JavaScript 在運行時自動將一種類型轉換為另一種類型。例如,在數學運算中,JavaScript 會將字元串轉換為數字。 顯式類型轉換指在代碼中使用內置函數或全局對象將一種類型顯式地轉換為另一種類型。例如,使 ...
  • 商品系統是電商系統最基礎、最核心的系統之一。商品數據遍佈所有業務,首頁、門店頁、購物車、訂單、結算、售後、庫存、價格等,都離不開商品。商品信息要穩定提供至到家供應鏈的每個節點,所以必須要有一套穩定的、高性能的商品服務體系支撐。 隨著京東到家商品業務的快速發展,業務從單一轉變為多元化,系統功能設... ...
  • 測試一、虛繼承與繼承的區別 1.1 單個繼承,不帶虛函數 1>class B size(8): 1> + 1> 0 | + (base class A) 1> 0 | | _ia //4B 1> | + 1> 4 | _ib //4B 有兩個int類型數據成員,占8B,基類邏輯存在前面 1.2、單個 ...
  • AOP-03 7.AOP-切入表達式 7.1切入表達式的具體使用 1.切入表達式的作用: 通過表達式的方式定義一個或多個具體的連接點。 2.語法細節: (1)切入表達式的語法格式: execution([許可權修飾符] [返回值類型] [簡單類名/全類名] [方法名]([參數列表]) 若目標類、介面與 ...
  • 這次設計一個通用的多位元組SPI介面模塊,特點如下: 可以設置為1-128位元組的SPI通信模塊 可以修改CPOL、CPHA來進行不同的通信模式 可以設置輸出的時鐘 狀態轉移圖和思路與多位元組串口發送模塊一樣,這裡就不給出了,具體可看該隨筆。 一、模塊代碼 1、需要的模塊 通用8位SPI介面模塊 `tim ...
  • 簡介: 享元模式,屬於結構型的設計模式。運用共用技術有效地支持大量細粒度的對象。 適用場景: 具有相同抽象但是細節不同的場景中。 優點: 把公共的部分分離為抽象,細節依賴於抽象,符合依賴倒轉原則。 缺點: 增加複雜性。 代碼: //用戶類 class User { private $name; fu ...
一周排行
    -Advertisement-
    Play Games
  • 1. 說明 /* Performs operations on System.String instances that contain file or directory path information. These operations are performed in a cross-pla ...
  • 視頻地址:【WebApi+Vue3從0到1搭建《許可權管理系統》系列視頻:搭建JWT系統鑒權-嗶哩嗶哩】 https://b23.tv/R6cOcDO qq群:801913255 一、在appsettings.json中設置鑒權屬性 /*jwt鑒權*/ "JwtSetting": { "Issuer" ...
  • 引言 集成測試可在包含應用支持基礎結構(如資料庫、文件系統和網路)的級別上確保應用組件功能正常。 ASP.NET Core 通過將單元測試框架與測試 Web 主機和記憶體中測試伺服器結合使用來支持集成測試。 簡介 集成測試與單元測試相比,能夠在更廣泛的級別上評估應用的組件,確認多個組件一起工作以生成預 ...
  • 在.NET Emit編程中,我們探討了運算操作指令的重要性和應用。這些指令包括各種數學運算、位操作和比較操作,能夠在動態生成的代碼中實現對數據的處理和操作。通過這些指令,開發人員可以靈活地進行算術運算、邏輯運算和比較操作,從而實現各種複雜的演算法和邏輯......本篇之後,將進入第七部分:實戰項目 ...
  • 前言 多表頭表格是一個常見的業務需求,然而WPF中卻沒有預設實現這個功能,得益於WPF強大的控制項模板設計,我們可以通過修改控制項模板的方式自己實現它。 一、需求分析 下圖為一個典型的統計表格,統計1-12月的數據。 此時我們有一個需求,需要將月份按季度劃分,以便能夠直觀地看到季度統計數據,以下為該需求 ...
  • 如何將 ASP.NET Core MVC 項目的視圖分離到另一個項目 在當下這個年代 SPA 已是主流,人們早已忘記了 MVC 以及 Razor 的故事。但是在某些場景下 SSR 還是有意想不到效果。比如某些靜態頁面,比如追求首屏載入速度的時候。最近在項目中回歸傳統效果還是不錯。 有的時候我們希望將 ...
  • System.AggregateException: 發生一個或多個錯誤。 > Microsoft.WebTools.Shared.Exceptions.WebToolsException: 生成失敗。檢查輸出視窗瞭解更多詳細信息。 內部異常堆棧跟蹤的結尾 > (內部異常 #0) Microsoft ...
  • 引言 在上一章節我們實戰了在Asp.Net Core中的項目實戰,這一章節講解一下如何測試Asp.Net Core的中間件。 TestServer 還記得我們在集成測試中提供的TestServer嗎? TestServer 是由 Microsoft.AspNetCore.TestHost 包提供的。 ...
  • 在發現結果為真的WHEN子句時,CASE表達式的真假值判斷會終止,剩餘的WHEN子句會被忽略: CASE WHEN col_1 IN ('a', 'b') THEN '第一' WHEN col_1 IN ('a') THEN '第二' ELSE '其他' END 註意: 統一各分支返回的數據類型. ...
  • 在C#編程世界中,語法的精妙之處往往體現在那些看似微小卻極具影響力的符號與結構之中。其中,“_ =” 這一組合突然出現還真不知道什麼意思。本文將深入剖析“_ =” 的含義、工作原理及其在實際編程中的廣泛應用,揭示其作為C#語法奇兵的重要角色。 一、下劃線 _:神秘的棄元符號 下劃線 _ 在C#中並非 ...