diff --git a/pom.xml b/pom.xml index a5c7a2dcbaad008bcf9053585973f3cba77be715..6e2715f84244f659760d3606e6c4314c15937ebf 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,11 @@ spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-aop + + org.projectlombok lombok diff --git a/src/main/java/com/easysoftware/aop/ManagementLogAOP.java b/src/main/java/com/easysoftware/aop/ManagementLogAOP.java new file mode 100644 index 0000000000000000000000000000000000000000..bdc3545bcd4145fd9d31ec981dc58455c5856cbc --- /dev/null +++ b/src/main/java/com/easysoftware/aop/ManagementLogAOP.java @@ -0,0 +1,36 @@ +package com.easysoftware.aop; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.easysoftware.utils.LogUtil; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Aspect +@Component +public class ManagementLogAOP { + + @Autowired + private HttpServletRequest request; + + @Autowired + private HttpServletResponse response; + + //定义切点 + @Pointcut("execution(* com.easysoftware.adapter.*.*(..))") + public void pointcut() { + } + + @AfterReturning(pointcut = "pointcut()", returning = "returnObject") + public void afterReturning(JoinPoint joinPoint, Object returnObject) { + LogUtil.managementOperate(joinPoint, request, response, returnObject); + } + +} + diff --git a/src/main/java/com/easysoftware/application/GlobalExceptionHandler.java b/src/main/java/com/easysoftware/application/GlobalExceptionHandler.java index 5e8f891521623ea7a29c09cba315d41e042829dd..cc59104cfd0a7755a2dfc50011d8ade5dd1fa0c0 100644 --- a/src/main/java/com/easysoftware/application/GlobalExceptionHandler.java +++ b/src/main/java/com/easysoftware/application/GlobalExceptionHandler.java @@ -1,46 +1,28 @@ package com.easysoftware.application; -import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.util.StringUtils; -import org.springframework.validation.BindException; -import org.springframework.validation.BindingResult; -import org.springframework.validation.FieldError; -import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.MissingServletRequestParameterException; -import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; -import com.easysoftware.domain.common.exception.ParamErrorException; -import com.easysoftware.domain.common.utils.HttpResult; - -import jakarta.validation.ConstraintViolationException; -import lombok.extern.slf4j.Slf4j; - -import java.util.List; +import com.easysoftware.result.MessageCode; +import com.easysoftware.result.Result; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; -@Slf4j @RestControllerAdvice() public class GlobalExceptionHandler { + private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); + @ExceptionHandler(MethodArgumentNotValidException.class) - public String handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { - BindingResult result = e.getBindingResult(); - if (!result.hasErrors()) { - return HttpResult.fail(HttpStatus.BAD_REQUEST.value(), "请求错误", null); - } - List errors = result.getAllErrors(); - // ViolationFieldError - for (ObjectError error : errors) { - log.error("未通过参数校验: {}", error.toString()); - } - return HttpResult.fail(HttpStatus.BAD_REQUEST.value(), "请求错误", null); + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseEntity exception(MethodArgumentNotValidException e) { + logger.error(MessageCode.EC0001.getMsgEn(), e); + MessageCode messageCode = MessageCode.msgCodeMap.get(e.getMessage()); + return Result.fail(HttpStatus.BAD_REQUEST, messageCode); } - - } diff --git a/src/main/java/com/easysoftware/result/MessageCode.java b/src/main/java/com/easysoftware/result/MessageCode.java new file mode 100644 index 0000000000000000000000000000000000000000..e8e54ef59ff96a503d4393a9106535ca7e47f2d3 --- /dev/null +++ b/src/main/java/com/easysoftware/result/MessageCode.java @@ -0,0 +1,52 @@ +/* This project is licensed under the Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + PURPOSE. + See the Mulan PSL v2 for more details. + Create: 2024 +*/ + +package com.easysoftware.result; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +public enum MessageCode { + // client exception + EC0001("EC0001", "Request Error", "请求异常"), + EC0005("EC0002", "Wrong parameter", "参数错误"), + EC0009("EC0003", "Unsupported community", "不支持该community"), + + // self service exception + ES0001("ES0001", "Internal Server Error", "服务异常"); + + + private final String code; + private final String msgEn; + private final String msgZh; + + MessageCode(String code, String msgEn, String msgZh) { + this.code = code; + this.msgEn = msgEn; + this.msgZh = msgZh; + } + + public String getCode() { + return code; + } + + public String getMsgEn() { + return msgEn; + } + + public String getMsgZh() { + return msgZh; + } + + public static final Map msgCodeMap = Arrays.stream(MessageCode.values()) + .collect(Collectors.toMap(MessageCode::getCode, e -> e)); +} diff --git a/src/main/java/com/easysoftware/result/Result.java b/src/main/java/com/easysoftware/result/Result.java new file mode 100644 index 0000000000000000000000000000000000000000..da02e6794263b0be60234308be5a559ab4f3ec42 --- /dev/null +++ b/src/main/java/com/easysoftware/result/Result.java @@ -0,0 +1,123 @@ +/* This project is licensed under the Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + PURPOSE. + See the Mulan PSL v2 for more details. + Create: 2024 +*/ + +package com.easysoftware.result; + +import java.util.HashMap; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import com.easysoftware.vo.ResultMsgVo; +import com.easysoftware.vo.ResultVo; + + +public class Result { + public static ResponseEntity success(HttpStatus status) { + ResultVo res = new ResultVo() + .setCode(status.value()) + .setMsg(status.getReasonPhrase()); + return new ResponseEntity<>(res, status); + } + + public static ResponseEntity success(HttpStatus status, MessageCode msgCode) { + ResultVo res = new ResultVo() + .setCode(status.value()) + .setMsg(new ResultMsgVo() + .setCode(msgCode.getCode()) + .setMsgEn(msgCode.getMsgEn()) + .setMsgZh(msgCode.getMsgZh())); + return new ResponseEntity<>(res, status); + } + + public static ResponseEntity success(HttpStatus status, Object data) { + ResultVo res = new ResultVo() + .setCode(status.value()) + .setMsg(status.getReasonPhrase()) + .setData(data); + return new ResponseEntity<>(res, status); + } + + public static ResponseEntity fail(HttpStatus status, MessageCode msgCode) { + ResultVo res = new ResultVo() + .setCode(status.value()) + .setMsg(new ResultMsgVo() + .setCode(msgCode.getCode()) + .setMsgEn(msgCode.getMsgEn()) + .setMsgZh(msgCode.getMsgZh())); + return new ResponseEntity<>(res, status); + } + + public static ResponseEntity fail(HttpStatus status, MessageCode msgCode, String error) { + ResultVo res = new ResultVo() + .setCode(status.value()) + .setMsg(new ResultMsgVo() + .setCode(msgCode.getCode()) + .setMsgEn(msgCode.getMsgEn()) + .setMsgZh(msgCode.getMsgZh())) + .setError(error); + return new ResponseEntity<>(res, status); + } + + public static ResponseEntity setResult(HttpStatus status, MessageCode msgCode) { + HashMap res = new HashMap<>(); + if (status.value() == 200) { + res.put("code", status.value()); + res.put("msg", status.getReasonPhrase()); + return new ResponseEntity<>(res, status); + } + + if (msgCode != null) { + HashMap msgMap = new HashMap<>(); + msgMap.put("code", msgCode.getCode()); + msgMap.put("message_en", msgCode.getMsgEn()); + msgMap.put("message_zh", msgCode.getMsgZh()); + res.put("msg", msgMap); + } + return new ResponseEntity<>(res, status); + } + + public static ResponseEntity setResult(HttpStatus status, MessageCode msgCode, String error) { + HashMap res = new HashMap<>(); + if (status.value() == 200) { + res.put("code", status.value()); + res.put("msg", status.getReasonPhrase()); + res.put("error", error); + return new ResponseEntity<>(res, status); + } + + if (msgCode != null) { + HashMap msgMap = new HashMap<>(); + msgMap.put("code", msgCode.getCode()); + msgMap.put("message_en", msgCode.getMsgEn()); + msgMap.put("message_zh", msgCode.getMsgZh()); + res.put("msg", msgMap); + res.put("error", error); + } + return new ResponseEntity<>(res, status); + } + +/* public static ResponseEntity paramError(HttpStatus status, MessageCode msgCode, String parameter) { + ResultEntity res = new ResultEntity() + .setCode(status.value()) + .setMsg(new ResultMsgEntity() + .setCode(msgCode.getCode()) + .setMsgEn(msgCode.getMsgEn()) + .setMsgZh(msgCode.getMsgZh())) + .setError(); + return new ResponseEntity<>(res, status); + }*/ + + /*public static ResponseEntity paramError(String parameter) { + String error = MessageCode.EC0004.getMsgEn() + ": " + parameter; + return fail(HttpStatus.BAD_REQUEST, MessageCode.EC0004, error); + }*/ +} diff --git a/src/main/java/com/easysoftware/utils/ClientUtil.java b/src/main/java/com/easysoftware/utils/ClientUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..aaa33fe46c5830d2b7fc794d2a94d148632859f4 --- /dev/null +++ b/src/main/java/com/easysoftware/utils/ClientUtil.java @@ -0,0 +1,67 @@ +package com.easysoftware.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class ClientUtil { + private static final Logger logger = LoggerFactory.getLogger(ClientUtil.class); + + public static String getClientIpAddress(HttpServletRequest request) { + // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址 + String headerName = "x-forwarded-for"; + String ip = request.getHeader(headerName); + if (null != ip && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) { + // 多次反向代理后会有多个IP值,第一个IP才是真实IP,它们按照英文逗号','分割 + if (ip.indexOf(",") != -1) { + ip = ip.split(",")[0]; + } + } + if (checkIp(ip)) { + headerName = "Proxy-Client-IP"; + ip = request.getHeader(headerName); + } + if (checkIp(ip)) { + headerName = "WL-Proxy-Client-IP"; + ip = request.getHeader(headerName); + } + if (checkIp(ip)) { + headerName = "HTTP_CLIENT_IP"; + ip = request.getHeader(headerName); + } + if (checkIp(ip)) { + headerName = "HTTP_X_FORWARDED_FOR"; + ip = request.getHeader(headerName); + } + if (checkIp(ip)) { + headerName = "X-Real-IP"; + ip = request.getHeader(headerName); + } + if (checkIp(ip)) { + headerName = "remote addr"; + ip = request.getRemoteAddr(); + // 127.0.0.1 ipv4, 0:0:0:0:0:0:0:1 ipv6 + if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) { + // 根据网卡取本机配置的IP + InetAddress inet = null; + try { + inet = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + logger.error("get local host error: " + e.getMessage()); + } + ip = inet.getHostAddress(); + } + } + return ip; + } + + private static boolean checkIp(String ip) { + if (null == ip || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + return true; + } + return false; + } +} diff --git a/src/main/java/com/easysoftware/utils/LogUtil.java b/src/main/java/com/easysoftware/utils/LogUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..ad3464c4cc609ade95023a0c48cf7ca943712857 --- /dev/null +++ b/src/main/java/com/easysoftware/utils/LogUtil.java @@ -0,0 +1,56 @@ +package com.easysoftware.utils; + +import com.easysoftware.vo.ManagementLog; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.aspectj.lang.JoinPoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.SneakyThrows; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; + +public class LogUtil { + private static final Logger logger = LoggerFactory.getLogger(LogUtil.class); + private static ObjectMapper objectMapper = new ObjectMapper(); + + @SneakyThrows + public static void managementOperate(JoinPoint joinPoint, HttpServletRequest request, HttpServletResponse response, + Object returnObject) { + ManagementLog log = new ManagementLog(); + log.setType("OmOperate"); + + LocalDateTime dateTime = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + log.setTime(dateTime.format(formatter)); + + log.setFunc(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(), + joinPoint.getSignature().getName())); + + log.setRequestUrl(request.getRequestURI()); + log.setMethod(request.getMethod()); + + log.setAppIP(ClientUtil.getClientIpAddress(request)); + + if (returnObject instanceof ResponseEntity) { + ResponseEntity responseEntity = (ResponseEntity) returnObject; + log.setStatus(responseEntity.getStatusCodeValue()); + if (responseEntity.getBody() instanceof HashMap) { + HashMap body = (HashMap) responseEntity.getBody(); + Object msg = (body.get("msg") == null) ? body.get("message") : body.get("msg"); + log.setMessage((msg == null) ? "" : msg.toString()); + } + } + log.setOperator(""); + + String jsonLog = objectMapper.writeValueAsString(log); + logger.info("operationLog:{}", jsonLog); + } + +} \ No newline at end of file diff --git a/src/main/java/com/easysoftware/vo/ManagementLog.java b/src/main/java/com/easysoftware/vo/ManagementLog.java new file mode 100644 index 0000000000000000000000000000000000000000..55a5543f2f5f485bc1f46f6802a02ab7c02b42ae --- /dev/null +++ b/src/main/java/com/easysoftware/vo/ManagementLog.java @@ -0,0 +1,24 @@ +package com.easysoftware.vo; + +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +@Getter +@Setter +public class ManagementLog implements Serializable { + private static final long serialVersionUID = 1L; + private String type; + private String time; + private String func; + private String eventDetails; + private String requestUrl; + private String method; + private String appIP; + private int status; + private String message; + private String ErrorLog; + private String operator; +} + diff --git a/src/main/java/com/easysoftware/vo/ResultMsgVo.java b/src/main/java/com/easysoftware/vo/ResultMsgVo.java new file mode 100644 index 0000000000000000000000000000000000000000..b7ae5ea087841fbd0b8684ca938ddbd786ed9c7c --- /dev/null +++ b/src/main/java/com/easysoftware/vo/ResultMsgVo.java @@ -0,0 +1,21 @@ +package com.easysoftware.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +@Data +@Accessors(chain = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResultMsgVo implements Serializable { + private String code; + + @JsonProperty("message_en") + private String msgEn; + + @JsonProperty("message_zh") + private String msgZh; +} diff --git a/src/main/java/com/easysoftware/vo/ResultVo.java b/src/main/java/com/easysoftware/vo/ResultVo.java new file mode 100644 index 0000000000000000000000000000000000000000..e7e736e9c17cd14fc632d2ef3216d453345ba6df --- /dev/null +++ b/src/main/java/com/easysoftware/vo/ResultVo.java @@ -0,0 +1,17 @@ +package com.easysoftware.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +@Data +@Accessors(chain = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResultVo implements Serializable { + private int code; + private Object msg; + private Object data; + private String error; +}