소스 검색

framework

xufeng 2 년 전
부모
커밋
7554cd5cf8
56개의 변경된 파일5230개의 추가작업 그리고 41개의 파일을 삭제
  1. 56 0
      game-module/game-common/pom.xml
  2. 9 0
      game-module/game-common/src/main/java/com/zanxiang/common/Test.java
  3. 85 0
      game-module/game-common/src/main/java/com/zanxiang/common/domain/ResultVo.java
  4. 27 0
      game-module/game-common/src/main/java/com/zanxiang/common/enums/ResEnum.java
  5. 59 0
      game-module/game-common/src/main/java/com/zanxiang/common/exception/BaseException.java
  6. 35 0
      game-module/game-common/src/main/java/com/zanxiang/common/exception/CustomException.java
  7. 13 0
      game-module/game-common/src/main/java/com/zanxiang/common/exception/PreAuthorizeException.java
  8. 22 0
      game-module/game-common/src/main/java/com/zanxiang/common/exception/UtilException.java
  9. 88 0
      game-module/game-common/src/main/java/com/zanxiang/common/handler/GlobalExceptionHandler.java
  10. 91 0
      game-module/game-common/src/main/java/com/zanxiang/common/text/CharsetKit.java
  11. 870 0
      game-module/game-common/src/main/java/com/zanxiang/common/text/Convert.java
  12. 77 0
      game-module/game-common/src/main/java/com/zanxiang/common/text/StrFormatter.java
  13. 441 0
      game-module/game-common/src/main/java/com/zanxiang/common/text/UUID.java
  14. 62 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/CronUtil.java
  15. 402 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/DateUtils.java
  16. 35 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/ExceptionUtil.java
  17. 173 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/FileUtils.java
  18. 47 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/IdUtils.java
  19. 39 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/IpUtils.java
  20. 172 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/JsonUtil.java
  21. 21 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/KeyBuilder.java
  22. 32 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/MathUtil.java
  23. 73 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/MimeMapUtil.java
  24. 102 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/NumberUtil.java
  25. 13 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/ObjectUtil.java
  26. 57 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/RandomStringUtil.java
  27. 348 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/RegexUtil.java
  28. 102 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/SpringUtils.java
  29. 356 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/StringUtils.java
  30. 149 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/URIUtil.java
  31. 144 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/bean/BeanUtils.java
  32. 139 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/http/AjaxResult.java
  33. 88 0
      game-module/game-common/src/main/java/com/zanxiang/common/utils/http/HttpStatus.java
  34. 3 20
      game-module/game-manage/pom.xml
  35. 26 0
      game-module/game-manage/src/main/java/com/zanxiang/manage/ManageApplication.java
  36. 45 0
      game-module/game-manage/src/main/java/com/zanxiang/manage/controller/DemoController.java
  37. 28 0
      game-module/game-manage/src/main/java/com/zanxiang/manage/controller/TestController.java
  38. 45 0
      game-module/game-manage/src/main/java/com/zanxiang/manage/domain/entity/Demo.java
  39. 33 0
      game-module/game-manage/src/main/java/com/zanxiang/manage/domain/vo/DemoVO.java
  40. 62 0
      game-module/game-manage/src/main/java/com/zanxiang/manage/mapper/DemoMapper.java
  41. 14 0
      game-module/game-manage/src/main/java/com/zanxiang/manage/service/DemoService.java
  42. 18 0
      game-module/game-manage/src/main/java/com/zanxiang/manage/service/Impl/DemoServiceImpl.java
  43. 45 0
      game-module/game-manage/src/main/resources/bootstrap.yml
  44. 88 0
      game-module/game-manage/src/main/resources/mapper/DemoMapper.xml
  45. 3 21
      game-module/game-sdk/pom.xml
  46. 26 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/SDKApplication.java
  47. 37 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/controller/DemoController.java
  48. 43 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/entity/Demo.java
  49. 30 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/vo/DemoVO.java
  50. 62 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/mapper/DemoMapper.java
  51. 15 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/DemoService.java
  52. 18 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/DemoServiceImpl.java
  53. 45 0
      game-module/game-sdk/src/main/resources/bootstrap.yml
  54. 88 0
      game-module/game-sdk/src/main/resources/mapper/DemoMapper.xml
  55. 22 0
      game-module/pom.xml
  56. 7 0
      pom.xml

+ 56 - 0
game-module/game-common/pom.xml

