mirror of
https://github.com/zongzibinbin/MallChat.git
synced 2026-03-14 14:13:42 +08:00
项目基础搭建
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
package com.abin.mallchat.custom.common.config;
|
||||
|
||||
import com.abin.mallchat.custom.common.intecepter.CollectorInterceptor;
|
||||
import com.abin.mallchat.custom.common.intecepter.TokenInterceptor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Description: 配置所有拦截器
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-04-05
|
||||
*/
|
||||
@Configuration
|
||||
public class InterceptorConfig implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
private TokenInterceptor tokenInterceptor;
|
||||
@Autowired
|
||||
private CollectorInterceptor collectorInterceptor;
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(tokenInterceptor)
|
||||
.addPathPatterns("/capi/**");
|
||||
registry.addInterceptor(collectorInterceptor)
|
||||
.addPathPatterns("/capi/**");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.abin.mallchat.custom.common.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.Profiles;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
|
||||
|
||||
/**
|
||||
* Description:
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-03-23
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2WebMvc
|
||||
public class SwaggerConfig {
|
||||
@Bean(value = "defaultApi2")
|
||||
Docket docket() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
//配置网站的基本信息
|
||||
.apiInfo(new ApiInfoBuilder()
|
||||
//网站标题
|
||||
.title("mallchat接口文档")
|
||||
//标题后面的版本号
|
||||
.version("v1.0")
|
||||
.description("mallchat接口文档")
|
||||
//联系人信息
|
||||
.contact(new Contact("阿斌", "http://www.mallchat.cn", "972627721@qq.com"))
|
||||
.build())
|
||||
.select()
|
||||
//指定接口的位置
|
||||
.apis(RequestHandlerSelectors
|
||||
.withClassAnnotation(RestController.class)
|
||||
)
|
||||
.paths(PathSelectors.any())
|
||||
.build();
|
||||
}
|
||||
/**
|
||||
* swagger 配置
|
||||
* @param environment 环境
|
||||
*/
|
||||
// @Bean
|
||||
// public Docket docket(Environment environment) {
|
||||
//
|
||||
// // 设置环境范围
|
||||
// Profiles profiles = Profiles.of("dev","test");
|
||||
// // 如果在该环境返回内则返回:true,反之返回 false
|
||||
// boolean flag = environment.acceptsProfiles(profiles);
|
||||
//
|
||||
// // 创建一个 swagger 的 bean 实例
|
||||
// return new Docket(DocumentationType.SWAGGER_2)
|
||||
// .enable(flag) // 是否开启 swagger:true -> 开启,false -> 关闭
|
||||
// ;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.abin.mallchat.custom.common.config;
|
||||
|
||||
import com.abin.mallchat.custom.user.service.handler.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.chanjar.weixin.common.redis.JedisWxRedisOps;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType.UNSUBSCRIBE;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
|
||||
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
|
||||
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;
|
||||
|
||||
/**
|
||||
* wechat mp configuration
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxMpProperties.class)
|
||||
public class WxMpConfiguration {
|
||||
private final LogHandler logHandler;
|
||||
private final MsgHandler msgHandler;
|
||||
private final SubscribeHandler subscribeHandler;
|
||||
private final ScanHandler scanHandler;
|
||||
private final WxMpProperties properties;
|
||||
|
||||
@Bean
|
||||
public WxMpService wxMpService() {
|
||||
// 代码里 getConfigs()处报错的同学,请注意仔细阅读项目说明,你的IDE需要引入lombok插件!!!!
|
||||
final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
|
||||
if (configs == null) {
|
||||
throw new RuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
|
||||
}
|
||||
|
||||
WxMpService service = new WxMpServiceImpl();
|
||||
service.setMultiConfigStorages(configs
|
||||
.stream().map(a -> {
|
||||
WxMpDefaultConfigImpl configStorage;
|
||||
configStorage = new WxMpDefaultConfigImpl();
|
||||
|
||||
configStorage.setAppId(a.getAppId());
|
||||
configStorage.setSecret(a.getSecret());
|
||||
configStorage.setToken(a.getToken());
|
||||
configStorage.setAesKey(a.getAesKey());
|
||||
return configStorage;
|
||||
}).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
|
||||
return service;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
|
||||
final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
|
||||
|
||||
// 记录所有事件的日志 (异步执行)
|
||||
newRouter.rule().handler(this.logHandler).next();
|
||||
|
||||
// 关注事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();
|
||||
|
||||
// 扫码事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(EventType.SCAN).handler(this.scanHandler).end();
|
||||
|
||||
// 默认
|
||||
newRouter.rule().async(false).handler(this.msgHandler).end();
|
||||
|
||||
return newRouter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.abin.mallchat.custom.common.config;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* wechat mp properties
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "wx.mp")
|
||||
public class WxMpProperties {
|
||||
/**
|
||||
* 是否使用redis存储access token
|
||||
*/
|
||||
private boolean useRedis;
|
||||
|
||||
/**
|
||||
* redis 配置
|
||||
*/
|
||||
private RedisConfig redisConfig;
|
||||
|
||||
@Data
|
||||
public static class RedisConfig {
|
||||
/**
|
||||
* redis服务器 主机地址
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* redis服务器 端口号
|
||||
*/
|
||||
private Integer port;
|
||||
|
||||
/**
|
||||
* redis服务器 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* redis 服务连接超时时间
|
||||
*/
|
||||
private Integer timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个公众号配置信息
|
||||
*/
|
||||
private List<MpConfig> configs;
|
||||
|
||||
@Data
|
||||
public static class MpConfig {
|
||||
/**
|
||||
* 设置微信公众号的appid
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的app secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSONUtil.toJsonStr(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.abin.mallchat.custom.common.event;
|
||||
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@Getter
|
||||
public class MessageMarkEvent extends ApplicationEvent {
|
||||
private ChatMessageMarkReq req;
|
||||
|
||||
public MessageMarkEvent(Object source, ChatMessageMarkReq req) {
|
||||
super(source);
|
||||
this.req = req;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.abin.mallchat.custom.common.event;
|
||||
|
||||
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@Getter
|
||||
public class MessageSendEvent extends ApplicationEvent {
|
||||
private Long msgId;
|
||||
|
||||
public MessageSendEvent(Object source, Long msgId) {
|
||||
super(source);
|
||||
this.msgId = msgId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.abin.mallchat.custom.common.event;
|
||||
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@Getter
|
||||
public class UserOfflineEvent extends ApplicationEvent {
|
||||
private User user;
|
||||
|
||||
public UserOfflineEvent(Object source, User user) {
|
||||
super(source);
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.abin.mallchat.custom.common.event;
|
||||
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Getter
|
||||
public class UserOnlineEvent extends ApplicationEvent {
|
||||
private User user;
|
||||
|
||||
public UserOnlineEvent(Object source, User user) {
|
||||
super(source);
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.abin.mallchat.custom.common.event;
|
||||
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@Getter
|
||||
public class UserRegisterEvent extends ApplicationEvent {
|
||||
private User user;
|
||||
|
||||
public UserRegisterEvent(Object source, User user) {
|
||||
super(source);
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.abin.mallchat.custom.common.event.listener;
|
||||
|
||||
import com.abin.mallchat.common.chat.dao.MessageDao;
|
||||
import com.abin.mallchat.common.chat.dao.MessageMarkDao;
|
||||
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||
import com.abin.mallchat.common.chat.domain.enums.MessageMarkTypeEnum;
|
||||
import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
|
||||
import com.abin.mallchat.common.common.domain.enums.IdempotentEnum;
|
||||
import com.abin.mallchat.common.user.domain.enums.ItemEnum;
|
||||
import com.abin.mallchat.common.user.service.IUserBackpackService;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
||||
import com.abin.mallchat.custom.common.event.MessageMarkEvent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 消息标记监听器
|
||||
*
|
||||
* @author zhongzb create on 2022/08/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MessageMarkListener {
|
||||
@Autowired
|
||||
private MessageMarkDao messageMarkDao;
|
||||
@Autowired
|
||||
private MessageDao messageDao;
|
||||
@Autowired
|
||||
private IUserBackpackService iUserBackpackService;
|
||||
|
||||
@Async
|
||||
@EventListener(classes = MessageMarkEvent.class)
|
||||
public void changeMsgType(MessageMarkEvent event) {
|
||||
ChatMessageMarkReq req = event.getReq();
|
||||
Message msg = messageDao.getById(req.getMsgId());
|
||||
if (!Objects.equals(msg, MessageTypeEnum.NORMAL.getType())) {//普通消息才需要升级
|
||||
return;
|
||||
}
|
||||
//消息被标记次数
|
||||
Integer markCount = messageMarkDao.getMarkCount(req.getMsgId(), req.getMarkType());
|
||||
MessageMarkTypeEnum markTypeEnum = MessageMarkTypeEnum.of(req.getMarkType());
|
||||
if (markCount < markTypeEnum.getRiseNum()) {
|
||||
return;
|
||||
}
|
||||
boolean updateSuccess = messageDao.riseOptimistic(msg.getId(), msg.getType(), markTypeEnum.getRiseEnum().getType());
|
||||
if (MessageMarkTypeEnum.LIKE.getType().equals(req.getMarkType()) && updateSuccess) {//尝试给用户发送一张徽章
|
||||
iUserBackpackService.acquireItem(msg.getFromUid(), ItemEnum.LIKE_BADGE.getId(), IdempotentEnum.MSG_ID, msg.getId().toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.abin.mallchat.custom.common.event.listener;
|
||||
|
||||
import com.abin.mallchat.common.chat.dao.MessageDao;
|
||||
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
||||
import com.abin.mallchat.custom.common.event.MessageSendEvent;
|
||||
import com.abin.mallchat.custom.chat.service.ChatService;
|
||||
import com.abin.mallchat.custom.user.service.WebSocketService;
|
||||
import com.abin.mallchat.custom.user.service.adapter.WSAdapter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 消息发送监听器
|
||||
*
|
||||
* @author zhongzb create on 2022/08/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MessageSendListener {
|
||||
@Autowired
|
||||
private WebSocketService webSocketService;
|
||||
@Autowired
|
||||
private ChatService chatService;
|
||||
@Autowired
|
||||
private MessageDao messageDao;
|
||||
|
||||
@Async
|
||||
@EventListener(classes = MessageSendEvent.class)
|
||||
public void notifyAllOnline(MessageSendEvent event) {
|
||||
Message message = messageDao.getById(event.getMsgId());
|
||||
ChatMessageResp msgResp = chatService.getMsgResp(message, null);
|
||||
webSocketService.sendToAllOnline(WSAdapter.buildMsgSend(msgResp), message.getFromUid());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.abin.mallchat.custom.common.event.listener;
|
||||
|
||||
import com.abin.mallchat.common.user.dao.UserDao;
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||
import com.abin.mallchat.custom.common.event.UserOfflineEvent;
|
||||
import com.abin.mallchat.custom.common.event.UserOnlineEvent;
|
||||
import com.abin.mallchat.custom.user.service.WebSocketService;
|
||||
import com.abin.mallchat.custom.user.service.adapter.WSAdapter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 用户下线监听器
|
||||
*
|
||||
* @author zhongzb create on 2022/08/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UserOfflineListener {
|
||||
@Autowired
|
||||
private WebSocketService webSocketService;
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
@Autowired
|
||||
private UserCache userCache;
|
||||
@Autowired
|
||||
private WSAdapter wsAdapter;
|
||||
|
||||
@Async
|
||||
@EventListener(classes = UserOfflineEvent.class)
|
||||
public void saveRedisAndPush(UserOfflineEvent event) {
|
||||
User user = event.getUser();
|
||||
userCache.offline(user.getId(), user.getLastOptTime());
|
||||
//推送给所有在线用户,该用户下线
|
||||
webSocketService.sendToAllOnline(wsAdapter.buildOfflineNotifyResp(event.getUser()), event.getUser().getId());
|
||||
}
|
||||
|
||||
@Async
|
||||
@EventListener(classes = UserOfflineEvent.class)
|
||||
public void saveDB(UserOfflineEvent event) {
|
||||
User user = event.getUser();
|
||||
User update = new User();
|
||||
update.setId(user.getId());
|
||||
update.setLastOptTime(user.getLastOptTime());
|
||||
userDao.updateById(update);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.abin.mallchat.custom.common.event.listener;
|
||||
|
||||
import com.abin.mallchat.common.chat.dao.MessageDao;
|
||||
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||
import com.abin.mallchat.common.user.dao.UserDao;
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
import com.abin.mallchat.common.user.service.IpService;
|
||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
||||
import com.abin.mallchat.custom.chat.service.ChatService;
|
||||
import com.abin.mallchat.custom.common.event.MessageSendEvent;
|
||||
import com.abin.mallchat.custom.common.event.UserOnlineEvent;
|
||||
import com.abin.mallchat.custom.user.service.WebSocketService;
|
||||
import com.abin.mallchat.custom.user.service.adapter.WSAdapter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 用户上线监听器
|
||||
*
|
||||
* @author zhongzb create on 2022/08/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UserOnlineListener {
|
||||
@Autowired
|
||||
private WebSocketService webSocketService;
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
@Autowired
|
||||
private UserCache userCache;
|
||||
@Autowired
|
||||
private WSAdapter wsAdapter;
|
||||
@Autowired
|
||||
private IpService ipService;
|
||||
|
||||
@Async
|
||||
@EventListener(classes = UserOnlineEvent.class)
|
||||
public void saveRedisAndPush(UserOnlineEvent event) {
|
||||
User user = event.getUser();
|
||||
userCache.online(user.getId(), user.getLastOptTime());
|
||||
//推送给所有在线用户,该用户登录成功
|
||||
webSocketService.sendToAllOnline(wsAdapter.buildOnlineNotifyResp(event.getUser()), event.getUser().getId());
|
||||
}
|
||||
|
||||
@Async
|
||||
@EventListener(classes = UserOnlineEvent.class)
|
||||
public void saveDB(UserOnlineEvent event) {
|
||||
User user = event.getUser();
|
||||
User update = new User();
|
||||
update.setId(user.getId());
|
||||
update.setLastOptTime(user.getLastOptTime());
|
||||
update.setIpInfo(user.getIpInfo());
|
||||
userDao.updateById(update);
|
||||
//更新用户ip详情
|
||||
ipService.refreshIpDetailAsync(user.getId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.abin.mallchat.custom.common.event.listener;
|
||||
|
||||
import com.abin.mallchat.common.common.domain.enums.IdempotentEnum;
|
||||
import com.abin.mallchat.common.user.dao.UserDao;
|
||||
import com.abin.mallchat.common.user.domain.entity.User;
|
||||
import com.abin.mallchat.common.user.domain.enums.ItemEnum;
|
||||
import com.abin.mallchat.common.user.service.IUserBackpackService;
|
||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||
import com.abin.mallchat.custom.common.event.UserOnlineEvent;
|
||||
import com.abin.mallchat.custom.common.event.UserRegisterEvent;
|
||||
import com.abin.mallchat.custom.user.service.WebSocketService;
|
||||
import com.abin.mallchat.custom.user.service.adapter.WSAdapter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 用户上线监听器
|
||||
*
|
||||
* @author zhongzb create on 2022/08/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UserRegisterListener {
|
||||
@Autowired
|
||||
private WebSocketService webSocketService;
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
@Autowired
|
||||
private UserCache userCache;
|
||||
@Autowired
|
||||
private WSAdapter wsAdapter;
|
||||
@Autowired
|
||||
private IUserBackpackService iUserBackpackService;
|
||||
|
||||
@Async
|
||||
@EventListener(classes = UserRegisterEvent.class)
|
||||
public void sendCard(UserRegisterEvent event) {
|
||||
User user = event.getUser();
|
||||
//送一张改名卡
|
||||
iUserBackpackService.acquireItem(user.getId(), ItemEnum.MODIFY_NAME_CARD.getId(), IdempotentEnum.UID, user.getId().toString());
|
||||
}
|
||||
|
||||
@Async
|
||||
@EventListener(classes = UserRegisterEvent.class)
|
||||
public void sendBadge(UserOnlineEvent event) {
|
||||
User user = event.getUser();
|
||||
int count = userDao.count();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.abin.mallchat.custom.common.intecepter;
|
||||
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.abin.mallchat.common.common.utils.RequestHolder;
|
||||
import com.abin.mallchat.common.common.domain.dto.RequestInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 信息收集的拦截器
|
||||
*/
|
||||
@Order
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CollectorInterceptor implements HandlerInterceptor, WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(this)
|
||||
.addPathPatterns("/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
RequestInfo info = new RequestInfo();
|
||||
info.setUid(Optional.ofNullable(request.getAttribute(TokenInterceptor.ATTRIBUTE_UID)).map(Object::toString).map(Long::parseLong).orElse(null));
|
||||
info.setIp(ServletUtil.getClientIP(request));
|
||||
RequestHolder.set(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
RequestHolder.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.abin.mallchat.custom.common.intecepter;
|
||||
|
||||
import com.abin.mallchat.common.common.constant.MDCKey;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.annotation.WebFilter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Description: 设置链路追踪的值,初期单体项目先简单用
|
||||
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||
* Date: 2023-04-05
|
||||
*/
|
||||
@Slf4j
|
||||
@WebFilter(urlPatterns = "/*")
|
||||
public class HttpTraceIdFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
String tid = UUID.randomUUID().toString();
|
||||
MDC.put(MDCKey.TID, tid);
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.abin.mallchat.custom.common.intecepter;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.abin.mallchat.common.common.constant.MDCKey;
|
||||
import com.abin.mallchat.common.common.exception.HttpErrorEnum;
|
||||
import com.abin.mallchat.custom.user.service.LoginService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Order(-2)
|
||||
@Slf4j
|
||||
@Component
|
||||
public class TokenInterceptor implements HandlerInterceptor {
|
||||
|
||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
public static final String AUTHORIZATION_SCHEMA = "Bearer ";
|
||||
public static final String ATTRIBUTE_UID = "uid";
|
||||
|
||||
@Autowired
|
||||
private LoginService loginService;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
//获取用户登录token
|
||||
String token = getToken(request);
|
||||
Long validUid = loginService.getValidUid(token);
|
||||
if (Objects.nonNull(validUid)) {//有登录态
|
||||
request.setAttribute(ATTRIBUTE_UID, validUid);
|
||||
} else {
|
||||
boolean isPublicURI = isPublicURI(request.getRequestURI());
|
||||
if (!isPublicURI) {//又没有登录态,又不是公开路径,直接401
|
||||
HttpErrorEnum.ACCESS_DENIED.sendHttpError(response);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MDC.put(MDCKey.UID, String.valueOf(validUid));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是不是公共方法,可以未登录访问的
|
||||
*
|
||||
* @param requestURI
|
||||
*/
|
||||
private boolean isPublicURI(String requestURI) {
|
||||
String[] split = requestURI.split("/");
|
||||
return split.length > 2 && "public".equals(split[3]);
|
||||
}
|
||||
|
||||
private String getToken(HttpServletRequest request) {
|
||||
String header = request.getHeader(AUTHORIZATION_HEADER);
|
||||
return Optional.ofNullable(header)
|
||||
.filter(h -> h.startsWith(AUTHORIZATION_SCHEMA))
|
||||
.map(h -> h.substring(AUTHORIZATION_SCHEMA.length()))
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.abin.mallchat.custom.common.intecepter;
|
||||
|
||||
import cn.hutool.core.date.StopWatch;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.abin.mallchat.common.common.utils.RequestHolder;
|
||||
import com.abin.mallchat.common.common.domain.dto.RequestInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
/**
|
||||
* 日志切面
|
||||
*
|
||||
* @author wayne
|
||||
*/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WebLogAspect {
|
||||
|
||||
|
||||
/**
|
||||
* 接收到请求,记录请求内容
|
||||
* 所有controller包下所有的类的方法,都是切点
|
||||
* <p>
|
||||
* 如果ApiResult返回success=false,则打印warn日志;
|
||||
* warn日志只能打印在同一行,因为只有等到ApiResult结果才知道是success=false。
|
||||
* <p>
|
||||
* 如果ApiResult返回success=true,则打印info日志;
|
||||
* 特别注意:由于info级别日志已经包含了warn级别日志。如果开了info级别日志,warn就不会打印了。
|
||||
*/
|
||||
@Around("execution(* com..controller..*.*(..))")
|
||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
||||
String method = request.getMethod();
|
||||
String uri = request.getRequestURI();
|
||||
//如果参数有HttpRequest,ServletResponse,直接移除,不打印这些
|
||||
List<Object> paramList = Stream.of(joinPoint.getArgs())
|
||||
.filter(args -> !(args instanceof ServletRequest))
|
||||
.filter(args -> !(args instanceof ServletResponse))
|
||||
.collect(Collectors.toList());
|
||||
String printParamStr = paramList.size() == 1 ? JSONUtil.toJsonStr(paramList.get(0)) : JSONUtil.toJsonStr(paramList);
|
||||
RequestInfo requestInfo = RequestHolder.get();
|
||||
String userHeaderStr = JSONUtil.toJsonStr(requestInfo);
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("[{}][{}]【base:{}】【request:{}】", method, uri, userHeaderStr, printParamStr);
|
||||
}
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
Object result = joinPoint.proceed();
|
||||
stopWatch.stop();
|
||||
long cost = stopWatch.getTotalTimeMillis();
|
||||
String printResultStr = JSONUtil.toJsonStr(result);
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("[{}]【response:{}】[cost:{}ms]", uri, printResultStr, cost);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user