网站架构文案,怎么建单位的网站,网络营销方式和消费者群体之间的关系,室内设计软件大全网站今天遇到一个需求#xff0c;在不改动原系统代码的情况下。将Controller的返回值和异常包装到一个统一的返回对象中去。 例如原系统的接口
public String myIp(ApiIgnore HttpServletRequest request);返回的只是一个IP字符串0:0:0:0:0:0:0:1#xff0c;目前接口…今天遇到一个需求在不改动原系统代码的情况下。将Controller的返回值和异常包装到一个统一的返回对象中去。 例如原系统的接口
public String myIp(ApiIgnore HttpServletRequest request);返回的只是一个IP字符串0:0:0:0:0:0:0:1目前接口需要包装为
{code:200,message:,result:0:0:0:0:0:0:0:1,success:true} 而原异常跳转到error页面需要调整为
{ success: false, message: For input string: \fdsafddfs\, code: 500, result: message } 因此就有了2个工作子项需要完成
1Exception的处理
2controller return值的处理 Exception的自动包装
返回的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 ResultString 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(); //服务器可以记录出错时的请求啦}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请设置为10Mpublic Result? handleMaxUploadSizeExceededException(HttpServletRequest request, MaxUploadSizeExceededException e) {return createError(request, e, HttpStatus.SC_INTERNAL_SERVER_ERROR, error.mvc.fileTooLarge, EMPTY_ARGS);}ExceptionHandler(Exception.class)ResponseBodypublic 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当然也可以使用Component支持扫描随你喜欢 Beanpublic GlobalRestControllerAdvice globalRestControllerAdvice(MessageSource messageSource, LocaleResolver localeResolver){return new GlobalRestControllerAdvice(messageSource, localeResolver);}controller return值的自动包装
网上的例子有很多坑包括使用HandlerMethodReturnValueHandler看了源码才发现。还是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 ResponseBodyAdviceObject {private static final Pattern CONTROLLER_PATTERN Pattern.compile(^org\\.ccframe\\.(subsys|sdk)\\.[a-z0-9]\\.controller\\.);Overridepublic boolean supports(MethodParameter returnType, Class? extends HttpMessageConverter? converterType) {return // 只有自己的cotroller类才需要进入否则swagger都会挂了
CONTROLLER_PATTERN.matcher(returnType.getContainingClass().getName()).find();}Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class? extends HttpMessageConverter? selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {System.out.println(returnType.getContainingClass());ResultObject result new Result();result.setResult(body);result.setCode(HttpStatus.SC_OK);if(body instanceof String){ //String返回要特殊处理return JSON.toJSONString(result);}else {return result;}}
}如果你不需要根据正则来指定包可以直接用RestControllerAdvice的basePackages属性来过滤 注意这里有2个坑
1String类型的返回被其它的转换接口StringHttpMessageConverter处理因此返回要进行JSON编码而不能返回其他类型否则会报cast类型错因此就有了String部分的特殊处理方法。
2controller方法签名返回是void时不会被处理 在Config类初始它 Beanpublic CcResponseBodyAdvice ccResponseBodyAdvice() {return new CcResponseBodyAdvice();}最后。上面两个Bean也可以写在一个有兴趣的自己尝试。