SpringBoot學習總結

来源:https://www.cnblogs.com/zydevelop/p/18210682/zy_springboot
-Advertisement-
Play Games

SpringBoot筆記 SpringBoot文檔 官網: https://spring.io/projects/spring-boot 學習文檔: https://docs.spring.io/spring-boot/docs/current/reference/html/ 線上API: http ...


SpringBoot筆記

SpringBoot文檔

  1. 官網: https://spring.io/projects/spring-boot
  2. 學習文檔: https://docs.spring.io/spring-boot/docs/current/reference/html/
  3. 線上API: https://docs.spring.io/spring-boot/docs/current/api/

Spring Boot 是什麼

  1. Spring Boot 可以輕鬆創建獨立的、生產級的基於Spring 的應用程式
  2. Spring Boot 直接嵌入Tomcat、Jetty 或Undertow ,可以"直接運行" SpringBoot 應用程式
  3. Spring Boot有Web場景啟動器,會自動導入和Web相關的依賴

Springboot/Srping/SpringMVC之間的關係

  1. 關係大概是: Spring Boot > Spring > Spring MVC
  2. Spring MVC 只是Spring 處理WEB 層請求的一個模塊/組件, Spring MVC 的基石是Servlet
  3. Spring 的核心是IOC 和AOP, IOC 提供了依賴註入的容器, AOP 解決了面向切麵編程
  4. Spring Boot 是為了簡化開發, 推出的封神框架(約定優於配置[COC],簡化了Spring 項目的配置流程), SpringBoot 包含很多組件/架,Spring 就是最核心的內容之一,也包含SpringMVC
  5. Spring 家族,有眾多衍生框架和組件例如boot、security、jpa 等, 他們的基礎都是Spring

約定優於配置

  1. 約定優於配置(Convention over Configuration/COC),又稱按約定編程,是一種軟體設計規範, 本質上是對系統、類庫或框架中一些東西假定一個大眾化合理的預設值(預設值)
  2. 例如在模型中存在一個名為User 的類,那麼對應到資料庫會存在一個名為user 的表,只有在偏離這個約定時才需要做相關的配置(例如你想將表名命名為t_user 等非user 時才需要寫關於這個名字的配置)
  3. 簡單來說就是假如你所期待的配置與約定的配置一致,那麼就可以不做任何配置,約定不符合期待時, 才需要對約定進行替換配置
  4. 約定其實就是一種規範,遵循了規範,那麼就存在通用性,存在通用性,那麼事情就會變得相對簡單,程式員之間的溝通成本會降低,工作效率會提升,合作也會變得更加簡單

依賴管理

  1. spring-boot-starter-parent 還有父項目, 聲明瞭開發中常用的依賴的版本號

  2. 並且進行自動版本仲裁, 即如果程式員沒有指定某個依賴jar 的版本,則以父項目指
    定的版本為準

如何修改版本仲裁?

修改版本仲裁-方法一

在pom.xml中顯示的配置

修改版本仲裁-方法二

在spring-boot-starter-parent 的父項目 中修改即可

場景啟動器Starter

  1. 開發中我們引入了相關場景的starter,這個場景中所有的相關依賴都引入進來了,比如我們做web 開發引入了,該starter 將導入與web 開發相關的所有包
  2. SpringBoot 也支持第三方starter。第三方starter 不要從spring-boot 開始,因為這是官方spring-boot 保留的命名方式的。第三方啟動程式通常以項目名稱開頭。
  3. 也就是說:xxx-spring-boot-starter 是第三方為我們提供的簡化開發的場景啟動器

SpringBoot 自動配置了哪些?

  1. 自動配置Tomcat
  2. 自動配置SpringMVC
  3. 自動配置Web 常用功能: 比如字元過濾器
  4. 【預設掃描主程式所在包以及其子包】

如何修改預設掃描包結構?

設置 @SpringBootApplication(scanBasePackages="com.xxx")

如何修改SpringBoot預設配置?

在 resources/application.properties 文件中修改

  • 預設配置最終會映射到某個類【屬性類】

在application.properties 自定義配置

  1. 通過 @Value(${ })獲取值

  2. 例如 my.website=http://www.baidu.com

     	@value(${my.website})//獲取方式:
    	private String bdUrl(){
    	
    	}
    
  3. SpringBoot 所有的自動配置功能都在spring-boot-autoconfigure 包裡面

  4. 在SpringBoot 的自動配置包, 一般是XxxAutoConfiguration.java, 對應XxxxProperties.java

容器功能

Spring註解

Spring中傳統的註解依然可以使用

@Configuration註解

案例一

@Configuration//表示這是一個配置類【類似spring的bean.xml配置文件】
//當一個類被 @Configuration 標識 ,該類【bean】自己本身也會註入到容器中
public class BeanConfig {//配置類可以有多個, 就和Spring 可以有多個beans.xnl配置文件是一個道理.

    @Bean  // 程式員可以通過@Bean 註解註入bean對象到容器
    // 給容器添加組件,就是Monster bean;
    
    // 方法名(monster01),作為 bean 的 id/名字 ;
    // 返回值(Monster) 表示 註入類型 是 Monster 類型 ;
    // new Monster(200,"nmw",500,"fmq"); 就是註入到容器的bean的具體信息
    public Monster monster01() {
        return new Monster(200, "nmw", 500, "fmq");
    }
  1. 方法名(monster01),作為 bean 的 id/名字 ;
  2. 返回值(Monster) 表示 註入類型 是 Monster 類型 ;
  3. new Monster(200,"nmw",500,"fmq"); 就是註入到容器的bean的具體信息

案例二

  • 可以通過在註解 @Bean 中設置屬性 來指定bean的名字 @Bean("monster_nmw")
        @Bean("monster_nmw")
    // 也可以通過在註解  @Bean 中設置屬性 來指定bean的名字 @Bean("monster_nmw")
    public Monster monster02() {
        return new Monster(200, "nmw", 500, "fmq");
    }

案例三

