引言
1. 权限验证
在之前的Blog项目当中,其实已经体验过权限验证了,不过那时候用的是SpringSecurity API来实现的方法,当没使用API时,可以使用Spring的AOP来进行权限验证了.其实也可以通过使用拦截器来实现登录权限验证,但是AOP相对而言更加灵活
消息管理
2. 消息管理
通过Srping的AOP可以在用户对业务进行操作的时候执行时能发送消息,从而使用户能接收到来自业务的消息提醒.
实现步骤
1. 创建一个注解
- 登录验证
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface GlobalInterceptor {
boolean checkLogin() default false;
}
这里涉及到的注解相关知识就不再赘述(主要是在写这个知识点的时候已经能看懂代码了所以不想再赘述了)
2. 发送提醒消息
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RecordUserMessage {
MessageTypeEnum messageType();
}
2. 创建Aspect切面类
- 登录验证
这里代码逻辑简单就不需要特别解释了
@Aspect
@Component
@Slf4j
public class GlobalOperationAspect {
@Resource
private RedisComponent redisComponent;
// 在ControllerMethod方法从@GlobalInterceptor自定义注解来标记切面,在ControllerMethod方法前执行该方法
@Before("@annotation(com.easylive.annotation.GlobalInterceptor)")
public void interceptoDto(JoinPoint joinPoint) {
log.error("开始执行登录校验切点拦截");
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
GlobalInterceptor annotation = method.getAnnotation(GlobalInterceptor.class);
if (Objects.isNull(annotation)) {
return;
}
if (annotation.checkLogin()) {
checkLogin();
}
}
private void checkLogin() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader(Constants.TOKEN_WEB);
if (Objects.isNull(token)) {
throw new BusinessException(ResponseCodeEnum.CODE_901);
}
TokenUserInfoDto tokenInfo = redisComponent.getTokenInfo(token);
if (Objects.isNull(tokenInfo)) {
throw new BusinessException(ResponseCodeEnum.CODE_901);
}
}
}
- 发送提醒消息
@Aspect
@Component
@Slf4j
public class UserMessageOperationAspect {
@Resource
private RedisComponent redisComponent;
@Resource
private UserMessageService userMessageService;
private static final String PARAMETERS_VIDEO_ID = "videoId";
private static final String PARAMETERS_ACTION_TYPE = "actionType";
private static final String PARAMETERS_REPLY_COMMENTID = "replyCommentId";
private static final String PARAMETERS_CONTENT = "content";
private static final String PARAMETERS_AUDIT_REJECT_REASON = "reason";
@Around("@annotation(com.easylive.annotation.RecordUserMessage)")
public ResponseVO interceptorDto(ProceedingJoinPoint joinPoint) throws Throwable {
ResponseVO proceed = (ResponseVO) joinPoint.proceed();
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
RecordUserMessage annotation = method.getAnnotation(RecordUserMessage.class);
//在这里joinPoint.getArgs()获取的是ControllerMethod的实际参数值,method.getParameters()获取的是控制器方法的参数元数据(参数定义名称和类型)
if (annotation != null) {
saveMessage(annotation, joinPoint.getArgs(), method.getParameters());
}
return proceed;
}
private void saveMessage(RecordUserMessage recordUserMessage, Object[] args, Parameter[] parameters) {
String videoId = null;
Integer actionType = null;
Integer replyCommentId = null;
String content = null;
for (int i = 0; i < parameters.length; i++) {
if (PARAMETERS_VIDEO_ID.equals(parameters[i].getName())) {
videoId = (String) args[i];
} else if (PARAMETERS_ACTION_TYPE.equals(parameters[i].getName())) {
actionType = (Integer) args[i];
} else if (PARAMETERS_REPLY_COMMENTID.equals(parameters[i].getName())) {
replyCommentId = (Integer) args[i];
} else if (PARAMETERS_CONTENT.equals(parameters[i].getName())) {
content = (String) args[i];
}
}
MessageTypeEnum messageTypeEnum = recordUserMessage.messageType();
/*
*这里还要单独设置一个条件判断是否为收藏是因为原来的doAction方法里注解默认是写LIKE的
*靠参数actionType来区分互动类型,互动只提示点赞和收藏不提示投币
*所以默认LIKE然后根据actionType参数来变更消息类型
*/
if (UserActionTypeEnum.VIDEO_COLLECT.getType().equals(actionType)) {
messageTypeEnum = MessageTypeEnum.COLLECTION;
}
TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();
userMessageService.saveUserMessage(videoId, tokenUserInfoDto == null ? null : tokenUserInfoDto.getUserId(), messageTypeEnum, content, replyCommentId);
}
protected TokenUserInfoDto getTokenUserInfoDto() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader(Constants.TOKEN_WEB);
return redisComponent.getTokenInfo(token);
}
}
异步实现发送提醒消息
@Override
@Async
public void saveUserMessage(String videoId, String sendUserId, MessageTypeEnum messageTypeEnum, String content, Integer replyCommentId) {
VideoInfo videoInfo = videoInfoMapper.selectByVideoId(videoId);
if (Objects.isNull(videoInfo)) {
return;
}
UserMessageExtendDto extendDto = new UserMessageExtendDto();
extendDto.setMessageContent(content);
String reciveUserId = videoInfo.getUserId();
// 收藏取消已经记录的不再记录
if (ArrayUtils.contains(new Integer[]{MessageTypeEnum.LIKE.getType(), MessageTypeEnum.COLLECTION.getType()}, messageTypeEnum.getType())) {
UserMessageQuery userMessageQuery = new UserMessageQuery();
userMessageQuery.setUserId(reciveUserId);
userMessageQuery.setVideoId(videoId);
userMessageQuery.setMessageType(messageTypeEnum.getType());
Integer count = userMessageMapper.selectCount(userMessageQuery);
if (count > 0) {
return;
}
}
UserMessage userMessage = new UserMessage();
userMessage.setUserId(reciveUserId);
userMessage.setVideoId(videoId);
userMessage.setMessageType(messageTypeEnum.getType());
userMessage.setReadType(MessageReadTypeEnum.NO_READ.getType());
userMessage.setCreateTime(new Date());
userMessage.setSendUserId(sendUserId);
// 评论特殊处理
if (Objects.nonNull(replyCommentId)) {
VideoComment videoComment = videoCommentMapper.selectByCommentId(replyCommentId);
if (Objects.nonNull(videoComment)) {
reciveUserId = videoComment.getUserId();
extendDto.setMessageContentReply(videoComment.getContent());
}
}
if (reciveUserId.equals(sendUserId)) {
return;
}
// 系统消息特殊处理
if (MessageTypeEnum.SYS.getType().equals(messageTypeEnum.getType())) {
VideoInfoPost videoInfoPost = videoInfoPostMapper.selectByVideoId(videoId);
extendDto.setAuditStatus(videoInfoPost.getStatus());
}
userMessage.setUserId(reciveUserId);
userMessage.setExtendJson(JsonUtils.convertObj2Json(extendDto));
userMessageMapper.insert(userMessage);
}
表结构
这里还有个UserMessageExtendDto类
这个类在数据库表里的主要功能是提供灵活性,在表结构当中这个以JSON形式存储在数据库当中,取出返回的时候从JSON序列化为Object,这个可以给数据库表提供灵活性.
结束
标签:userMessage,String,Spring,getType,videoId,private,AOP,annotation,SpringBoot From: https://www.cnblogs.com/MingHaiZ/p/18599650其实之前的MHBLOG项目当中也使用过AOP来进行日志记录,但是那次忘记记录了,这次在这个项目当中使用到的AOP相关知识其实也覆盖了上次使用过的知识点.总之就是这么多了.