修改项目整体结构 添加公告代码

master
bynt 10 months ago
parent 8af33093b5
commit 284d2a7bc6

@ -48,5 +48,12 @@
<artifactId>ad-distribute-starter-web</artifactId>
<version>1.1.0</version>
</dependency>
<!-- notify 通知模块 -->
<dependency>
<groupId>com.baiye</groupId>
<artifactId>distribute-notify-controller</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
</project>

@ -34,7 +34,7 @@ import org.springframework.security.oauth2.server.resource.introspection.OpaqueT
// @ComponentScan({ "com.hccake.ballcat.admin.upms", "com.hccake.ballcat.system",
// "com.hccake.ballcat.log",
// "com.hccake.ballcat.file", "com.hccake.ballcat.notify" })
@ComponentScan({ "com.baiye.upms", "com.hccake.ballcat.system" })
@ComponentScan({ "com.baiye.upms", "com.baiye.system" })
@EnableConfigurationProperties({ SystemProperties.class, SecurityProperties.class })
public class UpmsAutoConfiguration {

@ -20,5 +20,12 @@
<artifactId>ad-distribute-starter-websocket</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>distribute-notify-biz</artifactId>
<version>1.1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

@ -14,16 +14,12 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
* @author Hccake 2021/1/5
* @version 1.0
*/
@Import({ SystemWebsocketEventListenerConfiguration.class })
@Import({ SystemWebsocketEventListenerConfiguration.class})
@Configuration
@RequiredArgsConstructor
public class AdminWebSocketAutoConfiguration {
@Bean
@ConditionalOnMissingBean(UserAttributeHandshakeInterceptor.class)
public HandshakeInterceptor authenticationHandshakeInterceptor() {
return new UserAttributeHandshakeInterceptor();
}
@Bean
@ConditionalOnMissingBean(SessionKeyGenerator.class)
@ -31,4 +27,8 @@ public class AdminWebSocketAutoConfiguration {
return new UserSessionKeyGenerator();
}
@Bean
public HandshakeInterceptor authenticationHandshakeInterceptor() {
return new UserAttributeHandshakeInterceptor();
}
}

@ -1,60 +1,67 @@
// package com.hccake.ballcat.admin.websocket.listener;
//
// import com.hccake.ballcat.common.util.JsonUtils;
// import com.hccake.ballcat.common.websocket.distribute.MessageDO;
// import com.hccake.ballcat.common.websocket.distribute.MessageDistributor;
// import com.hccake.ballcat.notify.event.AnnouncementCloseEvent;
// import com.hccake.ballcat.notify.event.StationNotifyPushEvent;
// import com.hccake.ballcat.notify.handler.NotifyInfoDelegateHandler;
// import com.hccake.ballcat.notify.model.domain.NotifyInfo;
// import com.hccake.ballcat.admin.websocket.message.AnnouncementCloseMessage;
// import com.hccake.ballcat.system.model.entity.SysUser;
// import lombok.RequiredArgsConstructor;
// import lombok.extern.slf4j.Slf4j;
// import org.springframework.context.event.EventListener;
// import org.springframework.scheduling.annotation.Async;
//
// import java.util.List;
//
/// **
// * @author Hccake 2021/1/5
// * @version 1.0
// */
// @Slf4j
// @RequiredArgsConstructor
// public class NotifyWebsocketEventListener {
//
// private final MessageDistributor messageDistributor;
//
// private final NotifyInfoDelegateHandler<? super NotifyInfo> notifyInfoDelegateHandler;
//
// /**
// * 公告关闭事件监听
// * @param event the AnnouncementCloseEvent
// */
// @Async
// @EventListener(AnnouncementCloseEvent.class)
// public void onAnnouncementCloseEvent(AnnouncementCloseEvent event) {
// // 构建公告关闭的消息体
// AnnouncementCloseMessage message = new AnnouncementCloseMessage();
// message.setId(event.getId());
// String msg = JsonUtils.toJson(message);
//
// // 广播公告关闭信息
// MessageDO messageDO = new MessageDO().setMessageText(msg).setNeedBroadcast(true);
// messageDistributor.distribute(messageDO);
// }
//
// /**
// * 站内通知推送事件
// * @param event the StationNotifyPushEvent
// */
// @Async
// @EventListener(StationNotifyPushEvent.class)
// public void onAnnouncementPublishEvent(StationNotifyPushEvent event) {
// NotifyInfo notifyInfo = event.getNotifyInfo();
// List<SysUser> userList = event.getUserList();
// notifyInfoDelegateHandler.handle(userList, notifyInfo);
// }
//
// }
package com.baiye.listener;
import com.baiye.distribute.MessageDO;
import com.baiye.distribute.MessageDistributor;
import com.baiye.message.AnnouncementCloseMessage;
import com.baiye.notify.event.AnnouncementCloseEvent;
import com.baiye.notify.event.StationNotifyPushEvent;
import com.baiye.notify.handler.NotifyInfoDelegateHandler;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.util.JsonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author Hccake 2021/1/5
* @version 1.0
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class NotifyWebsocketEventListener {
private final MessageDistributor messageDistributor;
private final NotifyInfoDelegateHandler<? super NotifyInfo> notifyInfoDelegateHandler;
/**
*
*
* @param event the AnnouncementCloseEvent
*/
@Async
@EventListener(AnnouncementCloseEvent.class)
public void onAnnouncementCloseEvent(AnnouncementCloseEvent event) {
// 构建公告关闭的消息体
AnnouncementCloseMessage message = new AnnouncementCloseMessage();
message.setId(event.getId());
String msg = JsonUtils.toJson(message);
// 广播公告关闭信息
MessageDO messageDO = new MessageDO().setMessageText(msg).setNeedBroadcast(true);
messageDistributor.distribute(messageDO);
}
/**
*
*
* @param event the StationNotifyPushEvent
*/
@Async
@EventListener(StationNotifyPushEvent.class)
public void onAnnouncementPublishEvent(StationNotifyPushEvent event) {
NotifyInfo notifyInfo = event.getNotifyInfo();
List<Long> userList = event.getUserIdList();
notifyInfoDelegateHandler.handle(userList, notifyInfo);
}
}

@ -1 +1 @@
com.hccake.common.core.test.desensite.TestDesensitizationHandler
com.baiye.common.core.test.desensite.TestDesensitizationHandler

@ -55,6 +55,7 @@ public abstract class AbstractMessageDistributor implements MessageDistributor {
continue;
}
for (WebSocketSession wsSession : sessions) {
log.info("============ send message time {} body {} ============", System.currentTimeMillis(), messageText);
WebSocketMessageSender.send(wsSession, messageText);
}
}

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.baiye</groupId>
<artifactId>ad-distribute-notify</artifactId>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>distribute-notify-biz</artifactId>
<dependencies>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>common-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>distribute-notify-model</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>system-biz</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,23 @@
package com.baiye.notify.event;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
/**
*
*
* @author Hccake 2021/1/7
* @version 1.0
*/
@Getter
@ToString
@AllArgsConstructor
public class AnnouncementCloseEvent {
/**
* ID
*/
private final Long id;
}

@ -0,0 +1,26 @@
package com.baiye.notify.event;
import com.baiye.notify.model.domain.NotifyInfo;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/**
*
*
* @author Hccake 2020/12/17
* @version 1.0
*/
@Getter
public class NotifyPublishEvent extends ApplicationEvent {
/**
*
*/
private final NotifyInfo notifyInfo;
public NotifyPublishEvent(NotifyInfo notifyInfo) {
super(notifyInfo);
this.notifyInfo = notifyInfo;
}
}

@ -0,0 +1,28 @@
package com.baiye.notify.event;
import com.baiye.notify.model.domain.NotifyInfo;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.List;
/**
* @author Hccake 2021/1/5
* @version 1.0
*/
@Data
@RequiredArgsConstructor
public class StationNotifyPushEvent {
/**
*
*/
private final NotifyInfo notifyInfo;
/**
*
*/
private final List<Long> userIdList;
}

@ -0,0 +1,71 @@
package com.baiye.notify.handler;
import cn.hutool.core.collection.CollUtil;
import com.baiye.distribute.MessageDO;
import com.baiye.distribute.MessageDistributor;
import com.baiye.message.JsonWebSocketMessage;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.system.model.entity.SysUser;
import com.baiye.util.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
*
*
* @author huyuanzhi
* @param <T>event
* @param <M> websocket
*/
public abstract class AbstractNotifyInfoHandler<T extends NotifyInfo, M extends JsonWebSocketMessage>
implements NotifyInfoHandler<T> {
@Autowired
private MessageDistributor messageDistributor;
protected final Class<T> clz;
@SuppressWarnings("unchecked")
protected AbstractNotifyInfoHandler() {
Type superClass = getClass().getGenericSuperclass();
ParameterizedType type = (ParameterizedType) superClass;
clz = (Class<T>) type.getActualTypeArguments()[0];
}
@Override
public void handle(List<Long> userIdList, T notifyInfo) {
M message = createMessage(notifyInfo);
String msg = JsonUtils.toJson(message);
List<Object> sessionKeys = new ArrayList<>(userIdList);
persistMessage(userIdList, notifyInfo);
MessageDO messageDO = new MessageDO().setMessageText(msg)
.setSessionKeys(sessionKeys)
.setNeedBroadcast(CollUtil.isEmpty(sessionKeys));
messageDistributor.distribute(messageDO);
}
@Override
public Class<T> getNotifyClass() {
return this.clz;
}
/**
*
* @param userIdList
* @param notifyInfo
*/
protected abstract void persistMessage(List<Long> userIdList, T notifyInfo);
/**
*
* @param notifyInfo
* @return
*/
protected abstract M createMessage(T notifyInfo);
}

