初始代码

This commit is contained in:
wangmingwei
2026-04-21 16:49:46 +08:00
parent aae9dc4036
commit f0453ff3a3
2396 changed files with 256575 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
<?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>yunzhupaas-java-boot</artifactId>
<groupId>com.yunzhupaas</groupId>
<version>5.2.0-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yunzhupaas-exception</artifactId>
<dependencies>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-common-auth</artifactId>
</dependency>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-common-all</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-oauth-entity</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,169 @@
package com.yunzhupaas.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import com.yunzhupaas.base.controller.SuperController;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import com.yunzhupaas.base.ActionResult;
import com.yunzhupaas.base.vo.PaginationVO;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.entity.LogEntity;
import com.yunzhupaas.model.*;
import com.yunzhupaas.service.LogService;
import com.yunzhupaas.util.JsonUtil;
import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 系统日志
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2023/09/27
*/
@Tag(name = "系统日志", description = "Log")
@RestController
@RequestMapping("/api/system/Log")
public class LogController extends SuperController<LogService, LogEntity> {
@Autowired
private LogService logService;
/**
* 获取系统日志信息
*
* @param pagination category 主键值分类 1登录日志2.访问日志3.操作日志4.异常日志5.请求日志
* @return
*/
@Operation(summary = "获取系统日志列表")
@Parameters({
@Parameter(name = "category", description = "分类", required = true)
})
@SaCheckPermission("system.log")
@GetMapping
public ActionResult getInfoList(PaginationLogModel pagination) {
List<LogEntity> list = logService.getList(pagination.getCategory(), pagination);
PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
switch (pagination.getCategory()) {
case 1:
List<LoginLogVO> loginLogVOList = JsonUtil.getJsonToList(list, LoginLogVO.class);
for (int i = 0; i < loginLogVOList.size(); i++) {
loginLogVOList.get(i).setAbstracts(list.get(i).getDescription());
}
return ActionResult.page(loginLogVOList, paginationVO);
case 3:
List<HandleLogVO> handleLogVOList = JsonUtil.getJsonToList(list, HandleLogVO.class);
return ActionResult.page(handleLogVOList, paginationVO);
case 4:
List<ErrorLogVO> errorLogVOList = JsonUtil.getJsonToList(list, ErrorLogVO.class);
return ActionResult.page(errorLogVOList, paginationVO);
case 5:
List<RequestLogVO> requestLogVOList = JsonUtil.getJsonToList(list, RequestLogVO.class);
return ActionResult.page(requestLogVOList, paginationVO);
default:
return ActionResult.fail(MsgCode.FA012.get());
}
}
/**
* 获取系统日志信息
*
* @param id 主键值
* @return
*/
@Operation(summary = "获取系统日志信息")
@Parameters({
@Parameter(name = "category", description = "分类", required = true)
})
@SaCheckPermission("system.log")
@GetMapping("/{id}")
public ActionResult<LogInfoVO> getInfoList(@PathVariable("id") String id) {
LogEntity entity = logService.getInfo(id);
if (entity == null) {
return ActionResult.fail(MsgCode.FA001.get());
}
LogInfoVO vo = JsonUtil.getJsonToBean(entity, LogInfoVO.class);
return ActionResult.success(vo);
}
/**
* 批量删除系统日志
*
* @param logDelForm 批量删除日志模型
* @return
*/
@Operation(summary = "批量删除系统日志")
@Parameters({
@Parameter(name = "logDelForm", description = "批量删除日志模型", required = true)
})
@SaCheckPermission("system.log")
@DeleteMapping
public ActionResult delete(@RequestBody LogDelForm logDelForm) {
boolean flag = logService.delete(logDelForm.getIds());
if (!flag) {
return ActionResult.fail(MsgCode.FA003.get());
}
return ActionResult.success(MsgCode.SU003.get());
}
/**
* 一键清空操作日志
*
* @param type 分类
* @return
*/
@Operation(summary = "一键清空操作日志")
@Parameters({
@Parameter(name = "type", description = "分类", required = true)
})
@SaCheckPermission("system.log")
@DeleteMapping("/{type}")
public ActionResult deleteHandelLog(@PathVariable("type") String type) {
logService.deleteHandleLog(type, null);
return ActionResult.success(MsgCode.SU005.get());
}
/**
* 一键清空登陆日志
*
* @return
*/
@Operation(summary = "一键清空登陆日志")
@SaCheckPermission("system.log")
@DeleteMapping("/deleteLoginLog")
public ActionResult deleteLoginLog() {
logService.deleteHandleLog("1", 1);
return ActionResult.success(MsgCode.SU005.get());
}
/**
* 获取菜单名
*
* @return
*/
@Operation(summary = "获取菜单名")
@SaCheckPermission("system.log")
@GetMapping("/ModuleName")
public ActionResult<List<Map<String, String>>> moduleName() {
List<Map<String, String>> list = new ArrayList<> (16);
Set<String> set = logService.queryList();
for (String moduleName : set) {
Map<String, String> map = new HashedMap<>(1);
map.put("moduleName", moduleName);
list.add(map);
}
return ActionResult.success(list);
}
}

