策略模式加AOP,再也不怕产品改需求了~~~

Posted NewWorldForU

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了策略模式加AOP,再也不怕产品改需求了~~~相关的知识,希望对你有一定的参考价值。

需求

先说需求:
      某页面需要有多个操作按钮(本业务中是7个),每个按钮对应不同的表操作,每次操作都要记录下日志。

对接口的思考

对于多个操作按钮

      按照原先的思路,每个按钮写一套接口,7个按钮七个接口(我先忍着),如果中途产品说新增3个按钮,我就再加三个接口(还可以忍),写完之后产品说删几个吧,操作太多对用户不友好(WTM)。
      那么如果用多态来判断是哪个操作,之后进行不同的表操作,那我岂不是一劳永逸?

对于操作入库

      日志记录脑子里直接就是AOP,毕竟面试的时候一堆概念不是白背的。

实现

对于多个操作按钮

      首先是对于业务的抽象,对于所有操作抽象成了一个枚举类EventOperationLogTypeEnum,枚举中有一个clz字段,每一个对应一个具体的实现。

public enum EventOperationLogTypeEnum {

    BUSINESS_EVENT_STATUS("businessEventStatus","业务事件事件状态修改", UpdateBusinessEventStatusImpl.class),
    BUSINESS_OBJECT_TYPE_UPDATE("businessObjectTypeUpdate","业务事件对象类型修改", UpdateBusinessObjectTypeImpl.class),
    BUSINESS_EVENT_TYPE_UPDATE("businessEventTypeUpdate","业务事件事件类型修改", UpdateBusinessEventTypeImpl.class),
    CHILD_ADD_BUSINESS_EVENT("childAddBusinessEvent","子事件添加到业务事件", AddChildToBusinessEventImpl.class),
    CHILD_REMOVE_CHILD_EVENT("removeChildEvent","子事件从业务事件中剔除", RemoveChildFromEventImpl.class),
    CHILD_ADD_KEY_EVENT("childAddKeyEvent","子事件设为关键", ChildAddKeyEventImpl.class),
    CHILD_REMOVE_KEY_EVENT("childRemoveKeyEvent","子事件取消关键事件", ChildRemoveKeyEventImpl.class);

    String abb;
    String msg;
    Class <? extends EventBatchMarkService> clz;
}

      Controller传参之后,进入到对应的实现。

@ApiOperation("事件打标")
@PostMapping("/batch/mark")
public RestObject<Boolean> eventBatchMark(@RequestBody EventBatchMarkVO eventBatchMarkVO) {

    return RestObject.success(eventService.eventBatchMark(eventBatchMarkVO));
}

@Data
public class EventBatchMarkVO {

    @ApiModelProperty("业务事件uuid")
    String businessUuid;

    @ApiModelProperty("子事件uuid")
    String childUuid;

    @ApiModelProperty("修改之前的值")
    List<String> beforeTheUpdate;

    @ApiModelProperty("修改之后的值")
    List<String> afterTheUpdate;

    @ApiModelProperty("打标操作")
    EventOperationLogTypeEnum mark;
}

      根据不同的enum获取不同的Bean,进行eventBatchMarkService.eventTagging()修改表的操作,之后直接返回,不关心操作了什么表,或者进行了什么操作。具体的实现依靠enum中封装好的impl

@Override
public Boolean eventBatchMark(EventBatchMarkVO eventBatchMarkVO) {

    if(!checkEventBatchMarkParma(eventBatchMarkVO)) {
        return false;
    }

    EventBatchMarkService eventBatchMarkService = applicationContext.getBean(eventBatchMarkVO.getMark().getClz());

    return eventBatchMarkService.eventTagging(eventBatchMarkVO.getBusinessUuid(), eventBatchMarkVO.getChildUuid(), eventBatchMarkVO.getBeforeTheUpdate(), eventBatchMarkVO.getAfterTheUpdate(), eventBatchMarkVO.getMark());
}
public interface EventBatchMarkService {

    /**
     *  事件详情页面打标接口
     * @param businessUuid          业务事件uuid
     * @param childUuid             子事件uuid
     * @param beforeTheUpdate       数据修改前值
     * @param afterTheUpdate        数据修改后值
     * @return
     */
    Boolean eventTagging(String businessUuid, String childUuid, List<String> beforeTheUpdate, List<String> afterTheUpdate, EventOperationLogTypeEnum eventOperationLogTypeEnum);
}

      以下是其中某一个的实现类,其他类似。

   @Service
