SpringBoot配置自定義攔截器實現過程詳解
1. HttpServletRequest包裝類
因為HttpServletRequest隻能讀取一次,所以需要對request進行包裝,變成可重復讀的request.
package net.lesscoding.interceptor; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; /** * 由於流隻能讀取一次,所以使用此包裝類對HttpServletRequest對象進行包裝,讀取完之後再將 * 內容塞回去,不影響後續springmvc的參數處理。 */ public class RequestWrapper extends HttpServletRequestWrapper { private String body; public RequestWrapper(HttpServletRequest request) { super(request); if (request.getHeader("Content-Type") != null && request.getHeader("Content-Type").contains("multipart/form-data")){ try{ request.getParts(); }catch (Exception e){ e.printStackTrace(); } } StringBuilder stringBuilder = new StringBuilder(); try (InputStream inputStream = request.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))){ char[] charBuffer = new char[128]; int bytesRead = -1; while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { stringBuilder.append(charBuffer, 0, bytesRead); } }catch (NullPointerException ex){ stringBuilder.append(""); } catch (Exception ex) { } body = stringBuilder.toString(); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); ServletInputStream servletInputStream = new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() throws IOException { return byteArrayInputStream.read(); } }; return servletInputStream; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream())); } public String getBody() { return body; } public void setBody(String body) { this.body = body; } }
2. 使用Filter將request傳遞下去
因為filter是在request前邊執行的,所以我們需要使用一個filter將我們包裝好的request傳遞下去,讓後邊使用的request都是我們包裝好的,防止出現流已經被讀取的錯誤出現
package net.lesscoding.filter; import net.lesscoding.interceptor.RequestWrapper; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * @apiNote 傳遞request的過濾器 */ public class RepeatedlyReadFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if(request instanceof HttpServletRequest){ requestWrapper = new RequestWrapper((HttpServletRequest) request); } chain.doFilter( requestWrapper == null ? request : requestWrapper,response ); } @Override public void destroy() { } }
3. 添加攔截器
這裡我們添加一個判斷用戶登錄狀態的攔截器,從 request中獲取token信息,查詢redis如果redis存在則用戶已經登錄,否則就返回false
package net.lesscoding.interceptor; import cn.hutool.core.util.StrUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.concurrent.TimeUnit; /** * @apiNote 登錄攔截器 */ @Configuration public class LoginInterceptor implements HandlerInterceptor { @Autowired private RedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("AccessToken"); String redisToken = String.valueOf(redisTemplate.opsForValue().get(token)); if(StrUtil.isBlank(redisToken)){ throw new RuntimeException("token失效,請重新登錄"); } // 這裡為瞭方便 成功之後就刷新在redis中的時間 redisTemplate.opsForValue().set("token",redisToken,30, TimeUnit.MINUTES); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
4. 全局異常處理器
使用全局異常處理器捕獲攔截器拋出的異常信息,做統一返回
package net.lesscoding.config; import lombok.extern.slf4j.Slf4j; import net.lesscoding.common.Result; import net.lesscoding.common.ResultFactory; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * @apiNote 全局異常處理器 */ @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { @ExceptionHandler(value = RuntimeException.class) public Result runtimeExceptionHandler(RuntimeException e){ e.printStackTrace(); log.error("{}", e.getMessage()); return ResultFactory.buildThrowable(e); } @ExceptionHandler(value = Exception.class) public Result exceptionHandler(Exception e){ e.printStackTrace(); log.error("{}", e.getMessage()); return ResultFactory.buildThrowable(e); } @ExceptionHandler(value = Throwable.class) public Result exceptionHandler(Throwable t){ t.printStackTrace(); log.error("{}", t.getMessage()); return ResultFactory.buildThrowable(t); } }
5. 配置攔截器
對攔截器進行註冊,指定攔截哪些url請求
package net.lesscoding.config; import net.lesscoding.filter.RepeatedlyReadFilter; import net.lesscoding.interceptor.LoginInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @apiNote 對項目進行配置攔截器 */ @Configuration public class LoginConfiguration implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Bean public FilterRegistrationBean repeatedlyReadFilter(){ FilterRegistrationBean registration = new FilterRegistrationBean(); RepeatedlyReadFilter repeatedlyReadFilter = new RepeatedlyReadFilter(); registration.setFilter(repeatedlyReadFilter); registration.addUrlPatterns("/*"); return registration; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) // 攔截所有請求 .addPathPatterns("/**") // 排除登錄註冊修改密碼等接口 .excludePathPatterns("/oauth/**","/login/**","logout/**","/common/**", "options","/try/**","/user/updatePwd") // 判處swagger等接口 .excludePathPatterns("/doc.html","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**","/favicon.ico") ; } }
到此這篇關於SpringBoot配置自定義攔截器實現過程詳解的文章就介紹到這瞭,更多相關SpringBoot自定義攔截器內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- SpringBoot 過濾器與攔截器實例演示
- 在攔截器中讀取request參數,解決在controller中無法二次讀取的問題
- CorsFilter 過濾器解決跨域的處理
- SpringBoot 請求參數忽略大小寫的實例
- 使用ServletInputStream在攔截器或過濾器中應用後重寫