View File

@@ -0,0 +1,138 @@
package com.yunzhupaas.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yunzhupaas.base.entity.SuperExtendEntity;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 系统日志
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2023/09/27
*/
@Data
@TableName("base_sys_log")
public class LogEntity extends SuperExtendEntity.SuperExtendDescriptionEntity<String> implements Serializable {
/**
* 用户主键
*/
@TableField("F_USER_ID")
private String userId;
/**
* 用户主键
*/
@TableField("F_USER_NAME")
private String userName;
/**
* 日志类型
*/
@TableField("F_TYPE")
private Integer type;
/**
* 日志级别
*/
@TableField("F_LEVEL")
private Integer levels;
/**
* IP地址
*/
@TableField("F_IP_ADDRESS")
private String ipAddress;
/**
* IP所在城市
*/
@TableField("F_IP_ADDRESS_NAME")
private String ipAddressName;
/**
* 请求地址
*/
@TableField("F_REQUEST_URL")
private String requestUrl;
/**
* 请求方法
*/
@TableField("F_REQUEST_METHOD")
private String requestMethod;
/**
* 请求耗时
*/
@TableField("F_REQUEST_DURATION")
private Integer requestDuration;
/**
* 日志内容
*/
@TableField("F_JSON")
private String jsons;
/**
* 平台设备
*/
@TableField("F_PLAT_FORM")
private String platForm;
/**
* 功能主键
*/
@TableField("F_MODULE_ID")
private String moduleId;
/**
* 功能名称
*/
@TableField("F_MODULE_NAME")
private String moduleName;
/**
* 对象Id
*/
@TableField("F_OBJECT_ID")
private String objectId;
/**
* 浏览器
*/
@TableField("f_browser")
private String browser;
/**
* 请求参数
*/
@TableField("f_request_param")
private String requestParam;
/**
* 请求方法
*/
@TableField("f_request_target")
private String requestTarget;
/**
* 是否登录成功标志
*/
@TableField("f_login_mark")
private Integer loginMark;
/**
* 登录类型
*/
@TableField("f_login_type")
private Integer loginType;
}

View File

