SpringBoot全局異常處理方式
異常處理方案分類
異常處理主要分為三類:
- 基于請求轉(zhuǎn)發(fā)的方式處理異常;
- 基于異常處理器的方式處理異常;
- 基于過濾器的方式處理異常。
基于請求轉(zhuǎn)發(fā)
基于請求轉(zhuǎn)發(fā)的異常處理方式是真正的全局異常處理。
實(shí)現(xiàn)方式有:
- BasicExceptionController
基于異常處理器
基于異常處理器的異常處理方式其實(shí)并不是真正的全局異常處理,因?yàn)樗幚聿涣诉^濾器等拋出的異常。
實(shí)現(xiàn)方式有:
- @ExceptionHandler
- @ControllerAdvice+@ExceptionHandler
- SimpleMappingExceptionResolver
- HandlerExceptionResolver
基于過濾器
基于過濾器的異常處理方式近似與全局異常處理。它能處理過濾器及之后的環(huán)節(jié)拋出的異常。
實(shí)現(xiàn)方式有:
- Filter
常見異常處理實(shí)現(xiàn)方案
1. BasicExceptionController
這是SpringBoot默認(rèn)處理異常方式:一旦程序中出現(xiàn)了異常SpringBoot就會(huì)請求/error的url,在SpringBoot中提供了一個(gè)叫BasicExceptionController的類來處理/error請求,然后跳轉(zhuǎn)到默認(rèn)顯示異常的頁面來展示異常信息。顯示異常的頁面也可以自定義,在目錄src/main/resources/templates/下定義一個(gè)叫error的文件,可以是jsp也可以是html 。
此種方式是通過請求轉(zhuǎn)發(fā)實(shí)現(xiàn)的,出現(xiàn)異常時(shí),會(huì)轉(zhuǎn)發(fā)到請求到/error,該接口對異常進(jìn)行處理返回。是最符合全局異常處理的。
可以自定義Controller繼承BasicErrorController異常處理來實(shí)現(xiàn)異常處理的自定義。
@Slf4j
@RestController
public class MyErrorController extends BasicErrorController {
public MyErrorController() {
super(new DefaultErrorAttributes(), new ErrorProperties());
}
/**
* produces 設(shè)置返回的數(shù)據(jù)類型:application/json
* @param request 請求
* @return 自定義的返回實(shí)體類
*/
@Override
@RequestMapping(value = "", produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
// 獲取錯(cuò)誤信息
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
String code = body.get("status").toString();
String message = body.get("message").toString();
return new ResponseEntity(ApiUtil.fail(message), HttpStatus.OK);
}
}需要注意
1.該種方式能獲取到的信息時(shí)有限的。一般情況只能獲取到下面這幾個(gè)參數(shù)(特殊情況會(huì)有補(bǔ)充參數(shù))。

現(xiàn)在一般項(xiàng)目需要的響應(yīng)信息都是自定義統(tǒng)一格式的JSON(code、msg、data)。對于自定義業(yè)務(wù)錯(cuò)誤碼code不好得到,對于錯(cuò)誤信息msg有時(shí)得到的也不一定是你所想要的(簡單說就是一些特殊的異常描述信息不好得到)。
比如:自定義的參數(shù)校驗(yàn)信息
@NotNull(message = "主鍵不能為空")

