中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

商貿(mào)網(wǎng)站管理培訓(xùn)機構(gòu)

商貿(mào)網(wǎng)站,管理培訓(xùn)機構(gòu),西寧網(wǎng)站建設(shè)服務(wù)公司,裝飾設(shè)計乙級資質(zhì)目錄 一、用戶登錄權(quán)限驗證 1.1 SpringAOP可以進行處理嗎? 1.2 創(chuàng)建自定義攔截器 1.3 將自定義攔截器配置到系統(tǒng)配置項中 1.4 攔截器的實現(xiàn)原理 1.4.1 實現(xiàn)原理源碼分析 1.5 統(tǒng)一訪問前綴添加 二、統(tǒng)一異常處理 2.1 為什么需要使用統(tǒng)一異常處理?…

目錄

一、用戶登錄權(quán)限驗證

1.1 SpringAOP可以進行處理嗎?

1.2?創(chuàng)建自定義攔截器

?1.3?將自定義攔截器配置到系統(tǒng)配置項中

1.4 攔截器的實現(xiàn)原理

1.4.1 實現(xiàn)原理源碼分析

1.5 統(tǒng)一訪問前綴添加

二、統(tǒng)一異常處理

2.1 為什么需要使用統(tǒng)一異常處理?

2.2 統(tǒng)一異常處理的實現(xiàn)

三、統(tǒng)一數(shù)據(jù)返回格式

3.1 為什么需要統(tǒng)一數(shù)據(jù)返回格式?

3.2 統(tǒng)一數(shù)據(jù)返回格式的實現(xiàn)

?3.3 返回值為String類型時,應(yīng)該如何處理?

3.3.1 將 StringHttpMessageConverter 去掉。

3.3.2 在統(tǒng)一數(shù)據(jù)返回的時候,單獨處理String類型,讓其返回一個String字符串,而非 HashMap

?總結(jié):


前言:

一般Spring Boot統(tǒng)一功能處理模塊,也是AOP的實戰(zhàn)環(huán)節(jié),要實現(xiàn)課程目標有以下3個:

  • 統(tǒng)一用戶登錄權(quán)限驗證
  • 統(tǒng)一數(shù)據(jù)格式
  • 統(tǒng)一異常處理

一、用戶登錄權(quán)限驗證

1.1 SpringAOP可以進行處理嗎?

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class UserAspect {// 定義切點?法 controller 包下、?孫包下所有類的所有?法@Pointcut("execution(* com.example.demo.controller..*.*(..))")public void pointcut(){ }// 前置?法@Before("pointcut()")public void doBefore(){}// 環(huán)繞?法@Around("pointcut()")public Object doAround(ProceedingJoinPoint joinPoint){Object obj = null;System.out.println("Around ?法開始執(zhí)?");try {// 執(zhí)?攔截?法obj = joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}System.out.println("Around ?法結(jié)束執(zhí)?");return obj;}
}

我們知道SpringAOP雖然就提供了對用戶登錄的處理邏輯,但是存在一些問題:

  • 沒有辦法獲取HttpSession對象
  • 如果要對一部分方法攔截,一部分方法不攔截,這種情況很難處理。(比如注冊和登錄方法在用戶登錄權(quán)限驗證中是不能進行攔截的)

攔截器和SpringAOP雖然都是AOP的實現(xiàn)方式,但是這兩個其實是完全不同的技術(shù)體系。

Spring提供了具體的實現(xiàn)攔截器:HandlerInterceptor,該SpringBoot 攔截器實現(xiàn)分為以下兩個步驟:

  1. 自定義攔截器
  2. 將自定義攔截器配置到系統(tǒng)配置項,并且設(shè)置合理的攔截規(guī)則

1.2?創(chuàng)建自定義攔截器

自定義攔截器繼承HandlerInterceptor后,需要重寫相對應(yīng)的方法,這里我們重寫 preHandle方法:

?代碼如下:

package com.example.demo.common;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/*** 自定義攔截器*/
public class LoginInterceptor implements HandlerInterceptor {/*** 以下方法是調(diào)用目標方法之前執(zhí)行的方法。此方法返回boolean類型的值* 返回true標識驗證成功,程序會繼續(xù)執(zhí)行后續(xù)流程* 返回false, 表示攔截器攔截失敗, 驗證未通過, 后續(xù)的流程和目標方法不再執(zhí)行。* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic 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) {// 用戶已經(jīng)登錄return true;}return false;}
}

?1.3?將自定義攔截器配置到系統(tǒng)配置項中

?重寫addInterceptors方法:

?設(shè)置攔截規(guī)則,代碼如下

package com.example.demo.config;import com.example.demo.common.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;public class MyConfig implements WebMvcConfigurer {@AutowiredLoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**") //攔截所有的url.excludePathPatterns("user/login") // url為:user/login 不進行攔截 以下同理.excludePathPatterns("user/reg").excludePathPatterns("image/**"); // image夾目錄下的所有url都不進行攔截}
}

或者使用Spring方法,通過DI注入的方式,這樣可以實現(xiàn)不用new一個實例:

首先需要將攔截器添加到spring中,也就是給其添加一個五大類注解,這里我們就使用@Component。接著就可以使用@Autowired來得到實例。

?其中:

  • addPathPatterns: 表示需要攔截的URL,“**”表示攔截任意方法(也就是所有方法)。
  • excludePathPatterns: 表示需要排除的URL。

?說明:以上攔截規(guī)則可以攔截此項目中的URL,包括靜態(tài)文件(圖片文件,JS和CSS等文件)。

1.4 攔截器的實現(xiàn)原理

下面我們先來看一組正常情況下的調(diào)用順序:

然而有了攔截器之后,會在調(diào)用Controller之前進行相應(yīng)的業(yè)務(wù)處理,執(zhí)行的流程如下圖所示:

1.4.1 實現(xiàn)原理源碼分析

所有的Controller執(zhí)行都會通過一個調(diào)度器DispatcherServlet來實現(xiàn),這一點可以從Spring Boot控制臺的打印信息看出,如下圖所示:

在IDEA中,通過全局搜索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 {processedRequest = this.checkMultipart(request);multipartRequestParsed = processedRequest != request;mappedHandler = this.getHandler(processedRequest);if (mappedHandler == null) {this.noHandlerFound(processedRequest, response);return;}HandlerAdapter ha = this.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;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 實現(xiàn)Controller的業(yè)務(wù)邏輯mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}this.applyDefaultViewName(processedRequest, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception var20) {dispatchException = var20;} catch (Throwable var21) {dispatchException = new NestedServletException("Handler dispatch failed", var21);}this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);} catch (Exception var22) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);} catch (Throwable var23) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));}} finally {if (asyncManager.isConcurrentHandlingStarted()) {if (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}} else if (multipartRequestParsed) {this.cleanupMultipart(processedRequest);}}}

觀察DispatcherServlet中的某段代碼:

我們發(fā)現(xiàn),在執(zhí)行后續(xù)的Controller代碼之前,都會先執(zhí)行這個applyPreHandle方法,于是鼠標雙擊 applyPreHandle,得到代碼如下:

從上述源碼可以看出,在applyPreHandle中會獲取所有的攔截器HandlerInterceptor并執(zhí)行攔截器中的preHandle方法,這樣就和之前定義的攔截器對應(yīng)上了,如下圖所示:

package com.example.demo.common;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
public class LoginInterceptor implements HandlerInterceptor {/*** 以下方法是調(diào)用目標方法之前執(zhí)行的方法。此方法返回boolean類型的值* 返回true標識驗證成功,程序會繼續(xù)執(zhí)行后續(xù)流程* 返回false, 表示攔截器攔截失敗, 驗證未通過, 后續(xù)的流程和目標方法不再執(zhí)行。* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic 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) {// 用戶已經(jīng)登錄return true;}response.setContentType("application/json");response.setCharacterEncoding("utf8");response.getWriter().println("asdasd");return false;}
}

1.5 統(tǒng)一訪問前綴添加

所有請求地址添加api前綴:

代碼如下:

package com.example.demo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class AppConfig implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("fox", c -> true);}
}

二、統(tǒng)一異常處理

2.1 為什么需要使用統(tǒng)一異常處理?

通俗來講,統(tǒng)一異常處理的主要目的是為了方便前端,讓其更好的處理后端的信息,盡量將邏輯處理這塊放置于后端,前端的目的其實主要是為用戶服務(wù)。

比如:可以跟前端約定出現(xiàn)異常報錯時候的狀態(tài)碼是多少,這樣方便前端的處理,也方便后續(xù)后端在日志文件中將其找到,并修改異常。

2.2 統(tǒng)一異常處理的實現(xiàn)

統(tǒng)一異常處理使用的是@ControllerAdvice + @ExceptionHandler 來實現(xiàn)的,@ControllerAdvice表示控制器通知類, @ExceptionHandler是異常處理器,兩個結(jié)合表示當出現(xiàn)異常的時候執(zhí)行某個通知,也就是執(zhí)行某個方法事件,具體實現(xiàn)代碼如下:

以上方法表示,如果出現(xiàn)了異常就返回給前端一個HashMap對象, 其中包含的字段如代碼定義那樣。

?注意:

方法名和返回值都是可以自定義的,另外 @ExceptionHandler()中的參數(shù)是可以選擇的,這里是Exception.class:表示的是可以在程序拋出異常的時候執(zhí)行這里的代碼,讓其返回數(shù)據(jù)給前端,如果填入的參數(shù)是NullPointerException:那么表示的是當程序出現(xiàn)空指針異常的時候,會執(zhí)行這里的代碼。

這里的實現(xiàn)邏輯和Java中的異常處理是相似的,如果開發(fā)者有對Exception和NullPointerException分別進行了處理,那么當程序出現(xiàn)NullPointerException異常的時候,還是會根據(jù)我們寫的NullPointerException執(zhí)行邏輯進行處理,并不會直接走Exception的邏輯。

示例如下:

訪問頁面后效果如下:

總結(jié):當有多個異常通知時,匹配順序為當前類及其子類向上依次匹配。

三、統(tǒng)一數(shù)據(jù)返回格式

3.1 為什么需要統(tǒng)一數(shù)據(jù)返回格式?

統(tǒng)一數(shù)據(jù)返回格式的優(yōu)點如下,比如以下幾個:

  • 方便前端程序員更好的接受和解析后端數(shù)據(jù)接口的數(shù)據(jù)
  • 降低前端程序員和后端程序員的溝通成本
  • 有利于項目統(tǒng)一數(shù)據(jù)的維護和修改
  • 有利于后端技術(shù)部門的統(tǒng)一規(guī)范的標準制定,不會出現(xiàn)稀奇古怪的返回內(nèi)容

3.2 統(tǒng)一數(shù)據(jù)返回格式的實現(xiàn)

統(tǒng)一的數(shù)據(jù)返回格式可以使用@ControllerAdvice + ResponseBodyAdvice 的方式實現(xiàn),具體實現(xiàn)代碼如下:

package com.example.demo.common;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.ResponseBodyAdvice;import java.util.HashMap;/*** 統(tǒng)一數(shù)據(jù)格式處理*/
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {/*** 是否執(zhí)行 beforeBodyWrite 方法, 返回 true 就執(zhí)行, 返回 false 就不執(zhí)行* @param returnType* @param converterType* @return*/@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}/*** 返回數(shù)據(jù)之前進行數(shù)據(jù)重寫* @param body 原始返回值* @param returnType* @param selectedContentType* @param selectedConverterType* @param request* @param response* @return*/@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 這里我們規(guī)定統(tǒng)一的數(shù)據(jù)返回為HashMapif (body instanceof HashMap) {return body;}// 重寫返回結(jié)果,讓其返回一個統(tǒng)一的數(shù)據(jù)格式HashMap<String, Object> result = new HashMap<>();result.put("code",200);result.put("data",body);result.put("msg","");return result;}
}