@ -0,0 +1,52 @@
package com.baiye.notify.handler;
import com.baiye.notify.model.domain.NotifyInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
*
* @author huyuanzhi
* @param <T>
*/
@Slf4j
@Component
@AllArgsConstructor
public class NotifyInfoDelegateHandler<T extends NotifyInfo> {
private final List<NotifyInfoHandler<T>> notifyInfoHandlers;
private Map<Class<?>, NotifyInfoHandler<T>> handlerMap;
@PostConstruct
public void init() {
handlerMap = new HashMap<>(notifyInfoHandlers.size());
for (NotifyInfoHandler<T> handler : notifyInfoHandlers) {
handlerMap.put(handler.getNotifyClass(), handler);
}
}
/**
*
* @param userIdList
* @param info
*/
public void handle(List<Long> userIdList, T info) {
Assert.notNull(info, "event message cant be null!");
NotifyInfoHandler<T> notifyInfoHandler = handlerMap.get(info.getClass());
if (notifyInfoHandler == null) {
log.warn("no notifyHandler bean for class:{},please check!", info.getClass().getName());
return;
}
notifyInfoHandler.handle(userIdList, info);
}
}

@ -0,0 +1,29 @@
package com.baiye.notify.handler;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.system.model.entity.SysUser;
import java.util.List;
/**
* event
*
* @author huyuanzhi
*/
public interface NotifyInfoHandler<T extends NotifyInfo> {
/**
*
* @param userIdList
* @param info
*/
void handle(List<Long> userIdList, T info);
/**
*
* @return
*/
Class<T> getNotifyClass();
}

@ -0,0 +1,50 @@
package com.baiye.notify.handler.impl;
import com.baiye.notify.handler.AbstractNotifyInfoHandler;
import com.baiye.notify.model.domain.AnnouncementNotifyInfo;
import com.baiye.notify.model.entity.UserAnnouncement;
import com.baiye.notify.service.UserAnnouncementService;
import com.baiye.system.model.entity.SysUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
*
*
* @author huyuanzhi
*/
@Component
@RequiredArgsConstructor
public class AnnouncementNotifyInfoHandler
extends AbstractNotifyInfoHandler<AnnouncementNotifyInfo, AnnouncementPushMessage> {
private final UserAnnouncementService userAnnouncementService;
@Override
protected void persistMessage(List<Long> userIdList, AnnouncementNotifyInfo announcementNotifyInfo) {
List<UserAnnouncement> userAnnouncements = new ArrayList<>(userIdList.size());
// 向指定用户推送
for (Long userId : userIdList) {
UserAnnouncement userAnnouncement = userAnnouncementService.prodUserAnnouncement
(userId, announcementNotifyInfo.getId(), announcementNotifyInfo.getState(), announcementNotifyInfo.getType(),
announcementNotifyInfo.getMessageKey(), announcementNotifyInfo.getTitle(), announcementNotifyInfo.getContent());
userAnnouncements.add(userAnnouncement);
}
userAnnouncementService.saveBatch(userAnnouncements);
}
@Override
protected AnnouncementPushMessage createMessage(AnnouncementNotifyInfo announcementNotifyInfo) {
AnnouncementPushMessage message = new AnnouncementPushMessage();
message.setId(announcementNotifyInfo.getId());
message.setTitle(announcementNotifyInfo.getTitle());
message.setContent(announcementNotifyInfo.getContent());
message.setImmortal(announcementNotifyInfo.getImmortal());
message.setDeadline(announcementNotifyInfo.getDeadline());
return message;
}
}

@ -0,0 +1,49 @@
package com.baiye.notify.handler.impl;
import com.baiye.message.JsonWebSocketMessage;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
/**
*
*
* @author Hccake 2021/1/5
* @version 1.0
*/
@Getter
@Setter
public class AnnouncementPushMessage extends JsonWebSocketMessage {
public AnnouncementPushMessage() {
super("announcement-push");
}
/**
* ID
*/
private Long id;
/**
*
*/
private String title;
/**
*
*/
private String content;
/**
*
* @see com.baiye.ballcat.common.core.constant.enums.BooleanEnum
*/
private Integer immortal;
/**
*
*/
private LocalDateTime deadline;
}

@ -0,0 +1,93 @@
package com.baiye.notify.listener;
import com.baiye.constant.DefaultNumberConstants;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.model.entity.Announcement;
import com.baiye.notify.model.entity.UserAnnouncement;
import com.baiye.notify.recipient.RecipientHandler;
import com.baiye.notify.service.AnnouncementService;
import com.baiye.notify.service.UserAnnouncementService;
import com.baiye.security.userdetails.User;
import com.baiye.system.model.entity.SysUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author Hccake 2020/12/23
* @version 1.0
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class AnnouncementLoginEventListener {
private final AnnouncementService announcementService;
private final RecipientHandler recipientHandler;
private final UserAnnouncementService userAnnouncementService;
/**
*
* @param event event
*/
@EventListener(AuthenticationSuccessEvent.class)
public void onAuthenticationSuccessEvent(AuthenticationSuccessEvent event) throws InterruptedException {
AbstractAuthenticationToken source = (AbstractAuthenticationToken) event.getSource();
Object details = source.getDetails();
if (!(details instanceof HashMap)) {
return;
}
// https://github.com/spring-projects-experimental/spring-authorization-server
if ("password".equals(((HashMap) details).get("grant_type"))) {
User user = (User) source.getPrincipal();
SysUser sysUser = getSysUser(user);
// 获取当前用户未拉取过的公告信息
Long userId = sysUser.getUserId();
List<Announcement> announcements = announcementService.listUnPulled(userId);
// 获取当前用户的各个过滤属性
Map<Integer, Object> filterAttrs = recipientHandler.getFilterAttrs(sysUser);
// 获取符合当前用户条件的,且接收类型包含站内的公告,保存其关联关系
List<UserAnnouncement> userAnnouncements = announcements.stream()
.filter(x -> x.getReceiveMode().contains(NotifyChannelEnum.STATION.getValue()))
.filter(x -> filterMatched(x, filterAttrs))
.map(x -> userAnnouncementService.prodUserAnnouncement
(userId, x.getId(), DefaultNumberConstants.ZERO_NUMBER, x.getType(), null, x.getTitle(), x.getContent()))
.collect(Collectors.toList());
try {
userAnnouncementService.saveBatch(userAnnouncements);
}
catch (Exception exception) {
log.error("用户公告保存失败:[{}]", userAnnouncements, exception);
}
}
}
private SysUser getSysUser(User user) {
SysUser sysUser = new SysUser();
sysUser.setUserId(user.getUserId());
sysUser.setUsername(user.getUsername());
sysUser.setNickname(user.getNickname());
sysUser.setAvatar(user.getAvatar());
sysUser.setOrganizationId(user.getOrganizationId());
sysUser.setType(user.getType());
return sysUser;
}
private boolean filterMatched(Announcement announ, Map<Integer, Object> filterAttrs) {
Integer type = announ.getRecipientFilterType();
return recipientHandler.match(type, filterAttrs.get(type), announ.getRecipientFilterCondition());
}
}

@ -0,0 +1,37 @@
package com.baiye.notify.listener;
import com.baiye.notify.event.NotifyPublishEvent;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.notify.push.NotifyPushExecutor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
*
*
* @author Hccake 2020/12/17
* @version 1.0
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class NotifyPublishEventListener {
private final NotifyPushExecutor notifyPushExecutor;
/**
*
* @param event the NotifyPublishEvent
*/
@Async
@EventListener(NotifyPublishEvent.class)
public void onNotifyPublishEvent(NotifyPublishEvent event) {
NotifyInfo notifyInfo = event.getNotifyInfo();
// 推送通知
notifyPushExecutor.push(notifyInfo);
}
}

@ -0,0 +1,76 @@
package com.baiye.notify.mapper;
import com.baiye.constant.GlobalConstants;
import com.baiye.domain.PageParam;
import com.baiye.domain.PageResult;
import com.baiye.notify.enums.AnnouncementStatusEnum;
import com.baiye.notify.model.entity.Announcement;
import com.baiye.notify.model.qo.AnnouncementQO;
import com.baiye.notify.model.vo.AnnouncementPageVO;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.baiye.extend.mybatis.plus.conditions.query.LambdaQueryWrapperX;
import com.baiye.extend.mybatis.plus.mapper.ExtendMapper;
import com.baiye.extend.mybatis.plus.toolkit.WrappersX;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
*
*
* @author hccake 2020-12-15 17:01:15
*/
public interface AnnouncementMapper extends ExtendMapper<Announcement> {
/**
*
* @param pageParam
* @param qo
* @return PageResult
*/
default PageResult<AnnouncementPageVO> queryPage(PageParam pageParam, AnnouncementQO qo) {
IPage<Announcement> page = this.prodPage(pageParam);
LambdaQueryWrapperX<Announcement> wrapperX = WrappersX.lambdaAliasQueryX(Announcement.class)
.likeIfPresent(Announcement::getTitle, qo.getTitle())
.inIfPresent(Announcement::getStatus, (Object[]) qo.getStatus())
.eqIfPresent(Announcement::getRecipientFilterType, qo.getRecipientFilterType())
.eq(Announcement::getDeleted, GlobalConstants.NOT_DELETED_FLAG);
IPage<AnnouncementPageVO> voPage = this.selectByPage(page, wrapperX);
return new PageResult<>(voPage.getRecords(), voPage.getTotal());
}
/**
*
* @param page
* @param wrapper
* @return
*/
IPage<AnnouncementPageVO> selectByPage(IPage<Announcement> page,
@Param(Constants.WRAPPER) Wrapper<Announcement> wrapper);
/**
*
* @param announcement
* @return
*/
default boolean updateIfUnpublished(Announcement announcement) {
int flag = this.update(announcement,
Wrappers.<Announcement>lambdaUpdate()
.eq(Announcement::getId, announcement.getId())
.eq(Announcement::getStatus, AnnouncementStatusEnum.UNPUBLISHED.getValue()));
return SqlHelper.retBool(flag);
}
/**
*
* @param userId ID
* @param pulled
* @return
*/
List<Announcement> listUserAnnouncements(@Param("userId") Long userId, @Param("pulled") boolean pulled);
}