@@ -0,0 +1,56 @@
+<?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>game-center</artifactId>
+        <groupId>com.zanxiang.game</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>game-common</artifactId>
+    <packaging>pom</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- nacos配置中心 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <!-- nacos注册中心 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Mybatis Plus -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>${mybatis-plus.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+
+        <!-- Mysql Connector -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 9 - 0
game-module/game-common/src/main/java/com/zanxiang/common/Test.java

@@ -0,0 +1,9 @@
+package com.zanxiang.common;
+
+import lombok.Data;
+
+//@Entity(name="test")
+@Data
+public class Test {
+    private Long Id;
+}

+ 85 - 0
game-module/game-common/src/main/java/com/zanxiang/common/domain/ResultVo.java

@@ -0,0 +1,85 @@
+package com.zanxiang.common.domain;
+
+import com.zanxiang.common.enums.ResEnum;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 响应信息主体
+ *
+ * @author ruoyi
+ */
+@Data
+public class ResultVo<T> implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    // 成功
+    public static final int CODE_SUCCESS = 200;
+    // 页面重定向
+    public static final int CODE_REDIRECT = 301;
+    // 重新去登录
+    public static final int CODE_TO_LOGIN = 310;
+    // 服务异常
+    public static final int CODE_ERROR = 500;
+
+    private int code;
+
+    private String msg;
+
+    private T data;
+
+    private ResultVo() {
+        this(CODE_SUCCESS);
+    }
+
+    public ResultVo(int code) {
+        this(code, null);
+    }
+
+    public ResultVo(int code, String msg) {
+        this(code, msg, null);
+    }
+
+    public ResultVo(int code, String msg, T data) {
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public static <T> ResultVo<T> ok() {
+        return new ResultVo<>(CODE_SUCCESS);
+    }
+
+    public static <T> ResultVo<T> ok(T data) {
+        return new ResultVo<>(CODE_SUCCESS, null, data);
+    }
+
+    public static <T> ResultVo<T> fail(ResEnum res) {
+        return new ResultVo<>(res.getCode(), res.getMsg());
+    }
+
+    public static <T> ResultVo<T> fail() {
+        return fail("服务异常!!");
+    }
+
+    public static <T> ResultVo<T> fail(String msg) {
+        return new ResultVo<>(CODE_ERROR, msg);
+    }
+
+    public static <T> ResultVo<T> toLogin() {
+        return toLogin("登录错误,请重新登录!!!");
+    }
+
+    public static <T> ResultVo<T> toLogin(String msg) {
+        return new ResultVo<>(CODE_TO_LOGIN, msg);
+    }
+
+    public boolean hasSuccess() {
+        return this.code == CODE_SUCCESS;
+    }
+
+    public boolean hasFailed() {
+        return !hasSuccess();
+    }
+}

+ 27 - 0
game-module/game-common/src/main/java/com/zanxiang/common/enums/ResEnum.java

@@ -0,0 +1,27 @@
+package com.zanxiang.common.enums;
+
+public enum ResEnum {
+    SUCCESS(200, "SUCCESS"),
+    TO_LOGIN(310, "登录失效,请重新登录!"),
+    ERROR(500, "系统异常"),
+    REMOTE_SERVER_FAIL(503, "远程服务调用失败"),
+    LOGIN_FAIL(1001, "用户名或密码错误"),
+    AD_NO_LOGIN(1003, "腾讯广告平台未登录或登录失效");
+
+    ResEnum(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    private final int code;
+
+    private final String msg;
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 59 - 0
game-module/game-common/src/main/java/com/zanxiang/common/exception/BaseException.java

@@ -0,0 +1,59 @@
+package com.zanxiang.common.exception;
+
+/**
+ * 基础异常
+ */
+public class BaseException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 所属模块
+     */
+    private String module;
+
+    /**
+     * 错误码
+     */
+    private String code;
+
+    /**
+     * 错误码对应的参数
+     */
+    private Object[] args;
+
+    public BaseException(String module, String code, Object[] args, String message) {
+        super(message);
+        this.module = module;
+        this.code = code;
+        this.args = args;
+    }
+
+    public BaseException(String module, String code, Object[] args) {
+        this(module, code, args, null);
+    }
+
+    public BaseException(String module, String message) {
+        this(module, null, null, message);
+    }
+
+    public BaseException(String code, Object[] args) {
+        this(null, code, args, null);
+    }
+
+    public BaseException(String message) {
+        this(null, null, null, message);
+    }
+
+    public String getModule() {
+        return module;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public Object[] getArgs() {
+        return args;
+    }
+}
+

+ 35 - 0
game-module/game-common/src/main/java/com/zanxiang/common/exception/CustomException.java

@@ -0,0 +1,35 @@
+package com.zanxiang.common.exception;
+
+/**
+ * 自定义异常
+ */
+public class CustomException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    private Integer code;
+
+    private String message;
+
+    public CustomException(String message) {
+        this.message = message;
+    }
+
+    public CustomException(String message, Integer code) {
+        this.message = message;
+        this.code = code;
+    }
+
+    public CustomException(String message, Throwable e) {
+        super(message, e);
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+}

+ 13 - 0
game-module/game-common/src/main/java/com/zanxiang/common/exception/PreAuthorizeException.java

@@ -0,0 +1,13 @@
+package com.zanxiang.common.exception;
+
+/**
+ * 权限异常
+ *
+ * @author ruoyi
+ */
+public class PreAuthorizeException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public PreAuthorizeException() {
+    }
+}

+ 22 - 0
game-module/game-common/src/main/java/com/zanxiang/common/exception/UtilException.java

@@ -0,0 +1,22 @@
+package com.zanxiang.common.exception;
+
+/**
+ * 工具类异常
+ *
+ * @author ruoyi
+ */
+public class UtilException extends RuntimeException {
+    private static final long serialVersionUID = 8247610319171014183L;
+
+    public UtilException(Throwable e) {
+        super(e.getMessage(), e);
+    }
+
+    public UtilException(String message) {
+        super(message);
+    }
+
+    public UtilException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+}

+ 88 - 0
game-module/game-common/src/main/java/com/zanxiang/common/handler/GlobalExceptionHandler.java

@@ -0,0 +1,88 @@
+package com.zanxiang.common.handler;
+
+import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.common.exception.BaseException;
+import com.zanxiang.common.exception.CustomException;
+import com.zanxiang.common.exception.PreAuthorizeException;
+import com.zanxiang.common.utils.StringUtils;
+import com.zanxiang.common.utils.http.AjaxResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+
+/**
+ * 全局异常处理器
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+    /**
+     * 基础异常
+     */
+    @ExceptionHandler(BaseException.class)
+    public ResultVo<?> baseException(BaseException e) {
+        return ResultVo.fail(e.getMessage());
+    }
+
+    /**
+     * 业务异常
+     */
+    @ExceptionHandler(CustomException.class)
+    public ResultVo<?> businessException(CustomException e) {
+        if (StringUtils.isNull(e.getCode())) {
+            return ResultVo.fail(e.getMessage());
+        }
+        return ResultVo.fail(e.getMessage());
+    }
+
+    @ExceptionHandler(Exception.class)
+    public ResultVo<?> handleException(Exception e) {
+        log.error(e.getMessage(), e);
+        return ResultVo.fail("操作异常");
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(BindException.class)
+    public ResultVo<?> validatedBindException(BindException e) {
+        log.error(e.getMessage(), e);
+        String message = e.getAllErrors().get(0).getDefaultMessage();
+        return ResultVo.fail(message);
+    }
+
+    /**
+     * 参数类型不匹配导致转换异常
+     *
+     * @param e
+     * @return
+     */
+    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+    public ResultVo<?> mismatchErrorHandler(MethodArgumentTypeMismatchException e) {
+        log.error("方法:{},字段:{},参数:{},错误信息:{}", e.getParameter().getMethod(), e.getName(), e.getValue(), e.getMessage());
+        return ResultVo.fail("参数异常,请勿非法操作");
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Object validExceptionHandler(MethodArgumentNotValidException e) {
+        log.error(e.getMessage(), e);
+        String message = e.getBindingResult().getFieldError().getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 权限异常
+     */
+    @ExceptionHandler(PreAuthorizeException.class)
+    public ResultVo<?> preAuthorizeException(PreAuthorizeException e) {
+        return ResultVo.fail("没有权限,请联系管理员授权");
+    }
+}

+ 91 - 0
game-module/game-common/src/main/java/com/zanxiang/common/text/CharsetKit.java

@@ -0,0 +1,91 @@
+package com.zanxiang.common.text;
+
+import org.springframework.util.StringUtils;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 字符集工具类
+ *
+ * @author ruoyi
+ */
+public class CharsetKit {
+    /**
+     * ISO-8859-1
+     */
+    public static final String ISO_8859_1 = "ISO-8859-1";
+    /**
+     * UTF-8
+     */
+    public static final String UTF_8 = "UTF-8";
+    /**
+     * GBK
+     */
+    public static final String GBK = "GBK";
+
+    /**
+     * ISO-8859-1
+     */
+    public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
+    /**
+     * UTF-8
+     */
+    public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
+    /**
+     * GBK
+     */
+    public static final Charset CHARSET_GBK = Charset.forName(GBK);
+
+    /**
+     * 转换为Charset对象
+     *
+     * @param charset 字符集,为空则返回默认字符集
+     * @return Charset
+     */
+    public static Charset charset(String charset) {
+        return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
+    }
+
+    /**
+     * 转换字符串的字符集编码
+     *
+     * @param source      字符串
+     * @param srcCharset  源字符集,默认ISO-8859-1
+     * @param destCharset 目标字符集,默认UTF-8
+     * @return 转换后的字符集
+     */
+    public static String convert(String source, String srcCharset, String destCharset) {
+        return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
+    }
+
+    /**
+     * 转换字符串的字符集编码
+     *
+     * @param source      字符串
+     * @param srcCharset  源字符集,默认ISO-8859-1
+     * @param destCharset 目标字符集,默认UTF-8
+     * @return 转换后的字符集
+     */
+    public static String convert(String source, Charset srcCharset, Charset destCharset) {
+        if (null == srcCharset) {
+            srcCharset = StandardCharsets.ISO_8859_1;
+        }
+
+        if (null == destCharset) {
+            srcCharset = StandardCharsets.UTF_8;
+        }
+
+        if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) {
+            return source;
+        }
+        return new String(source.getBytes(srcCharset), destCharset);
+    }
+
+    /**
+     * @return 系统字符集编码
+     */
+    public static String systemCharset() {
+        return Charset.defaultCharset().name();
+    }
+}

+ 870 - 0
game-module/game-common/src/main/java/com/zanxiang/common/text/Convert.java

@@ -0,0 +1,870 @@
+package com.zanxiang.common.text;
+
+
+import com.zanxiang.common.utils.JsonUtil;
+import com.zanxiang.common.utils.StringUtils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.text.NumberFormat;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 类型转换器
+ *
+ * @author ruoyi
+ */
+public class Convert {
+    /**
+     * 转换为字符串<br>
+     * 如果给定的值为null,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static String toStr(Object value, String defaultValue) {
+        if (null == value) {
+            return defaultValue;
+        }
+        if (value instanceof String) {
+            return (String) value;
+        }
+        return value.toString();
+    }
+
+    /**
+     * 转换为字符串<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static String toStr(Object value) {
+        return toStr(value, null);
+    }
+
+    /**
+     * 转换为字符<br>
+     * 如果给定的值为null,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Character toChar(Object value, Character defaultValue) {
+        if (null == value) {
+            return defaultValue;
+        }
+        if (value instanceof Character) {
+            return (Character) value;
+        }
+
+        final String valueStr = toStr(value, null);
+        return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
+    }
+
+    /**
+     * 转换为字符<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Character toChar(Object value) {
+        return toChar(value, null);
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Byte toByte(Object value, Byte defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Byte) {
+            return (Byte) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).byteValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Byte.parseByte(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Byte toByte(Object value) {
+        return toByte(value, null);
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Short toShort(Object value, Short defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Short) {
+            return (Short) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).shortValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Short.parseShort(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Short toShort(Object value) {
+        return toShort(value, null);
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Number toNumber(Object value, Number defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Number) {
+            return (Number) value;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return NumberFormat.getInstance().parse(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Number toNumber(Object value) {
+        return toNumber(value, null);
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Integer toInt(Object value, Integer defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).intValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Integer.parseInt(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Integer toInt(Object value) {
+        return toInt(value, null);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String str) {
+        return toIntArray(",", str);
+    }
+
+    /**
+     * 转换为Long数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String str) {
+        return toLongArray(",", str);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     *
+     * @param split 分隔符
+     * @param split 被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String split, String str) {
+        if (StringUtils.isEmpty(str)) {
+            return new Integer[]{};
+        }
+        String[] arr = str.split(split);
+        final Integer[] ints = new Integer[arr.length];
+        for (int i = 0; i < arr.length; i++) {
+            final Integer v = toInt(arr[i], 0);
+            ints[i] = v;
+        }
+        return ints;
+    }
+
+    /**
+     * 转换为Long数组<br>
+     *
+     * @param split 分隔符
+     * @param str   被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String split, String str) {
+        if (StringUtils.isEmpty(str)) {
+            return new Long[]{};
+        }
+        String[] arr = str.split(split);
+        final Long[] longs = new Long[arr.length];
+        for (int i = 0; i < arr.length; i++) {
+            final Long v = toLong(arr[i], null);
+            longs[i] = v;
+        }
+        return longs;
+    }
+
+    /**
+     * 转换为String数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String str) {
+        return toStrArray(",", str);
+    }
+
+    /**
+     * 转换为String数组<br>
+     *
+     * @param split 分隔符
+     * @param split 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String split, String str) {
+        return str.split(split);
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Long toLong(Object value, Long defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Long) {
+            return (Long) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).longValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            // 支持科学计数法
+            return new BigDecimal(valueStr.trim()).longValue();
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Long toLong(Object value) {
+        return toLong(value, null);
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Double toDouble(Object value, Double defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Double) {
+            return (Double) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).doubleValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            // 支持科学计数法
+            return new BigDecimal(valueStr.trim()).doubleValue();
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Double toDouble(Object value) {
+        return toDouble(value, null);
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Float toFloat(Object value, Float defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Float) {
+            return (Float) value;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).floatValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Float.parseFloat(valueStr.trim());
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Float toFloat(Object value) {
+        return toFloat(value, null);
+    }
+
+    /**
+     * 转换为boolean<br>
+     * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value, Boolean defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof Boolean) {
+            return (Boolean) value;
+        }
+        String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        valueStr = valueStr.trim().toLowerCase();
+        switch (valueStr) {
+            case "true":
+                return true;
+            case "false":
+                return false;
+            case "yes":
+                return true;
+            case "ok":
+                return true;
+            case "no":
+                return false;
+            case "1":
+                return true;
+            case "0":
+                return false;
+            default:
+                return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为boolean<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value) {
+        return toBool(value, null);
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     *
+     * @param clazz        Enum的Class
+     * @param value        值
+     * @param defaultValue 默认值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (clazz.isAssignableFrom(value.getClass())) {
+            @SuppressWarnings("unchecked")
+            E myE = (E) value;
+            return myE;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return Enum.valueOf(clazz, valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     *
+     * @param clazz Enum的Class
+     * @param value 值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) {
+        return toEnum(clazz, value, null);
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value, BigInteger defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof BigInteger) {
+            return (BigInteger) value;
+        }
+        if (value instanceof Long) {
+            return BigInteger.valueOf((Long) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return new BigInteger(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value) {
+        return toBigInteger(value, null);
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value        被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        }
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+        if (value instanceof Long) {
+            return new BigDecimal((Long) value);
+        }
+        if (value instanceof Double) {
+            return new BigDecimal((Double) value);
+        }
+        if (value instanceof Integer) {
+            return new BigDecimal((Integer) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr)) {
+            return defaultValue;
+        }
+        try {
+            return new BigDecimal(valueStr);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value) {
+        return toBigDecimal(value, null);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj 对象
+     * @return 字符串
+     */
+    public static String utf8Str(Object obj) {
+        return str(obj, CharsetKit.CHARSET_UTF_8);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj         对象
+     * @param charsetName 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, String charsetName) {
+        return str(obj, Charset.forName(charsetName));
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj     对象
+     * @param charset 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, Charset charset) {
+        if (null == obj) {
+            return null;
+        }
+
+        if (obj instanceof String) {
+            return (String) obj;
+        } else if (obj instanceof byte[] || obj instanceof Byte[]) {
+            return str((Byte[]) obj, charset);
+        } else if (obj instanceof ByteBuffer) {
+            return str((ByteBuffer) obj, charset);
+        }
+        return obj.toString();
+    }
+
+    /**
+     * 将byte数组转为字符串
+     *
+     * @param bytes   byte数组
+     * @param charset 字符集
+     * @return 字符串
+     */
+    public static String str(byte[] bytes, String charset) {
+        return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
+    }
+
+    /**
+     * 解码字节码
+     *
+     * @param data    字符串
+     * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+     * @return 解码后的字符串
+     */
+    public static String str(byte[] data, Charset charset) {
+        if (data == null) {
+            return null;
+        }
+
+        if (null == charset) {
+            return new String(data);
+        }
+        return new String(data, charset);
+    }
+
+    /**
+     * 将编码的byteBuffer数据转换为字符串
+     *
+     * @param data    数据
+     * @param charset 字符集,如果为空使用当前系统字符集
+     * @return 字符串
+     */
+    public static String str(ByteBuffer data, String charset) {
+        if (data == null) {
+            return null;
+        }
+
+        return str(data, Charset.forName(charset));
+    }
+
+    /**
+     * 将编码的byteBuffer数据转换为字符串
+     *
+     * @param data    数据
+     * @param charset 字符集,如果为空使用当前系统字符集
+     * @return 字符串
+     */
+    public static String str(ByteBuffer data, Charset charset) {
+        if (null == charset) {
+            charset = Charset.defaultCharset();
+        }
+        return charset.decode(data).toString();
+    }
+
+    /**
+     * 半角转全角
+     *
+     * @param input String.
+     * @return 全角字符串.
+     */
+    public static String toSBC(String input) {
+        return toSBC(input, null);
+    }
+
+    /**
+     * 半角转全角
+     *
+     * @param input         String
+     * @param notConvertSet 不替换的字符集合
+     * @return 全角字符串.
+     */
+    public static String toSBC(String input, Set<Character> notConvertSet) {
+        char c[] = input.toCharArray();
+        for (int i = 0; i < c.length; i++) {
+            if (null != notConvertSet && notConvertSet.contains(c[i])) {
+                // 跳过不替换的字符
+                continue;
+            }
+
+            if (c[i] == ' ') {
+                c[i] = '\u3000';
+            } else if (c[i] < '\177') {
+                c[i] = (char) (c[i] + 65248);
+
+            }
+        }
+        return new String(c);
+    }
+
+    /**
+     * 全角转半角
+     *
+     * @param input String.
+     * @return 半角字符串
+     */
+    public static String toDBC(String input) {
+        return toDBC(input, null);
+    }
+
+    /**
+     * 替换全角为半角
+     *
+     * @param text          文本
+     * @param notConvertSet 不替换的字符集合
+     * @return 替换后的字符
+     */
+    public static String toDBC(String text, Set<Character> notConvertSet) {
+        char c[] = text.toCharArray();
+        for (int i = 0; i < c.length; i++) {
+            if (null != notConvertSet && notConvertSet.contains(c[i])) {
+                // 跳过不替换的字符
+                continue;
+            }
+
+            if (c[i] == '\u3000') {
+                c[i] = ' ';
+            } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
+                c[i] = (char) (c[i] - 65248);
+            }
+        }
+        String returnString = new String(c);
+
+        return returnString;
+    }
+
+    /**
+     * 数字金额大写转换 先写个完整的然后将如零拾替换成零
+     *
+     * @param n 数字
+     * @return 中文大写数字
+     */
+    public static String digitUppercase(double n) {
+        String[] fraction = {"角", "分"};
+        String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
+        String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
+
+        String head = n < 0 ? "负" : "";
+        n = Math.abs(n);
+
+        String s = "";
+        for (int i = 0; i < fraction.length; i++) {
+            s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
+        }
+        if (s.length() < 1) {
+            s = "整";
+        }
+        int integerPart = (int) Math.floor(n);
+
+        for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
+            String p = "";
+            for (int j = 0; j < unit[1].length && n > 0; j++) {
+                p = digit[integerPart % 10] + unit[1][j] + p;
+                integerPart = integerPart / 10;
+            }
+            s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
+        }
+        return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
+    }
+
+    /**
+     * unicode编码转换中文
+     *
+     * @param object: 需要转码的字符串
+     * @return : 转码之后的结果
+     */
+    public static String unicodeToString(Object object) {
+        String str = JsonUtil.toString(object);
+        Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
+        Matcher matcher = pattern.matcher(str);
+        char ch;
+        while (matcher.find()) {
+            ch = (char) Integer.parseInt(matcher.group(2), 16);
+            str = str.replace(matcher.group(1), ch + "");
+        }
+        return str;
+    }
+}

+ 77 - 0
game-module/game-common/src/main/java/com/zanxiang/common/text/StrFormatter.java

@@ -0,0 +1,77 @@
+package com.zanxiang.common.text;
+
+
+import com.zanxiang.common.utils.StringUtils;
+
+/**
+ * 字符串格式化
+ *
+ * @author ruoyi
+ */
+public class StrFormatter {
+    public static final String EMPTY_JSON = "{}";
+    public static final char C_BACKSLASH = '\\';
+    public static final char C_DELIM_START = '{';
+    public static final char C_DELIM_END = '}';
+
+    /**
+     * 格式化字符串<br>
+     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
+     * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
+     * 例:<br>
+     * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     *
+     * @param strPattern 字符串模板
+     * @param argArray   参数列表
+     * @return 结果
+     */
+    public static String format(final String strPattern, final Object... argArray) {
+        if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) {
+            return strPattern;
+        }
+        final int strPatternLength = strPattern.length();
+
+        // 初始化定义好的长度以获得更好的性能
+        StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
+
+        int handledPosition = 0;
+        int delimIndex;// 占位符所在位置
+        for (int argIndex = 0; argIndex < argArray.length; argIndex++) {
+            delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
+            if (delimIndex == -1) {
+                if (handledPosition == 0) {
+                    return strPattern;
+                } else { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
+                    sbuf.append(strPattern, handledPosition, strPatternLength);
+                    return sbuf.toString();
+                }
+            } else {
+                if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) {
+                    if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) {
+                        // 转义符之前还有一个转义符,占位符依旧有效
+                        sbuf.append(strPattern, handledPosition, delimIndex - 1);
+                        sbuf.append(Convert.utf8Str(argArray[argIndex]));
+                        handledPosition = delimIndex + 2;
+                    } else {
+                        // 占位符被转义
+                        argIndex--;
+                        sbuf.append(strPattern, handledPosition, delimIndex - 1);
+                        sbuf.append(C_DELIM_START);
+                        handledPosition = delimIndex + 1;
+                    }
+                } else {
+                    // 正常占位符
+                    sbuf.append(strPattern, handledPosition, delimIndex);
+                    sbuf.append(Convert.utf8Str(argArray[argIndex]));
+                    handledPosition = delimIndex + 2;
+                }
+            }
+        }
+        // 加入最后一个占位符后所有的字符
+        sbuf.append(strPattern, handledPosition, strPattern.length());
+
+        return sbuf.toString();
+    }
+}

+ 441 - 0
game-module/game-common/src/main/java/com/zanxiang/common/text/UUID.java