message參數(shù)取到的并不是“主鍵不能為空”。
2.當(dāng)出現(xiàn)拋出兩次異常,第一次被異常處理器處理,第二次異常轉(zhuǎn)由BasicExceptionController處理。但能取到的異常信息可能是一次的,具體原因下面有分析。
2. @ExceptionHandler
該種方式只能作用于使用@ExceptionHandler注解的Controller的異常,對于其他Controller的異常就無能為力了,所以并不不推薦使用。
此種方式是通過異常處理器實(shí)現(xiàn)的,使用HandlerExceptionResolverComposite異常處理器中的ExceptionHandlerExceptionResolver異常處理器處理的。
@RestController
public class TestController {
@GetMapping("test9")
public FundInfo test9() throws Exception {
throw new Exception("test9 error");
}
@GetMapping("test10")
public FundInfo test10() throws Exception {
throw new IOException("test10 error");
}
@ExceptionHandler(Exception.class)
public ApiResult exceptionHandler(Exception e) {
return ApiUtil.custom(500, e.getMessage());
}
}注意:如果既在具體Controller使用了@ExceptionHandler,也定義了全局異常處理器類(@ControllerAdvice+@ExceptionHandler),優(yōu)先使用Controller定義的@ExceptionHandler處理。如果處理不了,才會(huì)使用全局異常處理器處理。
3. @ControllerAdvice+@ExceptionHandler
使用 @ControllerAdvice+@ExceptionHandler注解能夠進(jìn)行近似全局異常處理,這種方式推薦使用。
一般說它只能處理控制器中拋出的異常,這種說法并不準(zhǔn)確,其實(shí)它能處理DispatcherServlet.doDispatch方法中DispatcherServlet.processDispatchResult方法之前捕捉到的所有異常,包括:攔截器、參數(shù)綁定(參數(shù)解析、參數(shù)轉(zhuǎn)換、參數(shù)校驗(yàn))、控制器、返回值處理等模塊拋出的異常。
此種方式是通過異常處理器實(shí)現(xiàn)的,使用HandlerExceptionResolverComposite異常處理器中的ExceptionHandlerExceptionResolver異常處理器處理的。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
......省略代碼......
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
......省略代碼......
mappedHandler = getHandler(processedRequest);
......省略代碼......
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
......省略代碼......
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
......省略代碼......
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
......省略代碼......
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
......省略代碼......
}
catch (Throwable err) {
......省略代碼......
}
finally {
......省略代碼......
}
}使用方式
定義一個(gè)類,使用@ControllerAdvice注解該類,使用@ExceptionHandler注解方法。@RestControllerAdvice注解是@ControllerAdvice注解的擴(kuò)展(@RestControllerAdvice=@ControllerAdvice+@ResponseBody),返回值自動(dòng)為JSON的形式。
/**
* 全局異常處理器
*/
@Slf4j
@SuppressWarnings("ALL")
@RestControllerAdvice
public class MyGlobalExceptionHandler {
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.OK)
public ApiResult bindException(HttpServletRequest request,
HttpServletResponse response,
BindException exception) {
return ApiUtil.fail(exception.getBindingResult().getFieldError().getDefaultMessage());
}
@ExceptionHandler(org.springframework.web.bind.MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.OK)
public ApiResult methodArgumentNotValidException(HttpServletRequest request,
HttpServletResponse response,
MethodArgumentNotValidException exception) {
return ApiUtil.fail(exception.getBindingResult().getFieldError().getDefaultMessage());
}
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.OK)
public ApiResult methodArgumentNotValidException(HttpServletRequest request,
HttpServletResponse response,
MissingServletRequestParameterException exception) {
return ApiUtil.fail(exception.getMessage());
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.OK)
public ApiResult methodArgumentNotValidException(HttpServletRequest request,
HttpServletResponse response,
ConstraintViolationException exception) {
System.out.println(exception.getLocalizedMessage());
Iterator<ConstraintViolation<?>> iterator = exception.getConstraintViolations().iterator();
if (iterator.hasNext()) {
ConstraintViolationImpl next = (ConstraintViolationImpl)iterator.next();
return ApiUtil.fail(next.getMessage());
}
return ApiUtil.fail(exception.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.OK)
public ApiResult exception(HttpServletRequest request,
HttpServletResponse response,
Exception exception) {
return ApiUtil.fail(exception.getMessage());
}
}@ResponseStatus注解
作用:指定http狀態(tài)碼,正確執(zhí)行時(shí)返回該狀態(tài)碼,但方法執(zhí)行報(bào)錯(cuò)時(shí),該返回啥狀態(tài)碼就是啥狀態(tài)碼,指定的狀態(tài)碼無效。
4. SimpleMappingExceptionResolver
使用簡單映射異常處理器處理異常,通過配置SimpleMappingExceptionResolver類也是進(jìn)行近似全局異常處理,但該種方式不能得到具體的異常信息,且返回的是視圖,不推薦使用。
此種方式是通過異常處理器實(shí)現(xiàn)的,使用SimpleMappingExceptionResolver異常處理器處理的。
@Configuration
public class GlobalExceptionConfig {
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
/**
* 參數(shù)一:異常的類型,這里必須要異常類型的全名
* 參數(shù)二:要跳轉(zhuǎn)的視圖名稱
*/
Properties mappings = new Properties();
mappings.put("java.lang.ArithmeticException", "error1");
mappings.put("java.lang.NullPointerException", "error1");
mappings.put("java.lang.Exception", "error1");
mappings.put("java.io.IOException", "error1");
// 設(shè)置異常與視圖的映射信息
resolver.setExceptionMappings(mappings);
return resolver;
}
}
5. HandlerExceptionResolver
實(shí)現(xiàn)HandlerExceptionResolver接口來處理異常,該種方式是近似全局異常處理。
此種方式是通過異常處理器實(shí)現(xiàn)的,使用自定義的異常處理器(實(shí)現(xiàn)HandlerExceptionResolver接口)處理的。
public class MyExceptionResolver extends AbstractHandlerExceptionResolver {
/**
* 異常解析器的順序, 數(shù)值越小,表示優(yōu)先級越高
* @return
*/
@Override
public int getOrder() {
return -999999;
}
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
try {
response.getWriter().write(JSON.toJSONString(ApiUtil.fail(ex.getMessage())));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}AbstractHandlerExceptionResolver類實(shí)現(xiàn)了HandlerExceptionResolver接口。
6. Filter
基于過濾器的異常處理方式,比異常處理器處理的范圍要大一些(能處理到Filter過濾器拋出的異常),更近似全局異常處理。使用自定義過濾器進(jìn)行異常處理時(shí),該過濾器應(yīng)該放到過濾鏈的第一個(gè)位置,這樣才能保證能處理到后續(xù)過濾器拋出的異常。
@Bean
ExceptionFilter exceptionFilter() {
return new ExceptionFilter();
}
@Bean
public FilterRegistrationBean exceptionFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(exceptionFilter());
registration.setName("exceptionFilter");
//此處盡量小,要比其他Filter靠前
registration.setOrder(-1);
return registration;
}/**
* 自定義異常過濾器
* 用于處理Controller外拋出的異常(如Filter拋出的異常)
*/
@Slf4j
public class ExceptionFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException,IOException {
try {
filterChain.doFilter(httpServletRequest, httpServletResponse);
} catch (IOException e) {
httpServletResponse.getWriter().write(JSON.toJSONString(ApiUtil.fail(e.getMessage())));
}
}
}上面的寫法其實(shí)還是有一定問題的,如果進(jìn)入了catch就會(huì)重復(fù)寫入httpServletResponse,可能會(huì)導(dǎo)致產(chǎn)生一些列的問題。
舉例一個(gè)問題來說明,通過上面的寫法,這樣的對響應(yīng)的寫入一般是累加的,可能會(huì)導(dǎo)致返回的數(shù)據(jù)格式有問題,比如:當(dāng)異常處理器處理了Controller拋出的異常,寫入了響應(yīng),然后過濾器又拋出了異常,被ExceptionFilter給catch到,這就有一次處理了異常,寫入了響應(yīng),最后的到的響應(yīng)數(shù)據(jù)可能是這樣的:
{
"code": 500,
"msg": "Controller error"
}{
"code": 505,
"msg": "Filter error"
}這個(gè)時(shí)候我們一般會(huì)使用代理類來再次封裝Response,filterChain.doFilter傳遞的是封裝后的代理類。
Response代理類
/**
* Response代理類
*/
public class ResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private PrintWriter printWriter = new PrintWriter(outputStream);
public ResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener writeListener) {
}
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
@Override
public void write(byte[] b) throws IOException {
outputStream.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
outputStream.write(b, off, len);
}
@Override
public void flush() throws IOException {
outputStream.flush();
}
};
}
@Override
public PrintWriter getWriter() throws IOException {
return printWriter;
}
public void flush(){
try {
printWriter.flush();
printWriter.close();
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public byte[] getContent() {
flush();
return outputStream.toByteArray();
}
}自定義過濾器類修改為
@Slf4j
public class ExceptionFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException,IOException {
try {
// 封裝Response,得到代理對象
ResponseWrapper responseWrapper = new ResponseWrapper(httpServletResponse);
// 使用代理對象
filterChain.doFilter(httpServletRequest, responseWrapper);
// 讀取響應(yīng)內(nèi)容
byte[] bytes = responseWrapper.getContent();
// 這里可以對響應(yīng)內(nèi)容進(jìn)行修改等操作
// 模擬Filter拋出異常
if (true) {
throw new IOException("Filter error");
}
// 內(nèi)容重新寫入原響應(yīng)對象中
httpServletResponse.getOutputStream().write(bytes);
} catch (Exception e) {
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
httpServletResponse.getOutputStream().write(JSON.toJSONString(ApiUtil.fail(e.getMessage())).getBytes());
}
}
}全局異常處理實(shí)現(xiàn)方案
要想實(shí)現(xiàn)正在的全局異常處理,顯然只通過異常處理器的方式處理是不夠的,這種方案處理不了過濾器等拋出的異常。
全局異常處理的幾種實(shí)現(xiàn)方案:
- 基于請求轉(zhuǎn)發(fā);
- 基于異常處理器+請求轉(zhuǎn)發(fā)補(bǔ)充;
- 基于過濾器;
- 基于異常處理器+過濾器補(bǔ)充。
1. 請求轉(zhuǎn)發(fā)
該方案貌似不好獲取到特殊的異常描述信息(沒仔細(xì)研究),如參數(shù)校驗(yàn)中的message屬性信息:
@NotNull(message = "主鍵不能為空")
本方案通過自定義錯(cuò)誤處理Controller繼承BasicExceptionController來實(shí)現(xiàn)。
具體實(shí)現(xiàn)參考:常用異常處理實(shí)現(xiàn)方案1。
2. 異常處理器+請求轉(zhuǎn)發(fā)補(bǔ)充
(1)自定義異常處理Controller實(shí)現(xiàn)BasicExceptionController
具體實(shí)現(xiàn)參考:常用異常處理實(shí)現(xiàn)方案1。
(2)異常處理器實(shí)現(xiàn)
- 方式1:@ControllerAdvice+@ExceptionHandler(推薦使用)
具體實(shí)現(xiàn)參考:常用異常處理實(shí)現(xiàn)方案3。 - 方式2:SimpleMappingExceptionResolver
具體實(shí)現(xiàn)參考:常用異常處理實(shí)現(xiàn)方案4。 - 方式3:HandlerExceptionResolver
具體實(shí)現(xiàn)參考:常用異常處理實(shí)現(xiàn)方案5。
3. 過濾器
具體實(shí)現(xiàn)參考:常用異常處理實(shí)現(xiàn)方案6。
4. 異常處理器+過濾器補(bǔ)充
創(chuàng)建自定義過濾器bean
@Bean
ExceptionFilter exceptionFilter() {
return new ExceptionFilter();
}
@Bean
public FilterRegistrationBean exceptionFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(exceptionFilter());
registration.setName("exceptionFilter");
//此處盡量小,要比其他Filter靠前
registration.setOrder(-1);
return registration;
}方式1:@ControllerAdvice+@ExceptionHandler+Filter(推薦使用)
@ControllerAdvice+@ExceptionHandler的實(shí)現(xiàn)參考:常用異常處理實(shí)現(xiàn)方案3。
Filter實(shí)現(xiàn):
- 方式1:參考常用異常處理實(shí)現(xiàn)方案6。
- 方式2:借助異常處理器處理異常。
@Slf4j
public class ExceptionFilter extends OncePerRequestFilter {
/**
* 遇到的坑,ExceptionFilter對象的創(chuàng)建沒有交給Spring容器(直接new的),導(dǎo)致@Autowired注入不會(huì)生效
*/
@Autowired
private HandlerExceptionResolver handlerExceptionResolver;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException,IOException {
try {
// 封裝Response,得到代理對象
ResponseWrapper responseWrapper = new ResponseWrapper(httpServletResponse);
// 使用代理對象
filterChain.doFilter(httpServletRequest, responseWrapper);
// 讀取響應(yīng)內(nèi)容
byte[] bytes = responseWrapper.getContent();
// 這里可以對響應(yīng)內(nèi)容進(jìn)行修改等操作
// 模擬Filter拋出異常
if (true) {
throw new IOException("Filter error");
}
// 內(nèi)容重新寫入原響應(yīng)對象中
httpServletResponse.getOutputStream().write(bytes);
} catch (Exception e) {
handlerExceptionResolver.resolveException(httpServletRequest, httpServletResponse, null, e);
}
}
}注入的HandlerExceptionResolver其實(shí)是HandlerExceptionResolverComposite異常處理器,最終是使用異常處理器中的ExceptionHandlerExceptionResolver異常處理器處理的。
方式2:HandlerExceptionResolver+Filter
HandlerExceptionResolver的實(shí)現(xiàn)參考:常用異常處理實(shí)現(xiàn)方案5。
Filter的實(shí)現(xiàn):注入的MyExceptionResolver是我們自定義的異常處理器。
- 方式1:參考常用異常處理實(shí)現(xiàn)方案6。
- 方式2:借助異常處理器處理異常。
@Slf4j
public class ExceptionFilter extends OncePerRequestFilter {
@Autowired
private MyExceptionResolver myExceptionResolver;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException,IOException {
try {
// 封裝Response,得到代理對象
ResponseWrapper responseWrapper = new ResponseWrapper(httpServletResponse);
// 使用代理對象
filterChain.doFilter(httpServletRequest, responseWrapper);
// 讀取響應(yīng)內(nèi)容
byte[] bytes = responseWrapper.getContent();
// 這里可以對響應(yīng)內(nèi)容進(jìn)行修改等操作
// 模擬Filter拋出異常
if (true) {
throw new IOException("Filter error");
}
// 內(nèi)容重新寫入原響應(yīng)對象中
httpServletResponse.getOutputStream().write(bytes);
} catch (Exception e) {
myExceptionResolver.resolveException(httpServletRequest, httpServletResponse, null, e);
}
}
}
注意事項(xiàng)
- 2、4兩種通過組合的方式進(jìn)行異常處理需要考慮到的問題:對于一個(gè)請求,如果兩個(gè)地方都捕捉到了異常,要考慮兩次異常處對response響應(yīng)信息的重復(fù)寫入問題。
- 比如:異常處理器處理了控制器拋出的異常,寫入響應(yīng);過濾器處理了過濾器拋出的異常,寫入響應(yīng)。這就會(huì)出現(xiàn)響應(yīng)被寫入了兩次的問題或者第二次寫入響應(yīng)直接報(bào)錯(cuò)。
- 一些處理思路:考慮使用Response代理類。第一次處理時(shí),異常處理器寫入的響應(yīng)信息是寫入到Response代理對象的,并可以從Response代理類中得到寫入的響應(yīng)信息;第二次處理,過濾器等寫入的響應(yīng)寫入到Response原對象中的。
- 過程中發(fā)現(xiàn)一個(gè)問題:通過BasicExceptionController+異常處理器處理異常的方式時(shí)。Controller拋出了異常,被異常處理器處理,返回的過程中,F(xiàn)ilter又拋出了一個(gè)異常,被BasicExceptionController處理,但BasicExceptionController的到的異常信息卻是Controller產(chǎn)生的異常信息,而不是Filter產(chǎn)生的異常信息。但是調(diào)到BasicExceptionController去處理異常又卻是是因?yàn)镕ilter拋出異常產(chǎn)生的。
- 個(gè)人猜想:異常處理器在處理異常時(shí),不僅是把響應(yīng)內(nèi)容部部分寫入了Response,還把異常信息寫入了Response。當(dāng)因?yàn)楫惓LD(zhuǎn)到BasicExceptionController進(jìn)行處理,BasicExceptionController在獲取異常信息時(shí),會(huì)先從Response獲取異常信息,獲取不到才會(huì)從異常中獲取異常信息。
方案推薦
請求轉(zhuǎn)發(fā)(推薦)。
- 完全統(tǒng)一的全局異常處理,自定義異常處理Controller能達(dá)到自定義統(tǒng)一響應(yīng)信息格式目的。
- 但是,現(xiàn)在一般項(xiàng)目需要的響應(yīng)信息都是自定義統(tǒng)一格式的JSON(code、msg、data)。但對于自定義業(yè)務(wù)錯(cuò)誤碼code不好得到,對于錯(cuò)誤信息msg有時(shí)得到的也不一定是你所想要的。
- 但感覺通過自定義的擴(kuò)展是能得到業(yè)務(wù)狀態(tài)碼和特殊異常描述信息的(沒詳細(xì)研究)。
異常處理+請求轉(zhuǎn)發(fā)補(bǔ)充(個(gè)人最推薦)。
- 推薦使用
@ControllerAdvice+@ExceptionHandler+BasicExceptionController的方式。 - 異常處理器能自定義處理大多異常(包括特殊的異常),剩余處理不到的異常交給異常處理控制器處理。
過濾器(不推薦)。
- 異常處理全需要手寫代碼實(shí)現(xiàn),自己的代碼肯定不會(huì)太完美,可能有沒考慮到的情況,容易出問題;
- 且過濾器之前拋出的異常處理不到
異常處理器+過濾器補(bǔ)充(不太推薦)。
- 推薦使用
@ControllerAdvice+@ExceptionHandler+Filter(借助異常處理器處理異常)的方式 - 但過濾器之前拋出的異常處理不到
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java 較大數(shù)據(jù)量取差集,list.removeAll性能優(yōu)化詳解
這篇文章主要介紹了java 較大數(shù)據(jù)量取差集,list.removeAll性能優(yōu)化詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
java實(shí)現(xiàn)CSV文件導(dǎo)入與導(dǎo)出功能
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)CSV文件導(dǎo)入與導(dǎo)出,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08
SpringBoot默認(rèn)使用HikariDataSource數(shù)據(jù)源方式
這篇文章主要介紹了SpringBoot默認(rèn)使用HikariDataSource數(shù)據(jù)源方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Spring Security SecurityContextHolder組件示例說明
SpringSecurity的SecurityContextHolder組件是存儲(chǔ)當(dāng)前安全上下文的地方,包括認(rèn)證用戶信息,它支持全局訪問、線程局部存儲(chǔ)和上下文傳播,是SpringSecurity認(rèn)證和授權(quán)的核心,文章通過示例展示了如何訪問已認(rèn)證用戶的詳細(xì)信息、手動(dòng)設(shè)置認(rèn)證信息以及使用認(rèn)證信息保護(hù)方法2024-11-11
MyBatis分頁查詢返回list的時(shí)候出現(xiàn)null的問題
這篇文章主要介紹了MyBatis分頁查詢返回list的時(shí)候出現(xiàn)null的問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
Springboot集成定時(shí)器和多線程異步處理操作
這篇文章主要介紹了Springboot集成定時(shí)器和多線程異步處理操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09

