【Spring】Spring統一功能處理

Spring統一功能處理

  • 攔截器
    • 攔截器
      • 什么是攔截器
      • 攔截器的基本使用
        • 定義攔截器
        • 注冊配置攔截器
      • 攔截器詳解
        • 攔截器的攔截路徑配置
        • 攔截器實現原理
          • 初始化
          • 處理請求
      • 適配器模式
  • 統一數據返回格式
    • 統一數據返回格式快速入門
  • 統一異常處理

攔截器

場景: 我們要對一個網站實現強制登陸的功能,后端根據Session來判斷用戶是否登錄,但是如果我們要這樣實現,就需要對每一個接口都增加這樣的邏輯處理 此時就比較麻煩

? 需要修改每個接?的處理邏輯
? 需要修改每個接?的返回結果
? 接?定義修改, 前端代碼也需要跟著修改

有沒有更簡單的辦法, 統?攔截所有的請求, 并進?Session校驗呢, 這?我們學習?種新的解決辦法: 攔截器

攔截器

什么是攔截器

攔截器是Spring框架提供的核?功能之?, 主要?來攔截??的請求, 在指定?法前后, 根據業務需要執?預先設定的代碼

也就是說, 允許開發?員提前預定義?些邏輯, 在??的請求響應前后執?. 也可以在??請求前阻?
其執?.
在攔截器當中,開發?員可以在應?程序中做?些通?性的操作, ?如通過攔截器來攔截前端發來的
請求, 判斷Session中是否有登錄??的信息. 如果有就可以放?, 如果沒有就進?攔截.

攔截器的基本使用

定義攔截器

實現HandleInterceptor接口 重寫方法

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("LoginInterceptor 目標方法執行前");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("LoginInterceptor 目標方法執行后");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("LoginInterceptor 視圖執行后");}
}

preHandle方法:目標方法執行前執行,返回true 繼續執行后續操作,返回false 中斷后續操作
postHandle方法:目標方法執行后執行
afterCompletion()?法:視圖渲染完畢后執?,最后執?

注冊配置攔截器

實現WebMvcConfigurer接口 重寫addInterceptors方法

@Configuration
public class WebConfig implements WebMvcConfigurer {//?定義的攔截器對象@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注冊?定義攔截器對象registry.addInterceptor(loginInterceptor).addPathPatterns("/**");//設置攔截器攔截的請求路徑}
}

攔截器詳解

攔截器的攔截路徑配置

攔截路徑是指我們定義的這個攔截器, 對哪些請求?效.我們在注冊配置攔截器的時候, 通過 addPathPatterns()?法指定要攔截哪些請求. 也可以通過excludePathPatterns() 指定不攔截哪些請求

@Configuration
public class WebConfig implements WebMvcConfigurer {//自定義攔截器對象@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//設置攔截器的請求路徑// /**表示攔截所有registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login").excludePathPatterns("/**/*.js").excludePathPatterns("/**/*.css").excludePathPatterns("/**/*.png").excludePathPatterns("/**/*.html");//addPath設置攔截那些請求//excludePath設置不攔截哪些請求}
}

在攔截器中除了可以設置 /** 攔截所有資源外,還有?些常?攔截路徑設置:

攔截路徑含義舉例
/*一級路徑能匹配/user,/book,/login,不能匹配 /user/login
/**任意級路徑能匹配/user,/user/login,/user/reg
/book/*/book下的?級路徑能匹配/book/addBook,不能匹配/book/addBook/1,/book
/book/**/book下的任意級路徑能匹配/book,/book/addBook,/book/addBook/2,不能匹配/user/login

添加攔截器后, 執?Controller的?法之前, 請求會先被攔截器攔截住. 執? preHandle() ?法,
這個?法需要返回?個布爾類型的值.
如果返回true, 就表?放?本次操作, 繼續訪問controller中的?法.
如果返回false,則不會放?(controller中的?法也不會執?).

controller當中的?法執?完畢后,再回過來執? postHandle() 這個?法以及afterCompletion() ?法,執?完畢之后,最終給瀏覽器響應數據.

攔截器實現原理

當Tomcat啟動之后, 有?個核?的類DispatcherServlet, 它來控制程序的執?順序.

所有請求都會先進到DispatcherServlet,執?doDispatch 調度?法. 如果有攔截器,會先執?攔截器preHandle() ?法的代碼, 如果 preHandle() 返回true, 繼續訪問controller中的?法.controller當中的?法執?完畢后,再回過來執? postHandle() 和 afterCompletion(),返回給DispatcherServlet, 最終給瀏覽器響應數據.
在這里插入圖片描述