@ -0,0 +1,60 @@
package com.baiye.notify.mapper;
import com.baiye.domain.PageParam;
import com.baiye.domain.PageResult;
import com.baiye.extend.mybatis.plus.conditions.query.LambdaQueryWrapperX;
import com.baiye.extend.mybatis.plus.mapper.ExtendMapper;
import com.baiye.extend.mybatis.plus.toolkit.WrappersX;
import com.baiye.notify.converter.UserAnnouncementConverter;
import com.baiye.notify.enums.UserAnnouncementStateEnum;
import com.baiye.notify.model.entity.UserAnnouncement;
import com.baiye.notify.model.qo.UserAnnouncementQO;
import com.baiye.notify.model.vo.UserAnnouncementPageVO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.time.LocalDateTime;
/**
*
*
* @author hccake 2020-12-25 08:04:53
*/
public interface UserAnnouncementMapper extends ExtendMapper<UserAnnouncement> {
/**
*
* @param pageParam
* @param qo
* @return PageResult
*/
default PageResult<UserAnnouncementPageVO> queryPage(PageParam pageParam, UserAnnouncementQO qo) {
IPage<UserAnnouncement> page = this.prodPage(pageParam);
LambdaQueryWrapperX<UserAnnouncement> wrapperX = WrappersX.lambdaQueryX(UserAnnouncement.class);
if (StringUtils.isNotBlank(qo.getStartTime()) && StringUtils.isNotBlank(qo.getEndTime())) {
wrapperX.between(UserAnnouncement::getCreateTime, qo.getStartTime(), qo.getEndTime());
}
wrapperX.eqIfPresent(UserAnnouncement::getId, qo.getId()).likeIfPresent(UserAnnouncement::getContent, qo.getContent())
.orderByDesc(UserAnnouncement::getState).orderByAsc(UserAnnouncement::getId);
this.selectPage(page, wrapperX);
IPage<UserAnnouncementPageVO> voPage = page.convert(UserAnnouncementConverter.INSTANCE::poToPageVo);
return new PageResult<>(voPage.getRecords(), voPage.getTotal());
}
/**
*
* @param userId ID
* @param announcementId ID
*/
default void updateToReadState(Long userId, Long announcementId) {
LambdaUpdateWrapper<UserAnnouncement> wrapper = Wrappers.<UserAnnouncement>lambdaUpdate()
.set(UserAnnouncement::getState, UserAnnouncementStateEnum.READ.getValue())
.set(UserAnnouncement::getReadTime, LocalDateTime.now())
.eq(UserAnnouncement::getAnnouncementId, announcementId)
.eq(UserAnnouncement::getUserId, userId);
this.update(null, wrapper);
}
}

@ -0,0 +1,52 @@
/*
package com.baiye.notify.push;
import cn.hutool.core.util.StrUtil;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.system.model.entity.SysUser;
import lombok.RequiredArgsConstructor;
import org.springframework.mail.MailSender;
import java.util.List;
*/
/**
*
*
* @author Hccake 2020/12/21
* @version 1.0
*//*
@RequiredArgsConstructor
public class MailNotifyPusher implements NotifyPusher {
private final MailSender mailSender;
*/
/**
*
* @see NotifyChannelEnum
* @return
*//*
@Override
public Integer notifyChannel() {
return NotifyChannelEnum.MAIL.getValue();
}
@Override
public void push(NotifyInfo notifyInfo, List<SysUser> userList) {
String[] emails = userList.stream().map(SysUser::getEmail).filter(StrUtil::isNotBlank).toArray(String[]::new);
// 密送群发,不展示其他收件人
MailDetails mailDetails = new MailDetails();
mailDetails.setShowHtml(true);
mailDetails.setSubject(notifyInfo.getTitle());
mailDetails.setContent(notifyInfo.getContent());
mailDetails.setBcc(emails);
mailSender.sendMail(mailDetails);
}
}
*/

@ -0,0 +1,77 @@
package com.baiye.notify.push;
import cn.hutool.core.collection.CollUtil;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.notify.recipient.RecipientHandler;
import com.baiye.system.model.entity.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
*
*
* @author Hccake 2020/12/21
* @version 1.0
*/
@Slf4j
@Component
public class NotifyPushExecutor {
private final RecipientHandler recipientHandler;
private final Map<Integer, NotifyPusher> notifyPusherMap = new LinkedHashMap<>();
public NotifyPushExecutor(RecipientHandler recipientHandler, List<NotifyPusher> notifyPusherList) {
this.recipientHandler = recipientHandler;
if (CollUtil.isNotEmpty(notifyPusherList)) {
for (NotifyPusher notifyPusher : notifyPusherList) {
this.addNotifyPusher(notifyPusher);
}
}
}
/**
*
* @param notifyPusher
*/
public void addNotifyPusher(NotifyPusher notifyPusher) {
this.notifyPusherMap.put(notifyPusher.notifyChannel(), notifyPusher);
}
/**
*
* @param notifyInfo
*
*/
public void push(NotifyInfo notifyInfo) {
// 获取通知接收人
Integer recipientFilterType = notifyInfo.getRecipientFilterType();
List<Object> recipientFilterCondition = notifyInfo.getRecipientFilterCondition();
List<SysUser> userList = recipientHandler.query(recipientFilterType, recipientFilterCondition);
// 执行推送
// TODO 返回推送失败渠道信息,以便重试
for (Integer notifyChannel : notifyInfo.getReceiveMode()) {
try {
NotifyPusher notifyPusher = notifyPusherMap.get(notifyChannel);
if (notifyPusher == null) {
log.error("Unknown notify channel[{}]notifyInfo title[{}]", notifyChannel,
notifyInfo.getTitle());
}
else {
notifyPusher.push(notifyInfo, userList);
}
}
catch (Exception e) {
log.error("push notify error in channel[{}]notifyInfo title[{}]", notifyChannel,
notifyInfo.getTitle(), e);
}
}
}
}

@ -0,0 +1,33 @@
package com.baiye.notify.push;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.system.model.entity.SysUser;
import java.util.List;
/**
*
*
* @author Hccake 2020/12/21
* @version 1.0
*/
public interface NotifyPusher {
/**
*
* @see NotifyChannelEnum
* @return
*/
Integer notifyChannel();
/**
*
* @param notifyInfo
* @param userList
*/
void push(NotifyInfo notifyInfo, List<SysUser> userList);
}

@ -0,0 +1,45 @@
package com.baiye.notify.push;
import cn.hutool.core.util.StrUtil;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.system.model.entity.SysUser;
import com.baiye.util.HtmlUtils;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
*
*
* @author Hccake 2020/12/21
* @version 1.0
*/
@Component
public class SmsNotifyPusher implements NotifyPusher {
/**
*
* @see NotifyChannelEnum
* @return
*/
@Override
public Integer notifyChannel() {
return NotifyChannelEnum.SMS.getValue();
}
@Override
public void push(NotifyInfo notifyInfo, List<SysUser> userList) {
List<String> phoneList = userList.stream()
.map(SysUser::getPhoneNumber)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList());
// 短信文本去除 html 标签
String content = HtmlUtils.toText(notifyInfo.getContent());
// TODO 对接短信发送平台
System.out.println("短信推送");
}
}

@ -0,0 +1,45 @@
package com.baiye.notify.push;
;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.event.StationNotifyPushEvent;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.system.model.entity.SysUser;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
*
*
* @author Hccake 2020/12/21
* @version 1.0
*/
@Component
@RequiredArgsConstructor
public class StationNotifyPusher implements NotifyPusher {
private final ApplicationEventPublisher publisher;
/**
*
*
* @return
* @see NotifyChannelEnum
*/
@Override
public Integer notifyChannel() {
return NotifyChannelEnum.STATION.getValue();
}
@Override
public void push(NotifyInfo notifyInfo, List<SysUser> userList) {
List<Long> userIdList = userList.stream().map(SysUser::getUserId).collect(Collectors.toList());
// 发布事件,监听者进行实际的 websocket 推送
publisher.publishEvent(new StationNotifyPushEvent(notifyInfo, userIdList));
}
}

@ -0,0 +1,62 @@
package com.baiye.notify.recipient;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import com.baiye.system.model.entity.SysUser;
import com.baiye.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author Hccake 2020/12/21
* @version 1.0
*/
@Component
@RequiredArgsConstructor
public class AllRecipientFilter implements RecipientFilter {
private final SysUserService sysUserService;
/**
*
* @return
* @see NotifyRecipientFilterTypeEnum
*/
@Override
public Integer filterType() {
return NotifyRecipientFilterTypeEnum.ALL.getValue();
}
/**
*
* @param filterCondition
* @return
*/
@Override
public List<SysUser> filter(List<Object> filterCondition) {
return sysUserService.list();
}
/**
*
* @param sysUser
* @return
*/
@Override
public Object getFilterAttr(SysUser sysUser) {
return null;
}
/**
*
* @param filterAttr
* @param filterCondition
* @return boolean true:
*/
@Override
public boolean match(Object filterAttr, List<Object> filterCondition) {
return true;
}
}

@ -0,0 +1,46 @@
package com.baiye.notify.recipient;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import com.baiye.system.model.entity.SysUser;
import java.util.List;
/**
*
*
* @author Hccake 2020/12/21
* @version 1.0
*/
public interface RecipientFilter {
/**
*
* @see NotifyRecipientFilterTypeEnum
* @return
*/
Integer filterType();
/**
*
* @param filterCondition
* @return
*/
List<SysUser> filter(List<Object> filterCondition);
/**
*
* @param sysUser
* @return
*/
Object getFilterAttr(SysUser sysUser);
/**
*
* @param filterAttr
* @param filterCondition
* @return boolean true:
*/
boolean match(Object filterAttr, List<Object> filterCondition);
}