  • @Configuration(proxyBeanMethods = true) ---proxyBeanMethods:代理bean 的方法
@Configuration(proxyBeanMethods = true)
public class BeanConfig {
    @Bean  
    //預設單例註入
    //多例模式 添加註解: @Scope("prototype")
    public Monster monster01() {
        return new Monster(200, "nmw", 500, "fmq");
    }
  1. proxyBeanMethods:代理bean 的方法
  2. Full(proxyBeanMethods = true) 【保證每個@Bean 方法被調用多少次返回的組件都是單實例的, 是代理方式】
  3. Lite(proxyBeanMethods = false)【每個@Bean 方法被調用多少次返回的組件都是新創建的, 是非代理方式】
  4. 特別說明: proxyBeanMethods 是在調用@Bean 方法才生效,因此,需要先獲取BeanConfig 組件,再調用方法而不是直接通過SpringBoot 主程式得到的容器來獲取bean, 註意觀察直接通過ioc.getBean() 獲取Bean,proxyBeanMethods 值並沒有生效
  5. 如何選擇: 組件依賴必須使用Full 模式預設。如果不需要組件依賴使用Lite 模式 ;
  6. Lite 模式也稱為輕量級模式,因為不檢測依賴關係,運行速度快

@Import註解

@Configuration
@Import({Dog.class, Cat.class})//可以指定Class數組,可以註入指定類型的Bean ;預設組件 id 是 對應的類型的全類名
public class BeanConfig {}
  1. 可以指定Class數組,可以註入指定類型的Bean ;
  2. 預設組件 id 是 對應的類型的全類名(com.xxx.xx...)

@Conditional註解

  1. 條件裝配,滿足Conditional 指定的條件,才進行組件註入
  2. @Conditional 是一個根註解,下麵有很多擴展註解
  • 例如 @ConditionalOnBean
@Bean
    @ConditionalOnBean(name = "monster_nmw")
    //【條件裝配】表示 只有在ioc容器中存在一個名字 為 monster_nmw 的bean,才能註入 dog01
    public Dog dog01() {
        return new Dog();
    }
  1. 只有在ioc容器中存在一個名字 為 monster_nmw 的bean,才能註入 dog01

  2. 對name約束,對其他無關

  3. 有 其他擴展註解,對應不同的約束例如 :@ConditionalOnMissingBeanName(name="monster-nmw")

    表示 沒有name="monster-nmw" 才會註入容器

  4. 如果@ConditionalOnBean 表示在某個類上,則該類所有的組件都要受到約束

@ImportResource

  • 作用:原生配置文件引入, 也就是可以直接導入Spring 傳統的beans.xml ,可以認為是SpringBoot 對Spring 容器文件的相容.
@Configuration
//導入bean.xml文件
@ImportResource("classpath:beans.xml")
public class BeanConfig2 {

}

將beans.xml導入到配置類

配置綁定@ConfigurationProperties

  • 使用Java 讀取到SpringBoot 核心配置文件application.properties 的內容,並且把它封裝到JavaBean 中

1.在application.properties 文件中設置 屬性 k-v 【屬性需要和JavaBean的屬性對應】

furn01.id=100
furn01.name=soft_chair!!
furn01.price=45678.9

2.在JavaBean上添加註解 @ConfigurationProperties(prefix = "furn01")

@Component
@ConfigurationProperties(prefix = "furn01")
public class Furn {
    private Integer id;
    private String name;
    private Double price;
}

註意事項

  1. 另一種綁定方式:在配置類上加上 @EnableConfigurationProperties(Furn.class)
  2. 如果application.properties 有中文, 需要轉成unicode 編碼寫入, 否則出現亂碼

yaml介紹

  1. yaml以數據作為中心,不以標記語言為中心
  2. yaml仍然是一種標記語言,但是以數據作為中心
  3. yaml非常適合用來做以數據為中心的配置文件

yaml基本語法

  1. 形式為 key: value 【註意: 後有空格】
  2. 區分大小寫
  3. 使用縮進表示層級關係
  4. 縮進推薦使用空格
  5. 縮進空格數不重要,只要相同層級的元素左對齊即可
  6. 字元串無需加引號
  7. yaml註釋使用 #

yaml數據類型

  1. 字面量:date,boolean,string,number,null

  2. 對象:鍵值對的集合 map,hash,set,object

    行內寫法

    k: {k1: v1,k2: v2,k3: v3}
    

    換行寫法

    k:
     k1: v2
     k2: v2
     k3: v3
    
  3. 數組 array,list,queue

    行內寫法

    k: [v1,v2,v3]
    

    換行寫法

    k:
     -v2
     -v2
     -v3
    

註意事項:

  1. application.properties 的優先順序比 application.yml 高,因此要避免首碼相同
  2. 字元串無需加引號,加引號不影響

靜態資源的訪問

基本介紹

  1. 只要靜態資源放在 類路徑下 :“classpath:/META-INF/resources/","classpath:/resources/", "classpath:/static/", "classpath:/public/”

  2. 訪問方式:預設 項目根路徑/靜態資源名

註意事項