初始化

DispatcherServlet的初始化?法 init() 在其?類 HttpServletBean 中實現的.

主要作?是加載 web.xml 中 DispatcherServlet 的 配置, 并調??類的初始化.
在這里插入圖片描述

在 HttpServletBean 的 init() 中調?了 initServletBean() , 它是在FrameworkServlet 類中實現的, 主要作?是建? WebApplicationContext 容器(有時也稱上下?), 并加載 SpringMVC 配置?件中定義的 Bean到該容器中, 最后將該容器添加到 ServletContext 中. 下?是initServletBean() 的具體代碼:

在這里插入圖片描述
初始化web容器的過程中, 會通過onRefresh 來初始化SpringMVC的容器
在這里插入圖片描述
在initStrategies()中進?9?組件的初始化, 如果沒有配置相應的組件,就使?默認定義的組件(在
DispatcherServlet.properties中有配置默認的策略, ?致了解即可

在這里插入圖片描述

?法initMultipartResolver、initLocaleResolver、initThemeResolver、initRequestToViewNameTranslator、initFlashMapManager的處理?式?乎都?樣(1.2.3.7.8,9),從應??中取出指定的Bean, 如果沒有, 就使?默認的.?法initHandlerMappings、initHandlerAdapters、initHandlerExceptionResolvers的處理?式?乎都?樣(4,5,6)

  1. 初始化處理器映射器HandlerMappings:處理器映射器作?,1)通過處理器映射器找到對應的處理器適配器,將請求交給適配器處理;2)緩存每個請求地址URL對應的位置(Controller.xxx?法);如果在ApplicationContext發現有HandlerMappings,則從ApplicationContext中獲取到所有的HandlerMappings,并進?排序;如果在ApplicationContext中沒有發現有處理器映射器,則默認BeanNameUrlHandlerMapping作為處理器映射器
  2. 初始化處理器適配器HandlerAdapter:作?是通過調?具體的?法來處理具體的請求;如果在ApplicationContext發現有handlerAdapter,則從ApplicationContext中獲取到所有的 HandlerAdapter,并進?排序;如果在ApplicationContext中沒有發現處理器適配器,則不設置異常處理器,則默認SimpleControllerHandlerAdapter作為處理器適配器
  3. 初始化異常處理器解析器HandlerExceptionResolver:如果在ApplicationContext發現有handlerExceptionResolver,則從ApplicationContext中獲取到所有的HandlerExceptionResolver,并進?排序;如果在ApplicationContext中沒有發現異常處理器解析器,則不設置異常處理器
處理請求
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);//1.獲取執行鏈//遍歷所有的HandlerMapper 找到與請求對應的HandlermappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}//2. 獲取適配器//遍歷所有的HandlerAdapter 找到可以處理該Handler的HandlerAdapterHandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());String method = request.getMethod();boolean isGet = HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}//3. 執行攔截器的preHandler方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}//4. 執行目標方法mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);//5. 執行攔截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}//6.處理視圖 處理之后執?攔截器afterCompletion?法processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {//7.執?攔截器afterCompletion?法triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}}

此處最關鍵的就是3 4 5 點 這里規定了執行目標方法前執行preHandle 執行目標方法之后執行postHandle方法

適配器模式

適配器模式是一種設計模式,用于將一個類的接口轉換成客戶端所期望的另一個接口。它允許原本不兼容的類能夠合作無間。

適配器模式主要包括兩個核心角色:目標接口(Target)和適配器(Adapter)。目標接口是客戶端所期望的接口,適配器則是將原本不兼容的類轉換成目標接口的中間層。

適配器模式可以通過兩種方式實現:類適配器和對象適配器。在類適配器中,適配器繼承了被適配類,并實現了目標接口。而在對象適配器中,適配器持有一個被適配對象的實例,并實現了目標接口。

使用適配器模式可以有以下幾個好處:

  1. 可以讓原本不兼容的類能夠一起工作,提高代碼的復用性。
  2. 可以封裝已有的類,對外隱藏底層的實現細節。
  3. 可以在不修改現有代碼的情況下引入新的功能。
    總之,適配器模式是一種常用的設計模式,可用于解決不同接口之間不兼容的問題,使得原本無法合作的類能夠協同工作。

在這里插入圖片描述
HandlerAdapter 在 Spring MVC 中使?了適配器模式

