策略模式加AOP,再也不怕产品改需求了~~~
Posted NewWorldForU
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了策略模式加AOP,再也不怕产品改需求了~~~相关的知识,希望对你有一定的参考价值。
一次多态加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,再也不怕产品改需求了~~~的主要内容,如果未能解决你的问题,请参考以下文章