@@ -0,0 +1,441 @@
+package com.zanxiang.common.text;
+
+
+import com.zanxiang.common.exception.UtilException;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 提供通用唯一识别码(universally unique identifier)(UUID)实现
+ *
+ * @author ruoyi
+ */
+public final class UUID implements java.io.Serializable, Comparable<UUID> {
+    private static final long serialVersionUID = -1185015143654744140L;
+
+    /**
+     * SecureRandom 的单例
+     */
+    private static class Holder {
+        static final SecureRandom numberGenerator = getSecureRandom();
+    }
+
+    /**
+     * 此UUID的最高64有效位
+     */
+    private final long mostSigBits;
+
+    /**
+     * 此UUID的最低64有效位
+     */
+    private final long leastSigBits;
+
+    /**
+     * 私有构造
+     *
+     * @param data 数据
+     */
+    private UUID(byte[] data) {
+        long msb = 0;
+        long lsb = 0;
+        assert data.length == 16 : "data must be 16 bytes in length";
+        for (int i = 0; i < 8; i++) {
+            msb = (msb << 8) | (data[i] & 0xff);
+        }
+        for (int i = 8; i < 16; i++) {
+            lsb = (lsb << 8) | (data[i] & 0xff);
+        }
+        this.mostSigBits = msb;
+        this.leastSigBits = lsb;
+    }
+
+    /**
+     * 使用指定的数据构造新的 UUID。
+     *
+     * @param mostSigBits  用于 {@code UUID} 的最高有效 64 位
+     * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位
+     */
+    public UUID(long mostSigBits, long leastSigBits) {
+        this.mostSigBits = mostSigBits;
+        this.leastSigBits = leastSigBits;
+    }
+
+    /**
+     * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。
+     *
+     * @return 随机生成的 {@code UUID}
+     */
+    public static UUID fastUUID() {
+        return randomUUID(false);
+    }
+
+    /**
+     * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
+     *
+     * @return 随机生成的 {@code UUID}
+     */
+    public static UUID randomUUID() {
+        return randomUUID(true);
+    }
+
+    /**
+     * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
+     *
+     * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能
+     * @return 随机生成的 {@code UUID}
+     */
+    public static UUID randomUUID(boolean isSecure) {
+        final Random ng = isSecure ? Holder.numberGenerator : getRandom();
+
+        byte[] randomBytes = new byte[16];
+        ng.nextBytes(randomBytes);
+        randomBytes[6] &= 0x0f; /* clear version */
+        randomBytes[6] |= 0x40; /* set to version 4 */
+        randomBytes[8] &= 0x3f; /* clear variant */
+        randomBytes[8] |= 0x80; /* set to IETF variant */
+        return new UUID(randomBytes);
+    }
+
+    /**
+     * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。
+     *
+     * @param name 用于构造 UUID 的字节数组。
+     * @return 根据指定数组生成的 {@code UUID}
+     */
+    public static UUID nameUUIDFromBytes(byte[] name) {
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new InternalError("MD5 not supported");
+        }
+        byte[] md5Bytes = md.digest(name);
+        md5Bytes[6] &= 0x0f; /* clear version */
+        md5Bytes[6] |= 0x30; /* set to version 3 */
+        md5Bytes[8] &= 0x3f; /* clear variant */
+        md5Bytes[8] |= 0x80; /* set to IETF variant */
+        return new UUID(md5Bytes);
+    }
+
+    /**
+     * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。
+     *
+     * @param name 指定 {@code UUID} 字符串
+     * @return 具有指定值的 {@code UUID}
+     * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常
+     */
+    public static UUID fromString(String name) {
+        String[] components = name.split("-");
+        if (components.length != 5) {
+            throw new IllegalArgumentException("Invalid UUID string: " + name);
+        }
+        for (int i = 0; i < 5; i++) {
+            components[i] = "0x" + components[i];
+        }
+
+        long mostSigBits = Long.decode(components[0]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[1]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[2]).longValue();
+
+        long leastSigBits = Long.decode(components[3]).longValue();
+        leastSigBits <<= 48;
+        leastSigBits |= Long.decode(components[4]).longValue();
+
+        return new UUID(mostSigBits, leastSigBits);
+    }
+
+    /**
+     * 返回此 UUID 的 128 位值中的最低有效 64 位。
+     *
+     * @return 此 UUID 的 128 位值中的最低有效 64 位。
+     */
+    public long getLeastSignificantBits() {
+        return leastSigBits;
+    }
+
+    /**
+     * 返回此 UUID 的 128 位值中的最高有效 64 位。
+     *
+     * @return 此 UUID 的 128 位值中最高有效 64 位。
+     */
+    public long getMostSignificantBits() {
+        return mostSigBits;
+    }
+
+    /**
+     * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。
+     * <p>
+     * 版本号具有以下含意:
+     * <ul>
+     * <li>1 基于时间的 UUID
+     * <li>2 DCE 安全 UUID
+     * <li>3 基于名称的 UUID
+     * <li>4 随机生成的 UUID
+     * </ul>
+     *
+     * @return 此 {@code UUID} 的版本号
+     */
+    public int version() {
+        // Version is bits masked by 0x000000000000F000 in MS long
+        return (int) ((mostSigBits >> 12) & 0x0f);
+    }
+
+    /**
+     * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。
+     * <p>
+     * 变体号具有以下含意:
+     * <ul>
+     * <li>0 为 NCS 向后兼容保留
+     * <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>(Leach-Salz), 用于此类
+     * <li>6 保留,微软向后兼容
+     * <li>7 保留供以后定义使用
+     * </ul>
+     *
+     * @return 此 {@code UUID} 相关联的变体号
+     */
+    public int variant() {
+        // This field is composed of a varying number of bits.
+        // 0 - - Reserved for NCS backward compatibility
+        // 1 0 - The IETF aka Leach-Salz variant (used by this class)
+        // 1 1 0 Reserved, Microsoft backward compatibility
+        // 1 1 1 Reserved for future definition.
+        return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
+    }
+
+    /**
+     * 与此 UUID 相关联的时间戳值。
+     *
+     * <p>
+     * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>
+     * 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。
+     *
+     * <p>
+     * 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
+     * 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
+     *
+     * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。
+     */
+    public long timestamp() throws UnsupportedOperationException {
+        checkTimeBase();
+        return (mostSigBits & 0x0FFFL) << 48//
+                | ((mostSigBits >> 16) & 0x0FFFFL) << 32//
+                | mostSigBits >>> 32;
+    }
+
+    /**
+     * 与此 UUID 相关联的时钟序列值。
+     *
+     * <p>
+     * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。
+     * <p>
+     * {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出
+     * UnsupportedOperationException。
+     *
+     * @return 此 {@code UUID} 的时钟序列
+     * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
+     */
+    public int clockSequence() throws UnsupportedOperationException {
+        checkTimeBase();
+        return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
+    }
+
+    /**
+     * 与此 UUID 相关的节点值。
+     *
+     * <p>
+     * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。
+     * <p>
+     * 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
+     * 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
+     *
+     * @return 此 {@code UUID} 的节点值
+     * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
+     */
+    public long node() throws UnsupportedOperationException {
+        checkTimeBase();
+        return leastSigBits & 0x0000FFFFFFFFFFFFL;
+    }
+
+    /**
+     * 返回此{@code UUID} 的字符串表现形式。
+     *
+     * <p>
+     * UUID 的字符串表示形式由此 BNF 描述:
+     *
+     * <pre>
+     * {@code
+     * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * </pre>
+     *
+     * </blockquote>
+     *
+     * @return 此{@code UUID} 的字符串表现形式
+     * @see #toString(boolean)
+     */
+    @Override
+    public String toString() {
+        return toString(false);
+    }
+
+    /**
+     * 返回此{@code UUID} 的字符串表现形式。
+     *
+     * <p>
+     * UUID 的字符串表示形式由此 BNF 描述:
+     *
+     * <pre>
+     * {@code
+     * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * </pre>
+     *
+     * </blockquote>
+     *
+     * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串
+     * @return 此{@code UUID} 的字符串表现形式
+     */
+    public String toString(boolean isSimple) {
+        final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
+        // time_low
+        builder.append(digits(mostSigBits >> 32, 8));
+        if (false == isSimple) {
+            builder.append('-');
+        }
+        // time_mid
+        builder.append(digits(mostSigBits >> 16, 4));
+        if (false == isSimple) {
+            builder.append('-');
+        }
+        // time_high_and_version
+        builder.append(digits(mostSigBits, 4));
+        if (false == isSimple) {
+            builder.append('-');
+        }
+        // variant_and_sequence
+        builder.append(digits(leastSigBits >> 48, 4));
+        if (false == isSimple) {
+            builder.append('-');
+        }
+        // node
+        builder.append(digits(leastSigBits, 12));
+
+        return builder.toString();
+    }
+
+    /**
+     * 返回此 UUID 的哈希码。
+     *
+     * @return UUID 的哈希码值。
+     */
+    @Override
+    public int hashCode() {
+        long hilo = mostSigBits ^ leastSigBits;
+        return ((int) (hilo >> 32)) ^ (int) hilo;
+    }
+
+    /**
+     * 将此对象与指定对象比较。
+     * <p>
+     * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。
+     *
+     * @param obj 要与之比较的对象
+     * @return 如果对象相同,则返回 {@code true};否则返回 {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if ((null == obj) || (obj.getClass() != UUID.class)) {
+            return false;
+        }
+        UUID id = (UUID) obj;
+        return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);
+    }
+
+    // Comparison Operations
+
+    /**
+     * 将此 UUID 与指定的 UUID 比较。
+     *
+     * <p>
+     * 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。
+     *
+     * @param val 与此 UUID 比较的 UUID
+     * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。
+     */
+    @Override
+    public int compareTo(UUID val) {
+        // The ordering is intentionally set up so that the UUIDs
+        // can simply be numerically compared as two numbers
+        return (this.mostSigBits < val.mostSigBits ? -1 : //
+                (this.mostSigBits > val.mostSigBits ? 1 : //
+                        (this.leastSigBits < val.leastSigBits ? -1 : //
+                                (this.leastSigBits > val.leastSigBits ? 1 : //
+                                        0))));
+    }
+
+    // Private method start
+
+    /**
+     * 返回指定数字对应的hex值
+     *
+     * @param val    值
+     * @param digits 位
+     * @return 值
+     */
+    private static String digits(long val, int digits) {
+        long hi = 1L << (digits * 4);
+        return Long.toHexString(hi | (val & (hi - 1))).substring(1);
+    }
+
+    /**
+     * 检查是否为time-based版本UUID
+     */
+    private void checkTimeBase() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+    }
+
+    /**
+     * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
+     *
+     * @return {@link SecureRandom}
+     */
+    public static SecureRandom getSecureRandom() {
+        try {
+            return SecureRandom.getInstance("SHA1PRNG");
+        } catch (NoSuchAlgorithmException e) {
+            throw new UtilException(e);
+        }
+    }
+
+    /**
+     * 获取随机数生成器对象<br>
+     * ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。
+     *
+     * @return {@link ThreadLocalRandom}
+     */
+    public static ThreadLocalRandom getRandom() {
+        return ThreadLocalRandom.current();
+    }
+}

+ 62 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/CronUtil.java

@@ -0,0 +1,62 @@
+package com.zanxiang.common.utils;
+
+import org.springframework.scheduling.support.CronSequenceGenerator;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Author wcc
+ * @Date 2020/11/17 20:37
+ * @Version 1.0
+ * @Description
+ */
+public class CronUtil {
+    /**
+     * 计算指定时间之后的下次执行时间
+     *
+     * @param cron
+     * @param date 时间节点
+     * @return
+     */
+    public static Date getExecuteTime(String cron, Date date) {
+        if (StringUtils.isEmpty(cron)) {
+            throw new IllegalArgumentException("cron表达式不可为空");
+        }
+        return new CronSequenceGenerator(cron).next(date);
+    }
+
+    /**
+     * 根据当前计算下次执行时间
+     *
+     * @param cron
+     * @return
+     */
+    public static Date getExecuteTime(String cron) {
+        return getExecuteTime(cron, new Date());
+    }
+
+    /**
+     * 计算多个执行时间
+     *
+     * @param cron  表达式
+     * @param count 执行时间个数
+     * @return
+     */
+    public static List<Date> getExecuteTime(String cron, Integer count) {
+        if (StringUtils.isEmpty(cron)) {
+            throw new IllegalArgumentException("cron表达式不可为空");
+        }
+        count = count == null || count < 1 ? 1 : count;
+        CronSequenceGenerator cronSequenceGenerator = new CronSequenceGenerator(cron);
+        List<Date> list = new ArrayList<>(count);
+        Date nextTimePoint = new Date();
+        for (int i = 0; i < count; i++) {
+            // 计算下次时间点的开始时间
+            nextTimePoint = cronSequenceGenerator.next(nextTimePoint);
+            list.add(nextTimePoint);
+        }
+        return list;
+    }
+}

+ 402 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/DateUtils.java

@@ -0,0 +1,402 @@
+package com.zanxiang.common.utils;
+
+import org.apache.commons.lang.time.DateFormatUtils;
+
+import java.lang.management.ManagementFactory;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalAccessor;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * 时间工具类
+ *
+ * @author ruoyi
+ */
+public class DateUtils extends org.apache.commons.lang.time.DateUtils {
+    public static String YYYY_MM_DD = "yyyy-MM-dd";
+
+    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+
+    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+
+    private static String[] parsePatterns = {"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+    public static final DateTimeFormatter FORMAT_DATETIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+    public static final DateTimeFormatter FORMAT_FOR_KEY = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH:mm");
+    public static final DateTimeFormatter FORMAT_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+    public static final DateTimeFormatter FORMAT_TIME = DateTimeFormatter.ofPattern("HH:mm:ss");
+
+    public static long localDateToSecond(LocalDate localDate) {
+        return localDate.atStartOfDay(ZoneOffset.ofHours(8)).toEpochSecond();
+    }
+
+    public static long localDateToMilli(LocalDate localDate) {
+        return localDate.atStartOfDay(ZoneOffset.ofHours(8)).toInstant().toEpochMilli();
+    }
+
+    public static Date localDateToDate(LocalDate localDate) {
+        return Date.from(localDate.atStartOfDay(ZoneOffset.ofHours(8)).toInstant());
+    }
+
+    public static LocalDateTime localDateToLocalDateTime(LocalDate localDate) {
+        return LocalDateTime.of(localDate, LocalTime.MIN);
+    }
+
+    public static long localDateTimeToSecond(LocalDateTime localDateTime) {
+        return localDateTime.toEpochSecond(ZoneOffset.ofHours(8));
+    }
+
+    public static long localDateTimeToMilli(LocalDateTime localDateTime) {
+        return localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
+    }
+
+    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
+        return Date.from(localDateTime.atZone(ZoneOffset.ofHours(8)).toInstant());
+    }
+
+    public static LocalDate secondToLocalDate(long second) {
+        return Instant.ofEpochSecond(second).atZone(ZoneOffset.ofHours(8)).toLocalDate();
+    }
+
+    public static LocalDate milliToLocalDate(long milli) {
+        return Instant.ofEpochMilli(milli).atZone(ZoneOffset.ofHours(8)).toLocalDate();
+    }
+
+    public static long milliToSecond(long milli) {
+        return milli / 1000;
+    }
+
+    public static int milliToSecond2(long milli) {
+        return ((Long) (milli / 1000)).intValue();
+    }
+
+    public static boolean equals(LocalDateTime date1, LocalDateTime date2) {
+        if (date1 == null && date2 == null) {
+            return true;
+        }
+        if (date1 == null || date2 == null) {
+            return false;
+        }
+        return date1.compareTo(date2) == 0;
+    }
+
+    public static boolean equals(LocalDate date1, LocalDate date2) {
+        if (date1 == null && date2 == null) {
+            return true;
+        }
+        if (date1 == null || date2 == null) {
+            return false;
+        }
+        return date1.compareTo(date2) == 0;
+    }
+
+    public static LocalDateTime secondToLocalDateTime(long second) {
+        return Instant.ofEpochSecond(second).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
+    }
+
+    public static long secondToMilli(int second) {
+        return second * 1000;
+    }
+
+    public static long secondToMilli(long second) {
+        return second * 1000;
+    }
+
+    public static LocalDateTime milliToLocalDateTime(long milli) {
+        return Instant.ofEpochMilli(milli).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
+    }
+
+    public static LocalDate dateToLocalDate(Date date) {
+        return date.toInstant().atZone(ZoneOffset.ofHours(8)).toLocalDate();
+    }
+
+    public static LocalDateTime dateToLocalDateTime(Date date) {
+        return date.toInstant().atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
+    }
+
+    public static String format(TemporalAccessor temporal, DateTimeFormatter formatter) {
+        return formatter.format(temporal);
+    }
+
+    public static String formatLocalDate(LocalDate localDate) {
+        return FORMAT_DATE.format(localDate);
+    }
+
+    public static String formatLocalDateTime(LocalDateTime localDateTime) {
+        return FORMAT_DATETIME.format(localDateTime);
+    }
+
+    /**
+     * 2个日期的时间间隔
+     *
+     * @param beginDate
+     * @param endDate
+     * @return
+     */
+    public static long intervalOfDays(LocalDate beginDate, LocalDate endDate) {
+        return endDate.toEpochDay() - beginDate.toEpochDay();
+    }
+
+    /**
+     * 2个日期的时间间隔
+     *
+     * @param beginDate
+     * @param endDate
+     * @return
+     */
+    public static long intervalOfHour(LocalDateTime beginDate, LocalDateTime endDate) {
+        return ChronoUnit.HOURS.between(beginDate, endDate);
+    }
+
+    /**
+     * 2个日期的时间间隔
+     *
+     * @param beginDate
+     * @param endDate
+     * @return
+     */
+    public static long intervalOfMinute(LocalDateTime beginDate, LocalDateTime endDate) {
+        return ChronoUnit.MINUTES.between(beginDate, endDate);
+    }
+
+    public static List<LocalDate> splitByWeek(LocalDate startLocalDate, LocalDate endLocalDate) {
+        if (startLocalDate.compareTo(endLocalDate) > 0) {
+            throw new RuntimeException("startLocalDate must be less than endLocalDate");
+        }
+        List<LocalDate> localDates = new ArrayList<>();
+        LocalDate lastMonday = startLocalDate.with(DayOfWeek.MONDAY).plusDays(7);// 下周一
+        do {
+            localDates.add(startLocalDate);
+            startLocalDate = lastMonday;
+            lastMonday = lastMonday.plusDays(7);
+        } while (startLocalDate.compareTo(endLocalDate) < 0);
+        localDates.add(endLocalDate);
+        return localDates;
+    }
+
+    /**
+     * 将时间段按照月份切割
+     * <p>
+     * ex:2020-01-30  ~  2020-01-30   =>   ["2020-01-30","2020-01-30"]
+     * ex:2020-01-30  ~  2020-02-01   =>   ["2020-01-30","2020-02-01"]
+     * ex:2020-01-30  ~  2020-03-03   =>   ["2020-01-30","2020-02-01","2020-03-01","2020-03-03"]
+     *
+     * @param startLocalDate
+     * @param endLocalDate
+     * @return
+     */
+    public static List<LocalDate> splitByMonth(LocalDate startLocalDate, LocalDate endLocalDate) {
+        if (startLocalDate.compareTo(endLocalDate) > 0) {
+            throw new RuntimeException("startLocalDate must be less than endLocalDate");
+        }
+        List<LocalDate> localDates = new ArrayList<>();
+        LocalDate lastMonth = startLocalDate.withDayOfMonth(1).plusMonths(1);// 下月 1号
+        do {
+            localDates.add(startLocalDate);
+            startLocalDate = lastMonth;
+            lastMonth = startLocalDate.plusMonths(1);
+        } while (startLocalDate.compareTo(endLocalDate) < 0);
+        localDates.add(endLocalDate);
+        return localDates;
+    }
+
+    /**
+     * 将时间段按天切割
+     *
+     * @param startLocalDate
+     * @param endLocalDate
+     * @return
+     */
+    public static List<LocalDate> splitByDay(LocalDate startLocalDate, LocalDate endLocalDate) {
+        if (startLocalDate.compareTo(endLocalDate) > 0) {
+            throw new RuntimeException("startLocalDate must be less than endLocalDate");
+        }
+        List<LocalDate> localDates = new ArrayList<>();
+        long day = endLocalDate.toEpochDay() - startLocalDate.toEpochDay();
+        for (int i = 0; i <= day; i++) {
+            localDates.add(startLocalDate.plusDays(i));
+        }
+        return localDates;
+    }
+
+    /**
+     * 获取指定年月的天数
+     *
+     * @param year
+     * @param month
+     * @return
+     */
+    public static long daysOfYearMonth(int year, int month) {
+        LocalDate start = LocalDate.of(year, month, 1);
+        if (month == 12) {
+            year += 1;
+            month = 1;
+        } else {
+            month += 1;
+        }
+        LocalDate end = LocalDate.of(year, month, 1);
+        return intervalOfDays(start, end);
+    }
+
+    public String localDateFormat(LocalDate localDate, String formatStr) {
+        return localDate.format(DateTimeFormatter.ofPattern(formatStr));
+    }
+
+    public String localDateFormat(LocalDate localDate, DateTimeFormatter formatter) {
+        return localDate.format(formatter);
+    }
+
+    /**
+     * 获取当前日期, 默认格式为yyyy-MM-dd
+     *
+     * @return String
+     */
+    public static String getDate() {
+        return dateTimeNow(YYYY_MM_DD);
+    }
+
+    public static final String getTime() {
+        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
+    }
+
+    public static final String dateTimeNow() {
+        return dateTimeNow(YYYYMMDDHHMMSS);
+    }
+
+    public static final String dateTimeNow(final String format) {
+        return parseDateToStr(format, new Date());
+    }
+
+    public static final String dateTime(final Date date) {
+        return parseDateToStr(YYYY_MM_DD, date);
+    }
+
+    public static final String parseDateToStr(final String format, final Date date) {
+        return new SimpleDateFormat(format).format(date);
+    }
+
+    public static final Date dateTime(final String format, final String ts) {
+        try {
+            return new SimpleDateFormat(format).parse(ts);
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 日期路径 即年/月/日 如2018/08/08
+     */
+    public static final String datePath() {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyy/MM/dd");
+    }
+
+    /**
+     * 日期路径 即年/月/日 如20180808
+     */
+    public static final String dateTime() {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyyMMdd");
+    }
+
+    /**
+     * 日期型字符串转化为日期 格式
+     */
+    public static Date parseDate(Object str) {
+        if (str == null) {
+            return null;
+        }
+        try {
+            return parseDate(str.toString(), parsePatterns);
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 获取服务器启动时间
+     */
+    public static Date getServerStartDate() {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 计算两个时间差
+     */
+    public static String getDatePoor(Date endDate, Date nowDate) {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // long ns = 1000;
+        // 获得两个时间的毫秒时间差异
+        long diff = endDate.getTime() - nowDate.getTime();
+        // 计算差多少天
+        long day = diff / nd;
+        // 计算差多少小时
+        long hour = diff % nd / nh;
+        // 计算差多少分钟
+        long min = diff % nd % nh / nm;
+        // 计算差多少秒//输出结果
+        // long sec = diff % nd % nh % nm / ns;
+        return day + "天" + hour + "小时" + min + "分钟";
+    }
+
+    /**
+     * String转换成LocalDate,标准时间字符串
+     *
+     * @param date "2021-01-01"
+     * @return
+     */
+    public static LocalDateTime string2LocalDate(String date) {
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        return LocalDateTime.parse(date, fmt);
+    }
+
+    /**
+     * 特殊日期字符串处理
+     *
+     * @param dateTime “2021-01-01T00:00:00+08:00”
+     * @return
+     */
+    public static LocalDateTime string2LocalDateTime(String dateTime) throws ParseException {
+        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+        Date date = df.parse(dateTime);
+        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
+        date = sdf.parse(date.toString());
+        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return string2LocalDate(df.format(date));
+    }
+
+    /**
+     * 获得某天最小时间 2020-08-19 00:00:00
+     *
+     * @param oneDayTime : 某天的时间
+     * @return : 返回某天零点时间13位时间戳
+     */
+    public static long getStartOfDay(Long oneDayTime) {
+        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(oneDayTime), ZoneId.systemDefault());
+        LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
+        return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()).getTime();
+    }
+
+    /**
+     * 获得某天最大时间 2021-08-19 23:59:59
+     *
+     * @param oneDayTime : 某天的时间
+     * @return : 返回某天23:59:59的13位时间戳
+     */
+    public static long getEndOfDay(Long oneDayTime) {
+        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(oneDayTime), ZoneId.systemDefault());
+        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
+        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()).getTime();
+    }
+}

