• [Spring cloud 一步步实现广告系统] 4. 通用代码模块设计


    一个大的系统,在代码的复用肯定是必不可少的,它能解决:

    1. 统一的响应处理(可以对外提供统一的响应对象包装)

    UTOOLS1564230299519.png

    1. 统一的异常处理(可以将业务异常统一收集处理)

    UTOOLS1564230319631.png

    1. 通用代码定义、配置定义(通用的配置信息放在统一的代码管理中,便于维护和更新)

    创建项目 mscx-ad-common

    POM文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>mscx-ad</artifactId>
            <groupId>com.sxzhongf</groupId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../pom.xml</relativePath>
        </parent>
        <modelVersion>4.0.0</modelVersion>
        <packaging>jar</packaging>
    
        <groupId>com.sxzhongf</groupId>
        <artifactId>mscx-ad-common</artifactId>
        <version>1.0-SNAPSHOT</version>
        <name>Common-Service</name>
        <description>公共逻辑 and 帮助类</description>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
          	<!-- fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.58</version>
            </dependency>
          	<!--  -->
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
            </dependency>
        </dependencies>
    		<!--maven编译插件-->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    项目结构

    • vo (统一响应对象package)

    • advice (bean 增强package )

      Spring支持五种类型的增强或通知(Advice)

      • Before(方法执行前) org.apringframework.aop.MethodBeforeAdvice
      • AfterReturning(方法返回后) org.springframework.aop.AfterReturningAdvice
      • After-throwing(异常抛出后) org.springframework.aop.ThrowsAdviceArround环绕,即方法前后 org.aopaliance.intercept.MethodInterceptor
        引介,不常用 org.springframework.aop.IntroductionInterceptor
        具体可参考:细说advice,advisor
    • annotation

    • config

    • exception

    • utils

    • export

    通用响应编码
    1. 创建通用返回对象
    /**
    * @Data是下属注解的组合注解
    * 
    * @see Getter
    * @see Setter
    * @see RequiredArgsConstructor
    * @see ToString
    * @see EqualsAndHashCode
    * @see lombok.Value 
    */
    @Data
    @NoArgsConstructor //无参构造函数
    @AllArgsConstructor //全参构造函数
    public class CommonResponse<T> implements Serializable {
       private Integer code = 0;
       private String message = "success";
       /**
        * 具体的数据对象信息
        */
       private T data;
    
       public CommonResponse(Integer code, String message) {
           this.code = code;
           this.message = message;
       }
    
       public CommonResponse(T data) {
           this.data = data;
       }
    }
    
    1. 在advice包中实现对响应的统一拦截com.sxzhongf.ad.common.advice.CommonResponseDataAdvice,参考 ResponseBodyAdvice, RestControllerAdvice 可查看源码org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice
       @RestControllerAdvice
       public class CommonResponseDataAdvice implements ResponseBodyAdvice<Object> {
       
           /**
            * 判断是否需要对响应进行处理
            *
            * @return false -> 不处理,true -> 处理
            */
           @Override
           public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) {
       //
       //        //获取当前处理请求的controller的方法
       //        String methodName = methodParameter.getMethod().getName().toLowerCase();
       //        // 不拦截/不需要处理返回值 的方法
       //        String method = "login"; //如登录
       //        //不拦截
       //        return !method.equals(methodName);
       
               // 如果类上标记了@IgnoreResponseAdvice,则不拦截
               if (methodParameter.getDeclaringClass().isAnnotationPresent(IgnoreResponseAdvice.class)) {
                   return false;
               }
       
               // 如果方法上标记了@IgnoreResponseAdvice,则不拦截
               if (methodParameter.getMethod().isAnnotationPresent(IgnoreResponseAdvice.class)) {
                   return false;
               }
       
               //对响应进行处理,执行beforeBodyWrite方法
               return true;
           }
       
           /**
            * 目的 拦截CommonResponse
            *
            * @param body 原始的Controller需要返回的数据
            */
           @Override
           public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                         MediaType selectedContentType,
                                         Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                         ServerHttpRequest request,
                                         ServerHttpResponse response) {
       
               CommonResponse<Object> commonResponse = new CommonResponse<>();
       
               if (null == body) {
                   return commonResponse;
               } else if (body instanceof CommonResponse) {
                   commonResponse = (CommonResponse<Object>) body;
               } else {
                   commonResponse.setData(body);
               }
               return commonResponse;
           }
       }
    

    我们在annotation包下面添加一个注解com.sxzhongf.ad.common.annotation.IgnoreResponseAdvice,用它来标柱是否需要支持上面的统一返回拦截。

       /**
        * IgnoreResponseAdvice for 标示需要忽略拦截动作
        *
        * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
        */
       //ElementType.TYPE 表示该注解可用于class
       //ElementType.METHOD 表示可用于方法
       @Target({ElementType.TYPE, ElementType.METHOD})
       @Retention(RetentionPolicy.RUNTIME)
       public @interface IgnoreResponseAdvice {
       }
    
    通用异常处理

    异常处理也是统一的,那么同样就要使用到RestControllerAdvice,同时,需要使用的Spring 的ExceptionHandler进行异常处理

    1. 创建统一异常拦截类
    /**
     * GlobalExceptionAdvice for 全局统一异常拦截
     *
     * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
     * @see RestControllerAdvice
     * @see ExceptionHandler
     */
    @RestControllerAdvice
    public class GlobalExceptionAdvice {
    
        /**
         * 对 {@link AdException} 进行统一处理
         * {@link ExceptionHandler}  对指定的异常进行拦截
         * 可优化:
         * 定义多种类异常,实现对应的异常处理,
         * 例如:
         * <ul>
         * <li>
         * 推广单元操作异常,抛出 AdUnitException
         * </li>
         * <li>
         * Binlog 解析异常,抛出 BinlogException
         * </li>
         * </ul>
         * 拦截Spring Exception 使用 {@link ExceptionHandler}注解
         */
        @ExceptionHandler(value = AdException.class)
        public CommonResponse<String> handlerAdException(HttpServletRequest request, AdException ex) {
            CommonResponse<String> response = new CommonResponse<>(-1, "business error");
            response.setData(ex.getMessage());
            return response;
        }
    }
    
    1. 创建通用异常类
    /**
     * AdException for 统一异常处理类
     *
     * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
     */
    public class AdException extends Exception {
        public AdException(String message) {
            super(message);
        }
    }
    
    通用配置信息

    通过HTTP消息转换器HttpMessageConverter,实现对象转换,Java Object -> HTTP 数据流

    1. 新增WebConfiguration,我们通过实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer来定制和修改Spring MVC的配置信息。
    /**
     * WebConfiguration for 对Spring的配置和行为进行定制修改
     *
     * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
     * @see WebMvcConfigurer
     */
    @Configuration
    public class WebConfiguration implements WebMvcConfigurer {
        /**
         * 匹配路由请求规则
         */
        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
    
        }
        /**
         * 注册自定义的Formatter 和 Convert
         */
        @Override
        public void addFormatters(FormatterRegistry registry) {
    
        }
        /**
         * 添加静态资源处理器
         */
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
        }
        /**
         * 添加自定义视图控制器
         */
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
    
        }
        /**
         * 添加自定义方法参数处理器
         */
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    
        }
        /**
         * 配置消息转换器
         */
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            //清空所有转换器
            converters.clear();
          	// Java Obj -> Json Obj (http header: application/json)
            converters.add(new MappingJackson2HttpMessageConverter());
        }
    }
    

    做一个好人。

  • 相关阅读:
    CompletionService--实现并行获取future.get()结果
    ConcurrentHashMap+FutureTask实现高效缓存耗时较长的业务结果获取
    Exchanger--线程执行过程中交换数据
    线程池的处理流程
    CyclicBarrier--栅栏,挡住指定数量线程后一次放行
    Semaphore--信号量,控制并发线程数,如流量控制
    CountDownLatch---多线程等待
    线程安全相关概念
    SimpleDateFormat非线程安全
    记java.lang.NoSuchMethodError错误解决过程
  • 原文地址:https://www.cnblogs.com/zhangpan1244/p/11256501.html
Copyright © 2020-2023  润新知