自定義統一api返回json格式(app后台框架搭建三)


在統一json自定義格式的方式有多種:1,直接重寫@reposeBody的實現,2,自定義一個注解,自己去解析對象成為json字符串進行返回

第一種方式,我就不推薦,想弄得的話,可以自己去研究一下源碼

第二種方式,主要通過定義注解,通過 HandlerMethodReturnValueHandler 對返回值的處理,而不讓他進去viewResolver處理

 

==================================================================================

1,講解HandlerMethodReturnValueHandler 處理原理 (簡單介紹,網上資料很多)

2,如何實現自定義統一的json返回格式

==================================================================================

1,HandlerMethodReturnValueHandler 

HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用來處理完映射控制類方法返回的值處理,RequestMappingHandlerAdapter

類包含默認的值處理器鏈的所有處理引擎,默認是會加入handlers.add(new ModelAttributeMethodProcessor(true)); getDefaultReturnValueHandlers()方法里可以查看到所有默認的處理引擎。

對處理后的對象,會調用RequestMappingHandlerAdapter里invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)

 方法:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            invocableMethod.setDataBinderFactory(binderFactory);
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);

            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.setTaskExecutor(this.taskExecutor);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

            if (asyncManager.hasConcurrentResult()) {
                Object result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                if (logger.isDebugEnabled()) {
                    logger.debug("Found concurrent result value [" + result + "]");
                }
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }

            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }

            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }

關鍵是調用 invocableMethod.invokeAndHandle(webRequest, mavContainer);

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(getResponseStatusReason())) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }
首先設置 mavContainer.setRequestHandled(false);說明是會按處理鏈進行處理,如果設置為true就是處理完就結束了。
 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); 是真正獲取處理鏈,然后從處理鏈中選擇合適的引擎並依次處理。


HandlerMethodReturnValueHandler 只提供兩個接口,
public interface HandlerMethodReturnValueHandler {
   boolean supportsReturnType(MethodParameter returnType);
   void handleReturnValue(Object returnValue, MethodParameter returnType,
         ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}

第一方法是判斷是否支持值處理引擎,第二方法是對值進行處理,並確定是否繼續進行下一個處理引擎執行。

所以,第一個supportsReturnType(MethodParameter returnType)的判斷一定要正確,如果不正確,就永遠不會被執行,這是關鍵。

具體的執行,就可以按這幾個關鍵的類去debug一下就可以了。

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

2, 具體的實現 

  2.1  定義注解:用於識別json轉換處理的

import java.lang.annotation.*;

/**
 * Created by ThinkPad on 2017/6/22.
 */
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AppResponsBody {
    String type() default "json";
}

2.2  處理引擎的:需要實現 HandlerMethodReturnValueHandler

/**
 * Created by ThinkPad on 2017/6/22.
 */
public class FormatJsonReturnValueHandler implements HandlerMethodReturnValueHandler{
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        System.out.println("===========sdfdsf==============="+ returnType.getMethodAnnotation(AppResponsBody.class));
        boolean hasJSONAnno = returnType.getMethodAnnotation(AppResponsBody.class) != null || returnType.getMethodAnnotation(AppResponsBody.class) != null;
        return hasJSONAnno;
    }

    @Override
    public void handleReturnValue(Object obj, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest) throws Exception {
           modelAndViewContainer.setRequestHandled(true);
          AppResponsBody res=methodParameter.getMethodAnnotation(AppResponsBody.class);
          String type = res.type();
        HttpServletResponse response=nativeWebRequest.getNativeResponse(HttpServletResponse.class);
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        PrintWriter writer = null;
        Gson gson=new Gson();
        ResultInfo info=new ResultInfo();
         info.setData(obj);
        try {
            writer = response.getWriter();
            writer.write(gson.toJson(info));
            writer.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if (writer != null)
                writer.close();
        }
      }

}

2.3   注冊你編寫的HandlerMethodReturnValueHandler引擎 到webConfig配置文件里

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.ouyang.teson"},useDefaultFilters = true)
public class WebConfig extends WebMvcConfigurerAdapter{

配置文件里增加以下:

@Bean
public FormatJsonReturnValueHandler JsonReturnHandler(){
    FormatJsonReturnValueHandler formatJsonReturnValueHandler=new FormatJsonReturnValueHandler();
    return formatJsonReturnValueHandler;
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
    returnValueHandlers.add(JsonReturnHandler());
}

另外,還需要定義一個響應類處理統一格式的:ResultInfo.java 

public class ResultInfo {

    public long code;
    public String message;
    public Object data;

    public long getCode() {
        if(code==0l){
            code=200l;
        }
        return code;
    }

    public void setCode(long code) {
        this.code = code;
    }

    public String getMessage() {
        if(message==null){
            message="處理成功!";
        }
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

 至此,我們的所有工作完成,接着進行測試操作:

 瀏覽測試結果:

注意:

         如果中途有什么問題,自己可以debug以下,用intellij可以很方便的下載源碼,直接debug,這一點很不錯,這也沒有什么難度。

 下一節,要講的就是怎么使用spring-boot快速搭建api后台框架,即是把該配置遷移到spring-boot上並快速啟動。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM