最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringController返回值和異常自動(dòng)包裝的問題小結(jié)

 更新時(shí)間:2024年03月13日 10:44:15   作者:applebomb  
今天遇到一個(gè)需求,在不改動(dòng)原系統(tǒng)代碼的情況下,將Controller的返回值和異常包裝到一個(gè)統(tǒng)一的返回對(duì)象中去,下面通過本文給大家介紹SpringController返回值和異常自動(dòng)包裝的問題,需要的朋友可以參考下

今天遇到一個(gè)需求,在不改動(dòng)原系統(tǒng)代碼的情況下。將Controller的返回值和異常包裝到一個(gè)統(tǒng)一的返回對(duì)象中去。

例如原系統(tǒng)的接口

public String myIp(@ApiIgnore HttpServletRequest request);

返回的只是一個(gè)IP字符串"0:0:0:0:0:0:0:1",目前接口需要包裝為:

{"code":200,"message":"","result":"0:0:0:0:0:0:0:1","success":true}

而原異常跳轉(zhuǎn)到error頁面,需要調(diào)整為

{
  "success": false,
  "message": "For input string: \"fdsafddfs\"",
  "code": 500,
  "result": "message"
}

因此就有了2個(gè)工作子項(xiàng)需要完成:

1)Exception的處理

2)controller return值的處理

Exception的自動(dòng)包裝

返回的exception處理可以采用@RestControllerAdvice來處理。

建立自己的Advice類,注入國際化資源(異常需要支持多語言)

package org.ccframe.commons.mvc;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.ccframe.commons.filter.CcRequestLoggingFilter;
import org.ccframe.commons.util.BusinessException;
import org.ccframe.config.GlobalEx;
import org.ccframe.subsys.core.dto.Result;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.core.MethodParameter;
import org.springframework.http.ResponseEntity;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.NoHandlerFoundException;
import javax.servlet.http.HttpServletRequest;
import java.util.Locale;
@RestControllerAdvice
@Log4j2
public class GlobalRestControllerAdvice{
    private MessageSource messageSource; //國際化資源
    private LocaleResolver localeResolver;
    private Object[] EMPTY_ARGS = new Object[0];
    public GlobalRestControllerAdvice(MessageSource messageSource, LocaleResolver localeResolver){
        this.messageSource = messageSource;
        this.localeResolver = localeResolver;
    }
    private Result<String> createError(HttpServletRequest request, Exception e,int code, String msgKey, Object[] args){
        Locale currentLocale = localeResolver.resolveLocale(request);
        String message = "";
        try {
            message = messageSource.getMessage(msgKey, args, currentLocale);
        }catch (NoSuchMessageException ex){
            message = e.getMessage();
        }finally {
            log.error(message);
            CcRequestLoggingFilter.pendingLog(); //服務(wù)器可以記錄出錯(cuò)時(shí)的請(qǐng)求啦??
        }
        return Result.error(code, message, msgKey);
    }
    @ExceptionHandler(NoHandlerFoundException.class)
    public Result<?> handlerNoFoundException(HttpServletRequest request, Exception e) {
        return createError(request, e, HttpStatus.SC_NOT_FOUND, "error.mvc.uriNotFound", EMPTY_ARGS);
    }
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<?> httpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e){
        return createError(request,e, HttpStatus.SC_NOT_FOUND,"error.mvc.methodNotSupported",
            new Object[]{e.getMethod(), StringUtils.join(e.getSupportedMethods(), GlobalEx.DEFAULT_TEXT_SPLIT_CHAR)});
    }
    @ExceptionHandler(BusinessException.class)
    public Result<?> businessException(HttpServletRequest request, BusinessException e){
        return createError(request,e, HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMsgKey(), e.getArgs());
    }
    @ExceptionHandler(ObjectOptimisticLockingFailureException.class) //樂觀鎖異常
    public Result<?> objectOptimisticLockingFailureException(HttpServletRequest request, ObjectOptimisticLockingFailureException e){
        return createError(request,e, HttpStatus.SC_INTERNAL_SERVER_ERROR, "errors.db.optimisticLock", EMPTY_ARGS);
    }
    @ExceptionHandler(MaxUploadSizeExceededException.class) // 文件上傳超限,nginx請(qǐng)?jiān)O(shè)置為10M
    public Result<?> handleMaxUploadSizeExceededException(HttpServletRequest request, MaxUploadSizeExceededException e) {
        return createError(request, e, HttpStatus.SC_INTERNAL_SERVER_ERROR, "error.mvc.fileTooLarge", EMPTY_ARGS);
    }
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result<?> handleException(HttpServletRequest request, Exception e) {
        log.error(e);
        return createError(request,e, HttpStatus.SC_INTERNAL_SERVER_ERROR, "message", new Object[]{e.getMessage()});
    }
}
 