?訪問user/login1:

經(jīng)過統(tǒng)一功能處理后代碼展現(xiàn)如下:

?3.3 返回值為String類型時,應(yīng)該如何處理?

?但是如果將返回值改為String類型,按照以上的執(zhí)行邏輯,那么就無法走上述的正常數(shù)據(jù)統(tǒng)一處理:

我們發(fā)現(xiàn),當返回類型為String的時候,程序會拋出異常,從而被我們的 統(tǒng)一異常處理模塊攔截。

觀察異常信息,發(fā)現(xiàn) 拋出異常:java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String

可能會感到奇怪,為什么會拋出這個異常呢?

下面我們來看看后端返回前端時候的執(zhí)行流程:

1.? 一開始,前端訪問該網(wǎng)址時,方法返回的是 String:

2. 統(tǒng)一數(shù)據(jù)返回之前會進行處理,將 String 轉(zhuǎn)換為 HashMap:

3. 將HaspMap轉(zhuǎn)換成 application/json 字符串給前端(接口)

這個步驟有兩種情況,先判斷原Body的類型:

  • 是 String 類型,那么就會使用 StringHttpMessageConverter 進行類型轉(zhuǎn)換
  • 如果不是 String 類型,那么使用 HttpMessageConverter 進行類型轉(zhuǎn)換

