# Conflicts: # dq-financial-crms/src/main/resources/bootstrap.properties # dq-financial-guarantee/src/main/resources/bootstrap.properties # dq-financial-hrms-auth/src/main/resources/bootstrap.properties # dq-financial-hrms/src/main/resources/bootstrap.properties # dq-govern-gateway/src/main/resources/bootstrap.propertiesmaster
commit
f44e278b10
68 changed files with 1877 additions and 800 deletions
@ -1,13 +1,13 @@ |
||||
//package com.daqing.financial.crms.config;
|
||||
//
|
||||
//import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
//@Configuration
|
||||
//public class IPageConfig {
|
||||
// @Bean
|
||||
// public PaginationInterceptor paginationInterceptor() {
|
||||
// return new PaginationInterceptor();
|
||||
// }
|
||||
//}
|
||||
package com.daqing.financial.crms.config; |
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
@Configuration |
||||
public class IPageConfig { |
||||
@Bean |
||||
public PaginationInterceptor paginationInterceptor() { |
||||
return new PaginationInterceptor(); |
||||
} |
||||
} |
||||
|
@ -1,18 +1,18 @@ |
||||
//package com.daqing.financial.guarantee.config;
|
||||
//
|
||||
//import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
///**
|
||||
// * @auther River
|
||||
// * @date 2020/11/5 14:38
|
||||
// */
|
||||
//
|
||||
//@Configuration
|
||||
//public class IPageConfig {
|
||||
// @Bean
|
||||
// public PaginationInterceptor paginationInterceptor() {
|
||||
// return new PaginationInterceptor();
|
||||
// }
|
||||
//}
|
||||
package com.daqing.financial.guarantee.config; |
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* @auther River |
||||
* @date 2020/11/5 14:38 |
||||
*/ |
||||
|
||||
@Configuration |
||||
public class IPageConfig { |
||||
@Bean |
||||
public PaginationInterceptor paginationInterceptor() { |
||||
return new PaginationInterceptor(); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,112 @@ |
||||
package com.daqing.financial.guarantee.model.response; |
||||
|
||||
import com.baomidou.mybatisplus.annotation.*; |
||||
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
import lombok.Data; |
||||
|
||||
import java.io.Serializable; |
||||
import java.math.BigDecimal; |
||||
import java.util.Date; |
||||
|
||||
/** |
||||
* <p> |
||||
* 还款记录表 |
||||
* </p> |
||||
* |
||||
* @author Qyq |
||||
* @since 2021-03-17 |
||||
*/ |
||||
@Data |
||||
public class AlRepaymentEntryListRes implements Serializable { |
||||
|
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
/** |
||||
* 主键id |
||||
*/ |
||||
@TableId(value = "id", type = IdType.AUTO) |
||||
private Integer id; |
||||
|
||||
/** |
||||
* 保后外键id |
||||
*/ |
||||
private Integer insuranceId; |
||||
|
||||
/** |
||||
* 应还款日 |
||||
*/ |
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
||||
private Date repaymentDate; |
||||
|
||||
/** |
||||
* 实际还款日 |
||||
*/ |
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
||||
private Date actualRepaymentDate; |
||||
|
||||
/** |
||||
* 逾期天数 |
||||
*/ |
||||
private Integer overdueDays; |
||||
|
||||
/** |
||||
* 还款总额(元) |
||||
*/ |
||||
private BigDecimal totalRepayment; |
||||
|
||||
/** |
||||
* 本次还款(元) |
||||
*/ |
||||
private BigDecimal currentRepayment; |
||||
|
||||
/** |
||||
* 利息(元) |
||||
*/ |
||||
private BigDecimal interest; |
||||
|
||||
/** |
||||
* 其他费用(元) |
||||
*/ |
||||
private BigDecimal otherExpenses; |
||||
|
||||
/** |
||||
* 减免金额(元) |
||||
*/ |
||||
private BigDecimal deductionAmount; |
||||
|
||||
/** |
||||
* 还款备注 |
||||
*/ |
||||
private String repaymentNotes; |
||||
|
||||
/** |
||||
* 还款状态:1->待还款;2->已还款;3->已逾期;4->未到期; |
||||
*/ |
||||
private Integer repaymentStatus; |
||||
|
||||
/** |
||||
* 提交人id |
||||
*/ |
||||
private Integer submitterId; |
||||
|
||||
/** |
||||
* 提交人名称 |
||||
*/ |
||||
private String submitterName; |
||||
|
||||
/** |
||||
* 创建时间 |
||||
*/ |
||||
@TableField(fill= FieldFill.INSERT) |
||||
private Date createTime; |
||||
|
||||
/** |
||||
* 修改时间 |
||||
*/ |
||||
@TableField(fill= FieldFill.INSERT_UPDATE) |
||||
private Date updateTime; |
||||
/** |
||||
* 担保额度(元) |
||||
*/ |
||||
private Double guaranteeAmount; |
||||
} |
@ -1,48 +1,48 @@ |
||||
package com.daqing.financial.hrauth.annotation; |
||||
|
||||
|
||||
import com.daqing.financial.hrauth.enums.OperationType; |
||||
import com.daqing.financial.hrauth.enums.OperationUnit; |
||||
|
||||
import java.lang.annotation.*; |
||||
|
||||
/** |
||||
* @author Rogers |
||||
* 操作日志注解 |
||||
* @create 2020-07-03 |
||||
*/ |
||||
@Target({ElementType.METHOD}) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
public @interface Log { |
||||
|
||||
/** |
||||
* 方法描述,可使用占位符获取参数:{{tel}} |
||||
*/ |
||||
String detail() default ""; |
||||
|
||||
/** |
||||
* 日志等级:自己定,此处分为1-9 |
||||
*/ |
||||
int level() default 0; |
||||
|
||||
/** |
||||
* 操作类型(enum):主要是select,insert,update,delete |
||||
*/ |
||||
OperationType operationType() default OperationType.UNKNOWN; |
||||
|
||||
/** |
||||
* 被操作的对象(此处使用enum):可以是任何对象,如表名(user),或者是工具(redis) |
||||
*/ |
||||
OperationUnit operationUnit() default OperationUnit.UNKNOWN; |
||||
|
||||
/** 该属性需要访问的微服务名称 */ |
||||
// String serverId();
|
||||
//
|
||||
// /** 表名 */
|
||||
// String tableName();
|
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
//package com.daqing.financial.hrauth.annotation;
|
||||
//
|
||||
//
|
||||
//import com.daqing.financial.hrauth.enums.OperationType;
|
||||
//import com.daqing.financial.hrauth.enums.OperationUnit;
|
||||
//
|
||||
//import java.lang.annotation.*;
|
||||
//
|
||||
///**
|
||||
// * @author Rogers
|
||||
// * 操作日志注解
|
||||
// * @create 2020-07-03
|
||||
// */
|
||||
//@Target({ElementType.METHOD})
|
||||
//@Retention(RetentionPolicy.RUNTIME)
|
||||
//@Documented
|
||||
//public @interface Log {
|
||||
//
|
||||
// /**
|
||||
// * 方法描述,可使用占位符获取参数:{{tel}}
|
||||
// */
|
||||
// String detail() default "";
|
||||
//
|
||||
// /**
|
||||
// * 日志等级:自己定,此处分为1-9
|
||||
// */
|
||||
// int level() default 0;
|
||||
//
|
||||
// /**
|
||||
// * 操作类型(enum):主要是select,insert,update,delete
|
||||
// */
|
||||
// OperationType operationType() default OperationType.UNKNOWN;
|
||||
//
|
||||
// /**
|
||||
// * 被操作的对象(此处使用enum):可以是任何对象,如表名(user),或者是工具(redis)
|
||||
// */
|
||||
// OperationUnit operationUnit() default OperationUnit.UNKNOWN;
|
||||
//
|
||||
// /** 该属性需要访问的微服务名称 */
|
||||
//// String serverId();
|
||||
////
|
||||
//// /** 表名 */
|
||||
//// String tableName();
|
||||
//
|
||||
//
|
||||
//}
|
||||
//
|
||||
//
|
||||
|
@ -1,194 +1,194 @@ |
||||
package com.daqing.financial.hrauth.aspect; |
||||
|
||||
import com.alibaba.fastjson.JSON; |
||||
import com.alibaba.fastjson.JSONObject; |
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
||||
import com.daqing.financial.hrauth.annotation.Log; |
||||
import com.daqing.financial.hrauth.feign.HrmsFeignService; |
||||
import com.daqing.financial.hrauth.service.TokenService; |
||||
import com.daqing.financial.hrauth.service.UserLoginService; |
||||
import com.daqing.framework.domain.hrms.EmployeeEntity; |
||||
import com.daqing.framework.domain.hrms.Token; |
||||
import com.daqing.framework.domain.hrms.UserEntity; |
||||
import com.daqing.framework.model.response.ResponseResult; |
||||
import com.daqing.framework.util.RedisUtil; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.aspectj.lang.JoinPoint; |
||||
import org.aspectj.lang.ProceedingJoinPoint; |
||||
import org.aspectj.lang.annotation.*; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; |
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.context.request.RequestContextHolder; |
||||
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
|
||||
import javax.annotation.Resource; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @ClassName SysLogAspect |
||||
* @Description 操作日志切面 |
||||
* @Date 2020/9/30 |
||||
* @Version 1.0 |
||||
*/ |
||||
@Slf4j |
||||
@Aspect |
||||
@Component |
||||
@EnableDiscoveryClient |
||||
@EnableAspectJAutoProxy(proxyTargetClass = true) |
||||
public class SysLogAspect { |
||||
|
||||
@Resource |
||||
private Operation operation; |
||||
@Autowired |
||||
private TokenService tokenService; |
||||
@Autowired |
||||
private UserLoginService userLoginService; |
||||
@Autowired |
||||
private HrmsFeignService hrmsFeignService; |
||||
/** |
||||
* 此处的切点是注解的方式,也可以用包名的方式达到相同的效果 |
||||
* '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")' |
||||
*/ |
||||
@Pointcut("@annotation(com.daqing.financial.hrauth.annotation.Log)") |
||||
public void operationLog() { |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 环绕增强,相当于MethodInterceptor |
||||
*/ |
||||
@Around("operationLog()") |
||||
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { |
||||
Object res = null; |
||||
long time = System.currentTimeMillis(); |
||||
try { |
||||
res = joinPoint.proceed(); |
||||
time = System.currentTimeMillis() - time; |
||||
return res; |
||||
} finally { |
||||
try { |
||||
//User systemUser = (User) SecurityUtils.getSubject().getPrincipal();
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); |
||||
String token = request.getHeader("token"); |
||||
String userId = RedisUtil.get("dq:token:"+token); |
||||
String userEntityStr = RedisUtil.get("dq:userId:"+userId); |
||||
UserEntity systemUser = JSON.parseObject(userEntityStr,UserEntity.class); |
||||
|
||||
//根据userId查询工号以及员工姓名
|
||||
if(userId !=null || userId != ""){ |
||||
EmployeeEntity employeeEntity = hrmsFeignService.getEmpmsgById(Long.valueOf(userId)); |
||||
operation.addOperationLog(joinPoint,res,time,systemUser,employeeEntity); |
||||
} |
||||
|
||||
//Token userToken = tokenService.getOne(new QueryWrapper<Token>().eq("token", token));
|
||||
//UserEntity systemUser = userLoginService.getOne(new QueryWrapper<UserEntity>().eq("id",userId));
|
||||
//package com.daqing.financial.hrauth.aspect;
|
||||
//
|
||||
//import com.alibaba.fastjson.JSON;
|
||||
//import com.alibaba.fastjson.JSONObject;
|
||||
//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
//import com.daqing.financial.hrauth.annotation.Log;
|
||||
//import com.daqing.financial.hrauth.feign.HrmsFeignService;
|
||||
//import com.daqing.financial.hrauth.service.TokenService;
|
||||
//import com.daqing.financial.hrauth.service.UserLoginService;
|
||||
//import com.daqing.framework.domain.hrms.EmployeeEntity;
|
||||
//import com.daqing.framework.domain.hrms.Token;
|
||||
//import com.daqing.framework.domain.hrms.UserEntity;
|
||||
//import com.daqing.framework.model.response.ResponseResult;
|
||||
//import com.daqing.framework.util.RedisUtil;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.aspectj.lang.JoinPoint;
|
||||
//import org.aspectj.lang.ProceedingJoinPoint;
|
||||
//import org.aspectj.lang.annotation.*;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
//import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.web.context.request.RequestContextHolder;
|
||||
//import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
//
|
||||
//import javax.annotation.Resource;
|
||||
//import javax.servlet.http.HttpServletRequest;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.Map;
|
||||
//
|
||||
///**
|
||||
// * @ClassName SysLogAspect
|
||||
// * @Description 操作日志切面
|
||||
// * @Date 2020/9/30
|
||||
// * @Version 1.0
|
||||
// */
|
||||
//@Slf4j
|
||||
//@Aspect
|
||||
//@Component
|
||||
//@EnableDiscoveryClient
|
||||
//@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
//public class SysLogAspect {
|
||||
//
|
||||
// @Resource
|
||||
// private Operation operation;
|
||||
// @Autowired
|
||||
// private TokenService tokenService;
|
||||
// @Autowired
|
||||
// private UserLoginService userLoginService;
|
||||
// @Autowired
|
||||
// private HrmsFeignService hrmsFeignService;
|
||||
// /**
|
||||
// * 此处的切点是注解的方式,也可以用包名的方式达到相同的效果
|
||||
// * '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")'
|
||||
// */
|
||||
// @Pointcut("@annotation(com.daqing.financial.hrauth.annotation.Log)")
|
||||
// public void operationLog() {
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 环绕增强,相当于MethodInterceptor
|
||||
// */
|
||||
// @Around("operationLog()")
|
||||
// public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
// Object res = null;
|
||||
// long time = System.currentTimeMillis();
|
||||
// try {
|
||||
// res = joinPoint.proceed();
|
||||
// time = System.currentTimeMillis() - time;
|
||||
// return res;
|
||||
// } finally {
|
||||
// try {
|
||||
// //User systemUser = (User) SecurityUtils.getSubject().getPrincipal();
|
||||
// HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
// String token = request.getHeader("token");
|
||||
// String userId = RedisUtil.get("dq:token:"+token);
|
||||
// String userEntityStr = RedisUtil.get("dq:userId:"+userId);
|
||||
// UserEntity systemUser = JSON.parseObject(userEntityStr,UserEntity.class);
|
||||
//
|
||||
// //根据userId查询工号以及员工姓名
|
||||
// if(userId !=null || userId != ""){
|
||||
// EmployeeEntity employeeEntity = hrmsFeignService.getEmpmsgById(Long.valueOf(userId));
|
||||
// operation.addOperationLog(joinPoint,res,time,systemUser,employeeEntity);
|
||||
//方法执行完成后增加日志
|
||||
// addOperationLog(joinPoint, res, time);
|
||||
} catch (Exception e) { |
||||
log.error("LogAspect 操作失败:" + e.getMessage()); |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 对当前登录用户和占位符处理 |
||||
* |
||||
* @param argNames 方法参数名称数组 |
||||
* @param args 方法参数数组 |
||||
* @param annotation 注解信息 |
||||
* @return 返回处理后的描述 |
||||
*/ |
||||
private String getDetail(String[] argNames, Object[] args, Log annotation) { |
||||
//获得登录用户信息
|
||||
//User systemUser = (User) SecurityUtils.getSubject().getPrincipal();
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); |
||||
UserEntity systemUser = (UserEntity) request.getUserPrincipal(); |
||||
|
||||
Map<Object, Object> map = new HashMap<>(4); |
||||
for (int i = 0; i < argNames.length; i++) { |
||||
map.put(argNames[i], args[i]); |
||||
} |
||||
|
||||
String detail = annotation.detail(); |
||||
try { |
||||
detail = "'" + systemUser.getAccount() + "'=》" + annotation.detail(); |
||||
for (Map.Entry<Object, Object> entry : map.entrySet()) { |
||||
Object k = entry.getKey(); |
||||
Object v = entry.getValue(); |
||||
detail = detail.replace("{{" + k + "}}", JSONObject.toJSONString(v)); |
||||
} |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return detail; |
||||
} |
||||
|
||||
@Before("operationLog()") |
||||
public void doBeforeAdvice(JoinPoint joinPoint) { |
||||
// System.out.println("进入方法前执行.....");
|
||||
} |
||||
|
||||
/** |
||||
* 处理完请求,返回内容 |
||||
* |
||||
* @param ret |
||||
*/ |
||||
@AfterReturning(returning = "ret", pointcut = "operationLog()") |
||||
public void doAfterReturning(Object ret) { |
||||
// System.out.println("方法的返回值 : " + ret);
|
||||
} |
||||
|
||||
/** |
||||
* 后置异常通知 |
||||
*/ |
||||
@AfterThrowing("operationLog()") |
||||
public void throwss(JoinPoint jp) { |
||||
// System.out.println("方法异常时执行.....");
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行 |
||||
*/ |
||||
@After("operationLog()") |
||||
public void after(JoinPoint jp) { |
||||
// System.out.println("方法最后执行.....");
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取客户端ip地址 |
||||
* |
||||
* @param request |
||||
* @return |
||||
*/ |
||||
public static String getClientIp(HttpServletRequest request) { |
||||
String ip = request.getHeader("x-forwarded-for"); |
||||
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getHeader("Proxy-Client-IP"); |
||||
} |
||||
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getHeader("WL-Proxy-Client-IP"); |
||||
} |
||||
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getRemoteAddr(); |
||||
} |
||||
// 多个路由时,取第一个非unknown的ip
|
||||
final String[] arr = ip.split(","); |
||||
for (final String str : arr) { |
||||
if (!"unknown".equalsIgnoreCase(str)) { |
||||
ip = str; |
||||
break; |
||||
} |
||||
} |
||||
return ip; |
||||
} |
||||
|
||||
} |
||||
// }
|
||||
//
|
||||
// //Token userToken = tokenService.getOne(new QueryWrapper<Token>().eq("token", token));
|
||||
// //UserEntity systemUser = userLoginService.getOne(new QueryWrapper<UserEntity>().eq("id",userId));
|
||||
// //operation.addOperationLog(joinPoint,res,time,systemUser,employeeEntity);
|
||||
// //方法执行完成后增加日志
|
||||
//// addOperationLog(joinPoint, res, time);
|
||||
// } catch (Exception e) {
|
||||
// log.error("LogAspect 操作失败:" + e.getMessage());
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 对当前登录用户和占位符处理
|
||||
// *
|
||||
// * @param argNames 方法参数名称数组
|
||||
// * @param args 方法参数数组
|
||||
// * @param annotation 注解信息
|
||||
// * @return 返回处理后的描述
|
||||
// */
|
||||
// private String getDetail(String[] argNames, Object[] args, Log annotation) {
|
||||
// //获得登录用户信息
|
||||
// //User systemUser = (User) SecurityUtils.getSubject().getPrincipal();
|
||||
// HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
// UserEntity systemUser = (UserEntity) request.getUserPrincipal();
|
||||
//
|
||||
// Map<Object, Object> map = new HashMap<>(4);
|
||||
// for (int i = 0; i < argNames.length; i++) {
|
||||
// map.put(argNames[i], args[i]);
|
||||
// }
|
||||
//
|
||||
// String detail = annotation.detail();
|
||||
// try {
|
||||
// detail = "'" + systemUser.getAccount() + "'=》" + annotation.detail();
|
||||
// for (Map.Entry<Object, Object> entry : map.entrySet()) {
|
||||
// Object k = entry.getKey();
|
||||
// Object v = entry.getValue();
|
||||
// detail = detail.replace("{{" + k + "}}", JSONObject.toJSONString(v));
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return detail;
|
||||
// }
|
||||
//
|
||||
// @Before("operationLog()")
|
||||
// public void doBeforeAdvice(JoinPoint joinPoint) {
|
||||
//// System.out.println("进入方法前执行.....");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 处理完请求,返回内容
|
||||
// *
|
||||
// * @param ret
|
||||
// */
|
||||
// @AfterReturning(returning = "ret", pointcut = "operationLog()")
|
||||
// public void doAfterReturning(Object ret) {
|
||||
//// System.out.println("方法的返回值 : " + ret);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 后置异常通知
|
||||
// */
|
||||
// @AfterThrowing("operationLog()")
|
||||
// public void throwss(JoinPoint jp) {
|
||||
//// System.out.println("方法异常时执行.....");
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
|
||||
// */
|
||||
// @After("operationLog()")
|
||||
// public void after(JoinPoint jp) {
|
||||
//// System.out.println("方法最后执行.....");
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 获取客户端ip地址
|
||||
// *
|
||||
// * @param request
|
||||
// * @return
|
||||
// */
|
||||
// public static String getClientIp(HttpServletRequest request) {
|
||||
// String ip = request.getHeader("x-forwarded-for");
|
||||
// if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
|
||||
// ip = request.getHeader("Proxy-Client-IP");
|
||||
// }
|
||||
// if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
|
||||
// ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
// }
|
||||
// if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
|
||||
// ip = request.getRemoteAddr();
|
||||
// }
|
||||
// // 多个路由时,取第一个非unknown的ip
|
||||
// final String[] arr = ip.split(",");
|
||||
// for (final String str : arr) {
|
||||
// if (!"unknown".equalsIgnoreCase(str)) {
|
||||
// ip = str;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// return ip;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
@ -1,66 +1,66 @@ |
||||
package com.daqing.financial.hrauth.enums; |
||||
|
||||
/** |
||||
* 日志操作类型 |
||||
*/ |
||||
public enum BusinessType |
||||
{ |
||||
/** |
||||
* 其它 |
||||
*/ |
||||
OTHER, |
||||
/** |
||||
* 新增 |
||||
*/ |
||||
INSERT, |
||||
/** |
||||
* 修改 |
||||
*/ |
||||
UPDATE, |
||||
/** |
||||
* 删除 |
||||
*/ |
||||
DELETE, |
||||
/** |
||||
* 查询 |
||||
*/ |
||||
SELECT, |
||||
/** |
||||
* 导出 |
||||
*/ |
||||
EXPORT, |
||||
/** |
||||
* 导入 |
||||
*/ |
||||
IMPORT; |
||||
|
||||
public static String getMsg(BusinessType type){ |
||||
String result = null; |
||||
switch (type) { |
||||
case INSERT: |
||||
result = "新增"; |
||||
break; |
||||
case UPDATE: |
||||
result = "修改"; |
||||
break; |
||||
case DELETE: |
||||
result = "删除"; |
||||
break; |
||||
case SELECT: |
||||
result = "查询"; |
||||
break; |
||||
case EXPORT: |
||||
result = "导出"; |
||||
break; |
||||
case IMPORT: |
||||
result = "导入"; |
||||
break; |
||||
case OTHER: |
||||
result = "其它"; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return result; |
||||
} |
||||
} |
||||
//package com.daqing.financial.hrauth.enums;
|
||||
//
|
||||
///**
|
||||
// * 日志操作类型
|
||||
// */
|
||||
//public enum BusinessType
|
||||
//{
|
||||
// /**
|
||||
// * 其它
|
||||
// */
|
||||
// OTHER,
|
||||
// /**
|
||||
// * 新增
|
||||
// */
|
||||
// INSERT,
|
||||
// /**
|
||||
// * 修改
|
||||
// */
|
||||
// UPDATE,
|
||||
// /**
|
||||
// * 删除
|
||||
// */
|
||||
// DELETE,
|
||||
// /**
|
||||
// * 查询
|
||||
// */
|
||||
// SELECT,
|
||||
// /**
|
||||
// * 导出
|
||||
// */
|
||||
// EXPORT,
|
||||
// /**
|
||||
// * 导入
|
||||
// */
|
||||
// IMPORT;
|
||||
//
|
||||
// public static String getMsg(BusinessType type){
|
||||
// String result = null;
|
||||
// switch (type) {
|
||||
// case INSERT:
|
||||
// result = "新增";
|
||||
// break;
|
||||
// case UPDATE:
|
||||
// result = "修改";
|
||||
// break;
|
||||
// case DELETE:
|
||||
// result = "删除";
|
||||
// break;
|
||||
// case SELECT:
|
||||
// result = "查询";
|
||||
// break;
|
||||
// case EXPORT:
|
||||
// result = "导出";
|
||||
// break;
|
||||
// case IMPORT:
|
||||
// result = "导入";
|
||||
// break;
|
||||
// case OTHER:
|
||||
// result = "其它";
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
//}
|
||||
|
@ -1,52 +1,52 @@ |
||||
package com.daqing.financial.hrauth.enums; |
||||
|
||||
public enum OperationType { |
||||
|
||||
/** |
||||
* 操作类型 |
||||
*/ |
||||
UNKNOWN("UNKNOWN"), |
||||
DELETE("DELETE"), |
||||
SELECT("SELECT"), |
||||
UPDATE("UPDATE"), |
||||
INSERT("INSERT"); |
||||
|
||||
private String value; |
||||
|
||||
public String getValue() { |
||||
return value; |
||||
} |
||||
|
||||
public void setValue(String value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
OperationType(String s) { |
||||
this.value = s; |
||||
} |
||||
|
||||
|
||||
public static String getMsg(BusinessType type){ |
||||
String result = null; |
||||
switch (type) { |
||||
case INSERT: |
||||
result = "新增"; |
||||
break; |
||||
case UPDATE: |
||||
result = "修改"; |
||||
break; |
||||
case DELETE: |
||||
result = "删除"; |
||||
break; |
||||
case SELECT: |
||||
result = "查询"; |
||||
break; |
||||
case OTHER: |
||||
result = "其它"; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return result; |
||||
} |
||||
} |
||||
//package com.daqing.financial.hrauth.enums;
|
||||
//
|
||||
//public enum OperationType {
|
||||
//
|
||||
// /**
|
||||
// * 操作类型
|
||||
// */
|
||||
// UNKNOWN("UNKNOWN"),
|
||||
// DELETE("DELETE"),
|
||||
// SELECT("SELECT"),
|
||||
// UPDATE("UPDATE"),
|
||||
// INSERT("INSERT");
|
||||
//
|
||||
// private String value;
|
||||
//
|
||||
// public String getValue() {
|
||||
// return value;
|
||||
// }
|
||||
//
|
||||
// public void setValue(String value) {
|
||||
// this.value = value;
|
||||
// }
|
||||
//
|
||||
// OperationType(String s) {
|
||||
// this.value = s;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public static String getMsg(BusinessType type){
|
||||
// String result = null;
|
||||
// switch (type) {
|
||||
// case INSERT:
|
||||
// result = "新增";
|
||||
// break;
|
||||
// case UPDATE:
|
||||
// result = "修改";
|
||||
// break;
|
||||
// case DELETE:
|
||||
// result = "删除";
|
||||
// break;
|
||||
// case SELECT:
|
||||
// result = "查询";
|
||||
// break;
|
||||
// case OTHER:
|
||||
// result = "其它";
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
//}
|
||||
|
@ -1,59 +1,59 @@ |
||||
package com.daqing.financial.hrauth.enums; |
||||
|
||||
public enum OperationUnit { |
||||
/** |
||||
* 被操作的单元 |
||||
*/ |
||||
UNKNOWN("unknown"), |
||||
APPLYAMOUNTINFO("业务申请"), |
||||
GUARANTEE("担保部调查"), |
||||
ASSETS("资产部调查"), |
||||
MESSAGE("信息部调查"), |
||||
COMPLIANCE("合规调查"), |
||||
WORKCONFERENCE("工作会"), |
||||
LOANCOMMITTEE("贷审会"), |
||||
GUARANTEELETTER("担保函"), |
||||
PAYMENTCONFIRMATION("财务确认"), |
||||
LOANNOTICE("放款通知"), |
||||
COPYFOR("抄送"), |
||||
EFFICIENCY("流程效率"), |
||||
FORMDESIGN("表单设计"), |
||||
PROCESSMANAGE("流程管理"), |
||||
STATISTICS("业务统计"), |
||||
LOGIN("登录"), |
||||
ROLEPERMISSION("角色权限管理"), |
||||
EMPLOYEE("员工信息"), |
||||
COMPANY("企业信息"), |
||||
SYSLOG("日志管理"), |
||||
INSURANCE("保后管理"), |
||||
COLLECTION("催收管理"), |
||||
USER("user"), |
||||
LOG("log"), |
||||
PERMISSION("permission"), |
||||
ROLE("role"), |
||||
DEVICE("device"), |
||||
WITHDRAW("withdraw"), |
||||
ATRUSER("atrUser"), |
||||
ASSERT("ASSERT"), |
||||
COIN("coin"), |
||||
NOTICE("notice"), |
||||
DATASTATISTIC("datastatistic"), |
||||
BlockGroup("blockGroup"), |
||||
C2C("c2c"), |
||||
USERROLE("userRole"); |
||||
|
||||
private String value; |
||||
|
||||
OperationUnit(String value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
public String getValue() { |
||||
return value; |
||||
} |
||||
|
||||
public void setValue(String value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
} |
||||
//package com.daqing.financial.hrauth.enums;
|
||||
//
|
||||
//public enum OperationUnit {
|
||||
// /**
|
||||
// * 被操作的单元
|
||||
// */
|
||||
// UNKNOWN("unknown"),
|
||||
// APPLYAMOUNTINFO("业务申请"),
|
||||
// GUARANTEE("担保部调查"),
|
||||
// ASSETS("资产部调查"),
|
||||
// MESSAGE("信息部调查"),
|
||||
// COMPLIANCE("合规调查"),
|
||||
// WORKCONFERENCE("工作会"),
|
||||
// LOANCOMMITTEE("贷审会"),
|
||||
// GUARANTEELETTER("担保函"),
|
||||
// PAYMENTCONFIRMATION("财务确认"),
|
||||
// LOANNOTICE("放款通知"),
|
||||
// COPYFOR("抄送"),
|
||||
// EFFICIENCY("流程效率"),
|
||||
// FORMDESIGN("表单设计"),
|
||||
// PROCESSMANAGE("流程管理"),
|
||||
// STATISTICS("业务统计"),
|
||||
// LOGIN("登录"),
|
||||
// ROLEPERMISSION("角色权限管理"),
|
||||
// EMPLOYEE("员工信息"),
|
||||
// COMPANY("企业信息"),
|
||||
// SYSLOG("日志管理"),
|
||||
// INSURANCE("保后管理"),
|
||||
// COLLECTION("催收管理"),
|
||||
// USER("user"),
|
||||
// LOG("log"),
|
||||
// PERMISSION("permission"),
|
||||
// ROLE("role"),
|
||||
// DEVICE("device"),
|
||||
// WITHDRAW("withdraw"),
|
||||
// ATRUSER("atrUser"),
|
||||
// ASSERT("ASSERT"),
|
||||
// COIN("coin"),
|
||||
// NOTICE("notice"),
|
||||
// DATASTATISTIC("datastatistic"),
|
||||
// BlockGroup("blockGroup"),
|
||||
// C2C("c2c"),
|
||||
// USERROLE("userRole");
|
||||
//
|
||||
// private String value;
|
||||
//
|
||||
// OperationUnit(String value) {
|
||||
// this.value = value;
|
||||
// }
|
||||
//
|
||||
// public String getValue() {
|
||||
// return value;
|
||||
// }
|
||||
//
|
||||
// public void setValue(String value) {
|
||||
// this.value = value;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
@ -1,13 +1,13 @@ |
||||
//package com.daqing.financial.hrms.config;
|
||||
//
|
||||
//import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
//@Configuration
|
||||
//public class IPageConfig {
|
||||
// @Bean
|
||||
// public PaginationInterceptor paginationInterceptor() {
|
||||
// return new PaginationInterceptor();
|
||||
// }
|
||||
//}
|
||||
package com.daqing.financial.hrms.config; |
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
@Configuration |
||||
public class IPageConfig { |
||||
@Bean |
||||
public PaginationInterceptor paginationInterceptor() { |
||||
return new PaginationInterceptor(); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,47 @@ |
||||
package com.daqing.framework.annotation; |
||||
|
||||
import com.daqing.framework.enums.OperationType; |
||||
import com.daqing.framework.enums.OperationUnit; |
||||
|
||||
import java.lang.annotation.*; |
||||
|
||||
/** |
||||
* @author Rogers |
||||
* 操作日志注解 |
||||
* @create 2020-07-03 |
||||
*/ |
||||
@Target({ElementType.METHOD}) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
public @interface Log { |
||||
|
||||
/** |
||||
* 方法描述,可使用占位符获取参数:{{tel}} |
||||
*/ |
||||
String detail() default ""; |
||||
|
||||
/** |
||||
* 日志等级:自己定,此处分为1-9 |
||||
*/ |
||||
int level() default 0; |
||||
|
||||
/** |
||||
* 操作类型(enum):主要是select,insert,update,delete |
||||
*/ |
||||
OperationType operationType() default OperationType.UNKNOWN; |
||||
|
||||
/** |
||||
* 被操作的对象(此处使用enum):可以是任何对象,如表名(user),或者是工具(redis) |
||||
*/ |
||||
OperationUnit operationUnit() default OperationUnit.UNKNOWN; |
||||
|
||||
/** 该属性需要访问的微服务名称 */ |
||||
// String serverId();
|
||||
//
|
||||
// /** 表名 */
|
||||
// String tableName();
|
||||
|
||||
|
||||
} |
||||
|
||||
|
@ -0,0 +1,129 @@ |
||||
package com.daqing.framework.aspect; |
||||
|
||||
import com.alibaba.fastjson.JSON; |
||||
import com.alibaba.fastjson.JSONObject; |
||||
import com.daqing.framework.annotation.Log; |
||||
import com.daqing.framework.feign.HrauthFeignService; |
||||
import com.daqing.framework.model.EmployeeEntity; |
||||
import com.daqing.framework.model.SystemLog; |
||||
import com.daqing.framework.model.UserEntity; |
||||
import com.daqing.framework.model.response.ResponseResult; |
||||
import com.daqing.framework.util.IpUtils; |
||||
import com.daqing.framework.util.RedisUtil; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.apache.commons.lang3.StringUtils; |
||||
import org.aspectj.lang.JoinPoint; |
||||
import org.aspectj.lang.reflect.MethodSignature; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; |
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy; |
||||
import org.springframework.scheduling.annotation.Async; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.context.request.RequestContextHolder; |
||||
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
|
||||
import javax.annotation.Resource; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import java.util.Date; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.UUID; |
||||
|
||||
/** |
||||
* @ClassName Operation |
||||
* @Description 操作日志类 |
||||
* @Date 2020/9/29 10:06 |
||||
* @Version 1.0 |
||||
*/ |
||||
@Slf4j |
||||
@Component |
||||
@EnableDiscoveryClient |
||||
@EnableAspectJAutoProxy(proxyTargetClass = true) |
||||
public class Operation { |
||||
@Autowired |
||||
private HrauthFeignService hrauthFeignService; |
||||
|
||||
@Async |
||||
public void addOperationLog(JoinPoint joinPoint, Object res, long time, UserEntity systemUser, EmployeeEntity employeeEntity) { |
||||
// synchronized (SysLogAspect.class) {//获得登录用户信息
|
||||
// User systemUser = (User) SecurityUtils.getSubject().getPrincipal();
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); |
||||
SystemLog operationLog = new SystemLog(); |
||||
operationLog.setJobNumber(employeeEntity.getJobNumber()); |
||||
//获取内网地址IpUtils.intranetIp()
|
||||
//获取外网地址IpUtils.internetIp()
|
||||
// operationLog.setIpAddressLan("");
|
||||
// operationLog.setIpAddressWan("");
|
||||
operationLog.setIpAddressLan(IpUtils.intranetIp()); |
||||
//获取不到外网IP设置内网IP
|
||||
if (StringUtils.isBlank(IpUtils.internetIp())) { |
||||
operationLog.setIpAddressWan(IpUtils.intranetIp()); |
||||
} else { |
||||
operationLog.setIpAddressWan(IpUtils.internetIp()); |
||||
} |
||||
// operationLog.setRunTime(time);
|
||||
//operationLog.setRunTime(0L);
|
||||
operationLog.setReturnValue(JSONObject.toJSONString(res)); |
||||
operationLog.setId(UUID.randomUUID().toString()); |
||||
operationLog.setArgs(JSONObject.toJSONString(joinPoint.getArgs())); |
||||
operationLog.setCreateTime(new Date()); |
||||
operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName()); |
||||
operationLog.setUserId(systemUser.getId() + ""); |
||||
operationLog.setUserName(employeeEntity.getName()); |
||||
Log annotation = signature.getMethod().getAnnotation(Log.class); |
||||
if (annotation != null) { |
||||
operationLog.setLogLevel(annotation.level()); |
||||
operationLog.setLogDescribe(getDetail(((MethodSignature) joinPoint.getSignature()).getParameterNames(), joinPoint.getArgs(), annotation)); |
||||
operationLog.setOperationType(annotation.operationType().getValue()); |
||||
operationLog.setOperationUnit(annotation.operationUnit().getValue()); |
||||
} |
||||
|
||||
//这里保存日志
|
||||
// log.info("######记录日志:{}######", operationLog.toString());
|
||||
//int b = systemLogMapper.insert(operationLog);
|
||||
ResponseResult insert = hrauthFeignService.insert(operationLog); |
||||
log.info("######记录日志:{}######", operationLog.toString()); |
||||
if (insert.getCode()== 40007) { |
||||
log.error("#####新增###记录日志失败:{}####", operationLog); |
||||
} |
||||
// }
|
||||
} |
||||
|
||||
/** |
||||
* 对当前登录用户和占位符处理 |
||||
* |
||||
* @param argNames 方法参数名称数组 |
||||
* @param args 方法参数数组 |
||||
* @param annotation 注解信息 |
||||
* @return 返回处理后的描述 |
||||
*/ |
||||
private String getDetail(String[] argNames, Object[] args, Log annotation) { |
||||
//获得登录用户信息
|
||||
//User systemUser = (User) SecurityUtils.getSubject().getPrincipal();
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); |
||||
String token = request.getHeader("token"); |
||||
String userId = RedisUtil.get("dq:token:"+token); |
||||
String userEntityStr = RedisUtil.get("dq:userId:"+userId); |
||||
UserEntity systemUser = JSON.parseObject(userEntityStr,UserEntity.class); |
||||
//Token userToken = tokenService.getOne(new QueryWrapper<Token>().eq("token", token));
|
||||
//UserEntity systemUser = userLoginService.getOne(new QueryWrapper<UserEntity>().eq("id",userToken.getUserId()));
|
||||
|
||||
Map<Object, Object> map = new HashMap<>(4); |
||||
for (int i = 0; i < argNames.length; i++) { |
||||
map.put(argNames[i], args[i]); |
||||
} |
||||
|
||||
String detail = annotation.detail(); |
||||
try { |
||||
detail = "'" + systemUser.getAccount() + "'=》" + annotation.detail(); |
||||
for (Map.Entry<Object, Object> entry : map.entrySet()) { |
||||
Object k = entry.getKey(); |
||||
Object v = entry.getValue(); |
||||
detail = detail.replace("{{" + k + "}}", JSONObject.toJSONString(v)); |
||||
} |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return detail; |
||||
} |
||||
} |
@ -0,0 +1,185 @@ |
||||
package com.daqing.framework.aspect; |
||||
|
||||
import com.alibaba.fastjson.JSON; |
||||
import com.alibaba.fastjson.JSONObject; |
||||
import com.daqing.framework.annotation.Log; |
||||
import com.daqing.framework.feign.HrmsFeignService; |
||||
import com.daqing.framework.model.EmployeeEntity; |
||||
import com.daqing.framework.model.UserEntity; |
||||
import com.daqing.framework.util.RedisUtil; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.aspectj.lang.JoinPoint; |
||||
import org.aspectj.lang.ProceedingJoinPoint; |
||||
import org.aspectj.lang.annotation.*; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; |
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.context.request.RequestContextHolder; |
||||
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
|
||||
import javax.annotation.Resource; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @ClassName SysLogAspect |
||||
* @Description 操作日志切面 |
||||
* @Date 2020/9/30 |
||||
* @Version 1.0 |
||||
*/ |
||||
@Slf4j |
||||
@Aspect |
||||
@Component |
||||
@EnableDiscoveryClient |
||||
@EnableAspectJAutoProxy(proxyTargetClass = true) |
||||
public class SysLogAspect { |
||||
|
||||
@Resource |
||||
private Operation operation; |
||||
@Autowired |
||||
private HrmsFeignService hrmsFeignService; |
||||
/** |
||||
* 此处的切点是注解的方式,也可以用包名的方式达到相同的效果 |
||||
* '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")' |
||||
*/ |
||||
@Pointcut("@annotation(com.daqing.framework.annotation.Log)") |
||||
public void operationLog() { |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 环绕增强,相当于MethodInterceptor |
||||
*/ |
||||
@Around("operationLog()") |
||||
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { |
||||
Object res = null; |
||||
long time = System.currentTimeMillis(); |
||||
try { |
||||
res = joinPoint.proceed(); |
||||
time = System.currentTimeMillis() - time; |
||||
return res; |
||||
} finally { |
||||
try { |
||||
//User systemUser = (User) SecurityUtils.getSubject().getPrincipal();
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); |
||||
String token = request.getHeader("token"); |
||||
String userId = RedisUtil.get("dq:token:"+token); |
||||
String userEntityStr = RedisUtil.get("dq:userId:"+userId); |
||||
UserEntity systemUser = JSON.parseObject(userEntityStr,UserEntity.class); |
||||
|
||||
//根据userId查询工号以及员工姓名
|
||||
if(userId !=null && userId != ""){ |
||||
EmployeeEntity employeeEntity = hrmsFeignService.getEmpmsgById(Long.valueOf(userId)); |
||||
operation.addOperationLog(joinPoint,res,time,systemUser,employeeEntity); |
||||
} |
||||
|
||||
//Token userToken = tokenService.getOne(new QueryWrapper<Token>().eq("token", token));
|
||||
//UserEntity systemUser = userLoginService.getOne(new QueryWrapper<UserEntity>().eq("id",userId));
|
||||
//operation.addOperationLog(joinPoint,res,time,systemUser,employeeEntity);
|
||||
//方法执行完成后增加日志
|
||||
// addOperationLog(joinPoint, res, time);
|
||||
} catch (Exception e) { |
||||
log.error("LogAspect 操作失败:" + e.getMessage()); |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 对当前登录用户和占位符处理 |
||||
* |
||||
* @param argNames 方法参数名称数组 |
||||
* @param args 方法参数数组 |
||||
* @param annotation 注解信息 |
||||
* @return 返回处理后的描述 |
||||
*/ |
||||
private String getDetail(String[] argNames, Object[] args, Log annotation) { |
||||
//获得登录用户信息
|
||||
//User systemUser = (User) SecurityUtils.getSubject().getPrincipal();
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); |
||||
UserEntity systemUser = (UserEntity) request.getUserPrincipal(); |
||||
|
||||
Map<Object, Object> map = new HashMap<>(4); |
||||
for (int i = 0; i < argNames.length; i++) { |
||||
map.put(argNames[i], args[i]); |
||||
} |
||||
|
||||
String detail = annotation.detail(); |
||||
try { |
||||
detail = "'" + systemUser.getAccount() + "'=》" + annotation.detail(); |
||||
for (Map.Entry<Object, Object> entry : map.entrySet()) { |
||||
Object k = entry.getKey(); |
||||
Object v = entry.getValue(); |
||||
detail = detail.replace("{{" + k + "}}", JSONObject.toJSONString(v)); |
||||
} |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return detail; |
||||
} |
||||
|
||||
@Before("operationLog()") |
||||
public void doBeforeAdvice(JoinPoint joinPoint) { |
||||
// System.out.println("进入方法前执行.....");
|
||||
} |
||||
|
||||
/** |
||||
* 处理完请求,返回内容 |
||||
* |
||||
* @param ret |
||||
*/ |
||||
@AfterReturning(returning = "ret", pointcut = "operationLog()") |
||||
public void doAfterReturning(Object ret) { |
||||
// System.out.println("方法的返回值 : " + ret);
|
||||
} |
||||
|
||||
/** |
||||
* 后置异常通知 |
||||
*/ |
||||
@AfterThrowing("operationLog()") |
||||
public void throwss(JoinPoint jp) { |
||||
// System.out.println("方法异常时执行.....");
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行 |
||||
*/ |
||||
@After("operationLog()") |
||||
public void after(JoinPoint jp) { |
||||
// System.out.println("方法最后执行.....");
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 获取客户端ip地址 |
||||
* |
||||
* @param request |
||||
* @return |
||||
*/ |
||||
public static String getClientIp(HttpServletRequest request) { |
||||
String ip = request.getHeader("x-forwarded-for"); |
||||
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getHeader("Proxy-Client-IP"); |
||||
} |
||||
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getHeader("WL-Proxy-Client-IP"); |
||||
} |
||||
if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getRemoteAddr(); |
||||
} |
||||
// 多个路由时,取第一个非unknown的ip
|
||||
final String[] arr = ip.split(","); |
||||
for (final String str : arr) { |
||||
if (!"unknown".equalsIgnoreCase(str)) { |
||||
ip = str; |
||||
break; |
||||
} |
||||
} |
||||
return ip; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,66 @@ |
||||
package com.daqing.framework.enums; |
||||
|
||||
/** |
||||
* 日志操作类型 |
||||
*/ |
||||
public enum BusinessType |
||||
{ |
||||
/** |
||||
* 其它 |
||||
*/ |
||||
OTHER, |
||||
/** |
||||
* 新增 |
||||
*/ |
||||
INSERT, |
||||
/** |
||||
* 修改 |
||||
*/ |
||||
UPDATE, |
||||
/** |
||||
* 删除 |
||||
*/ |
||||
DELETE, |
||||
/** |
||||
* 查询 |
||||
*/ |
||||
SELECT, |
||||
/** |
||||
* 导出 |
||||
*/ |
||||
EXPORT, |
||||
/** |
||||
* 导入 |
||||
*/ |
||||
IMPORT; |
||||
|
||||
public static String getMsg(BusinessType type){ |
||||
String result = null; |
||||
switch (type) { |
||||
case INSERT: |
||||
result = "新增"; |
||||
break; |
||||
case UPDATE: |
||||
result = "修改"; |
||||
break; |
||||
case DELETE: |
||||
result = "删除"; |
||||
break; |
||||
case SELECT: |
||||
result = "查询"; |
||||
break; |
||||
case EXPORT: |
||||
result = "导出"; |
||||
break; |
||||
case IMPORT: |
||||
result = "导入"; |
||||
break; |
||||
case OTHER: |
||||
result = "其它"; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return result; |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
package com.daqing.framework.enums; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <p> 全局常用变量 </p> |
||||
* |
||||
* @description : |
||||
* @author : zhengqing |
||||
* @date : 2019/10/12 14:47 |
||||
*/ |
||||
public class Constants { |
||||
|
||||
/** |
||||
* 接口url |
||||
*/ |
||||
public static Map<String,String> URL_MAPPING_MAP = new HashMap<>(); |
||||
|
||||
/** |
||||
* 获取项目根目录 |
||||
*/ |
||||
public static String PROJECT_ROOT_DIRECTORY = System.getProperty("user.dir"); |
||||
|
||||
/** |
||||
* 密码加密相关 |
||||
*/ |
||||
public static String SALT = "zhengqing"; |
||||
public static final int HASH_ITERATIONS = 1; |
||||
|
||||
/** |
||||
* 请求头 - token |
||||
*/ |
||||
public static final String REQUEST_HEADER = "X-Token"; |
||||
|
||||
/** |
||||
* 请求头类型: |
||||
* application/x-www-form-urlencoded : form表单格式 |
||||
* application/json : json格式 |
||||
*/ |
||||
public static final String REQUEST_HEADERS_CONTENT_TYPE = "application/json"; |
||||
|
||||
/** |
||||
* 未登录者角色 |
||||
*/ |
||||
public static final String ROLE_LOGIN = "role_login"; |
||||
|
||||
} |
@ -0,0 +1,52 @@ |
||||
package com.daqing.framework.enums; |
||||
|
||||
public enum OperationType { |
||||
|
||||
/** |
||||
* 操作类型 |
||||
*/ |
||||
UNKNOWN("UNKNOWN"), |
||||
DELETE("DELETE"), |
||||
SELECT("SELECT"), |
||||
UPDATE("UPDATE"), |
||||
INSERT("INSERT"); |
||||
|
||||
private String value; |
||||
|
||||
public String getValue() { |
||||
return value; |
||||
} |
||||
|
||||
public void setValue(String value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
OperationType(String s) { |
||||
this.value = s; |
||||
} |
||||
|
||||
|
||||
public static String getMsg(BusinessType type){ |
||||
String result = null; |
||||
switch (type) { |
||||
case INSERT: |
||||
result = "新增"; |
||||
break; |
||||
case UPDATE: |
||||
result = "修改"; |
||||
break; |
||||
case DELETE: |
||||
result = "删除"; |
||||
break; |
||||
case SELECT: |
||||
result = "查询"; |
||||
break; |
||||
case OTHER: |
||||
result = "其它"; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return result; |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
package com.daqing.framework.enums; |
||||
|
||||
public enum OperationUnit { |
||||
/** |
||||
* 被操作的单元 |
||||
*/ |
||||
UNKNOWN("unknown"), |
||||
APPLYAMOUNTINFO("业务申请"), |
||||
GUARANTEE("担保部调查"), |
||||
ASSETS("资产部调查"), |
||||
MESSAGE("信息部调查"), |
||||
COMPLIANCE("合规调查"), |
||||
WORKCONFERENCE("工作会"), |
||||
LOANCOMMITTEE("贷审会"), |
||||
GUARANTEELETTER("担保函"), |
||||
PAYMENTCONFIRMATION("财务确认"), |
||||
LOANNOTICE("放款通知"), |
||||
COPYFOR("抄送"), |
||||
EFFICIENCY("流程效率"), |
||||
FORMDESIGN("表单设计"), |
||||
PROCESSMANAGE("流程管理"), |
||||
STATISTICS("业务统计"), |
||||
LOGIN("登录"), |
||||
ROLEPERMISSION("角色权限管理"), |
||||
EMPLOYEE("员工信息"), |
||||
COMPANY("企业信息"), |
||||
SYSLOG("日志管理"), |
||||
INSURANCE("保后管理"), |
||||
COLLECTION("催收管理"), |
||||
USER("user"), |
||||
LOG("log"), |
||||
PERMISSION("permission"), |
||||
ROLE("role"), |
||||
DEVICE("device"), |
||||
WITHDRAW("withdraw"), |
||||
ATRUSER("atrUser"), |
||||
ASSERT("ASSERT"), |
||||
COIN("coin"), |
||||
NOTICE("notice"), |
||||
DATASTATISTIC("datastatistic"), |
||||
BlockGroup("blockGroup"), |
||||
C2C("c2c"), |
||||
USERROLE("userRole"); |
||||
|
||||
private String value; |
||||
|
||||
OperationUnit(String value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
public String getValue() { |
||||
return value; |
||||
} |
||||
|
||||
public void setValue(String value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,22 @@ |
||||
package com.daqing.framework.feign; |
||||
|
||||
import com.daqing.framework.model.SystemLog; |
||||
import com.daqing.framework.model.response.ResponseResult; |
||||
import org.springframework.cloud.openfeign.FeignClient; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.PostMapping; |
||||
import org.springframework.web.bind.annotation.RequestBody; |
||||
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
||||
import java.util.List; |
||||
|
||||
|
||||
/** |
||||
* 这是一个声明式的远程调用 |
||||
*/ |
||||
@FeignClient(value = "dq-financial-hrms-auth",contextId = "common-hrms-auth") |
||||
public interface HrauthFeignService { |
||||
|
||||
@PostMapping("/hrms/auth/systemLog/insert") |
||||
ResponseResult insert(@RequestBody SystemLog operationLog); |
||||
} |
@ -0,0 +1,21 @@ |
||||
package com.daqing.framework.feign; |
||||
|
||||
import com.daqing.framework.model.EmployeeEntity; |
||||
import com.daqing.framework.model.response.ResponseResult; |
||||
import org.springframework.cloud.openfeign.FeignClient; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.bind.annotation.*; |
||||
|
||||
import java.util.List; |
||||
|
||||
|
||||
/** |
||||
* 这是一个声明式的远程调用 |
||||
*/ |
||||
@Component |
||||
@FeignClient(name="dq-financial-hrms",contextId = "common-hrms") |
||||
public interface HrmsFeignService { |
||||
|
||||
@GetMapping("hrms/employee/getEmpmsgById") |
||||
EmployeeEntity getEmpmsgById(@RequestParam("id") Long id); |
||||
} |
@ -0,0 +1,73 @@ |
||||
package com.daqing.framework.model; |
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType; |
||||
import com.baomidou.mybatisplus.annotation.TableId; |
||||
import com.baomidou.mybatisplus.annotation.TableName; |
||||
import lombok.Data; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Date; |
||||
|
||||
/** |
||||
* 记录员工的基本信息,如姓名、电话、部门等 |
||||
* |
||||
* @author gongsj |
||||
* @email gongsj@gmail.com |
||||
* @date 2020-09-07 16:26:04 |
||||
*/ |
||||
@Data |
||||
@TableName("hrms_employee") |
||||
public class EmployeeEntity implements Serializable { |
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
/** |
||||
* 主键 |
||||
*/ |
||||
@TableId(value = "id", type = IdType.INPUT) |
||||
private Long id; |
||||
/** |
||||
* 姓名 |
||||
*/ |
||||
private String name; |
||||
/** |
||||
* 性别:1、男,0、女 |
||||
*/ |
||||
private Integer gender; |
||||
/** |
||||
* 生日 |
||||
*/ |
||||
private Date birthday; |
||||
/** |
||||
* 办公电话 |
||||
*/ |
||||
private String officePhone; |
||||
/** |
||||
* 手机号码 |
||||
*/ |
||||
private String phone; |
||||
/** |
||||
* 公司邮箱 |
||||
*/ |
||||
private String companyMail; |
||||
/** |
||||
* 备用邮箱 |
||||
*/ |
||||
private String spareMail; |
||||
/** |
||||
* 职位描述 |
||||
*/ |
||||
private String positionDescription; |
||||
/** |
||||
* 工号 |
||||
*/ |
||||
private String jobNumber; |
||||
/** |
||||
* 头像地址 |
||||
*/ |
||||
private String headPortaritUrl; |
||||
/** |
||||
* 账号表id |
||||
*/ |
||||
private Long userId; |
||||
|
||||
} |
@ -0,0 +1,105 @@ |
||||
package com.daqing.framework.model; |
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType; |
||||
import com.baomidou.mybatisplus.annotation.TableId; |
||||
import com.baomidou.mybatisplus.annotation.TableName; |
||||
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
import io.swagger.annotations.ApiModel; |
||||
import io.swagger.annotations.ApiModelProperty; |
||||
import lombok.AllArgsConstructor; |
||||
import lombok.Builder; |
||||
import lombok.Data; |
||||
import lombok.NoArgsConstructor; |
||||
|
||||
import java.util.Date; |
||||
|
||||
/** |
||||
* @ClassName SystemLog |
||||
* @Description 操作日志 |
||||
* @Date 2020/9/29 14:30 |
||||
* @Version 1.0 |
||||
*/ |
||||
|
||||
@NoArgsConstructor |
||||
@AllArgsConstructor |
||||
@Builder |
||||
@Data |
||||
@TableName("sys_action_log") |
||||
@ApiModel("操作日志") |
||||
public class SystemLog { |
||||
@TableId(value = "id", type = IdType.UUID) |
||||
private String id; |
||||
/** |
||||
* 创建时间 |
||||
*/ |
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
// @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
// @TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@ApiModelProperty("创建时间") |
||||
private Date createTime; |
||||
/** |
||||
* 日志等级 |
||||
*/ |
||||
@ApiModelProperty("日志等级") |
||||
private Integer logLevel; |
||||
/** |
||||
* 被操作的对象 |
||||
*/ |
||||
@ApiModelProperty("被操作的对象") |
||||
private String operationUnit; |
||||
/** |
||||
* 方法名 |
||||
*/ |
||||
@ApiModelProperty("method") |
||||
private String method; |
||||
/** |
||||
* 参数 |
||||
*/ |
||||
@ApiModelProperty("参数") |
||||
private String args; |
||||
/** |
||||
* 操作人id |
||||
*/ |
||||
@ApiModelProperty("操作人id") |
||||
private String userId; |
||||
/** |
||||
* 操作人 |
||||
*/ |
||||
@ApiModelProperty("操作人") |
||||
private String userName; |
||||
/** |
||||
* 日志描述 |
||||
*/ |
||||
@ApiModelProperty("日志描述") |
||||
private String logDescribe; |
||||
/** |
||||
* 操作类型 |
||||
*/ |
||||
@ApiModelProperty("操作类型") |
||||
private String operationType; |
||||
/** |
||||
* 方法运行时间 |
||||
*/ |
||||
@ApiModelProperty("方法运行时间") |
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
private Long runTime; |
||||
/** |
||||
* 方法返回值 |
||||
*/ |
||||
@ApiModelProperty("方法返回值") |
||||
private String returnValue; |
||||
/** |
||||
* 内网IP地址 |
||||
*/ |
||||
@ApiModelProperty("内网IP地址") |
||||
private String ipAddressLan; |
||||
|
||||
/** |
||||
* 外网IP地址 |
||||
*/ |
||||
@ApiModelProperty("外网IP地址") |
||||
private String ipAddressWan; |
||||
|
||||
@ApiModelProperty("工号") |
||||
private String jobNumber; |
||||
} |
@ -0,0 +1,102 @@ |
||||
package com.daqing.framework.model; |
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType; |
||||
import com.baomidou.mybatisplus.annotation.TableId; |
||||
import com.baomidou.mybatisplus.annotation.TableName; |
||||
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
import io.swagger.annotations.ApiModelProperty; |
||||
import lombok.Data; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Date; |
||||
|
||||
/** |
||||
* 人资管理系统,员工账号信息表,用于存储员工账号密码等登录相关数据 |
||||
* |
||||
* @author gongsj |
||||
* @email gongsj@gmail.com |
||||
* @date 2020-09-07 16:26:04 |
||||
*/ |
||||
@Data |
||||
@TableName("hrms_user") |
||||
public class UserEntity implements Serializable { |
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
/** |
||||
* 主键 |
||||
*/ |
||||
@TableId(value = "id", type = IdType.INPUT) |
||||
private Long id; |
||||
/** |
||||
* 用于登录的账号,必填 |
||||
*/ |
||||
private String account; |
||||
/** |
||||
* 用户可以绑定手机账号,用于登录 |
||||
*/ |
||||
private String phoneAccount; |
||||
/** |
||||
* 登录密码 |
||||
*/ |
||||
private String password; |
||||
/** |
||||
* 登录次数 |
||||
*/ |
||||
private Integer loginNum; |
||||
/** |
||||
* 上次的登录时间 |
||||
*/ |
||||
private Date lasttime; |
||||
/** |
||||
* 微信的唯一标识 |
||||
*/ |
||||
private String wechatId; |
||||
/** |
||||
* 状态:0、启用,1、禁用 |
||||
*/ |
||||
private Integer status; |
||||
/** |
||||
* 禁用开始时间 |
||||
*/ |
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
||||
@ApiModelProperty("禁用开始时间") |
||||
private Date disableStartTime; |
||||
/** |
||||
* 禁用结束时间 |
||||
*/ |
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
||||
@ApiModelProperty("禁用结束时间") |
||||
private Date disableEndTime; |
||||
/** |
||||
* 禁用原因 |
||||
*/ |
||||
@ApiModelProperty("禁用原因") |
||||
private String disableCause; |
||||
/** |
||||
* 是否删除:0、未删除,1、删除 |
||||
*/ |
||||
private Integer delOrNot; |
||||
/** |
||||
* 创建时间 |
||||
*/ |
||||
private Date createTime; |
||||
/** |
||||
* 更新时间 |
||||
*/ |
||||
private Date motifyTime; |
||||
|
||||
/** |
||||
* Token |
||||
*/ |
||||
private String token; |
||||
|
||||
/** |
||||
* 盐值 |
||||
*/ |
||||
//private String salt;
|
||||
/** |
||||
* 头像地址 |
||||
*/ |
||||
private String headPortaritUrl; |
||||
|
||||
} |
@ -0,0 +1,67 @@ |
||||
package com.daqing.framework.util; |
||||
|
||||
import java.net.Inet4Address; |
||||
import java.net.InetAddress; |
||||
import java.net.NetworkInterface; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* @ClassName IpUtils |
||||
* @Description Ip工具类,获取ip |
||||
* @Date 2020/9/30 |
||||
* @Version 1.0 |
||||
*/ |
||||
public class IpUtils { |
||||
/*** |
||||
* 获取外网IP |
||||
* @return |
||||
*/ |
||||
public static String internetIp() { |
||||
try { |
||||
|
||||
Enumeration<NetworkInterface> networks = NetworkInterface.getNetworkInterfaces(); |
||||
InetAddress inetAddress = null; |
||||
Enumeration<InetAddress> inetAddresses = null; |
||||
while (networks.hasMoreElements()) { |
||||
inetAddresses = networks.nextElement().getInetAddresses(); |
||||
while (inetAddresses.hasMoreElements()) { |
||||
inetAddress = inetAddresses.nextElement(); |
||||
if (inetAddress != null |
||||
&& inetAddress instanceof Inet4Address |
||||
&& !inetAddress.isSiteLocalAddress() |
||||
&& !inetAddress.isLoopbackAddress() |
||||
&& inetAddress.getHostAddress().indexOf(":") == -1) { |
||||
return inetAddress.getHostAddress(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
|
||||
} catch (Exception e) { |
||||
|
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取内网IP |
||||
* |
||||
* @return |
||||
*/ |
||||
public static String intranetIp() { |
||||
try { |
||||
return InetAddress.getLocalHost().getHostAddress(); |
||||
} catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取服务启动host |
||||
* @return |
||||
*/ |
||||
public static String getHost(){ |
||||
return internetIp()==null?intranetIp():internetIp(); |
||||
} |
||||
} |
Loading…
Reference in new issue