@ -0,0 +1,60 @@
package com.baiye.notify.recipient;
import com.baiye.system.model.entity.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* @author Hccake 2020/12/21
* @version 1.0
*/
@Slf4j
@Component
public class RecipientHandler {
private final Map<Integer, RecipientFilter> recipientFilterMap = new LinkedHashMap<>();
public RecipientHandler(List<RecipientFilter> recipientFilterList) {
for (RecipientFilter recipientFilter : recipientFilterList) {
this.recipientFilterMap.put(recipientFilter.filterType(), recipientFilter);
}
}
public List<SysUser> query(Integer filterType, List<Object> filterCondition) {
RecipientFilter recipientFilter = recipientFilterMap.get(filterType);
if (recipientFilter == null) {
log.error("Unknown recipient filter[{}]filterCondition{}", filterType, filterCondition);
return new ArrayList<>();
}
return recipientFilter.filter(filterCondition);
}
/**
*
* @param recipientFilterType
* @param filterAttr
* @param recipientFilterCondition
* @return boolean true
*/
public boolean match(Integer recipientFilterType, Object filterAttr, List<Object> recipientFilterCondition) {
RecipientFilter recipientFilter = recipientFilterMap.get(recipientFilterType);
return recipientFilter != null && recipientFilter.match(filterAttr, recipientFilterCondition);
}
/**
*
* @param sysUser
* @return Map keyfilterType value: attr
*/
public Map<Integer, Object> getFilterAttrs(SysUser sysUser) {
Map<Integer, Object> map = new HashMap<>(recipientFilterMap.size());
for (RecipientFilter recipientFilter : recipientFilterMap.values()) {
Object obj = recipientFilter.getFilterAttr(sysUser);
map.put(recipientFilter.filterType(), obj);
}
return map;
}
}

@ -0,0 +1,65 @@
package com.baiye.notify.recipient;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import com.baiye.system.model.entity.SysUser;
import com.baiye.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Hccake 2020/12/21
* @version 1.0
*/
@Component
@RequiredArgsConstructor
public class SpecifyOrganizationRecipientFilter implements RecipientFilter {
private final SysUserService sysUserService;
/**
*
* @return
* @see NotifyRecipientFilterTypeEnum
*/
@Override
public Integer filterType() {
return NotifyRecipientFilterTypeEnum.SPECIFY_ORGANIZATION.getValue();
}
/**
*
* @param filterCondition
* @return
*/
@Override
public List<SysUser> filter(List<Object> filterCondition) {
List<Long> organizationIds = filterCondition.stream().map(Long.class::cast).collect(Collectors.toList());
return sysUserService.listByOrganizationIds(organizationIds);
}
/**
*
* @param sysUser
* @return
*/
@Override
public Object getFilterAttr(SysUser sysUser) {
return sysUser.getOrganizationId();
}
/**
*
* @param filterAttr
* @param filterCondition
* @return boolean true:
*/
@Override
public boolean match(Object filterAttr, List<Object> filterCondition) {
Integer organizationId = (Integer) filterAttr;
return filterCondition.stream().map(Integer.class::cast).anyMatch(x -> x.equals(organizationId));
}
}

@ -0,0 +1,79 @@
package com.baiye.notify.recipient;
import cn.hutool.core.collection.CollUtil;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import com.baiye.system.model.entity.SysUser;
import com.baiye.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Hccake 2020/12/21
* @version 1.0
*/
@Component
@RequiredArgsConstructor
public class SpecifyRoleRecipientFilter implements RecipientFilter {
private final SysUserService sysUserService;
/**
*
* @return
* @see NotifyRecipientFilterTypeEnum
*/
@Override
public Integer filterType() {
return NotifyRecipientFilterTypeEnum.SPECIFY_ROLE.getValue();
}
/**
*
* @param filterCondition
* @return
*/
@Override
public List<SysUser> filter(List<Object> filterCondition) {
List<String> roleCodes = filterCondition.stream().map(String.class::cast).collect(Collectors.toList());
return sysUserService.listByRoleCodes(roleCodes);
}
/**
*
* @param sysUser
* @return
*/
@Override
public Object getFilterAttr(SysUser sysUser) {
return sysUserService.listRoleCodes(sysUser.getUserId());
}
/**
*
* @param filterAttr
* @param filterCondition
* @return boolean true:
*/
@Override
@SuppressWarnings("unchecked")
public boolean match(Object filterAttr, List<Object> filterCondition) {
if (!(filterAttr instanceof List)) {
return false;
}
List<String> roleCodes = (List<String>) filterAttr;
if (CollUtil.isEmpty(roleCodes)) {
return false;
}
for (Object roleCode : roleCodes) {
boolean matched = filterCondition.stream().map(String.class::cast).anyMatch(x -> x.equals(roleCode));
if (matched) {
return true;
}
}
return false;
}
}

@ -0,0 +1,65 @@
package com.baiye.notify.recipient;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import com.baiye.system.model.entity.SysUser;
import com.baiye.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Hccake 2020/12/21
* @version 1.0
*/
@Component
@RequiredArgsConstructor
public class SpecifyUserRecipientFilter implements RecipientFilter {
private final SysUserService sysUserService;
/**
*
* @return
* @see NotifyRecipientFilterTypeEnum
*/
@Override
public Integer filterType() {
return NotifyRecipientFilterTypeEnum.SPECIFY_USER.getValue();
}
/**
*
* @param filterCondition ID
* @return
*/
@Override
public List<SysUser> filter(List<Object> filterCondition) {
List<Long> userIds = filterCondition.stream().map(Long.class::cast).collect(Collectors.toList());
return sysUserService.listByUserIds(userIds);
}
/**
*
* @param sysUser
* @return
*/
@Override
public Object getFilterAttr(SysUser sysUser) {
return sysUser.getUserId();
}
/**
*
* @param filterAttr
* @param filterCondition
* @return boolean true:
*/
@Override
public boolean match(Object filterAttr, List<Object> filterCondition) {
Long userId = (Long) filterAttr;
return filterCondition.stream().map(Long.class::cast).anyMatch(x -> x.equals(userId));
}
}

@ -0,0 +1,65 @@
package com.baiye.notify.recipient;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import com.baiye.system.model.entity.SysUser;
import com.baiye.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Hccake 2020/12/21
* @version 1.0
*/
@Component
@RequiredArgsConstructor
public class SpecifyUserTypeRecipientFilter implements RecipientFilter {
private final SysUserService sysUserService;
/**
*
* @return
* @see NotifyRecipientFilterTypeEnum
*/
@Override
public Integer filterType() {
return NotifyRecipientFilterTypeEnum.SPECIFY_USER_TYPE.getValue();
}
/**
*
* @param filterCondition
* @return
*/
@Override
public List<SysUser> filter(List<Object> filterCondition) {
List<Integer> userTypes = filterCondition.stream().map(Integer.class::cast).collect(Collectors.toList());
return sysUserService.listByUserTypes(userTypes);
}
/**
*
* @param sysUser
* @return
*/
@Override
public Object getFilterAttr(SysUser sysUser) {
return sysUser.getType();
}
/**
*
* @param filterAttr
* @param filterCondition
* @return boolean true:
*/
@Override
public boolean match(Object filterAttr, List<Object> filterCondition) {
Integer type = (Integer) filterAttr;
return filterCondition.stream().map(Integer.class::cast).anyMatch(x -> x.equals(type));
}
}

@ -0,0 +1,79 @@
package com.baiye.notify.service;
import com.baiye.domain.PageParam;
import com.baiye.domain.PageResult;
import com.baiye.extend.mybatis.plus.service.ExtendService;
import com.baiye.notify.model.dto.AnnouncementDTO;
import com.baiye.notify.model.entity.Announcement;
import com.baiye.notify.model.qo.AnnouncementQO;
import com.baiye.notify.model.vo.AnnouncementPageVO;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
*
*
* @author hccake 2020-12-15 17:01:15
*/
public interface AnnouncementService extends ExtendService<Announcement> {
/**
* QueryObject
* @param page
* @param qo
* @return PageResult<AnnouncementVO>
*/
PageResult<AnnouncementPageVO> queryPage(PageParam page, AnnouncementQO qo);
/**
*
* @param announcementDTO
* @return boolean
*/
boolean addAnnouncement(AnnouncementDTO announcementDTO);
/**
*
* @param announcementDTO announcementDTO
* @return boolean
*/
boolean updateAnnouncement(AnnouncementDTO announcementDTO);
/**
*
* @param announcementId ID
* @return boolean
*/
boolean publish(Long announcementId);
/**
*
* @param announcementId ID
* @return boolean
*/
boolean close(Long announcementId);
/**
*
* @param files
* @return
*/
List<String> uploadImages(List<MultipartFile> files);
/**
*
* @param userId id
* @return List<Announcement>
*/
List<Announcement> listUnPulled(Long userId);
/**
*
* @param userId id
* @return List<Announcement>
*/
List<Announcement> listActiveAnnouncements(Long userId);
}

@ -0,0 +1,47 @@
package com.baiye.notify.service;
import com.baiye.domain.PageParam;
import com.baiye.domain.PageResult;
import com.baiye.extend.mybatis.plus.service.ExtendService;
import com.baiye.notify.model.entity.UserAnnouncement;
import com.baiye.notify.model.qo.UserAnnouncementQO;
import com.baiye.notify.model.vo.UserAnnouncementPageVO;
/**
*
*
* @author hccake 2020-12-25 08:04:53
*/
public interface UserAnnouncementService extends ExtendService<UserAnnouncement> {
/**
* QueryObject
* @param pageParam
* @param qo
* @return PageResult<AnnouncementVO>
*/
PageResult<UserAnnouncementPageVO> queryPage(PageParam pageParam, UserAnnouncementQO qo);
/**
* IDid
*
* @param userId ID
* @param announcementId ID
* @param state
* @param type
* @param messageKey
* @param title
* @param content
* @return UserAnnouncement
*/
UserAnnouncement prodUserAnnouncement(Long userId, Long announcementId, Integer state, Integer type, String messageKey, String title, String content);
/**
*
* @param userId id
* @param announcementId id
*/
void readAnnouncement(Long userId, Long announcementId);
}