public class UpdateBusinessEventStatusImpl implements EventBatchMarkService {

    @Resource
    private BusinessEventMapper businessEventMapper;

    /**
     *      事件详情页面点击确认,将业务事件表中的事件状态置为 correct
     * @param businessUuid          业务事件uuid
     * @param childUuid             子事件uuid
     * @param beforeTheUpdate       数据修改前值
     * @param afterTheUpdate        数据修改后值
     * @return
     */
    @Override
    @EventOperationLogAnnotation()
    public Boolean eventTagging(String businessUuid, String childUuid, List<String> beforeTheUpdate, List<String> afterTheUpdate, EventOperationLogTypeEnum eventOperationLogTypeEnum) {
        if(Objects.isNull(EventStatusEnum.getEnumByValue(afterTheUpdate.get(0)))) {
            log.info("事件详情页面点击确认后,修改的数据非法。");
            return false;
        }

        BusinessEventPO businessEventPO = new BusinessEventPO();
        businessEventPO.setEventStatus(afterTheUpdate.get(0));

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("uuid", businessUuid);
        queryWrapper.orderByDesc("id");

        int update = businessEventMapper.update(businessEventPO, queryWrapper);

        return update > 0 ? true : false;
    }
}

对于操作入表

先介绍一下AOP是什么:(具体的AOP介绍会单独出一个文章)
     面向切面编程,在保持原有业务流程不变的情况之下,横向打断业务流程,加入一些别的操作,实现代码解耦。
使用场景:
     日志记录、加缓存,权限控制。

AOP、拦截器和过滤器的区别:
     拦截器和过滤器:链式处理流程,一般面向Controller层面
     AOP:面向切面,一般面向Service层面,更加的灵活

请求->>过滤器->>拦截器–>Aspect->>拦截器->>过滤器->>响应

注解类:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventOperationLogAnnotation {

    String expire() default "";

}

切面类:

@Slf4j
@Aspect
@Component
public class EventOperationLogAnnotationAspect {

    @Resource
    private BusinessEventMapper businessEventMapper;

    @Resource
    private ChildEventMapper childEventMapper;

    @Resource
    private EventOperationLogMapper eventOperationLogMapper;

    @Value("${tagging.correctTime}")
    private Long correctTime;

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private Long timeLong = 60 * 60 * 24 * 1000L;

    @AfterThrowing("@annotation(eventOperationLogAnnotation)")
    public void eventOperationLogAnnotationThrow(EventOperationLogAnnotation eventOperationLogAnnotation) {
        log.info("操作记录表切面出错。");
    }

    @Around("@annotation(eventOperationLogAnnotation)")
    public Object around(ProceedingJoinPoint jp, EventOperationLogAnnotation eventOperationLogAnnotation) throws Throwable {

        Object proceed = jp.proceed();
        if((Boolean) proceed) {
            Object[] args = jp.getArgs();
            String businessUuid = (String)args[0];
            String childUuid = (String)args[1];
            List<String> beforeTheUpdate = (List<String>)args[2];
            List<String> afterTheUpdate = (List<String>)args[3];
            EventOperationLogTypeEnum eventOperationLogTypeEnum = (EventOperationLogTypeEnum) args[4];
            // 具体的操作入日志表,这里省略。
            insertEventOperationLog(eventOperationLogTypeEnum, businessUuid, childUuid, beforeTheUpdate, afterTheUpdate);
        }

        return proceed;
    }
}



												————  What is worth doing is worth doing well.

以上是关于策略模式加AOP,再也不怕产品改需求了~~~的主要内容,如果未能解决你的问题,请参考以下文章

策略模式加AOP,再也不怕产品改需求了~~~

策略模式加AOP,再也不怕产品改需求了~~~

再也不怕面试官追问我设计模式了

再也不怕数据结构和算法之开篇

缓存穿透缓存雪崩缓存击穿?再也不怕了,你随便问吧

缓存穿透缓存雪崩缓存击穿?再也不怕了,你随便问吧