feat: SpringBoot整合log4j2日志

1.整合log4j2
2.maven依赖包整理
This commit is contained in:
有来技术 2021-08-25 08:24:04 +08:00
parent f915e0aad0
commit 0bc02bda5c
38 changed files with 140 additions and 826 deletions

View File

@ -13,12 +13,6 @@
<dependencies> <dependencies>
<!-- web环境 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud & Alibaba --> <!-- Spring Cloud & Alibaba -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
@ -106,11 +100,6 @@
<artifactId>common-rabbitmq</artifactId> <artifactId>common-rabbitmq</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-log</artifactId>
<version>${youlai.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.github.binarywang</groupId> <groupId>com.github.binarywang</groupId>

View File

@ -12,13 +12,6 @@
<artifactId>pms-boot</artifactId> <artifactId>pms-boot</artifactId>
<dependencies> <dependencies>
<!-- web环境 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 读取配置 --> <!-- 读取配置 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -30,6 +23,12 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
<exclusions>
<exclusion>
<artifactId>asm</artifactId>
<groupId>org.ow2.asm</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -71,6 +70,12 @@
<dependency> <dependency>
<groupId>io.seata</groupId> <groupId>io.seata</groupId>
<artifactId>seata-all</artifactId> <artifactId>seata-all</artifactId>
<exclusions>
<exclusion>
<artifactId>caffeine</artifactId>
<groupId>com.github.ben-manes.caffeine</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -100,11 +105,6 @@
<artifactId>common-redis</artifactId> <artifactId>common-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-log</artifactId>
<version>${youlai.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.youlai</groupId> <groupId>com.youlai</groupId>

View File

@ -15,12 +15,6 @@
</properties> </properties>
<dependencies> <dependencies>
<!-- web环境 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 读取配置 --> <!-- 读取配置 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -87,6 +81,13 @@
<version>${youlai.version}</version> <version>${youlai.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-core</artifactId>
<version>${dozer.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -1,4 +1,4 @@
package com.youlai.common.base; package com.youlai.mall.sms.common.base;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;

View File

@ -1,4 +1,4 @@
package com.youlai.common.web.util; package com.youlai.mall.sms.common.util;
import org.dozer.DozerBeanMapperBuilder; import org.dozer.DozerBeanMapperBuilder;
import org.dozer.Mapper; import org.dozer.Mapper;

View File

@ -1,8 +1,7 @@
package com.youlai.common.mybatis.utils; package com.youlai.mall.sms.common.util;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlai.common.web.util.BeanMapperUtils;
/** /**
* @author xinyi * @author xinyi

View File

@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlai.common.base.BasePageQuery; import com.youlai.mall.sms.common.base.BasePageQuery;
import com.youlai.common.result.Result; import com.youlai.common.result.Result;
import com.youlai.common.web.util.JwtUtils; import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord; import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;

View File

@ -1,7 +1,7 @@
package com.youlai.mall.sms.controller.app; package com.youlai.mall.sms.controller.app;
import com.youlai.common.result.Result; import com.youlai.common.result.Result;
import com.youlai.common.web.util.BeanMapperUtils; import com.youlai.mall.sms.common.util.BeanMapperUtils;
import com.youlai.common.web.util.JwtUtils; import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.sms.pojo.domain.SmsCoupon; import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.vo.CouponTemplateVO; import com.youlai.mall.sms.pojo.vo.CouponTemplateVO;

View File

@ -5,7 +5,7 @@ import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import com.youlai.common.redis.utils.RedisUtils; import com.youlai.common.redis.utils.RedisUtils;
import com.youlai.common.web.util.BeanMapperUtils; import com.youlai.mall.sms.common.util.BeanMapperUtils;
import com.youlai.mall.sms.pojo.domain.SmsSeckillSession; import com.youlai.mall.sms.pojo.domain.SmsSeckillSession;
import com.youlai.mall.sms.pojo.domain.SmsSeckillSkuRelation; import com.youlai.mall.sms.pojo.domain.SmsSeckillSkuRelation;
import com.youlai.mall.sms.pojo.to.SeckillSkuRedisTO; import com.youlai.mall.sms.pojo.to.SeckillSkuRedisTO;

View File

@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.common.web.exception.BizException; import com.youlai.common.web.exception.BizException;
import com.youlai.common.web.util.BeanMapperUtils; import com.youlai.mall.sms.common.util.BeanMapperUtils;
import com.youlai.common.web.util.JwtUtils; import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.sms.mapper.SmsCouponMapper; import com.youlai.mall.sms.mapper.SmsCouponMapper;
import com.youlai.mall.sms.pojo.domain.CouponTemplateRule; import com.youlai.mall.sms.pojo.domain.CouponTemplateRule;

View File

@ -7,9 +7,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.common.mybatis.utils.PageMapperUtils;
import com.youlai.common.web.exception.BizException; import com.youlai.common.web.exception.BizException;
import com.youlai.common.web.util.BeanMapperUtils; import com.youlai.mall.sms.common.util.BeanMapperUtils;
import com.youlai.mall.sms.mapper.SmsCouponTemplateMapper; import com.youlai.mall.sms.mapper.SmsCouponTemplateMapper;
import com.youlai.mall.sms.pojo.domain.CouponTemplateRule; import com.youlai.mall.sms.pojo.domain.CouponTemplateRule;
import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate; import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate;
@ -22,6 +21,7 @@ import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateInfoVO;
import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateVO; import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateVO;
import com.youlai.mall.sms.service.IAsyncService; import com.youlai.mall.sms.service.IAsyncService;
import com.youlai.mall.sms.service.ISmsCouponTemplateService; import com.youlai.mall.sms.service.ISmsCouponTemplateService;
import com.youlai.mall.sms.common.util.PageMapperUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@ -3,7 +3,7 @@ package com.youlai.mall.sms.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import com.youlai.common.web.exception.BizException; import com.youlai.common.web.exception.BizException;
import com.youlai.common.web.util.BeanMapperUtils; import com.youlai.mall.sms.common.util.BeanMapperUtils;
import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate; import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate;
import com.youlai.mall.sms.pojo.vo.CouponTemplateVO; import com.youlai.mall.sms.pojo.vo.CouponTemplateVO;
import com.youlai.mall.sms.service.ISmsCouponTemplateService; import com.youlai.mall.sms.service.ISmsCouponTemplateService;

View File

@ -16,13 +16,6 @@
</properties> </properties>
<dependencies> <dependencies>
<!-- web环境 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 读取配置 --> <!-- 读取配置 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -73,6 +66,12 @@
<dependency> <dependency>
<groupId>io.seata</groupId> <groupId>io.seata</groupId>
<artifactId>seata-all</artifactId> <artifactId>seata-all</artifactId>
<exclusions>
<exclusion>
<artifactId>caffeine</artifactId>
<groupId>com.github.ben-manes.caffeine</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.seata</groupId> <groupId>io.seata</groupId>
@ -100,11 +99,6 @@
<artifactId>common-redis</artifactId> <artifactId>common-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-log</artifactId>
<version>${youlai.version}</version>
</dependency>
</dependencies> </dependencies>

View File

@ -1,32 +0,0 @@
package com.youlai.admin.pojo.domain;
import com.youlai.common.base.BaseDocument;
import lombok.Data;
/**
* @author hxr
* @date 2021-03-09
*/
@Data
public class LoginRecord extends BaseDocument {
private String clientIP;
private long elapsedTime;
private Object message;
private String token;
private String username;
private String loginTime;
private String region;
/**
* 会话状态 0-离线 1-在线
*/
private Integer status;
}

View File

@ -1,4 +1,4 @@
package com.youlai.common.pojo.vo; package com.youlai.admin.pojo.vo;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data; import lombok.Data;

View File

@ -17,11 +17,6 @@
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 配置读取 --> <!-- 配置读取 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -45,6 +40,12 @@
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<artifactId>jsr305</artifactId>
<groupId>com.google.code.findbugs</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -79,6 +80,12 @@
<dependency> <dependency>
<groupId>io.minio</groupId> <groupId>io.minio</groupId>
<artifactId>minio</artifactId> <artifactId>minio</artifactId>
<exclusions>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -96,11 +103,6 @@
<artifactId>common-es</artifactId> <artifactId>common-es</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-log</artifactId>
<version>${youlai.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.youlai</groupId> <groupId>com.youlai</groupId>

View File

@ -1,48 +0,0 @@
package com.youlai.admin.common.util;
import cn.hutool.json.JSONUtil;
import com.nimbusds.jose.JWSObject;
import com.youlai.common.constant.AuthConstants;
import com.youlai.common.pojo.JwtPayload;
import lombok.SneakyThrows;
import org.apache.logging.log4j.util.Strings;
/**
* @author hxr
* @date 2021-03-10
*/
public class JWTUtils {
/**
* 获取JWT的载体
* @param token
* @return
*/
@SneakyThrows
public static JwtPayload getJWTPayload(String token) {
token = token.replace(AuthConstants.AUTHORIZATION_PREFIX, Strings.EMPTY);
JWSObject jwsObject = JWSObject.parse(token);
JwtPayload payload = JSONUtil.toBean(jwsObject.getPayload().toString(), JwtPayload.class);
return payload;
}
/**
* 判断token是否过期
* @param token
* @return
*/
public static boolean isExpired(String token) {
JwtPayload payload = getJWTPayload(token);
// 计算是否过期
long currentTimeSeconds = System.currentTimeMillis() / 1000;
Long exp = payload.getExp();
if (exp < currentTimeSeconds) { // token已过期无需加入黑名单
return true;
}
return false;
}
}

View File

@ -1,205 +0,0 @@
package com.youlai.admin.controller;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.youlai.admin.pojo.domain.LoginRecord;
import com.youlai.admin.service.ITokenService;
import com.youlai.common.base.BaseDocument;
import com.youlai.common.elasticsearch.service.ElasticSearchService;
import com.youlai.common.result.Result;
import com.youlai.common.web.util.IPUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description 首页控制台
* @author hxr
* @date 2021-03-08
*/
@Api(tags = "首页控制台")
@RestController
@RequestMapping("/api/v1/dashboard")
@Slf4j
@AllArgsConstructor
public class DashboardController {
ITokenService tokenService;
ElasticSearchService elasticSearchService;
@ApiOperation(value = "控制台数据")
@GetMapping
public Result data() {
Map<String, Object> data = new HashMap<>();
// 今日IP数
long todayIpCount = getTodayIpCount();
data.put("todayIpCount", todayIpCount);
// 总IP数
long totalIpCount = getTotalIpCount();
data.put("totalIpCount", totalIpCount);
// 登录统计
int days = 10; // 统计天数
Map loginCount = getLoginCount(days);
data.put("loginCount", loginCount);
return Result.success(data);
}
private long getTodayIpCount() {
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("date", date);
String indexName = "youlai-auth-login-" + date; //索引名称
long todayIpCount = elasticSearchService.countDistinct(termQueryBuilder, "clientIP.keyword", indexName);
return todayIpCount;
}
private long getTotalIpCount() {
long totalIpCount = elasticSearchService.countDistinct(null, "clientIP.keyword", "youlai-auth-login-*");
return totalIpCount;
}
private Map getLoginCount(int days) {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String startDate = now.plusDays(-days).format(formatter);
String endDate = now.format(formatter);
String[] indices = new String[days]; // 查询ES索引数组
String[] xData = new String[days]; // 柱状图x轴数据
for (int i = 0; i < days; i++) {
String date = now.plusDays(-i).format(formatter);
xData[i] = date;
indices[i] = "youlai-auth-login-"+ date;
}
// 查询条件范围内日期统计
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("date").from(startDate).to(endDate);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(rangeQueryBuilder);
// 总数统计
Map<String, Long> totalCountMap = elasticSearchService.dateHistogram(
boolQueryBuilder,
"date", // 根据date字段聚合统计登录数 logback-spring.xml 中的自定义扩展字段 date
DateHistogramInterval.days(1),
indices);
// 当前用户统计
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String clientIP = IPUtils.getIpAddr(request);
boolQueryBuilder.must(QueryBuilders.termQuery("clientIP", clientIP));
Map<String, Long> myCountMap = elasticSearchService.dateHistogram(boolQueryBuilder, "date", DateHistogramInterval.days(1), indices);
// 组装echarts数据
Long[] totalCount = new Long[days];
Long[] myCount = new Long[days];
Arrays.sort(xData);// 默认升序
for (int i = 0; i < days; i++) {
String key = xData[i];
totalCount[i] = Convert.toLong(totalCountMap.get(key), 0l);
myCount[i] = Convert.toLong(myCountMap.get(key), 0l);
}
Map<String, Object> map = new HashMap<>(4);
map.put("xData", xData); // x轴坐标
map.put("totalCount", totalCount); // 总数
map.put("myCount", myCount); // 我的
return map;
}
@ApiOperation(value = "列表分页")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "页码", defaultValue = "1", paramType = "query", dataType = "Long"),
@ApiImplicitParam(name = "limit", value = "每页数量", defaultValue = "10", paramType = "query", dataType = "Long"),
@ApiImplicitParam(name = "startDate", value = "开始日期", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "endDate", value = "结束日期", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "clientIP", value = "客户端IP", paramType = "query", dataType = "String")
})
@GetMapping("/login-records")
public Result list(
Integer page,
Integer limit,
String startDate,
String endDate,
String clientIP
) {
// 日期范围
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("date");
if (StrUtil.isNotBlank(startDate)) {
rangeQueryBuilder.from(startDate);
}
if (StrUtil.isNotBlank(endDate)) {
rangeQueryBuilder.to(endDate);
}
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(rangeQueryBuilder);
if (StrUtil.isNotBlank(clientIP)) {
queryBuilder.must(QueryBuilders.wildcardQuery("clientIP", "*" + clientIP + "*"));
}
// 总记录数
long count = elasticSearchService.count(queryBuilder, "youlai-auth-login-*");
// 排序
FieldSortBuilder sortBuilder = new FieldSortBuilder("@timestamp").order(SortOrder.DESC);
// 分页查询
List<LoginRecord> list = elasticSearchService.search(queryBuilder, sortBuilder, page, limit, LoginRecord.class, "youlai-auth-login-*");
// 遍历获取会话状态
list.forEach(item -> {
String token = item.getToken();
int tokenStatus = 0;
if (StrUtil.isNotBlank(token)) {
tokenStatus = tokenService.getTokenStatus(item.getToken());
}
item.setStatus(tokenStatus);
});
return Result.success(list, count);
}
@ApiOperation(value = "删除登录记录")
@ApiImplicitParam(name = "ids", value = "id集合", required = true, paramType = "query", dataType = "String")
@DeleteMapping("/login-records")
public Result delete(@RequestBody List<BaseDocument> documents) {
documents.forEach(document -> elasticSearchService.deleteById(document.getId(), document.getIndex()));
return Result.success();
}
}

View File

@ -1,40 +0,0 @@
package com.youlai.admin.controller;
import com.youlai.admin.service.ITokenService;
import com.youlai.common.result.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author hxr
* @date 2021-03-09
*/
@Api(tags = "令牌接口")
@RestController
@RequestMapping("/api/v1/tokens")
@Slf4j
@AllArgsConstructor
public class TokenController {
ITokenService tokenService;
@ApiOperation(value = "强制下线")
@ApiImplicitParam(name = "token", value = "访问令牌", required = true, paramType = "query", dataType = "String")
@PostMapping("/{token}/_invalidate")
@SneakyThrows
public Result invalidateToken(@PathVariable String token) {
boolean status = tokenService.invalidateToken(token);
return Result.judge(status);
}
}

View File

@ -1,24 +0,0 @@
package com.youlai.admin.service;
import java.text.ParseException;
public interface ITokenService {
/**
* 使令牌token失效
*
* @param token
* @return
*/
boolean invalidateToken(String token) throws ParseException;
/**
* 获取token状态
* @param token
* @return 1-有效0-失效过期或被加入黑名单
*/
int getTokenStatus(String token);
}

View File

@ -1,63 +0,0 @@
package com.youlai.admin.service.impl;
import com.youlai.admin.common.util.JWTUtils;
import com.youlai.admin.service.ITokenService;
import com.youlai.common.constant.AuthConstants;
import com.youlai.common.pojo.JwtPayload;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* @author haoxr
* @date 2021-03-10
*/
@Service
@AllArgsConstructor
public class TokenServiceImpl implements ITokenService {
RedisTemplate redisTemplate;
@Override
@SneakyThrows
public boolean invalidateToken(String token) {
JwtPayload payload = JWTUtils.getJWTPayload(token);
// 计算是否过期
long currentTimeSeconds = System.currentTimeMillis() / 1000;
Long exp = payload.getExp();
if (exp < currentTimeSeconds) { // token已过期无需加入黑名单
return true;
}
// 添加至黑名单使其失效
redisTemplate.opsForValue().set(AuthConstants.TOKEN_BLACKLIST_PREFIX + payload.getJti(), null, (exp - currentTimeSeconds), TimeUnit.SECONDS);
return true;
}
@Override
public int getTokenStatus(String token) {
JwtPayload payload = JWTUtils.getJWTPayload(token);
// 计算是否过期
long currentTimeSeconds = System.currentTimeMillis() / 1000;
Long exp = payload.getExp();
if (exp < currentTimeSeconds) { // token已过期 返回失效
return 0;
}
// 判断是否存在黑名单
String jti = payload.getJti();
Boolean isExists = redisTemplate.hasKey(AuthConstants.TOKEN_BLACKLIST_PREFIX + jti);
if (isExists == true) { // 被添加到黑名单 返回失效
return 0;
}
return 1;
}
}

View File

@ -16,13 +16,6 @@
</properties> </properties>
<dependencies> <dependencies>
<!-- web环境 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 配置读取 --> <!-- 配置读取 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -114,11 +107,6 @@
<groupId>com.github.xiaoymin</groupId> <groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-micro-spring-boot-starter</artifactId> <artifactId>knife4j-micro-spring-boot-starter</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-log</artifactId>
<version>${youlai.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -12,12 +12,16 @@
<artifactId>common-core</artifactId> <artifactId>common-core</artifactId>
<dependencies> <dependencies>
<!-- spring boot web -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>jackson-databind</artifactId>
<optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<!-- mybatis-plus --> <!-- mybatis-plus -->
<dependency> <dependency>
@ -26,17 +30,6 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-core</artifactId>
<version>${dozer.version}</version>
</dependency>
<dependency> <dependency>
<groupId>io.swagger</groupId> <groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId> <artifactId>swagger-annotations</artifactId>
@ -47,6 +40,11 @@
<artifactId>spring-data-redis</artifactId> <artifactId>spring-data-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,22 +0,0 @@
package com.youlai.common.base;
import lombok.Data;
/**
* @description document ES 里的一个 JSON 对象包括零个或多个field类比关系数据库的一行记录
* @author haoxr
* @createTime 2021/3/9 22:14
*/
@Data
public class BaseDocument {
/**
* 数据唯一标识
*/
private String id;
/**
* 索引名称
*/
private String index;
}

View File

@ -1,17 +0,0 @@
package com.youlai.common.pojo;
import lombok.Data;
/**
* JWT载体
*
* @author hxr
* @date 2021-03-10
*/
@Data
public class JwtPayload {
private String jti;
private Long exp;
}

View File

@ -2,8 +2,9 @@ package com.youlai.common.elasticsearch.service;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.youlai.common.base.BaseDocument;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.delete.DeleteResponse;
@ -38,10 +39,10 @@ import java.util.Map;
* @date 2021-03-05 * @date 2021-03-05
*/ */
@Service @Service
@AllArgsConstructor @RequiredArgsConstructor
public class ElasticSearchService { public class ElasticSearchService {
private RestHighLevelClient client; private final RestHighLevelClient client;
@SneakyThrows @SneakyThrows
@ -174,4 +175,45 @@ public class ElasticSearchService {
return true; return true;
} }
@Data
public static class BaseDocument {
/**
* 数据唯一标识
*/
private String id;
/**
* 索引名称
*/
private String index;
}
@Data
public class LoginRecord extends BaseDocument {
private String clientIP;
private long elapsedTime;
private Object message;
private String token;
private String username;
private String loginTime;
private String region;
/**
* 会话状态 0-离线 1-在线
*/
private Integer status;
}
} }

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>youlai-common</artifactId>
<groupId>com.youlai</groupId>
<version>2.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-log</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>

View File

@ -13,8 +13,13 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.youlai</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>common-web</artifactId> <artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.config.GlobalConfig; import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.youlai.common.mybatis.handler.FieldFillHandler; import com.youlai.common.mybatis.handler.MyMetaObjectHandler;
import com.youlai.common.mybatis.handler.IntegerArrayJsonTypeHandler; import com.youlai.common.mybatis.handler.IntegerArrayJsonTypeHandler;
import com.youlai.common.mybatis.handler.LongArrayJsonTypeHandler; import com.youlai.common.mybatis.handler.LongArrayJsonTypeHandler;
@ -52,7 +52,7 @@ public class MybatisPlusConfig {
@Bean @Bean
public GlobalConfig globalConfig() { public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig(); GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setMetaObjectHandler(new FieldFillHandler()); globalConfig.setMetaObjectHandler(new MyMetaObjectHandler());
return globalConfig; return globalConfig;
} }

View File

@ -1,26 +0,0 @@
package com.youlai.common.mybatis.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@Slf4j
public class FieldFillHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("gmtCreate", new Date(), metaObject);
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
}

View File

@ -1,4 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.youlai.common.mybatis.config.MybatisPlusConfig,\ com.youlai.common.mybatis.config.MybatisPlusConfig,\
com.youlai.common.mybatis.handler.FieldFillHandler com.youlai.common.mybatis.handler.MyMetaObjectHandler

View File

@ -36,14 +36,6 @@
<artifactId>redisson</artifactId> <artifactId>redisson</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId> <artifactId>jackson-annotations</artifactId>

View File

@ -19,13 +19,30 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<!-- 排除SpringBoot默认日志框架logback的依赖 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入log4j2依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>io.github.openfeign</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>feign-core</artifactId>
<optional>true</optional> </dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency> </dependency>
<dependency> <dependency>
@ -49,20 +66,6 @@
<artifactId>ip2region</artifactId> <artifactId>ip2region</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -4,19 +4,13 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.youlai.common.constant.AuthConstants; import com.youlai.common.constant.AuthConstants;
import com.youlai.common.web.util.IPUtils;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings; import org.apache.logging.log4j.util.Strings;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC; import org.slf4j.MDC;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
@ -74,17 +68,14 @@ public class LoginLogAspect {
token = jsonObject.getStr("value"); token = jsonObject.getStr("value");
} }
String clientIP = IPUtils.getIpAddr(request); // 客户端请求IP注意如果使用Nginx代理需配置
String region = IPUtils.getCityInfo(clientIP); // IP对应的城市信息
// MDC 扩展logback字段具体请看logback-spring.xml的自定义日志输出格式 // MDC 扩展logback字段具体请看logback-spring.xml的自定义日志输出格式
MDC.put("elapsedTime", StrUtil.toString(elapsedTime)); MDC.put("elapsedTime", StrUtil.toString(elapsedTime));
MDC.put("description", description); /* MDC.put("description", description);
MDC.put("region", region); MDC.put("region", region);
MDC.put("username", username); MDC.put("username", username);
MDC.put("date", date); MDC.put("date", date);
MDC.put("token", token); MDC.put("token", token);
MDC.put("clientIP", clientIP); MDC.put("clientIP", clientIP);*/
//log.info("{} 登录,耗费时间 {} 毫秒", username, elapsedTime); // 收集日志这里必须打印一条日志内容随便吧记录在message字段具体看logback-spring.xml文件 //log.info("{} 登录,耗费时间 {} 毫秒", username, elapsedTime); // 收集日志这里必须打印一条日志内容随便吧记录在message字段具体看logback-spring.xml文件
return result; return result;

View File

@ -1,152 +0,0 @@
package com.youlai.common.web.util;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.util.Strings;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* IP工具类
*/
@Slf4j
public class IPUtils {
private static String LOCAL_IP = "127.0.0.1";
/**
* 获取IP地址
* 使用Nginx等反向代理软件 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话X-Forwarded-For的值并不止一个而是一串IP地址X-Forwarded-For中第一个非unknown的有效IP字符串则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = null;
try {
if (request == null) {
return "";
}
ip = request.getHeader("x-forwarded-for");
if (checkIp(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (checkIp(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (checkIp(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (checkIp(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (checkIp(ip)) {
ip = request.getRemoteAddr();
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
// 根据网卡取本机配置的IP
ip = getLocalAddr();
}
}
} catch (Exception e) {
log.error("IPUtils ERROR, {}", e.getMessage());
}
//使用代理则获取第一个IP地址
if (StrUtil.isNotBlank(ip) && ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
return ip;
}
private static boolean checkIp(String ip) {
String unknown = "unknown";
return StrUtil.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip);
}
/**
* 获取本机的IP地址
*/
private static String getLocalAddr() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.error("InetAddress.getLocalHost()-error, {}", e.getMessage());
}
return null;
}
/**
* 根据IP获取城市信息
* @param ip
* @return
*/
public static String getCityInfo(String ip) {
return getCityInfo(ip, DbSearcher.BTREE_ALGORITHM);
}
public static String getCityInfo(String ip, Integer algorithm) {
if (Util.isIpAddress(ip) == false) {
return Strings.EMPTY;
}
if (LOCAL_IP.equals(ip)) {
return "本地访问";
}
String dbPath = IPUtils.class.getResource("/ip2region.db").getPath();
File file = new File(dbPath);
// 打成jar包时ip2region.db文件路径发生变化导致File无法读取通过stream流方式复制生成临时的ip2region.db文件
if (file.exists() == false) {
String tmpdir = System.getProperties().getProperty("java.io.tmpdir");
dbPath = tmpdir + "/ip2region.db";
file = new File(dbPath);
if (file.exists() == false) {
try {
FileUtils.copyInputStreamToFile(IPUtils.class.getClassLoader()
.getResourceAsStream("classpath:ip2region.db"), file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
DbConfig config = new DbConfig();
DbSearcher searcher = new DbSearcher(config, dbPath);
Method method;
switch (algorithm) {
case DbSearcher.BTREE_ALGORITHM:
method = searcher.getClass().getMethod("btreeSearch", String.class);
break;
case DbSearcher.BINARY_ALGORITHM:
method = searcher.getClass().getMethod("binarySearch", String.class);
break;
case DbSearcher.MEMORY_ALGORITYM:
method = searcher.getClass().getMethod("memorySearch", String.class);
break;
default:
method = searcher.getClass().getMethod("memorySearch", String.class);
break;
}
DataBlock dataBlock = (DataBlock) method.invoke(searcher, ip);
searcher.close();
return dataBlock.getRegion();
} catch (Exception e) {
e.printStackTrace();
}
return Strings.EMPTY;
}
}

View File

@ -20,6 +20,5 @@
<module>common-mybatis</module> <module>common-mybatis</module>
<module>common-rabbitmq</module> <module>common-rabbitmq</module>
<module>common-es</module> <module>common-es</module>
<module>common-log</module>
</modules> </modules>
</project> </project>

View File

@ -97,11 +97,6 @@
<artifactId>common-redis</artifactId> <artifactId>common-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-log</artifactId>
<version>${youlai.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -1,36 +0,0 @@
package com.youlai.gateway.swagger;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
/**
* @link https://gitee.com/xiaoym/swagger-bootstrap-ui-demo/blob/master/knife4j-spring-cloud-gateway/service-doc/src/main/java/com/xiaominfo/swagger/service/doc/config/SwaggerHeaderFilter.java
* @auth xianrui
* @date 2021-02-25 16:29
*/
@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private static final String URI = "/v2/api-docs";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (!StringUtils.endsWithIgnoreCase(path,URI )) {
return chain.filter(exchange);
}
String basePath = path.substring(0, path.lastIndexOf(URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}