1. RESTFul 風格
RESTFul是一種基於 HTTP 和標準化設計原則的軟體架構風格,用於設計和實現可靠、可擴充套件和易於整合的 Web 服務和應用程式。
要求:
-
每一個URI 代表一種資源,是名詞,也就是 url中不要帶動作
-
客戶端使用 GET、POST、PUT、DELETE 表示操作方式的動詞對服務端資源進行操作,GET獲取資源,進行查詢操作。POST進行插入操作,PUT進行更新操作,DELETE 進行刪除操作。
使用 RESTFul 風格,url可能是相同的,但是透過 請求方式的不同可以區別不同的請求
操作 | 傳統風格 | REST風格 |
---|---|---|
儲存 | /crud/saveEmp | url:/crud/emp 請求方式:POST |
刪除 | /crud/deleteEmp?id=1 | url:/crud/emp/1 請求方式:DELETE |
更新 | /crud/updateEmp | url:/crud/emp 請求方式:PUT |
查詢 | /crud/selectEmp?id=1 | url:/crud/emp/1 請求方式:GET |
RESTFul 並不是只能用 路徑傳參。在某些情況下也可以使用 param傳參
當查詢的是一個單一的資源,傳入的是一個id值,這時候可以用 路徑傳參,比如根據id 查詢一個使用者
當查詢的是一個集合資源,傳入的是一個範圍值,這時可以用 param傳參,比如分頁查詢或多條件模糊查詢等
而POST 和 PUT 用 請求體傳參即可,即json資料
2. 全域性異常處理
當出現異常時,有兩種解決方案:
-
程式設計式異常處理:在業務邏輯程式碼中顯示地進行異常處理,用try catch
-
宣告式異常處理:將業務邏輯程式碼與異常處理分離,透過配置進行統一的管理,互不干擾
步驟:
-
宣告異常處理控制器類
定義一個類,在類上使用 @ControllerAdvice 或 @RestControllerAdvice 註解,捕捉全域性異常
-
在這個類中,宣告異常處理handler方法,透過 @ExceptionHandler 註解指定相應的異常
當出現異常時,就會走對應的handler方法
@ControllerAdvice 和 @RestControllerAdvice 的區別是:前者可以返回檢視,可以重定向和轉發。後者返回字串
@RestController
@RequestMapping("exception")
public class ExceptionController {
@GetMapping("data")
public String data(){
String name = null;
name.toString();
return name;
}
}
上面會出現空指標異常
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NullPointerException.class)
public Object NullPointerException(NullPointerException e){
return e.getMessage();
}
}
定義了一個全域性異常處理類,裡面透過 @ExceptionHandler 指定了 如果出現 NullPointerException異常就會走下面的方法,在該方法中處理異常即可。
注意:需要保證 @RestControllerAdvice 被掃描到
3. 攔截器
攔截器可以在執行handler 之前和之後或者在DispatcherServlet返回時執行一些程式碼,加上一些功能,如登入校驗等。和Filter功能類似。
攔截器和過濾器的區別:
相似點:
-
攔截:必須把請求攔住,才能執行後續操作
-
過濾:攔截器或過濾器存在的意義就是對請求進行統一處理
-
放行:對請求執行了必要操作後,放請求過去,讓它訪問原本想要訪問的資源
不同點:
-
工作平臺不同
-
過濾器工作在Servlet容器中
-
攔截器工作在SpringMVC 的基礎上
-
-
攔截的範圍
-
過濾器能夠攔截到的最大範圍是整個web應用
-
攔截器能夠攔截到的最大範圍是整個SpringMVC 負責的請求
-
-
IOC 容器支援
-
想得到過濾器ioc容器需要呼叫專門的工具方法,spring並沒有支援
-
攔截器就放在ioc容器中,可以直接從ioc容器中裝配元件,可以直接得到ioc容器的支援
-
使用
-
建立一個類,實現 HandlerInterceptor 介面,重寫三個方法
-
preHandler 在處理請求的目標Handler方法之前執行,返回true就是放行,返回false攔截
-
postHandler 在目標handler方法之後執行,如果handler報錯則不執行
-
afterCompletion 渲染檢視後執行(在最後)一定執行
-
-
將攔截器加入到 ioc容器中
在配置類裡重寫 addInterceptor 方法,呼叫 引數 InterceptorRegistry的 registry方法,傳入的引數是 new
攔截器類
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return HandlerInterceptor.super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
引數:request 請求物件、response 響應物件、handler 呼叫的物件方法、modelAndView 返回的檢視和共享域物件、Exception 異常物件
@Configuration
@ComponentScan({"com.ztone.controller","com.ztone.error"})
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
}
必須繼承 WebMvcConfigurer
上面這種方式是攔截了所有的請求,如果想要攔截指定請求可以追加呼叫 addPathPatterns
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/data");
}
也可以排除攔截某些請求,呼叫 excludePathPatterns
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/user/**").excludePathPatterns("/user/data");
}
如果有多個攔截器,那麼先宣告的攔截器優先順序高,優先順序高的在外層,也就是 優先順序高的攔截器先執行 preHandler,後執行 postHandler 和 afterCompletion
4.引數校驗註解
jsr303 是Java為Bean資料合法性校驗提供的標準框架
註解 | 規則 |
---|---|
@Null | 標註值必須為null |
@NotNull | 標註值不可null |
@AssertTrue | 標註值必須為true |
@AssertFalse | 標註值必須為false |
@Max(value) | 標註值必須小於等於value |
@Min(value) | 標註值必須大於等於value |
@DecimalMin(value) | 標註值必須大於等於value |
@DecimalMax(value) | 標註值必須小於等於value |
@Size(max,min) | 標註值必須在max和min範圍內 |
@Digits(integer,fratction) | 標註值必須是數字,並且在可接受的範圍內 |
@Past | 標註值只能用於日期型,且必須是過去的日期 |
@Future | 標註值只能用於日期型,且必須是未來的日期 |
@Pattern(value) | 標註值必須符合指定的正規表示式 |
標註值必須是格式正確的Email | |
@Length | 標註值字串大小必須在指定的範圍內 |
@NotEmpty | 標註集合長度不為空 |
@Range | 標註值必須在指定的範圍內 |
@NotBlank | 標註值字串不為null,且不是空字串 |
使用:
-
需要匯入依賴
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.0.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator-annotation-processor</artifactId> <version>8.0.0.Final</version> </dependency>
-
在實體類的屬性上使用註解
@Data public class User { @NotBlank private String name; @Length(min = 6, max = 12) private String password; @Min(0) private int age; }
-
在接收引數的地方使用 @Validated
@Controller public class UserController { @GetMapping("data") public String data(@Validated @RequestBody User user){ return null; } }
當傳來的引數沒有透過校驗,那麼就會直接向前端報異常
如果想要自定義向前端的輸出,可以在引數的後面緊挨著一個 引數 BindingResult
在handler中呼叫 該物件的 hasErrors方法,一旦報錯就會返回 true
@Controller
public class UserController {
@GetMapping("data")
public String data(@Validated @RequestBody User user, BindingResult bindingResult){
if (bindingResult.hasErrors()) {
//處理向前端的返回資料
}
return null;
}
}