+ 35 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/ExceptionUtil.java

@@ -0,0 +1,35 @@
+package com.zanxiang.common.utils;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 错误信息处理类。
+ *
+ * @author ruoyi
+ */
+public class ExceptionUtil {
+    /**
+     * 获取exception的详细错误信息。
+     */
+    public static String getExceptionMessage(Throwable e) {
+        StringWriter sw = new StringWriter();
+        e.printStackTrace(new PrintWriter(sw, true));
+        return sw.toString();
+    }
+
+    public static String getRootErrorMessage(Exception e) {
+        Throwable root = ExceptionUtils.getRootCause(e);
+        root = (root == null ? e : root);
+        if (root == null) {
+            return "";
+        }
+        String msg = root.getMessage();
+        if (msg == null) {
+            return "null";
+        }
+        return StringUtils.defaultString(msg);
+    }
+}

+ 173 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/FileUtils.java

@@ -0,0 +1,173 @@
+package com.zanxiang.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.net.URL;
+import java.net.URLEncoder;
+
+/**
+ * 文件处理工具类
+ *
+ * @author ruoyi
+ */
+@Slf4j
+public class FileUtils extends org.apache.commons.io.FileUtils {
+    public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
+
+    public static String getTmpPath() {
+        return System.getProperty("java.io.tmpdir") + File.separator;
+    }
+
+    /**
+     * 通过 url下载文件
+     *
+     * @param url
+     * @param path
+     * @param filename
+     * @return
+     * @throws IOException
+     */
+    public static File downloadFileByUrl(String url, String path, String filename) throws IOException {
+        try (InputStream in = new URL(url).openConnection().getInputStream()) {
+            return saveFile(in, path, filename, true);
+        }
+    }
+
+    /**
+     * 将输入流写入文件
+     *
+     * @param in
+     * @param path
+     * @param filename
+     * @return
+     * @throws IOException
+     */
+    public static File saveFile(InputStream in, String path, String filename, boolean close) throws IOException {
+        File file = createFile(path, filename);
+        file.delete();
+        try (OutputStream out = new FileOutputStream(file)) {
+            IOUtils.copy(in, out);
+            return file;
+        } finally {
+            if (close) {
+                in.close();
+            }
+        }
+    }
+
+    /**
+     * 输出指定文件的byte数组
+     *
+     * @param filePath 文件路径
+     * @param os       输出流
+     * @return
+     */
+    public static void writeBytes(String filePath, OutputStream os) throws IOException {
+        FileInputStream fis = null;
+        try {
+            File file = new File(filePath);
+            if (!file.exists()) {
+                throw new FileNotFoundException(filePath);
+            }
+            fis = new FileInputStream(file);
+            byte[] b = new byte[1024];
+            int length;
+            while ((length = fis.read(b)) > 0) {
+                os.write(b, 0, length);
+            }
+        } catch (IOException e) {
+            throw e;
+        } finally {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException e1) {
+                    e1.printStackTrace();
+                }
+            }
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (IOException e1) {
+                    e1.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * 删除文件
+     *
+     * @param filePath 文件
+     * @return
+     */
+    public static boolean deleteFile(String filePath) {
+        boolean flag = false;
+        File file = new File(filePath);
+        // 路径为文件且不为空则进行删除
+        if (file.isFile() && file.exists()) {
+            file.delete();
+            flag = true;
+        }
+        return flag;
+    }
+
+    /**
+     * 文件名称验证
+     *
+     * @param filename 文件名称
+     * @return true 正常 false 非法
+     */
+    public static boolean isValidFilename(String filename) {
+        return filename.matches(FILENAME_PATTERN);
+    }
+
+    /**
+     * 下载文件名重新编码
+     *
+     * @param request  请求对象
+     * @param fileName 文件名
+     * @return 编码后的文件名
+     */
+    public static String setFileDownloadHeader(HttpServletRequest request, String fileName)
+            throws UnsupportedEncodingException {
+        final String agent = request.getHeader("USER-AGENT");
+        String filename = fileName;
+        if (agent.contains("MSIE")) {
+            // IE浏览器
+            filename = URLEncoder.encode(filename, "utf-8");
+            filename = filename.replace("+", " ");
+        } else if (agent.contains("Firefox")) {
+            // 火狐浏览器
+            filename = new String(fileName.getBytes(), "ISO8859-1");
+        } else if (agent.contains("Chrome")) {
+            // google浏览器
+            filename = URLEncoder.encode(filename, "utf-8");
+        } else {
+            // 其它浏览器
+            filename = URLEncoder.encode(filename, "utf-8");
+        }
+        return filename;
+    }
+
+    /**
+     * 创建文件
+     *
+     * @param path
+     * @param fileName
+     * @return
+     */
+    public static File createFile(String path, String fileName) {
+        if (!path.endsWith("/") && !path.endsWith("\\")) {
+            path += File.separator;
+        }
+        File pathFile = new File(path);
+        if (!pathFile.exists()) {
+            pathFile.mkdirs();
+        }
+        return new File(path + fileName);
+    }
+}

+ 47 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/IdUtils.java

@@ -0,0 +1,47 @@
+package com.zanxiang.common.utils;
+
+
+import com.zanxiang.common.text.UUID;
+
+/**
+ * ID生成器工具类
+ *
+ * @author ruoyi
+ */
+public class IdUtils {
+    /**
+     * 获取随机UUID
+     *
+     * @return 随机UUID
+     */
+    public static String randomUUID() {
+        return UUID.randomUUID().toString();
+    }
+
+    /**
+     * 简化的UUID,去掉了横线
+     *
+     * @return 简化的UUID,去掉了横线
+     */
+    public static String simpleUUID() {
+        return UUID.randomUUID().toString(true);
+    }
+
+    /**
+     * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID
+     *
+     * @return 随机UUID
+     */
+    public static String fastUUID() {
+        return UUID.fastUUID().toString();
+    }
+
+    /**
+     * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
+     *
+     * @return 简化的UUID,去掉了横线
+     */
+    public static String fastSimpleUUID() {
+        return UUID.fastUUID().toString(true);
+    }
+}

+ 39 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/IpUtils.java

@@ -0,0 +1,39 @@
+package com.zanxiang.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+@Slf4j
+public class IpUtils {
+    private static final String UNKNOWN = "unknown";
+    private static final String LOCAL_IP = "127.0.0.1";
+
+    public static String getRealIp(HttpServletRequest request) {
+        String ipAddress = request.getHeader("x-forwarded-for");
+        if (StringUtils.isBlank(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getHeader("Proxy-Client-IP");
+        }
+        if (StringUtils.isBlank(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (StringUtils.isBlank(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getRemoteAddr();
+            if (LOCAL_IP.equals(ipAddress) || "0:0:0:0:0:0:0:1".equals(ipAddress)) {
+                //根据网卡取本机配置的IP
+                try {
+                    ipAddress = InetAddress.getLocalHost().getHostAddress();
+                } catch (UnknownHostException e) {
+                    log.error(e.getMessage(), e);
+                }
+            }
+        }
+        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
+        if (StringUtils.isNotBlank(ipAddress) && ipAddress.contains(",")) { //"***.***.***.***".length() = 15
+            ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
+        }
+        return ipAddress;
+    }
+}

+ 172 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/JsonUtil.java

@@ -0,0 +1,172 @@
+package com.zanxiang.common.utils;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * @Author wcc
+ * @Date 2020/11/17 20:37
+ * @Version 1.0
+ * @Description
+ */
+public class JsonUtil {
+    private static final Logger log = LoggerFactory.getLogger(JsonUtil.class);
+
+    /**
+     * 序列化和反序列化不带 @class属性
+     */
+    public static final ObjectMapper JACKSON = new ObjectMapper()
+            // json字符串转对象多余属性不报错
+            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+            // 对象转 json为 null不显示
+            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+            // 指定要序列化的域,只序列化字段(包括 private字段),不对 get、set及 isXxx进行序列化。ANY指所有作用域的字段,包括 private
+            .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
+            .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
+            .setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
+            .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)
+            .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+
+    /**
+     * 序列化和反序列化带 @class属性
+     */
+    public static final ObjectMapper JACKSON_WITH_CLASS = new ObjectMapper()
+            // json字符串转对象多余属性不报错
+            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+            // 对象转 json为 null不显示
+            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+            // 指定要序列化的域,只序列化字段(包括 private字段),不对 get、set及 isXxx进行序列化。ANY指所有作用域的字段,包括 private
+            .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
+            .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
+            .setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
+            .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE)
+            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
+            .activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
+                    ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY)
+            .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+
+    static {// 解决 java.time包里面的类的序列化问题
+        JACKSON.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+        JACKSON_WITH_CLASS.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+        JavaTimeModule timeModule = new JavaTimeModule();
+        timeModule.addDeserializer(LocalDate.class,
+                new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+        timeModule.addDeserializer(LocalDateTime.class,
+                new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        timeModule.addSerializer(LocalDate.class,
+                new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+        timeModule.addSerializer(LocalDateTime.class,
+                new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        JACKSON.registerModule(timeModule);
+        JACKSON_WITH_CLASS.registerModule(timeModule);
+    }
+
+    public static String toString(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        try {
+            return JACKSON.writeValueAsString(obj);
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public static String toStringWithClass(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        try {
+            return JACKSON_WITH_CLASS.writeValueAsString(obj);
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public static <T> T toObj(String json, Class<T> clazz) {
+        try {
+            return JACKSON.readValue(json, clazz);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public static Object toObjWithClass(String json) {
+        try {
+            return JACKSON_WITH_CLASS.readValue(json, Object.class);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public static <T> Collection<T> toList(String json, Class<? extends Collection> collectionClazz, Class<T> tClass) {
+        try {
+            return JACKSON.readValue(json, JACKSON.getTypeFactory().constructCollectionType(collectionClazz, tClass));
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public static Collection<Object> toListWithClass(String json, Class<? extends Collection> collectionClazz) {
+        try {
+            return JACKSON_WITH_CLASS.readValue(json, JACKSON_WITH_CLASS.getTypeFactory().constructCollectionType(collectionClazz, Object.class));
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public static <V> Map<String, V> toMap(String json, Class<? extends Map> mapClazz, Class<V> vClass) {
+        try {
+            return JACKSON.readValue(json, JACKSON.getTypeFactory().constructMapType(mapClazz, String.class, vClass));
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public static Map<String, Object> toMapWithClass(String json, Class<? extends Map> mapClazz) {
+        try {
+            return JACKSON_WITH_CLASS.readValue(json, JACKSON_WITH_CLASS.getTypeFactory().constructMapType(mapClazz, String.class, Object.class));
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    public static <K, V> Map<K, V> toMap(String json, Class<? extends Map> mapClazz, Class<K> kClass, Class<V> vClass) {
+        try {
+            return JACKSON.readValue(json, JACKSON.getTypeFactory().constructMapType(mapClazz, kClass, vClass));
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage(), e);
+        }
+        return null;
+    }
+}

+ 21 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/KeyBuilder.java

@@ -0,0 +1,21 @@
+package com.zanxiang.common.utils;
+
+/**
+ * <p>
+ * Key生成器
+ * </p>
+ *
+ * @author zhengwangeng
+ * @since 2020/10/19 18:29
+ */
+public final class KeyBuilder {
+
+    public static final char SPLIT = ':';
+
+    private KeyBuilder() {
+    }
+
+    public static String build(Object... array) {
+        return StringUtils.join(array, SPLIT);
+    }
+}

+ 32 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/MathUtil.java

@@ -0,0 +1,32 @@
+package com.zanxiang.common.utils;
+
+import java.math.BigDecimal;
+
+/**
+ * @Author wcc
+ * @Date 2021/1/4 11:47
+ * @Version 1.0
+ * @Description
+ */
+public class MathUtil {
+
+    public static int add(Integer num1, Integer num2) {
+        num1 = num1 == null ? 0 : num1;
+        num2 = num2 == null ? 0 : num2;
+        return num1 + num2;
+    }
+
+    /**
+     * 除法保留 2位小数,多余位删除(除 0返回 0)
+     *
+     * @param dividend 被除数
+     * @param divisor  除数
+     * @return
+     */
+    public static BigDecimal division(BigDecimal dividend, BigDecimal divisor) {
+        if (divisor.compareTo(BigDecimal.ZERO) == 0) {
+            return BigDecimal.ZERO;
+        }
+        return dividend.divide(divisor, 2, BigDecimal.ROUND_DOWN);
+    }
+}

+ 73 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/MimeMapUtil.java

@@ -0,0 +1,73 @@
+package com.zanxiang.common.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Author wcc
+ * @Date 2021/3/31 18:29
+ * @Version 1.0
+ * @Description
+ */
+public class MimeMapUtil {
+    private static final Map<String, String> MIME_MAPPING = new HashMap<>();
+
+    static {
+        // 文档
+        MIME_MAPPING.put("application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx");
+        MIME_MAPPING.put("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx");
+        MIME_MAPPING.put("application/vnd.openxmlformats-officedocument.presentationml.presentation", "pptx");
+        MIME_MAPPING.put("application/msword", "doc");
+        MIME_MAPPING.put("application/vnd.ms-excel", "xls");
+        MIME_MAPPING.put("application/vnd.ms-powerpoint", "ppt");
+        MIME_MAPPING.put("application/pdf", "pdf");
+
+        // 视频
+        MIME_MAPPING.put("video/mp4", "mp4");
+        MIME_MAPPING.put("video/3gpp", "3gp");
+        MIME_MAPPING.put("video/mpeg", "mpeg");
+        MIME_MAPPING.put("video/webm", "webm");
+        MIME_MAPPING.put("video/x-flv", "flv");
+        MIME_MAPPING.put("video/x-m4v", "m4v");
+        MIME_MAPPING.put("video/x-ms-wmv", "wmv");
+        MIME_MAPPING.put("video/x-msvideo", "avi");
+
+        // 音频
+        MIME_MAPPING.put("audio/mp3", "mp3");
+        MIME_MAPPING.put("audio/midi", "mid");
+        MIME_MAPPING.put("audio/ogg", "ogg");
+        MIME_MAPPING.put("audio/x-m4a", "m4a");
+        MIME_MAPPING.put("audio/m4a", "m4a");
+        MIME_MAPPING.put("audio/mpeg", "mp3");
+        MIME_MAPPING.put("audio/x-realaudio", "ra");
+
+        // 文本
+        MIME_MAPPING.put("text/html", "html");
+        MIME_MAPPING.put("text/plain", "txt");
+        MIME_MAPPING.put("application/rtf", "rtf");
+
+        // 压缩文件
+        MIME_MAPPING.put("application/x-7z-compressed", "7z");
+        MIME_MAPPING.put("application/x-rar-compressed", "rar");
+        MIME_MAPPING.put("application/zip", "zip");
+        MIME_MAPPING.put("application/x-zip-compressed", "zip");
+        MIME_MAPPING.put("application/x-gzip", "gz");
+
+        // 图片
+        MIME_MAPPING.put("image/jpeg", "jpg");
+        MIME_MAPPING.put("image/jpg", "jpg");
+        MIME_MAPPING.put("image/png", "png");
+        MIME_MAPPING.put("image/gif", "gif");
+        MIME_MAPPING.put("image/tiff", "tif");
+        MIME_MAPPING.put("image/vnd.wap.wbmp", "wbmp");
+        MIME_MAPPING.put("image/x-icon", "ico");
+        MIME_MAPPING.put("image/x-jng", "jng");
+        MIME_MAPPING.put("image/x-ms-bmp", "bmp");
+        MIME_MAPPING.put("image/svg+xml", "svg");
+        MIME_MAPPING.put("image/webp", "webp");
+    }
+
+    public static String getSuffixByMime(String mime) {
+        return MIME_MAPPING.get(mime);
+    }
+}

+ 102 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/NumberUtil.java

@@ -0,0 +1,102 @@
+package com.zanxiang.common.utils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Date;
+
+/**
+ * @Author wcc
+ * @Date 2020/9/17 19:54
+ * @Version 1.0
+ * @Description
+ */
+public class NumberUtil {
+
+    public static Long toLong(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        if (obj instanceof Integer) {
+            return ((Integer) obj).longValue();
+        }
+        if (obj instanceof Long) {
+            return (Long) obj;
+        }
+        if (obj instanceof String) {
+            return new BigDecimal((String) obj).longValue();
+        }
+        if (obj instanceof BigDecimal) {
+            return ((BigDecimal) obj).longValue();
+        }
+        if (obj instanceof BigInteger) {
+            return ((BigInteger) obj).longValue();
+        }
+        throw new RuntimeException("unknown data type! Class: " + obj.getClass());
+    }
+
+    public static Integer toInt(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        }
+        if (obj instanceof Long) {
+            return ((Long) obj).intValue();
+        }
+        if (obj instanceof String) {
+            return new BigDecimal((String) obj).intValue();
+        }
+        if (obj instanceof BigDecimal) {
+            return ((BigDecimal) obj).intValue();
+        }
+        if (obj instanceof BigInteger) {
+            return ((BigInteger) obj).intValue();
+        }
+        throw new RuntimeException("unknown data type! Class: " + obj.getClass());
+    }
+
+    public static Boolean toBool(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        if (obj instanceof Boolean) {
+            return (Boolean) obj;
+        }
+        if (obj instanceof String) {
+            String temp = (String) obj;
+            temp = temp.toLowerCase();
+            if (temp.equals("true")) {
+                return true;
+            }
+            if (temp.equals("false")) {
+                return false;
+            }
+            try {
+                return new BigDecimal(temp).compareTo(BigDecimal.ZERO) != 0;
+            } catch (Exception e) {
+                throw new RuntimeException("Failed transform String to Boolean! value: " + temp);
+            }
+        }
+        return toLong(obj) != 0;
+    }
+
+    public static LocalDateTime toLocalDateTime(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        if (obj instanceof Date) {
+            return DateUtils.dateToLocalDateTime((Date) obj);
+        }
+        if (obj instanceof LocalDateTime) {
+            return (LocalDateTime) obj;
+        }
+        if (obj instanceof LocalDate) {
+            return LocalDateTime.of((LocalDate) obj, LocalTime.MIDNIGHT);
+        }
+        throw new RuntimeException("unknown data type! Class: " + obj.getClass());
+    }
+}

+ 13 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/ObjectUtil.java

@@ -0,0 +1,13 @@
+package com.zanxiang.common.utils;
+
+public class ObjectUtil {
+    public static <T> boolean objEquals(T t1, T t2) {
+        if (t1 == null && t2 == null) {
+            return true;
+        }
+        if (t1 == null || t2 == null) {
+            return false;
+        }
+        return t1.equals(t2);
+    }
+}

+ 57 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/RandomStringUtil.java

@@ -0,0 +1,57 @@
+package com.zanxiang.common.utils;
+
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class RandomStringUtil {
+    public static final Random RANDOM = ThreadLocalRandom.current();
+    private static final char[] numChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+    private static final char[] abcChars = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
+    private static final char[] ABCChars = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
+    private static final char[] abcNumChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
+
+    public static String randomAbcNumStr(int length, boolean firstNum) {
+        if (length <= 0) {
+            throw new RuntimeException("Random string, length cannot be less than 0");
+        }
+        char[] chars = new char[length];
+        if (firstNum) {
+            for (int i = 0; i < length; i++) {
+                chars[i] = randomChar(abcNumChars);
+            }
+        } else {
+            chars[0] = randomChar(abcChars);
+            for (int i = 1; i < length; i++) {
+                chars[i] = randomChar(abcNumChars);
+            }
+        }
+        return new String(chars);
+    }
+
+    public static String randomNumStr(int length) {
+        if (length <= 0) {
+            throw new RuntimeException("Random string, length cannot be less than 0");
+        }
+        char[] chars = new char[length];
+        for (int i = 0; i < length; i++) {
+            chars[i] = randomChar(numChars);
+        }
+        return new String(chars);
+    }
+
+    public static String randomStr(char[] chars, int length) {
+        if (length <= 0) {
+            throw new RuntimeException("Random string, length cannot be less than 0");
+        }
+        char[] result = new char[length];
+        for (int i = 0; i < length; i++) {
+            result[i] = randomChar(chars);
+        }
+        return new String(result);
+    }
+
+
+    private static char randomChar(char[] chars) {
+        return chars[RANDOM.nextInt(chars.length)];
+    }
+}

+ 348 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/RegexUtil.java

@@ -0,0 +1,348 @@
+package com.zanxiang.common.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author yj
+ * @date 2020/9/22 5:43 下午
+ */
+public class RegexUtil {
+
+
+    /**
+     * Regex of simple mobile.
+     */
+    public static final String REGEX_MOBILE_SIMPLE = "^[1]\\d{10}$";
+    /**
+     * Regex of exact mobile.
+     * <p>china mobile: 134(0-8), 135, 136, 137, 138, 139, 147, 150, 151, 152, 157, 158, 159, 178, 182, 183, 184, 187, 188, 198</p>
+     * <p>china unicom: 130, 131, 132, 145, 155, 156, 166, 171, 175, 176, 185, 186</p>
+     * <p>china telecom: 133, 153, 173, 177, 180, 181, 189, 199</p>
+     * <p>global star: 1349</p>
+     * <p>virtual operator: 170</p>
+     */
+    public static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(16[6])|(17[0,1,3,5-8])|(18[0-9])|(19[0,2,6-9]))\\d{8}$";
+    /**
+     * Regex of telephone number.
+     */
+    public static final String REGEX_TEL = "^0\\d{2,3}[- ]?\\d{7,8}";
+    /**
+     * Regex of id card number which length is 15.
+     */
+    public static final String REGEX_ID_CARD15 = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$";
+    /**
+     * Regex of id card number which length is 18.
+     */
+    public static final String REGEX_ID_CARD18 = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9Xx])$";
+    /**
+     * Regex of email.
+     */
+    public static final String REGEX_EMAIL = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";
+    /**
+     * Regex of url.
+     */
+    public static final String REGEX_URL = "[a-zA-z]+://[^\\s]*";
+    /**
+     * Regex of Chinese character.
+     */
+    public static final String REGEX_ZH = "^[\\u4e00-\\u9fa5]+$";
+    /**
+     * Regex of username.
+     * <p>scope for "a-z", "A-Z", "0-9", "_", "Chinese character"</p>
+     * <p>can't end with "_"</p>
+     * <p>length is between 6 to 20</p>
+     */
+    public static final String REGEX_USERNAME = "^[\\w\\u4e00-\\u9fa5]{6,20}(?<!_)$";
+    /**
+     * Regex of date which pattern is "yyyy-MM-dd".
+     */
+    public static final String REGEX_DATE = "^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$";
+    /**
+     * Regex of ip address.
+     */
+    public static final String REGEX_IP = "((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)";
+
+    ///////////////////////////////////////////////////////////////////////////
+    // The following come from http://tool.oschina.net/regex
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Regex of double-byte characters.
+     */
+    public static final String REGEX_DOUBLE_BYTE_CHAR = "[^\\x00-\\xff]";
+    /**
+     * Regex of blank line.
+     */
+    public static final String REGEX_BLANK_LINE = "\\n\\s*\\r";
+    /**
+     * Regex of QQ number.
+     */
+    public static final String REGEX_QQ_NUM = "[1-9][0-9]{4,}";
+    /**
+     * Regex of postal code in China.
+     */
+    public static final String REGEX_CHINA_POSTAL_CODE = "[1-9]\\d{5}(?!\\d)";
+    /**
+     * Regex of positive integer.
+     */
+    public static final String REGEX_POSITIVE_INTEGER = "^[1-9]\\d*$";
+    /**
+     * Regex of negative integer.
+     */
+    public static final String REGEX_NEGATIVE_INTEGER = "^-[1-9]\\d*$";
+    /**
+     * Regex of integer.
+     */
+    public static final String REGEX_INTEGER = "^-?[1-9]\\d*$";
+    /**
+     * Regex of non-negative integer.
+     */
+    public static final String REGEX_NOT_NEGATIVE_INTEGER = "^[1-9]\\d*|0$";
+    /**
+     * Regex of non-positive integer.
+     */
+    public static final String REGEX_NOT_POSITIVE_INTEGER = "^-[1-9]\\d*|0$";
+    /**
+     * Regex of positive float.
+     */
+    public static final String REGEX_POSITIVE_FLOAT = "^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$";
+    /**
+     * Regex of negative float.
+     */
+    public static final String REGEX_NEGATIVE_FLOAT = "^-[1-9]\\d*\\.\\d*|-0\\.\\d*[1-9]\\d*$";
+
+    public static final String REGEX_BLANK_CHARACTER = "\\s*";
+
+
+    private RegexUtil() {
+        throw new UnsupportedOperationException("u can't instantiate me...");
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // If u want more please visit http://toutiao.com/i6231678548520731137
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Return whether input matches regex of simple mobile.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isMobileSimple(final CharSequence input) {
+        return isMatch(REGEX_MOBILE_SIMPLE, input);
+    }
+
+    /**
+     * Return whether input matches regex of exact mobile.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isMobileExact(final CharSequence input) {
+        return isMatch(REGEX_MOBILE_EXACT, input);
+    }
+
+    /**
+     * Return whether input matches regex of telephone number.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isTel(final CharSequence input) {
+        return isMatch(REGEX_TEL, input);
+    }
+
+    /**
+     * Return whether input matches regex of id card number which length is 15.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isIDCard15(final CharSequence input) {
+        return isMatch(REGEX_ID_CARD15, input);
+    }
+
+    /**
+     * Return whether input matches regex of id card number which length is 18.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isIDCard18(final CharSequence input) {
+        return isMatch(REGEX_ID_CARD18, input);
+    }
+
+    /**
+     * Return whether input matches regex of email.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isEmail(final CharSequence input) {
+        return isMatch(REGEX_EMAIL, input);
+    }
+
+    /**
+     * Return whether input matches regex of url.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isURL(final CharSequence input) {
+        return isMatch(REGEX_URL, input);
+    }
+
+    /**
+     * Return whether input matches regex of Chinese character.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isZh(final CharSequence input) {
+        return isMatch(REGEX_ZH, input);
+    }
+
+    /**
+     * Return whether input matches regex of username.
+     * <p>scope for "a-z", "A-Z", "0-9", "_", "Chinese character"</p>
+     * <p>can't end with "_"</p>
+     * <p>length is between 6 to 20</p>.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isUsername(final CharSequence input) {
+        return isMatch(REGEX_USERNAME, input);
+    }
+
+    /**
+     * Return whether input matches regex of date which pattern is "yyyy-MM-dd".
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isDate(final CharSequence input) {
+        return isMatch(REGEX_DATE, input);
+    }
+
+    /**
+     * Return whether input matches regex of ip address.
+     *
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isIP(final CharSequence input) {
+        return isMatch(REGEX_IP, input);
+    }
+
+    /**
+     * Return whether input matches the regex.
+     *
+     * @param regex The regex.
+     * @param input The input.
+     * @return {@code true}: yes<br>{@code false}: no
+     */
+    public static boolean isMatch(final String regex, final CharSequence input) {
+        return input != null && input.length() > 0 && Pattern.matches(regex, input);
+    }
+
+    /**
+     * Return the list of input matches the regex.
+     *
+     * @param regex The regex.
+     * @param input The input.
+     * @return the list of input matches the regex
+     */
+    public static List<String> getMatches(final String regex, final CharSequence input) {
+        if (input == null) {
+            return Collections.emptyList();
+        }
+        List<String> matches = new ArrayList<>();
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(input);
+        while (matcher.find()) {
+            matches.add(matcher.group());
+        }
+        return matches;
+    }
+
+    /**
+     * Splits input around matches of the regex.
+     *
+     * @param input The input.
+     * @param regex The regex.
+     * @return the array of strings computed by splitting input around matches of regex
+     */
+    public static String[] getSplits(final String input, final String regex) {
+        if (input == null) {
+            return new String[0];
+        }
+        return input.split(regex);
+    }
+
+    /**
+     * Replace the first subsequence of the input sequence that matches the
+     * regex with the given replacement string.
+     *
+     * @param input       The input.
+     * @param regex       The regex.
+     * @param replacement The replacement string.
+     * @return the string constructed by replacing the first matching
+     * subsequence by the replacement string, substituting captured
+     * subsequences as needed
+     */
+    public static String getReplaceFirst(final String input,
+                                         final String regex,
+                                         final String replacement) {
+        if (input == null) {
+            return "";
+        }
+        return Pattern.compile(regex).matcher(input).replaceFirst(replacement);
+    }
+
+    /**
+     * Replace every subsequence of the input sequence that matches the
+     * pattern with the given replacement string.
+     *
+     * @param input       The input.
+     * @param regex       The regex.
+     * @param replacement The replacement string.
+     * @return the string constructed by replacing each matching subsequence
+     * by the replacement string, substituting captured subsequences
+     * as needed
+     */
+    public static String getReplaceAll(final String input,
+                                       final String regex,
+                                       final String replacement) {
+        if (input == null) {
+            return "";
+        }
+        return Pattern.compile(regex).matcher(input).replaceAll(replacement);
+    }
+
+    /**
+     * 将一个普通文本里面带有正则表达式特殊字符的字符进行转义
+     * ex:你好?->你好\?
+     *
+     * @param text
+     * @return
+     */
+    public static String normalText(String text) {
+        return text.replaceAll("\\$", "\\\\$")
+                .replaceAll("\\(", "\\\\(")
+                .replaceAll("\\)", "\\\\)")
+                .replaceAll("\\*", "\\\\*")
+                .replaceAll("\\+", "\\\\+")
+                .replaceAll("\\.", "\\\\.")
+                .replaceAll("\\[", "\\\\[")
+                .replaceAll("\\?", "\\\\?")
+                .replaceAll("\\\\", "\\\\")
+                .replaceAll("\\^", "\\\\^")
+                .replaceAll("\\{", "\\\\{")
+                .replaceAll("\\|", "\\\\|");
+    }
+}

+ 102 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/SpringUtils.java

@@ -0,0 +1,102 @@
+package com.zanxiang.common.utils;
+
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring工具类 方便在非spring管理环境中获取bean
+ *
+ * @author ruoyi
+ */
+@Component
+public final class SpringUtils implements BeanFactoryPostProcessor {
+    /**
+     * Spring应用上下文环境
+     */
+    private static ConfigurableListableBeanFactory beanFactory;
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+        SpringUtils.beanFactory = beanFactory;
+    }
+
+    /**
+     * 获取对象
+     *
+     * @param name
+     * @return Object 一个以所给名字注册的bean的实例
+     * @throws BeansException
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name) throws BeansException {
+        return (T) beanFactory.getBean(name);
+    }
+
+    /**
+     * 获取类型为requiredType的对象
+     *
+     * @param clz
+     * @return
+     * @throws BeansException
+     */
+    public static <T> T getBean(Class<T> clz) throws BeansException {
+        T result = (T) beanFactory.getBean(clz);
+        return result;
+    }
+
+    /**
+     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
+     *
+     * @param name
+     * @return boolean
+     */
+    public static boolean containsBean(String name) {
+        return beanFactory.containsBean(name);
+    }
+
+    /**
+     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
+     *
+     * @param name
+     * @return boolean
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.isSingleton(name);
+    }
+
+    /**
+     * @param name
+     * @return Class 注册对象的类型
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.getType(name);
+    }
+
+    /**
+     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
+     *
+     * @param name
+     * @return
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 获取aop代理对象
+     *
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker) {
+        return (T) AopContext.currentProxy();
+    }
+}

+ 356 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/StringUtils.java

@@ -0,0 +1,356 @@
+package com.zanxiang.common.utils;
+
+import com.zanxiang.common.text.StrFormatter;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * 字符串工具类
+ *
+ * @author ruoyi
+ */
+public class StringUtils extends org.apache.commons.lang.StringUtils {
+    /**
+     * 空字符串
+     */
+    private static final String NULLSTR = "";
+
+    /**
+     * 下划线
+     */
+    private static final char SEPARATOR = '_';
+
+
+    public static String trimBlank(String str) {
+        return str.replaceAll(RegexUtil.REGEX_BLANK_CHARACTER, "");
+    }
+
+    /**
+     * 获取参数不为空值
+     *
+     * @param value defaultValue 要判断的value
+     * @return value 返回值
+     */
+    public static <T> T nvl(T value, T defaultValue) {
+        return value != null ? value : defaultValue;
+    }
+
+    /**
+     * * 判断一个Collection是否为空, 包含List,Set,Queue
+     *
+     * @param coll 要判断的Collection
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Collection<?> coll) {
+        return isNull(coll) || coll.isEmpty();
+    }
+
+    /**
+     * * 判断一个Collection是否非空,包含List,Set,Queue
+     *
+     * @param coll 要判断的Collection
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Collection<?> coll) {
+        return !isEmpty(coll);
+    }
+
+    /**
+     * * 判断一个对象数组是否为空
+     *
+     * @param objects 要判断的对象数组
+     *                * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Object[] objects) {
+        return isNull(objects) || (objects.length == 0);
+    }
+
+    /**
+     * * 判断一个对象数组是否非空
+     *
+     * @param objects 要判断的对象数组
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Object[] objects) {
+        return !isEmpty(objects);
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     *
+     * @param map 要判断的Map
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Map<?, ?> map) {
+        return isNull(map) || map.isEmpty();
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     *
+     * @param map 要判断的Map
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Map<?, ?> map) {
+        return !isEmpty(map);
+    }
+
+    /**
+     * * 判断一个字符串是否为空串
+     *
+     * @param str String
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(String str) {
+        return isNull(str) || NULLSTR.equals(str.trim());
+    }
+
+    /**
+     * * 判断一个字符串是否为非空串
+     *
+     * @param str String
+     * @return true:非空串 false:空串
+     */
+    public static boolean isNotEmpty(String str) {
+        return !isEmpty(str);
+    }
+
+    /**
+     * * 判断一个对象是否为空
+     *
+     * @param object Object
+     * @return true:为空 false:非空
+     */
+    public static boolean isNull(Object object) {
+        return object == null;
+    }
+
+    /**
+     * * 判断一个对象是否非空
+     *
+     * @param object Object
+     * @return true:非空 false:空
+     */
+    public static boolean isNotNull(Object object) {
+        return !isNull(object);
+    }
+
+    /**
+     * * 判断一个对象是否是数组类型(Java基本型别的数组)
+     *
+     * @param object 对象
+     * @return true:是数组 false:不是数组
+     */
+    public static boolean isArray(Object object) {
+        return isNotNull(object) && object.getClass().isArray();
+    }
+
+    /**
+     * 去空格
+     */
+    public static String trim(String str) {
+        return (str == null ? "" : str.trim());
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str   字符串
+     * @param start 开始
+     * @return 结果
+     */
+    public static String substring(final String str, int start) {
+        if (str == null) {
+            return NULLSTR;
+        }
+
+        if (start < 0) {
+            start = str.length() + start;
+        }
+
+        if (start < 0) {
+            start = 0;
+        }
+        if (start > str.length()) {
+            return NULLSTR;
+        }
+
+        return str.substring(start);
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str   字符串
+     * @param start 开始
+     * @param end   结束
+     * @return 结果
+     */
+    public static String substring(final String str, int start, int end) {
+        if (str == null) {
+            return NULLSTR;
+        }
+
+        if (end < 0) {
+            end = str.length() + end;
+        }
+        if (start < 0) {
+            start = str.length() + start;
+        }
+
+        if (end > str.length()) {
+            end = str.length();
+        }
+
+        if (start > end) {
+            return NULLSTR;
+        }
+
+        if (start < 0) {
+            start = 0;
+        }
+        if (end < 0) {
+            end = 0;
+        }
+
+        return str.substring(start, end);
+    }
+
+    /**
+     * 格式化文本, {} 表示占位符<br>
+     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
+     * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
+     * 例:<br>
+     * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     *
+     * @param template 文本模板,被替换的部分用 {} 表示
+     * @param params   参数值
+     * @return 格式化后的文本
+     */
+    public static String format(String template, Object... params) {
+        if (isEmpty(params) || isEmpty(template)) {
+            return template;
+        }
+        return StrFormatter.format(template, params);
+    }
+
+    /**
+     * 下划线转驼峰命名
+     */
+    public static String toUnderScoreCase(String str) {
+        if (str == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        // 前置字符是否大写
+        boolean preCharIsUpperCase = true;
+        // 当前字符是否大写
+        boolean curreCharIsUpperCase = true;
+        // 下一字符是否大写
+        boolean nexteCharIsUpperCase = true;
+        for (int i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            if (i > 0) {
+                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
+            } else {
+                preCharIsUpperCase = false;
+            }
+
+            curreCharIsUpperCase = Character.isUpperCase(c);
+
+            if (i < (str.length() - 1)) {
+                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
+            }
+
+            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
+                sb.append(SEPARATOR);
+            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
+                sb.append(SEPARATOR);
+            }
+            sb.append(Character.toLowerCase(c));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 是否包含字符串
+     *
+     * @param str  验证字符串
+     * @param strs 字符串组
+     * @return 包含返回true
+     */
+    public static boolean inStringIgnoreCase(String str, String... strs) {
+        if (str != null && strs != null) {
+            for (String s : strs) {
+                if (str.equalsIgnoreCase(trim(s))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
+     *
+     * @param name 转换前的下划线大写方式命名的字符串
+     * @return 转换后的驼峰式命名的字符串
+     */
+    public static String convertToCamelCase(String name) {
+        StringBuilder result = new StringBuilder();
+        // 快速检查
+        if (name == null || name.isEmpty()) {
+            // 没必要转换
+            return "";
+        } else if (!name.contains("_")) {
+            // 不含下划线,仅将首字母大写
+            return name.substring(0, 1).toUpperCase() + name.substring(1);
+        }
+        // 用下划线将原始字符串分割
+        String[] camels = name.split("_");
+        for (String camel : camels) {
+            // 跳过原始字符串中开头、结尾的下换线或双重下划线
+            if (camel.isEmpty()) {
+                continue;
+            }
+            // 首字母大写
+            result.append(camel.substring(0, 1).toUpperCase());
+            result.append(camel.substring(1).toLowerCase());
+        }
+        return result.toString();
+    }
+
+    /**
+     * 驼峰式命名法 例如:user_name->userName
+     */
+    public static String toCamelCase(String s) {
+        if (s == null) {
+            return null;
+        }
+        s = s.toLowerCase();
+        StringBuilder sb = new StringBuilder(s.length());
+        boolean upperCase = false;
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+
+            if (c == SEPARATOR) {
+                upperCase = true;
+            } else if (upperCase) {
+                sb.append(Character.toUpperCase(c));
+                upperCase = false;
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T cast(Object obj) {
+        return (T) obj;
+    }
+}

+ 149 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/URIUtil.java

@@ -0,0 +1,149 @@
+package com.zanxiang.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.Assert;
+
+import java.io.UnsupportedEncodingException;
+import java.net.InetSocketAddress;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Map;
+
+/**
+ * @Author wcc
+ * @Date 2020/12/28 11:36
+ * @Version 1.0
+ * @Description
+ */
+@Slf4j
+public class URIUtil {
+
+    /**
+     * 填充 url的请求参数,如果 params的值为空,不会写在 url上
+     *
+     * @param url
+     * @param params
+     * @return
+     */
+    public static String fillUrlParams(String url, Map<String, String> params, boolean ignoreBlank) {
+        if (params == null || params.isEmpty()) {
+            return url;
+        }
+        boolean first = !url.contains("?");
+        StringBuilder urlBuilder = new StringBuilder(url);
+        for (Map.Entry<String, String> param : params.entrySet()) {
+            if (ignoreBlank && StringUtils.isBlank(param.getValue())) {
+                continue;
+            }
+            if (first) {
+                urlBuilder.append("?");
+                first = false;
+            } else {
+                urlBuilder.append("&");
+            }
+            urlBuilder.append(param.getKey()).append("=").append(StringUtils.isBlank(param.getValue()) ? "" : param.getValue());
+        }
+        url = urlBuilder.toString();
+        return url;
+    }
+
+    /**
+     * 对应 js中的 encodeURIComponent
+     *
+     * @param uri
+     * @return
+     */
+    public static String encodeURIComponent(String uri) {
+        return encodeURIComponent(uri, "UTF-8");
+    }
+
+    /**
+     * 对应 js中的 encodeURIComponent
+     *
+     * @param uri
+     * @return
+     */
+    public static String encodeURIComponent(String uri, String enc) {
+        try {
+            return URLEncoder.encode(uri, enc)
+                    .replaceAll("\\+", "%20")
+                    .replaceAll("\\!", "%21")
+                    .replaceAll("\\'", "%27")
+                    .replaceAll("\\(", "%28")
+                    .replaceAll("\\)", "%29")
+                    .replaceAll("\\~", "%7E");
+        } catch (UnsupportedEncodingException e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 对应 js的 decodeURIComponent
+     *
+     * @param uri
+     * @return
+     */
+    public static String decodeURIComponent(String uri) {
+        return decodeURIComponent(uri, "UTF-8");
+    }
+
+    /**
+     * 对应 js的 decodeURIComponent
+     *
+     * @param uri
+     * @return
+     */
+    public static String decodeURIComponent(String uri, String enc) {
+        try {
+            return URLDecoder.decode(uri.replaceAll("%20", "+")
+                    .replaceAll("%21", "!")
+                    .replaceAll("%27", "'")
+                    .replaceAll("%28", "(")
+                    .replaceAll("%29", ")")
+                    .replaceAll("%7E", "~"), enc);
+        } catch (UnsupportedEncodingException e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+    }
+
+    public static InetSocketAddress parseURI(String uri, int defaultPort) {
+        Assert.notNull(uri, "uri must not be null");
+        String host;
+        String portString = null;
+
+        int colonPos = uri.indexOf(':');
+        if (colonPos >= 0 && uri.indexOf(':', colonPos + 1) == -1) {
+            // Exactly 1 colon. Split into host:port.
+            host = uri.substring(0, colonPos);
+            portString = uri.substring(colonPos + 1);
+        } else {
+            // 0 or 2+ colons. Bare hostname or IPv6 literal.
+            host = uri;
+        }
+
+        int port = defaultPort;
+        if (StringUtils.isNotBlank(portString)) {
+            // Try to parse the whole port string as a number.
+            Assert.isTrue(!portString.startsWith("+"), String.format("Cannot parse port number: %s", uri));
+            try {
+                port = Integer.parseInt(portString);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException(String.format("Cannot parse port number: %s", uri));
+            }
+
+            Assert.isTrue(isValidPort(port), String.format("Port number out of range: %s", uri));
+        }
+
+        return InetSocketAddress.createUnresolved(host, port);
+    }
+
+    /**
+     * @param port the port number
+     * @return {@literal true} for valid port numbers.
+     */
+    private static boolean isValidPort(int port) {
+        return port >= 0 && port <= 65535;
+    }
+}

+ 144 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/bean/BeanUtils.java

@@ -0,0 +1,144 @@
+package com.zanxiang.common.utils.bean;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Bean 工具类
+ *
+ * @author ruoyi
+ */
+public class BeanUtils extends org.springframework.beans.BeanUtils {
+    /**
+     * Bean方法名中属性名开始的下标
+     */
+    private static final int BEAN_METHOD_PROP_INDEX = 3;
+
+    /**
+     * 匹配getter方法的正则表达式
+     */
+    private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
+
+    /**
+     * 匹配setter方法的正则表达式
+     */
+    private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");
+
+    /**
+     * 对象浅拷贝
+     *
+     * @param source
+     * @param target
+     * @param <T>
+     * @return
+     */
+    public static <T> T copy(Object source, Class<T> target) {
+        if (source == null) {
+            return null;
+        }
+        T obj = instantiateClass(target);
+        copyProperties(source, obj);
+        return obj;
+    }
+
+    /**
+     * 对象浅拷贝
+     *
+     * @param sourceList
+     * @param target
+     * @param <T>
+     * @return
+     */
+    public static <T> List<T> copyList(Collection sourceList, Class<T> target) {
+        if (sourceList == null || sourceList.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<T> objs = new ArrayList<>(sourceList.size());
+        for (Object source : sourceList) {
+            objs.add(copy(source, target));
+        }
+        return objs;
+    }
+
+    /**
+     * 获取对象的setter方法。
+     *
+     * @param obj 对象
+     * @return 对象的setter方法列表
+     */
+    public static List<Method> getSetterMethods(Object obj) {
+        // setter方法列表
+        List<Method> setterMethods = new ArrayList<Method>();
+
+        // 获取所有方法
+        Method[] methods = obj.getClass().getMethods();
+
+        // 查找setter方法
+
+        for (Method method : methods) {
+            Matcher m = SET_PATTERN.matcher(method.getName());
+            if (m.matches() && (method.getParameterTypes().length == 1)) {
+                setterMethods.add(method);
+            }
+        }
+        // 返回setter方法列表
+        return setterMethods;
+    }
+
+    /**
+     * 获取对象的getter方法。
+     *
+     * @param obj 对象
+     * @return 对象的getter方法列表
+     */
+
+    public static List<Method> getGetterMethods(Object obj) {
+        // getter方法列表
+        List<Method> getterMethods = new ArrayList<Method>();
+        // 获取所有方法
+        Method[] methods = obj.getClass().getMethods();
+        // 查找getter方法
+        for (Method method : methods) {
+            Matcher m = GET_PATTERN.matcher(method.getName());
+            if (m.matches() && (method.getParameterTypes().length == 0)) {
+                getterMethods.add(method);
+            }
+        }
+        // 返回getter方法列表
+        return getterMethods;
+    }
+
+    /**
+     * 检查Bean方法名中的属性名是否相等。<br>
+     * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。
+     *
+     * @param m1 方法名1
+     * @param m2 方法名2
+     * @return 属性名一样返回true,否则返回false
+     */
+
+    public static boolean isMethodPropEquals(String m1, String m2) {
+        return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
+    }
+
+    /**
+     * 将对象转为map
+     *
+     * @param obj
+     * @return
+     */
+    public static Map<String, String> parseObj2Map(Object obj) throws IllegalAccessException {
+        Map<String, String> map = new HashMap();
+        Field[] declaredFields = obj.getClass().getDeclaredFields();
+        for (Field field : declaredFields) {
+            field.setAccessible(true);
+            if (Objects.nonNull(field.get(obj))) {
+                map.put(field.getName(), field.get(obj).toString());
+            }
+        }
+        return map;
+    }
+}

+ 139 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/http/AjaxResult.java

@@ -0,0 +1,139 @@
+package com.zanxiang.common.utils.http;
+
+import com.zanxiang.common.utils.StringUtils;
+
+import java.util.HashMap;
+
+/**
+ * 操作消息提醒
+ */
+public class AjaxResult<T> extends HashMap<String, Object> {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 状态码
+     */
+    public static final String CODE_TAG = "code";
+
+    /**
+     * 返回内容
+     */
+    public static final String MSG_TAG = "msg";
+
+    /**
+     * 数据对象
+     */
+    public static final String DATA_TAG = "data";
+
+    /**
+     * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
+     */
+    public AjaxResult() {
+    }
+
+    /**
+     * 初始化一个新创建的 AjaxResult 对象
+     *
+     * @param code 状态码
+     * @param msg  返回内容
+     */
+    public AjaxResult(int code, String msg) {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+    }
+
+    /**
+     * 初始化一个新创建的 AjaxResult 对象
+     *
+     * @param code 状态码
+     * @param msg  返回内容
+     * @param data 数据对象
+     */
+    public AjaxResult(int code, String msg, T data) {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+        if (StringUtils.isNotNull(data)) {
+            super.put(DATA_TAG, data);
+        }
+    }
+
+    /**
+     * 返回成功消息
+     *
+     * @return 成功消息
+     */
+    public static <T> AjaxResult<T> success() {
+        return AjaxResult.success("操作成功");
+    }
+
+    /**
+     * 返回成功数据
+     *
+     * @return 成功消息
+     */
+    public static <T> AjaxResult<T> success(T data) {
+        return AjaxResult.success("操作成功", data);
+    }
+
+    /**
+     * 返回成功消息
+     *
+     * @param msg 返回内容
+     * @return 成功消息
+     */
+    public static <T> AjaxResult<T> success(String msg) {
+        return AjaxResult.success(msg, null);
+    }
+
+    /**
+     * 返回成功消息
+     *
+     * @param msg  返回内容
+     * @param data 数据对象
+     * @return 成功消息
+     */
+    public static <T> AjaxResult<T> success(String msg, T data) {
+        return new AjaxResult<>(HttpStatus.SUCCESS, msg, data);
+    }
+
+    /**
+     * 返回错误消息
+     *
+     * @return
+     */
+    public static <T> AjaxResult<T> error() {
+        return AjaxResult.error("操作失败");
+    }
+
+    /**
+     * 返回错误消息
+     *
+     * @param msg 返回内容
+     * @return 警告消息
+     */
+    public static <T> AjaxResult<T> error(String msg) {
+        return AjaxResult.error(msg, null);
+    }
+
+    /**
+     * 返回错误消息
+     *
+     * @param msg  返回内容
+     * @param data 数据对象
+     * @return 警告消息
+     */
+    public static <T> AjaxResult<T> error(String msg, T data) {
+        return new AjaxResult<>(HttpStatus.ERROR, msg, data);
+    }
+
+    /**
+     * 返回错误消息
+     *
+     * @param code 状态码
+     * @param msg  返回内容
+     * @return 警告消息
+     */
+    public static <T> AjaxResult<T> error(int code, String msg) {
+        return new AjaxResult<>(code, msg, null);
+    }
+}

+ 88 - 0
game-module/game-common/src/main/java/com/zanxiang/common/utils/http/HttpStatus.java

@@ -0,0 +1,88 @@
+package com.zanxiang.common.utils.http;
+
+/**
+ * 返回状态码
+ *
+ * @author ruoyi
+ */
+public class HttpStatus {
+    /**
+     * 操作成功
+     */
+    public static final int SUCCESS = 200;
+
+    /**
+     * 对象创建成功
+     */
+    public static final int CREATED = 201;
+
+    /**
+     * 请求已经被接受
+     */
+    public static final int ACCEPTED = 202;
+
+    /**
+     * 操作已经执行成功,但是没有返回数据
+     */
+    public static final int NO_CONTENT = 204;
+
+    /**
+     * 资源已被移除
+     */
+    public static final int MOVED_PERM = 301;
+
+    /**
+     * 重定向
+     */
+    public static final int SEE_OTHER = 303;
+
+    /**
+     * 资源没有被修改
+     */
+    public static final int NOT_MODIFIED = 304;
+
+    /**
+     * 参数列表错误(缺少,格式不匹配)
+     */
+    public static final int BAD_REQUEST = 400;
+
+    /**
+     * 未授权
+     */
+    public static final int UNAUTHORIZED = 401;
+
+    /**
+     * 访问受限,授权过期
+     */
+    public static final int FORBIDDEN = 403;
+
+    /**
+     * 资源,服务未找到
+     */
+    public static final int NOT_FOUND = 404;
+
+    /**
+     * 不允许的http方法
+     */
+    public static final int BAD_METHOD = 405;
+
+    /**
+     * 资源冲突,或者资源被锁
+     */
+    public static final int CONFLICT = 409;
+
+    /**
+     * 不支持的数据,媒体类型
+     */
+    public static final int UNSUPPORTED_TYPE = 415;
+
+    /**
+     * 系统内部错误
+     */
+    public static final int ERROR = 500;
+
+    /**
+     * 接口未实现
+     */
+    public static final int NOT_IMPLEMENTED = 501;
+}

+ 3 - 20
game-module/game-manage/pom.xml

@@ -8,30 +8,13 @@
         <version>0.0.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
-
     <artifactId>game-manage</artifactId>
 
     <dependencies>
         <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
-
-        <!-- nacos配置中心 -->
-        <dependency>
-            <groupId>com.alibaba.cloud</groupId>
-            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
-        </dependency>
-        <!-- nacos注册中心 -->
-        <dependency>
-            <groupId>com.alibaba.cloud</groupId>
-            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>test</scope>
+            <groupId>com.zanxiang.game</groupId>
+            <artifactId>game-common</artifactId>
+            <version>${game-common.vertion}</version>
         </dependency>
     </dependencies>
 

+ 26 - 0
game-module/game-manage/src/main/java/com/zanxiang/manage/ManageApplication.java

@@ -0,0 +1,26 @@
+package com.zanxiang.manage;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+
+@Slf4j
+@EnableDiscoveryClient
+@SpringBootApplication
+public class ManageApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(ManageApplication.class, args);
+		System.out.println("赞象Manage服务启动成功 ( ´・・)ノ(._.`) \n" +
+				" ______  __     __     \n" +
+				"/_____/\\/__/\\ /__/\\    \n" +
+				"\\:::__\\/\\ \\::\\\\:.\\ \\   \n" +
+				"   /: /  \\_\\::_\\:_\\/   \n" +
+				"  /::/___  _\\/__\\_\\_/\\ \n" +
+				" /_:/____/\\\\ \\ \\ \\::\\ \\\n" +
+				" \\_______\\/ \\_\\/  \\__\\/\n");
+	}
+
+}

+ 45 - 0
game-module/game-manage/src/main/java/com/zanxiang/manage/controller/DemoController.java

@@ -0,0 +1,45 @@
+package com.zanxiang.manage.controller;
+
+import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.common.utils.bean.BeanUtils;
+import com.zanxiang.manage.domain.entity.Demo;
+import com.zanxiang.manage.domain.vo.DemoVO;
+import com.zanxiang.manage.service.DemoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * demo示例
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+@Api(tags = "demo示例")
+@RestController
+@RequestMapping("/demo")
+public class DemoController {
+
+    @Autowired
+    private DemoService demoService;
+
+    @GetMapping("/info")
+    @ApiOperation("/info")
+    public ResultVo<DemoVO> getDemo(@RequestParam(name = "id", defaultValue = "1", required = false) String id) {
+        Demo demo = demoService.getById(id);
+        return ResultVo.ok(BeanUtils.copy(demo, DemoVO.class));
+    }
+
+    @GetMapping("/add")
+    @ApiOperation("/add")
+    public ResultVo<Boolean> addDemo(@RequestParam("name") String name, @RequestParam("content") String content) {
+        Demo demo = new Demo();
+        demo.setContent(content);
+        demo.setName(name);
+        return ResultVo.ok(demoService.save(demo));
+    }
+}

+ 28 - 0
game-module/game-manage/src/main/java/com/zanxiang/manage/controller/TestController.java

@@ -0,0 +1,28 @@
+package com.zanxiang.manage.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.jni.Time;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@Api(tags = {"示例接口"})
+@RestController
+@RequestMapping("/game/test/")
+@Slf4j
+@Component
+public class TestController {
+
+    @ApiOperation(value = "根据id获取")
+    @GetMapping("/index")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功")})
+    public String index() {
+        return "game-manage service" + new Time();
+    }
+}

+ 45 - 0
game-module/game-manage/src/main/java/com/zanxiang/manage/domain/entity/Demo.java

@@ -0,0 +1,45 @@
+package com.zanxiang.manage.domain.entity;
+
+import java.io.Serializable;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.IdType;
+
+/**
+ * 注释
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+
+public class Demo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 是否启用
+     */
+    private Integer isEnable;
+
+    /**
+     * 内容
+     */
+    private String content;
+}

+ 33 - 0
game-module/game-manage/src/main/java/com/zanxiang/manage/domain/vo/DemoVO.java

@@ -0,0 +1,33 @@
+package com.zanxiang.manage.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+
+@Data
+public class DemoVO {
+
+    private static final long serialVersionUID = 1L;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long id;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 是否启用
+     */
+    private Integer isEnable;
+
+    /**
+     * 内容
+     */
+    private String content;
+
+}

+ 62 - 0
game-module/game-manage/src/main/java/com/zanxiang/manage/mapper/DemoMapper.java

@@ -0,0 +1,62 @@
+package com.zanxiang.manage.mapper;
+
+import org.apache.ibatis.annotations.Mapper;
+import com.zanxiang.manage.domain.entity.Demo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * 注释 Mapper
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+@Mapper
+public interface DemoMapper extends BaseMapper<Demo> {
+
+    /**
+     * 根据主键id查询
+     *
+     * @param id
+     * @return 记录信息
+     */
+    Demo selectByPrimaryKey(Long id);
+
+    /**
+     * 根据主键删除数据
+     *
+     * @param id
+     * @return 数量
+     */
+    int deleteByPrimaryKey(Long id);
+
+    /**
+     * 插入数据库记录(不建议使用)
+     *
+     * @param record
+     */
+    int insert(Demo record);
+
+    /**
+     * 插入数据库记录(建议使用)
+     *
+     * @param record 插入数据
+     * @return 插入数量
+     */
+    int insertSelective(Demo record);
+
+    /**
+     * 修改数据(推荐使用)
+     *
+     * @param record 更新值
+     * @return 更新数量
+     */
+    int updateByPrimaryKeySelective(Demo record);
+
+    /**
+     * 根据主键更新数据
+     *
+     * @param record 更新值
+     * @return 更新数量
+     */
+    int updateByPrimaryKey(Demo record);
+}

+ 14 - 0
game-module/game-manage/src/main/java/com/zanxiang/manage/service/DemoService.java

@@ -0,0 +1,14 @@
+package com.zanxiang.manage.service;
+
+import com.zanxiang.manage.domain.entity.Demo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * 服务类接口
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+public interface DemoService extends IService<Demo> {
+
+}

+ 18 - 0
game-module/game-manage/src/main/java/com/zanxiang/manage/service/Impl/DemoServiceImpl.java

@@ -0,0 +1,18 @@
+package com.zanxiang.manage.service.Impl;
+
+import com.zanxiang.manage.service.DemoService;
+import com.zanxiang.manage.domain.entity.Demo;
+import com.zanxiang.manage.mapper.DemoMapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * 服务实现类
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+@Service
+public class DemoServiceImpl extends ServiceImpl<DemoMapper, Demo> implements DemoService {
+
+}

+ 45 - 0
game-module/game-manage/src/main/resources/bootstrap.yml

@@ -0,0 +1,45 @@
+# Tomcat
+server:
+  shutdown: graceful
+  port: 8092
+  
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: game-sdk
+  profiles:
+    # 环境配置
+    active: dev
+  cloud:
+    nacos:
+      discovery:
+        namespace: DEV_game
+        # 服务注册地址
+        server-addr: 118.178.187.109:8848
+      config:
+        namespace: DEV_game
+        # 配置中心地址
+        server-addr: 118.178.187.109:8848
+        # 配置文件格式
+        file-extension: yml
+        # 配置文件分组
+        group: GAME
+        # 共享配置
+        shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+        max-retry: 10
+
+  #数据库配置
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://118.178.187.109:3306/zx-game?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+    username: root
+    password: zxdev3306
+
+logging:
+  level:
+    root: warn
+    com.zanxiang.manage: debug
+    com.zanxiang.manage.mapper: debug
+
+

+ 88 - 0
game-module/game-manage/src/main/resources/mapper/DemoMapper.xml

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.zanxiang.manage.mapper.DemoMapper">
+    <resultMap id="BaseResultMap" type="com.zanxiang.manage.domain.entity.Demo">
+        <id column="id" jdbcType="BIGINT" property="id"/>
+        <result column="name" jdbcType="VARCHAR" property="name"/>
+        <result column="is_enable" jdbcType="TINYINT" property="isEnable"/>
+        <result column="content" jdbcType="VARCHAR" property="content"/>
+    </resultMap>
+    <sql id="Base_Column_List">
+        id
+        , name, is_enable, content
+    </sql>
+
+    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from demo
+        where id = #{id,jdbcType=BIGINT}
+    </select>
+
+    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+        delete
+        from demo
+        where id = #{id,jdbcType=BIGINT}
+    </delete>
+
+    <insert id="insert" parameterType="com.zanxiang.manage.domain.entity.Demo">
+        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
+            SELECT LAST_INSERT_ID()
+        </selectKey>
+        insert into demo(name, is_enable, content)
+        values (#{name,jdbcType=VARCHAR}, #{isEnable,jdbcType=TINYINT}, #{content,jdbcType=VARCHAR})
+    </insert>
+
+    <insert id="insertSelective" parameterType="com.zanxiang.manage.domain.entity.Demo">
+        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
+            SELECT LAST_INSERT_ID()
+        </selectKey>
+        insert into demo
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="name != null">
+                name,
+            </if>
+            <if test="isEnable != null">
+                is_enable,
+            </if>
+            <if test="content != null">
+                content,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="name != null">
+                #{name,jdbcType=VARCHAR},
+            </if>
+            <if test="isEnable != null">
+                #{isEnable,jdbcType=TINYINT},
+            </if>
+            <if test="content != null">
+                #{content,jdbcType=VARCHAR},
+            </if>
+        </trim>
+    </insert>
+
+    <update id="updateByPrimaryKeySelective" parameterType="com.zanxiang.manage.domain.entity.Demo">
+        update demo
+        <set>
+            <if test="name != null">
+                name = #{name,jdbcType=VARCHAR},
+            </if>
+            <if test="isEnable != null">
+                is_enable = #{isEnable,jdbcType=TINYINT},
+            </if>
+            <if test="content != null">
+                content = #{content,jdbcType=VARCHAR},
+            </if>
+        </set>
+        where id = #{id,jdbcType=BIGINT}
+    </update>
+
+    <update id="updateByPrimaryKey" parameterType="com.zanxiang.manage.domain.entity.Demo">
+        update demo
+        set name      = #{name,jdbcType=VARCHAR},
+            is_enable = #{isEnable,jdbcType=TINYINT},
+            content   = #{content,jdbcType=VARCHAR}
+        where id = #{id,jdbcType=BIGINT}
+    </update>
+</mapper>

+ 3 - 21
game-module/game-sdk/pom.xml

@@ -8,31 +8,13 @@
         <version>0.0.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
-
     <artifactId>game-sdk</artifactId>
 
     <dependencies>
         <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
-
-        <!-- nacos配置中心 -->
-        <dependency>
-            <groupId>com.alibaba.cloud</groupId>
-            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
-        </dependency>
-        <!-- nacos注册中心 -->
-        <dependency>
-            <groupId>com.alibaba.cloud</groupId>
-            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>test</scope>
+            <groupId>com.zanxiang.game</groupId>
+            <artifactId>game-common</artifactId>
+            <version>${game-common.vertion}</version>
         </dependency>
     </dependencies>
-
 </project>

+ 26 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/SDKApplication.java

@@ -0,0 +1,26 @@
+package com.zanxiang.sdk;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+
+@Slf4j
+@EnableDiscoveryClient
+@SpringBootApplication
+public class SDKApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(SDKApplication.class, args);
+        System.out.println("赞象SDK服务启动成功 ( ´・・)ノ(._.`) \n" +
+                " ______  __     __     \n" +
+                "/_____/\\/__/\\ /__/\\    \n" +
+                "\\:::__\\/\\ \\::\\\\:.\\ \\   \n" +
+                "   /: /  \\_\\::_\\:_\\/   \n" +
+                "  /::/___  _\\/__\\_\\_/\\ \n" +
+                " /_:/____/\\\\ \\ \\ \\::\\ \\\n" +
+                " \\_______\\/ \\_\\/  \\__\\/\n");
+    }
+
+}

+ 37 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/controller/DemoController.java

@@ -0,0 +1,37 @@
+package com.zanxiang.sdk.controller;
+
+import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.common.utils.bean.BeanUtils;
+import com.zanxiang.sdk.domain.entity.Demo;
+import com.zanxiang.sdk.domain.vo.DemoVO;
+import com.zanxiang.sdk.service.DemoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * demo示例
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+@Api(tags = "demo示例")
+@RestController
+@RequestMapping("/sdkdemo")
+public class DemoController {
+
+    @Autowired
+    private DemoService demoService;
+
+    @GetMapping("/info")
+    @ApiOperation("/info")
+    public ResultVo<DemoVO> getDemo(@RequestParam(name = "id", defaultValue = "1", required = false) String id) {
+        Demo demo = demoService.getById(id);
+        return ResultVo.ok(BeanUtils.copy(demo, DemoVO.class));
+    }
+
+}

+ 43 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/entity/Demo.java

@@ -0,0 +1,43 @@
+package com.zanxiang.sdk.domain.entity;
+
+import java.io.Serializable;
+
+import lombok.Data;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.IdType;
+
+/**
+ * 注释
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Demo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 是否启用
+     */
+    private Integer isEnable;
+
+    /**
+     * 内容
+     */
+    private String content;
+}

+ 30 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/vo/DemoVO.java

@@ -0,0 +1,30 @@
+package com.zanxiang.sdk.domain.vo;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+
+@Data
+public class DemoVO {
+
+    private static final long serialVersionUID = 1L;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long id;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 是否启用
+     */
+    private Integer isEnable;
+
+    /**
+     * 内容
+     */
+    private String content;
+
+}

+ 62 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/mapper/DemoMapper.java

@@ -0,0 +1,62 @@
+package com.zanxiang.sdk.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.sdk.domain.entity.Demo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 注释 Mapper
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+@Mapper
+public interface DemoMapper extends BaseMapper<Demo> {
+
+    /**
+     * 根据主键id查询
+     *
+     * @param id
+     * @return 记录信息
+     */
+    Demo selectByPrimaryKey(Long id);
+
+    /**
+     * 根据主键删除数据
+     *
+     * @param id
+     * @return 数量
+     */
+    int deleteByPrimaryKey(Long id);
+
+    /**
+     * 插入数据库记录(不建议使用)
+     *
+     * @param record
+     */
+    int insert(Demo record);
+
+    /**
+     * 插入数据库记录(建议使用)
+     *
+     * @param record 插入数据
+     * @return 插入数量
+     */
+    int insertSelective(Demo record);
+
+    /**
+     * 修改数据(推荐使用)
+     *
+     * @param record 更新值
+     * @return 更新数量
+     */
+    int updateByPrimaryKeySelective(Demo record);
+
+    /**
+     * 根据主键更新数据
+     *
+     * @param record 更新值
+     * @return 更新数量
+     */
+    int updateByPrimaryKey(Demo record);
+}

+ 15 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/DemoService.java

@@ -0,0 +1,15 @@
+package com.zanxiang.sdk.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.sdk.domain.entity.Demo;
+
+/**
+ * 服务类接口
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+public interface DemoService extends IService<Demo> {
+
+}

+ 18 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/DemoServiceImpl.java

@@ -0,0 +1,18 @@
+package com.zanxiang.sdk.service.Impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.sdk.domain.entity.Demo;
+import com.zanxiang.sdk.mapper.DemoMapper;
+import com.zanxiang.sdk.service.DemoService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 服务实现类
+ *
+ * @author xufeng
+ * @date 2022-05-31 17:06
+ */
+@Service
+public class DemoServiceImpl extends ServiceImpl<DemoMapper, Demo> implements DemoService {
+
+}

+ 45 - 0
game-module/game-sdk/src/main/resources/bootstrap.yml

@@ -0,0 +1,45 @@
+# Tomcat
+server:
+  shutdown: graceful
+  port: 8091
+#  servlet:
+#    context-path: /game-manage
+
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: game-manage
+  profiles:
+    # 环境配置
+    active: dev
+  cloud:
+    nacos:
+      discovery:
+        namespace: DEV_game
+        # 服务注册地址
+        server-addr: 118.178.187.109:8848
+      config:
+        namespace: DEV_game
+        # 配置中心地址
+        server-addr: 118.178.187.109:8848
+        # 配置文件格式
+        file-extension: yml
+        # 配置文件分组
+        group: GAME
+        # 共享配置
+        shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+        max-retry: 10
+
+  #数据库配置
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://118.178.187.109:3306/zx-game?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+    username: root
+    password: zxdev3306
+
+logging:
+  level:
+    root: warn
+    com.zanxiang.manage: debug
+    com.zanxiang.manage.mapper: debug

+ 88 - 0
game-module/game-sdk/src/main/resources/mapper/DemoMapper.xml

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.zanxiang.manage.mapper.DemoMapper">
+    <resultMap id="BaseResultMap" type="com.zanxiang.sdk.domain.entity.Demo">
+        <id column="id" jdbcType="BIGINT" property="id"/>
+        <result column="name" jdbcType="VARCHAR" property="name"/>
+        <result column="is_enable" jdbcType="TINYINT" property="isEnable"/>
+        <result column="content" jdbcType="VARCHAR" property="content"/>
+    </resultMap>
+    <sql id="Base_Column_List">
+        id
+        , name, is_enable, content
+    </sql>
+
+    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from demo
+        where id = #{id,jdbcType=BIGINT}
+    </select>
+
+    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+        delete
+        from demo
+        where id = #{id,jdbcType=BIGINT}
+    </delete>
+
+    <insert id="insert" parameterType="com.zanxiang.sdk.domain.entity.Demo">
+        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
+            SELECT LAST_INSERT_ID()
+        </selectKey>
+        insert into demo(name, is_enable, content)
+        values (#{name,jdbcType=VARCHAR}, #{isEnable,jdbcType=TINYINT}, #{content,jdbcType=VARCHAR})
+    </insert>
+
+    <insert id="insertSelective" parameterType="com.zanxiang.sdk.domain.entity.Demo">
+        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
+            SELECT LAST_INSERT_ID()
+        </selectKey>
+        insert into demo
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="name != null">
+                name,
+            </if>
+            <if test="isEnable != null">
+                is_enable,
+            </if>
+            <if test="content != null">
+                content,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="name != null">
+                #{name,jdbcType=VARCHAR},
+            </if>
+            <if test="isEnable != null">
+                #{isEnable,jdbcType=TINYINT},
+            </if>
+            <if test="content != null">
+                #{content,jdbcType=VARCHAR},
+            </if>
+        </trim>
+    </insert>
+
+    <update id="updateByPrimaryKeySelective" parameterType="com.zanxiang.sdk.domain.entity.Demo">
+        update demo
+        <set>
+            <if test="name != null">
+                name = #{name,jdbcType=VARCHAR},
+            </if>
+            <if test="isEnable != null">
+                is_enable = #{isEnable,jdbcType=TINYINT},
+            </if>
+            <if test="content != null">
+                content = #{content,jdbcType=VARCHAR},
+            </if>
+        </set>
+        where id = #{id,jdbcType=BIGINT}
+    </update>
+
+    <update id="updateByPrimaryKey" parameterType="com.zanxiang.sdk.domain.entity.Demo">
+        update demo
+        set name      = #{name,jdbcType=VARCHAR},
+            is_enable = #{isEnable,jdbcType=TINYINT},
+            content   = #{content,jdbcType=VARCHAR}
+        where id = #{id,jdbcType=BIGINT}
+    </update>
+</mapper>

+ 22 - 0
game-module/pom.xml

@@ -14,6 +14,28 @@
     <modules>
         <module>game-manage</module>
         <module>game-sdk</module>
+        <module>game-common</module>
     </modules>
 
+    <dependencies>
+        <!-- web 的集成 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <!--swagger2 的集成-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger2.version}</version>
+        </dependency>
+        <!--swagger样式 的集成-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger2.ui.version}</version>
+        </dependency>
+
+    </dependencies>
+
 </project>

+ 7 - 0
pom.xml

@@ -18,4 +18,11 @@
     <artifactId>game-center</artifactId>
     <version>0.0.1-SNAPSHOT</version>
 
+    <properties>
+        <swagger2.version>2.9.2</swagger2.version>
+        <swagger2.ui.version>2.9.2</swagger2.ui.version>
+        <mybatis-plus.version>3.4.0</mybatis-plus.version>
+        <game-common.vertion>0.0.1-SNAPSHOT</game-common.vertion>
+    </properties>
+
 </project>