封装springboot框架详解java

下面要给大家介绍的是和自定义封装springboot框架相关的内容,在java当中这算是比较常见的问题了,一起来看看吧。

自定义封装框架

1、对request请求,添加拦截器。

继承webMvcConfiguerAdapter,只要把自定义的拦截器注入就可以了。

这个截器主要有五个功能:

假如有OpenInterface注解,那么跳过拦截,主要用于第三方回调,或者接口直接调用;

获取前端app_name、app_version,这两个参数主要是用来验证app版本是不是需要更新,假如,是web项目这两个参数可以不要,最后将他们写到MDC去;

添加追踪信息到MDC里去;

traceId作用和springcloud的sleuth类似,能够在查询日志的时候,凭借这个关键字拉取某个请求全部日志,用uuid生成,保证每个请求的traceId不一样;

假如网页要切换语言,将下面注释的部分打开就可以了,一个做语言国际化标准;

token校验,这里的话是自己写的token校验,假如,大家用shiro或者是spring security这个可以不用,主要的话,是判断是否登入,不需要这个功能的可以删除;

@Configuration
public class GlobalRequestHandler extends WebMvcConfigurerAdapter
{
    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(requestInterceptor());
    }
    public HandlerInterceptorAdapter requestInterceptor()
    {
        return new HandlerInterceptorAdapter()
        {
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
            {
                //OpenInterface注释的接口不拦截
                if (((HandlerMethod) handler)
                    .getMethod()
                    .isAnnotationPresent(OpenInterface.class))
                {
                    return true;
                }
                interceptorHandler(request, handler);
                return true;
            }
        };
    }
    private void interceptorHandler(HttpServletRequest request, Object handler)
    {
        //获取请求信息
        String appName = request.getHeader(Constants.APP_NAME);
        String appVersion = request.getHeader(Constants.APP_VERSION);
        //String lang = request.getHeader(Constants.LANG);
        if (StringUtils.isEmpty(appName) || StringUtils.isEmpty(appVersion))
        {
            throw new SystemException(ExceptionCode.HANDLER_PARAM_ERROR.getCode(), "handler param is null!");
        }
        //清空线程缓存
        MDC.clear();
        //设置请求信息
        MDC.put(Constants.APP_NAME, appName);
        MDC.put(Constants.APP_VERSION, appVersion);
        MDC.put("traceId", UUID.randomUUID()
            .toString());
        //语言国际化,有需要开启
        //LocaleContextHolder.setLocale(StringUtils.isEmpty(lang) ? Constants.DEFAULT_LANG : Locale.forLanguageTag(lang));
        //检查token,标记UncheckToken不检查token
        if (!((HandlerMethod) handler)
            .getMethod()
            .isAnnotationPresent(UncheckToken.class))
        {
            String token = "";
            token = Utils.getCookieByName(request.getCookies(), Constants.COOKILE_TOKEN);
            //TODO 校验token步骤
            //if (StringUtils.isEmpty(token) &&  ){
            //    throw new SystemException(ExceptionCode.NEED_LOGIN.getCode(), "token is over time");
            //}
        }
    }
}

2、封装response返回格式

这里的话修改了reponse返回格式

结果:不论是返回的是对象又或者是tring都统一格式化成code、data、msg

这里,之所以将springmvc的源码进行修改,主要是因为假如返回string类型,那么当你将它格式化之后会报错,这主要就是因为springmvc认为string类型应该用string信息解析器,可以,你却把它封装成了个对象,所以就最终造成了不能够解析了。

@RestControllerAdvice
public class GlobalResponseHandler extends WebMvcRegistrationsAdapter
{
    /*
     *  WebMvcRegistrationsAdapter通过getRequestMappingHandlerAdapter获取RequestMappingHandlerAdapter。
     *  RequestMappingHandlerAdapter重写ReturnValueHandlers方法
     *  传入的视图解析器是jackson
     *  注:ReturnValueHandlers调用视图转换器,所以在此处替换returnValue
     */
    @Override
    public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter()
    {
        RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter();
        List < HandlerMethodReturnValueHandler > handlerList = new ArrayList < > ();
        handlerList.add(new RequestResponseBodyMethodProcessor(Collections.singletonList(new MappingJackson2HttpMessageConverter()))
        {
            @Override
            public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException
            {
                super.handleReturnValue(packageResult(returnValue), returnType, mavContainer, webRequest);
            }
        });
        requestMappingHandlerAdapter.setReturnValueHandlers(handlerList);
        return requestMappingHandlerAdapter;
    }
    private Object packageResult(Object data)
    {
        Response response = new Response();
        response.setData(data);
        return response;
    }
}

3、全局异常拦截

作用和上面的相差不了多少,只是说上面的是对response格式化,这里的话是全局异常拦截并且格式化。

@RestControllerAdvice
public class GlobalExceptionHandler
{
    @ExceptionHandler(Throwable.class)
    public Response handlerException(Throwable throwable)
    {
        Response response = new Response();
        response.setMeg(throwable.getMessage());
        response.setCode(ExceptionCode.SYSTEM_ERROR.getCode());
        return getError(throwable, response);
    }
    private Response getError(Throwable throwable, Response response)
    {
        if (throwable instanceof ServiceException)
        {
            response.setCode(((ServiceException) throwable)
                .getCode());
        }
        else if (throwable instanceof NoHandlerFoundException)
        {
            response.setCode(ExceptionCode.NO_HANDLER_ERROR.getCode());
        }
        else if (throwable instanceof HttpMessageNotReadableException)
        {
            response.setCode(ExceptionCode.PARAM_TYPE_ERROR.getCode());
        }
        return response;
    }
}

4、日志

pringboot默认是用logback,logstash是对接ELK的,所以FILE-INFO用该格式化,能够直接对接ELK。

def final LOCATION = "/data/log/app/"
def final SERVER_NAME = "base"
def final SAVE_TIME_RANGE = 7
String ENV = System.getProperty("env")
if (StringUtils.isEmpty(ENV))
{
    appender('CONSOLE', ConsoleAppender)
    {
        encoder(PatternLayoutEncoder)
        {
            pattern = "%d{yyyy-MM-dd HH:mm:ss.SSS} %relative [%thread] %-5level %logger{36} %X{requestId} - %msg%n"
        }
    }
    root(INFO, ['CONSOLE'])
}
else
{
    appender('FILE-INFO', RollingFileAppender)
    {
        rollingPolicy(TimeBasedRollingPolicy)
        {
            fileNamePattern = String.format("%s%s/%s%s%s", LOCATION, SERVER_NAME, "logFile.", ENV, ".%d{yyyy-MM-dd}.log.gz")
            maxHistory = SAVE_TIME_RANGE
        }
        encoder(LogstashEncoder)
        {
            includeMdcKeyNames = ["traceId"]
        }
    }
    root(INFO, ['FILE-INFO'])
}

在java当中有很多的东西都是我们要去了解和掌握的,希望上面的内容能够对你有所帮助,更多java基础知识,请继续通过奇Q工具网来进行了解吧。

推荐阅读:

springboot框架的优点是什么? springboot比spring的优势如何?

java springboot框架面试题,springboot常见面试题整理

springboot框架工作原理是怎样的?原理详解