项目基础搭建

This commit is contained in:
zhongzb
2023-04-22 21:13:22 +08:00
parent 783ad1ee26
commit ceb28ace8b
149 changed files with 8026 additions and 0 deletions

View File

@@ -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/**");
}
}

View File

@@ -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) // 是否开启 swaggertrue -> 开启false -> 关闭
// ;
// }
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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());
}
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}