SpringBoot實現(xiàn)統(tǒng)一功能處理的教程詳解
實現(xiàn)三個SpringBoot統(tǒng)一功能處理
1.統(tǒng)一用戶登陸權(quán)限驗證
2.統(tǒng)一異常處理
3.統(tǒng)一數(shù)據(jù)格式返回
1.統(tǒng)一用戶登陸權(quán)限驗證
之前的博客系統(tǒng)中,我們在每個頁面都要檢查用戶是否登錄,之后才有權(quán)限去做其他操作,之前的判斷方式就是,需要驗權(quán)的每一處都寫了相同的驗證方法.業(yè)務(wù)代碼中夾雜了這些非業(yè)務(wù)的代碼
現(xiàn)在我們提供一個公共的AOP方法來進(jìn)行統(tǒng)一的用戶登陸權(quán)限驗證
在AOP的切面中實現(xiàn)用戶登陸權(quán)限的校驗功能非常麻煩
Spring中提供了具體的實現(xiàn)攔截器:HandlerInterceptor
攔截器的實現(xiàn):
WebMvcConfigurer+HandlerInterceptor
1.1.創(chuàng)建自定義攔截器
創(chuàng)建一個 Java 類,并實現(xiàn) HandlerInterceptor 接口,該接口有三個方法:preHandle、postHandle 和 afterCompletion。在 preHandle 方法中編寫前置處理邏輯,在 postHandle 方法中編寫后置處理邏輯,在 afterCompletion 方法中編寫完成后的處理邏輯


此方法返回的是布爾類型的值,返回true表示攔截器驗證成功,繼續(xù)執(zhí)行目標(biāo)方法
返回false,則表示攔截器執(zhí)行失敗,驗證不通過,后續(xù)目標(biāo)方法不會執(zhí)行
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//用戶登錄判斷的業(yè)務(wù)
HttpSession session = request.getSession(false);
if(session!=null && session.getAttribute("session_userinfo")!=null){
//用戶登陸成功
return true;
}
//response.sendRedirect("http://www.baidu.com");跳轉(zhuǎn)頁面
//response.setStatus(401);沒有權(quán)限
return false;
}
}2.將自定義攔截器配置到系統(tǒng)配置項,并設(shè)置攔截規(guī)則


代碼
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")//攔截所有的url
.excludePathPatterns("/user/login")//排除登陸功能
.excludePathPatterns("/user/reg")//排除注冊功能
.excludePathPatterns("/image/**")//排除image下所有的文件
;
}
}對如下代碼測試



這里登陸失敗后由于將狀態(tài)設(shè)置為了401,所以網(wǎng)頁無法正常運作了
正常的應(yīng)該是,返回檢驗登陸失敗的信息,讓用戶從前端了解情況


有了攔截器之后,會在調(diào)用Controller之前進(jìn)行攔截器的預(yù)處理操作
執(zhí)行流程:用戶->攔截器->controller->service->mapper->database
下來我們分析源碼
所有的Controller執(zhí)行都會通過一個DispatcherServlet來實現(xiàn),可以從打印臺看出
DispatcherServlet是SpringMVC框架的核心,主要負(fù)責(zé)管理請求和處理器之間的映射關(guān)系,并結(jié)合所配置的攔截器和視圖解析器來實現(xiàn)請求的分發(fā)和結(jié)果的呈現(xiàn)
例如:攔截器:DispatcherServlet支持對請求進(jìn)行攔截,并允許用戶定義自己的攔截器來進(jìn)行請求處理前和處理后的操作

大致流程如下

2.統(tǒng)一異常處理
如果不進(jìn)行統(tǒng)一異常處理,出現(xiàn)異常,會直接將異常拋到前端


統(tǒng)一的異常處理使用的是@ControllerAdvice和@ExceptionHandler來實現(xiàn)的
@ControllerAdvice表示控制器通知類,@ExceptionHandler是異常處理器,兩者結(jié)合表示出現(xiàn)異常時執(zhí)行某個通知
1.建立異常處理類
添加該注解可以集中處理所有 Controller 中拋出的異常,從而避免開發(fā)人員在每個 Controller 中都編寫異常處理代碼的重復(fù)勞動

2.創(chuàng)建異常檢測的類和業(yè)務(wù)處理方法
@ControllerAdvice 可以定義一些方法,在方法內(nèi)部使用 @ExceptionHandler 注解來處理指定類型的異常。當(dāng) Controller 中拋出該類型的異常時,就會自動調(diào)用相應(yīng)的方法來處理異常,而不是直接將異常拋到前端


此時就會返回一個json格式的異常信息到前端
上述只是處理了空指針異常,其它異常是攔截不到的.所以將監(jiān)視異常的范圍擴(kuò)大,出現(xiàn)各種異常,就會找到它們的父類--Exception

添加一個異常代碼