@@ -0,0 +1,77 @@
package com.yunzhupaas.enums;
/**
* 日志等级
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024-09-26 上午9:18
*/
public enum LogLevelEnum {
/**
* 错误
*/
Error(0,"错误"),
/**
* 成功
*/
Success(1,"成功"),
/**
* 警告
*/
Warning(2,"警告");
private int code;
private String message;
LogLevelEnum(int code, String message){
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/**
* 根据状态code获取枚举名称
* @return
*/
public static String getMessageByCode(Integer code) {
for (LogLevelEnum status : LogLevelEnum.values()) {
if (status.getCode().equals(code)) {
return status.message;
}
}
return null;
}
/**
* 根据状态code获取枚举值
* @return
*/
public static LogLevelEnum getByCode(Integer code) {
for (LogLevelEnum status : LogLevelEnum.values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
}

View File

@@ -0,0 +1,85 @@
package com.yunzhupaas.enums;
/**
* 日志分类
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024-09-26 上午9:18
*/
public enum LogSortEnum {
/**
* 登录
*/
Login(1, "登录"),
/**
* 访问
*/
Visit(2, "访问"),
/**
* 操作
*/
Operate(3, "操作"),
/**
* 异常
*/
Exception(4, "异常"),
/**
* 请求
*/
Request(5, "请求");
private int code;
private String message;
LogSortEnum(int code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/**
* 根据状态code获取枚举名称
*
* @return
*/
public static String getMessageByCode(Integer code) {
for (LogSortEnum status : LogSortEnum.values()) {
if (status.getCode().equals(code)) {
return status.message;
}
}
return null;
}
/**
* 根据状态code获取枚举值
*
* @return
*/
public static LogSortEnum getByCode(Integer code) {
for (LogSortEnum status : LogSortEnum.values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
}

View File

@@ -0,0 +1,321 @@
package com.yunzhupaas.exception;
import cn.dev33.satoken.exception.SameTokenInvalidException;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.alibaba.fastjson.JSON;
import com.yunzhupaas.base.ActionResult;
import com.yunzhupaas.base.ActionResultCode;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.config.ConfigValueUtil;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.database.util.NotTenantPluginHolder;
import com.yunzhupaas.database.util.TenantDataSourceUtil;
import com.yunzhupaas.entity.LogEntity;
import com.yunzhupaas.service.LogService;
import com.yunzhupaas.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:10
*/
@Slf4j
@Controller
@ControllerAdvice
public class ResultException extends BasicErrorController {
@Autowired
private LogService logService;
@Autowired
private ConfigValueUtil configValueUtil;
public ResultException(){
super(new DefaultErrorAttributes(), new ErrorProperties());
}
@ResponseBody
@ExceptionHandler(value = LoginException.class)
public ActionResult loginException(LoginException e) {
ActionResult result = ActionResult.fail(ActionResultCode.Fail.getCode(), e.getMessage());
result.setData(e.getData());
return result;
}
/**
* 简单异常处理
*/
@ResponseBody
@ExceptionHandler(value = {ImportException.class, DataException.class, EncryptFailException.class})
public ActionResult simpleException(Exception e) {
ActionResult result = ActionResult.fail(ActionResultCode.Fail.getCode(), e.getMessage());
return result;
}
// @ResponseBody
// @ExceptionHandler(value = FileNotException.class)
// public ActionResult loginException(FileNotException e) {
// ActionResult result = ActionResult.fail(ActionResultCode.Fail.getCode(), "文件不存在");
// return result;
// }
/**
* 租户数据库异常
*
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = {TenantDatabaseException.class, TenantInvalidException.class})
public ActionResult<String> tenantDatabaseException(TenantInvalidException e) {
String msg;
if(e.getMessage() == null){
if (configValueUtil.getMultiTenancyUrl().contains("https")) {
// https 官网提示
msg = MsgCode.LOG109.get();
} else {
msg = MsgCode.LOG110.get();
}
}else{
msg = e.getMessage();
}
if(e.getLogMsg() != null){
log.error(e.getLogMsg());
}
return ActionResult.fail(ActionResultCode.Fail.getCode(), msg);
}
///
// @ResponseBody
// @ExceptionHandler(value = SQLSyntaxErrorException.class)
// public ActionResult sqlException(SQLSyntaxErrorException e) {
// ActionResult result;
// log.error(e.getMessage());
// e.printStackTrace();
// if (e.getMessage().contains("Unknown database")) {
// printLog(e, "请求失败");
// result = ActionResult.fail(ActionResultCode.Fail.getCode(), "请求失败");
// } else {
// printLog(e, "数据库异常");
// result = ActionResult.fail(ActionResultCode.Fail.getCode(), "数据库异常");
// }
// return result;
// }
//
// @ResponseBody
// @ExceptionHandler(value = SQLServerException.class)
// public ActionResult sqlServerException(SQLServerException e) {
// ActionResult result;
// printLog(e, "系统异常");
// if (e.getMessage().contains("将截断字符串")) {
// printLog(e, "某个字段字符长度超过限制,请检查。");
// result = ActionResult.fail(ActionResultCode.Fail.getCode(), "某个字段字符长度超过限制,请检查。");
// } else {
// log.error(e.getMessage());
// printLog(e, "数据库异常,请检查。");
// result = ActionResult.fail(ActionResultCode.Fail.getCode(), "数据库异常,请检查。");
// }
// return result;
// }
@ResponseBody
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public ActionResult methodArgumentNotValidException(MethodArgumentNotValidException e) {
Map<String, String> map = new HashMap<>(16);
List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
for (int i = 0; i < allErrors.size(); i++) {
String s = allErrors.get(i).getCodes()[0];
//用分割的方法得到字段名
String[] parts = s.split("\\.");
String part1 = parts[parts.length - 1];
map.put(part1, allErrors.get(i).getDefaultMessage());
}
String json = JSON.toJSONString(map);
ActionResult result = ActionResult.fail(ActionResultCode.ValidateError.getCode(), json);
printLog(e, "字段验证异常", 4);
return result;
}
@ResponseBody
@ExceptionHandler(value = WorkFlowException.class)
public ActionResult workFlowException(WorkFlowException e) {
if (e.getCode() == 200) {
Map<String, Object> map = JsonUtil.stringToMap(e.getMessage());
return ActionResult.success(map);
} else {
if(e.getSuppressed()!=null) {
printLog(e, "系统异常", 4);
}
return ActionResult.fail(e.getMessage());
}
}
@ResponseBody
@ExceptionHandler(value = WxErrorException.class)
public ActionResult wxErrorException(WxErrorException e) {
return ActionResult.fail(e.getError().getErrorCode(), MsgCode.AD103.get());
}
@ResponseBody
@ExceptionHandler(value = ServletException.class)
public void exception(ServletException e) throws Exception {
log.error("系统异常:" + e.getMessage(), e);
printLog(e, "系统异常", 4);
throw new Exception();
}
@ResponseBody
@ExceptionHandler(value = Exception.class)
public ActionResult exception(Exception e) {
log.error("系统异常:" + e.getMessage(), e);
printLog(e, "系统异常", 4);
if(e instanceof ConnectDatabaseException || e.getCause() instanceof ConnectDatabaseException){
Throwable t = e;
if(e.getCause() instanceof ConnectDatabaseException){
t = e.getCause();
}
return ActionResult.fail(ActionResultCode.Fail.getCode(), t.getMessage());
}
return ActionResult.fail(ActionResultCode.Fail.getCode(), MsgCode.AD102.get());
}
/**
* 权限码异常
*/
@ResponseBody
@ExceptionHandler(NotPermissionException.class)
public ActionResult<Void> handleNotPermissionException(NotPermissionException e) {
return ActionResult.fail(ActionResultCode.Fail.getCode(), MsgCode.AD104.get());
}
/**
* 角色权限异常
*/
@ResponseBody
@ExceptionHandler(NotRoleException.class)
public ActionResult<Void> handleNotRoleException(NotRoleException e) {
return ActionResult.fail(ActionResultCode.ValidateError.getCode(), MsgCode.AD104.get());
}
/**
* 认证失败
*/
@ResponseBody
@ExceptionHandler(NotLoginException.class)
public ActionResult<Void> handleNotLoginException(NotLoginException e) {
return ActionResult.fail(ActionResultCode.SessionOverdue.getCode(), MsgCode.AD105.get());
}
/**
* 无效认证
*/
@ResponseBody
@ExceptionHandler(SameTokenInvalidException.class)
public ActionResult<Void> handleIdTokenInvalidException(SameTokenInvalidException e) {
return ActionResult.fail(ActionResultCode.SessionOverdue.getCode(), MsgCode.AD106.get());
}
private void printLog(Exception e, String msg, int type) {
try {
UserInfo userInfo = UserProvider.getUser();
if (userInfo.getId() == null) {
e.printStackTrace();
return;
}
//接口错误将不会进入数据库切源拦截器需要手动设置
if (configValueUtil.isMultiTenancy() && TenantHolder.getDatasourceId() == null) {
try {
TenantDataSourceUtil.switchTenant(userInfo.getTenantId());
} catch (Exception ee){
e.printStackTrace();
return;
}
}
LogEntity entity = new LogEntity();
entity.setId(RandomUtil.uuId());
entity.setUserId(userInfo.getUserId());
entity.setUserName(userInfo.getUserName() + "/" + userInfo.getUserAccount());
// if (!ServletUtil.getIsMobileDevice()) {
entity.setDescription(msg);
// }
StringBuilder sb = new StringBuilder();
sb.append(e.toString() + "\n");
StackTraceElement[] stackArray = e.getStackTrace();
for (int i = 0; i < stackArray.length; i++) {
StackTraceElement element = stackArray[i];
sb.append(element.toString() + "\n");
}
entity.setJsons(sb.toString());
entity.setRequestUrl(ServletUtil.getRequest().getServletPath());
entity.setRequestMethod(ServletUtil.getRequest().getMethod());
entity.setType(type);
entity.setUserId(userInfo.getUserId());
// ip
String ipAddr = IpUtil.getIpAddr();
entity.setIpAddress(ipAddr);
entity.setIpAddressName(IpUtil.getIpCity(ipAddr));
entity.setCreatorTime(new Date());
UserAgent userAgent = UserAgentUtil.parse(ServletUtil.getUserAgent());
if (userAgent != null) {
entity.setPlatForm(userAgent.getPlatform().getName() + " " + userAgent.getOsVersion());
entity.setBrowser(userAgent.getBrowser().getName() + " " + userAgent.getVersion());
}
if (configValueUtil.isMultiTenancy() && StringUtil.isEmpty(TenantHolder.getDatasourceId())) {
log.error("请求异常, 无登陆租户:" + ReflectionUtil.toString(entity), e);
} else {
logService.save(entity);
}
}catch (Exception g){
log.error(g.getMessage());
}finally {
UserProvider.clearLocalUser();
TenantProvider.clearBaseSystemIfo();
TenantDataSourceUtil.clearLocalTenantInfo();
NotTenantPluginHolder.clearNotSwitchFlag();
}
}
/**
* 覆盖默认的JSON响应
*/
@Override
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = getStatus(request);
if (status == HttpStatus.NOT_FOUND) {
return new ResponseEntity<>(status);
}
return super.error(request);
}
}

View File

@@ -0,0 +1,19 @@
package com.yunzhupaas.mapper;
import com.yunzhupaas.base.mapper.SuperMapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yunzhupaas.entity.LogEntity;
/**
* 系统日志
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2023/09/27
*/
public interface LogMapper extends SuperMapper<LogEntity> {
}

View File

@@ -0,0 +1,35 @@
package com.yunzhupaas.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:10
*/
@Data
public class ErrorLogVO {
@Schema(description = "创建用户")
private String userName;
@Schema(description = "创建时间",example = "1")
private Long creatorTime;
@Schema(description = "IP")
private String ipAddress;
private Long requestDuration;
@Schema(description = "地点")
private String ipAddressName;
@Schema(description = "id")
private String id;
@Schema(description = "请求设备")
private String platForm;
@Schema(description = "浏览器")
private String browser;
@Schema(description = "请求类型")
private String requestMethod;
@Schema(description = "请求地址")
private String requestUrl;
}

View File

@@ -0,0 +1,66 @@
package com.yunzhupaas.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
/**
* 操作日志模型
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:10
*/
@Data
public class HandleLogVO implements Serializable {
/**
* id
*/
public String id;
/**
* 请求时间
*/
public Long creatorTime;
/**
* 请求用户名
*/
public String userName;
/**
* 请求IP
*/
public String ipAddress;
/**
* 请求设备
*/
public String platForm;
/**
* 操作模块
*/
public String moduleName;
/**
* 操作类型
*/
public String requestMethod;
/**
* 请求耗时
*/
public int requestDuration;
@Schema(description = "地点")
private String ipAddressName;
@Schema(description = "浏览器")
private String browser;
@Schema(description = "请求地址")
private String requestUrl;
}

View File

@@ -0,0 +1,19 @@
package com.yunzhupaas.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:10
*/
@Data
public class LogDelForm {
@Schema(description = "id集合")
private String[] ids;
}

View File

@@ -0,0 +1,55 @@
package com.yunzhupaas.model;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:10
*/
@Data
public class LogInfoVO {
@Schema(description = "主键")
private String id;
@Schema(description = "用户主键")
private String userId;
@Schema(description = "用户名称")
private String userName;
@Schema(description = "日志类型")
private Integer type;
@Schema(description = "日志级别")
private Integer levels;
@Schema(description = "IP地址")
private String ipAddress;
@Schema(description = "IP所在城市")
private String ipAddressName;
@Schema(description = "请求地址")
private String requestUrl;
@Schema(description = "请求方法")
private String requestMethod;
@Schema(description = "请求耗时")
private Integer requestDuration;
@Schema(description = "日志内容")
private String jsons;
@Schema(description = "平台设备")
private String platForm;
@Schema(description = "功能主键")
private String moduleId;
@Schema(description = "功能名称")
private String moduleName;
@Schema(description = "浏览器")
private String browser;
@Schema(description = "请求参数")
private String requestParam;
@Schema(description = "请求方法")
private String requestTarget;
@Schema(description = "请求时间")
public Long creatorTime;
}

View File

@@ -0,0 +1,41 @@
package com.yunzhupaas.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:10
*/
@Data
public class LoginLogVO {
@Schema(description = "id")
private String id;
@Schema(description = "创建时间",example = "1")
private Long creatorTime;
@Schema(description = "登陆用户")
private String userName;
@Schema(description = "登陆IP")
private String ipAddress;
@Schema(description = "登陆平台")
private String platForm;
@Schema(description = "登陆日志摘要")
private String abstracts;
@Schema(description = "地点")
private String ipAddressName;
@Schema(description = "浏览器")
private String browser;
@Schema(description = "是否登录成功标志")
private Integer loginMark;
@Schema(description = "登录类型")
private Integer loginType;
/**
* 请求耗时
*/
public int requestDuration;
}

View File

@@ -0,0 +1,31 @@
package com.yunzhupaas.model;
import io.swagger.v3.oas.annotations.media.Schema;
import com.yunzhupaas.base.PaginationTime;
import lombok.Data;
/**
* 日志分页参数
*
* @author :云筑产品开发平台组
* @version: V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2022/3/18 9:50
*/
@Data
public class PaginationLogModel extends PaginationTime {
/**
* 操作类型
*/
private String requestMethod;
/**
* 类型
*/
private int category;
@Schema(description = "是否登录成功标志")
private Integer loginMark;
@Schema(description = "登录类型")
private Integer loginType;
}

View File

@@ -0,0 +1,36 @@
package com.yunzhupaas.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:10
*/
@Data
public class RequestLogVO {
@Schema(description = "id")
private String id;
@Schema(description = "请求时间",example = "1")
private Long creatorTime;
@Schema(description = "请求用户名")
private String userName;
@Schema(description = "请求IP")
private String ipAddress;
@Schema(description = "请求设备")
private String platForm;
@Schema(description = "请求地址")
private String requestUrl;
@Schema(description = "请求类型")
private String requestMethod;
@Schema(description = "请求耗时",example = "1")
private Long requestDuration;
@Schema(description = "地点")
private String ipAddressName;
@Schema(description = "浏览器")
private String browser;
}

View File

@@ -0,0 +1,39 @@
package com.yunzhupaas.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/12 15:31
*/
@Data
public class UserLogVO {
@Schema(description = "登录类型")
private Integer loginType;
@Schema(description = "登录时间")
private Long creatorTime;
@Schema(description = "登录用户")
private String userName;
@Schema(description = "登录IP")
private String ipAddress;
@Schema(description = "IP所在城市")
private String ipAddressName;
@Schema(description = "浏览器")
private String browser;
@Schema(description = "平台设备")
private String platForm;
@Schema(description = "请求耗时")
private Integer requestDuration;
@Schema(description = "是否登录成功标志")
private Integer loginMark;
@Schema(description = "说明")
private String abstracts;
@Schema(description = "主键")
private String id;
}

View File

@@ -0,0 +1,83 @@
package com.yunzhupaas.service;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.base.service.SuperService;
import com.yunzhupaas.entity.LogEntity;
import com.yunzhupaas.model.PaginationLogModel;
import java.util.List;
import java.util.Set;
/**
* 系统日志
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2023/09/27
*/
public interface LogService extends SuperService<LogEntity> {
/**
* 列表
*
* @param category 日志分类
* @param paginationTime 分页条件
* @return
*/
List<LogEntity> getList(int category, PaginationLogModel paginationTime);
/**
* 信息
*
* @param id 主键值
* @return
*/
LogEntity getInfo(String id);
/**
* 删除
* @param ids
* @return
*/
boolean delete(String[] ids);
/**
* 写入日志
*
* @param userId 用户Id
* @param userName 用户名称
* @param abstracts 摘要
*/
void writeLogAsync(String userId, String userName, String abstracts, long requestDuration);
/**
* 写入日志
*
* @param userId 用户Id
* @param userName 用户名称
* @param abstracts 摘要
*/
void writeLogAsync(String userId, String userName, String abstracts, UserInfo userInfo, int loginMark, Integer loginType, long requestDuration);
/**
* 请求日志
*
* @param logEntity 实体对象
*/
void writeLogAsync(LogEntity logEntity);
/**
* 请求日志
*/
void deleteHandleLog(String type, Integer userOnline);
/**
* 获取操作模块名
*
* @return
*/
Set<String> queryList();
}

View File

@@ -0,0 +1,194 @@
package com.yunzhupaas.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.common.collect.Lists;
import com.yunzhupaas.base.service.SuperServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.config.ConfigValueUtil;
import com.yunzhupaas.database.util.TenantDataSourceUtil;
import com.yunzhupaas.entity.LogEntity;
import com.yunzhupaas.enums.LogSortEnum;
import com.yunzhupaas.exception.LoginException;
import com.yunzhupaas.mapper.LogMapper;
import com.yunzhupaas.model.PaginationLogModel;
import com.yunzhupaas.service.LogService;
import com.yunzhupaas.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* 系统日志
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2023/09/27
*/
@Service
public class LogServiceImpl extends SuperServiceImpl<LogMapper, LogEntity> implements LogService {
@Autowired
private ConfigValueUtil configValueUtil;
@Override
public List<LogEntity> getList(int category, PaginationLogModel paginationTime) {
UserInfo userInfo = UserProvider.getUser();
QueryWrapper<LogEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(LogEntity::getType, category);
//用户Id
String userId = userInfo.getUserId();
String userAccount = userInfo.getUserAccount();
if (!StringUtil.isEmpty(userId) && !StringUtil.isEmpty(userAccount)) {
if (!userInfo.getIsAdministrator()){
queryWrapper.lambda().and(
t -> t.eq(LogEntity::getUserId, userId)
.or().eq(LogEntity::getUserId, userAccount)
);
}
}
//日期范围近7天、近1月、近3月、自定义
if (!ObjectUtil.isEmpty(paginationTime.getStartTime()) && !ObjectUtil.isEmpty(paginationTime.getEndTime())) {
queryWrapper.lambda().between(LogEntity::getCreatorTime, new Date(paginationTime.getStartTime()), new Date(paginationTime.getEndTime()));
}
//关键字用户、IP地址、功能名称
String keyWord = paginationTime.getKeyword();
if (!StringUtil.isEmpty(keyWord)) {
if (category == 1) {
queryWrapper.lambda().and(
t -> t.like(LogEntity::getUserName, keyWord)
.or().like(LogEntity::getIpAddress, keyWord)
);
} else if (category == 5 || category == 4){
queryWrapper.lambda().and(
t -> t.like(LogEntity::getUserName, keyWord)
.or().like(LogEntity::getIpAddress, keyWord)
.or().like(LogEntity::getRequestUrl, keyWord)
);
} else if (category == 3){
queryWrapper.lambda().and(
t -> t.like(LogEntity::getUserName, keyWord)
.or().like(LogEntity::getIpAddress, keyWord)
.or().like(LogEntity::getRequestUrl, keyWord)
.or().like(LogEntity::getModuleName, keyWord)
);
}
}
// 请求方式
if (StringUtil.isNotEmpty(paginationTime.getRequestMethod())) {
queryWrapper.lambda().eq(LogEntity::getRequestMethod, paginationTime.getRequestMethod());
}
// 类型
if (paginationTime.getLoginType() != null) {
queryWrapper.lambda().eq(LogEntity::getLoginType, paginationTime.getLoginType());
}
// 状态
if (paginationTime.getLoginMark() != null) {
queryWrapper.lambda().eq(LogEntity::getLoginMark, paginationTime.getLoginMark());
}
//排序
queryWrapper.lambda().orderByDesc(LogEntity::getCreatorTime);
Page<LogEntity> page = new Page<>(paginationTime.getCurrentPage(), paginationTime.getPageSize());
IPage<LogEntity> userPage = this.page(page, queryWrapper);
return paginationTime.setData(userPage.getRecords(), page.getTotal());
}
@Override
public LogEntity getInfo(String id) {
QueryWrapper<LogEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(LogEntity::getId, id);
return this.getOne(queryWrapper);
}
@Override
@DSTransactional
public boolean delete(String[] ids) {
if (ids.length > 0) {
QueryWrapper<LogEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().in(LogEntity::getId, ids);
return this.remove(queryWrapper);
}
return false;
}
@Override
public void writeLogAsync(String userId, String userName, String abstracts, long requestDuration) {
writeLogAsync(userId, userName, abstracts, null, 1, null, requestDuration);
}
@Override
public void writeLogAsync(String userId, String userName, String abstracts, UserInfo userInfo, int loginMark, Integer loginType, long requestDuration) {
LogEntity entity = new LogEntity();
if (configValueUtil.isMultiTenancy() && userInfo != null) {
try {
TenantDataSourceUtil.switchTenant(userInfo.getTenantId());
} catch (Exception e) {
return;
}
}
String ipAddr = IpUtil.getIpAddr();
entity.setIpAddress(ipAddr);
entity.setIpAddressName(IpUtil.getIpCity(ipAddr));
// 请求设备
UserAgent userAgent = UserAgentUtil.parse(ServletUtil.getUserAgent());
if (userAgent != null) {
entity.setPlatForm(userAgent.getPlatform().getName() + " " + userAgent.getOsVersion());
entity.setBrowser(userAgent.getBrowser().getName() + " " + userAgent.getVersion());
}
if (loginType != null) {
entity.setLoginType(1);
} else {
entity.setLoginType(0);
}
entity.setLoginMark(loginMark);
entity.setRequestDuration(Integer.parseInt(String.valueOf(requestDuration)));
entity.setId(RandomUtil.uuId());
entity.setUserId(userId);
entity.setUserName(userName);
entity.setDescription(abstracts);
entity.setRequestUrl(ServletUtil.getServletPath());
entity.setRequestMethod(ServletUtil.getRequest().getMethod());
entity.setType(LogSortEnum.Login.getCode());
this.save(entity);
}
@Override
public void writeLogAsync(LogEntity entity) {
entity.setId(RandomUtil.uuId());
this.save(entity);
}
@Override
public void deleteHandleLog(String type, Integer userOnline) {
QueryWrapper<LogEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(LogEntity::getType, Integer.valueOf(type));
if (ObjectUtil.equals(userOnline, 1)) {
queryWrapper.lambda().eq(LogEntity::getCreatorUserId, UserProvider.getLoginUserId());
}
queryWrapper.lambda().select(LogEntity::getId);
List<String> ids = this.list(queryWrapper).stream().map(LogEntity::getId).collect(Collectors.toList());
List<List<String>> lists = Lists.partition(ids, 1000);
for (List<String> list : lists) {
QueryWrapper<LogEntity> deleteWrapper = new QueryWrapper<>();
deleteWrapper.lambda().in(LogEntity::getId,list);
this.remove(deleteWrapper);
}
}
@Override
public Set<String> queryList() {
QueryWrapper<LogEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(LogEntity::getType, 3);
return this.list(queryWrapper).size() > 0 ? this.list(queryWrapper).stream().map(t -> t.getModuleName()).collect(Collectors.toSet()) : new HashSet<>(16);
}
}

View File

@@ -0,0 +1,79 @@
package com.yunzhupaas.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.exception.DataException;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:10
*/
public class JsonUtilEx {
/**
* 功能描述把java对象转换成JSON数据,时间格式化
* @param object java对象
* @return JSON数据
*/
public static String getObjectToStringDateFormat(Object object,String dateFormat) {
return JSON.toJSONStringWithDateFormat(object, dateFormat,SerializerFeature.WriteMapNullValue);
}
// /**
// * 功能描述把JSON数据转换成指定的java对象列表
// * @param jsonData JSON数据
// * @param clazz 指定的java对象
// * @return List<T>
// */
// public static <T> List<T> getJsonToListStringDateFormat(String jsonData, Class<T> clazz,String dateFormat) {
// JSONArray jsonArray=JSONUtil.getJsonToJsonArray(jsonData);
// JSONArray newJsonArray=JSONUtil.getJsonToJsonArray(jsonData);
// for (int i = 0; i < jsonArray.size(); i++) {
// JSONObject jsonObject = jsonArray.getJSONObject(i);
// newJsonArray.add(JSON.toJSONStringWithDateFormat(jsonObject, dateFormat,SerializerFeature.WriteMapNullValue));
// }
// jsonData=JSONUtil.getObjectToString(newJsonArray);
// return JSON.parseArray(jsonData, clazz);
// }
//
// public static void main(String[] args) {
// Date date=new Date();
// String obk="[" +
// "{\"date\":\""+date+"\"},{\"date\":\"1603165505\"}" +
// "]";
// List<String> list1= getJsonToList(obk,String.class);
// List<String> list11= getJsonToListStringDateFormat(obk,String.class,"yyyy-MM-dd");
// System.out.println("aaa");
// }
/**
* 功能描述把java对象转换成JSON数据
* @param object java对象
* @return JSON数据
*/
public static String getObjectToString(Object object) {
return JSON.toJSONString(object, SerializerFeature.WriteMapNullValue);
}
/**
* 功能描述把JSON数据转换成指定的java对象
* @param dto dto对象
* @param clazz 指定的java对象
* @return 指定的java对象
*/
public static <T> T getJsonToBeanEx(Object dto, Class<T> clazz) throws DataException {
if(dto==null){
throw new DataException(MsgCode.FA001.get());
}
return JSON.parseObject(getObjectToString(dto), clazz);
}
}