@ -0,0 +1,214 @@
package com.baiye.notify.service.impl;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.IdUtil;
import com.baiye.constant.enums.BooleanEnum;
import com.baiye.domain.PageParam;
import com.baiye.domain.PageResult;
import com.baiye.exception.BusinessException;
import com.baiye.extend.mybatis.plus.service.impl.ExtendServiceImpl;
import com.baiye.notify.converter.AnnouncementConverter;
import com.baiye.notify.converter.NotifyInfoConverter;
import com.baiye.notify.enums.AnnouncementStatusEnum;
import com.baiye.notify.event.AnnouncementCloseEvent;
import com.baiye.notify.event.NotifyPublishEvent;
import com.baiye.notify.mapper.AnnouncementMapper;
import com.baiye.notify.model.domain.NotifyInfo;
import com.baiye.notify.model.dto.AnnouncementDTO;
import com.baiye.notify.model.entity.Announcement;
import com.baiye.notify.model.qo.AnnouncementQO;
import com.baiye.notify.model.vo.AnnouncementPageVO;
import com.baiye.notify.service.AnnouncementService;
import com.baiye.result.SystemResultCode;
import com.baiye.util.FileUtil;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
/**
*
*
* @author hccake 2020-12-15 17:01:15
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AnnouncementServiceImpl extends ExtendServiceImpl<AnnouncementMapper, Announcement>
implements AnnouncementService {
private final ApplicationEventPublisher publisher;
// private final FileService fileService;
/**
* QueryObject
*
* @param pageParam
* @param qo
* @return PageResult<AnnouncementVO>
*/
@Override
public PageResult<AnnouncementPageVO> queryPage(PageParam pageParam, AnnouncementQO qo) {
return baseMapper.queryPage(pageParam, qo);
}
/**
*
*
* @param announcementDTO
* @return boolean
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean addAnnouncement(AnnouncementDTO announcementDTO) {
Announcement announcement = AnnouncementConverter.INSTANCE.dtoToPo(announcementDTO);
announcement.setId(null);
int flag = baseMapper.insert(announcement);
boolean inserted = SqlHelper.retBool(flag);
// 公告发布事件
boolean isPublishStatus = announcement.getStatus() == AnnouncementStatusEnum.ENABLED.getValue();
if (inserted && isPublishStatus) {
this.onAnnouncementPublish(announcement);
}
return inserted;
}
/**
*
*
* @param announcementDTO announcementDTO
* @return boolean
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateAnnouncement(AnnouncementDTO announcementDTO) {
Announcement oldAnnouncement = baseMapper.selectById(announcementDTO.getId());
if (oldAnnouncement.getStatus() != AnnouncementStatusEnum.UNPUBLISHED.getValue()) {
throw new BusinessException(SystemResultCode.BAD_REQUEST.getCode(), "不允许修改已经发布过的公告!");
}
Announcement announcement = AnnouncementConverter.INSTANCE.dtoToPo(announcementDTO);
// 不允许修改为《发布中》以外的状态
boolean isPublishStatus = announcement.getStatus() == AnnouncementStatusEnum.ENABLED.getValue();
if (!isPublishStatus) {
announcement.setStatus(null);
}
// 保证当前状态未被修改过
boolean isUpdated = baseMapper.updateIfUnpublished(announcement);
// 公告发布事件
if (isUpdated && isPublishStatus) {
this.onAnnouncementPublish(announcement);
}
return isUpdated;
}
/**
*
*
* @param announcementId ID
* @return boolean
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean publish(Long announcementId) {
Announcement announcement = baseMapper.selectById(announcementId);
if (announcement.getStatus() != AnnouncementStatusEnum.UNPUBLISHED.getValue()) {
throw new BusinessException(SystemResultCode.BAD_REQUEST.getCode(), "不允许修改已经发布过的公告!");
}
if (BooleanEnum.TRUE.intValue().equals(announcement.getImmortal())
&& LocalDateTime.now().isAfter(announcement.getDeadline())) {
throw new BusinessException(SystemResultCode.BAD_REQUEST.getCode(), "公告失效时间必须迟于当前时间!");
}
// 更新公共至发布状态
Announcement entity = new Announcement();
entity.setId(announcementId);
entity.setStatus(AnnouncementStatusEnum.ENABLED.getValue());
boolean isUpdated = baseMapper.updateIfUnpublished(entity);
if (isUpdated) {
announcement.setStatus(AnnouncementStatusEnum.ENABLED.getValue());
this.onAnnouncementPublish(announcement);
}
return isUpdated;
}
/**
*
*
* @param announcementId ID
* @return boolean
*/
@Override
public boolean close(Long announcementId) {
Announcement announcement = new Announcement();
announcement.setId(announcementId);
announcement.setStatus(AnnouncementStatusEnum.DISABLED.getValue());
int flag = baseMapper.updateById(announcement);
boolean isUpdated = SqlHelper.retBool(flag);
if (isUpdated) {
publisher.publishEvent(new AnnouncementCloseEvent(announcementId));
}
return isUpdated;
}
/**
*
*
* @param files
* @return
*/
@Override
public List<String> uploadImages(List<MultipartFile> files) {
List<String> objectNames = new ArrayList<>();
for (MultipartFile file : files) {
String objectName = "announcement/" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE)
+ StrPool.SLASH + IdUtil.fastSimpleUUID() + StrPool.DOT
+ FileUtil.extName(file.getOriginalFilename());
FileUtil.upload(file, objectName);
objectNames.add(objectName);
}
return objectNames;
}
/**
*
*
* @return List<Announcement>
*/
@Override
public List<Announcement> listUnPulled(Long userId) {
return baseMapper.listUserAnnouncements(userId, false);
}
/**
*
*
* @param userId id
* @return List<Announcement>
*/
@Override
public List<Announcement> listActiveAnnouncements(Long userId) {
return baseMapper.listUserAnnouncements(userId, true);
}
/**
*
*
* @param announcement
*/
private void onAnnouncementPublish(Announcement announcement) {
NotifyInfo notifyInfo = NotifyInfoConverter.INSTANCE.fromAnnouncement(announcement);
publisher.publishEvent(new NotifyPublishEvent(notifyInfo));
}
}

@ -0,0 +1,74 @@
package com.baiye.notify.service.impl;
import com.baiye.domain.PageParam;
import com.baiye.domain.PageResult;
import com.baiye.extend.mybatis.plus.service.impl.ExtendServiceImpl;
import com.baiye.notify.enums.UserAnnouncementStateEnum;
import com.baiye.notify.mapper.UserAnnouncementMapper;
import com.baiye.notify.model.entity.UserAnnouncement;
import com.baiye.notify.model.qo.UserAnnouncementQO;
import com.baiye.notify.model.vo.UserAnnouncementPageVO;
import com.baiye.notify.service.UserAnnouncementService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
/**
*
*
* @author hccake 2020-12-25 08:04:53
*/
@Service
public class UserAnnouncementServiceImpl extends ExtendServiceImpl<UserAnnouncementMapper, UserAnnouncement>
implements UserAnnouncementService {
/**
* QueryObject
* @param pageParam
* @param qo
* @return PageResult<UserAnnouncementVO>
*/
@Override
public PageResult<UserAnnouncementPageVO> queryPage(PageParam pageParam, UserAnnouncementQO qo) {
return baseMapper.queryPage(pageParam, qo);
}
/**
* IDid
*
* @param userId ID
* @param announcementId ID
* @param state
* @param type
* @param messageKey
* @param title
* @param content
* @return UserAnnouncement
*/
@Override
public UserAnnouncement prodUserAnnouncement(Long userId, Long announcementId, Integer state, Integer type, String messageKey, String title, String content) {
UserAnnouncement userAnnouncement = new UserAnnouncement();
userAnnouncement.setType(type);
userAnnouncement.setState(state);
userAnnouncement.setTitle(title);
userAnnouncement.setUserId(userId);
userAnnouncement.setContent(content);
userAnnouncement.setMessageKey(messageKey);
userAnnouncement.setAnnouncementId(announcementId);
userAnnouncement.setCreateTime(LocalDateTime.now());
userAnnouncement.setState(UserAnnouncementStateEnum.UNREAD.getValue());
return userAnnouncement;
}
/**
*
* @param userId id
* @param announcementId id
*/
@Override
public void readAnnouncement(Long userId, Long announcementId) {
baseMapper.updateToReadState(userId, announcementId);
}
}

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baiye.notify.mapper.AnnouncementMapper">
<resultMap id="announcementVoMap" type="com.baiye.notify.model.vo.AnnouncementPageVO">
<id property="id" column="id"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<result property="recipientFilterType" column="recipient_filter_type"/>
<result property="recipientFilterCondition" column="recipient_filter_condition"
typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
<result property="receiveMode" column="receive_mode"
typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
<result property="status" column="status"/>
<result property="immortal" column="immortal"/>
<result property="deadline" column="deadline"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<sql id="Base_Column_List">
id, title, content, recipient_filter_type, recipient_filter_condition, receive_mode,
status, immortal, deadline, create_by, create_time, update_time
</sql>
<sql id="Base_Alias_Column_List">
a.id, a.title, a.content, a.recipient_filter_type, a.recipient_filter_condition, a.receive_mode,
a.status, a.immortal, a.deadline, a.create_by, a.create_time, a.update_time
</sql>
<select id="selectByPage" resultMap="announcementVoMap">
SELECT
<include refid="Base_Alias_Column_List"/>
, su.username as create_username
FROM
notify_announcement a
LEFT JOIN sys_user su ON a.create_by = su.user_id
${ew.customSqlSegment}
</select>
<!-- com.baomidou.mybatisplus.core.metadata.TableInfo.initResultMapIfNeed -->
<select id="listUserAnnouncements" resultMap="mybatis-plus_Announcement">
SELECT
<include refid="Base_Alias_Column_List"/>
FROM
notify_announcement a
LEFT JOIN notify_user_announcement ua
ON ua.user_id = #{userId} AND ua.announcement_id = a.id
WHERE
a.STATUS = 1
AND ( a.immortal = 1 OR a.deadline > now() )
<choose>
<when test="pulled">
AND ua.id IS NOT NULL
</when>
<otherwise>
AND ua.id IS NULL
</otherwise>
</choose>
</select>
</mapper>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.baiye</groupId>
<artifactId>ad-distribute-notify</artifactId>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>distribute-notify-controller</artifactId>
<dependencies>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>common-log</artifactId>
</dependency>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>distribute-notify-biz</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,139 @@
package com.baiye.notify.controller;
import com.baiye.domain.PageParam;
import com.baiye.domain.PageResult;
import com.baiye.notify.model.dto.AnnouncementDTO;
import com.baiye.notify.model.entity.Announcement;
import com.baiye.notify.model.qo.AnnouncementQO;
import com.baiye.notify.model.vo.AnnouncementPageVO;
import com.baiye.notify.service.AnnouncementService;
import com.baiye.operation.annotation.CreateOperationLogging;
import com.baiye.operation.annotation.DeleteOperationLogging;
import com.baiye.operation.annotation.UpdateOperationLogging;
import com.baiye.result.BaseResultCode;
import com.baiye.result.R;
import com.baiye.security.util.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import java.util.List;
/**
*
*
* @author hccake 2020-12-15 17:01:15
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/notify/announcement")
@Tag(name = "公告信息管理")
public class AnnouncementController {
private final AnnouncementService announcementService;
/**
*
* @param pageParam
* @param announcementQO
* @return R
*/
@GetMapping("/page")
// @PreAuthorize("@per.hasPermission('notify:announcement:read')")
@Operation(summary = "分页查询", description = "分页查询")
public R<PageResult<AnnouncementPageVO>> getAnnouncementPage(@Validated PageParam pageParam,
AnnouncementQO announcementQO) {
return R.ok(announcementService.queryPage(pageParam, announcementQO));
}
/**
*
* @param announcementDTO
* @return R
*/
@CreateOperationLogging(msg = "新增公告信息")
@PostMapping
// @PreAuthorize("@per.hasPermission('notify:announcement:add')")
@Operation(summary = "新增公告信息", description = "新增公告信息")
public R<Void> save(@Valid @RequestBody AnnouncementDTO announcementDTO) {
return announcementService.addAnnouncement(announcementDTO) ? R.ok()
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "新增公告信息失败");
}
/**
*
* @param announcementDTO
* @return R
*/
@UpdateOperationLogging(msg = "修改公告信息")
@PutMapping
// @PreAuthorize("@per.hasPermission('notify:announcement:edit')")
@Operation(summary = "修改公告信息", description = "修改公告信息")
public R<Void> updateById(@Valid @RequestBody AnnouncementDTO announcementDTO) {
return announcementService.updateAnnouncement(announcementDTO) ? R.ok()
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "修改公告信息失败");
}
/**
* id
* @param id id
* @return R
*/
@DeleteOperationLogging(msg = "通过id删除公告信息")
@DeleteMapping("/{id}")
// @PreAuthorize("@per.hasPermission('notify:announcement:del')")
@Operation(summary = "通过id删除公告信息", description = "通过id删除公告信息")
public R<Void> removeById(@PathVariable("id") Long id) {
return announcementService.removeById(id) ? R.ok()
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "通过id删除公告信息失败");
}
/**
*
* @return R
*/
@UpdateOperationLogging(msg = "发布公告信息")
@PatchMapping("/publish/{announcementId}")
// @PreAuthorize("@per.hasPermission('notify:announcement:edit')")
@Operation(summary = "发布公告信息", description = "发布公告信息")
public R<Void> enableAnnouncement(@PathVariable("announcementId") Long announcementId) {
return announcementService.publish(announcementId) ? R.ok()
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "发布公告信息失败");
}
/**
*
* @return R
*/
@UpdateOperationLogging(msg = "关闭公告信息")
@PatchMapping("/close/{announcementId}")
// @PreAuthorize("@per.hasPermission('notify:announcement:edit')")
@Operation(summary = "关闭公告信息", description = "关闭公告信息")
public R<Void> disableAnnouncement(@PathVariable("announcementId") Long announcementId) {
return announcementService.close(announcementId) ? R.ok()
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "关闭公告信息失败");
}
@UpdateOperationLogging(msg = "公告内容图片上传", recordParams = false)
// @PreAuthorize("@per.hasPermission('notify:announcement:edit')")
@PostMapping("/image")
@Operation(summary = "公告内容图片上传", description = "公告内容图片上传")
public R<List<String>> uploadImages(@RequestParam("files") List<MultipartFile> files) {
List<String> objectNames = announcementService.uploadImages(files);
return R.ok(objectNames);
}
@GetMapping("/user")
// @PreAuthorize("@per.hasPermission('notify:userannouncement:read')")
@Operation(summary = "用户公告信息", description = "用户公告信息")
public R<List<Announcement>> getUserAnnouncements() {
Long userId = SecurityUtils.getUser().getUserId();
return R.ok(announcementService.listActiveAnnouncements(userId));
}
}

