溫州專業(yè)網(wǎng)站托管網(wǎng)絡(luò)熱詞的利弊
一、全局異常處理機(jī)制:
1.異常處理兩種方式:
開(kāi)發(fā)過(guò)程中是不可避免地會(huì)出現(xiàn)各種異常情況的,例如網(wǎng)絡(luò)連接異常、數(shù)據(jù)格式異常、空指針異常等等。異常的出現(xiàn)可能導(dǎo)致程序的運(yùn)行出現(xiàn)問(wèn)題,甚至直接導(dǎo)致程序崩潰。因此,在開(kāi)發(fā)過(guò)程中,合理處理異常、避免異常產(chǎn)生、以及對(duì)異常進(jìn)行有效的調(diào)試是非常重要的。
對(duì)于異常的處理,一般分為兩種方式:
(1).編程式異常處理:是指在代碼中顯式地編寫(xiě)處理異常的邏輯。它通常涉及到對(duì)異常類型的檢測(cè)及其處理,例如使用try-catch塊來(lái)捕獲異常,然后在catch塊中編寫(xiě)特定的處理代碼,或者在finally塊中執(zhí)行一些清理操作。在編程式異常處理中,開(kāi)發(fā)人員需要顯式地進(jìn)行異常處理,異常處理代碼混雜在業(yè)務(wù)代碼中,導(dǎo)致代碼可讀性較差。
(2).聲明式異常處理:則是將異常處理的邏輯從具體的業(yè)務(wù)邏輯中分離出來(lái),通過(guò)配置等方式進(jìn)行統(tǒng)一的管理和處理。在聲明式異常處理中,開(kāi)發(fā)人員只需要為方法或類標(biāo)注相應(yīng)的注解(如@Throws或@ExceptionHandler),就可以處理特定類型的異常。相較于編程式異常處理,聲明式異常處理可以使代碼更加簡(jiǎn)潔、易于維護(hù)和擴(kuò)展。
站在宏觀角度來(lái)看待聲明式事務(wù)處理:整個(gè)項(xiàng)目從架構(gòu)這個(gè)層面設(shè)計(jì)的異常處理的統(tǒng)一機(jī)制和規(guī)范。一個(gè)項(xiàng)目中會(huì)包含很多個(gè)模塊,各個(gè)模塊需要分工完成。如果張三負(fù)責(zé)的模塊按照 A 方案處理異常,李四負(fù)責(zé)的模塊按照 B 方案處理異?!鱾€(gè)模塊處理異常的思路、代碼、命名細(xì)節(jié)都不一樣,那么就會(huì)讓整個(gè)項(xiàng)目非?;靵y。使用聲明式異常處理,可以統(tǒng)一項(xiàng)目處理異常思路,項(xiàng)目更加清晰明了
2.基于注解異常聲明異常處理:
(1).聲明異常處理控制器類:
異常處理控制類,統(tǒng)一定義異常處理handler方法
/*** projectName: com.atguigu.execptionhandler* * description: 全局異常處理器,內(nèi)部可以定義異常處理Handler!*//*** @RestControllerAdvice = @ControllerAdvice + @ResponseBody* @ControllerAdvice 代表當(dāng)前類的異常處理controller! */
@RestControllerAdvice
public class GlobalExceptionHandler {}
(2).聲明異常處理hander方法:
異常處理handler方法和普通的handler方法參數(shù)接收和響應(yīng)都一致
只不過(guò)異常處理handler方法要映射異常,發(fā)生對(duì)應(yīng)的異常會(huì)調(diào)用
普通的handler方法要使用@RequestMapping注解映射路徑,發(fā)生對(duì)應(yīng)的路徑調(diào)用
/*** 異常處理handler * @ExceptionHandler(HttpMessageNotReadableException.class) * 該注解標(biāo)記異常處理Handler,并且指定發(fā)生異常調(diào)用該方法!* * * @param e 獲取異常對(duì)象!* @return 返回handler處理結(jié)果!*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public Object handlerJsonDateException(HttpMessageNotReadableException e){return null;
}/*** 當(dāng)發(fā)生空指針異常會(huì)觸發(fā)此方法!* @param e* @return*/
@ExceptionHandler(NullPointerException.class)
public Object handlerNullException(NullPointerException e){return null;
}/*** 所有異常都會(huì)觸發(fā)此方法!但是如果有具體的異常處理Handler! * 具體異常處理Handler優(yōu)先級(jí)更高!* 例如: 發(fā)生NullPointerException異常!* 會(huì)觸發(fā)handlerNullException方法,不會(huì)觸發(fā)handlerException方法!* @param e* @return*/
@ExceptionHandler(Exception.class)
public Object handlerException(Exception e){return null;
}
(3).配置文件掃描控制器類配置:
確保異常處理控制類被掃描
<!-- 掃描controller對(duì)應(yīng)的包,將handler加入到ioc-->@ComponentScan(basePackages = {"com.atguigu.controller","com.atguigu.exceptionhandler"})
二、攔截器的使用:
1.攔截器的概念:攔截器和過(guò)濾器解決問(wèn)題
在程序中,使用攔截器在請(qǐng)求到達(dá)具體handler方法前,統(tǒng)一執(zhí)行檢測(cè)
攔截器Springmvc VS 過(guò)濾器javaWeb:
(1).相似點(diǎn):
a.攔截:必須先把請(qǐng)求攔住,才能執(zhí)行后續(xù)操作
b.過(guò)濾:攔截器或過(guò)濾器存在的意義就是對(duì)請(qǐng)求進(jìn)行統(tǒng)一處理
c.放行:對(duì)請(qǐng)求執(zhí)行了必要操作后,放請(qǐng)求過(guò)去,讓它訪問(wèn)原本想要訪問(wèn)的資源
(2).不同點(diǎn):
a.工作平臺(tái)不同:
過(guò)濾器工作在Servlet容器中
攔截器工作在SpringMVC的基礎(chǔ)上
b.攔截的范圍:
過(guò)濾器能夠攔截到的最大范圍是整個(gè)Web應(yīng)用
攔截器能夠攔截到的最大范圍是整個(gè)SpringMVC負(fù)責(zé)的請(qǐng)求
c.IOC容器支持:
過(guò)濾器想得到IOC容器需要調(diào)用專門(mén)的工具方法,是間接的
攔截器它自己就在IOC容器中,所以可以直接從IOC容器中裝配組件,也就是可以直接得到IOC容器的支持
選擇:功能需要如果用 SpringMVC 的攔截器能夠?qū)崿F(xiàn),就不使用過(guò)濾器
2.攔截器的使用:
(1).創(chuàng)建攔截器類:
public class Process01Interceptor implements HandlerInterceptor {// if( ! preHandler()){return;}// 在處理請(qǐng)求的目標(biāo) handler 方法前執(zhí)行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("request = " + request + ", response = " + response + ", handler = " + handler);System.out.println("Process01Interceptor.preHandle");// 返回true:放行// 返回false:不放行return true;}// 在目標(biāo) handler 方法之后,handler報(bào)錯(cuò)不執(zhí)行!@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", modelAndView = " + modelAndView);System.out.println("Process01Interceptor.postHandle");}// 渲染視圖之后執(zhí)行(最后),一定執(zhí)行!@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", ex = " + ex);System.out.println("Process01Interceptor.afterCompletion");}
}
攔截器方法攔截位置:
(2).修改配置類添加攔截器:
@EnableWebMvc //json數(shù)據(jù)處理,必須使用此注解,因?yàn)樗麜?huì)加入json處理器
@Configuration
@ComponentScan(basePackages = {"com.atguigu.controller","com.atguigu.exceptionhandler"}) //TODO: 進(jìn)行controller掃描
//WebMvcConfigurer springMvc進(jìn)行組件配置的規(guī)范,配置組件,提供各種方法! 前期可以實(shí)現(xiàn)
public class SpringMvcConfig implements WebMvcConfigurer {//配置jsp對(duì)應(yīng)的視圖解析器@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {//快速配置jsp模板語(yǔ)言對(duì)應(yīng)的registry.jsp("/WEB-INF/views/",".jsp");}//開(kāi)啟靜態(tài)資源處理 <mvc:default-servlet-handler/>@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}//添加攔截器@Overridepublic void addInterceptors(InterceptorRegistry registry) { //將攔截器添加到Springmvc環(huán)境,默認(rèn)攔截所有Springmvc分發(fā)的請(qǐng)求registry.addInterceptor(new Process01Interceptor());}
}
(3).修改配置:
a.默認(rèn)攔截全部:
@Override
public void addInterceptors(InterceptorRegistry registry) {//將攔截器添加到Springmvc環(huán)境,默認(rèn)攔截所有Springmvc分發(fā)的請(qǐng)求registry.addInterceptor(new Process01Interceptor());
}
b.精準(zhǔn)配置:
@Override
public void addInterceptors(InterceptorRegistry registry) {//將攔截器添加到Springmvc環(huán)境,默認(rèn)攔截所有Springmvc分發(fā)的請(qǐng)求registry.addInterceptor(new Process01Interceptor());//精準(zhǔn)匹配,設(shè)置攔截器處理指定請(qǐng)求 路徑可以設(shè)置一個(gè)或者多個(gè),為項(xiàng)目下路徑即可//addPathPatterns("/common/request/one") 添加攔截路徑//也支持 /* 和 /** 模糊路徑。 * 任意一層字符串 ** 任意層 任意字符串registry.addInterceptor(new Process01Interceptor()).addPathPatterns("/common/request/one","/common/request/tow");
}
c.排除配置:
//添加攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {//將攔截器添加到Springmvc環(huán)境,默認(rèn)攔截所有Springmvc分發(fā)的請(qǐng)求registry.addInterceptor(new Process01Interceptor());//精準(zhǔn)匹配,設(shè)置攔截器處理指定請(qǐng)求 路徑可以設(shè)置一個(gè)或者多個(gè),為項(xiàng)目下路徑即可//addPathPatterns("/common/request/one") 添加攔截路徑registry.addInterceptor(new Process01Interceptor()).addPathPatterns("/common/request/one","/common/request/tow");//排除匹配,排除應(yīng)該在匹配的范圍內(nèi)排除//addPathPatterns("/common/request/one") 添加攔截路徑//excludePathPatterns("/common/request/tow"); 排除路徑,排除應(yīng)該在攔截的范圍內(nèi)registry.addInterceptor(new Process01Interceptor()).addPathPatterns("/common/request/one","/common/request/tow").excludePathPatterns("/common/request/tow");
}
(4).多個(gè)攔截器執(zhí)行順序:
a.preHandle()方法:SpringMVC會(huì)把所有攔截器收集到一起,然后按照配置順序調(diào)用各個(gè) preHandle()方法。
b.postHandle()方法:SpringMVC會(huì)把所有攔截器收集到一起,然后按照配置相反的順序調(diào)用各個(gè) postHandle()方法。
c.afterCompletion()方法:SpringMVC會(huì)把所有攔截器收集到一起,然后按照配置相反的順序調(diào)用各個(gè) afterCompletion()方法。?
三、參數(shù)校驗(yàn):
在Web應(yīng)用三層架構(gòu)體系中,表述層負(fù)責(zé)接收瀏覽器提交的數(shù)據(jù),業(yè)務(wù)邏輯層負(fù)責(zé)數(shù)據(jù)的處理。為了能夠讓業(yè)務(wù)邏輯層基于正確的數(shù)據(jù)進(jìn)行處理,我們需要在表述層對(duì)數(shù)據(jù)進(jìn)行檢查,將錯(cuò)誤的數(shù)據(jù)隔絕在業(yè)務(wù)邏輯層之外
1.校驗(yàn)概述:
JSR 303是Java為Bean數(shù)據(jù)合法性校驗(yàn)提供的標(biāo)準(zhǔn)框架,它已經(jīng)包含在JavaEE 6.0標(biāo)準(zhǔn)中。JSR 303通過(guò)在Bean屬性上標(biāo)注類似于@NotNull、@Max等標(biāo)準(zhǔn)的注解指定校驗(yàn)規(guī)則,并通過(guò)標(biāo)準(zhǔn)的驗(yàn)證接口對(duì)Bean進(jìn)行驗(yàn)證
注解 | 規(guī)則 |
---|---|
@Null | 標(biāo)注值必須為null |
@NotNull | 標(biāo)注值不可為null |
@AssertTrue | 標(biāo)注值必須為true |
@AssertFalse | 標(biāo)注值必須為false |
@Min(value) | 標(biāo)注值必須大于或等于value |
@Max(value) | 標(biāo)注值必須小于或等于value |
@DecimalMin(value) | 標(biāo)注值必須大于或等于value |
@DecimalMax(value) | 標(biāo)注值必須小于或等于value |
@Size(max,min) | 標(biāo)注值大小必須在max和min限定的范圍內(nèi) |
@Digits(integer,fratction) | 標(biāo)注值值必須是一個(gè)數(shù)字,且必須在可接受的范圍內(nèi) |
@Past | 標(biāo)注值只能用于日期型,且必須是過(guò)去的日期 |
@Future | 標(biāo)注值只能用于日期型,且必須是將來(lái)的日期 |
@Pattern(value) | 標(biāo)注值必須符合指定的正則表達(dá)式 |
JSR 303只是一套標(biāo)準(zhǔn),需要提供其實(shí)現(xiàn)才可以使用。Hibernate Validator是JSR 303的一個(gè)參考實(shí)現(xiàn),除支持所有標(biāo)準(zhǔn)的校驗(yàn)注解外,它還支持以下的擴(kuò)展注解:
注解 | 規(guī)則 |
---|---|
標(biāo)注值必須是格式正確的 Email 地址 | |
@Length | 標(biāo)注值字符串大小必須在指定的范圍內(nèi) |
@NotEmpty | 標(biāo)注值字符串不能是空字符串 |
@Range | 標(biāo)注值必須在指定的范圍內(nèi) |
Spring 4.0版本已經(jīng)擁有自己獨(dú)立的數(shù)據(jù)校驗(yàn)框架,同時(shí)支持JSR 303標(biāo)準(zhǔn)的校驗(yàn)框架。Spring在進(jìn)行數(shù)據(jù)綁定時(shí),可同時(shí)調(diào)用校驗(yàn)框架完成數(shù)據(jù)校驗(yàn)工作。在SpringMVC 中,可直接通過(guò)注解驅(qū)動(dòng)@EnableWebMvc的方式進(jìn)行數(shù)據(jù)校驗(yàn)。Spring 的LocalValidatorFactoryBean既實(shí)現(xiàn)了Spring 的Validator接口,也實(shí)現(xiàn)了JSR 303的Validator接口。只要在Spring容器中定義了一個(gè)LocalValidatorFactoryBean,即可將其注入到需要數(shù)據(jù)校驗(yàn)的Bean中。Spring本身并沒(méi)有提供JSR 303的實(shí)現(xiàn),所以必須將JSR 303的實(shí)現(xiàn)者的jar包放到類路徑下。
配置@EnableWebMvc后,SpringMVC會(huì)默認(rèn)裝配好一個(gè)LocalValidatorFactoryBean,通過(guò)在處理方法的入?yún)⑸蠘?biāo)注@Validated注解即可讓SpringMVC在完成數(shù)據(jù)綁定后執(zhí)行數(shù)據(jù)校驗(yàn)的工作。
2.操作演示:
導(dǎo)入依賴:
<!-- 校驗(yàn)注解 -->
<dependency><groupId>jakarta.platform</groupId><artifactId>jakarta.jakartaee-web-api</artifactId><version>9.1.0</version><scope>provided</scope>
</dependency><!-- 校驗(yàn)注解實(shí)現(xiàn)-->
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<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>
應(yīng)用校驗(yàn)注解:
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import org.hibernate.validator.constraints.Length;/*** projectName: com.atguigu.pojo*/
public class User {//age 1 <= age < = 150@Min(10)private int age;//name 3 <= name.length <= 6@Length(min = 3,max = 10)private String name;//email 郵箱格式@Emailprivate String email;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}
}
handler標(biāo)記和綁定錯(cuò)誤收集:
@RestController
@RequestMapping("user")
public class UserController {/*** @Validated 代表應(yīng)用校驗(yàn)注解! 必須添加!*/@PostMapping("save")public Object save(@Validated @RequestBody User user,//在實(shí)體類參數(shù)和 BindingResult 之間不能有任何其他參數(shù), BindingResult可以接受錯(cuò)誤信息,避免信息拋出!BindingResult result){//判斷是否有信息綁定錯(cuò)誤! 有可以自行處理!if (result.hasErrors()){System.out.println("錯(cuò)誤");String errorMsg = result.getFieldError().toString();return errorMsg;}//沒(méi)有,正常處理業(yè)務(wù)即可System.out.println("正常");return user;}
}
測(cè)試效果:
3.易混總結(jié):
@NotNull、@NotEmpty、@NotBlank都是用于在數(shù)據(jù)校驗(yàn)中檢查字段值是否為空的注解,但是它們的用法和校驗(yàn)規(guī)則有所不同。
(1).@NotNull(包裝類型不為null)
@NotNull注解是JSR 303規(guī)范中定義的注解,當(dāng)被標(biāo)注的字段值為null時(shí),會(huì)認(rèn)為校驗(yàn)失敗而拋出異常。該注解不能用于字符串類型的校驗(yàn),若要對(duì)字符串進(jìn)行校驗(yàn),應(yīng)該使用@NotBlank或 @NotEmpty注解。
(2).@NotEmpty(集合類型長(zhǎng)度大于0)
@NotEmpty注解同樣是JSR 303規(guī)范中定義的注解,對(duì)于CharSequence、Collection、Map或者數(shù)組對(duì)象類型的屬性進(jìn)行校驗(yàn),校驗(yàn)時(shí)會(huì)檢查該屬性是否為Null或者size()==0,如果是的話就會(huì)校驗(yàn)失敗。但是對(duì)于其他類型的屬性,該注解無(wú)效。需要注意的是只校驗(yàn)空格前后的字符串,如果該字符串中間只有空格,不會(huì)被認(rèn)為是空字符串,校驗(yàn)不會(huì)失敗。
(3).@NotBlank(字符串,不為null,不為" ?"字符串)
@NotBlank注解是Hibernate Validator附加的注解,對(duì)于字符串類型的屬性進(jìn)行校驗(yàn),校驗(yàn)時(shí)會(huì)檢查該屬性是否為Null或“”或者只包含空格,如果是的話就會(huì)校驗(yàn)失敗。需要注意的是,@NotBlank 注解只能用于字符串類型的校驗(yàn)。
總之,這三種注解都是用于校驗(yàn)字段值是否為空的注解,但是其校驗(yàn)規(guī)則和用法有所不同。在進(jìn)行數(shù)據(jù)校驗(yàn)時(shí),需要根據(jù)具體情況選擇合適的注解進(jìn)行校驗(yàn)。
SpringMVC總結(jié):
核心點(diǎn) | 掌握目標(biāo) |
springmvc框架 | 主要作用、核心組件、調(diào)用流程 |
簡(jiǎn)化參數(shù)接收 | 路徑設(shè)計(jì)、參數(shù)接收、請(qǐng)求頭接收、cookie接收 |
簡(jiǎn)化數(shù)據(jù)響應(yīng) | 模板頁(yè)面、轉(zhuǎn)發(fā)和重定向、JSON數(shù)據(jù)、靜態(tài)資源 |
restful風(fēng)格設(shè)計(jì) | 主要作用、具體規(guī)范、請(qǐng)求方式和請(qǐng)求參數(shù)選擇 |
功能擴(kuò)展 | 全局異常處理、攔截器、參數(shù)校驗(yàn)注解 |