  1. 靜態資源訪問原理:靜態映射的 /**,也就是攔截所有請求。當請求進來,先判斷Controller能否處理,不能處理的請求交給靜態資源處理器,如果靜態資源找不到,響應404頁面

  2. 修改靜態資源訪問首碼【當與Controller路徑衝突時】

    在application.yml配置‘

    spring:
      mvc:
        static-path-pattern: /zyres/** #靜態資源首碼
    
  3. 修改靜態資源訪問路徑

    在application.yml配置‘

      web:
        resources:
          static-locations: [classpath:/img/]  #添加預設靜態資源路徑
    

    原先的預設路徑會被覆蓋,需要再配

Rest風格請求

  1. Rest風格請求的核心Filter:HiddenHttpMethodFilter,表單請求會被HiddenHttpMethodFilter 攔截,獲取表單的 _method值,再判斷是PUT/PELETE/PATCH

  2. 如果需要Springboot支持 頁面表單的rest風格請求功能,需要在application.yml 啟用filter功能,否則無效

    spring:
      mvc:
        hiddenmethod:
          filter:
            enabled: true #頁面表單支持rest風格
    

視圖解析器的配置

spring:
  mvc:
    view:
      suffix: .html
      prefix: /zyres/ #視圖解析器  <-這裡如果修改了static-path-pattern 需要保持一致
  • 如果配置了視圖解析器,而controller的路徑和視圖路徑一致時,會走視圖解析器

接收參數註解

@PathVaiable

請求 :

<a href="/monster/100/king"></a>
  @RequestMapping("/monster/{id}/{name}")
    @ResponseBody
    public String pathVariable(@PathVariable("id") Integer id,
                               @PathVariable("name") String name,
                               @PathVariable Map<String, String> map) {
        System.out.println("id= " + id + ", name= " + name);
        System.out.println("map= " + map);
        return "success";
    }
  1. @RequestMapping("/monster/{id}/{name}") 和 @PathVariable("id")相對應
  2. Integer id形參無所謂
  3. Map<String, String> map) ,map會存放所有 @PathVariable的 k-v

@RequestHeader

 @RequestMapping("/requestHeader")
    @ResponseBody
    public String requestHeader(@RequestHeader("Host") String host,
                                @RequestHeader Map<String, String> header) {
        System.out.println("host= " + host);
        System.out.println("header= " + header);
        return "success";
    }
  1. @RequestHeader("Host")大小寫無所謂
  2. @RequestHeader Map<String, String> header),map獲取 @RequestHeader的 所有請求頭

@RequestParam

請求:

<a href="/hi?name=zy&fruit=apple&fruit=pear"></a>
@GetMapping("/hi")
    @ResponseBody
    public String hi(@RequestParam("name") String userName,
                     @RequestParam("fruit") List<String> fruits,//一個參數名對應多個值時 用List接收
                     @RequestParam Map<String, String> params) {
        System.out.println("userName= " + userName);
        System.out.println("fruits= " + fruits);
        System.out.println("params= " + params);
        return "success";
    }
  1. ​ @RequestParam("fruit") List fruits,//一個參數名對應多個值時 用List接收
  2. <a href="/hi?name=zy 中的name 要和 @RequestParam("name") 註解中對應
  3. String userName形參無所謂’
  4. @RequestParam Map<String, String> params ,map獲取所有請求參數
  5. 但是k-v中k是唯一,所以獲取相同參數只有一個值會被放入 map

@CookieValue

@GetMapping("/cookie")
    @ResponseBody
    public String cookie(@CookieValue(value = "cookie_key",required = false) String cookie_value,
                         @CookieValue(value = "username",required = false) Cookie cookie) {
        System.out.println("cookie_value= "+cookie_value);
        System.out.println("username= "+cookie.getName()+"-"+cookie.getValue());
        return "success";
    }
  1. 當形參為 String 類型,會取出cookie對應的value
  2. 當形參為 Cookie 類型,會取出封裝好的cookie

@RequestBody

@PostMapping("/save")
@ResponseBody
public String save(@RequestBody String content) {
    System.out.println("content= "+content);
    return "success";
}
  1. 可以接收客戶端 json格式數據
  2. 可以獲取post請求體

@RequestAttribute

   @PostMapping("/login")
    @ResponseBody
    public String login(@RequestAttribute String content) {
        System.out.println("content= "+content);
        return "success";
    }
  1. 用來獲取Request域中的屬性

@SessionAttribute

  • 用來獲取Session域中的屬性

  • 用法和@RequestAttribute一致

複雜參數

  1. Springboot在響應客戶端請求時,也支持複雜參數。例如:map,model等
  2. map,model數據會放在request域
  3. RedirectAttribute 重定向攜帶數據
  //響應註冊請求
    @GetMapping("/register")
    public String register(Map<String, Object> map,
                           Model mondel,
                           HttpServletResponse response) {
        //將數據封裝到map或model
        map.put("user", "zy");
        map.put("job", "java後端開發");
        mondel.addAttribute("sal", "8000");

        //請求轉發
        return "forward:/registerOk";
    }

自定義對象參數-自動封裝

  1. springboot在響應客戶端請求時,也支持自定義對象參數
  2. 完成自動類型轉換與格式化
  3. 支持級聯封裝

轉換器

  1. Springboot在響應客戶端請求時,將提供的數據封裝成對象時,使用了內置的轉換器
  2. springboot也支持自定義轉換器,springboot提供了124內置轉換器

自定義轉換器

自定義轉換器--- 方式一

@Configuration(proxyBeanMethods = false)//Lite模式
public class WebConfig {

    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addFormatters(FormatterRegistry registry) {
//                在addFormatters 中 添加自定義轉換器String->Car
//                添加的自定義轉換器 會註冊到 converters 容器中
//                converters 底層是 ConcurrentHashMap 內置124個轉換器
                registry.addConverter(new Converter<String, Car>() {
                    @Override
                    public Car convert(String s) {//s 就是傳入的需要轉換的數據
                        //加入自定義的轉換的業務代碼
                        if (!ObjectUtils.isEmpty(s)){
                            String[] split = s.split(",");
                            Car car = new Car();
                            car.setName(split[0]);
                            car.setPrice(Double.parseDouble(split[1]));
                            return car;
                        }
                        return null;
                    }
                });
              }
        };
    }
}

自定義轉換器--- 方式二

@Configuration(proxyBeanMethods = false)//Lite模式
public class WebConfig {

    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addFormatters(FormatterRegistry registry) {

                //方式二
                //1.先創建自定義的轉換器
                Converter<String, Car> zyConverter = new Converter<String, Car>() {
                    @Override
                    public Car convert(String s) {//s 就是傳入的需要轉換的數據
                        //加入自定義的轉換的業務代碼
                        if (!ObjectUtils.isEmpty(s)) {
                            String[] split = s.split(",");
                            Car car = new Car();
                            car.setName(split[0]);
                            car.setPrice(Double.parseDouble(split[1]));
                            return car;
                        }
                        return null;
                    }
                };

                registry.addConverter(zyConverter);//添加
                //這裡可以添加多個自定義轉換器,但如果泛型一樣,後面的轉換器會覆蓋
                //原因: 因為容器底層時CurrentHashMap,key是唯一,二key時泛型組合成的
            }
        };
    }
}

Thymeleaf

Thymeleaf是什麼?

  1. Thymeleaf 是一個跟Velocity,FreeMarker類似的模板引擎,可完全替代
  2. Thymeleaf是一個java類庫,它是一個xml/xhtml/html5的模板引擎,可以作為mvc的web應用的view層

Thymeleaf的優點

  1. 實現JSTL,OGNL表達式的效果,語法相似
  2. Thymeleaf 模板頁面無需伺服器渲染,也可以被瀏覽器運行,頁面簡潔
  3. Springboot支持FreeMarker,Thymeleaf,Velocity

Thymeleaf的缺點

  1. 並不是一個高性能引擎,適用於單體應用
  2. 高併發應用依然選擇前後端分離更好

Thymeleaf機制

  1. Thymeleaf是伺服器渲染技術,頁面數據是在服務端進行渲染的
  2. 當用戶請求頁面,Thymeleaf模板引擎完成處理【服務端】,將頁面返回
  3. Thymeleaf並非前後端分離,是在伺服器端完成渲染

Thymeleaf語法

表達式

${...} 變數表達式,獲取請求域,session域,對象等值

@{...} 鏈接表達式,生成鏈接

#{...} 消息表達式,獲取國際化等值

~{...} 代碼塊表達式,類似jsp中include作用,映入公共片段

*{...} 選擇變數表達式,獲取上下文對象值

字面量
  1. 文本值:'zy','hello',...;數字:10,15.3,...;布爾值:true,false
  2. 空值: null
  3. 變數:name,age...
文本操作

字元串拼接 +

變數替換 |age=${age}|

運算符
  1. 數學運算 +,-,*,/,%

  2. 布爾運算 and,or

    一元運算 !,not

  3. 比較運算

    比較 ><,>=,<=(gt,lt,ge,le)

    等式 ==,!=(eq,ne)

條件運算
  1. if-then:(if)?(then)
  2. if-then-else:(if)?(then):(else)
  3. Default : (value)?:(defaul value)

th屬性

1)th:text:文本替換;

2)th:utext:支持html的文本替換。

3)th:value:屬性賦值

4)th:each:遍歷迴圈元素

5)th:if:判斷條件,類似的還有th:unless,th:switch,th:case

6)th:insert:代碼塊引入,類似的還有th:replace,th:include,常用於公共代碼塊提取的場景

7)th:fragment:定義代碼塊,方便被th:insert引用

8)th:object:聲明變數,一般和*{}一起配合使用,達到偷懶的效果。

9)th:attr:設置標簽屬性,多個屬性可以用逗號分隔

攔截器Interceptor

  • springboot項目,攔截器是開發中常用的手段,登陸驗證,性能檢查,日誌記錄等

基本介紹

  1. 編寫一個攔截器實現HandleInterceptor介面
  2. 攔截器註冊到配置類【實現WebMvcConfiguration 的 addInterceptors】
  3. 也可以直接實現WebMvcConfigurer介面
  4. 指定攔截規則
@Configuration
public class WebConfig implements WebMvcConfigurer{

    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(new LoginInterceptor())
                        .addPathPatterns("/**")//攔截所有
                        .excludePathPatterns("/","/login","/images/**","/upload.html","/register"
                        ,"/css/**");//指定放行
            }
        };
    }

}

註意事項

  1. URI和URL的區別:URI唯一標識一個資源【網站內部】;URL可以提供找到該資源的路徑【帶主機和埠】
  2. URI = /manage.html
  3. URL = http://localhost:8080/manage.html

異常處理

基本介紹

  1. 預設情況下,springboot提供 /error 處理所有錯誤的映射
  2. 當出現錯誤時,springboot底層會請求轉發到 /error映射
  3. 比如當瀏覽器訪問不存在的路徑,響應一個"whitelable"錯誤視圖,以HTML格式呈現給用戶
  4. springboot底層預設由DefaultErrorViewResolver

攔截器和過濾器的區別

攔截器和過濾器使用範圍不同

  1. 過濾器實現的是javax.servlet.Filter介面,而這個介面實在Servlet規範中定義的,也就是說過濾器Filter的使用要依賴與Tomcat等容器,Filter只能在Web程式使用
  2. 攔截器是一個Spring組件,並由Spring容器管理,並不依賴Tomcat容器,是可以單獨使用的,不僅能應用在web工程,還能用於Application等程式

攔截器和過濾器觸發時機不同

  1. 過濾器Filter是在請求進入容器後,但在進入Servlet之前進行預處理,請求結果實在Servlet處理完以後。

  2. 攔截器實在請求進入Servlet後,進入Controller之前進行預處理,Controller渲染了對應的視圖後結束

  3. 請求

    Tomcat

    Filter

    Servlet

    Interceptor

    Controller

  4. 過濾器不會處理 請求轉發,攔截器會處理請求轉發

自定義異常頁面

  1. 如果是用模板引擎,需要將自定義異常的頁面放在 /templates/error/路徑
  2. 如果沒有使用模板引擎,就放在靜態資源路徑下【四個預設】,"/resource/static/errpr/路徑"
  3. “classpath:/META-INF/resources/error/路徑","classpath:/resources/error/路徑", "classpath:/static/error/路徑", "classpath:/public/error/路徑”
  4. 先會根據狀態碼精確查找 (例如 404.html),若找不到,會去找 4xx.html
  5. 如果都沒有,會new 一個預設頁面返回
  6. 前端可以使用 th:text="${status}"取出狀態碼

全局異常

基本介紹

  1. @ControllerAdvice + @ExceptionHandler 處理全局異常
  2. 底層是ExceptionHandlerExceptionResolver支持的
  3. 作用:當發生異常時,不使用預設異常機制匹配xxx.html,而是通過全局異常機制,顯示指定的錯誤頁面
  4. 對比:自定義異常是根據狀態碼來決定 返回的html頁面;全局異常是根據Java異常類型來決定 返回的html頁面

如何獲取到異常發生的地方?

用HandlerMethod在形參上獲取

具體實現

@ControllerAdvice //標識全局異常處理器/對象 ,GlobalExceptionHandler 會被註入到spring容器
@Slf4j
public class GlobalExceptionHandler {

    //編寫方法處理指定的異常
    //Exception e 表示異常發生後,傳遞的異常對象
    //Model model 可以存放錯誤信息到model,再放入到request域,帶到目標頁面顯示
    //  Class<? extends Throwable>[] value() default {};
    @ExceptionHandler({ArithmeticException.class, NullPointerException.class,AccessException.class})
    public String handleAritException(Exception e, Model model){
        log.info("異常信息={}",e.getMessage());
        model.addAttribute("msg",e);
        return "/error/global";
    }
}
  1. Exception e 表示異常發生後,傳遞的異常對象
  2. Model model 可以存放錯誤信息到model,再放入到request域,帶到目標頁面顯示
  3. @ControllerAdvice //標識全局異常處理器/對象 ,GlobalExceptionHandler 會被註入到spring容器
  4. @ExceptionHandler({ArithmeticException.class, NullPointerException.class,AccessException.class})指定捕獲哪些異常

自定義異常

基本介紹

  1. springboot提供的異常不滿足需求,程式員可以自定義異常
  2. @ResponseStatus + 自定義異常
  3. 底層是 ResponseStatusExceptionResolver ,底層調用response.sendError
  4. 當拋出自定義異常後,仍然會根據狀態碼去匹配xxx.html顯示
  5. 可以將自定義異常放在全局異常處理器處理,但仍然走全局異常

具體實現

//自定義異常,需要繼承Exception (編譯異常)/RuntionException(運行異常)
// 一般繼承RuntionException(運行異常)
@ResponseStatus(value = HttpStatus.BAD_GATEWAY)
public class AccessException extends RuntimeException{
    //提供構造器,可以指定信息
    public AccessException(String message){
        super(message);
    }

    public AccessException(){

    }
}

Springboot文件上傳

前端 enctype="multipart/form-data"

<form action="#" th:action="@{/register}" method="post" enctype="multipart/form-data">
  用戶名:<input type="text" style="width: 150px" name="name"/><br/><br/>
  電郵:<input type="text" style="width: 150px" name="email"/><br/><br/>
  年齡:<input type="text" style="width: 150px" name="age"/><br/><br/>
  職位:<input type="text" style="width: 150px" name="job"/><br/><br/>
  頭像:<input type="file" style="width: 150px" name="header"/><br/><br/>
  寵物:<input type="file" style="width: 150px" name="photos" multiple/><br/><br/>
  <input type="submit" value="註冊"/>
  <input type="reset" value="重新填寫"/>
</form>

類型一 將上傳的文件保存到指定目錄

@Controller
@Slf4j
public class UploadController {

    //處理請求轉發-用戶註冊 可以完成文件上傳
    @GetMapping("/upload.html")
    public String upload() {
        return "upload";
    }

    //處理用戶註冊
    @PostMapping("/register")
    @ResponseBody
    public String register(@RequestParam("name") String name,
                           @RequestParam("email") String email,
                           @RequestParam("age") Integer age,
                           @RequestParam("job") String job,
                           @RequestParam("header") MultipartFile header,
                           @RequestParam("photos") MultipartFile[] photos) throws IOException {

        //1.將上傳的文件保存到指定目錄
        if (!header.isEmpty()) {
            String originalFilename = header.getOriginalFilename();
            File file = new File("d:\\temp_upload\\" + originalFilename);
            header.transferTo(file);
        }

        //處理圖片
        if (photos.length > 0) {
            for (MultipartFile photo : photos) {
                if (!photo.isEmpty()) {
                    String originalFilename = photo.getOriginalFilename();
                    File file = new File("d:\\temp_upload\\" + originalFilename);
                    photo.transferTo(file);
                }
            }
        }
                return "註冊用戶成功/文件上傳成功";
    }
}

類型二 將上傳的文件保存到指定目錄

@Controller
@Slf4j
public class UploadController {

    //處理請求轉發-用戶註冊 可以完成文件上傳
    @GetMapping("/upload.html")
    public String upload() {
        return "upload";
    }

    //處理用戶註冊
    @PostMapping("/register")
    @ResponseBody
    public String register(@RequestParam("name") String name,
                           @RequestParam("email") String email,
                           @RequestParam("age") Integer age,
                           @RequestParam("job") String job,
                           @RequestParam("header") MultipartFile header,
                           @RequestParam("photos") MultipartFile[] photos) throws IOException {



        //2.動態創建目錄並保存
        // D:\zy_springboot\springboot-thymeleaf-usersys\target\classes\static\images\xupload\\

        //獲取當前年月日【解決分目錄】
        LocalDate now = LocalDate.now();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        String format = now.format(dtf);
        System.out.println("format= "+format);


        String path = ResourceUtils.getURL("classpath:").getPath();
        path = path + "static/images/upload/"+format+"/";
        File file = new File(path);
        if (!file.exists()) {
            //目錄不存在 就創建
            file.mkdirs();
        }

        //【解決文件覆蓋問題】
        String prefix = UUID.randomUUID().toString();
        prefix = prefix +"_"+ System.currentTimeMillis()+"_";


        if (!header.isEmpty()) {
            String originalFilename = header.getOriginalFilename();
            header.transferTo( new File(file.getAbsolutePath()+"/"+prefix+originalFilename));
        }

        //處理圖片
        if (photos.length > 0) {
            for (MultipartFile photo : photos) {
                if (!photo.isEmpty()) {
                    String originalFilename = photo.getOriginalFilename();
                    photo.transferTo( new File(file.getAbsolutePath()+"/"+prefix+originalFilename));
                }
            }
        }
        return "註冊用戶成功/文件上傳成功";
    }
}

Servlet/Filter/Listener在springboot如何註入

基本介紹

  1. 考慮到相容,springboot支持將Servlet/Filter/Listener註入spring容器,成為spring 的 bean
  2. 即 springboot開放了和原生web組件的相容
  3. 如果要使用原生web組件的開發,需要在主啟動器添加註解@ServletComponentScan(basePackages = "com.xxx.xx")指定要掃描的包,才會註入容器
  4. Servlet/Filter/Listener在springboot註入有兩種方式,
  5. 方式一是通過@WebServlet,@WebFilter,@WebListener註解註入
  6. 方式二是通過RegistrationBean方式註入

通過@WebServlet,@WebFilter,@WebListener註解註入

註入Servlet 【@WebServlet】

//有@WebServlet標識 表示: 將 Servlet_ 對應的bean 註入到容器
//@WebServlet(urlPatterns = {"/servlet01","/servlet02"})//映射的路徑
public class Servlet_ extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("hello Servlet_~");
    }
}
  1. 註意:註入的原生的Servlet 不會被 SpringBoot攔截器 攔截 ---原因走原生的Servlet處理,而不是springboot的DispatchServlet
  2. 原因:
  3. 當多個Servlet都能處理同一層路徑,精確優先/最長首碼匹配原則,所以當請求/servlet時,會直接匹配註入的servlet

註入Filter【@WebFilter】

@WebFilter(urlPatterns = {"/css/*","/images/*"})
public class Filter_  implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init...");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("hello Filter_~");
        HttpServletRequest request = (HttpServletRequest)servletRequest ;
        System.out.println("URI= "+request.getRequestURI());
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("destroy...");
    }
}
  • 過濾器會被SpringBoot攔截器 攔截

註入Listener 【@WebListener 】

@WebListener
public class Listener_ implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        system.out.println("項目初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        ServletContextListener.super.contextDestroyed(sce);
    }
}

通過RegistrationBean方式註入

RegistrationBean方式-註入Servlet

//    //註入Servlet
    @Bean
    public ServletRegistrationBean servlet_(){
        Servlet_ servlet = new Servlet_();//創建原生的Servlet對象

        //把servlet 和 ServletRegistrationBean 關聯
        //"servlet01","servlet02" 是url-pattern
        return new ServletRegistrationBean(servlet,"/servlet01","/servlet02");
    }

RegistrationBean方式-註入Filter

//註入Filter
@Bean
public FilterRegistrationBean filter_(){
    Filter_ filter = new Filter_();//創建原生的filter對象

    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(filter);

    filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*","/images/*"));
    return filterRegistrationBean;
}

RegistrationBean方式-註入Listener

//註入Listener
    @Bean
    public ServletListenerRegistrationBean listener_(){
        Listener_ listener = new Listener_();//創建原生的listener對象

        ServletListenerRegistrationBean servletListenerRegistrationBean =
                new ServletListenerRegistrationBean(listener);

        return servletListenerRegistrationBean;
    }

內置的WebServlet【伺服器】切換

基本介紹

  1. Springboot支持的WebServlet:Tomcat,Jetty,Undertom
  2. Springboot啟動,web場景啟動器自動導入tomcat
  3. 支持切換WebServlet

如何配置內置的tomcat

  1. 可以通過application.yml完成配置【配置信息和ServletProperties.java關聯】

  2. 通過配置類進行配置

  3. @Component
    public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
    
    
        @Override
        public void customize(ConfigurableServletWebServerFactory factory) {
            factory.setPort(8080);//配置埠
        }
    }
    

切換WebServlet

  1. 修改pom.xml文件,刪除tomcat依賴,引入undertow

  2. <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!--排除tomcat starter-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    
  3. 引入undertow

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

資料庫操作

  • springboot預設使用JDBC+HikariDataSource

如何使用預設JDBC+HikariDataSource進行資料庫操作

  1. 引入data-jdbc starter

  2. <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jdbc</artifactId>
    </dependency>
    
  3. springboot並不知道具體要操作哪一種資料庫,需要在pom.xml中指定導入資料庫驅動,並指定對應版本

  4. <!--    引入mysql驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
    
  5. 在application.yml中配置數據源

  6. spring:
      datasource:
        url: jdbc:mysql://localhost:3306/furn_ssm2?useSSL=true&useUnicode=true&characterEncoding=UTF-8
        username: root
        password: zy
        driver-class-name: com.mysql.jdbc.Driver
    
  7. 完成測試

  8. @SpringBootTest//需要引入 spring-boot-starter-test 依賴
    public class ApplicationTests {
    
        @Resource
        private JdbcTemplate jdbcTemplate;
    
        @Test
        public void contextLoads(){
    
            BeanPropertyRowMapper<Furn> rowMapper =
                    new BeanPropertyRowMapper<>(Furn.class);
    
            List<Furn> furns =
                    jdbcTemplate.query("SELECT * FROM `furn`", rowMapper);
    
            for (Furn furn : furns) {
                System.out.println("furn= "+furn);
            }
    
            System.out.println(jdbcTemplate.getDataSource().getClass());
    
        }
    
    }
    

整合Druid 和 springboot

基本介紹

  1. Druid是Java語言中最好的資料庫連接池。Druid能夠提供強大的監控和擴展功能。

  2. Druid提供了一個高效、功能強大、可擴展性好的資料庫連接池。

  3. 可以監控資料庫訪問性能,Druid內置提供了一個功能強大的StatFilter插件,能夠詳細統計SQL的執行性能,這對於線上分析資料庫訪問性能有幫助。

  4. 資料庫密碼加密。DruidDruiver和DruidDataSource都支持PasswordCallback。

  5. SQL執行日誌,,監控你應用的資料庫訪問情況。

整合Druid 和 springboot【2種方式】

方式一 自定義方式整合

  1. 引入druid依賴

  2. <!--引入druid依賴-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.17</version>
    </dependency>
    
  3. 在配置類註入DataSource

  4. @Configuration
    public class DruidDataSourceConfig {
        //編寫方法註入 DruidDataSource
        @ConfigurationProperties(prefix = "spring.datasource")//就可以和 application.yml相關聯【DataSource】
        @Bean
        public DataSource dataSource() throws SQLException {
    
            DruidDataSource druidDataSource =
                    new DruidDataSource();
    
            //加入監控功能
            druidDataSource.setFilters("stat,wall");
            return druidDataSource;
        }
    
    
        //配置druid的監控功能
        @Bean
        public ServletRegistrationBean statViewServlet() {
            StatViewServlet statViewServlet = new StatViewServlet();
            ServletRegistrationBean<StatViewServlet> registrationBean =
                    new ServletRegistrationBean<>(statViewServlet, "/druid/*");
    
            //設置init-parameter  [設置用戶名和密碼]
            registrationBean.addInitParameter("loginUsername", "zy");
            registrationBean.addInitParameter("loginPassword", "666666");
    
    
            return registrationBean;
        }
    
        //配置 WebStatFilter 用於Web的監控功能
        @Bean
        public FilterRegistrationBean webStatFilter() {
            WebStatFilter webStatFilter = new WebStatFilter();
            FilterRegistrationBean<WebStatFilter> registrationBean =
                    new FilterRegistrationBean<>(webStatFilter);
            //預設對所有請求進行監控
            registrationBean.setUrlPatterns(Arrays.asList("/*"));
            //排除指定的url
            registrationBean.addInitParameter("exclusions",
                    "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
    
            return registrationBean;
        }
    
    }
    

方式二 引入druid starter方式整合

  1. 引入druid starter

  2. <!--    引入druid starter-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.17</version>
        </dependency>
    
  3. 在application.yml中配置druid和監控功能

  4. #配置druid 和 監控功能
    druid:
      stat-view-servlet:
        enabled: true
        login-username: jack
        login-password: 666
        reset-enable: false
    
      #開啟web監控
      web-stat-filter:
        enabled: true
        url-pattern: /*
        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
    
      #開啟sql監控
      filter:
        stat:
          slow-sql-millis: 1000 #慢查詢
          log-slow-sql: true
          enabled: true
    
        #開啟防火牆監控
        wall:
          enabled: true
          config:
            drop-table-allow: false
            select-all-column-allow: false
    

為什麼註入自己的DataSource,預設的HikariDataSource會失效?

​ 原因: 因為預設的數據源是根據@ConditionalOnMissingBean判斷,如果自己沒有配,預設使用HikariDataSource;如果配置了,就用配置了的DataSource。

Springboot整合MyBatis

  1. 需要在application.yml種指定mapper.xml掃描的路徑

  2. mybatis:
    #  指定要掃描的 Xxxmapper.xml
      mapper-locations: classpath:mapper/*.xml
    
  3. 在Mapper介面上可以通過添加@Mapper註解,註入容器

  4. @Mapper //@Mapper就會掃描 並 將介面對象註入容器
    public interface MonsterMapper {
        //根據id 返回monster
        Monster getMonsterById(Integer id);
    
    }
    
  5. 在application.yml中,可以通過 config-location 可以指定 mybatis-config.xml,來進行傳統mybatis方式的配置

  6. mybatis:
      config-location: classpath:mybatis-config.xml
    
  7. 也可以直接在application.yml中配置mybatis【推薦】

  8. mybatis:
    # 配置類型別名
      type-aliases-package: com.zy88.springboot.bean
      configuration:
      # 配置日誌
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
  9. 如果配置內容少,建議直接在application.yml中配置mybatis,如果內容很多,才考慮單獨做一個 mybatis-config.xml

Springboot整合MyBatis-Plus

基本介紹

  1. MyBatis-Plus(簡稱 MP)是一個 MyBatis 的增強工具,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。
  2. 內置通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求

Springboot整合MyBatis-Plus

  1. 需要引入MyBatis-Plus starter【在meven倉庫中】

  2. <!--    引入Mybatis-Plus starter-->
    <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.3</version>
    </dependency>
    
  3. 在application.yml配置數據源

  4. server:
      port: 9090
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/hsp_mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
        username: root
        password: zy
    
  5. 在配置類註入DruidDataSource

  6. @Configuration
    public class DruidDataSourceConfig {
        //編寫方法註入 DruidDataSource
        @ConfigurationProperties(prefix = "spring.datasource")
        @Bean
        public DataSource dataSource()  {
    
            DruidDataSource druidDataSource =
                    new DruidDataSource();
    
            return druidDataSource;
        }
    
    
    
    }
    

整合mapper【MyBatis-Plus與MyBatis的不同】

  • mapper介面需要繼承BeseMapper<>
@Mapper
public interface MonsterMapper extends BaseMapper<Monster> {
    //自定義方法

int insertSelective(Monster monster);

}
  1. BaseMapper 已經預設提供了很多crud方法,可以直接使用
  2. 如果 BaseMapper 提供的方法不能滿足業務需求,我們可以開發新的方法 ,併在MonsterMapper.xml配置

整合service【MyBatis-Plus與MyBatis的不同】

  • service需要繼承父介面 ISercice<>
public interface MonsterService extends IService<Monster> {
    //自定義方法
}
  1. IService介面聲明瞭很多方法,crud
  2. 如果不能滿足需求,可以再聲明需要的方法,然後在實現類實現即可
  • 註意:MyBatis-Plus開發實現類 需要繼承 ServletImpl
@Service
public class MonsterServiceImpl
        extends ServiceImpl<MonsterMapper, Monster>
        implements MonsterService{
}

指定掃描某個包下的所有mapper介面

在主啟動器上添加@MapperScan(basePackages = {"com.xxx.xxx.xx"})

@MapperScan(basePackages = {"com.zy88.springboot.mybatisplus.mapper"})
@SpringBootApplication
public class Application {
    public static void main(String[] args){
        SpringApplication.run(Application.class,args);
    }
}

@TableName作用

  1. 預設情況:如果類名首字母小寫和表名不一致,可以映射
  2. 當類名首字母小寫和表名不一致時,通過@TableName,在實體類上加@TableName("表名")進行映射
@TableName("monster_")
public class Monster {
    private Integer id;
    private Integer age;
    private String name;
    private String email;
    //解決時區問題
    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")//GMT 是格林尼治標準時間 ,如果需要時分秒加上 HH:mm:ss
    private Date birthday;
    private double salary;
    private Integer gender;
}
  • 為了開發方便可以添加MyBatisX插件

本文學習內容來自韓順平老師的課程

僅供個人參考學習


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 貪吃蛇作為一款極其經典且廣受歡迎的小游戲,是早期 Windows 電腦和功能手機(特別是諾基亞手機)流行度極高的小游戲,是當時功能手機時代最具代表性的游戲之一。游戲的基本規則和目標十分簡單,但卻極具吸引力,讓人欲罷不能。本博文我們用 Python 編寫屬於自己的貪吃蛇游戲,一起來體驗一下編程的樂趣與... ...
  • 當開發與Linux環境下MySQL資料庫交互的Java應用程式時,理解MySQL中的大小寫敏感性可以避免潛在的錯誤和問題。本指南深入探討了MySQL中的大小寫敏感設置,比較了5.7和8.0版本,併為Java開發者提供了最佳實踐。 1 理解MySQL中的大小寫敏感性 預設情況下,MySQL在Windo ...
  • 1. Spring6 對 集成MyBatis 開發運用(附有詳細的操作步驟) @目錄1. Spring6 對 集成MyBatis 開發運用(附有詳細的操作步驟)每博一文案2. 大概的實現步驟概述3. 詳細實現操作步驟4. Spring配置文件的 import,導入外部xml 配置5. 總結:6. 最 ...
  • 1 為啥要折騰搭建一個專屬圖床? 技術大佬寫博客都用 md 格式,要在多平臺發佈,圖片就得有外鏈 後續如博客遷移,國內博客網站如掘金,簡書,語雀等都做了防盜鏈,圖片無法遷移 2 為啥選擇CloudFlare R2 跳轉:https://dash.cloudflare.com/ 有白嫖額度 免費 CD ...
  • 實時識別關鍵詞是一種能夠將搜索結果提升至新的高度的API介面。它可以幫助我們更有效地分析文本,並提取出關鍵詞,以便進行進一步的處理和分析。 該介面是挖數據平臺提供的,有三種模式:精確模式、全模式和搜索引擎模式。不同的模式在分詞的方式上有所不同,適用於不同的場景。 首先是精確模式。這種模式會儘量將句子 ...
  • Java JUC&多線程 基礎完整版 目錄Java JUC&多線程 基礎完整版1、 多線程的第一種啟動方式之繼承Thread類2、多線程的第二種啟動方式之實現Runnable介面3、多線程的第三種實現方式之實現Callable介面4、多線的常用成員方法5、線程的優先順序6、守護線程7、線程的讓出8、線 ...
  • 本文介紹基於Python語言,遍歷文件夾並從中找到文件名稱符合我們需求的多個.txt格式文本文件,並從上述每一個文本文件中,找到我們需要的指定數據,最後得到所有文本文件中我們需要的數據的合集的方法~ ...
  • 作為後端工程師,多數情況都是給別人提供介面,寫的好不好使你得重視起來。 最近我手頭一些活,需要和外部公司對接,我們需要提供一個介面文檔,這樣可以節省雙方時間、也可以防止後續扯皮。這是就要考驗我的介面是否規範化。 1. 介面名稱清晰、明確 顧名思義,介面是做什麼的,是否準確、清晰?讓使用這一眼就能知道 ...
一周排行
    -Advertisement-
    Play Games
  • 下麵是一個標準的IDistributedCache用例: public class SomeService(IDistributedCache cache) { public async Task<SomeInformation> GetSomeInformationAsync (string na ...
  • 這個庫提供了在啟動期間實例化已註冊的單例,而不是在首次使用它時實例化。 單例通常在首次使用時創建,這可能會導致響應傳入請求的延遲高於平時。在註冊時創建實例有助於防止第一次Request請求的SLA 以往我們要在註冊的時候實例單例可能會這樣寫: //註冊: services.AddSingleton< ...
  • 最近公司的很多項目都要改單點登錄了,不過大部分都還沒敲定,目前立刻要做的就只有一個比較老的項目 先改一個試試手,主要目標就是最短最快實現功能 首先因為要保留原登錄方式,所以頁面上的改動就是在原來登錄頁面下加一個SSO登錄入口 用超鏈接寫的入口,頁面改造後如下圖: 其中超鏈接的 href="Staff ...
  • Like運算符很好用,特別是它所提供的其中*、?這兩種通配符,在Windows文件系統和各類項目中運用非常廣泛。 但Like運算符僅在VB中支持,在C#中,如何實現呢? 以下是關於LikeString的四種實現方式,其中第四種為Regex正則表達式實現,且在.NET Standard 2.0及以上平... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式記憶體會偶發性暴漲,自己分析了下是非托管記憶體問題,讓我幫忙看下怎麼回事?哈哈,看到這個dump我還是非常有興趣的,居然還有這種游戲幣自助機類型的程式,下次去大玩家看看他們出幣的機器後端是不是C#寫的?由於dump是linux上的程式,剛好win ...
  • 前言 大家好,我是老馬。很高興遇到你。 我們為 java 開發者實現了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何處理的,可以參考我的另一個項目: 手寫從零實現簡易版 tomcat minicat 手寫 ngin ...
  • 上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。 Filter為二方包異常手動捕獲 參考:ht ...
  • 大家好,我是R哥。 今天分享一個爽飛了的面試輔導 case: 這個杭州兄弟空窗期 1 個月+,面試了 6 家公司 0 Offer,不知道問題出在哪,難道是杭州的 IT 崩盤了麽? 報名面試輔導後,經過一個多月的輔導打磨,現在成功入職某上市公司,漲薪 30%+,955 工作制,不咋加班,還不捲。 其他 ...
  • 引入依賴 <!--Freemarker wls--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> ...
  • 你應如何運行程式 互動式命令模式 開始一個互動式會話 一般是在操作系統命令行下輸入python,且不帶任何參數 系統路徑 如果沒有設置系統的PATH環境變數來包括Python的安裝路徑,可能需要機器上Python可執行文件的完整路徑來代替python 運行的位置:代碼位置 不要輸入的內容:提示符和註 ...