在Config類初始化該Bean(當(dāng)然也可以使用@Component支持掃描,隨你喜歡)

@Bean
	public GlobalRestControllerAdvice globalRestControllerAdvice(MessageSource messageSource, LocaleResolver localeResolver){
		return new GlobalRestControllerAdvice(messageSource, localeResolver);
	}

controller return值的自動(dòng)包裝

網(wǎng)上的例子有很多坑,包括使用HandlerMethodReturnValueHandler,看了源碼才發(fā)現(xiàn)。還是ResponseBodyAdvice好使。

建立自己的處理Bean

package org.ccframe.commons.mvc;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import org.apache.http.HttpStatus;
import org.ccframe.commons.util.JsonUtil;
import org.ccframe.subsys.core.dto.Result;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
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 springfox.documentation.swagger.web.ApiResourceController;
import java.util.regex.Pattern;
@ControllerAdvice
public class CcResponseBodyAdvice implements ResponseBodyAdvice<Object> {
    private static final Pattern CONTROLLER_PATTERN = Pattern.compile("^org\\.ccframe\\.(subsys|sdk)\\.[a-z0-9]+\\.controller\\.");
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return 
    // 只有自己的cotroller類才需要進(jìn)入,否則swagger都會(huì)掛了
CONTROLLER_PATTERN.matcher(returnType.getContainingClass().getName()).find();
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        System.out.println(returnType.getContainingClass());
        Result<Object> result = new Result<>();
        result.setResult(body);
        result.setCode(HttpStatus.SC_OK);
        if(body instanceof String){ //String返回要特殊處理
            return JSON.toJSONString(result);
        }else {
            return result;
        }
    }
}

如果你不需要根據(jù)正則來指定包,可以直接用RestControllerAdvice的basePackages屬性來過濾

注意這里有2個(gè)坑

1)String類型的返回被其它的轉(zhuǎn)換接口StringHttpMessageConverter處理,因此返回要進(jìn)行JSON編碼而不能返回其他類型,否則會(huì)報(bào)cast類型錯(cuò),因此就有了String部分的特殊處理方法。

2)controller方法簽名返回是void時(shí),不會(huì)被處理。為什么,有什么辦法?得看spring這段源碼:

當(dāng)returnValue==null時(shí),設(shè)置為RequestHandled,也就是提前結(jié)束了。后面任何返回的處理都不再進(jìn)行。所以,如果一定要返回null值的話,可以在controller里返回一個(gè)
return new ResponseEntity<Void>(HttpStatus.OK);
這樣在返回的值里面就有詳細(xì)的結(jié)構(gòu)了。

最后要生效的話,在Config類初始它:

@Bean
	public CcResponseBodyAdvice ccResponseBodyAdvice() {
		return new CcResponseBodyAdvice();
	}

最后。上面兩個(gè)Bean也可以寫在一個(gè),有興趣的自己嘗試。

---------------

null無法被BodyAdvice處理的問題。隨著源碼跟蹤,慢慢知道怎么回事了,我們嘗試根本來解決這個(gè)問題。從這個(gè)圖開始:

當(dāng)返回為null時(shí),mavContainer.isRequestHandled()為true導(dǎo)致了后面的沒有處理。

那么想當(dāng)然的,mavContainer.isRequestHandled()為flase不久解決了嗎,向前跟蹤,基本到MVC invoke的核心代碼里了,發(fā)現(xiàn)在invoke前,mavContainer.isRequestHandled()變成了true,再繼續(xù)跟蹤,找到這個(gè)方法:

在HandlerMethodArgumentResolverComposite的argumentResolvers看到了上面這個(gè)。進(jìn)行了setRequestHandled。HandlerMethodArgumentResolver是spring controller的參數(shù)自動(dòng)注入機(jī)制??戳讼略创a也沒有太多的擴(kuò)展點(diǎn),于是只能換個(gè)思路。

到此這篇關(guān)于SpringController返回值和異常自動(dòng)包裝的文章就介紹到這了,更多相關(guān)SpringController返回值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java反射超詳細(xì)講解

    java反射超詳細(xì)講解

    本文非常詳細(xì)的講解了java反射具體的內(nèi)容以及使用,java反射在現(xiàn)今的使用中很頻繁,希望此文可以幫大家解答疑惑,可以幫助大家理解
    2021-08-08
  • 淺談spring aop的五種通知類型

    淺談spring aop的五種通知類型

    這篇文章主要介紹了淺談spring aop的五種通知類型,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12
  • java實(shí)現(xiàn)在線聊天系統(tǒng)

    java實(shí)現(xiàn)在線聊天系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)在線聊天系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • 如何通過idea實(shí)現(xiàn)springboot集成mybatis

    如何通過idea實(shí)現(xiàn)springboot集成mybatis

    這篇文章主要介紹了如何通過idea實(shí)現(xiàn)springboot集成mybatis,使用springboot 集成 mybatis后,通過http請(qǐng)求接口,使得通過http請(qǐng)求可以直接操作數(shù)據(jù)庫,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • 舉例講解Java設(shè)計(jì)模式編程中Decorator裝飾者模式的運(yùn)用

    舉例講解Java設(shè)計(jì)模式編程中Decorator裝飾者模式的運(yùn)用

    這篇文章主要介紹了Java設(shè)計(jì)模式編程中Decorator裝飾者模式的運(yùn)用,裝飾者模式就是給一個(gè)對(duì)象動(dòng)態(tài)的添加新的功能,裝飾者和被裝飾者實(shí)現(xiàn)同一個(gè)接口,裝飾者持有被裝飾者的實(shí)例,需要的朋友可以參考下
    2016-05-05
  • mybatis中的擴(kuò)展實(shí)現(xiàn)源碼解析

    mybatis中的擴(kuò)展實(shí)現(xiàn)源碼解析

    這篇文章主要介給大家紹了關(guān)于mybatis中擴(kuò)展實(shí)現(xiàn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • 聊聊springmvc中controller的方法的參數(shù)注解方式

    聊聊springmvc中controller的方法的參數(shù)注解方式

    本篇文章主要介紹了聊聊springmvc中controller的方法的參數(shù)注解方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • 深入理解Java注解類型(@Annotation)

    深入理解Java注解類型(@Annotation)

    這篇文章主要介紹了深入理解Java注解類型(@Annotation),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • java阻塞隊(duì)列實(shí)現(xiàn)原理及實(shí)例解析

    java阻塞隊(duì)列實(shí)現(xiàn)原理及實(shí)例解析

    這篇文章主要介紹了java阻塞隊(duì)列實(shí)現(xiàn)原理及實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 使用 Spring Boot 實(shí)現(xiàn) WebSocket實(shí)時(shí)通信

    使用 Spring Boot 實(shí)現(xiàn) WebSocket實(shí)時(shí)通信

    本篇文章主要介紹了使用 Spring Boot 實(shí)現(xiàn) WebSocket實(shí)時(shí)通信,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10

最新評(píng)論

蕲春县| 鹰潭市| 广安市| 太康县| 南靖县| 苗栗市| 岢岚县| 峨山| 从化市| 江西省| 乐业县| 长治市| 南乐县| 天长市| 仪陇县| 淳安县| 浦东新区| 精河县| 莫力| 溆浦县| 兰溪市| 安庆市| 长寿区| 宣汉县| 大邑县| 吴川市| 民丰县| 丽水市| 延吉市| 泰兴市| 如皋市| 宁河县| 高州市| 孝义市| 阳春市| 五常市| 木里| 济南市| 界首市| 益阳市| 东台市|