HandlerAdapter 主要?于?持不同類型的處理器(如 Controller、HttpRequestHandler 或者Servlet 等),讓它們能夠適配統?的請求處理流程。這樣,Spring MVC 可以通過?個統?的接?來處理來?各種處理器的請求

場景: 前?學習的slf4j 就使?了適配器模式, slf4j提供了?系列打印?志的api, 底層調?的是log4j 或者logback來打?志, 我們作為調?者, 只需要調?slf4j的api就?了

//Slf4j接口
interface Slf4jApi{void log(String message);
}//log4j接口
class Log4j{void log4jLog(String message){System.out.println("Log4j打印:" + message);}
}//slf4j和log4j適配器class Slf4jLog4JAdapter implements Slf4jApi{private Log4j log4j;public Slf4jLog4JAdapter(Log4j log4j) {this.log4j = log4j;}@Overridepublic void log(String message) {log4j.log4jLog(message);}
}
public class Slf4jDemo {public static void main(String[] args) {Slf4jApi slf4jApi = new Slf4jLog4JAdapter(new Log4j());slf4jApi.log("使用slf4j打印日志");}
}

在這里插入圖片描述
適配器模式應?場景
?般來說,適配器模式可以看作?種"補償模式",?來補救設計上的缺陷. 應?這種模式算是"?奈之舉", 如果在設計初期,我們就能協調規避接?不兼容的問題, 就不需要使?適配器模式了

所以適配器模式更多的應?場景主要是對正在運?的代碼進?改造, 并且希望可以復?原有代碼實現新的功能. ?如版本升級等

統一數據返回格式

強制登錄案例中, 我們共做了兩部分?作

  1. 通過Session來判斷??是否登錄
  2. 對后端返回數據進?封裝, 告知前端處理的結果

后端統一返回結果