@ -0,0 +1,53 @@
package com.baiye.notify.controller;
import com.baiye.domain.PageParam;
import com.baiye.domain.PageResult;
import com.baiye.notify.model.qo.UserAnnouncementQO;
import com.baiye.notify.model.vo.UserAnnouncementPageVO;
import com.baiye.notify.service.UserAnnouncementService;
import com.baiye.result.R;
import com.baiye.security.util.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
*
*
* @author hccake 2020-12-25 08:04:53
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/notify/user-announcement")
@Tag(name = "用户公告表管理")
public class UserAnnouncementController {
private final UserAnnouncementService userAnnouncementService;
/**
*
* @param pageParam
* @param userAnnouncementQO
* @return R
*/
@GetMapping("/page")
// @PreAuthorize("@per.hasPermission('notify:userannouncement:read')")
@Operation(summary = "分页查询", description = "分页查询")
public R<PageResult<UserAnnouncementPageVO>> getUserAnnouncementPage(@Validated PageParam pageParam,
UserAnnouncementQO userAnnouncementQO) {
return R.ok(userAnnouncementService.queryPage(pageParam, userAnnouncementQO));
}
@PatchMapping("/read/{announcementId}")
// @PreAuthorize("@per.hasPermission('notify:userannouncement:read')")
@Operation(summary = "用户公告已读上报", description = "用户公告已读上报")
public R<Void> readAnnouncement(@PathVariable("announcementId") Long announcementId) {
Long userId = SecurityUtils.getUser().getUserId();
userAnnouncementService.readAnnouncement(userId, announcementId);
return R.ok();
}
}

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.baiye</groupId>
<artifactId>ad-distribute-notify</artifactId>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>distribute-notify-model</artifactId>
<dependencies>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>ad-distribute-extend-mybatis-plus</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<!-- bean 转换工具类 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.3.Final</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,36 @@
package com.baiye.notify.converter;
import com.baiye.notify.model.dto.AnnouncementDTO;
import com.baiye.notify.model.entity.Announcement;
import com.baiye.notify.model.vo.AnnouncementPageVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
/**
* @author Hccake 2020/12/16
* @version 1.0
*/
@Mapper
public interface AnnouncementConverter {
AnnouncementConverter INSTANCE = Mappers.getMapper(AnnouncementConverter.class);
/**
* PO PageVO
* @param announcement
* @return AnnouncementPageVO PageVO
*/
AnnouncementPageVO poToPageVo(Announcement announcement);
/**
* AnnouncementDTO Announcement
* @param dto AnnouncementDTO
* @return Announcement
*/
@Mapping(target = "updateTime", ignore = true)
@Mapping(target = "createTime", ignore = true)
@Mapping(target = "createBy", ignore = true)
Announcement dtoToPo(AnnouncementDTO dto);
}

@ -0,0 +1,24 @@
package com.baiye.notify.converter;
import com.baiye.notify.model.domain.AnnouncementNotifyInfo;
import com.baiye.notify.model.entity.Announcement;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @author Hccake 2020/12/23
* @version 1.0
*/
@Mapper
public interface NotifyInfoConverter {
NotifyInfoConverter INSTANCE = Mappers.getMapper(NotifyInfoConverter.class);
/**
*
* @param announcement
* @return
*/
AnnouncementNotifyInfo fromAnnouncement(Announcement announcement);
}

@ -0,0 +1,25 @@
package com.baiye.notify.converter;
import com.baiye.notify.model.entity.UserAnnouncement;
import com.baiye.notify.model.vo.UserAnnouncementPageVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
*
*
* @author hccake 2021-03-22 20:16:12
*/
@Mapper
public interface UserAnnouncementConverter {
UserAnnouncementConverter INSTANCE = Mappers.getMapper(UserAnnouncementConverter.class);
/**
* PO PageVO
* @param userAnnouncement
* @return UserAnnouncementPageVO PageVO
*/
UserAnnouncementPageVO poToPageVo(UserAnnouncement userAnnouncement);
}

@ -0,0 +1,33 @@
package com.baiye.notify.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
*
* @author Hccake 2020/12/17
* @version 1.0
*/
@Getter
@AllArgsConstructor
public enum AnnouncementStatusEnum {
/**
*
*/
DISABLED(0),
/**
*
*/
ENABLED(1),
/**
*
*/
UNPUBLISHED(2);
private final int value;
}

@ -0,0 +1,25 @@
package com.baiye.notify.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
*
*
* @author Hccake 2020/12/21
* @version 1.0
*/
@Getter
@RequiredArgsConstructor
public enum NotifyChannelEnum {
// 站内
STATION(1),
// 短信
SMS(2),
// 邮件
MAIL(3);
private final int value;
}

@ -0,0 +1,29 @@
package com.baiye.notify.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
*
*
* @author Hccake 2020/12/21
* @version 1.0
*/
@Getter
@RequiredArgsConstructor
public enum NotifyRecipientFilterTypeEnum {
// 全部
ALL(1),
// 指定用户
SPECIFY_ROLE(2),
// 指定组织
SPECIFY_ORGANIZATION(3),
// 指定用户类型
SPECIFY_USER_TYPE(4),
// 指定用户
SPECIFY_USER(5),;
private final int value;
}

@ -0,0 +1,27 @@
package com.baiye.notify.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
*
* @author Hccake 2021/1/19
* @version 1.0
*/
@Getter
@AllArgsConstructor
public enum UserAnnouncementStateEnum {
/**
*
*/
UNREAD(0),
/**
*
*/
READ(1);
private final int value;
}

