您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“SpringBoot統一處理功能如何實現”,內容詳細,步驟清晰,細節處理妥當,希望這篇“SpringBoot統一處理功能如何實現”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
在處理網絡請求時,有一部分功能是需要抽出來統一處理的,與業務隔開。
可以利用spring mvc的攔截器Interceptor,實現HandlerInterceptor接口即可。實現該接口后,會在把請求發給Controller之前進行攔截處理。
攔截器的實現分為以下兩個步驟:
創建?定義攔截器,實現 HandlerInterceptor 接?的 preHandle(執?具體?法之前的預處理)?法。
將?定義攔截器加? WebMvcConfigurer 的 addInterceptors ?法中。
我們使用session來作為登錄校驗的例子,實現如下:
package com.demo; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * 登錄攔截器 */ @Component @Slf4j public class LoginInterceptor implements HandlerInterceptor { /** * 為 false 則不能繼續往下執行;為 true 則可以。 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判斷session的信息是否合法 HttpSession session = request.getSession(false); if (session != null && session.getAttribute("userinfo") != null) { return true; } log.error("當前用戶沒有訪問權限"); response.setStatus(401); return false; } }
將寫好的?定義攔截器通過WebMvcConfigurer注冊到容器中,使得攔截器生效,具體實現代碼如下:
package com.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MyConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) .addPathPatterns("/**") // 攔截所有請求 .excludePathPatterns("/user/login"); // 排除不攔截的 url } }
如果不注入對象的話,addInterceptor() 的參數也可以直接 new 一個對象:
@Configuration // 一定不要忘記 public class MyConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**") // 攔截所有請求 .excludePathPatterns("/user/login"); // 排除不攔截的 url } }
原理
所有的 Controller 執?都會通過spring mvc的調度器 DispatcherServlet 來實現,所有?法都會執? DispatcherServlet 中的 doDispatch 調度?法,doDispatch 源碼如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null; Object dispatchException = null; try { // ... 忽略不重要的代碼 // 調?預處理 if (!mappedHandler.applyPreHandle(processedRequest, respon se)) { return; } // 執? Controller 中的業務 mv = ha.handle(processedRequest, response, mappedHandler.g etHandler()); // ... 忽略不重要的代碼 } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler di spatch failed", var21); } this.processDispatchResult(processedRequest, response, mappedH andler, mv, (Exception)dispatchException); } catch (Exception var22) { this.triggerAfterCompletion(processedRequest, response, mapped Handler, var22); } catch (Throwable var23) { this.triggerAfterCompletion(processedRequest, response, mapped Handler, new NestedServletException("Handler processing failed", var23)); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processe dRequest, response); } } else if (multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } }
從上述源碼可以看出在開始執? Controller 之前,會先調? 預處理?法 applyPreHandle,? applyPreHandle ?法的實現源碼如下:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) { // 獲取項?中使?的攔截器 HandlerInterceptor HandlerInterceptor interceptor = (HandlerInterceptor)this.intercep torList.get(i); if (!interceptor.preHandle(request, response, this.handler)) { this.triggerAfterCompletion(request, response, (Exception)null ); return false; } } return true; }
請求時的異常處理也是比較常見的統一處理的對象。
統?異常處理使?的是 @ControllerAdvice + @ExceptionHandler 來實現的,@ControllerAdvice 表示控制器通知類,@ExceptionHandler 是異常處理器,兩個結合表示當出現異常的時候執?某個通知,也就是執?某個?法事件,具體實現代碼如下:
package com.demo; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap; /** * 統一處理異常 * 一般都需要自定義一個異常對象,這里為了簡單說明只用一個map對象來說明 */ @ControllerAdvice public class ErrorAdive { @ExceptionHandler(Exception.class) @ResponseBody public HashMap<String, Object> exceptionAdvie(Exception e) { HashMap<String, Object> result = new HashMap<>(); result.put("code", "-1"); result.put("msg", e.getMessage()); return result; } @ExceptionHandler(ArithmeticException.class) @ResponseBody public HashMap<String, Object> arithmeticAdvie(ArithmeticException e) { HashMap<String, Object> result = new HashMap<>(); result.put("code", "-2"); result.put("msg", e.getMessage()); return result; } }
此時若出現異常就不會報錯了,代碼會繼續執行,但是會把自定義的異常信息返回給前端!
@ControllerAdvice是spring的aop對于Controller進行切面所有屬性的,包括切入點和需要織入的切面邏輯,配合@ExceptionHandler來捕獲Controller中拋出的指定類型的異常,從而達到不同類型的異常區別處理的目的。
統?的返回數據結構可以使用 @ControllerAdvice + ResponseBodyAdvice接口 的方式實現,具體實現代碼如下:
package com.demo; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyA dvice; import java.util.HashMap; /** * 統一返回數據的處理 */ @ControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice { /** * 內容是否需要重寫(通過此?法可以選擇性部分控制器和?法進?重寫) * 返回 true 表示重寫 */ @Override public boolean supports(MethodParameter returnType, Class converterTyp e) { return true; } /** * ?法返回之前調?此?法 */ @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpR equest request, ServerHttpResponse response) { // 構造統?返回對象 HashMap<String, Object> result = new HashMap<>(); result.put("state", 1); result.put("msg", ""); result.put("data", body); return result; } }
讀到這里,這篇“SpringBoot統一處理功能如何實現”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。