params = new HashMap<>();
+ while (parameters.hasMoreElements()) {
+ String parameter = parameters.nextElement();
+ String value = request.getParameter(parameter);
+ if (StringUtils.isNotBlank(value)) {
+ params.put(parameter, value);
+ }
+ }
+
+ return params;
+ }
+
+ public static String getDomain() {
+ HttpServletRequest request = getHttpServletRequest();
+ StringBuffer url = request.getRequestURL();
+ return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
+ }
+
+ public static String getOrigin() {
+ HttpServletRequest request = getHttpServletRequest();
+ return request.getHeader(HttpHeaders.ORIGIN);
+ }
+
+ public static String getLanguage() {
+ //默认语言
+ String defaultLanguage = "zh-CN";
+ //request
+ HttpServletRequest request = getHttpServletRequest();
+ if (request == null) {
+ return defaultLanguage;
+ }
+
+ //请求语言
+ defaultLanguage = request.getHeader(HttpHeaders.ACCEPT_LANGUAGE);
+
+ return defaultLanguage;
+ }
+
+ /**
+ * 获取客户端的唯一标识
+ *
+ * @return
+ */
+ public static String getClientCode() {
+ HttpServletRequest request = getHttpServletRequest();
+ if (request == null) {
+ return null;
+ }
+ String reqId = request.getHeader("User-Agent").toLowerCase();
+ String ipAddr = IpUtils.getIpAddr(request);
+ String date = DateUtils.format(new Date());
+ reqId = DigestUtils.md5DigestAsHex((ipAddr + date + reqId).getBytes());
+ return reqId;
+ }
+
+ public static String getRequestURI() {
+ HttpServletRequest request = getHttpServletRequest();
+ String url = request.getRequestURI();
+ return url;
+ }
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/IpUtils.java b/main/manager-api/src/main/java/xiaozhi/common/utils/IpUtils.java
new file mode 100644
index 00000000..307ad3b5
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/IpUtils.java
@@ -0,0 +1,47 @@
+package xiaozhi.common.utils;
+
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * IP地址
+ * Copyright (c) 人人开源 All rights reserved.
+ * Website: https://www.renren.io
+ */
+@Slf4j
+public class IpUtils {
+ /**
+ * 获取IP地址
+ *
+ * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
+ * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
+ */
+ public static String getIpAddr(HttpServletRequest request) {
+ String unknown = "unknown";
+ String ip = null;
+ try {
+ ip = request.getHeader("x-forwarded-for");
+ if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (StringUtils.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_CLIENT_IP");
+ }
+ if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+ }
+ if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ } catch (Exception e) {
+ log.error("IPUtils ERROR ", e);
+ }
+
+ return ip;
+ }
+
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/JsonUtils.java b/main/manager-api/src/main/java/xiaozhi/common/utils/JsonUtils.java
new file mode 100644
index 00000000..4a908245
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/JsonUtils.java
@@ -0,0 +1,68 @@
+package xiaozhi.common.utils;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JSON 工具类
+ * Copyright (c) 人人开源 All rights reserved.
+ * Website: https://www.renren.io
+ */
+public class JsonUtils {
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
+ public static String toJsonString(Object object) {
+ try {
+ return objectMapper.writeValueAsString(object);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static T parseObject(String text, Class clazz) {
+ if (StrUtil.isEmpty(text)) {
+ return null;
+ }
+ try {
+ return objectMapper.readValue(text, clazz);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static T parseObject(byte[] bytes, Class clazz) {
+ if (ArrayUtil.isEmpty(bytes)) {
+ return null;
+ }
+ try {
+ return objectMapper.readValue(bytes, clazz);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static T parseObject(String text, TypeReference typeReference) {
+ try {
+ return objectMapper.readValue(text, typeReference);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static List parseArray(String text, Class clazz) {
+ if (StrUtil.isEmpty(text)) {
+ return new ArrayList<>();
+ }
+ try {
+ return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/MessageUtils.java b/main/manager-api/src/main/java/xiaozhi/common/utils/MessageUtils.java
new file mode 100644
index 00000000..c346bf3d
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/MessageUtils.java
@@ -0,0 +1,25 @@
+package xiaozhi.common.utils;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.i18n.LocaleContextHolder;
+
+/**
+ * 国际化
+ * Copyright (c) 人人开源 All rights reserved.
+ * Website: https://www.renren.io
+ */
+public class MessageUtils {
+ private static MessageSource messageSource;
+
+ static {
+ messageSource = (MessageSource) SpringContextUtils.getBean("messageSource");
+ }
+
+ public static String getMessage(int code) {
+ return getMessage(code, new String[0]);
+ }
+
+ public static String getMessage(int code, String... params) {
+ return messageSource.getMessage(code + "", params, LocaleContextHolder.getLocale());
+ }
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/PropertiesUtils.java b/main/manager-api/src/main/java/xiaozhi/common/utils/PropertiesUtils.java
new file mode 100755
index 00000000..1064299b
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/PropertiesUtils.java
@@ -0,0 +1,11 @@
+package xiaozhi.common.utils;
+
+import org.springframework.stereotype.Component;
+
+/**
+ * 获取配置文件信息
+ * Copyright xin-nan.com
+ */
+@Component
+public class PropertiesUtils {
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/Result.java b/main/manager-api/src/main/java/xiaozhi/common/utils/Result.java
new file mode 100644
index 00000000..c21bdbf9
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/Result.java
@@ -0,0 +1,73 @@
+package xiaozhi.common.utils;
+
+import xiaozhi.common.exception.ErrorCode;
+import xiaozhi.common.page.PageData;
+import xiaozhi.modules.security.user.SecurityUser;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 响应数据
+ * Copyright (c) 人人开源 All rights reserved.
+ * Website: https://www.renren.io
+ */
+@Data
+@Schema(description = "响应")
+public class Result implements Serializable {
+
+ /**
+ * 编码:0表示成功,其他值表示失败
+ */
+ @Schema(description = "编码:0表示成功,其他值表示失败")
+ private int code = 0;
+ /**
+ * 消息内容
+ */
+ @Schema(description = "消息内容")
+ private String msg = "success";
+ /**
+ * 响应数据
+ */
+ @Schema(description = "响应数据")
+ private T data;
+
+ public Result ok(T data) {
+ this.setData(data);
+ return this;
+ }
+
+ public boolean success() {
+ return code == 0;
+ }
+
+ public Result error() {
+ this.code = ErrorCode.INTERNAL_SERVER_ERROR;
+ this.msg = MessageUtils.getMessage(this.code);
+ return this;
+ }
+
+ public Result error(int code) {
+ this.code = code;
+ this.msg = MessageUtils.getMessage(this.code);
+ return this;
+ }
+
+ public Result error(int code, String msg) {
+ this.code = code;
+ this.msg = msg;
+ return this;
+ }
+
+ public Result error(String msg) {
+ this.code = ErrorCode.INTERNAL_SERVER_ERROR;
+ this.msg = msg;
+ return this;
+ }
+
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/SpringContextUtils.java b/main/manager-api/src/main/java/xiaozhi/common/utils/SpringContextUtils.java
new file mode 100644
index 00000000..52aec0b7
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/SpringContextUtils.java
@@ -0,0 +1,45 @@
+package xiaozhi.common.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * Spring Context 工具类
+ */
+@Component
+public class SpringContextUtils implements ApplicationContextAware {
+ public static ApplicationContext applicationContext;
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext)
+ throws BeansException {
+ SpringContextUtils.applicationContext = applicationContext;
+ }
+
+ public static Object getBean(String name) {
+ return applicationContext.getBean(name);
+ }
+
+ public static T getBean(Class requiredType) {
+ return applicationContext.getBean(requiredType);
+ }
+
+ public static T getBean(String name, Class requiredType) {
+ return applicationContext.getBean(name, requiredType);
+ }
+
+ public static boolean containsBean(String name) {
+ return applicationContext.containsBean(name);
+ }
+
+ public static boolean isSingleton(String name) {
+ return applicationContext.isSingleton(name);
+ }
+
+ public static Class extends Object> getType(String name) {
+ return applicationContext.getType(name);
+ }
+
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/TreeNode.java b/main/manager-api/src/main/java/xiaozhi/common/utils/TreeNode.java
new file mode 100644
index 00000000..b60bc9cf
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/TreeNode.java
@@ -0,0 +1,30 @@
+package xiaozhi.common.utils;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 树节点,所有需要实现树节点的,都需要继承该类
+ * Copyright (c) 人人开源 All rights reserved.
+ * Website: https://www.renren.io
+ */
+@Data
+public class TreeNode implements Serializable {
+
+ /**
+ * 主键
+ */
+ private Long id;
+ /**
+ * 上级ID
+ */
+ private Long pid;
+ /**
+ * 子节点列表
+ */
+ private List children = new ArrayList<>();
+
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/TreeUtils.java b/main/manager-api/src/main/java/xiaozhi/common/utils/TreeUtils.java
new file mode 100644
index 00000000..766cb029
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/TreeUtils.java
@@ -0,0 +1,71 @@
+package xiaozhi.common.utils;
+
+import xiaozhi.common.validator.AssertUtils;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 树形结构工具类,如:菜单、部门等
+ * Copyright (c) 人人开源 All rights reserved.
+ * Website: https://www.renren.io
+ */
+public class TreeUtils {
+
+ /**
+ * 根据pid,构建树节点
+ */
+ public static List build(List treeNodes, Long pid) {
+ //pid不能为空
+ AssertUtils.isNull(pid, "pid");
+
+ List treeList = new ArrayList<>();
+ for (T treeNode : treeNodes) {
+ if (pid.equals(treeNode.getPid())) {
+ treeList.add(findChildren(treeNodes, treeNode));
+ }
+ }
+
+ return treeList;
+ }
+
+ /**
+ * 查找子节点
+ */
+ private static T findChildren(List treeNodes, T rootNode) {
+ for (T treeNode : treeNodes) {
+ if (rootNode.getId().equals(treeNode.getPid())) {
+ rootNode.getChildren().add(findChildren(treeNodes, treeNode));
+ }
+ }
+ return rootNode;
+ }
+
+ /**
+ * 构建树节点
+ */
+ public static List build(List treeNodes) {
+ List result = new ArrayList<>();
+
+ //list转map
+ Map nodeMap = new LinkedHashMap<>(treeNodes.size());
+ for (T treeNode : treeNodes) {
+ nodeMap.put(treeNode.getId(), treeNode);
+ }
+
+ for (T node : nodeMap.values()) {
+ T parent = nodeMap.get(node.getPid());
+ if (parent != null && !(node.getId().equals(parent.getId()))) {
+ parent.getChildren().add(node);
+ continue;
+ }
+
+ result.add(node);
+ }
+
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/common/validator/AssertUtils.java b/main/manager-api/src/main/java/xiaozhi/common/validator/AssertUtils.java
new file mode 100644
index 00000000..6a6b43e1
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/validator/AssertUtils.java
@@ -0,0 +1,89 @@
+package xiaozhi.common.validator;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ArrayUtil;
+import xiaozhi.common.exception.ErrorCode;
+import xiaozhi.common.exception.RenException;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 校验工具类
+ * Copyright (c) 人人开源 All rights reserved.
+ * Website: https://www.renren.io
+ */
+public class AssertUtils {
+
+ public static void isBlank(String str, String... params) {
+ isBlank(str, ErrorCode.NOT_NULL, params);
+ }
+
+ public static void isBlank(String str, Integer code, String... params) {
+ if (code == null) {
+ throw new RenException(ErrorCode.NOT_NULL, "code");
+ }
+
+ if (StringUtils.isBlank(str)) {
+ throw new RenException(code, params);
+ }
+ }
+
+ public static void isNull(Object object, String... params) {
+ isNull(object, ErrorCode.NOT_NULL, params);
+ }
+
+ public static void isNull(Object object, Integer code, String... params) {
+ if (code == null) {
+ throw new RenException(ErrorCode.NOT_NULL, "code");
+ }
+
+ if (object == null) {
+ throw new RenException(code, params);
+ }
+ }
+
+ public static void isArrayEmpty(Object[] array, String... params) {
+ isArrayEmpty(array, ErrorCode.NOT_NULL, params);
+ }
+
+ public static void isArrayEmpty(Object[] array, Integer code, String... params) {
+ if (code == null) {
+ throw new RenException(ErrorCode.NOT_NULL, "code");
+ }
+
+ if (ArrayUtil.isEmpty(array)) {
+ throw new RenException(code, params);
+ }
+ }
+
+ public static void isListEmpty(List> list, String... params) {
+ isListEmpty(list, ErrorCode.NOT_NULL, params);
+ }
+
+ public static void isListEmpty(List> list, Integer code, String... params) {
+ if (code == null) {
+ throw new RenException(ErrorCode.NOT_NULL, "code");
+ }
+
+ if (CollUtil.isEmpty(list)) {
+ throw new RenException(code, params);
+ }
+ }
+
+ public static void isMapEmpty(Map map, String... params) {
+ isMapEmpty(map, ErrorCode.NOT_NULL, params);
+ }
+
+ public static void isMapEmpty(Map map, Integer code, String... params) {
+ if (code == null) {
+ throw new RenException(ErrorCode.NOT_NULL, "code");
+ }
+
+ if (MapUtil.isEmpty(map)) {
+ throw new RenException(code, params);
+ }
+ }
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/common/validator/ValidatorUtils.java b/main/manager-api/src/main/java/xiaozhi/common/validator/ValidatorUtils.java
new file mode 100644
index 00000000..80acb097
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/common/validator/ValidatorUtils.java
@@ -0,0 +1,47 @@
+package xiaozhi.common.validator;
+
+import xiaozhi.common.exception.RenException;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.context.support.ResourceBundleMessageSource;
+import org.springframework.validation.beanvalidation.MessageSourceResourceBundleLocator;
+
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ * hibernate-validator校验工具类
+ * 参考文档:http://docs.jboss.org/hibernate/validator/6.0/reference/en-US/html_single/
+ */
+public class ValidatorUtils {
+
+ private static ResourceBundleMessageSource getMessageSource() {
+ ResourceBundleMessageSource bundleMessageSource = new ResourceBundleMessageSource();
+ bundleMessageSource.setDefaultEncoding("UTF-8");
+ bundleMessageSource.setBasenames("i18n/validation");
+ return bundleMessageSource;
+ }
+
+ /**
+ * 校验对象
+ *
+ * @param object 待校验对象
+ * @param groups 待校验的组
+ */
+ public static void validateEntity(Object object, Class>... groups)
+ throws RenException {
+ Locale.setDefault(LocaleContextHolder.getLocale());
+ Validator validator = Validation.byDefaultProvider().configure().messageInterpolator(
+ new ResourceBundleMessageInterpolator(new MessageSourceResourceBundleLocator(getMessageSource())))
+ .buildValidatorFactory().getValidator();
+
+ Set> constraintViolations = validator.validate(object, groups);
+ if (!constraintViolations.isEmpty()) {
+ ConstraintViolation