@ -0,0 +1,103 @@
package com.baiye.notify.model.domain;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import java.util.List;
/**
*
*
* @author Hccake 2020/12/23
* @version 1.0
*/
@Data
@Accessors(chain = true)
@Schema(title = "公告通知信息")
public class AnnouncementNotifyInfo implements NotifyInfo {
/**
* ID
*/
@Schema(title = "公告ID")
private Long id;
/**
*
*/
@Schema(title = "标题")
private String title;
/**
*
*/
@Schema(title = "公告类型")
private Integer type;
/**
* (1)|(0)
*/
@Schema(title = "状态,已读(1)|未读(0)")
private Integer state;
/**
*
*/
@Schema(title = "关键信息")
private String messageKey;
/**
*
*/
@Schema(title = "内容")
private String content;
/**
*
* @see NotifyRecipientFilterTypeEnum
*/
@Schema(title = "接收人筛选方式")
private Integer recipientFilterType;
/**
*
*/
@Schema(title = "对应接收人筛选方式的条件信息")
private List<Object> recipientFilterCondition;
/**
*
* @see NotifyChannelEnum
*/
@Schema(title = "接收方式")
private List<Integer> receiveMode;
/**
*
* @see com.baiye.ballcat.common.core.constant.enums.BooleanEnum
*/
@Schema(title = "永久有效的")
private Integer immortal;
/**
*
*/
@Schema(title = "截止日期")
private LocalDateTime deadline;
/**
*
*/
@Schema(title = "创建时间")
private LocalDateTime createTime;
}

@ -0,0 +1,46 @@
package com.baiye.notify.model.domain;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import java.util.List;
/**
* @author Hccake 2020/12/23
* @version 1.0
*/
public interface NotifyInfo {
/**
*
* @return String
*/
String getTitle();
/**
*
* @return String
*/
String getContent();
/**
*
* @see NotifyRecipientFilterTypeEnum
* @return Integer
*/
Integer getRecipientFilterType();
/**
*
* @return List<Object>
*/
List<Object> getRecipientFilterCondition();
/**
*
* @see NotifyChannelEnum
* @return List<Integer>
*/
List<Integer> getReceiveMode();
}

@ -0,0 +1,85 @@
package com.baiye.notify.model.dto;
import com.baiye.notify.enums.NotifyChannelEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
/**
*
*
* @author hccake 2020-12-15 17:01:15
*/
@Data
@Schema(title = "公告信息")
public class AnnouncementDTO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(title = "ID")
private Long id;
/**
*
*/
@NotBlank(message = "标题不能为空")
@Schema(title = "标题")
private String title;
/**
*
*/
@NotBlank(message = "内容不能为空")
@Schema(title = "内容")
private String content;
/**
* 1 2 3 4 5
*/
@NotNull(message = "接收人范围不能为空")
@Schema(title = "接收人范围")
private Integer recipientFilterType;
/**
* IDID
*/
@Schema(title = "对应接收人筛选方式的条件信息。如角色标识组织ID用户类型用户ID等")
private List<Object> recipientFilterCondition;
/**
*
* @see NotifyChannelEnum
*/
@Schema(title = "接收方式")
private List<Integer> receiveMode;
/**
*
* @see com.baiye.ballcat.common.core.constant.enums.BooleanEnum
*/
@Schema(title = "永久有效的")
private Integer immortal;
/**
*
*/
@Schema(title = "截止日期")
private LocalDateTime deadline;
/**
*
*/
@Schema(title = "状态")
private Integer status;
}

@ -0,0 +1,104 @@
package com.baiye.notify.model.entity;
import com.baiye.entity.LogicDeletedBaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.baiye.notify.enums.AnnouncementStatusEnum;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import com.baiye.extend.mybatis.plus.alias.TableAlias;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
import java.util.List;
/**
*
*
* @author hccake 2020-12-15 17:01:15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableAlias(Announcement.TABLE_ALIAS)
@TableName(value = "notify_announcement", autoResultMap = true)
@Schema(title = "公告信息")
public class Announcement extends LogicDeletedBaseEntity {
private static final long serialVersionUID = 1L;
public static final String TABLE_ALIAS = "a";
/**
* ID
*/
@TableId
@Schema(title = "ID")
private Long id;
/**
*
*/
@Schema(title = "标题")
private String title;
/**
*
*/
@Schema(title = "内容")
private String content;
/**
*
* @see NotifyRecipientFilterTypeEnum
*/
@Schema(title = "接收人筛选方式")
private Integer recipientFilterType;
/**
*
*/
@Schema(title = "公告类型")
private Integer type;
/**
* IDID
*/
@TableField(typeHandler = JacksonTypeHandler.class)
@Schema(title = "对应接收人筛选方式的条件信息。如角色标识组织ID用户类型用户ID等")
private List<Object> recipientFilterCondition;
/**
*
* @see NotifyChannelEnum
*/
@TableField(typeHandler = JacksonTypeHandler.class)
@Schema(title = "接收方式")
private List<Integer> receiveMode;
/**
*
* @see AnnouncementStatusEnum
*/
@Schema(title = "状态")
private Integer status;
/**
*
* @see com.baiye.ballcat.common.core.constant.enums.BooleanEnum
*/
@Schema(title = "永久有效的")
private Integer immortal;
/**
*
*/
@Schema(title = "截止日期")
private LocalDateTime deadline;
}

@ -0,0 +1,96 @@
package com.baiye.notify.model.entity;
import com.baiye.extend.mybatis.plus.alias.TableAlias;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
*
*
* @author hccake 2020-12-25 08:04:53
*/
@Data
@TableAlias(UserAnnouncement.TABLE_ALIAS)
@TableName("tb_notify_user_announcement")
@Schema(title = "用户公告表")
public class UserAnnouncement implements Serializable {
private static final long serialVersionUID = 1L;
public static final String TABLE_ALIAS = "ua";
/**
* ID
*/
@TableId("id")
@Schema(title = "ID")
private Long id;
/**
* id
*/
@Schema(title = "公告id")
private Long announcementId;
/**
*
*/
@Schema(title = "公告类型")
private Integer type;
/**
* ID
*/
@Schema(title = "用户ID")
private Long userId;
/**
*
*/
@Schema(title = "关键信息")
private String messageKey;
/**
*
*/
@Schema(title = "标题")
private String title;
/**
*
*/
@Schema(title = "内容")
private String content;
/**
* (1)|(0)
*/
@Schema(title = "状态,已读(1)|未读(0)")
@TableField("state")
private Integer state;
/**
*
*/
@Schema(title = "阅读时间")
private LocalDateTime readTime;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
@Schema(title = "拉取时间")
private LocalDateTime createTime;
}

@ -0,0 +1,37 @@
package com.baiye.notify.model.qo;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springdoc.api.annotations.ParameterObject;
/**
*
*
* @author hccake 2020-12-15 17:01:15
*/
@Data
@ParameterObject
@Schema(title = "公告信息查询对象")
public class AnnouncementQO {
private static final long serialVersionUID = 1L;
/**
*
*/
@Parameter(description = "标题")
private String title;
/**
*
* @see NotifyRecipientFilterTypeEnum
*/
@Parameter(description = "接收人筛选方式")
private Integer recipientFilterType;
@Parameter(description = "状态")
private Integer[] status;
}

@ -0,0 +1,37 @@
package com.baiye.notify.model.qo;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springdoc.api.annotations.ParameterObject;
/**
*
*
* @author hccake 2020-12-25 08:04:53
*/
@Data
@Schema(title = "用户公告表查询对象")
@ParameterObject
public class UserAnnouncementQO {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Parameter(description = "ID")
private Long id;
@Parameter(description = "创建人")
private String content;
@Parameter(description = "开始时间")
private String startTime;
@Parameter(description = "结束时间")
private String endTime;
}

@ -0,0 +1,110 @@
package com.baiye.notify.model.vo;
import com.baiye.notify.enums.AnnouncementStatusEnum;
import com.baiye.notify.enums.NotifyChannelEnum;
import com.baiye.notify.enums.NotifyRecipientFilterTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
*
*
* @author hccake 2020-12-15 17:01:15
*/
@Data
@Schema(title = "公告信息分页VO")
public class AnnouncementPageVO {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(title = "ID")
private Long id;
/**
*
*/
@Schema(title = "标题")
private String title;
/**
*
*/
@Schema(title = "内容")
private String content;
/**
* 1 2 3 4 5
* @see NotifyRecipientFilterTypeEnum
*/
@Schema(title = "接收人筛选方式")
private Integer recipientFilterType;
/**
* IDID
*/
@TableField(typeHandler = JacksonTypeHandler.class)
@Schema(title = "对应接收人筛选方式的条件信息。如角色标识组织ID用户类型用户ID等")
private List<Object> recipientFilterCondition;
/**
*
* @see NotifyChannelEnum
*/
@TableField(typeHandler = JacksonTypeHandler.class)
@Schema(title = "接收方式")
private List<Integer> receiveMode;
/**
*
* @see AnnouncementStatusEnum
*/
@Schema(title = "状态")
private Integer status;
/**
*
* @see com.baiye.ballcat.common.core.constant.enums.BooleanEnum
*/
@Schema(title = "永久有效的")
private Integer immortal;
/**
*
*/
@Schema(title = "截止日期")
private LocalDateTime deadline;
/**
* ID
*/
@Schema(title = "创建人ID")
private Integer createBy;
/**
*
*/
@Schema(title = "创建人名称")
private String createUsername;
/**
*
*/
@Schema(title = "创建时间")
private LocalDateTime createTime;
/**
*
*/
@Schema(title = "更新时间")
private LocalDateTime updateTime;
}

@ -0,0 +1,84 @@
package com.baiye.notify.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
*
*
* @author hccake 2020-12-25 08:04:53
*/
@Data
@Schema(title = "用户公告分页VO")
public class UserAnnouncementPageVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(title = "ID")
private Long id;
/**
* id
*/
@Schema(title = "公告id")
private Long announcementId;
/**
* ID
*/
@Schema(title = "用户ID")
private Long userId;
/**
* (1)|(0)
*/
@Schema(title = "状态,已读(1)|未读(0)")
private Integer state;
/**
*
*/
@Schema(title = "关键信息")
private String messageKey;
/**
*
*/
@Schema(title = "公告类型")
private Integer type;
/**
*
*/
@Schema(title = "标题")
private String title;
/**
*
*/
@Schema(title = "内容")
private String content;
/**
*
*/
@Schema(title = "阅读时间")
private LocalDateTime readTime;
/**
*
*/
@Schema(title = "拉取时间")
private LocalDateTime createTime;
}

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ad-distribute</artifactId>
<groupId>com.baiye</groupId>
<version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ad-distribute-notify</artifactId>
<packaging>pom</packaging>
<modules>
<module>distribute-notify-biz</module>
<module>distribute-notify-controller</module>
<module>distribute-notify-model</module>
</modules>
</project>