如果實現(xiàn)了具體的異常類,也實現(xiàn)了Exception.那么默認(rèn)是匹配具體的異常處理,匹配不到就會尋找父類的處理
3.統(tǒng)一數(shù)據(jù)格式返回
統(tǒng)一數(shù)據(jù)格式返回是指在 Spring MVC 中,定義一個通用的數(shù)據(jù)結(jié)構(gòu),來封裝所有接口的返回值,這樣可以更好地對所有返回結(jié)果進(jìn)行統(tǒng)一處理和管理,從而提高代碼的可維護(hù)性、可重用性和可擴(kuò)展性
使用注解@ControllerAdvice+ResponseBodyAdvice接口
步驟:
1.創(chuàng)建一個類,并添加 @ControllerAdvice 注解,該注解作用于類上,表示這是一個全局控制器增強(qiáng)器
2.實現(xiàn) ResponseBodyAdvice 接口,并指定泛型 T 為 Object 類型。該接口中定義了兩個方法 beforeBodyWrite() 和 supports(),分別用于處理響應(yīng)前的操作和判斷是否支持當(dāng)前返回值類型
3.在 beforeBodyWrite() 方法中,判斷響應(yīng)的對象是否為自定義的統(tǒng)一數(shù)據(jù)格式返回類型,如果不是,則將它轉(zhuǎn)換成統(tǒng)一的格式,例如封裝成一個 Result 對象
4.在 supports() 方法中,判斷當(dāng)前返回值類型是否需要進(jìn)行統(tǒng)一數(shù)據(jù)格式返回的處理
使用該方法后,所有返回類型為非基本數(shù)據(jù)類型的請求,都會經(jīng)過 ResponseBodyAdvice 的處理,從而統(tǒng)一返回給前端一個自定義的結(jié)構(gòu)體數(shù)據(jù)
@ControllerAdvice
public class ResponseBody implements ResponseBodyAdvice {
//是否執(zhí)行beforeBodyWrite,true為執(zhí)行
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
//返回數(shù)據(jù)之前進(jìn)行數(shù)據(jù)重寫
//body:原始返回值
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//標(biāo)準(zhǔn)返回格式定義為:HashMap<String,Object>->code,msg,data
if(body instanceof HashMap){
return body;
}
//重寫返回結(jié)果,返回統(tǒng)一格式
HashMap<String,Object> res = new HashMap<>();
res.put("code",200);
res.put("msg","");
res.put("data",body);
return res;
}
}
login:

reg:


按照保底的數(shù)據(jù)返回格式應(yīng)該返回data為sayhello

Resolved [java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String]
將String格式化數(shù)據(jù)執(zhí)行流程分為三部
1.方法返回String
2.統(tǒng)一數(shù)據(jù)格式返回之前處理:String轉(zhuǎn)換為Hash Map
3.將Hash Map轉(zhuǎn)換為application/json 字符串返回給前端(接口)
不進(jìn)行異常攔截時:

通過報錯信息,可以看出是第三步出了問題,無法將HashMap 轉(zhuǎn)換為json字符串
原因:在第三步會對原body類型進(jìn)行判斷
1.String類型:使用StringHttpMessageConverter轉(zhuǎn)換器進(jìn)行轉(zhuǎn)換
2.非string類型:HttpMessageConverter轉(zhuǎn)換器進(jìn)行轉(zhuǎn)換
使用的卻是StringHttpMessageConverter轉(zhuǎn)換器對HashMap轉(zhuǎn)換成json字符串.就會拋出異常
應(yīng)當(dāng)適用HttpMessageConverter
判斷時使用原body進(jìn)行判斷,轉(zhuǎn)換時使用的是Hash Map進(jìn)行轉(zhuǎn)換的..StringHttpMessageConverter轉(zhuǎn)換不了Hash Map
解決方案:
1. 移除StringHttpMessageConverter
通過config配置文件移除

@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);
}
}
2.統(tǒng)一數(shù)據(jù)重寫時單獨處理String類型,單獨返回,不使用Hash Map進(jìn)行統(tǒng)一返回
方式一:


方式二:使用json工具轉(zhuǎn)換



以上就是SpringBoot實現(xiàn)統(tǒng)一功能處理的教程詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot統(tǒng)一功能處理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring需要三個級別緩存解決循環(huán)依賴原理解析
這篇文章主要為大家介紹了Spring需要三個級別緩存解決循環(huán)依賴原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
劍指Offer之Java算法習(xí)題精講數(shù)組查找與字符串交集
跟著思路走,之后從簡單題入手,反復(fù)去看,做過之后可能會忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化2022-03-03
詳解servlet的url-pattern匹配規(guī)則
本篇文章主要介紹了=servlet的url-pattern匹配規(guī)則,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12
java連接hdfs ha和調(diào)用mapreduce jar示例
這篇文章主要介紹了Java API連接HDFS HA和調(diào)用MapReduce jar包,需要的朋友可以參考下2014-03-03