以上報錯就是因為原始Body是String類型,所以在類型轉(zhuǎn)換時候報錯了

解決方案有如下兩種:

  • 將 StringHttpMessageConverter 去掉。
  • 在統(tǒng)一數(shù)據(jù)返回的時候,單獨處理String類型,讓其返回一個String字符串,而非HashMap

3.3.1 將 StringHttpMessageConverter 去掉。

在配置文件中使用以下代碼即可;

package com.example.demo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;@Configuration
public class MyConfig implements WebMvcConfigurer {/*** 移除 StringHttpMessageConverter* @param converters*/@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);}
}

?訪問地址后顯示如下:

3.3.2 在統(tǒng)一數(shù)據(jù)返回的時候,單獨處理String類型,讓其返回一個String字符串,而非 HashMap

引入ObjectMapper(ObjectMapper?是Jackson庫中的一個類,用于在Java對象(POJO,Plain Old Java Objects)和JSON數(shù)據(jù)之間進行相互轉(zhuǎn)換):

對Body為String進行單獨處理:?

訪問頁面如下所示:

?總結(jié):

本文主要介紹了統(tǒng)一用戶登錄權(quán)限的效驗,使用WebMvcConfigurer + HandlerInterceptor 來實現(xiàn)。統(tǒng)一異常處理使用 @ControllerAdvice + @ExceptionHandler 來實現(xiàn),統(tǒng)一返回值處理使用@ControllerAdvice + ResponseBodyAdvice來處理。

http://www.risenshineclean.com/news/29869.html

相關(guān)文章:

  • ftp是專門提供文件傳輸?shù)木W(wǎng)站百度注冊新賬號
  • 品牌seo公司焦作關(guān)鍵詞優(yōu)化排名
  • 建網(wǎng)站的服務(wù)器學(xué)電商出來一般干什么工作
  • 創(chuàng)意個人網(wǎng)站設(shè)計大冶seo網(wǎng)站優(yōu)化排名推薦
  • 律師網(wǎng)站深圳網(wǎng)站設(shè)計百度app在哪里找
  • 黔東南網(wǎng)頁設(shè)計seo搜索引擎優(yōu)化人員
  • wordpress掃碼收款seo網(wǎng)絡(luò)營銷課程
  • 公司做的網(wǎng)站賬務(wù)處理淘寶關(guān)鍵詞搜索量查詢
  • 開發(fā)公司人效比seo排名培訓(xùn)學(xué)校
  • 做網(wǎng)站彩票代理犯法嗎我是站長網(wǎng)
  • php做網(wǎng)站網(wǎng)絡(luò)營銷有什么崗位
  • 國內(nèi)可以做的國外兼職網(wǎng)站海外營銷方案
  • 專門做微信推送的網(wǎng)站搜索引擎優(yōu)化要考慮哪些方面?
  • 海北高端網(wǎng)站建設(shè)哪家好網(wǎng)站推廣途徑和推廣要點
  • 網(wǎng)站建設(shè)方案書深圳關(guān)鍵詞推廣優(yōu)化
  • 東營本地網(wǎng)站制作公司可以入侵的網(wǎng)站
  • 公司網(wǎng)站維護該誰來做全網(wǎng)營銷外包
  • java可以做微信網(wǎng)站么站長統(tǒng)計工具
  • 做域名后就得做網(wǎng)站嗎河北高端網(wǎng)站建設(shè)
  • 網(wǎng)站title是什么培訓(xùn)機構(gòu)加盟店排行榜
  • 網(wǎng)站備案 取名資訊通不過外貿(mào)網(wǎng)站推廣費用
  • 去除wordpress相冊系統(tǒng)優(yōu)化工具
  • 做網(wǎng)站的回扣什么是seo?
  • 蘇州做門戶網(wǎng)站的公司公司網(wǎng)站怎么優(yōu)化
  • 中國建設(shè)銀行移動門戶網(wǎng)站百度推廣客戶端app
  • 阿里巴巴網(wǎng)站做推廣效果怎么樣如何制作一個網(wǎng)址
  • 重慶福彩建站2022新聞熱點10條
  • 怎么把網(wǎng)站做火seo入門培訓(xùn)課程
  • 泰國做彩票網(wǎng)站企業(yè)網(wǎng)站營銷的實現(xiàn)方式
  • 大數(shù)據(jù)技術(shù)建設(shè)網(wǎng)站百度地圖人工電話