@ -1,4 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baiye.ballcat.autoconfigure.redis.BallcatRedisAutoConfiguration,\
com.baiye.ballcat.autoconfigure.redis.MessageEventListenerAutoConfiguration,\
com.baiye.ballcat.autoconfigure.redis.RedisKeyEventAutoConfiguration
com.baiye.autoconfigure.redis.BallcatRedisAutoConfiguration,\
com.baiye.autoconfigure.redis.MessageEventListenerAutoConfiguration,\
com.baiye.autoconfigure.redis.RedisKeyEventAutoConfiguration

@ -1,9 +1,6 @@
package com.baiye.ballcat.autoconfigure.websocket;
package com.baiye.autoconfigure.websocket;
import com.baiye.ballcat.autoconfigure.websocket.config.LocalMessageDistributorConfig;
import com.baiye.ballcat.autoconfigure.websocket.config.RedisMessageDistributorConfig;
import com.baiye.ballcat.autoconfigure.websocket.config.RocketMqMessageDistributorConfig;
import com.baiye.ballcat.autoconfigure.websocket.config.WebSocketHandlerConfig;
import com.baiye.autoconfigure.websocket.config.*;
import com.baiye.handler.JsonMessageHandler;
import com.baiye.handler.PingJsonMessageHandler;
import com.baiye.holder.JsonMessageHandlerInitializer;
@ -31,8 +28,8 @@ import java.util.List;
* @author Yakir Hccake
*/
@AutoConfiguration
@Import({ WebSocketHandlerConfig.class, LocalMessageDistributorConfig.class, RedisMessageDistributorConfig.class,
RocketMqMessageDistributorConfig.class })
@Import({WebSocketHandlerConfig.class, LocalMessageDistributorConfig.class, RedisMessageDistributorConfig.class,
RocketMqMessageDistributorConfig.class})
@EnableWebSocket
@RequiredArgsConstructor
@EnableConfigurationProperties(WebSocketProperties.class)
@ -40,15 +37,16 @@ public class WebSocketAutoConfiguration {
private final WebSocketProperties webSocketProperties;
@Bean
@ConditionalOnMissingBean
public WebSocketConfigurer webSocketConfigurer(List<HandshakeInterceptor> handshakeInterceptor,
WebSocketHandler webSocketHandler,
@Autowired(required = false) SockJsServiceConfigurer sockJsServiceConfigurer) {
WebSocketHandler webSocketHandler,
@Autowired(required = false) SockJsServiceConfigurer sockJsServiceConfigurer) {
return registry -> {
WebSocketHandlerRegistration registration = registry
.addHandler(webSocketHandler, webSocketProperties.getPath())
.addInterceptors(handshakeInterceptor.toArray(new HandshakeInterceptor[0]));
.addHandler(webSocketHandler, webSocketProperties.getPath())
.addInterceptors(handshakeInterceptor.toArray(new HandshakeInterceptor[0]));
String[] allowedOrigins = webSocketProperties.getAllowedOrigins();
if (allowedOrigins != null && allowedOrigins.length > 0) {
@ -71,6 +69,7 @@ public class WebSocketAutoConfiguration {
/**
*
*
* @return PingJsonMessageHandler
*/
@Bean
@ -82,6 +81,7 @@ public class WebSocketAutoConfiguration {
/**
* JsonMessageHandlerInitializer json
*
* @param jsonMessageHandlerList json
* @return JsonMessageHandlerInitializer
*/

@ -1,4 +1,4 @@
package com.baiye.ballcat.autoconfigure.websocket;
package com.baiye.autoconfigure.websocket;
import com.baiye.handler.ConcurrentWebSocketSessionOptions;
import lombok.Data;
@ -14,7 +14,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty;
@ConfigurationProperties(WebSocketProperties.PREFIX)
public class WebSocketProperties {
public static final String PREFIX = "ballcat.websocket";
public static final String PREFIX = "distribute.websocket";
/**
* : : /ws : PathVariable: : /ws/{test} : /ws/{test1}/{test2} query:

@ -1,7 +1,7 @@
package com.baiye.ballcat.autoconfigure.websocket.config;
package com.baiye.autoconfigure.websocket.config;
import com.baiye.ballcat.autoconfigure.websocket.MessageDistributorTypeConstants;
import com.baiye.ballcat.autoconfigure.websocket.WebSocketProperties;
import com.baiye.autoconfigure.websocket.MessageDistributorTypeConstants;
import com.baiye.autoconfigure.websocket.WebSocketProperties;
import com.baiye.distribute.LocalMessageDistributor;
import com.baiye.distribute.MessageDistributor;
import com.baiye.session.WebSocketSessionStore;

@ -1,7 +1,7 @@
package com.baiye.ballcat.autoconfigure.websocket.config;
package com.baiye.autoconfigure.websocket.config;
import com.baiye.ballcat.autoconfigure.websocket.MessageDistributorTypeConstants;
import com.baiye.ballcat.autoconfigure.websocket.WebSocketProperties;
import com.baiye.autoconfigure.websocket.MessageDistributorTypeConstants;
import com.baiye.autoconfigure.websocket.WebSocketProperties;
import com.baiye.distribute.MessageDistributor;
import com.baiye.distribute.RedisMessageDistributor;
import com.baiye.distribute.RedisMessageListenerInitializer;

@ -1,7 +1,7 @@
package com.baiye.ballcat.autoconfigure.websocket.config;
package com.baiye.autoconfigure.websocket.config;
import com.baiye.ballcat.autoconfigure.websocket.MessageDistributorTypeConstants;
import com.baiye.ballcat.autoconfigure.websocket.WebSocketProperties;
import com.baiye.autoconfigure.websocket.MessageDistributorTypeConstants;
import com.baiye.autoconfigure.websocket.WebSocketProperties;
import com.baiye.distribute.MessageDistributor;
import com.baiye.distribute.RocketmqMessageDistributor;
import com.baiye.session.WebSocketSessionStore;

@ -1,6 +1,6 @@
package com.baiye.ballcat.autoconfigure.websocket.config;
package com.baiye.autoconfigure.websocket.config;
import com.baiye.ballcat.autoconfigure.websocket.WebSocketProperties;
import com.baiye.autoconfigure.websocket.WebSocketProperties;
import com.baiye.handler.CustomWebSocketHandler;
import com.baiye.handler.PlanTextMessageHandler;
import com.baiye.session.DefaultWebSocketSessionStore;
@ -45,4 +45,4 @@ public class WebSocketHandlerConfig {
return customWebSocketHandler;
}
}
}

@ -1,2 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baiye.ballcat.autoconfigure.websocket.WebSocketAutoConfiguration
com.baiye.autoconfigure.websocket.WebSocketAutoConfiguration

@ -1 +1 @@
com.baiye.ballcat.autoconfigure.websocket.WebSocketAutoConfiguration
com.baiye.autoconfigure.websocket.WebSocketAutoConfiguration

@ -35,12 +35,12 @@
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.0.Beta1</version>
<version>1.5.3.Final</version>
</dependency>
</dependencies>

@ -22,16 +22,19 @@
<artifactId>security-oauth2-authorization-server</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>admin-core</artifactId>
<artifactId>admin-websocket</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.baiye</groupId>
<artifactId>admin-websocket</artifactId>
<artifactId>admin-core</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

@ -26,6 +26,7 @@ public interface ClueMapper extends ExtendMapper<ClueEntity> {
LambdaAliasQueryWrapperX<ClueEntity> wrapperX = WrappersX.lambdaAliasQueryX(ClueEntity.class);
wrapperX.eqIfPresent(ClueEntity::getDeleted, 0)
.eqIfPresent(ClueEntity::getNid, qo.getNid())
.eqIfPresent(ClueEntity::getClueId, qo.getClueId())
.eqIfPresent(ClueEntity::getCreateBy, qo.getCreateBy())
.likeIfPresent(ClueEntity::getClueLabelName, qo.getClueLabelName())
.eqIfPresent(ClueEntity::getAssignedBy, qo.getAssignedBy())

@ -7,6 +7,9 @@ import lombok.Data;
@Data
public class ClueQo {
@Schema(title = "线索id")
private String clueId;
@Schema(title = "手机号")
private String nid;

@ -85,4 +85,4 @@
<appender-ref ref="stdAppender"/>
<appender-ref ref="fileAppender"/>
</root>
</configuration>
</configuration>

@ -0,0 +1,41 @@
import com.baiye.AdminApplication;
import com.baiye.notify.event.StationNotifyPushEvent;
import com.baiye.notify.model.domain.AnnouncementNotifyInfo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import java.time.LocalDateTime;
import java.util.Collections;
/**
* @author Enzo
* @date : 2023/11/24
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AdminApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PushMessageTest {
@Autowired
private ApplicationContext publisher;
@Test
public void pushMessage() {
// 发布事件,监听者进行实际的 websocket 推送
AnnouncementNotifyInfo notifyInfo = new AnnouncementNotifyInfo();
notifyInfo.setTitle("变形金刚");
notifyInfo.setMessageKey("783");
notifyInfo.setContent("《变形金刚》是美国科幻动作系列电影改编自起源于20世纪80年代的变形金刚品牌系列。该电影系列由派拉蒙影业公司和梦工厂发行。");
notifyInfo.setCreateTime(LocalDateTime.now());
notifyInfo.setType(1);
notifyInfo.setState(0);
publisher.publishEvent( new StationNotifyPushEvent(notifyInfo, Collections.singletonList(137L)));
}
}

@ -13,6 +13,7 @@
<module>ad-distribute-common</module>
<module>ad-distribute-security</module>
<module>ad-distribute-admin</module>
<module>ad-distribute-notify</module>
<module>ad-distribute-starters</module>
<module>ad-distribute-extends</module>
</modules>

Loading…
Cancel
Save