package com.bite.book.model;import com.bite.book.enums.ResultCode;
import lombok.Data;@Data
public class Result<T> {/*** 業務狀態碼*/private ResultCode code;  //0-成功  -1 失敗  -2 未登錄/*** 錯誤信息*/private String errMsg;/*** 數據*/private T data;public static <T> Result<T> success(T data){Result result = new Result();result.setCode(ResultCode.SUCCESS);result.setErrMsg("");result.setData(data);return result;}public static <T> Result<T> fail(String errMsg){Result result = new Result();result.setCode(ResultCode.FAIL);result.setErrMsg(errMsg);result.setData(null);return result;}public static <T> Result<T> fail(String errMsg,Object data){Result result = new Result();result.setCode(ResultCode.FAIL);result.setErrMsg(errMsg);result.setData(data);return result;}public static <T> Result<T> unlogin(){Result result = new Result();result.setCode(ResultCode.UNLOGIN);result.setErrMsg("用戶未登錄");result.setData(null);return result;}}

后端返回接口

@RequestMapping("/getBookListByPage")public Result getBookListByPage(PageRequest pageRequest, HttpSession session){log.info("查詢翻頁信息, pageRequest:{}",pageRequest);//校驗成功if (pageRequest.getPageSize()<0 || pageRequest.getCurrentPage()<1){return Result.fail("參數校驗失敗");}PageResult<BookInfo> bookInfoPageResult = null;try {bookInfoPageResult = bookService.selectBookInfoByPage(pageRequest);//此處對返回的數據進行再次封裝return Result.success(bookInfoPageResult);}catch (Exception e){log.error("查詢翻頁信息錯誤,e:{}",e);return Result.fail(e.getMessage());}}

攔截器幫我們實現了第?個功能, 接下來看SpringBoot對第?個功能如何?持

統一數據返回格式快速入門

統一的數據返回格式使用@ControllerAdviceResponseBodyAdvice 的方式實現

@ControllerAdvice表示控制器通知類

添加類 ResponseAdvice , 實現 ResponseBodyAdvice 接?, 并在類上添加 @ControllerAdvice 注解

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Autowired//轉jsonprivate ObjectMapper objectMapper;//判斷是否要執行beforeBodyWrite方法//ture為執行//false不執行@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {return Result.success(body);}
}

supports方法: 判斷是否要執行beforeBodyWrite方法, true為執行 false不執行, 通過該方法可以選擇那些類或者哪些方法的response要進行處理 其他的不處理
beforeBodyWrite方法: 對response方法進行具體操作處理

統一異常處理

統?異常處理使?的是 @ControllerAdvice + @ExceptionHandler 來實現的,@ControllerAdvice 表?控制器通知類, @ExceptionHandler 是異常處理器,兩個結合表?當出現異常的時候執?某個通知,也就是執?某個?法事件

package com.bite.book.config;import com.bite.book.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice
@ResponseBody
@Slf4j
public class ErrorHandler {@ExceptionHandlerpublic Object handler(Exception e){log.info("發生異常 e:{}",e.getMessage());return Result.fail(e.getMessage());}@ExceptionHandlerpublic Object handler(NullPointerException e) {return Result.fail("發?NullPointerException:"+e.getMessage());}@ExceptionHandlerpublic Object handler(ArithmeticException e) {return Result.fail("發?ArithmeticException:"+e.getMessage());}
}

當有多個異常通知時,匹配順序為當前類及其?類向上依次匹配

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/213262.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213262.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213262.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ChibiOS簡介2/5

ChibiOS簡介2/5 1. 源由2. ChibiOS基礎知識2/52.4 Chapter 4 - ChibiOS General Architecture2.4.1 The Big Picture&#xff08;總體框圖&#xff09;2.4.2 Embedded Components&#xff08;嵌入式組件&#xff09;2.4.3 Application Model&#xff08;應用模型&#xff09;2.…

爬蟲解析——Xpath的安裝及使用(五)

目錄 一、Xpath插件的安裝 二、安裝 lxml 三、Xpath解析文件 1.解析本地文件 &#xff08;1&#xff09;導入本地文件 &#xff08;2&#xff09;解析本地文件 2.服務器文件解析 &#xff08;1&#xff09;獲取網頁源碼 &#xff08;2&#xff09;解析服務器響應文件 …

力扣373. 查找和最小的 K 對數字

優先隊列 思路&#xff1a; 使用下標 (x, y) 標識數值對&#xff0c;x 為第一個數組的下標&#xff0c;y 為第二個數組的下標&#xff1b;所以 k 個數值對 x 的范圍屬于 [0, min(k, m)]&#xff0c;m 為第一個數組的 size&#xff1b;數值對 (x, y) &#xff0c;那么下一個比其…

TailwindCSS 如何處理RTL布局模式

背景 TikTok作為目前全世界最受歡迎的APP&#xff0c;需要考慮兼容全世界各個地區的本地化語言和閱讀習慣。其中對于阿拉伯語、波斯語等語言的閱讀書寫習慣是從右向左的&#xff0c;在前端有一個專有名字RTL模式&#xff0c;即Right-to-Left。 其中以阿拉伯語作為第一語言的人…

C# 獲取windows 系統開關機時間

關機時間&#xff0c;引用&#xff1a;https://www.coder.work/article/1589448 public static DateTime GetLastSystemShutdown() { string sKey "System\CurrentControlSet\Control\Windows"; Microsoft.Win32.RegistryKey key …

建立個人學習觀|地鐵上的自習室

作者&#xff1a;向知 如果大家有機會來北京&#xff0c;可以來看看工作日早上八九點鐘&#xff0c;15 號線從那座叫“順義”的城市通向“望京”的地鐵&#xff0c;你在那上面&#xff0c;能看到明明白白的&#xff0c;人們奔向夢想的模樣。 一、地鐵上的自習室 我在來北京之前…

華為數據之道學習筆記】3-5 規則數據治理

在業務規則管理方面&#xff0c;華為經常面對“各種業務場景業務規則不同&#xff0c;記不住&#xff0c;找不到”“大量規則在政策、流程等文件中承載&#xff0c;難以遵守”“各國規則均不同&#xff0c;IT能否一國一策、快速上線”等問題。 規則數據是結構化描述業務規則變量…

【算法集訓】基礎數據結構:三、鏈表

鏈表就是將所有數據都用一個鏈子串起來&#xff0c;其中鏈表也有多種形式&#xff0c;包含單向鏈表、雙向鏈表等&#xff1b; 現在畢竟還是基礎階段&#xff0c;就先學習單鏈表吧&#xff1b; 鏈表用頭結點head表示一整個鏈表&#xff0c;每個鏈表的節點包含當前節點的值val和下…

2024 年頂級的 Android 系統修復軟件與方法

您是否正在尋找可以修復 PC 上 Android 操作系統的工具&#xff1f;這是我們精選的最好的 Android 系統修復軟件&#xff01; Android 是世界著名的智能手機操作系統。全世界有數百萬人使用這個操作系統&#xff0c;這使得它安全可靠。然而&#xff0c;這仍然不能使它完美無缺…

048:利用vue-video-player播放m3u8

第048個 查看專欄目錄: VUE ------ element UI 專欄目標 在vue和element UI聯合技術棧的操控下&#xff0c;本專欄提供行之有效的源代碼示例和信息點介紹&#xff0c;做到靈活運用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安裝、引用&#xff0c;模板使…

普冉(PUYA)單片機開發筆記(6): 呼吸燈

概述 上一篇的實驗中&#xff0c;分別正確地配置了 TIM16 和 TIM1&#xff0c;TIM16 的中斷服務程序中每隔 500ms 翻轉板載 LED 一次&#xff1b;TIM1 的 CHANNEL_1 用于輸出一個固定占空比的 PWM 信號。這一次我們進一小步&#xff1a;使用 TIM16 的中斷設置 TIM1 CHANNEL_1 …

MyBatis進階之分頁和延遲加載

文章目錄 分頁1. RowBounds 分頁2. PageHelper 分頁3. PageInfo 對象屬性描述 延遲加載立即加載激進式延遲加載真-延遲加載 分頁 Mybatis 中實現分頁功能有 3 種途徑&#xff1a; RowBounds 分頁&#xff08;不建議使用&#xff09;Example 分頁&#xff08;簡單情況可用)Pag…

關于對向量檢索研究的一些學習資料整理

官方學習資料 主要是的學習資料是&#xff0c; 官方文檔 和官方博客。相關文章還是挺多 挺不錯的 他們更新也比較及時。有最新的東西 都會更新出來。es scdn官方博客 這里簡單列一些&#xff0c;還有一些其他的&#xff0c;大家自己感興趣去看。 什么是向量數據庫 Elasticse…

文件加密軟件哪個最好用 好用的文件加密軟件推薦

一說到文件加密軟件&#xff0c;可能大家都會去搜一些不知名的軟件來&#xff0c;但是選擇這種加密軟件&#xff0c;最好還是要看一些資質的。 資質不好的&#xff0c;可能加密過后你自己也打不開文件&#xff0c;&#xff08;ps&#xff1a;我自己就遇到過這種情況&#xff09…

【華為OD機試python】分蘋果【2023 B卷|100分】

【華為OD機試】-真題 !!點這里!! 【華為OD機試】真題考點分類 !!點這里 !! 題目描述 A、B兩個人把蘋果分為兩堆,A希望按照他的計算規則等分蘋果, 他的計算規則是按照二進制加法計算,并且不計算進位 12+5=9(1100 + 0101 = 9), B的計算規則是十進制加法,包括正常進位,…

基于Java SSM框架高校校園點餐訂餐系統項目【項目源碼+論文說明】計算機畢業設計

基于java的SSM框架高校校園點餐訂餐系統演示 摘要 21世紀的今天&#xff0c;隨著社會的不斷發展與進步&#xff0c;人們對于信息科學化的認識&#xff0c;已由低層次向高層次發展&#xff0c;由原來的感性認識向理性認識提高&#xff0c;管理工作的重要性已逐漸被人們所認識&a…

(一)Java 基礎語法

目錄 一. 前言 二. Hello World 三. Java 語法 3.1. 基本語法 3.2. Java 標識符 3.3. Java 修飾符 3.4. Java 變量 3.5. Java 數組 3.6. Java 枚舉 3.7. Java 關鍵字 3.8. Java 注釋 3.9. Java 空行 3.10. Java 繼承 3.11. Java 接口&#xff08;interface&#…

Oracle(2-14)User-Managed Incomplete Recovery

文章目錄 一、基礎知識1、Incomplete Recovery Overview 不完全恢復概述2、Situations Requiring IR 需要不完全恢復的情況3、Types of IR 不完全恢復的類型4、IR Guidelines 不完全恢復指南5、User-Managed Procedures 用戶管理程序6、RECOVER Command Overview 恢復命令概述7…

算法訓練營Day8(字符串)

344.反轉字符串 344. 反轉字符串 - 力扣&#xff08;LeetCode&#xff09; class Solution {public void reverseString(char[] s) {for(int i 0,j s.length-1;i< s.length/2 ; i,j--){swap(s,i,j);}}public void swap(char[] s,int i,int j ){char temp s[i];s[i] s[j]…

Python數據科學視頻講解:Python注釋

2.3 Python注釋 視頻為《Python數據科學應用從入門到精通》張甜 楊維忠 清華大學出版社一書的隨書贈送視頻講解2.3節內容。本書已正式出版上市&#xff0c;當當、京東、淘寶等平臺熱銷中&#xff0c;搜索書名即可。內容涵蓋數據科學應用的全流程&#xff0c;包括數據科學應用和…