diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..884e62d --- /dev/null +++ b/.gitignore @@ -0,0 +1,147 @@ +# Created by .ignore support plugin (hsz.mobi) +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.idea +.editorconfig +.sdkmanrc + +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a983199 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 hb730 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 2152e28..e69de29 100644 --- a/README.md +++ b/README.md @@ -1,34 +0,0 @@ -# Boot-Admin V5 - -基于Java17,SpringBoot3,Spring security6,Mysql8,MybatisPlus的前后端分离的后台管理系统 - -| | | | -|---------------------------------------------------------------------------------|--------------------------------------------------------------------------------|--------------------------------------------------------------------------------| -| ![](https://github.com/hb0730/boot-admin/raw/v5/doc/asset/boot-admin_v5_1.png) | ![](https://github.com/hb0730/boot-admin/raw/v5/doc/asset/boot-admin_v5_2.png) | ![](https://github.com/hb0730/boot-admin/raw/v5/doc/asset/boot-admin_v5_2.png) | -| ![](https://github.com/hb0730/boot-admin/raw/v5/doc/asset/boot-admin_v5_3.png) | ![](https://github.com/hb0730/boot-admin/raw/v5/doc/asset/boot-admin_v5_5.png) | ![](https://github.com/hb0730/boot-admin/raw/v5/doc/asset/boot-admin_v5_6.png) | - - -## 开源地址 -| | 后端 | 前端 | -|--------|--------------------------------------|------------------------------------------| -| Github | https://github.com/hb0730/boot-admin | https://github.com/hb0730/boot-admin-ui | -| Gitee | https://gitee.com/hb0730/boot-admin/ | https://gitee.com/hb0730/boot-admin-ui | - -## 特征 -* 前端采用vue-pure-admin (Vue3,Element-Plus,Vite) -* 支持动态菜单与路由 -* 自定义权限认证与Security的结合使用 -## 在线预览 -https://boot.hb0730.com/next - -**admin/123456 能不能访问凭运气,Java Server: HK,Redis Server: HK,Mysql Server:HK** - - -## SQL 所在地 -> doc/sql/boot-admin.sql - -## question -* 为什么实时请求routes - >1. 首先我们后端已经缓存了当前用户路由 - >2. 我们采用EventListener,当管理者更改了用户权限能够实时响应, - >3. 如果要前端缓存,可以开启前端配置: `CachingAsyncRoutes` \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..6132fce --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,19 @@ +FROM eclipse-temurin:17-jre as builder +WORKDIR application +ARG JAR_FILE=*.jar +COPY ${JAR_FILE} application.jar +RUN java -Djarmode=layertools -jar application.jar extract + +FROM eclipse-temurin:17-jre +WORKDIR application +COPY --from=builder application/dependencies/ ./ +COPY --from=builder application/spring-boot-loader/ ./ +COPY --from=builder application/snapshot-dependencies/ ./ +COPY --from=builder application/application/ ./ + +ENV JAVA_OPTS="-server -Xms2048m -Xmx2048m -Xmn512m -XX:MaxMetaspaceSize=512m" \ + TZ=Asia/Shanghai + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +ENTRYPOINT java $JAVA_OPTS org.springframework.boot.loader.JarLauncher diff --git a/docker/docker-compose.infra.yml b/docker/docker-compose.infra.yml new file mode 100644 index 0000000..b7a6781 --- /dev/null +++ b/docker/docker-compose.infra.yml @@ -0,0 +1,25 @@ +version: '3' +services: + mysql8_server: + image: mysql:8 + container_name: boot_admin_mysql8_server + ports: + - 3306:3306 + volumes: + - ./data/mysql:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: 1234 + MYSQL_DATABASE: boot-admin + TZ: Asia/Shanghai + redis_server: + image: redis:alpine + container_name: boot_admin_redis_server + ports: + - 6379:6379 + volumes: + # redis配置 + - ./conf/redis:/usr/local/etc/redis + # redis 数据挂载 + - ./data/redis:/data + command: redis-server /usr/local/etc/redis/redis.conf + diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..d93be0f --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3' +services: + next_boot-admin: + image: boot-admin:v5 + container_name: next_boot-admin + ports: + - '8089:8088' + environment: + JAVA_OPTS: '-server -Dspring.profiles.active=prod -Dspring.config.additional-location=/application/conf/' + TZ: "Asia/Shanghai" + volumes: + - ./conf:/application/conf \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5f191ed --- /dev/null +++ b/pom.xml @@ -0,0 +1,192 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.0.1 + + + com.hb0730 + boot-admin + 5.0.0-SNAPSHOT + boot-admin + Demo project for Spring Boot + + 8 + UTF-8 + UTF-8 + + 5.8.11 + 1.72 + + 3.5.3.1 + 1.0.3 + 4.1.0 + 4.2.2 + + + + org.springframework.boot + spring-boot-configuration-processor + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security + spring-security-test + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-quartz + + + + com.mysql + mysql-connector-j + runtime + + + org.projectlombok + lombok + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + com.zaxxer + HikariCP + + + + com.auth0 + java-jwt + ${jwt.version} + + + + cn.hutool + hutool-core + ${hutool.version} + + + cn.hutool + hutool-extra + ${hutool.version} + + + cn.hutool + hutool-crypto + ${hutool.version} + + + org.bouncycastle + bcpkix-jdk15to18 + ${bouncycastle.version} + + + + com.hb0730 + jsons + ${hb0730-jsons.version} + + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + ${knife4j.version} + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + 4.3.0 + + + com.alibaba + fastjson + 1.2.83 + + + com.aliyun.oss + aliyun-sdk-oss + 3.10.2 + + + + cn.mrzin + tool-wx + 1.0.1-SNAPSHOT + + + com.google.code.gson + gson + 2.8.7 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 14 + 14 + + + + org.springframework.boot + spring-boot-maven-plugin + ${project.parent.version} + + + + + src/main/resources + true + + + src/main/java + + **/*.xml + **/*.json + **/*.ftl + + + + + + diff --git a/src/main/java/com/hb0730/boot/admin/BootAdminApplication.java b/src/main/java/com/hb0730/boot/admin/BootAdminApplication.java new file mode 100644 index 0000000..269acda --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/BootAdminApplication.java @@ -0,0 +1,24 @@ +package com.hb0730.boot.admin; + +import cn.hutool.extra.spring.EnableSpringUtil; +import com.hb0730.boot.admin.base.BootAdminApp; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; + +/** + * @author hb0730 + * @date 2023/1/11 + */ +@SpringBootApplication +@EnableSpringUtil +@EnableAsync +public class BootAdminApplication extends BootAdminApp { + public static void main(String[] args) { + bootstrap(BootAdminApplication.class, args); + } + + @Override + protected void doSomethingAfterBooted() { + + } +} diff --git a/src/main/java/com/hb0730/boot/admin/base/BootAdminApp.java b/src/main/java/com/hb0730/boot/admin/base/BootAdminApp.java new file mode 100644 index 0000000..0337a41 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/BootAdminApp.java @@ -0,0 +1,62 @@ +package com.hb0730.boot.admin.base; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.Banner; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.env.Environment; + +/** + * SPRING 启动器 + * + * @author hb0730 + * @date 2023/1/11 + */ +@Slf4j +public class BootAdminApp implements ApplicationContextAware, ApplicationRunner { + private ApplicationContext context; + + + public static void bootstrap(Class clazz, String... args) { + log.debug("{} 启动开始 ...", clazz.getCanonicalName()); + SpringApplication application = new SpringApplication(clazz); + application.setBannerMode(Banner.Mode.CONSOLE); + application.run(args); + log.debug("{} 启动完成 ...", clazz.getCanonicalName()); + } + + @Override + public void run(ApplicationArguments args) throws Exception { + //启动后做点啥 + doSomethingAfterBooted(); + + //输出启动完成信息 + doShowBootedInfs(); + } + + /** + * 启动后做点啥 + */ + protected void doSomethingAfterBooted() { + } + + /** + * 输出启动完成信息 + */ + protected void doShowBootedInfs() { + Environment env = context.getEnvironment(); + log.info("启动完成 -> {}:{}", + env.getProperty("server.servlet.context-path"), + env.getProperty("server.port") + ); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + context = applicationContext; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/base/BootAdminConst.java b/src/main/java/com/hb0730/boot/admin/base/BootAdminConst.java new file mode 100644 index 0000000..e3944a2 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/BootAdminConst.java @@ -0,0 +1,17 @@ +package com.hb0730.boot.admin.base; + +/** + * 常量池 + * + * @author hb0730 + * @date 2023/1/30 + */ +public interface BootAdminConst { + + String CHARSET_NAME_UTF8 = "utf-8"; + + /** + * 访问令牌头 + */ + String X_ACCESS_TOKEN = "X-Access-Token"; +} diff --git a/src/main/java/com/hb0730/boot/admin/base/BootAdminContext.java b/src/main/java/com/hb0730/boot/admin/base/BootAdminContext.java new file mode 100644 index 0000000..f624766 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/BootAdminContext.java @@ -0,0 +1,37 @@ +package com.hb0730.boot.admin.base; + +import cn.hutool.extra.spring.SpringUtil; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.lang.annotation.Annotation; +import java.util.Map; + +/** + * Spring ApplicationContext + * + * @author hb0730 + * @date 2023/1/11 + */ +@Component +public class BootAdminContext extends SpringUtil { + /** + * 获取HttpServletRequest + */ + public static HttpServletRequest getHttpServletRequest() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } + + /** + * 根据BEAN注解获取BEAN + * + * @param annotationType BEAN注解 + * @return BEANS + */ + public static Map getBeansWithAnnotation(Class annotationType) { + return getApplicationContext().getBeansWithAnnotation(annotationType); + } + +} diff --git a/src/main/java/com/hb0730/boot/admin/base/R.java b/src/main/java/com/hb0730/boot/admin/base/R.java new file mode 100644 index 0000000..86ef348 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/R.java @@ -0,0 +1,239 @@ +package com.hb0730.boot.admin.base; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 接口返回数据格式 + * + * @author hb0730 + * @date 2023/1/11 + */ +@Data +@EqualsAndHashCode +public class R implements Serializable { + public static final Integer OK_200 = 200; + public static final Integer SERVER_ERROR_500 = 500; + /** + * 默认失败 状态码 + */ + public static final Integer SUC_0 = 0; + /** + * 成功状态码 + */ + public static final Integer SUC_1 = 1; + + /** + * 成功标志 + */ + @Schema(description = "成功标识") + private boolean success = true; + /** + * 返回处理消息 + */ + @Schema(description = "返回处理消息") + private String message = "操作成功!"; + /** + * 返回代码 + */ + @Schema(description = "返回代码") + private Integer code = 0; + /** + * 返回数据对象 data + */ + @Schema(description = "返回数据对象") + private T result; + /** + * 时间戳 + */ + @Schema(description = "时间戳") + private long timestamp = System.currentTimeMillis(); + + public R() { + } + + public R(T result) { + this.code = SUC_1; + this.result = result; + } + + public R(boolean success, String message) { + this.success = success; + this.message = message; + if (success) { + this.code = SUC_1; + } else { + this.code = SUC_0; + } + } + + /** + * 接口返回数据:成功 + * + * @param message 消息 + * @return 接口返回数据:成功 + */ + public R success(String message) { + this.message = message; + this.code = OK_200; + this.success = true; + return this; + } + + /** + * 接口返回数据:失败,code: 500 + * + * @param message 消息 + * @return 接口返回数据:失败 + */ + public R error(String message) { + return error(SERVER_ERROR_500, message); + } + + /** + * 接口返回数据:失败 + * + * @param code 代码 + * @param message 消息 + * @param . + * @return 接口返回数据:失败 + */ + public static R error(int code, String message) { + R r = new R<>(); + r.setCode(code); + r.setMessage(message); + r.setSuccess(false); + return r; + } + + /** + * 接口返回数据:成功 + * + * @param . + * @return 接口返回数据:成功 + */ + public static R OK() { + return OK("成功!", null); + } + + /** + * 接口返回数据:成功 + * + * @param data 数据 + * @param . + * @return 接口返回数据:成功 + */ + public static R OK(T data) { + return OK("成功", data); + } + + /** + * 接口返回数据:成功 + * + * @param code 代码 + * @param message 消息 + * @param . + * @return 接口返回数据:成功 + */ + public static R OK(int code, String message) { + return OK(code, message, null); + } + + /** + * 接口返回数据:成功 + * + * @param message 消息 + * @param . + * @return 接口返回数据:成功 + */ + public static R OK(String message) { + return OK(OK_200, message, null); + } + + /** + * 接口返回数据:成功 + * + * @param message 消息 + * @param data 数据 + * @param . + * @return 接口返回数据:成功 + */ + public static R OK(String message, T data) { + return OK(OK_200, message, data); + } + + /** + * 接口返回数据:成功 + * + * @param code 代码 + * @param message 消息 + * @param data 数据 + * @param . + * @return 接口返回数据:成功 + */ + public static R OK(int code, String message, T data) { + R r = new R<>(); + r.setSuccess(true); + r.setCode(code); + r.setMessage(message); + r.setResult(data); + return r; + } + + /** + * 接口返回数据:失败 + * + * @param message 消息 + * @param . + * @return 接口返回数据:失败 + */ + public static R NG(String message) { + return NG(message, null); + } + + /** + * 接口返回数据:失败 + * + * @param message 消息 + * @param data 数据 + * @param . + * @return 接口返回数据:失败 + */ + public static R NG(String message, T data) { + return NG(SERVER_ERROR_500, message, data); + } + + + /** + * 接口返回数据:失败 + * + * @param code 代码 + * @param message 消息 + * @param . + * @return 接口返回数据:失败 + */ + public static R NG(int code, String message) { + return NG(code, message, null); + } + + /** + * 接口返回数据:失败 + * + * @param code 代码 + * @param message 消息 + * @param data 数据 + * @param . + * @return 接口返回数据:失败 + */ + public static R NG(int code, String message, T data) { + R r = new R<>(); + r.setSuccess(false); + r.setCode(code); + r.setMessage(message); + r.setResult(data); + return r; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/base/exception/BootAdminException.java b/src/main/java/com/hb0730/boot/admin/base/exception/BootAdminException.java new file mode 100644 index 0000000..d7fc34e --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/exception/BootAdminException.java @@ -0,0 +1,29 @@ +package com.hb0730.boot.admin.base.exception; + +/** + * 系统异常 + * + * @author hb0730 + * @date 2023/1/30 + */ +public class BootAdminException extends RuntimeException { + public BootAdminException() { + super(); + } + + public BootAdminException(String message) { + super(message); + } + + public BootAdminException(String message, Throwable cause) { + super(message, cause); + } + + public BootAdminException(Throwable cause) { + super(cause); + } + + protected BootAdminException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/base/util/AesEncryptUtil.java b/src/main/java/com/hb0730/boot/admin/base/util/AesEncryptUtil.java new file mode 100644 index 0000000..878a99d --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/util/AesEncryptUtil.java @@ -0,0 +1,74 @@ +package com.hb0730.boot.admin.base.util; + +import cn.hutool.crypto.Mode; +import cn.hutool.crypto.Padding; +import cn.hutool.crypto.symmetric.AES; +import jakarta.annotation.Nonnull; +import lombok.Data; + +import java.nio.charset.StandardCharsets; + +/** + * AES 加密 + * + * @author hb0730 + * @date 2023/1/30 + */ +public class AesEncryptUtil { + @Data + public static class SecKey { + + public static String key = "1234567890adbcde"; // 长度为16个字符 + + public static String iv = "1234567890hjlkew"; // 长度为16个字符 + } + + /** + * 加密方法,使用默认的密钥与偏移向量 + * + * @param data 要加密的数据 + * @return 加密的结果 + */ + public static String encrypt(String data) { + return encrypt(data, SecKey.key, SecKey.iv); + } + + /** + * 加密方式 + * + * @param data 要加密的数据 + * @param key 密钥 + * @param iv 偏移向量,加盐 + * @return 加密的结果 + */ + public static String encrypt(String data, @Nonnull String key, @Nonnull String iv) { + AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, key.getBytes(StandardCharsets.UTF_8), + iv.getBytes(StandardCharsets.UTF_8)); + return aes.encryptHex(data); + } + + /** + * 解密方法 + * + * @param data 要解密的数据 + * @return 解密的结果 + */ + public static String desEncrypt(String data) { + return desEncrypt(data, SecKey.key, SecKey.iv); + } + + /** + * 解密方法 + * + * @param data 要解密的数据 + * @param key 密钥 + * @param iv 偏移向量,加盐 + * @return 解密的结果 + */ + public static String desEncrypt(String data, @Nonnull String key, @Nonnull String iv) { + AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, key.getBytes(StandardCharsets.UTF_8), + iv.getBytes(StandardCharsets.UTF_8)); + return aes.decryptStr(data); + } + +} diff --git a/src/main/java/com/hb0730/boot/admin/base/util/JsonUtil.java b/src/main/java/com/hb0730/boot/admin/base/util/JsonUtil.java new file mode 100644 index 0000000..21d0474 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/util/JsonUtil.java @@ -0,0 +1,33 @@ +package com.hb0730.boot.admin.base.util; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.hb0730.jsons.support.jackson.JacksonImpl; + +/** + * json util + * + * @author hb0730 + * @date 2023/1/11 + */ +public class JsonUtil extends JacksonImpl { + public static JsonUtil DEFAULT = new JsonUtil(); + + public JsonUtil() { + ObjectMapper mapper = new ObjectMapper() { + { + //序列化时候,只序列化非空字段 + //this.setSerializationInclusion(Inclusion.NON_NULL); + //or this.setSerializationConfig(this.getSerializationConfig().withSerializationInclusion(Inclusion.NON_NULL)); + + // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性 + this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + this.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + + //this.setDateFormat(new SimpleDateFormat("yyyy-MM-dd")); + } + }; + setClient(mapper); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/base/util/JwtUtil.java b/src/main/java/com/hb0730/boot/admin/base/util/JwtUtil.java new file mode 100644 index 0000000..3a791a4 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/util/JwtUtil.java @@ -0,0 +1,110 @@ +package com.hb0730.boot.admin.base.util; + +import cn.hutool.core.util.StrUtil; +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.hb0730.boot.admin.base.BootAdminConst; +import com.hb0730.boot.admin.base.exception.BootAdminException; +import jakarta.annotation.Nullable; +import jakarta.servlet.http.HttpServletRequest; + +import java.util.Date; + +/** + * JWT util + * + * @author hb0730 + * @date 2023/1/30 + */ +public class JwtUtil { + /** + * 过期时间(毫秒):Token过期时间30分钟(用户登录过期时间是此时间的两倍,以token在reids缓存时间为准) + */ + public static final long EXPIRE_TIME = 30 * 60 * 1000; + + /** + * 获取 request 里传递的 token + * + * @param request . + * @return jwt_token + */ + public static String getTokenByRequest(HttpServletRequest request) { + String token = request.getParameter("token"); + if (token == null) { + token = request.getHeader(BootAdminConst.X_ACCESS_TOKEN); + } + return token; + } + + /** + * 根据request中的token获取用户账号 + * + * @param request 请求 + * @return 用户名 + */ + @Nullable + public static String getUserNameByToken(HttpServletRequest request) throws BootAdminException { + String accessToken = request.getHeader(BootAdminConst.X_ACCESS_TOKEN); + if (StrUtil.isBlank(accessToken)) { + return null; + } + String username = getUsername(accessToken); + if (StrUtil.isBlank(username)) { + throw new BootAdminException("未获取到用户"); + } + return username; + } + + /** + * 获得token中的信息无需secret解密也能获得 + * + * @return token中包含的用户名 + */ + public static String getUsername(String token) { + try { + DecodedJWT jwt = JWT.decode(token); + return jwt.getClaim("username").asString(); + } catch (JWTDecodeException e) { + return null; + } + } + + + /** + * 生成签名,EXPIRE_TIME后过期 + * + * @param username 用户名 + * @param secret 用户的密码 + * @return 加密的token + */ + public static String sign(String username, String secret) { + Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); + Algorithm algorithm = Algorithm.HMAC256(secret); + // 附带username信息 + return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm); + } + + + /** + * 校验token是否正确 + * + * @param token 密钥 + * @param secret 用户的密码 + * @return 是否正确 + */ + public static boolean verify(String token, String username, String secret) { + try { + // 根据密码生成JWT效验器 + Algorithm algorithm = Algorithm.HMAC256(secret); + JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build(); + // 效验TOKEN + DecodedJWT jwt = verifier.verify(token); + return true; + } catch (Exception exception) { + return false; + } + } +} diff --git a/src/main/java/com/hb0730/boot/admin/base/util/PasswordUtil.java b/src/main/java/com/hb0730/boot/admin/base/util/PasswordUtil.java new file mode 100644 index 0000000..e6bf699 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/util/PasswordUtil.java @@ -0,0 +1,68 @@ +package com.hb0730.boot.admin.base.util; + +import jakarta.annotation.Nonnull; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * 提供对密码的加密与匹对 + * + * @author hb0730 + * @date 2023/2/3 + */ +public class PasswordUtil { + /** + * 将原始密码进行编码,使用默认编码器{@link #defaultPasswordEncoder()} + * + * @param rawPassword 原密码 + * @return 编码后的密码 + */ + public static String encoder(String rawPassword) { + return encoder(rawPassword, defaultPasswordEncoder()); + } + + /** + * 将原始密码进行编码 + * + * @param rawPassword 原密码 + * @param passwordEncoder 编码器 + * @return 编码后的密码 + */ + public static String encoder(String rawPassword, @Nonnull PasswordEncoder passwordEncoder) { + return passwordEncoder.encode(rawPassword); + } + + /** + * 校验原始密码与编码后的密码是否为同一个密码,使用默认编码器{@link #defaultPasswordEncoder()} + * + * @param rawPassword 原密码 + * @param encodedPassword 编码后的密码 + * @return 是否一致 + */ + public static boolean matches(String rawPassword, String encodedPassword) { + return matches(rawPassword, encodedPassword, defaultPasswordEncoder()); + } + + /** + * 校验原始密码与编码后的密码是否为同一个密码 + * + * @param rawPassword 原密码 + * @param encodedPassword 编码后的密码 + * @param passwordEncoder 编码器 + * @return 是否一致 + */ + public static boolean matches(String rawPassword, String encodedPassword, + @Nonnull PasswordEncoder passwordEncoder) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + + /** + * 默认使用 {@link BCryptPasswordEncoder} 密码编码器 + * + * @return {@link BCryptPasswordEncoder} + */ + public static PasswordEncoder defaultPasswordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/base/util/RsaUtil.java b/src/main/java/com/hb0730/boot/admin/base/util/RsaUtil.java new file mode 100644 index 0000000..3d2797f --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/base/util/RsaUtil.java @@ -0,0 +1,106 @@ +package com.hb0730.boot.admin.base.util; + +import cn.hutool.core.codec.Base64; +import cn.hutool.crypto.KeyUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.UtilityClass; + +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * ras util + * + * @author hb0730 + * @date 2023/2/5 + */ +@UtilityClass +public class RsaUtil { + + /** + * 公钥加密,私钥解密 + * + * @param text 待加密的信息 + * @param publicKeyBase64 公钥 + * @return base64后的结果 + */ + public String encryptByPublicKey(String text, String publicKeyBase64) { + RSA rsa = new RSA(); + PublicKey publicKey = KeyUtil.generateRSAPublicKey(Base64.decode(publicKeyBase64)); + rsa.setPublicKey(publicKey); + return rsa.encryptBase64(text, KeyType.PublicKey); + } + + /** + * 私钥解密 + * + * @param text 待解密的信息,base64 + * @param privateKeyBase64 私钥 + * @return 解密后的结果 + */ + public String decryptByPrivateKey(String text, String privateKeyBase64) { + RSA rsa = new RSA(); + PrivateKey privateKey = KeyUtil.generateRSAPrivateKey(Base64.decode(privateKeyBase64)); + rsa.setPrivateKey(privateKey); + return rsa.decryptStr(text, KeyType.PrivateKey); + } + + /** + * 私钥解密,公钥解密 + * + * @param text 待解密信息 + * @param privateKeyBase64 私钥 + * @return 加密后的结果, base64类型 + */ + public String encryptByPrivateKey(String text, String privateKeyBase64) { + RSA rsa = new RSA(); + PrivateKey privateKey = KeyUtil.generateRSAPrivateKey(Base64.decode(privateKeyBase64)); + rsa.setPrivateKey(privateKey); + return rsa.encryptBase64(text, KeyType.PrivateKey); + } + + /** + * 公钥解密 + * + * @param text 待解密信息,base64 + * @param publicKeyBase64 公钥 + * @return 解密后的结果 + */ + public String decryptByPublicKey(String text, String publicKeyBase64) { + RSA rsa = new RSA(); + PublicKey publicKey = KeyUtil.generateRSAPublicKey(Base64.decode(publicKeyBase64)); + rsa.setPublicKey(publicKey); + return rsa.decryptStr(text, KeyType.PublicKey); + } + + /** + * 构建RSA密钥对 + * + * @return . + */ + public RsaKeyPair generateKey() { + KeyPair keyPair = KeyUtil.generateKeyPair("RSA", 1024); + + String publicBase64Key = KeyUtil.toBase64(keyPair.getPublic()); + String privateBase64Key = KeyUtil.toBase64(keyPair.getPrivate()); + return new RsaKeyPair(publicBase64Key, privateBase64Key); + } + + + /** + * RSA密钥对对象 + */ + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class RsaKeyPair { + private String publicKeyBase64; + private String privateKeyBase64; + + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/cache/BootAdminCache.java b/src/main/java/com/hb0730/boot/admin/config/cache/BootAdminCache.java new file mode 100644 index 0000000..4172be7 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/cache/BootAdminCache.java @@ -0,0 +1,260 @@ +package com.hb0730.boot.admin.config.cache; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import jakarta.annotation.Nonnull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * 缓存 + * + * @author hb0730 + * @date 2023/1/11 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class BootAdminCache { + private final BootAdminProperties cacheProperties; + private final StringRedisTemplate redisTemplate; + + /** + * 正规化缓存KEY,按照:进行拼接 + * + * @param key key + * @return "prefix:key" + */ + public String normaliz(String key) { + if (StrUtil.isBlank(key)) { + return null; + } + return cacheProperties.getCache().getPrefix() + ":" + key; + } + + /** + * 是否存在 + * + * @param key . + * @return . + */ + public boolean hasKey(String key) { + return Boolean.TRUE.equals(redisTemplate.hasKey(normaliz(key))); + } + + /** + * 获取所有keys + * + * @param key . + * @return . + */ + public Set getKeys(String key) { + String normalizKey = normaliz(key); + return Optional.ofNullable(redisTemplate.keys(normalizKey)) + .orElse(CollUtil.newHashSet()); + } + + /** + * 设置过期时间,单位 秒/s + * + * @param key key: prefix+key + * @param timeout timeout 单位 秒/s + * @return . + */ + public boolean expire(final String key, long timeout) { + return expire(key, timeout, TimeUnit.SECONDS); + } + + /** + * 设置过期时间 + * + * @param key key,自动追加前缀{@link #normaliz(String)} + * @param timeout timeout + * @param unit time unit + * @return . + */ + public boolean expire(final String key, long timeout, TimeUnit unit) { + String _key = normaliz(key); + Boolean _res = this.redisTemplate.expire(_key, timeout, unit); + return Boolean.TRUE.equals(_res); + } + + /** + * 获取过期时间,单位 秒/s + * + * @param key key,自动追加前缀{@link #normaliz(String)} + * @return timeout + */ + public long getExpire(final String key) { + return getExpire(key, TimeUnit.SECONDS); + } + + /** + * 获取剩下过期时间 + * + * @param key key,自动追加前缀{@link #normaliz(String)} + * @param unit time unit + * @return timeout + */ + public long getExpire(final String key, TimeUnit unit) { + String _key = normaliz(key); + return Optional.ofNullable(this.redisTemplate.getExpire(_key, unit)).orElse(0L); + } + + /** + * 设置永久缓存 + * + * @param key key,自动追加前缀{@link #normaliz(String)} + * @param value . + * @return . + */ + public boolean set(final String key, String value) { + return set(key, value, -1); + } + + /** + * 设置缓存,单位时间/秒 + * + * @param key key,自动追加前缀{@link #normaliz(String)} + * @param value . + * @param timeout timeout,如果为-l,则永久缓存 + * @return . + */ + public boolean set(final String key, String value, long timeout) { + return set(key, value, timeout, TimeUnit.SECONDS); + } + + /** + * 设置缓存 + * + * @param key key,自动追加前缀{@link #normaliz(String)} + * @param value . + * @param timeout timeout,如果为-l,则永久缓存 + * @param unit time unit + * @return . + */ + public boolean set(final String key, String value, long timeout, TimeUnit unit) { + if (StrUtil.isBlank(key)) { + log.warn("【boot-admin-cache】 set cache value warn, key missing"); + return false; + } + String _key = normaliz(key); + log.debug("【boot-admin-cache】set cache value : key: {}, value: {},timeout: {}", _key, value, timeout); + if (timeout == -1) { + this.redisTemplate.opsForValue().set(_key, value); + } else { + this.redisTemplate.opsForValue().set(_key, value, timeout, unit); + } + return Boolean.TRUE; + } + + /** + * 获取缓存 + * + * @param key,自动追加前缀{@link #normaliz(String)} + * @return . + */ + @Nonnull + public Optional getStr(final String key) { + String _key = normaliz(key); + return Optional.ofNullable(this.redisTemplate.opsForValue().get(_key)); + } + + /** + * 获取缓存 + * + * @param key key + * @return . + */ + public Optional defaultGet(final String key) { + return Optional.ofNullable(this.redisTemplate.opsForValue().get(key)); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + @Nonnull + public Optional> hmget(final String key) { + String _key = normaliz(key); + Map entries = this.redisTemplate.opsForHash().entries(_key); + return Optional.of(entries).map(Map::entrySet).map(entries1 -> { + Map map = new HashMap<>(entries1.size()); + entries1.forEach(entry -> map.put(entry.getKey().toString(), entry.getValue().toString())); + return map; + }); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key . + * @return . + */ + @Nonnull + public Optional> sGet(final String key) { + String _key = normaliz(key); + return Optional.ofNullable(this.redisTemplate.opsForSet().members(_key)); + } + + /** + * 获取list缓存的内容,默认 0 到 -1 + * + * @param key . + * @return . + */ + @Nonnull + public Optional> lGet(final String key) { + return lGet(key, 0, -1); + } + + /** + * 获取list缓存的内容, 0 到 -1代表所有值 + * + * @param key . + * @param start 开始 + * @param end 结束 + * @return . + */ + public Optional> lGet(final String key, long start, long end) { + String _key = normaliz(key); + return Optional.ofNullable(this.redisTemplate.opsForList().range(_key, start, end)); + } + + /** + * 批量删除 + * + * @param keys . + * @return . + */ + public boolean del(Collection keys) { + if (CollUtil.isEmpty(keys)) { + return Boolean.FALSE; + } + keys.forEach(this::del); + return Boolean.TRUE; + } + + /** + * 删除缓存 + * + * @param key,自动追加前缀{@link #normaliz(String)} + * @return . + */ + public boolean del(final String key) { + String _key = normaliz(key); + return Boolean.TRUE.equals(this.redisTemplate.delete(_key)); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/cache/BootAdminProperties.java b/src/main/java/com/hb0730/boot/admin/config/cache/BootAdminProperties.java new file mode 100644 index 0000000..0a06ad7 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/cache/BootAdminProperties.java @@ -0,0 +1,35 @@ +package com.hb0730.boot.admin.config.cache; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author hb0730 + * @date 2023/1/11 + */ +@Configuration +@ConfigurationProperties(prefix = "boot.admin") +@Data +public class BootAdminProperties { + /** + * 缓存 + */ + private CacheProperties cache = new CacheProperties(); + /** + * 是否刷新路由,默认不刷新 + *

+ * 一般用于用户权限发生变化时,刷新路由,如果用户量过多,不建议启用 + *

+ */ + public Boolean refreshRoutes = false; + + @Data + public static class CacheProperties { + /** + * 前缀 + */ + private String prefix = "boot:admin:cache"; + + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/cache/CacheUtil.java b/src/main/java/com/hb0730/boot/admin/config/cache/CacheUtil.java new file mode 100644 index 0000000..80400e7 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/cache/CacheUtil.java @@ -0,0 +1,37 @@ +package com.hb0730.boot.admin.config.cache; + +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * @author hb0730 + * @date 2023/1/30 + */ +public interface CacheUtil { + /** + * 缓存关键字连接符号:冒号 + */ + String CACHE_SPLICE_COLON = ":"; + + + /** + * 缓存KEY组装器 + * + * @param kv 缓存枚举 + * @param keys 缓存key拼接字符 + */ + default String getCacheKey(KeyValue kv, Object... keys) { + return buildKeys(kv, keys); + } + + static String buildKeys(KeyValue kv, Object... keys) { + if (keys.length == 0) { + return kv.getPrefix(); + } + return kv.getPrefix() + CACHE_SPLICE_COLON + concatKeys(keys); + } + + static String concatKeys(Object... keys) { + return Arrays.stream(keys).map(String::valueOf).collect(Collectors.joining(CACHE_SPLICE_COLON)); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/cache/DefaultKeyValue.java b/src/main/java/com/hb0730/boot/admin/config/cache/DefaultKeyValue.java new file mode 100644 index 0000000..3ab7f51 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/cache/DefaultKeyValue.java @@ -0,0 +1,96 @@ +package com.hb0730.boot.admin.config.cache; + +/** + * 非系统级别的缓存定义 + * + * @author hb0730 + * @date 2023/6/6 + */ +public enum DefaultKeyValue implements KeyValue { + + /** + * 【系统配置项】 + * -------------------------------------------------------------------------------- + *

系统配置表【sys_config】缓存

+ * -------------------------------------------------------------------------------- + */ + SYS_CONFIG("SYS", + EXPIRE_TIME_DEFAULT, + CacheType.STRING, + String.class, + "系统配置", + "SYS:key --> (String)value"), + + ; + /** + * KEY前缀 + */ + private final String prefix; + /** + * 过期时间(秒) + */ + private final long expire; + /** + * 缓存对象 + */ + private final Class clazz; + /** + * 缓存名称 + */ + private final String name; + + /** + * 缓存说明 + */ + private final String desc; + /** + * 缓存的数据类型 {涉及JimDB缓存的 get、set 方法使用} + */ + private CacheType type; + + DefaultKeyValue(String prefix, long expire, CacheType type, Class clazz, String name, String desc) { + this.prefix = prefix; + this.expire = expire; + this.clazz = clazz; + this.name = name; + this.desc = desc; + this.type = type; + } + + @Override + public String getPrefix() { + return prefix; + } + + @Override + public long getExpire() { + return expire; + } + + @Override + public Class getClazz() { + return clazz; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDesc() { + return desc; + } + + public CacheType getType() { + return type; + } + + /** + * JimDB缓存的数据类型 + *

涉及如何 set、get

+ */ + public enum CacheType { + STRING, OBJECT, HASHMAP, SET, LIST + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/cache/KeyValue.java b/src/main/java/com/hb0730/boot/admin/config/cache/KeyValue.java new file mode 100644 index 0000000..b621ce1 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/cache/KeyValue.java @@ -0,0 +1,65 @@ +package com.hb0730.boot.admin.config.cache; + +/** + * 缓存定义 + * + * @author hb0730 + * @date 2023/1/30 + */ +public interface KeyValue { + + /** + * 缓存key的失效时间 + *

不设置失效时间 == 永久有效 ; + * XXX: setObject方法设为-1时,经封装后代表永久有效 + *

单位:秒 + */ + long EXPIRE_TIME_DEFAULT = -1; + + /** + * 工单号在缓存存储时间 90天 + */ + long ORDER_TIME_OUT_LIMIT = 60 * 60 * 24 * 30; + /** + * KEY前缀 + * + * @return 前缀 + */ + default String getPrefix() { + return ""; + } + + /** + * 过期时间(秒) + * + * @return 过期时间 + */ + default long getExpire() { + return 0L; + } + + /** + * 缓存对象 + * + * @return 缓存对象 + */ + default Class getClazz() { + return null; + } + + /** + * 缓存名称 + * + * @return 缓存名称 + */ + default String getName() { + return ""; + } + + /** + * 缓存说明 + */ + default String getDesc() { + return ""; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/cors/CorsConfiguration.java b/src/main/java/com/hb0730/boot/admin/config/cors/CorsConfiguration.java new file mode 100644 index 0000000..6d05117 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/cors/CorsConfiguration.java @@ -0,0 +1,28 @@ +package com.hb0730.boot.admin.config.cors; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +/** + * 跨域 + * + * @author hb0730 + * @date 2023/1/11 + */ +@Configuration +public class CorsConfiguration { + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + org.springframework.web.cors.CorsConfiguration config = new org.springframework.web.cors.CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOriginPattern("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/handler/JsonHandler.java b/src/main/java/com/hb0730/boot/admin/config/handler/JsonHandler.java new file mode 100644 index 0000000..02634eb --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/handler/JsonHandler.java @@ -0,0 +1,34 @@ +package com.hb0730.boot.admin.config.handler; + +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.hb0730.boot.admin.modules.api.buiness.model.PictureEntity; + +import java.util.List; + +/** + * JSON转对象 + * @author jianpòlan + * @version 1.0 + **/ +public class JsonHandler extends JacksonTypeHandler { + + private final Class type; + + public JsonHandler(Class type) { + super(type); + this.type = type; + } + + @Override + protected Object parse(String json) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(json, new TypeReference>() { }); + }catch (Exception e){ + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/config/jackson/JacksonConfig.java b/src/main/java/com/hb0730/boot/admin/config/jackson/JacksonConfig.java new file mode 100644 index 0000000..3f03879 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/jackson/JacksonConfig.java @@ -0,0 +1,68 @@ +package com.hb0730.boot.admin.config.jackson; + +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.math.BigInteger; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; + +/** + * jackson 序列化与反序列化 + * + * @author hb0730 + * @date 2023/2/12 + */ +@Configuration +public class JacksonConfig { + private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; + + private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; + + @Bean + public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { + return builder -> { + // 这一部分也可以在 yaml 中配置 + builder + // 序列化时,对象为 null,是否抛异常 + .failOnEmptyBeans(false) + // 反序列化时,json 中包含 pojo 不存在属性时,是否抛异常 + .failOnUnknownProperties(false) + // 禁止将 java.util.Date, Calendar 序列化为数字(时间戳) + .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + // 设置 java.util.Date, Calendar 序列化、反序列化的格式 + .dateFormat(new SimpleDateFormat(DEFAULT_DATETIME_PATTERN)) + // 设置 java.util.Date、Calendar 序列化、反序列化的时区 + .timeZone(TimeZone.getTimeZone("GMT+8")) + ; + // Jackson 序列化 long类型为String,解决后端返回的Long类型在前端精度丢失的问题 + builder.serializerByType(BigInteger.class, ToStringSerializer.instance); + builder.serializerByType(Long.class, ToStringSerializer.instance); + builder.serializerByType(Long.TYPE, ToStringSerializer.instance); + // 配置 Jackson 反序列化 LocalDateTime、LocalDate、LocalTime 时使用的格式 + builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN))); + builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); + builder.deserializerByType(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); + + // 配置 Jackson 序列化 LocalDateTime、LocalDate、LocalTime 时使用的格式 + builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN))); + builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); + builder.serializers(new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); + }; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/mybatis/MybatisConfiguration.java b/src/main/java/com/hb0730/boot/admin/config/mybatis/MybatisConfiguration.java new file mode 100644 index 0000000..65f485c --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/mybatis/MybatisConfiguration.java @@ -0,0 +1,29 @@ +package com.hb0730.boot.admin.config.mybatis; + +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author hb0730 + * @date 2023/1/11 + */ +@Configuration +@MapperScan(basePackages = "com.hb0730.boot.admin.**.mapper") +public class MybatisConfiguration { + /** + * 插件 + * + * @return . + */ + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); + return interceptor; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/config/springdoc/SpringdocConfiguration.java b/src/main/java/com/hb0730/boot/admin/config/springdoc/SpringdocConfiguration.java new file mode 100644 index 0000000..535060d --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/config/springdoc/SpringdocConfiguration.java @@ -0,0 +1,54 @@ +package com.hb0730.boot.admin.config.springdoc; + +import com.hb0730.boot.admin.base.BootAdminConst; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author hb0730 + * @date 2023/1/12 + */ +@Configuration +public class SpringdocConfiguration { + @Bean + public OpenAPI openAPI() { + return new OpenAPI() + .info(getInfo() + ).addSecurityItem( + new io.swagger.v3.oas.models.security.SecurityRequirement() + .addList(BootAdminConst.X_ACCESS_TOKEN) + ).schemaRequirement( + BootAdminConst.X_ACCESS_TOKEN, + securityScheme() + ).components( + new Components() + .addSecuritySchemes(BootAdminConst.X_ACCESS_TOKEN, securityScheme()) + ); + } + + private Info getInfo() { + return new Info() + .title("boot-admin系统API") + .contact( + new Contact() + .name("hb0730") + .url("https://blog.hb0730.me") + .email("huangbing0730@gmail.com") + ) + .version("v5.0.0") + ; + } + + private SecurityScheme securityScheme() { + SecurityScheme securityScheme = new SecurityScheme(); + securityScheme.setType(SecurityScheme.Type.APIKEY); + securityScheme.setName(BootAdminConst.X_ACCESS_TOKEN); + securityScheme.setIn(SecurityScheme.In.HEADER); + return securityScheme; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/core/service/BaseServiceImpl.java b/src/main/java/com/hb0730/boot/admin/core/service/BaseServiceImpl.java new file mode 100644 index 0000000..a8e90e5 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/core/service/BaseServiceImpl.java @@ -0,0 +1,17 @@ +package com.hb0730.boot.admin.core.service; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.service.IService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +@Slf4j +public class BaseServiceImpl< + M extends BaseMapper, + T + > extends ServiceImpl implements IService { +} diff --git a/src/main/java/com/hb0730/boot/admin/data/domain/BaseEntity.java b/src/main/java/com/hb0730/boot/admin/data/domain/BaseEntity.java new file mode 100644 index 0000000..2f688d8 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/domain/BaseEntity.java @@ -0,0 +1,52 @@ +package com.hb0730.boot.admin.data.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode +@ToString +public class BaseEntity implements Serializable { + + /** + * ID + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; +} diff --git a/src/main/java/com/hb0730/boot/admin/data/domain/BasePage.java b/src/main/java/com/hb0730/boot/admin/data/domain/BasePage.java new file mode 100644 index 0000000..6c12867 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/domain/BasePage.java @@ -0,0 +1,84 @@ +package com.hb0730.boot.admin.data.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +/** + * 分页基类 + * + * @author hb0730 + * @date 2023/2/28 + */ +@Data +@EqualsAndHashCode +@ToString +public class BasePage implements Serializable { + /** + * 数据集合 + */ + @Schema(description = "数据集合") + private List records; + /** + * 数据总数 + */ + @Schema(description = "数据总数") + private long total; + /** + * 分页size + */ + @Schema(description = "分页size") + private long size; + /** + * 当前页码 + */ + @Schema(description = "当前页码") + private long current; + + public BasePage() { + this.records = Collections.emptyList(); + this.total = 0L; + this.size = 0L; + this.current = 0L; + } + + public BasePage(long current, long size) { + this(current, size, 0L); + } + + public BasePage(long current, long size, long total) { + this(current, size, total, null); + } + + public BasePage(long current, long size, long total, List records) { + this.setCurrent(current) + .setSize(size) + .setTotal(total) + .setRecords(records); + } + + public BasePage setCurrent(long current) { + this.current = current; + return this; + } + + public BasePage setSize(long size) { + this.size = size; + return this; + } + + public BasePage setTotal(long total) { + this.total = total; + return this; + } + + public BasePage setRecords(List records) { + this.records = records; + return this; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/data/domain/BasePageQuery.java b/src/main/java/com/hb0730/boot/admin/data/domain/BasePageQuery.java new file mode 100644 index 0000000..be6c0ca --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/domain/BasePageQuery.java @@ -0,0 +1,27 @@ +package com.hb0730.boot.admin.data.domain; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +/** + * 分页查询基类 + * + * @author hb0730 + * @date 2023/1/12 + */ +@Data +@EqualsAndHashCode +@ToString +public class BasePageQuery implements Serializable { + @Parameter(description = "分页size") + @Schema(description = "分页size") + private long size; + @Parameter(description = "当前页数") + @Schema(description = "当前页数") + private long current; +} diff --git a/src/main/java/com/hb0730/boot/admin/data/domain/TreeData.java b/src/main/java/com/hb0730/boot/admin/data/domain/TreeData.java new file mode 100644 index 0000000..0c76b69 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/domain/TreeData.java @@ -0,0 +1,42 @@ +package com.hb0730.boot.admin.data.domain; + +import java.io.Serializable; +import java.util.List; + +/** + * 数据结构的数据 + * + * @param . + * @author hb0730 + * @date 2023/1/12 + */ +public interface TreeData> extends Serializable { + /** + * id + * + * @return . + */ + String getId(); + + /** + * parent id + * + * @return . + */ + String getParentId(); + + /** + * children + * + * @return . + */ + List getChildren(); + + /** + * set children + * + * @param data . + * @return . + */ + TreeData setChildren(List data); +} diff --git a/src/main/java/com/hb0730/boot/admin/data/enums/ConfigTypeEnums.java b/src/main/java/com/hb0730/boot/admin/data/enums/ConfigTypeEnums.java new file mode 100644 index 0000000..66c2d90 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/enums/ConfigTypeEnums.java @@ -0,0 +1,29 @@ +package com.hb0730.boot.admin.data.enums; + +/** + * 配置类型 + * + * @author hb0730 + * @date 2023/6/12 + */ +public enum ConfigTypeEnums implements ValueEnum { + CONFIG_TYPE01(1, "系统配置"), + CONFIG_TYPE02(2, "业务配置"), + ; + private final Integer value; + private final String name; + + ConfigTypeEnums(Integer value, String name) { + this.value = value; + this.name = name; + } + + @Override + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/data/enums/EnabledEnums.java b/src/main/java/com/hb0730/boot/admin/data/enums/EnabledEnums.java new file mode 100644 index 0000000..e5a4d29 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/enums/EnabledEnums.java @@ -0,0 +1,38 @@ +package com.hb0730.boot.admin.data.enums; + +/** + * @author hb0730 + * @date 2023/1/11 + */ +public enum EnabledEnums implements ValueEnum { + /** + * 启用:1 + */ + enabled("启用", "", 1), + /** + * 禁用:0 + */ + un_enabled("禁用", "", 0); + private final String name; + private final String alias; + private final Integer value; + + EnabledEnums(String name, String alias, Integer value) { + this.name = name; + this.alias = alias; + this.value = value; + } + + public String getName() { + return name; + } + + public String getAlias() { + return alias; + } + + @Override + public Integer getValue() { + return value; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/data/enums/GenderEnums.java b/src/main/java/com/hb0730/boot/admin/data/enums/GenderEnums.java new file mode 100644 index 0000000..4983e59 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/enums/GenderEnums.java @@ -0,0 +1,45 @@ +package com.hb0730.boot.admin.data.enums; + +/** + * 性别 + * + * @author hb0730 + * @date 2023/1/11 + */ +public enum GenderEnums implements ValueEnum { + /** + * 未知 + */ + unknown("未知", "保密", -1), + /** + * 男性 + */ + man("男", "先生", 0), + /** + * 女性 + */ + woman("女", "女士", 1), + ; + private final String name; + private final String alias; + private final Integer value; + + GenderEnums(String name, String alias, Integer value) { + this.name = name; + this.alias = alias; + this.value = value; + } + + public String getName() { + return name; + } + + public String getAlias() { + return alias; + } + + @Override + public Integer getValue() { + return value; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/data/enums/MenuTypeEnums.java b/src/main/java/com/hb0730/boot/admin/data/enums/MenuTypeEnums.java new file mode 100644 index 0000000..efb0c80 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/enums/MenuTypeEnums.java @@ -0,0 +1,30 @@ +package com.hb0730.boot.admin.data.enums; + +/** + * 菜单类型 + * + * @author hb0730 + * @date 2023/1/12 + */ +public enum MenuTypeEnums implements ValueEnum { + dir("目录", 0), + menu("菜单", 1), + permission("权限", 2), + ; + private final String name; + private final Integer value; + + MenuTypeEnums(String name, Integer value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + @Override + public Integer getValue() { + return value; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/data/enums/OperateEnums.java b/src/main/java/com/hb0730/boot/admin/data/enums/OperateEnums.java new file mode 100644 index 0000000..a3c9189 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/enums/OperateEnums.java @@ -0,0 +1,52 @@ +package com.hb0730.boot.admin.data.enums; + +/** + * 操作 + * + * @author hb0730 + * @date 2023/1/12 + */ +public enum OperateEnums implements ValueEnum { + operate_null("", 0), + /** + * 查询 + */ + operate_query("查询", 1), + /** + * 添加 + */ + operate_add("添加", 2), + /** + * 更新 + */ + operate_edit("更新", 3), + /** + * 删除 + */ + operate_delete("删除", 4), + /** + * 导出 + */ + operate_export("导出", 5), + /** + * 导入 + */ + operate_import("导入", 6), + ; + private final String name; + private final Integer value; + + OperateEnums(String name, Integer value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + @Override + public Integer getValue() { + return value; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/data/enums/ValueEnum.java b/src/main/java/com/hb0730/boot/admin/data/enums/ValueEnum.java new file mode 100644 index 0000000..7aa2116 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/data/enums/ValueEnum.java @@ -0,0 +1,62 @@ +package com.hb0730.boot.admin.data.enums; + +import java.util.stream.Stream; + +/** + * @author hb0730 + * @date 2023/1/11 + */ +public interface ValueEnum { + /** + * Gets enum value. + * + * @return enum value + */ + T getValue(); + + /** + * Converts value to corresponding enum. + * + * @param enumType 枚举类型,不为空 + * @param value 值 + * @param 值类型 + * @param 枚举类型 + * @return corresponding enum + */ + static & ValueEnum> E valueToEnum(Class enumType, V value) { + return Stream.of(enumType.getEnumConstants()) + .filter(item -> item.getValue().equals(value)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("unknown database value: " + value)); + } + + /** + * Converts value to corresponding enum. + * + * @param enumType 枚举类型,不为空 + * @param value 值 + * @param defaultValue 默认值 + * @param 值类型 + * @param 枚举类型 + * @return corresponding enum + */ + static & ValueEnum> E valueToEnum(Class enumType, V value, E defaultValue) { + return Stream.of(enumType.getEnumConstants()) + .filter(item -> item.getValue().equals(value)) + .findFirst() + .orElse(defaultValue); + } + + /** + * 是否存在当前值 + * + * @param enumType 枚举类型 + * @param value 值 + * @param 值类型 + * @param 枚举类型 + * @return 是否存在 + */ + static & ValueEnum> boolean hash(Class enumType, V value) { + return Stream.of(enumType.getEnumConstants()).anyMatch(item -> item.getValue().equals(value)); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/job/MyTestJobService.java b/src/main/java/com/hb0730/boot/admin/job/MyTestJobService.java new file mode 100644 index 0000000..3de3cad --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/job/MyTestJobService.java @@ -0,0 +1,17 @@ +package com.hb0730.boot.admin.job; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author hb0730 + * @date 2023/6/13 + */ +@Component +@Slf4j +public class MyTestJobService { + + public void start(String params) { + log.info("MyTestJobService start {}", params); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/job/SampleInjectBeanJob.java b/src/main/java/com/hb0730/boot/admin/job/SampleInjectBeanJob.java new file mode 100644 index 0000000..fb452d3 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/job/SampleInjectBeanJob.java @@ -0,0 +1,45 @@ +package com.hb0730.boot.admin.job; + +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotNull; +import lombok.extern.slf4j.Slf4j; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.spi.TriggerFiredBundle; +import org.springframework.scheduling.quartz.QuartzJobBean; + +/** + * 依赖注入 + * + * @author hb0730 + * @date 2023/6/12 + * @see quartz + * 为什么需要@Resource或者@Autowired + * + * @param myTestJobService . + * @see org.springframework.scheduling.quartz.SpringBeanJobFactory#createJobInstance(TriggerFiredBundle) + * getAutowireCapableBeanFactory + *

+ */ + @Resource + public void setMyTestJobService(MyTestJobService myTestJobService) { + this.myTestJobService = myTestJobService; + } + + @Override + protected void executeInternal(@NotNull JobExecutionContext context) throws JobExecutionException { + log.info("普通定时任务 SampleInjectBeanJob ! 时间: {}", myTestJobService); + JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); + String parameter = jobDataMap.getString("parameter"); + myTestJobService.start(parameter); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/job/SampleJob.java b/src/main/java/com/hb0730/boot/admin/job/SampleJob.java new file mode 100644 index 0000000..c01467b --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/job/SampleJob.java @@ -0,0 +1,21 @@ +package com.hb0730.boot.admin.job; + +import cn.hutool.core.date.DateUtil; +import lombok.extern.slf4j.Slf4j; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +/** + * 示例不带参定时任务 + * + * @author hb0730 + * @date 2023/6/12 + */ +@Slf4j +public class SampleJob implements Job { + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + log.info("普通定时任务 SampleJob ! 时间: {}", DateUtil.now()); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/job/SampleParamJob.java b/src/main/java/com/hb0730/boot/admin/job/SampleParamJob.java new file mode 100644 index 0000000..8c85ab0 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/job/SampleParamJob.java @@ -0,0 +1,38 @@ +package com.hb0730.boot.admin.job; + +import cn.hutool.core.date.DateUtil; +import lombok.extern.slf4j.Slf4j; +import org.quartz.Job; +import org.quartz.JobExecutionContext; + +/** + * 带参数的JOB + * + * @author hb0730 + * @date 2023/6/12 + */ +@Slf4j +public class SampleParamJob implements Job { + + /** + * 任务参数 + */ + private String parameter; + + /** + * 设置任务参数 + * + * @param parameter 任务参数 + */ + public void setParameter(String parameter) { + this.parameter = parameter; + } + + //------------------------------------------------------------------------------------------------ + + @Override + public void execute(JobExecutionContext jobExecutionContext) { + + log.info("welcome {}! 带参数定时任务 SampleParamJob ! 时间 :{}", this.parameter, DateUtil.now()); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/OssController.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/OssController.java new file mode 100644 index 0000000..4753064 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/OssController.java @@ -0,0 +1,34 @@ +package com.hb0730.boot.admin.modules.api.buiness.controller; + +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.modules.api.buiness.service.OssService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +@Tag(name = "系统:阿里云:上传") +@RestController +@RequestMapping("buiness/oss") +public class OssController { + + @Autowired + OssService ossService; + + //1、上传文件到oss: 接收客户端上传的文件流和文件名称 上传到oss之后 返回上传成功的文件路径 + @PostMapping("upload") + @Operation(summary = "上传文件") + public R uploadFile(@RequestBody MultipartFile file + ) { + return ossService.uploadFile(file); + } + + //2、删除oss中的文件 + @DeleteMapping("delete") + @Operation(summary = "删除文件") + public R deleteFile(@RequestParam("path") String path + ) { + return ossService.deleteFile(path); + } +} \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysBoxController.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysBoxController.java new file mode 100644 index 0000000..660f9eb --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysBoxController.java @@ -0,0 +1,101 @@ +package com.hb0730.boot.admin.modules.api.buiness.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.model.SysBox; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.BoxQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.query.ShopQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.BoxVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import com.hb0730.boot.admin.modules.api.buiness.service.SysBoxService; +import com.hb0730.boot.admin.modules.api.buiness.service.SysShopService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.beans.BeanUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 包厢管理 + * + * @author hb0730 + * @date 2023/2/4 + */ +@RestController +@RequestMapping("/buiness/box") +@Tag(name = "系统:包厢管理") +@RequiredArgsConstructor +public class SysBoxController { + private final SysBoxService sysBoxService; + + + @GetMapping("/query/page") + @Operation(summary = "分页查询") + public R> queryPage(HttpServletRequest request, @ParameterObject BoxQuery query) { + BasePage res = this.sysBoxService.queryPage(query); + return R.OK(res); + } + +// @GetMapping("/query/list") +// @Operation(summary = "列表查询") +// public R> queryList(HttpServletRequest request, @ParameterObject UserQuery query) { +// List res = this.sysShopService.queryList(query); +// return R.OK(res); +// } +// +// @GetMapping("/check/username") +// @Operation(summary = "检查用户名是否存在") +// public R checkUsername(HttpServletRequest request, @RequestParam String username) { +// return this.sysBoxService.hashUsername(username); +// } +//// + @GetMapping("/") + @Operation(summary = "详情") + public R detail(HttpServletRequest request, @Parameter(name = "id", description = "包厢ID", + required = true) @RequestParam String id) { + return this.sysBoxService.detail(id); + } + + @PostMapping("/save") + @Operation(summary = "保存") + public R save(HttpServletRequest request, @Validated @RequestBody BoxVO boxVO) { + + return this.sysBoxService.saveShop(boxVO); + } + + + @PutMapping("/update/{id}") + @Operation(summary = "修改") + public R update(HttpServletRequest request,@PathVariable String id, + @Validated @RequestBody BoxVO boxVO) { + SysBox byId = sysBoxService.getById(boxVO.getId()); + boxVO.setModified(LocalDateTime.now()); + boxVO.setModifiedBy(SecurityUtil.getCurrentUsername()); + BeanUtils.copyProperties(boxVO,byId); + this.sysBoxService.updateById(byId); + return R.OK(boxVO); + } + + @GetMapping("/delete") + @Operation(summary = "删除") + public R delete(HttpServletRequest request , @RequestParam String id) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq( + "id",id + ); + return R.OK(this.sysBoxService.remove(wrapper)); + } + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysCouponController.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysCouponController.java new file mode 100644 index 0000000..321a84b --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysCouponController.java @@ -0,0 +1,102 @@ +package com.hb0730.boot.admin.modules.api.buiness.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.model.SysBox; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCoupon; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCouponLog; +import com.hb0730.boot.admin.modules.api.buiness.model.query.BoxQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.query.CouponQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.BoxVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.GetCouponLogVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import com.hb0730.boot.admin.modules.api.buiness.service.SysBoxService; +import com.hb0730.boot.admin.modules.api.buiness.service.SysCouponService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 包厢管理 + * + * @author hb0730 + * @date 2023/2/4 + */ +@RestController +@RequestMapping("/buiness/coupon") +@Tag(name = "系统:优惠券管理") +@RequiredArgsConstructor +public class SysCouponController { + private final SysCouponService sysCouponService; + + + @GetMapping("/query/page") + @Operation(summary = "分页查询") + public R> queryPage(HttpServletRequest request, @ParameterObject CouponQuery query) { + BasePage res = this.sysCouponService.queryPage(query); + return R.OK(res); + } + + @GetMapping() + @Operation(summary = "详情") + public R detail(HttpServletRequest request, @Parameter(name = "id", description = "优惠券ID", + required = true) @RequestParam String id) { + return this.sysCouponService.detail(id); + } + + @PostMapping("/save") + @Operation(summary = "保存") + public R save(HttpServletRequest request, @Validated @RequestBody CouponVO couponVO) { + + return this.sysCouponService.saveShop(couponVO); + } + + + @PutMapping("/update/{id}") + @Operation(summary = "修改") + public R update(HttpServletRequest request, @PathVariable String id, + @Validated @RequestBody CouponVO couponVO) { + couponVO.setModified(LocalDateTime.now()); + couponVO.setModifiedBy(SecurityUtil.getCurrentUsername()); + return this.sysCouponService.updateById(id, couponVO); + } + + @GetMapping("/delete") + @Operation(summary = "删除") + public R delete(HttpServletRequest request , @RequestParam String id) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq( + "id",id + ); + return R.OK(this.sysCouponService.remove(wrapper)); + } + + + @GetMapping("/getCoupon") + @Operation(summary = "领取取优惠券") + public R getCoupon(HttpServletRequest request , @RequestParam("id") String id , @RequestParam String openId) { + return this.sysCouponService.getCoupon(id,openId); + } + + @GetMapping("/verification") + @Operation(summary = "核销优惠券") + public R verification(HttpServletRequest request ,@Parameter(name = "id", description = "领取记录表ID", + required = true) @RequestParam String id , + @Parameter(name = "checkCode", description = "核销码", + required = true)@RequestParam String checkCode) { + return this.sysCouponService.verification(id,checkCode); + } + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysCouponLogController.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysCouponLogController.java new file mode 100644 index 0000000..e0ac3f3 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysCouponLogController.java @@ -0,0 +1,82 @@ +package com.hb0730.boot.admin.modules.api.buiness.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCoupon; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCouponLog; +import com.hb0730.boot.admin.modules.api.buiness.model.query.CouponQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponLogVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponVO; +import com.hb0730.boot.admin.modules.api.buiness.service.SysCouponLogService; +import com.hb0730.boot.admin.modules.api.buiness.service.SysCouponService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; + +/** + * 包厢管理 + * + * @author hb0730 + * @date 2023/2/4 + */ +@RestController +@RequestMapping("/buiness/couponLog") +@Tag(name = "系统:优惠券领取记录管理") +@RequiredArgsConstructor +public class SysCouponLogController { + private final SysCouponLogService sysCouponLogService; + + + @GetMapping("/query/page") + @Operation(summary = "分页查询") + public R> queryPage(HttpServletRequest request, @ParameterObject CouponQuery query) { + BasePage res = this.sysCouponLogService.queryPage(query); + return R.OK(res); + } + + @GetMapping() + @Operation(summary = "详情") + public R detail(HttpServletRequest request, @Parameter(name = "id", description = "优惠券ID", + required = true) @RequestParam String id) { + return this.sysCouponLogService.detail(id); + } + + @PostMapping("/save") + @Operation(summary = "保存") + public R save(HttpServletRequest request, @Validated @RequestBody CouponLogVO couponlogVO) { + + return this.sysCouponLogService.saveShop(couponlogVO); + } + + + @PutMapping("/update/{id}") + @Operation(summary = "修改") + public R update(HttpServletRequest request, @PathVariable String id, + @Validated @RequestBody CouponLogVO couponVO) { + couponVO.setModified(LocalDateTime.now()); + couponVO.setModifiedBy(SecurityUtil.getCurrentUsername()); + return this.sysCouponLogService.updateById(id, couponVO); + } + + @GetMapping("/delete") + @Operation(summary = "删除") + public R delete(HttpServletRequest request , @RequestParam String id) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq( + "id",id + ); + return R.OK(this.sysCouponLogService.remove(wrapper)); + } + + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysShopController.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysShopController.java new file mode 100644 index 0000000..a514d99 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/controller/SysShopController.java @@ -0,0 +1,103 @@ +package com.hb0730.boot.admin.modules.api.buiness.controller; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.ShopQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.HourVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.SeasonVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import com.hb0730.boot.admin.modules.api.buiness.service.SysShopService; +import com.hb0730.boot.admin.modules.sys.system.model.query.UserQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.RestPasswdVO; +import com.hb0730.boot.admin.modules.sys.system.model.vo.UserVO; +import com.hb0730.boot.admin.modules.sys.system.service.SysUserService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +/** + * 店铺管理 + * + * @author hb0730 + * @date 2023/2/4 + */ +@RestController +@RequestMapping("/buiness/shop") +@Tag(name = "系统:店铺管理") +@RequiredArgsConstructor +public class SysShopController { + private final SysShopService sysShopService; + + + @GetMapping("/query/page") + @Operation(summary = "分页查询") + public R> queryPage(HttpServletRequest request, @ParameterObject ShopQuery query) { + + BasePage res = this.sysShopService.queryPage(query); + + return R.OK(res); + } + + @GetMapping + @Operation(summary = "详情") + public R detail(HttpServletRequest request, @Parameter(name = "id", description = "店铺ID", + required = true) @RequestParam String id) { + return this.sysShopService.detail(id); + } + + @PostMapping("/save") + @Operation(summary = "保存") + public R save(HttpServletRequest request, @Validated @RequestBody ShopVO shopVO) { + + return this.sysShopService.saveShop(shopVO); + } +// +// + @PutMapping("/update/{id}") + @Operation(summary = "修改") + public R update(HttpServletRequest request, @PathVariable String id, + @Validated @RequestBody ShopVO shopVO) { + shopVO.setModified(LocalDateTime.now()); + shopVO.setModifiedBy(SecurityUtil.getCurrentUsername()); + return this.sysShopService.updateById(id, shopVO); + } + + @GetMapping("/delete") + @Operation(summary = "删除") + public R delete(HttpServletRequest request , @RequestParam String id) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq( + "id",id + ); + return R.OK(this.sysShopService.remove(wrapper)); + } + + + @GetMapping("/getSeason") + @Operation(summary = "获取季节菜品") + public R> getSeason(HttpServletRequest request) { + return R.OK(this.sysShopService.getSeason()); + } + + @GetMapping("/getHour") + @Operation(summary = "获取小时菜品") + public R> getHour(HttpServletRequest request) { + return R.OK(this.sysShopService.getHour()); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysBoxMapper.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysBoxMapper.java new file mode 100644 index 0000000..a92fca4 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysBoxMapper.java @@ -0,0 +1,19 @@ +package com.hb0730.boot.admin.modules.api.buiness.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.modules.api.buiness.model.SysBox; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.BoxQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.query.ShopQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.BoxVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface SysBoxMapper extends BaseMapper { + List queryPage(Page page, @Param("query") BoxQuery query); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysCouponLogMapper.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysCouponLogMapper.java new file mode 100644 index 0000000..6b445d1 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysCouponLogMapper.java @@ -0,0 +1,18 @@ +package com.hb0730.boot.admin.modules.api.buiness.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCoupon; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCouponLog; +import com.hb0730.boot.admin.modules.api.buiness.model.query.CouponQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponLogVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface SysCouponLogMapper extends BaseMapper { + List queryPage(Page page, @Param("query") CouponQuery query); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysCouponMapper.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysCouponMapper.java new file mode 100644 index 0000000..bfad284 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysCouponMapper.java @@ -0,0 +1,21 @@ +package com.hb0730.boot.admin.modules.api.buiness.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.modules.api.buiness.model.SysBox; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCoupon; +import com.hb0730.boot.admin.modules.api.buiness.model.query.BoxQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.query.CouponQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.BoxVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface SysCouponMapper extends BaseMapper { + List queryPage(Page page, @Param("query") CouponQuery query); + + void updateNums(@Param("id")String id); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysShopMapper.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysShopMapper.java new file mode 100644 index 0000000..ae431c5 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/SysShopMapper.java @@ -0,0 +1,22 @@ +package com.hb0730.boot.admin.modules.api.buiness.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.ShopQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.HourVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.SeasonVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface SysShopMapper extends BaseMapper { + List queryPage(Page page, @Param("query") ShopQuery query); + + List getSeason(); + + List getHour(); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysBoxMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysBoxMapper.xml new file mode 100644 index 0000000..0c271ca --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysBoxMapper.xml @@ -0,0 +1,31 @@ + + + + + + t.id, + t.created_by, + t.created, + t.modified_by, + t.modified, + t.name, + t.min, + t.max, + t.images_url, + t.shop_id, + t.nums + + + + + + \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysCouponLogMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysCouponLogMapper.xml new file mode 100644 index 0000000..d329973 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysCouponLogMapper.xml @@ -0,0 +1,27 @@ + + + + + + t.id, + t.created_by, + t.created, + t.modified_by, + t.modified, + t.user_id, + t.coupon_id, + t.open_id, + t.check_code, + t.user_name, + t.gift_name + + + + \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysCouponMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysCouponMapper.xml new file mode 100644 index 0000000..df84b81 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysCouponMapper.xml @@ -0,0 +1,38 @@ + + + + + + t.id, + t.created_by, + t.created, + t.modified_by, + t.modified, + t.coupon_name, + t.nums, + t.title, + t.receive_date, + t.receive_time, + t.activity_rules, + t.activity_dec, + t.gift_name, + t.gift_image, + t.open_id, + t.tag_img + + + + + + + + UPDATE sys_coupon SET nums = nums - 1 WHERE id = #{id}; + + + \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysShopMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysShopMapper.xml new file mode 100644 index 0000000..0e344c3 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/mapper/xml/SysShopMapper.xml @@ -0,0 +1,53 @@ + + + + + + t.id, + t.created_by, + t.created, + t.modified_by, + t.modified, + t.name, + t.intro_chi as introChi, + t.intro_eng as introEng, + t.intro_jap as introJap, + t.phone, + t.start_time, + t.end_time, + t.tag_url, + t.logo_url, + t.picture_url, + t.floor, + t.vagetable_url, + t.is_enable as isEnable, + t.name_picture, + t.title, + t.season, + t.hour, + t.sort + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/PictureEntity.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/PictureEntity.java new file mode 100644 index 0000000..c000b65 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/PictureEntity.java @@ -0,0 +1,10 @@ +package com.hb0730.boot.admin.modules.api.buiness.model; + +import lombok.Data; + +@Data +public class PictureEntity { + + public String name; + public String url; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysBox.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysBox.java new file mode 100644 index 0000000..1ea3fcb --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysBox.java @@ -0,0 +1,45 @@ +package com.hb0730.boot.admin.modules.api.buiness.model; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 包厢表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName +public class SysBox extends BaseEntity { + /** + * 包厢名称 + */ + private String name; + /** + * 包厢最小人数 + */ + private Integer min; + /** + * 包厢最大人数 + */ + private Integer max; + /** + * 包厢图片路径 + */ + private String imagesUrl; + /** + * 所属店铺id + */ + private String shopId; + + /** + * 包厢数量 + */ + private Integer nums; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysCoupon.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysCoupon.java new file mode 100644 index 0000000..300633a --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysCoupon.java @@ -0,0 +1,51 @@ +package com.hb0730.boot.admin.modules.api.buiness.model; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 优惠券表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName(value = "sys_coupon",autoResultMap = true) +public class SysCoupon extends BaseEntity { + /** + *优惠券名称 + */ + private String couponName; + + /** + * 优惠券数量 + */ + private Integer nums; + + private String userId; + + private String title; + + private String receiveDate; + + private String receiveTime; + + private String activityRules; + + private String activityDec; + + + private String giftName; + + + private String giftImage; + private String openId; + + private String tagImg; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysCouponLog.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysCouponLog.java new file mode 100644 index 0000000..f1e1ec9 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysCouponLog.java @@ -0,0 +1,37 @@ +package com.hb0730.boot.admin.modules.api.buiness.model; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 优惠券表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName(value = "sys_coupon_log") +public class SysCouponLog extends BaseEntity { + /** + *优惠券名称 + */ + private String title; + + private String userId; + + private String couponId; + + private String openId; + + private String checkCode; + + private String userName; + + private String giftName; + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysShop.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysShop.java new file mode 100644 index 0000000..d1704fb --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/SysShop.java @@ -0,0 +1,100 @@ +package com.hb0730.boot.admin.modules.api.buiness.model; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.config.handler.JsonHandler; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +/** + * 店铺表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName(value = "sys_shop",autoResultMap = true) +public class SysShop extends BaseEntity { + /** + * 店铺名称 + */ + private String name; + /** + * 店铺介绍(中文) + */ + private String introChi; + /** + * 店铺介绍(英文) + */ + private String introEng; + /** + * 店铺介绍(日文) + */ + private String introJap; + /** + * 预约电话 + */ + private String phone; + /** + * 营业时间(开始时间) + */ + private String startTime; + /** + * 营业时间(结束时间) + */ + private String endTime; + + /** + * 标签图片url + */ + private String tagUrl; + + /** + * logo url + */ + private String logoUrl; + + /** + * 名字url + */ + private String namePicture; + /** + * 轮播图url + */ + @TableField(value = "picture_url") + private String pictureUrl; + + @TableField(value = "vagetable_url") + private String vagetableUrl; + + /** + * 店铺楼层 + */ + private Integer floor; + /** + * 是否启用,true:启用,false:禁用 + */ + @TableField(value = "is_enable" ) + private Boolean isEnable= false; + + @TableField(value = "season" ) + private String season; + + @TableField(value = "title") + private String title; + +@TableField(value = "hour") + private String hour; + + @Schema(description = "排序") + @TableField(value = "sort") + private Integer sort; + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/BoxQuery.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/BoxQuery.java new file mode 100644 index 0000000..6675772 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/BoxQuery.java @@ -0,0 +1,25 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 用户查询参数 + * + * @author hb0730 + * @date 2023/6/8 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class BoxQuery extends BasePageQuery { + + /** + * 店铺id + */ + @Parameter(description = "店铺id") + private String shopId; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/CouponQuery.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/CouponQuery.java new file mode 100644 index 0000000..93ecdc6 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/CouponQuery.java @@ -0,0 +1,22 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 用户查询参数 + * + * @author hb0730 + * @date 2023/6/8 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class CouponQuery extends BasePageQuery { + + + private String id; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/ShopQuery.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/ShopQuery.java new file mode 100644 index 0000000..f8753a6 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/query/ShopQuery.java @@ -0,0 +1,25 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 用户查询参数 + * + * @author hb0730 + * @date 2023/6/8 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class ShopQuery extends BasePageQuery { + + /** + * 店铺名称 + */ + @Parameter(description = "店铺名称") + private String name; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/BoxVO.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/BoxVO.java new file mode 100644 index 0000000..b55f746 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/BoxVO.java @@ -0,0 +1,80 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 用户信息 + * + * @author hb0730 + * @date 2023/6/8 + */ +@Data +@EqualsAndHashCode +@ToString +public class BoxVO implements Serializable { + /** + * ID + */ + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; + + /** + * 所属店铺id + */ + @Schema(description = "更新时间") + private String shopId; + + /** + * 包厢名称 + */ + @Schema(description = "包厢名称") + private String name; + /** + * 包厢最小人数 + */ + @Schema(description = "包厢最小人数") + private Integer min; + /** + * 包厢最大人数 + */ + @Schema(description = "包厢最大人数") + private Integer max; + /** + * 包厢图片路径 + */ + @Schema(description = "包厢图片路径") + private String imagesUrl; + + @Schema(description = "包厢数量") + private Integer nums; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/CouponLogVO.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/CouponLogVO.java new file mode 100644 index 0000000..9970034 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/CouponLogVO.java @@ -0,0 +1,98 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.vo; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +/** + * 包厢表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName +public class CouponLogVO extends BaseEntity { + + + /** + * ID + */ + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; + /** + * 优惠券名称 + */ + @Schema(description = "优惠券名称") + private String couponName; + /** + * 用户id + */ + @Schema(description = "用户id") + private String userId; + + @Schema(description = "openId") + private String openId; + /** + * 优惠券数量 + */ + @Schema(description = "优惠券数量") + private Integer nums; + + @Schema(description = "优惠券标题") + private String title; + + @Schema(description = "优惠券领取日期") + private String receiveDate; + + @Schema(description = "优惠券领取时间") + private String receiveTime; + + @Schema(description = "活动规则") + private String activityRules; + + @Schema(description = "活动说明") + private String activityDec; + + + @Schema(description = "礼品名称") + private String giftName; + + @Schema(description = "礼品图片") + private String giftImage; + @Schema(description = "优惠券ID") + private String couponId; + + private String checkCode; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/CouponVO.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/CouponVO.java new file mode 100644 index 0000000..43fb5fe --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/CouponVO.java @@ -0,0 +1,96 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.vo; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +/** + * 包厢表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName +public class CouponVO extends BaseEntity { + + + /** + * ID + */ + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; + /** + * 优惠券名称 + */ + @Schema(description = "优惠券名称") + private String couponName; + /** + * 用户id + */ + @Schema(description = "用户id") + private String userId; + + @Schema(description = "openId") + private String openId; + /** + * 优惠券数量 + */ + @Schema(description = "优惠券数量") + private Integer nums; + + @Schema(description = "优惠券标题") + private String title; + + @Schema(description = "优惠券领取日期") + private String receiveDate; + + @Schema(description = "优惠券领取时间") + private String receiveTime; + + @Schema(description = "活动规则") + private String activityRules; + + @Schema(description = "活动说明") + private String activityDec; + + + @Schema(description = "礼品名称") + private String giftName; + + @Schema(description = "礼品图片") + private String giftImage; + @Schema(description = "标签图片") + private String tagImg; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/GetCouponLogVO.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/GetCouponLogVO.java new file mode 100644 index 0000000..dc1374b --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/GetCouponLogVO.java @@ -0,0 +1,99 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.vo; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +/** + * 包厢表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName +public class GetCouponLogVO extends BaseEntity { + + + /** + * ID + */ + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; + /** + * 优惠券名称 + */ + @Schema(description = "优惠券名称") + private String couponName; + /** + * 用户id + */ + @Schema(description = "用户id") + private String userId; + + @Schema(description = "openId") + private String openId; + /** + * 优惠券数量 + */ + @Schema(description = "优惠券数量") + private Integer nums; + + @Schema(description = "优惠券标题") + private String title; + + @Schema(description = "优惠券领取日期") + private String receiveDate; + + @Schema(description = "优惠券领取时间") + private String receiveTime; + + @Schema(description = "活动规则") + private String activityRules; + + @Schema(description = "活动说明") + private String activityDec; + + + @Schema(description = "礼品名称") + private String giftName; + + @Schema(description = "礼品图片") + private String giftImage; + @Schema(description = "优惠券ID") + private String couponId; + + @Schema(description = "用户名称") + private String userName; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/HourVO.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/HourVO.java new file mode 100644 index 0000000..54b88d8 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/HourVO.java @@ -0,0 +1,12 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class HourVO { + @Schema(description = "id") + private String id; + @Schema(description = "小时菜品url") + private String hour; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/SeasonVO.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/SeasonVO.java new file mode 100644 index 0000000..8f18330 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/SeasonVO.java @@ -0,0 +1,13 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class SeasonVO { + + @Schema(description = "id") + private String id; + @Schema(description = "季节菜品url") + private String season; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/ShopVO.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/ShopVO.java new file mode 100644 index 0000000..dfe1738 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/model/vo/ShopVO.java @@ -0,0 +1,141 @@ +package com.hb0730.boot.admin.modules.api.buiness.model.vo; + +import cn.hutool.core.util.StrUtil; +import com.hb0730.boot.admin.base.util.AesEncryptUtil; +import com.hb0730.boot.admin.modules.api.buiness.model.PictureEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户信息 + * + * @author hb0730 + * @date 2023/6/8 + */ +@Data +@EqualsAndHashCode +@ToString +public class ShopVO implements Serializable { + /** + * ID + */ + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; + /** + * 店铺名称 + */ + @Schema(description = "店铺名称") + private String name; + /** + * 店铺介绍(中文) + */ + @Schema(description = "店铺介绍(中文)") + private String introChi; + /** + * 店铺介绍(英文) + */ + @Schema(description = "店铺介绍(英文)") + private String introEng; + /** + * 店铺介绍(日文) + */ + @Schema(description = "店铺介绍(日文") + private String introJap; + /** + * 预约电话 + */ + @Schema(description = "预约电话") + private String phone; + /** + * 营业时间(开始时间) + */ + @Schema(description = "营业时间(开始时间)") + private String startTime; + /** + * 营业时间(结束时间) + */ + @Schema(description = "营业时间(结束时间)") + private String endTime; + + /** + * 标签图片url + */ + @Schema(description = "标签图片url") + private String tagUrl; + + /** + * logo url + */ + @Schema(description = "logo url") + private String logoUrl; + + /** + * 轮播图url + */ + @Schema(description = "轮播图url") + private String pictureUrl; + + /** + * 店铺楼层 + */ + @Schema(description = "店铺楼层") + private Integer floor; + + /** + * 是否启用,true:启用,false:禁用 + */ + @Schema(description = "是否启用,true:启用,false:禁用") + private Boolean isEnable; + + /** + * 名字url + */ + @Schema(description = "名字url") + private String namePicture; + + @Schema(description = "菜品url") + private String vagetableUrl; + + @Schema(description = "季节菜品url") + private String season; + + @Schema(description = "名字边上标题") + private String title; + + @Schema(description = "小时菜品") + private String hour; + + @Schema(description = "排序") + private Integer sort; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/OssService.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/OssService.java new file mode 100644 index 0000000..c6c8f05 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/OssService.java @@ -0,0 +1,12 @@ +package com.hb0730.boot.admin.modules.api.buiness.service; + + +import com.hb0730.boot.admin.base.R; +import org.springframework.web.multipart.MultipartFile; + +public interface OssService { + + R uploadFile(MultipartFile file); + + R deleteFile(String path); +} \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysBoxService.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysBoxService.java new file mode 100644 index 0000000..820c9bd --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysBoxService.java @@ -0,0 +1,23 @@ +package com.hb0730.boot.admin.modules.api.buiness.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.model.SysBox; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.BoxQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.query.ShopQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.BoxVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; + +import java.util.List; + +public interface SysBoxService extends IService { + BasePage queryPage(BoxQuery query); + + Rdetail(String id); + + R saveShop(BoxVO boxVO); + + R updateById(String id, BoxVO boxVO); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysCouponLogService.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysCouponLogService.java new file mode 100644 index 0000000..93d9e9e --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysCouponLogService.java @@ -0,0 +1,21 @@ +package com.hb0730.boot.admin.modules.api.buiness.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCoupon; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCouponLog; +import com.hb0730.boot.admin.modules.api.buiness.model.query.CouponQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponLogVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponVO; + +public interface SysCouponLogService extends IService { + + BasePage queryPage(CouponQuery query); + + R detail(String id); + + R saveShop(CouponLogVO couponlogVO); + + R updateById(String id, CouponLogVO couponVO); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysCouponService.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysCouponService.java new file mode 100644 index 0000000..6ad90d0 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysCouponService.java @@ -0,0 +1,29 @@ +package com.hb0730.boot.admin.modules.api.buiness.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.model.SysBox; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCoupon; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCouponLog; +import com.hb0730.boot.admin.modules.api.buiness.model.query.BoxQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.query.CouponQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.BoxVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.GetCouponLogVO; + +import java.util.List; + +public interface SysCouponService extends IService { + BasePage queryPage(CouponQuery query); + + Rdetail(String id); + + R saveShop(CouponVO couponVO); +// + R updateById(String id, CouponVO couponVO); + + R getCoupon(String id , String openId); + + R verification(String id, String checkCode); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysShopService.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysShopService.java new file mode 100644 index 0000000..5a73b5b --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/SysShopService.java @@ -0,0 +1,35 @@ +package com.hb0730.boot.admin.modules.api.buiness.service; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.service.IService; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.base.util.AesEncryptUtil; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.ShopQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.HourVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.SeasonVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUser; +import com.hb0730.boot.admin.modules.sys.system.model.vo.UserVO; + +import java.util.HashSet; +import java.util.List; + +public interface SysShopService extends IService { + BasePage queryPage(ShopQuery query); + + + R detail(String id); + + + R updateById(String id, ShopVO vo); + + R saveShop(ShopVO shopVO); + + List getSeason(); + + List getHour(); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/OssServiceImpl.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/OssServiceImpl.java new file mode 100644 index 0000000..e06ebd2 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/OssServiceImpl.java @@ -0,0 +1,59 @@ +package com.hb0730.boot.admin.modules.api.buiness.service.impl; + +import cn.hutool.core.date.DateTime; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.modules.api.buiness.service.OssService; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +@Service("ossService") +public class OssServiceImpl implements OssService { + + + + private static final String schema= "https://"; + private static final String endpoint= "oss-cn-shanghai.aliyuncs.com"; + private static final String accessKeyId= "LTAI5tMhBNyfJH7voue1VdD9"; + private static final String accessKeySecret= "tdlSGtauAy154Yx1qX5peuZgpQVzWh"; + private static final String bucketName= "huanqiuzhongxin";//huanqiuzhongxin + @Override + public R uploadFile(MultipartFile file) { + try { + //4、 创建OSSClient实例。 + OSS ossClient = new OSSClientBuilder().build(schema + endpoint, accessKeyId, accessKeySecret); + String fileName = file.getOriginalFilename();//获取上传文件的名称 + InputStream inputStream = file.getInputStream(); + // 通过ossClient上传文件: 参数1:桶名, 参数2:上传后的文件路径+文件名 ,参数3:要上传的文件流 + String objectName = new DateTime().toString("yyyy/MM/dd/") + + UUID.randomUUID().toString().replace("-", "").substring(0, 16) + + "_" + fileName;//使用UUID+源文件名称后缀拼接生成objectName + ossClient.putObject(bucketName, objectName, inputStream); + // 关闭OSSClient。 + ossClient.shutdown(); + + String path = schema + bucketName + "." + endpoint + "/" + objectName;//手动拼接上传成功的图片地址 + System.out.println("path ======================================" + path); + return R.OK(path); + + } catch (IOException e) { + throw new RuntimeException("图片上传失败"); + } + + } + + @Override + public R deleteFile(String path) { + String host = schema + bucketName + "." + endpoint +"/"; + String objectName = path.replace(host,""); + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); + ossClient.deleteObject(bucketName, objectName.trim()); + ossClient.shutdown(); + return R.OK("删除成功"); + } +} \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysBoxServiceImpl.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysBoxServiceImpl.java new file mode 100644 index 0000000..99b09cc --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysBoxServiceImpl.java @@ -0,0 +1,95 @@ +package com.hb0730.boot.admin.modules.api.buiness.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysBoxMapper; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysShopMapper; +import com.hb0730.boot.admin.modules.api.buiness.model.SysBox; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.BoxQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.query.ShopQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.BoxVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import com.hb0730.boot.admin.modules.api.buiness.service.SysBoxService; +import com.hb0730.boot.admin.modules.api.buiness.service.SysShopService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class SysBoxServiceImpl extends ServiceImpl implements SysBoxService { + + @Autowired + private SysShopMapper sysShopMapper; + @Override + public BasePage queryPage(BoxQuery query) { + + + Page page = new Page<>(); + if ( query.getSize() == 0 || query.getCurrent() == 0) { + + page = new Page<>(0, Integer.MAX_VALUE); + }else { + page = new Page<>(query.getCurrent(), query.getSize()); + } + List boxes = baseMapper.queryPage(page, query); + + List collect = boxes.stream().map(box -> { + BoxVO boxVO = new BoxVO(); + BeanUtils.copyProperties(box, boxVO); + return boxVO; + }).collect(Collectors.toList()); + + return new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), collect); + } + + @Override + public R detail(String id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysBox::getId, id); + SysBox box = this.baseMapper.selectOne(wrapper); + + BoxVO boxVO = new BoxVO(); + BeanUtil.copyProperties(box, boxVO); + return R.OK(boxVO); + } + + @Override + public R saveShop(BoxVO boxVO) { + SysBox box = new SysBox(); + + BeanUtils.copyProperties(boxVO,box); + box.setCreated(LocalDateTime.now()); + box.setCreatedBy(SecurityUtil.getCurrentUsername()); + box.setModified(LocalDateTime.now()); + box.setModifiedBy(SecurityUtil.getCurrentUsername()); + this.baseMapper.insert(box); + return R.OK(boxVO); + } + + @Override + public R updateById(String id, BoxVO boxVO) { + SysBox box = baseMapper.selectById(id); + if (null == box) { + return R.NG("包厢不存在"); + } + + BeanUtil.copyProperties(boxVO, box); + baseMapper.updateById(box); + return R.OK(boxVO); + } +} + diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysCouponLogServiceImpl.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysCouponLogServiceImpl.java new file mode 100644 index 0000000..9b14eab --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysCouponLogServiceImpl.java @@ -0,0 +1,104 @@ +package com.hb0730.boot.admin.modules.api.buiness.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysCouponLogMapper; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysCouponMapper; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCoupon; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCouponLog; +import com.hb0730.boot.admin.modules.api.buiness.model.query.CouponQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponLogVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponVO; +import com.hb0730.boot.admin.modules.api.buiness.service.SysCouponLogService; +import com.hb0730.boot.admin.modules.api.buiness.service.SysCouponService; +import com.hb0730.boot.admin.modules.sys.system.mapper.SysUserMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUser; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import lombok.Synchronized; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class SysCouponLogServiceImpl extends ServiceImpl implements SysCouponLogService { + + @Autowired + private SysCouponLogMapper sysCouponLogMapper; + + @Autowired + private SysUserMapper sysUserMapper; + @Override + public BasePage queryPage(CouponQuery query) { + Page page = new Page<>(); + if ( query.getSize() == 0 || query.getCurrent() == 0) { + + page = new Page<>(0, Integer.MAX_VALUE); + }else { + page = new Page<>(query.getCurrent(), query.getSize()); + } + List coupons = sysCouponLogMapper.queryPage(page, query); + + List collect = coupons.stream().map(coupon -> { + CouponLogVO couponLogVO = new CouponLogVO(); + BeanUtils.copyProperties(coupon, couponLogVO); + return couponLogVO; + }).collect(Collectors.toList()); + + return new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), collect); + } + + @Override + public R detail(String id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysCouponLog::getId, id); + SysCouponLog sysCouponLog = this.baseMapper.selectOne(wrapper); + + + + CouponLogVO couponVO = new CouponLogVO(); + BeanUtil.copyProperties(sysCouponLog, couponVO); + + + return R.OK(couponVO); + } + + + @Override + public R saveShop(CouponLogVO couponLogVO) { + SysCouponLog coupon = new SysCouponLog(); + + BeanUtils.copyProperties(couponLogVO,coupon); + coupon.setCreated(LocalDateTime.now()); + coupon.setCreatedBy(SecurityUtil.getCurrentUsername()); + coupon.setModified(LocalDateTime.now()); + coupon.setModifiedBy(SecurityUtil.getCurrentUsername()); + this.baseMapper.insert(coupon); + return R.OK(couponLogVO); + } +// +@Override + public R updateById(String id, CouponLogVO couponVO) { + + + SysCouponLog coupon = getById(id); + if (null == coupon) { + return R.NG("优惠券不存在"); + } + BeanUtil.copyProperties(couponVO, coupon); + baseMapper.updateById(coupon); + return R.OK(couponVO); +} + +} + diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysCouponServiceImpl.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysCouponServiceImpl.java new file mode 100644 index 0000000..f92d1ef --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysCouponServiceImpl.java @@ -0,0 +1,174 @@ +package com.hb0730.boot.admin.modules.api.buiness.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysBoxMapper; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysCouponLogMapper; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysCouponMapper; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysShopMapper; +import com.hb0730.boot.admin.modules.api.buiness.model.SysBox; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCoupon; +import com.hb0730.boot.admin.modules.api.buiness.model.SysCouponLog; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.BoxQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.query.CouponQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.BoxVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.CouponVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.GetCouponLogVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import com.hb0730.boot.admin.modules.api.buiness.service.SysBoxService; +import com.hb0730.boot.admin.modules.api.buiness.service.SysCouponLogService; +import com.hb0730.boot.admin.modules.api.buiness.service.SysCouponService; +import com.hb0730.boot.admin.modules.sys.system.mapper.SysUserMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUser; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.LocalDateTime; +import java.util.Formatter; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class SysCouponServiceImpl extends ServiceImpl implements SysCouponService { + + + @Autowired + private SysUserMapper sysUserMapper; + + @Autowired + private SysCouponLogMapper sysCouponLogMapper; + @Override + public BasePage queryPage(CouponQuery query) { + Page page = new Page<>(); + if ( query.getSize() == 0 || query.getCurrent() == 0) { + + page = new Page<>(0, Integer.MAX_VALUE); + }else { + page = new Page<>(query.getCurrent(), query.getSize()); + } + List coupons = baseMapper.queryPage(page, query); + + List collect = coupons.stream().map(coupon -> { + CouponVO couponVO = new CouponVO(); + BeanUtils.copyProperties(coupon, couponVO); + return couponVO; + }).collect(Collectors.toList()); + + return new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), collect); + } + + @Override + public R detail(String id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysCoupon::getId, id); + SysCoupon box = this.baseMapper.selectOne(wrapper); + + + + CouponVO couponVO = new CouponVO(); + BeanUtil.copyProperties(box, couponVO); + + + return R.OK(couponVO); + } + + @Override + public R saveShop(CouponVO couponVO) { + SysCoupon coupon = new SysCoupon(); + + BeanUtils.copyProperties(couponVO,coupon); + coupon.setCreated(LocalDateTime.now()); + coupon.setCreatedBy(SecurityUtil.getCurrentUsername()); + coupon.setModified(LocalDateTime.now()); + coupon.setModifiedBy(SecurityUtil.getCurrentUsername()); + this.baseMapper.insert(coupon); + return R.OK(couponVO); + } +// +@Override + public R updateById(String id, CouponVO couponVO) { + + + SysCoupon coupon = getById(id); + if (null == coupon) { + return R.NG("优惠券不存在"); + } + BeanUtil.copyProperties(couponVO, coupon); + baseMapper.updateById(coupon); + return R.OK(couponVO); +} + + @Override + public R getCoupon(String id,String openid) { + + LambdaQueryWrapper logs = new LambdaQueryWrapper<>(); + + SysCoupon coupon = this.baseMapper.selectById(id); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + SysUser user = sysUserMapper.selectOne(wrapper.eq(SysUser::getOpenId, openid)); + + + + long l = System.currentTimeMillis(); + String s = Long.toString(l, 36); + + SysCouponLog sysCouponLog = new SysCouponLog(); + + if(Objects.nonNull(user)){ + sysCouponLog.setUserId(user.getId()); + if (StringUtils.isNotEmpty(user.getUsername())) { + sysCouponLog.setUserName(user.getUsername()); + } + sysCouponLog.setOpenId(user.getOpenId()); + } + sysCouponLog.setCouponId(coupon.getId()); + sysCouponLog.setTitle(coupon.getTitle()); + sysCouponLog.setGiftName(coupon.getGiftName()); + + sysCouponLog.setCreated(LocalDateTime.now()); + sysCouponLog.setCheckCode(s); + sysCouponLogMapper.insert(sysCouponLog); + baseMapper.updateNums(id); + GetCouponLogVO getCouponLogVO = new GetCouponLogVO(); + BeanUtils.copyProperties(sysCouponLog,getCouponLogVO); + + return R.OK(getCouponLogVO); + } + + @Override + public R verification(String id, String checkCode) { + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysCouponLog::getCheckCode, checkCode); + wrapper.eq(SysCouponLog::getId, id); + SysCouponLog sysCouponLog = sysCouponLogMapper.selectOne(wrapper); + if(Objects.nonNull(sysCouponLog)){ + UpdateWrapper updateWrapper = new UpdateWrapper(); + updateWrapper.set("modified", LocalDateTime.now()); + updateWrapper.eq("id", id); + sysCouponLogMapper.update(sysCouponLog,updateWrapper); + return R.OK("验证通过!!!"); + }else { + return R.error(201,"验证失败!!!!"); + } + + } + +} + diff --git a/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysShopServiceImpl.java b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysShopServiceImpl.java new file mode 100644 index 0000000..29bab1f --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/api/buiness/service/impl/SysShopServiceImpl.java @@ -0,0 +1,111 @@ +package com.hb0730.boot.admin.modules.api.buiness.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.api.buiness.mapper.SysShopMapper; +import com.hb0730.boot.admin.modules.api.buiness.model.SysShop; +import com.hb0730.boot.admin.modules.api.buiness.model.query.ShopQuery; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.HourVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.SeasonVO; +import com.hb0730.boot.admin.modules.api.buiness.model.vo.ShopVO; +import com.hb0730.boot.admin.modules.api.buiness.service.SysShopService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class SysShopServiceImpl extends ServiceImpl implements SysShopService { + + @Autowired + private SysShopMapper sysShopMapper; + @Override + public BasePage queryPage(ShopQuery query) { + Page page = new Page<>(); + if ( query.getSize() == 0 || query.getCurrent() == 0) { + + page = new Page<>(0, Integer.MAX_VALUE); + }else { + page = new Page<>(query.getCurrent(), query.getSize()); + } + List shops = this.sysShopMapper.queryPage(page, query); + + List collect = shops.stream().map(shop -> { + + ShopVO shopVO = new ShopVO(); + BeanUtils.copyProperties(shop, shopVO); + return shopVO; + }).collect(Collectors.toList()); + + System.out.println(collect); + + return new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), collect); + } + + @Override + public R detail(String id) + { + SysShop shop = this.baseMapper.selectById(id); + ShopVO shopVO = new ShopVO(); + BeanUtil.copyProperties(shop, shopVO); + return R.OK(shopVO); + } + + @Override + public R updateById(String id, ShopVO vo) { + + + SysShop shop = getById(id); + if (null == shop) { + return R.NG("店铺不存在"); + } + BeanUtil.copyProperties(vo, shop); + baseMapper.updateById(shop); + return R.OK(vo); + } + + @Override + public R saveShop(ShopVO shopVO) { + + + SysShop sysShop = new SysShop(); + + BeanUtils.copyProperties(shopVO,sysShop); + sysShop.setCreated(LocalDateTime.now()); + sysShop.setCreatedBy(SecurityUtil.getCurrentUsername()); + sysShop.setModified(LocalDateTime.now()); + sysShop.setModifiedBy(SecurityUtil.getCurrentUsername()); + + +// sysShop.setPictureUrl(shopVO.getPictureUrl().toString()); + this.baseMapper.insert(sysShop); + return R.OK(shopVO); + } + + @Override + public List getSeason() { + List season = this.baseMapper.getSeason(); + + return season; + } + + @Override + public List getHour() { + List hour = this.baseMapper.getHour(); + return hour; + } + + +} + diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/AuthorizationController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/AuthorizationController.java new file mode 100644 index 0000000..8cbf2eb --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/AuthorizationController.java @@ -0,0 +1,98 @@ +package com.hb0730.boot.admin.modules.sys.auth.controller; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.crypto.SecureUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.base.util.JwtUtil; +import com.hb0730.boot.admin.base.util.RsaUtil; +import com.hb0730.boot.admin.modules.sys.auth.event.LogoutEvent; +import com.hb0730.boot.admin.modules.sys.auth.model.LoginRequest; +import com.hb0730.boot.admin.modules.sys.auth.model.LoginResponse; +import com.hb0730.boot.admin.security.config.LoginProperties; +import com.hb0730.boot.admin.security.model.UserInfo; +import com.hb0730.boot.admin.security.token.TokenProvider; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationContext; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 授权、根据token获取用户详细信息 + * + * @author hb0730 + * @date 2023/1/12 + */ +@RestController +@RequestMapping("/auth") +@Tag(name = "系统: 授权接口") +@RequiredArgsConstructor +public class AuthorizationController { + private final AuthenticationManager authenticationManager; + private final TokenProvider jwtTokenRedisCacheProvider; + private final LoginProperties loginProperties; + private final ApplicationContext applicationContext; + + @Operation(summary = "登录授权") + @PostMapping("/login") + public R login(HttpServletRequest request, @RequestBody @Valid LoginRequest login) throws Exception { + SecureUtil.disableBouncyCastle(); + String password = login.getPassword(); + // 解密 + + + password = RsaUtil.decryptByPrivateKey(login.getPassword(), loginProperties.getRsaPrivateKey()); + // + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(login.getUsername(), password); + Authentication authenticate = null; + try { + // 会调用UserDetailsService#loadUserByUsername(String username) + authenticate = authenticationManager.authenticate(authenticationToken); + } catch (AuthenticationException e) { + if (e instanceof UsernameNotFoundException) { + return R.NG("用户名不存在"); + } else { + return R.NG(e.getMessage()); + } + } + assert authenticate != null; + UserInfo userInfo = (UserInfo) authenticate.getPrincipal(); + String jwtToken = jwtTokenRedisCacheProvider.createToken(userInfo, request); + LoginResponse response = BeanUtil.toBean(userInfo, LoginResponse.class); + response.setToken(jwtToken); + return R.OK(response); + } + + @Operation(summary = "用户信息") + @GetMapping("/info") + public R getUserInfo() { + return null; + } + + @Operation(summary = "退出登录") + @PostMapping("/logout") + public R logout(HttpServletRequest request) { + String _jwtToken = JwtUtil.getTokenByRequest(request); + try { + // 如果超时,则获取失败 + UserInfo userInfo = SecurityUtil.getCurrentUser(); + applicationContext.publishEvent(new LogoutEvent(this, _jwtToken, userInfo.getUsername(), userInfo.getUserid())); + } catch (Exception ignored) { + + } + jwtTokenRedisCacheProvider.removeToken(_jwtToken); + return R.OK("成功"); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/WeChatJSSDKSignature.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/WeChatJSSDKSignature.java new file mode 100644 index 0000000..38a96a8 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/WeChatJSSDKSignature.java @@ -0,0 +1,73 @@ +package com.hb0730.boot.admin.modules.sys.auth.controller; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Formatter; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class WeChatJSSDKSignature { + public static void main(String[] args) { + // 替换成你的公众号AppID和AppSecret + String appId = "wxbad2e8a91c62a734"; + String appSecret = "e1b7fc425ca9cca05dd83609a6dc9c00"; + // 替换成当前页面的URL + String url = "CURRENT_PAGE_URL"; + + String nonceStr = createNonceStr(); + String timestamp = createTimestamp(); + String jsapiTicket = getJsApiTicket(appId, appSecret); + + String signature = generateSignature(jsapiTicket, nonceStr, timestamp, url); + + System.out.println("nonceStr: " + nonceStr); + System.out.println("timestamp: " + timestamp); + System.out.println("signature: " + signature); + } + + private static String createNonceStr() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + private static String createTimestamp() { + return Long.toString(System.currentTimeMillis() / 1000); + } + + private static String getJsApiTicket(String appId, String appSecret) { + // 调用微信API获取jsapi_ticket的逻辑,这里省略实现 + // 返回有效的jsapi_ticket + return "YOUR_JSAPI_TICKET"; + } + + private static String generateSignature(String jsapiTicket, String nonceStr, String timestamp, String url) { + Map paramMap = new HashMap<>(); + paramMap.put("noncestr", nonceStr); + paramMap.put("jsapi_ticket", jsapiTicket); + paramMap.put("timestamp", timestamp); + paramMap.put("url", url); + + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : paramMap.entrySet()) { + sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); + } + sb.deleteCharAt(sb.length() - 1); + + try { + MessageDigest crypt = MessageDigest.getInstance("SHA-1"); + crypt.reset(); + crypt.update(sb.toString().getBytes("UTF-8")); + byte[] digest = crypt.digest(); + Formatter formatter = new Formatter(); + for (byte b : digest) { + formatter.format("%02x", b); + } + String signature = formatter.toString(); + formatter.close(); + return signature; + } catch (NoSuchAlgorithmException | java.io.UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/WxLoginController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/WxLoginController.java new file mode 100644 index 0000000..77edbe3 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/controller/WxLoginController.java @@ -0,0 +1,197 @@ +package com.hb0730.boot.admin.modules.sys.auth.controller; + + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.mrzin.tool.http.HttpTool; +import cn.mrzin.tool.lang.StringUtils; +import cn.mrzin.wx.login.WxCommonUtil; +import cn.mrzin.wx.login.WxH5LoginUtil; +import cn.mrzin.wx.login.enums.AccessTokenGrantType; +import cn.mrzin.wx.login.model.WxSecretInfo; +import cn.mrzin.wx.login.response.AccessTokenInfo; +import cn.mrzin.wx.login.response.WxH5LoginResponse; +import cn.mrzin.wx.login.response.WxLoginResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.modules.sys.auth.model.*; +import com.hb0730.boot.admin.modules.sys.auth.model.dto.LoginDto; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUser; +import com.hb0730.boot.admin.modules.sys.system.service.SysUserService; +import com.hb0730.boot.admin.security.model.UserInfo; +import com.hb0730.boot.admin.security.token.TokenProvider; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +/** + * 授权、根据token获取用户详细信息 + * + * @author hb0730 + * @date 2023/1/12 + */ +@RestController +@RequestMapping("/wx") +@Tag(name = "系统: h5授权接口") +@RequiredArgsConstructor +public class WxLoginController { + + private static final RestTemplate REST_TEMPLATE = new RestTemplate(); + + + @Autowired + private SysUserService sysUserService; + /** + * AppID:wx292995002b9476f3 + * AppSecret:896202811f43b146123f8d3f9ad3c153 + */ + + + /** + * 微信小程序AppID + */ + private final static String AppID = "wxbad2e8a91c62a734"; + /** + * 微信小程序AppSecret + */ + private final static String AppSecret = "e1b7fc425ca9cca05dd83609a6dc9c00"; + + @Operation(summary = "微信登录") + @GetMapping("/wxlogin") + public R getWechatLoginInfo(@RequestParam String code) { + String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxbad2e8a91c62a734&secret=e1b7fc425ca9cca05dd83609a6dc9c00&code=" + code + "&grant_type=authorization_code"; + String H5 = HttpTool.get(url, String.class); + Gson gson = new Gson(); + H5LoginResponse h5LoginResponse = gson.fromJson(H5, H5LoginResponse.class); + System.out.println("h5LoginResponse = " + h5LoginResponse); + + + String useUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + h5LoginResponse.getAccessToken() + "&openid=" + h5LoginResponse.getOpenId() + "&lang=zh_CN"; + String user = HttpTool.get(useUrl, String.class); + System.out.println("user = " + user); + + UserResponse userResponse = gson.fromJson(user, UserResponse.class); + + String opeId = userResponse.getOpenId(); + + SysUser sysUser = sysUserService.getByOpenId(opeId); + if(sysUser == null){ + sysUser = new SysUser(); + sysUser.setUsername(userResponse.getNicName()); + sysUser.setOpenId(userResponse.getOpenId()); + sysUser.setUnionId(userResponse.getOpenId()); + sysUser.setPassword("123456"); + sysUserService.save(sysUser); + } + + JSH5LoginResponse jsh5LoginResponse = new JSH5LoginResponse(); + BeanUtils.copyProperties(h5LoginResponse, jsh5LoginResponse); + jsh5LoginResponse.setUser(user); + return R.OK(jsh5LoginResponse); + } + + @Operation(summary = "获取签名") + @GetMapping("/access") + public R access(String url){ + Gson gson = new Gson(); + Map map = new HashMap<>(); + map.put("appid","wxbad2e8a91c62a734"); + map.put("secret", "e1b7fc425ca9cca05dd83609a6dc9c00"); + map.put("grant_type","client_credential"); + String tokenUrl = "https://api.weixin.qq.com/cgi-bin/stable_token"; + String access = REST_TEMPLATE.postForObject(tokenUrl, map, String.class); +// String access = HttpTool.pos(tokenUrl, map, String.class); + System.out.println("access = " + access); + AccessTokenResponse accessTokenResponse = gson.fromJson(access, AccessTokenResponse.class); + + String jsUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessTokenResponse.getAccessToken()+"&type=jsapi"; + String js = HttpTool.get(jsUrl, String.class); + + JsResponse jsResponse = gson.fromJson(js, JsResponse.class); + System.out.println(js); + + + SignatureResponse signatureResponse = new SignatureResponse(); + + + // 替换成你的公众号AppID和AppSecret + String appId = "wxbad2e8a91c62a734"; + String appSecret = "e1b7fc425ca9cca05dd83609a6dc9c00"; + String nonceStr = createNonceStr(); + String timestamp = createTimestamp(); + String jsapiTicket = jsResponse.getTicket(); + + String signature = generateSignature(jsapiTicket, nonceStr, timestamp, url); + signatureResponse.setSignature(signature); + signatureResponse.setTimestamp(timestamp); + signatureResponse.setJsapiTicket(jsapiTicket); + signatureResponse.setNonceStr(nonceStr); + System.out.println("signature = " + signature); + System.out.println(url); + return R.OK(signatureResponse); + } + + + private static String createNonceStr() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + private static String createTimestamp() { + return Long.toString(System.currentTimeMillis() / 1000); + } + + private static String getJsApiTicket(String appId, String appSecret) { + // 调用微信API获取jsapi_ticket的逻辑,这里省略实现 + // 返回有效的jsapi_ticket + return "YOUR_JSAPI_TICKET"; + } + + private static String generateSignature(String jsapiTicket, String nonceStr, String timestamp, String url) { + + String sb = "jsapi_ticket=" + jsapiTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url; + + try { + MessageDigest crypt = MessageDigest.getInstance("SHA-1"); + crypt.reset(); + crypt.update(sb.toString().getBytes("UTF-8")); + byte[] digest = crypt.digest(); + Formatter formatter = new Formatter(); + for (byte b : digest) { + formatter.format("%02x", b); + } + String signature = formatter.toString(); + formatter.close(); + return signature; + } catch (NoSuchAlgorithmException | java.io.UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + + public static void main(String[] args) { + String json = "{\"openid\":\"o2r-U6sN-BMZEQlzEZIuVbRzeqPk\",\"nickname\":\"王文龙\",\"sex\":0,\"language\":\"\",\"city\":\"\",\"province\":\"\",\"country\":\"\",\"headimgurl\":\"https:\\/\\/thirdwx.qlogo.cn\\/mmopen\\/vi_32\\/PiajxSqBRaEJyptEMOSZmJ1480uG0gH5SpgxxXYtqIf6XKUn0fm9X6lxkT8aMRpX0sVBkTia5C9KtqsD70w8Q6VA\\/132\",\"privilege\":[]}"; + Gson gson = new Gson(); + UserResponse user = gson.fromJson(json, UserResponse.class); + + System.out.println(user.getNicName()); + System.out.println(user.getPrivilege()); + + } + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/event/LogoutEvent.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/event/LogoutEvent.java new file mode 100644 index 0000000..e52a9ec --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/event/LogoutEvent.java @@ -0,0 +1,43 @@ +package com.hb0730.boot.admin.modules.sys.auth.event; + +import org.springframework.context.ApplicationEvent; + +/** + * logout event + * + * @author hb0730 + * @date 2023/2/5 + */ +public class LogoutEvent extends ApplicationEvent { + /** + * 访问token + */ + private final String token; + /** + * 用户名 + */ + private final String username; + /** + * 用户ID + */ + private final String userid; + + public LogoutEvent(Object source, String token, String username, String userid) { + super(source); + this.token = token; + this.username = username; + this.userid = userid; + } + + public String getToken() { + return token; + } + + public String getUsername() { + return username; + } + + public String getUserid() { + return userid; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/event/LogoutListener.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/event/LogoutListener.java new file mode 100644 index 0000000..066591c --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/event/LogoutListener.java @@ -0,0 +1,32 @@ +package com.hb0730.boot.admin.modules.sys.auth.event; + +import com.hb0730.boot.admin.modules.sys.system.cache.RouteCache; +import com.hb0730.boot.admin.security.token.UserCacheProvider; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +/** + * 登出事件 + * + * @author hb0730 + * @date 2023/2/5 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class LogoutListener implements ApplicationListener { + private final UserCacheProvider userCacheProvider; + private final RouteCache routeCache; + + @Override + public void onApplicationEvent(LogoutEvent event) { + log.info("【用户注销事件】用户注销清理缓存信息>>>>>>>>>>>开始"); + String username = event.getUsername(); + userCacheProvider.clearUser(username); + log.info("【用户注销事件】成功清理缓存登录用户信息"); + routeCache.removeCache(event.getUserid()); + log.info("【用户注销事件】成功清理缓存用户路由信息"); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/AccessTokenResponse.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/AccessTokenResponse.java new file mode 100644 index 0000000..60fdf18 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/AccessTokenResponse.java @@ -0,0 +1,33 @@ +package com.hb0730.boot.admin.modules.sys.auth.model; + +import com.google.gson.annotations.SerializedName; + +public class AccessTokenResponse { + + @SerializedName("access_token") + private String accessToken; + + + @SerializedName("expires_in") + private Long expires_in; + + + public AccessTokenResponse() { + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public Long getExpires_in() { + return expires_in; + } + + public void setExpires_in(Long expires_in) { + this.expires_in = expires_in; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/H5LoginResponse.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/H5LoginResponse.java new file mode 100644 index 0000000..94e1988 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/H5LoginResponse.java @@ -0,0 +1,99 @@ +package com.hb0730.boot.admin.modules.sys.auth.model; + +import com.google.gson.annotations.SerializedName; + +public class H5LoginResponse { + + @SerializedName("access_token") + private String accessToken; + @SerializedName("refresh_token") + private String refreshToken; + @SerializedName("expiresIn") + private Long expires_in; + @SerializedName("unionid") + private String unionId; + @SerializedName("is_snapshotuser") + private Integer isSnapshotUser; + @SerializedName("openid") + private String openId; + @SerializedName("scope") + private String scope; + @SerializedName("errcode") + private Long errCode = 0L; + @SerializedName("errmsg") + private String errMsg; + public H5LoginResponse() { + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public Long getExpires_in() { + return expires_in; + } + + public void setExpires_in(Long expires_in) { + this.expires_in = expires_in; + } + + public String getUnionId() { + return unionId; + } + + public void setUnionId(String unionId) { + this.unionId = unionId; + } + + public Integer getIsSnapshotUser() { + return isSnapshotUser; + } + + public void setIsSnapshotUser(Integer isSnapshotUser) { + this.isSnapshotUser = isSnapshotUser; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public Long getErrCode() { + return errCode; + } + + public void setErrCode(Long errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/JSH5LoginResponse.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/JSH5LoginResponse.java new file mode 100644 index 0000000..8526e17 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/JSH5LoginResponse.java @@ -0,0 +1,121 @@ +package com.hb0730.boot.admin.modules.sys.auth.model; + +import com.google.gson.annotations.SerializedName; + +public class JSH5LoginResponse { + + @SerializedName("access_token") + private String accessToken; + @SerializedName("refresh_token") + private String refreshToken; + @SerializedName("expiresIn") + private Long expires_in; + @SerializedName("unionid") + private String unionId; + @SerializedName("is_snapshotuser") + private Integer isSnapshotUser; + @SerializedName("openid") + private String openId; + @SerializedName("scope") + private String scope; + @SerializedName("errcode") + private Long errCode = 0L; + @SerializedName("errmsg") + private String errMsg; + + @SerializedName("ticket") + private String ticket; + + private String user; + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getTicket() { + return ticket; + } + + public void setTicket(String ticket) { + this.ticket = ticket; + } + + public JSH5LoginResponse() { + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public Long getExpires_in() { + return expires_in; + } + + public void setExpires_in(Long expires_in) { + this.expires_in = expires_in; + } + + public String getUnionId() { + return unionId; + } + + public void setUnionId(String unionId) { + this.unionId = unionId; + } + + public Integer getIsSnapshotUser() { + return isSnapshotUser; + } + + public void setIsSnapshotUser(Integer isSnapshotUser) { + this.isSnapshotUser = isSnapshotUser; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public Long getErrCode() { + return errCode; + } + + public void setErrCode(Long errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/JsResponse.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/JsResponse.java new file mode 100644 index 0000000..4854955 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/JsResponse.java @@ -0,0 +1,49 @@ +package com.hb0730.boot.admin.modules.sys.auth.model; + +import com.google.gson.annotations.SerializedName; + +public class JsResponse { + + @SerializedName("ticket") + private String ticket; + + @SerializedName("expiresIn") + private Long expires_in; + + @SerializedName("errcode") + private Long errCode = 0L; + @SerializedName("errmsg") + private String errMsg; + + public String getTicket() { + return ticket; + } + + public void setTicket(String ticket) { + this.ticket = ticket; + } + + public Long getExpires_in() { + return expires_in; + } + + public void setExpires_in(Long expires_in) { + this.expires_in = expires_in; + } + + public Long getErrCode() { + return errCode; + } + + public void setErrCode(Long errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/LoginRequest.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/LoginRequest.java new file mode 100644 index 0000000..0d9e4be --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/LoginRequest.java @@ -0,0 +1,27 @@ +package com.hb0730.boot.admin.modules.sys.auth.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +/** + * login request body + * + * @author hb0730 + * @date 2023/1/30 + */ +@Data +@EqualsAndHashCode +@ToString +public class LoginRequest implements Serializable { + @Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "用户名为空") + private String username; + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "密码为空") + private String password; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/LoginResponse.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/LoginResponse.java new file mode 100644 index 0000000..9eaac4e --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/LoginResponse.java @@ -0,0 +1,27 @@ +package com.hb0730.boot.admin.modules.sys.auth.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.util.List; + +/** + * @author hb0730 + * @date 2023/2/5 + */ +@Data +@EqualsAndHashCode +@ToString +public class LoginResponse implements Serializable { + @Schema(description = "用户名") + private String username; + @Schema(description = "用户昵称") + private String nickname; + @Schema(description = "权限") + private List permissions; + @Schema(description = "访问token") + private String token; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/SignatureResponse.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/SignatureResponse.java new file mode 100644 index 0000000..525dea4 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/SignatureResponse.java @@ -0,0 +1,15 @@ +package com.hb0730.boot.admin.modules.sys.auth.model; + +import lombok.Data; + +@Data +public class SignatureResponse { + + private String signature; + + private String timestamp; + + private String nonceStr; + + private String jsapiTicket; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/UserResponse.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/UserResponse.java new file mode 100644 index 0000000..a6108e5 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/UserResponse.java @@ -0,0 +1,105 @@ +package com.hb0730.boot.admin.modules.sys.auth.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class UserResponse { + + @SerializedName("openid") + private String openId; + + + @SerializedName("unionid") + private String unionId; + @SerializedName("nickname") + private String nicName; + @SerializedName("sex") + private String sex; + @SerializedName("province") + private String province; + @SerializedName("city") + private String city; + @SerializedName("headimgurl") + private String headImgurl; + @SerializedName("privilege") + private List privilege; + @SerializedName("country") + private String country; + + public List getPrivilege() { + return privilege; + } + + public void setPrivilege(List privilege) { + this.privilege = privilege; + } + + public UserResponse() { + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getUnionId() { + return unionId; + } + + public void setUnionId(String unionId) { + this.unionId = unionId; + } + + public String getNicName() { + return nicName; + } + + public void setNicName(String nicName) { + this.nicName = nicName; + } + + public String getSex() { + return sex; + } + + public void setSex(String sex) { + this.sex = sex; + } + + public String getProvince() { + return province; + } + + public void setProvince(String province) { + this.province = province; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getHeadImgurl() { + return headImgurl; + } + + public void setHeadImgurl(String headImgurl) { + this.headImgurl = headImgurl; + } + + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/dto/LoginDto.java b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/dto/LoginDto.java new file mode 100644 index 0000000..ac180d1 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/auth/model/dto/LoginDto.java @@ -0,0 +1,14 @@ +package com.hb0730.boot.admin.modules.sys.auth.model.dto; + +import lombok.Data; + +@Data +public class LoginDto { + + private String code; + + /** + * 扩展字段 + */ + public Object extendParam; +} \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/controller/CacheController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/controller/CacheController.java new file mode 100644 index 0000000..19df5f3 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/controller/CacheController.java @@ -0,0 +1,92 @@ +package com.hb0730.boot.admin.modules.sys.monitor.controller; + +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.base.util.JsonUtil; +import com.hb0730.boot.admin.config.cache.BootAdminCache; +import com.hb0730.boot.admin.config.cache.DefaultKeyValue; +import com.hb0730.boot.admin.modules.sys.monitor.model.vo.CacheVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.List; + +/** + * 系统缓存 + * + * @author hb0730 + * @date 2023/6/14 + */ +@RestController +@RequestMapping("/monitor/cache") +@Tag(name = "系统:系统缓存", description = "业务缓存与系统缓存") +@RequiredArgsConstructor +public class CacheController { + private final BootAdminCache bootAdminCache; + + @GetMapping + @Operation(summary = "缓存列表") + @PreAuthorize("hasAuthority('cache:list')") + public R> queryList(HttpServletRequest request) { + List res = Arrays.stream(DefaultKeyValue.values()).map(e -> { + CacheVO cacheVo = new CacheVO(); + cacheVo.setPrefix(e.getPrefix()); + cacheVo.setName(e.getName()); + cacheVo.setDesc(e.getDesc()); + return cacheVo; + }).toList(); + return R.OK(res); + } + + @GetMapping("/query") + @Operation(summary = "查询缓存") + @PreAuthorize("hasAuthority('cache:query')") + public R query(HttpServletRequest request, CacheVO vo) { + // 完整缓存:KEY值 + String cacheKey = (vo.getPrefix() == null ? "" : vo.getPrefix() + ":") + vo.getKey(); + boolean exist = bootAdminCache.hasKey(cacheKey); + if (!exist) { + return R.NG(String.format("缓存KEY:[%s]不存在", cacheKey)); + } + // 缓存方式: 默认使用String方式 + String cacheType = StringUtils.isNotBlank(vo.getType()) ? vo.getType() : "String"; + switch (DefaultKeyValue.CacheType.valueOf(cacheType.toUpperCase())) { + case STRING, OBJECT -> + // <1> String 缓存 + vo.setValue(bootAdminCache.getStr(cacheKey).orElse("")); + case HASHMAP -> + // <3> Map 缓存 + bootAdminCache.hmget(cacheKey).ifPresent(e -> vo.setValue(JsonUtil.DEFAULT.toJson(e))); + case SET -> + // <4> Set 缓存 + bootAdminCache.sGet(cacheKey).ifPresent(e -> vo.setValue(JsonUtil.DEFAULT.toJson(e))); + case LIST -> + // <5> List 缓存 + bootAdminCache.lGet(cacheKey, 0, -1).ifPresent(e -> vo.setValue(JsonUtil.DEFAULT.toJson(e))); + default -> { + } + } + return R.OK(vo); + } + + @DeleteMapping("/remove") + @Operation(summary = "删除缓存") + @PreAuthorize("hasAuthority('cache:remove')") + public R remove(HttpServletRequest request, @RequestBody @Valid CacheVO vo) { + String cacheKey = (vo.getPrefix() == null ? "" : vo.getPrefix() + ":") + vo.getKey(); + if (bootAdminCache.hasKey(cacheKey)) { + bootAdminCache.del(cacheKey); + } + return R.OK(""); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/controller/QuartzJobController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/controller/QuartzJobController.java new file mode 100644 index 0000000..cf7e276 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/controller/QuartzJobController.java @@ -0,0 +1,180 @@ +package com.hb0730.boot.admin.modules.sys.monitor.controller; + +import cn.hutool.core.bean.BeanUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.monitor.model.vo.QuartzJobVO; +import com.hb0730.boot.admin.modules.sys.monitor.model.entity.QuartzJob; +import com.hb0730.boot.admin.modules.sys.monitor.model.query.QuartzJobQuery; +import com.hb0730.boot.admin.modules.sys.monitor.service.QuartzJobService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.quartz.CronExpression; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * Quartz定时任务Controller + * + * @author hb0730 + * @date 2023/6/12 + */ +@RestController +@RequestMapping("/monitor/quartz/job") +@Tag(name = "定时任务") +@RequiredArgsConstructor +@Slf4j +public class QuartzJobController { + private final QuartzJobService quartzJobService; + + /** + * 表达式是否正确 + * + * @param request . + * @param cron . + * @return . + */ + @GetMapping("/check/cron") + @Operation(summary = "表达式是否正确") + public R checkCron(HttpServletRequest request, String cron) { + boolean success = CronExpression.isValidExpression(cron); + return success ? R.OK() : R.NG(200,"表达式错误"); + } + + @GetMapping("/query/page") + @Operation(summary = "分页查询") + @PreAuthorize("hasAuthority('sys:quartz:job:query')") + public R> queryPage(HttpServletRequest request, @ParameterObject QuartzJobQuery query) { + return R.OK(quartzJobService.queryPage(query)); + } + + @GetMapping("/query/list") + @Operation(summary = "列表查询") + public R> queryList(HttpServletRequest request, @ParameterObject QuartzJobQuery query) { + return R.OK(quartzJobService.queryList(query)); + } + + @PostMapping("/save") + @Operation(summary = "保存") + @PreAuthorize("hasAuthority('sys:quartz:job:save')") + public R save(HttpServletRequest request, @RequestBody QuartzJobVO vo) { + String cronExpression = vo.getCronExpression(); + boolean success = CronExpression.isValidExpression(cronExpression); + if (!success) { + return R.NG("表达式错误"); + } + String username = SecurityUtil.getCurrentUsername(); + QuartzJob quartzJob = BeanUtil.toBean(vo, QuartzJob.class); + quartzJob.setCreated(LocalDateTime.now()); + quartzJob.setCreatedBy(username); + quartzJobService.saveAndScheduleJob(quartzJob); + vo = BeanUtil.toBean(quartzJob, QuartzJobVO.class); + return R.OK(vo); + } + + @PutMapping("/update/{id}") + @Operation(summary = "更新") + @PreAuthorize("hasAuthority('sys:quartz:job:update')") + public R updateById(HttpServletRequest request, @PathVariable String id, @RequestBody QuartzJobVO vo) { + try { + QuartzJob job = quartzJobService.getById(id); + if (null == job) { + return R.NG("任务不存在"); + } + String cronExpression = vo.getCronExpression(); + boolean success = CronExpression.isValidExpression(cronExpression); + if (!success) { + return R.NG("表达式错误"); + } + String username = SecurityUtil.getCurrentUsername(); + QuartzJob quartzJob = BeanUtil.toBean(vo, QuartzJob.class); + quartzJob.setModified(LocalDateTime.now()); + quartzJob.setModifiedBy(username); + quartzJobService.editAndScheduleJob(quartzJob); + vo = BeanUtil.toBean(quartzJob, QuartzJobVO.class); + return R.OK(vo); + } catch (Exception e) { + log.warn("更新定时任务失败", e); + return R.NG("更新定时任务失败"); + } + } + + @PutMapping("/pause/{id}") + @PreAuthorize("hasAuthority('sys:quartz:job:pause')") + @Operation(summary = "暂停") + public R pause(HttpServletRequest request, @PathVariable String id) { + QuartzJob quartzJob = quartzJobService.getById(id); + if (null == quartzJob) { + return R.NG("任务不存在"); + } + try { + quartzJobService.pauseJob(quartzJob); + return R.OK(); + } catch (Exception e) { + log.warn("暂停定时任务失败", e); + return R.NG("暂停定时任务失败"); + } + } + + @PutMapping("/resume/{id}") + @PreAuthorize("hasAuthority('sys:quartz:job:resume')") + @Operation(summary = "恢复") + public R resume(HttpServletRequest request, @PathVariable String id) { + QuartzJob quartzJob = quartzJobService.getById(id); + if (null == quartzJob) { + return R.NG("任务不存在"); + } + try { + quartzJobService.resumeJob(quartzJob); + return R.OK(); + } catch (Exception e) { + log.warn("恢复定时任务失败", e); + return R.NG("恢复定时任务失败"); + } + } + + @PutMapping("/execute/{id}") + @PreAuthorize("hasAuthority('sys:quartz:job:execute')") + @Operation(summary = "执行") + public R execute(HttpServletRequest request, @PathVariable String id) { + QuartzJob quartzJob = quartzJobService.getById(id); + if (null == quartzJob) { + return R.NG("任务不存在"); + } + try { + quartzJobService.executeJob(quartzJob); + return R.OK(); + } catch (Exception e) { + log.warn("执行定时任务失败", e); + return R.NG("执行定时任务失败"); + } + } + + @DeleteMapping("/delete") + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('sys:quartz:job:delete')") + public R delete(HttpServletRequest request, @RequestParam String id) { + QuartzJob quartzJob = quartzJobService.getById(id); + if (null == quartzJob) { + return R.NG("任务不存在"); + } + quartzJobService.deleteAndStopJob(quartzJob); + return R.OK(); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/mapper/QuartzJobMapper.java b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/mapper/QuartzJobMapper.java new file mode 100644 index 0000000..9c2bc54 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/mapper/QuartzJobMapper.java @@ -0,0 +1,38 @@ +package com.hb0730.boot.admin.modules.sys.monitor.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.modules.sys.monitor.model.entity.QuartzJob; +import com.hb0730.boot.admin.modules.sys.monitor.model.vo.QuartzJobVO; +import com.hb0730.boot.admin.modules.sys.monitor.model.query.QuartzJobQuery; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 定时任务在线管理 MAPPER + * + * @author hb0730 + * @date 2023/6/12 + */ +public interface QuartzJobMapper extends BaseMapper { + + /** + * 根据任务实现类全名取得匹配的任务 + * + * @param jobClassName 任务实现类全名 + * @return 匹配的任务 + */ + @Select("select * from sys_quartz_job where job_class_name = #{jobClassName}") + List findByJobClassName(@Param("jobClassName") String jobClassName); + + /** + * 分页查询 + * + * @param page . + * @param query . + * @return . + */ + List queryPage(Page page, @Param("query") QuartzJobQuery query); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/mapper/xml/QuratzJobMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/mapper/xml/QuratzJobMapper.xml new file mode 100644 index 0000000..9c8b981 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/mapper/xml/QuratzJobMapper.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/entity/QuartzJob.java b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/entity/QuartzJob.java new file mode 100644 index 0000000..747a111 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/entity/QuartzJob.java @@ -0,0 +1,41 @@ +package com.hb0730.boot.admin.modules.sys.monitor.model.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 定时任务在线管理表 + * + * @author hb0730 + * @date 2023/6/12 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName("sys_quartz_job") +public class QuartzJob extends BaseEntity { + /** + * 任务类名 + */ + private java.lang.String jobClassName; + /** + * 参数 + */ + private java.lang.String parameter; + /** + * cron表达式 + */ + private java.lang.String cronExpression; + + /** + * 状态 1正常 0停止 + */ + private java.lang.Integer status; + /** + * 描述 + */ + private java.lang.String description; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/query/QuartzJobQuery.java b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/query/QuartzJobQuery.java new file mode 100644 index 0000000..b003548 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/query/QuartzJobQuery.java @@ -0,0 +1,23 @@ +package com.hb0730.boot.admin.modules.sys.monitor.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 定时任务在线管理查询条件 + * + * @author hb0730 + * @date 2023/6/13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class QuartzJobQuery extends BasePageQuery { + @Schema(description = "任务类名") + private String jobClassName; + @Schema(description = "任务状态") + private Integer status; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/vo/CacheVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/vo/CacheVO.java new file mode 100644 index 0000000..ba37a77 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/vo/CacheVO.java @@ -0,0 +1,57 @@ +package com.hb0730.boot.admin.modules.sys.monitor.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +/** + * 系统缓存 + * + * @author hb0730 + * @date 2023/6/14 + */ +@Data +@EqualsAndHashCode +@ToString +public class CacheVO implements Serializable { + /** + * 缓存分类:前缀 + */ + @Schema(description = "缓存分类:前缀") + private String prefix; + + /** + * 配置KEY + */ + @Schema(description = "配置KEY") + @NotNull(message = "配置KEY不能为空") + private String key; + + /** + * 缓存实体JSON字符串 + */ + @Schema(description = "缓存实体JSON字符串") + private String value; + + /** + * 缓存名称 + */ + @Schema(description = "缓存名称") + private String name; + + /** + * 缓存描述 + */ + @Schema(description = "缓存描述") + private String desc; + + /** + * 缓存方式 + */ + @Schema(description = "缓存方式") + private String type; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/vo/QuartzJobVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/vo/QuartzJobVO.java new file mode 100644 index 0000000..9d167c6 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/model/vo/QuartzJobVO.java @@ -0,0 +1,75 @@ +package com.hb0730.boot.admin.modules.sys.monitor.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.time.LocalDateTime; + +/** + * 定时任务在线管理 + * + * @author hb0730 + * @date 2023/6/13 + */ +@Data +@EqualsAndHashCode +@ToString +public class QuartzJobVO implements java.io.Serializable { + @Schema(description = "主键") + private String id; + + /** + * 任务类名 + */ + @Schema(description = "任务类名") + @NotBlank(message = "任务类名不能为空") + private java.lang.String jobClassName; + /** + * 参数 + */ + @Schema(description = "参数") + private java.lang.String parameter; + /** + * cron表达式 + */ + @Schema(description = "cron表达式") + @NotBlank(message = "cron表达式不能为空") + private java.lang.String cronExpression; + + /** + * 状态 1正常 0停止 + */ + @Schema(description = "状态 1正常 0停止") + private java.lang.Integer status; + /** + * 描述 + */ + @Schema(description = "描述") + private java.lang.String description; + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/service/QuartzJobService.java b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/service/QuartzJobService.java new file mode 100644 index 0000000..6e55d3d --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/monitor/service/QuartzJobService.java @@ -0,0 +1,267 @@ +package com.hb0730.boot.admin.modules.sys.monitor.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.base.exception.BootAdminException; +import com.hb0730.boot.admin.core.service.BaseServiceImpl; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.data.enums.EnabledEnums; +import com.hb0730.boot.admin.modules.sys.monitor.model.entity.QuartzJob; +import com.hb0730.boot.admin.modules.sys.monitor.model.vo.QuartzJobVO; +import com.hb0730.boot.admin.modules.sys.monitor.mapper.QuartzJobMapper; +import com.hb0730.boot.admin.modules.sys.monitor.model.query.QuartzJobQuery; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.quartz.CronScheduleBuilder; +import org.quartz.CronTrigger; +import org.quartz.Job; +import org.quartz.JobBuilder; +import org.quartz.JobDetail; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.Trigger; +import org.quartz.TriggerBuilder; +import org.quartz.TriggerKey; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author hb0730 + * @date 2023/6/12 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class QuartzJobService extends BaseServiceImpl { + private final Scheduler scheduler; + + /** + * 列表查询 + * + * @param query . + * @return . + */ + public BasePage queryPage(QuartzJobQuery query) { + Page page = new Page<>(query.getCurrent(), query.getSize()); + List list = this.baseMapper.queryPage(page, query); + return new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), list); + } + + /** + * 列表查询 + * + * @param query . + * @return . + */ + public List queryList(QuartzJobQuery query) { + return this.baseMapper.queryPage(null, query); + } + + /** + * 根据任务实现类全名取得匹配的任务 + * + * @param jobClassName 任务实现类全名 + * @return 匹配的任务 + */ + public List findByJobClassName(String jobClassName) { + return this.baseMapper.findByJobClassName(jobClassName); + } + + /** + * 保存&启动定时任务 + * + * @param job 任务 + * @return 处理结果 + */ + public boolean saveAndScheduleJob(QuartzJob job) { + if (EnabledEnums.enabled.getValue().equals(job.getStatus())) { + // 定时器添加 + this.schedulerAdd( + job.getJobClassName().trim(), + job.getCronExpression().trim(), + job.getParameter()); + } + return this.save(job); + } + + /** + * 编辑&启停定时任务 + * + * @param job 任务 + * @return 处理结果 + * @throws SchedulerException . + */ + public boolean editAndScheduleJob(QuartzJob job) throws SchedulerException { + if (EnabledEnums.enabled.getValue().equals(job.getStatus())) { + schedulerDelete(job.getJobClassName().trim()); + + schedulerAdd( + job.getJobClassName().trim(), + job.getCronExpression().trim(), + job.getParameter()); + } else { + scheduler.pauseJob(JobKey.jobKey(job.getJobClassName().trim())); + } + + return this.updateById(job); + } + + /** + * 删除&停止删除定时任务 + * + * @param job 任务 + * @return 处理结果 + */ + public boolean deleteAndStopJob(QuartzJob job) { + schedulerDelete(job.getJobClassName().trim()); + + return this.removeById(job.getId()); + } + + /** + * 暂停定时任务 + * + * @param job 任务 + * @return 处理结果 + */ + public boolean pauseJob(QuartzJob job) throws SchedulerException { + scheduler.pauseJob(JobKey.jobKey(job.getJobClassName().trim())); + + job.setStatus(EnabledEnums.un_enabled.getValue()); + return this.updateById(job); + } + + /** + * 恢复定时任务 + * + * @param job 任务 + * @return 处理结果 + */ + public boolean resumeJob(QuartzJob job) { + schedulerDelete(job.getJobClassName().trim()); + + schedulerAdd( + job.getJobClassName().trim(), + job.getCronExpression().trim(), + job.getParameter()); + + job.setStatus(EnabledEnums.enabled.getValue()); + return this.updateById(job); + } + + /** + * 立即执行定时任务 + * + * @param job 任务 + */ + public void executeJob(QuartzJob job) { + + schedulerDelete(job.getJobClassName().trim()); + + //没有cronExpression表达式,只执行一次 + schedulerAdd( + job.getJobClassName().trim(), + job.getParameter()); + } + + /** + * 删除定时任务 + * + * @param jobClassName 任务实现类全名 + */ + private void schedulerDelete(String jobClassName) { + try { + scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName)); + scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName)); + scheduler.deleteJob(JobKey.jobKey(jobClassName)); + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new BootAdminException("删除定时任务失败"); + } + } + + /** + * 添加定时任务 + * + * @param jobClassName 任务实现类全名 + * @param cronExpression cron表达式 + * @param parameter 任务参数 + */ + private void schedulerAdd(String jobClassName, String cronExpression, String parameter) { + try { + // 启动调度器 + scheduler.start(); + + // 构建job信息 + JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()) + .withIdentity(jobClassName) + .usingJobData("parameter", parameter) + .build(); + + // 表达式调度构建器(即任务执行的时间) + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression); + + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger() + .withIdentity(jobClassName) + .withSchedule(scheduleBuilder) + .build(); + + scheduler.scheduleJob(jobDetail, trigger); + } catch (SchedulerException e) { + throw new BootAdminException("创建定时任务失败", e); + } catch (RuntimeException e) { + throw new BootAdminException(e.getMessage(), e); + } catch (Exception e) { + throw new BootAdminException("后台找不到该类名:" + jobClassName, e); + } + } + + /** + * 添加定时任务,不带cron表达式,执行一次 + * + * @param jobClassName 任务实现类全名 + * @param parameter 任务参数 + */ + private void schedulerAdd(String jobClassName, String parameter) { + try { + // 启动调度器 + scheduler.start(); + + // 构建job信息 + JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()) + .withIdentity(jobClassName) + .usingJobData("parameter", parameter) + .build(); + + // 没有cronExpression表达式构建一个新的trigger + Trigger trigger = TriggerBuilder.newTrigger() + .withIdentity(jobClassName) + .build(); + + scheduler.scheduleJob(jobDetail, trigger); + + } catch (SchedulerException e) { + throw new BootAdminException("创建定时任务失败", e); + } catch (RuntimeException e) { + throw new BootAdminException(e.getMessage(), e); + } catch (Exception e) { + throw new BootAdminException("后台找不到该类名:" + jobClassName, e); + } + } + + /** + * 实例化指定任务实现类 + * + * @param jobClassName 任务实现类全名 + * @return 任务实现类实例 + * @throws Exception . + */ + @SuppressWarnings("unchecked") + private static Job getClass(String jobClassName) throws Exception { + Class clazz = (Class) Class.forName(jobClassName); + return clazz.getConstructor().newInstance(); + } + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/cache/ConfigCache.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/cache/ConfigCache.java new file mode 100644 index 0000000..ec2e42e --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/cache/ConfigCache.java @@ -0,0 +1,53 @@ +package com.hb0730.boot.admin.modules.sys.system.cache; + +import com.hb0730.boot.admin.config.cache.BootAdminCache; +import com.hb0730.boot.admin.config.cache.CacheUtil; +import com.hb0730.boot.admin.config.cache.DefaultKeyValue; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysConfig; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +/** + * @author hb0730 + * @date 2023/6/12 + */ +@Component +@RequiredArgsConstructor +public class ConfigCache implements CacheUtil { + private final BootAdminCache cache; + + /** + * 设置缓存 + * + * @param config . + * @return . + */ + public boolean putCache(SysConfig config) { + String key = getCacheKey(DefaultKeyValue.SYS_CONFIG, config.getCode()); + return cache.set(key, config.getValue()); + } + + /** + * 移除缓存 + * + * @param code . + * @return . + */ + public boolean delCache(String code) { + String key = getCacheKey(DefaultKeyValue.SYS_CONFIG, code); + return cache.del(key); + } + + /** + * 获取缓存 + * + * @param code . + * @return . + */ + public Optional getCache(String code) { + String key = getCacheKey(DefaultKeyValue.SYS_CONFIG, code); + return cache.getStr(key); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/cache/RouteCache.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/cache/RouteCache.java new file mode 100644 index 0000000..b1650db --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/cache/RouteCache.java @@ -0,0 +1,89 @@ +package com.hb0730.boot.admin.modules.sys.system.cache; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.hb0730.boot.admin.base.util.JsonUtil; +import com.hb0730.boot.admin.config.cache.BootAdminCache; +import com.hb0730.boot.admin.config.cache.CacheUtil; +import com.hb0730.boot.admin.config.cache.KeyValue; +import com.hb0730.boot.admin.modules.sys.system.model.vo.VueMenuRouteVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +/** + * 缓存当前用户路由信息 + * + * @author hb0730 + * @date 2023/2/6 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class RouteCache implements CacheUtil { + private final BootAdminCache cache; + + /** + * 缓存用户路由 + * + * @param userid 用户路由 + * @param routes 路由 + */ + public void putCache(String userid, List routes) { + log.info("【用户路由】缓存用户: {} 路由信息, 缓存时间: 2小时", userid); + String cacheKey = getCacheKey(RouteCacheKey.default_key, userid); + String json = JsonUtil.DEFAULT.toJson(routes); + cache.set(cacheKey, json, 60 * 60 * 2); + } + + /** + * 获取用户路由 + * + * @param userid 用户ID + * @return 用户路由 + */ + public Optional> getCache(String userid) { + log.info("【用户路由】获取用户: {} 缓存的路由信息", userid); + String cacheKey = getCacheKey(RouteCacheKey.default_key, userid); + Optional jsonOptional = cache.getStr(cacheKey); + return jsonOptional.flatMap(e -> + Optional.ofNullable(JsonUtil.DEFAULT.fromJson(e, new TypeReference>() { + })) + ); + } + + /** + * 清理用户路由 + * + * @param userid . + */ + public void removeCache(String userid) { + log.info("【用户路由】清理用户: {} 缓存的路由信息", userid); + String cacheKey = getCacheKey(RouteCacheKey.default_key, userid); + cache.del(cacheKey); + } + + + public enum RouteCacheKey implements KeyValue { + default_key("route", "当前用户路由"); + private final String prefix; + private final String desc; + + RouteCacheKey(String prefix, String desc) { + this.prefix = prefix; + this.desc = desc; + } + + @Override + public String getPrefix() { + return this.prefix; + } + + @Override + public String getDesc() { + return this.desc; + } + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysCacheController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysCacheController.java new file mode 100644 index 0000000..4b037a0 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysCacheController.java @@ -0,0 +1,11 @@ +package com.hb0730.boot.admin.modules.sys.system.controller; + +/** + * 系统缓存管理 + * + * @author hb0730 + * @date 2023/6/6 + * @see com.hb0730.boot.admin.config.cache.DefaultKeyValue + */ +public class SysCacheController { +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysConfigController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysConfigController.java new file mode 100644 index 0000000..8fd63c2 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysConfigController.java @@ -0,0 +1,101 @@ +package com.hb0730.boot.admin.modules.sys.system.controller; + +import cn.hutool.core.bean.BeanUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysConfig; +import com.hb0730.boot.admin.modules.sys.system.model.query.ConfigQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.ConfigVO; +import com.hb0730.boot.admin.modules.sys.system.service.SysConfigService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 系统配置 + * + * @author hb0730 + * @date 2023/6/12 + */ +@RestController +@RequestMapping("/sys/config") +@Tag(name = "系统:系统配置") +@RequiredArgsConstructor +@Validated +public class SysConfigController { + private final SysConfigService configService; + + @GetMapping("/query/page") + @PreAuthorize("hasAuthority('sys:config:query')") + @Operation(summary = "分页查询") + public R> queryPage(HttpServletRequest request, @ParameterObject ConfigQuery query) { + return configService.queryPage(query); + } + + @GetMapping("/query/list") + @Operation(summary = "列表查询") + public R> queryList(HttpServletRequest request, @ParameterObject ConfigQuery query) { + return configService.queryList(query); + } + + @PostMapping("/save") + @Operation(summary = "保存") + @PreAuthorize("hasAuthority('sys:config:save')") + public R save(HttpServletRequest request, @RequestBody ConfigVO vo) { + String username = SecurityUtil.getCurrentUsername(); + SysConfig config = BeanUtil.toBean(vo, SysConfig.class); + config.setCreated(LocalDateTime.now()); + config.setCreatedBy(username); + configService.save(config); + ConfigVO bean = BeanUtil.toBean(config, ConfigVO.class); + return R.OK(bean); + } + + @PutMapping("/update/{id}") + @Operation(summary = "修改") + @PreAuthorize("hasAuthority('sys:config:update')") + public R updateById(HttpServletRequest request, @PathVariable String id, @RequestBody ConfigVO vo) { + String username = SecurityUtil.getCurrentUsername(); + SysConfig config = configService.getById(id); + if (null == config) { + return R.NG("数据不存在"); + } + BeanUtil.copyProperties(vo, config); + config.setModified(LocalDateTime.now()); + config.setModifiedBy(username); + configService.updateById(config); + ConfigVO bean = BeanUtil.toBean(config, ConfigVO.class); + return R.OK(bean); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('sys:config:del')") + public R delBatch(HttpServletRequest request, @RequestBody List ids) { + configService.removeByIds(ids); + return R.OK(); + } + + @PutMapping("/refresh/{id}") + @Operation(summary = "刷新缓存") + @PreAuthorize("hasAuthority('sys:config:refresh')") + public R refreshCache(HttpServletRequest request, @PathVariable String id) { + return configService.refreshCache(id); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysEnumsController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysEnumsController.java new file mode 100644 index 0000000..1153509 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysEnumsController.java @@ -0,0 +1,71 @@ +package com.hb0730.boot.admin.modules.sys.system.controller; + +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.enums.ConfigTypeEnums; +import com.hb0730.boot.admin.data.enums.EnabledEnums; +import com.hb0730.boot.admin.data.enums.GenderEnums; +import com.hb0730.boot.admin.modules.sys.system.vo.SelectOptionVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author hb0730 + * @date 2023/1/11 + */ +@RestController +@RequestMapping("/sys/enums") +@RequiredArgsConstructor +@Tag(name = "系统:常量") +public class SysEnumsController { + + + /** + * 状态 options + * + * @return . + */ + @GetMapping("/enabled") + @Operation(summary = "状态列表") + public R> enabledOptions() { + List res = Stream.of(EnabledEnums.values()) + .map(v -> SelectOptionVO.builder().value(v.getValue() + "").name(v.getName()).build()) + .collect(Collectors.toList()); + return R.OK(res); + } + + /** + * 性别 + * + * @return . + */ + @GetMapping("/gender") + @Operation(summary = "性别") + public R> genderOptions() { + List res = Stream.of(GenderEnums.values()) + .map(v -> SelectOptionVO.builder().name(v.getName()).value(v.getValue() + "").build()) + .collect(Collectors.toList()); + return R.OK(res); + } + + /** + * 配置类型 + * + * @return . + */ + @Operation(summary = "配置类型") + @GetMapping("/config_type") + public R> configTypeOptions() { + List res = Stream.of(ConfigTypeEnums.values()) + .map(v -> SelectOptionVO.builder().name(v.getName()).value(v.getValue() + "").build()) + .collect(Collectors.toList()); + return R.OK(res); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysOrgController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysOrgController.java new file mode 100644 index 0000000..0d7bbd0 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysOrgController.java @@ -0,0 +1,97 @@ +package com.hb0730.boot.admin.modules.sys.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.system.model.query.OrganizationQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.OrganizationTree; +import com.hb0730.boot.admin.modules.sys.system.model.vo.OrganizationVO; +import com.hb0730.boot.admin.modules.sys.system.service.SysOrgService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 机构Controller + * + * @author hb0730 + * @date 2023/6/3 + */ +@RestController +@RequestMapping("/sys/org") +@Tag(name = "系统:机构") +@RequiredArgsConstructor +public class SysOrgController { + private final SysOrgService sysOrgService; + + @GetMapping("/query/page") + @Operation(summary = "分页查询") + @PreAuthorize("hasAuthority('org:query')") + public R> getListPage(HttpServletRequest request,@ParameterObject OrganizationQuery query) { + BasePage page = sysOrgService.queryPage(query); + return R.OK(page); + } + + @GetMapping("/query/tree") + @Operation(summary = "树形结构") + @PreAuthorize("hasAuthority('org:query:tree')") + public R> getTree(HttpServletRequest request,@ParameterObject OrganizationQuery query) { + List res = sysOrgService.queryTree(query); + return R.OK(res); + } + + @GetMapping("/query/list") + @Operation(summary = "列表") + public R> getList(HttpServletRequest request,@ParameterObject OrganizationQuery query) { + List res = sysOrgService.queryList(query); + return R.OK(res); + } + + @PostMapping("/save") + @Operation(summary = "保存机构") + @PreAuthorize("hasAuthority('org:save')") + public R save(HttpServletRequest request, @RequestBody OrganizationVO vo) { + String parentId = vo.getParentId(); + if (StrUtil.isBlank(parentId)) { + return R.NG("不允许添加根节点"); + } + vo.setCreatedBy(SecurityUtil.getCurrentUsername()); + vo.setCreated(LocalDateTime.now()); + vo.setIsSystem(0); + return sysOrgService.save(vo); + } + + @PutMapping("/update/{id}") + @Operation(summary = "更新机构") + @PreAuthorize("hasAuthority('org:update')") + public R update(HttpServletRequest request, @PathVariable("id") String id, + @RequestBody OrganizationVO vo) { + vo.setModifiedBy(SecurityUtil.getCurrentUsername()); + vo.setModified(LocalDateTime.now()); + return sysOrgService.updateById(id, vo); + } + + @DeleteMapping("/del") + @Operation(summary = "删除机构") + @PreAuthorize("hasAuthority('org:del')") + public R del(HttpServletRequest request, @RequestBody List ids) { + return sysOrgService.batchDel(ids); + } + + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysPermissionController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysPermissionController.java new file mode 100644 index 0000000..b5328b9 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysPermissionController.java @@ -0,0 +1,193 @@ +package com.hb0730.boot.admin.modules.sys.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.enums.MenuTypeEnums; +import com.hb0730.boot.admin.data.enums.ValueEnum; +import com.hb0730.boot.admin.modules.sys.system.cache.RouteCache; +import com.hb0730.boot.admin.modules.sys.system.model.dto.PermissionTree; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysPermission; +import com.hb0730.boot.admin.modules.sys.system.model.query.PermissionTreeQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.PermissionVO; +import com.hb0730.boot.admin.modules.sys.system.model.vo.VueMenuRouteVO; +import com.hb0730.boot.admin.modules.sys.system.service.SysPermissionService; +import com.hb0730.boot.admin.security.model.UserInfo; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * @author hb0730 + * @date 2023/2/6 + */ + +@RestController +@RequestMapping("/sys/permission") +@Tag(name = "系统:菜单与权限") +@RequiredArgsConstructor +public class SysPermissionController { + private final SysPermissionService sysPermissionService; + private final RouteCache routeCache; + + /** + * 获取当前用户路由 + * + * @param request . + * @return . + */ + @GetMapping("/routes") + @Operation(summary = "获取当前用户路由") + public R> getCurrentRoute(HttpServletRequest request) { + UserInfo user = SecurityUtil.getCurrentUser(); + Optional> routeCacheOptional = routeCache.getCache(user.getUserid()); + if (routeCacheOptional.isPresent()) { + return R.OK(routeCacheOptional.get()); + } + List menuRoute = null; + if (user.isManger()) { + Set permissionIds = sysPermissionService.allPermissionIds(); + menuRoute = sysPermissionService.queryRouteByIds(List.copyOf(permissionIds)); + } else { + menuRoute = sysPermissionService.queryRouteByUserid(user.getUserid()); + } + routeCache.putCache(user.getUserid(), menuRoute); + return R.OK(menuRoute); + } + + /** + * 获取菜单与权限 + * + * @return . + */ + @GetMapping("/tree") + @Operation(summary = "获取菜单与权限树形列表") + @PreAuthorize("@permission.hashPermission('menu:query','role:query')") + public R> treesPermission(@ParameterObject PermissionTreeQuery query) { + Optional> permissionOpt = sysPermissionService.listPermission(query); + Optional> treeOpt = permissionOpt + .flatMap(e -> Optional.ofNullable(sysPermissionService.buildTree(e))); + List tree = treeOpt.orElse(Collections.emptyList()); + return R.OK(tree); + } + + @GetMapping("/tree/menu") + @Operation(summary = "获取菜单树形列表") + public R> tressMenus(@ParameterObject PermissionTreeQuery query) { + Optional> permissionOpt = sysPermissionService.listMenu(query); + Optional> treeOpt = permissionOpt + .flatMap(e -> Optional.ofNullable(sysPermissionService.buildTree(e))); + List tree = treeOpt.orElse(Collections.emptyList()); + return R.OK(tree); + } + + @PostMapping("/save") + @Operation(summary = "保存菜单与权限") + @PreAuthorize("@permission.hashPermission('menu:save')") + public R save(@RequestBody PermissionVO vo) { + MenuTypeEnums menuType = ValueEnum.valueToEnum(MenuTypeEnums.class, vo.getMenuType()); + R res = null; + if (MenuTypeEnums.dir == menuType) { + res = checkDirMenuType(vo); + } else if (MenuTypeEnums.menu == menuType) { + res = checkMenuType(vo); + } else { + res = checkPermissionType(vo); + } + if (null != res) { + return res; + } + String username = SecurityUtil.getCurrentUsername(); + vo.setCreated(LocalDateTime.now()); + vo.setCreatedBy(username); + Optional optional = sysPermissionService.save(vo); + return optional.map(R::OK).orElseGet(() -> R.NG("保存失败")); + } + + @PutMapping("/update") + @Operation(summary = "更新菜单与权限") + @PreAuthorize("@permission.hashPermission('menu:update')") + public R update(@Parameter(name = "id", description = "当前ID", required = true) @RequestParam("id") String id, + @Valid @RequestBody PermissionVO vo) { + MenuTypeEnums menuType = ValueEnum.valueToEnum(MenuTypeEnums.class, vo.getMenuType()); + R res = null; + if (MenuTypeEnums.dir == menuType) { + res = checkDirMenuType(vo); + } else if (MenuTypeEnums.menu == menuType) { + res = checkMenuType(vo); + } else { + res = checkPermissionType(vo); + } + if (null != res) { + return res; + } + String username = SecurityUtil.getCurrentUsername(); + vo.setModified(LocalDateTime.now()); + vo.setModifiedBy(username); + Optional optional = sysPermissionService.updateById(vo, id + ); + return optional.map(R::OK).orElseGet(() -> R.NG("更新失败")); + } + + private R checkDirMenuType(PermissionVO vo) { + String title = vo.getTitle(); + if (StrUtil.isBlank(title)) { + return R.NG("菜单名称为空"); + } + String path = vo.getPath(); + if (StrUtil.isBlank(path)) { + return R.NG("路由地址为空"); + } + Integer rank = vo.getRank(); + if (null == rank) { + return R.NG("显示顺序为空"); + } + return null; + } + + private R checkMenuType(PermissionVO vo) { + String title = vo.getTitle(); + if (StrUtil.isBlank(title)) { + return R.NG("菜单名称为空"); + } + String path = vo.getPath(); + if (StrUtil.isBlank(path)) { + return R.NG("路由地址为空"); + } + Integer rank = vo.getRank(); + if (null == rank) { + return R.NG("显示顺序为空"); + } + return null; + } + + private R checkPermissionType(PermissionVO vo) { + String title = vo.getTitle(); + if (StrUtil.isBlank(title)) { + return R.NG("权限名称为空"); + } + String perms = vo.getPerms(); + if (StrUtil.isBlank(perms)) { + return R.NG("权限标识为空"); + } + return null; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysRoleController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysRoleController.java new file mode 100644 index 0000000..f47acc7 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysRoleController.java @@ -0,0 +1,132 @@ +package com.hb0730.boot.admin.modules.sys.system.controller; + +import cn.hutool.core.collection.CollectionUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysRole; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysRolePermission; +import com.hb0730.boot.admin.modules.sys.system.model.query.RoleQuery; +import com.hb0730.boot.admin.modules.sys.system.service.SysRolePermissionService; +import com.hb0730.boot.admin.modules.sys.system.service.SysRoleService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 系统角色 + * + * @author hb0730 + * @date 2023/2/28 + */ +@RestController +@RequestMapping("/sys/role") +@Tag(name = "系统:系统角色") +@RequiredArgsConstructor +public class SysRoleController { + private final SysRoleService sysRoleService; + private final SysRolePermissionService sysRolePermissionService; + + @GetMapping("/query/page") + @PreAuthorize("@permission.hashPermission('role:query')") + @Operation(summary = "分页查询") + public R> queryPage(@ParameterObject RoleQuery query) { + BasePage page = sysRoleService.queryPage(query); + return R.OK(page); + } + + @GetMapping("/query/list") + @Operation(summary = "列表查询") + public R> queryList(@ParameterObject RoleQuery query) { + List roles = sysRoleService.queryList(query); + return R.OK(roles); + } + + @GetMapping("/check/code") + @Operation(summary = "校验code是否重复", parameters = { + @Parameter(name = "id", required = false, description = "id"), + @Parameter(name = "code", required = true, description = "角色编码") + }) + public R checkRole(@RequestParam(value = "id", required = false) String id, + @RequestParam(value = "code") String code) { + boolean checkCode = sysRoleService.checkCode(code, id); + return R.OK(checkCode); + } + + @PostMapping("/save") + @PreAuthorize("@permission.hashPermission('role:save')") + @Operation(summary = "新增") + public R save(@Valid @RequestBody SysRole role) { + String username = SecurityUtil.getCurrentUsername(); + role.setCreated(LocalDateTime.now()); + role.setCreatedBy(username); + return sysRoleService.saveRole(role); + } + + @PutMapping("/update") + @PreAuthorize("@permission.hashPermission('role:update')") + @Operation(summary = "修改") + public R update(@RequestParam("id") String id, @Valid @RequestBody SysRole role) { + String username = SecurityUtil.getCurrentUsername(); + role.setId(id); + role.setModified(LocalDateTime.now()); + role.setModifiedBy(username); + return sysRoleService.updateRole(role); + } + + @GetMapping("/permission") + @Operation(summary = "获取权限ID", parameters = { + @Parameter(required = true, description = "角色ID", name = "id") + }) + public R> getPermissionIdsByRoleId(@RequestParam("id") String id) { + Optional> optional = sysRolePermissionService.findPermissionIdByRole(id); + return R.OK(optional.orElse(Collections.emptyList())); + } + + @PutMapping("/permission") + @Operation(summary = "更新角色权限") + @PreAuthorize("@permission.hashPermission('role:permission')") + public R updatePermissionByRoleId(@Parameter(description = "角色ID") @RequestParam("id") String id, + @RequestBody List permissionIds) { + String username = SecurityUtil.getCurrentUsername(); + List permissions = new ArrayList<>(); + if (CollectionUtil.isNotEmpty(permissionIds)) { + permissions = permissionIds.stream().map(permissionId -> { + SysRolePermission rolePermission = new SysRolePermission(); + rolePermission.setPermissionId(permissionId); + rolePermission.setRoleId(id); + rolePermission.setCreated(LocalDateTime.now()); + rolePermission.setCreatedBy(username); + return rolePermission; + }).collect(Collectors.toList()); + } + return R.OK(sysRolePermissionService.updatePermissionByRoles(id, permissions)); + } + + @DeleteMapping("/del") + @Operation(summary = "删除角色") + @PreAuthorize("@permission.hashPermission('role:del')") + public R delRole(HttpServletRequest request, @Valid @RequestBody List ids) { + return sysRoleService.deleteByIds(ids); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysUserController.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysUserController.java new file mode 100644 index 0000000..458aec7 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/controller/SysUserController.java @@ -0,0 +1,168 @@ +package com.hb0730.boot.admin.modules.sys.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.system.model.query.UserQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.RestPasswdVO; +import com.hb0730.boot.admin.modules.sys.system.model.vo.UserVO; +import com.hb0730.boot.admin.modules.sys.system.service.SysUserService; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户管理 + * + * @author hb0730 + * @date 2023/2/4 + */ +@RestController +@RequestMapping("/sys/user") +@Tag(name = "系统:用户管理") +@RequiredArgsConstructor +public class SysUserController { + private final SysUserService sysUserService; + + + @GetMapping("/query/page") + @Operation(summary = "分页查询") + @PreAuthorize("@permission.hashPermission('user:query:page')") + public R> queryPage(HttpServletRequest request, @ParameterObject UserQuery query) { + BasePage res = this.sysUserService.queryPage(query); + return R.OK(res); + } + + @GetMapping("/query/list") + @Operation(summary = "列表查询") + public R> queryList(HttpServletRequest request, @ParameterObject UserQuery query) { + List res = this.sysUserService.queryList(query); + return R.OK(res); + } + + @GetMapping("/check/username") + @Operation(summary = "检查用户名是否存在") + public R checkUsername(HttpServletRequest request, @RequestParam String username) { + return this.sysUserService.hashUsername(username); + } + + @GetMapping("/") + @Operation(summary = "详情") + public R detail(HttpServletRequest request, @Parameter(name = "id", description = "用户ID", + required = true) @RequestParam String id) { + return this.sysUserService.detail(id); + } + + @GetMapping("/username") + @Operation(summary = "详情") + public R detailByUsername(HttpServletRequest request, @Parameter(name = "username", description = "用户帐号", + required = true) @RequestParam String username) { + return this.sysUserService.detailByUsername(username); + } + + @GetMapping("/query/role/ids") + @Operation(summary = "查询用户角色") + public R> queryRoleIds(HttpServletRequest request, + @Parameter(name = "id", description = "用户ID", required = true) @RequestParam String id) { + return this.sysUserService.getRoleIdsByUserId(id); + } + + @PostMapping("/save") + @Operation(summary = "保存") + @PreAuthorize("@permission.hashPermission('user:save')") + public R save(HttpServletRequest request, @Validated @RequestBody UserVO userVO) { + userVO.setCreated(LocalDateTime.now()); + userVO.setCreatedBy(SecurityUtil.getCurrentUsername()); + userVO.setModified(LocalDateTime.now()); + userVO.setModifiedBy(SecurityUtil.getCurrentUsername()); + return this.sysUserService.save(userVO); + } + + + @PutMapping("/update/{id}") + @Operation(summary = "修改") + @PreAuthorize("@permission.hashPermission('user:update')") + public R update(HttpServletRequest request, @PathVariable String id, + @Validated @RequestBody UserVO userVO) { + userVO.setPassword(null); + userVO.setOrgId(null); + userVO.setUsername(null); + userVO.setModified(LocalDateTime.now()); + userVO.setModifiedBy(SecurityUtil.getCurrentUsername()); + return this.sysUserService.updateById(id, userVO); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除") + @PreAuthorize("@permission.hashPermission('user:del')") + public R delete(HttpServletRequest request, @Validated @RequestBody List ids) { + if (null == ids || ids.isEmpty()) { + return R.NG("删除失败,缺少参数"); + } + return this.sysUserService.deleteByIds(ids); + } + + @PutMapping("/reset/passwd/{username}") + @Operation(summary = "重置密码") + @PreAuthorize("@permission.hashPermission('user:reset:passwd')") + public R resetPasswd(HttpServletRequest request, @PathVariable(value = "username") String username, + @Validated @RequestBody RestPasswdVO vo) { + if (StrUtil.isBlank(vo.getNewPassword())) { + return R.NG("新密码不能为空"); + } + if (!vo.getNewPassword().equals(vo.getConfirmPassword())) { + return R.NG("两次密码不一致"); + } + return this.sysUserService.resetPassword(username, vo.getConfirmPassword()); + } + + @PutMapping("/change/passwd/{username}") + @Operation(summary = "修改密码") + public R changePasswd(HttpServletRequest request, + @PathVariable("username") String username, @Validated @RequestBody RestPasswdVO vo) { + if (StrUtil.isBlank(vo.getNewPassword())) { + return R.NG("新密码不能为空"); + } + if (!vo.getNewPassword().equals(vo.getConfirmPassword())) { + return R.NG("两次密码不一致"); + } + if (vo.getOldPassword().equals(vo.getNewPassword())) { + return R.NG("新密码不能与旧密码相同"); + } + return this.sysUserService.changePasswd(username, vo.getOldPassword(), vo.getNewPassword()); + } + + @PutMapping("/update/passwd/{id}") + @Operation(summary = "修改密码") + public R updatePassword(HttpServletRequest request, + @PathVariable("id") String id, @Validated @RequestBody RestPasswdVO vo) { + if (StrUtil.isBlank(vo.getNewPassword())) { + return R.NG("新密码不能为空"); + } + if (!vo.getNewPassword().equals(vo.getConfirmPassword())) { + return R.NG("两次密码不一致"); + } + if (vo.getOldPassword().equals(vo.getNewPassword())) { + return R.NG("新密码不能与旧密码相同"); + } + return this.sysUserService.updatePassword(id, vo.getNewPassword()); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/event/RefreshOnlineUserRouteEvent.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/event/RefreshOnlineUserRouteEvent.java new file mode 100644 index 0000000..774a066 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/event/RefreshOnlineUserRouteEvent.java @@ -0,0 +1,15 @@ +package com.hb0730.boot.admin.modules.sys.system.event; + +import org.springframework.context.ApplicationEvent; + +/** + * 刷新在线用户路由&权限信息 + * + * @author hb0730 + * @date 2023/6/6 + */ +public class RefreshOnlineUserRouteEvent extends ApplicationEvent { + public RefreshOnlineUserRouteEvent(Object source) { + super(source); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/event/RefreshOnlineUserRouteListener.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/event/RefreshOnlineUserRouteListener.java new file mode 100644 index 0000000..1da2e1a --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/event/RefreshOnlineUserRouteListener.java @@ -0,0 +1,51 @@ +package com.hb0730.boot.admin.modules.sys.system.event; + +import com.hb0730.boot.admin.config.cache.BootAdminProperties; +import com.hb0730.boot.admin.modules.sys.system.cache.RouteCache; +import com.hb0730.boot.admin.security.model.UserInfo; +import com.hb0730.boot.admin.security.token.UserCacheProvider; +import jakarta.annotation.Nonnull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +/** + * @author hb0730 + * @date 2023/6/6 + */ +@Component +@RequiredArgsConstructor +@Slf4j +@Async +public class RefreshOnlineUserRouteListener implements ApplicationListener { + private final UserCacheProvider userCacheProvider; + private final BootAdminProperties properties; + private final RouteCache routeCache; + + @Override + public void onApplicationEvent(@Nonnull RefreshOnlineUserRouteEvent event) { + log.info("【刷新在线用户路由事件】刷新在线用户路由信息>>>>>>>>>>>开始"); + Boolean refreshRoutes = properties.getRefreshRoutes(); + if (!refreshRoutes) { + log.warn("【刷新在线用户路由事件】刷新在线用户路由信息>>>>>>>>>>>未开启"); + return; + } + Optional> users = userCacheProvider.getCacheUsers(); + if (users.isPresent()) { + List userInfoList = users.get(); + for (UserInfo userInfo : userInfoList) { + log.info("【刷新在线用户路由事件】开始清理登陆用户缓存信息: {}", userInfo.getUsername()); + // TODO 是否刷新用户权限信息 + userCacheProvider.clearUser(userInfo.getUsername()); + log.info("【刷新在线用户路由事件】开始清理登陆用户路由信息: {}", userInfo.getUsername()); + routeCache.removeCache(userInfo.getUserid()); + } + } + log.info("【刷新在线用户路由事件】刷新在线用户路由信息>>>>>>>>>>>结束"); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysConfigMapper.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000..8e442ff --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysConfigMapper.java @@ -0,0 +1,28 @@ +package com.hb0730.boot.admin.modules.sys.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysConfig; +import com.hb0730.boot.admin.modules.sys.system.model.query.ConfigQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.ConfigVO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 系统配置 + * + * @author hb0730 + * @date 2023/6/12 + */ +public interface SysConfigMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page . + * @param query . + * @return . + */ + List queryPage(Page page, @Param("query") ConfigQuery query); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysOrgMapper.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysOrgMapper.java new file mode 100644 index 0000000..b8b7578 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysOrgMapper.java @@ -0,0 +1,27 @@ +package com.hb0730.boot.admin.modules.sys.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysOrganization; +import com.hb0730.boot.admin.modules.sys.system.model.query.OrganizationQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.OrganizationVO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 机构 Mapper + * + * @author hb0730 + * @date 2023/6/3 + */ +public interface SysOrgMapper extends BaseMapper { + /** + * 分页查询 + * + * @param page . + * @param query . + * @return . + */ + List queryPage(Page page, @Param("query") OrganizationQuery query); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysPermissionMapper.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysPermissionMapper.java new file mode 100644 index 0000000..b1a0594 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysPermissionMapper.java @@ -0,0 +1,54 @@ +package com.hb0730.boot.admin.modules.sys.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysPermission; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +public interface SysPermissionMapper extends BaseMapper { + + /** + * 根据角色ID查询菜单与权限 + * + * @param roleIds 角色ID + * @param isEnabled 是否查询启用的 + * @return 菜单与权限 + */ + @Nullable + List listByRoleIds(@Nonnull @Param("roleIds") List roleIds, + @Nullable @Param("is_enabled") Boolean isEnabled); + + /** + * 菜单与权限 + * @param isEnabled 是否查询启用的 + * @return 菜单与权限 + */ + List list(@Nullable @Param("is_enabled") Boolean isEnabled); + /** + * 查询权限 + * + * @param ids ID集合 + * @param isEnabled 是否查询已启用的 + * @return 权限信息 + */ + List listPermission(@Nullable @Param("ids") List ids, + @Nullable @Param("is_enabled") Boolean isEnabled); + + /** + * 查询菜单根据ID + * + * @param ids 菜单ID集合 + * @param isEnabled 是否查询启用 + * @return 菜单集合 + */ + @Nullable + List listMenuByIds(@Nullable @Param("ids") List ids, + @Nullable @Param("is_enabled") Boolean isEnabled); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysRoleMapper.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..f7cc42f --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysRoleMapper.java @@ -0,0 +1,13 @@ +package com.hb0730.boot.admin.modules.sys.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysRole; + +/** + * 角色信息 + * + * @author hb0730 + * @date 2023/2/28 + */ +public interface SysRoleMapper extends BaseMapper { +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysRolePermissionMapper.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysRolePermissionMapper.java new file mode 100644 index 0000000..f6cc446 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysRolePermissionMapper.java @@ -0,0 +1,32 @@ +package com.hb0730.boot.admin.modules.sys.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysRolePermission; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色权限 + * + * @author hb0730 + * @date 2023/3/2 + */ +public interface SysRolePermissionMapper extends BaseMapper { + + /** + * 根据权限ID获取所有的父级ID + * + * @param permissionIds . + * @return . + */ + List getParentIdByPermissionIds(@Param("permissionIds") List permissionIds); + + /** + * 根据角色ID查询权限ID,只查询没有下级的权限 + * + * @param roleId . + * @return . + */ + List getPermissionIdByRoleId(@Param("roleId") String roleId); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysUserMapper.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..37c1525 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysUserMapper.java @@ -0,0 +1,96 @@ +package com.hb0730.boot.admin.modules.sys.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUser; +import com.hb0730.boot.admin.modules.sys.system.model.query.UserQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.UserVO; +import jakarta.annotation.Nullable; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Set; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +public interface SysUserMapper extends BaseMapper { + /** + * 根据用户名获取用户信息 + * + * @param username . + * @return . + */ + SysUser getByUsername(@Param("username") String username); + + /** + * 根据用户名获取已授权的角色代码 + * + * @param username 用户名 + * @return 已授权的角色代码 + */ + @Nullable + Set getRoleCodeByUsername(@Param("username") String username); + + /** + * 根据用户ID 获取对应的角色ID集合 + * + * @param userId 用户ID + * @return 角色ID集合 + */ + @Nullable + Set queryUserRole(@Param("userId") String userId); + + /** + * 获取全部角色code + * + * @return . + */ + @Nullable + Set allRoleCode(); + /*=========================================================*/ + + /** + * 分页查询 + * + * @param page . + * @param query . + * @return . + */ + List queryPage(Page page, @Param("query") UserQuery query); + + /** + * 保存用户角色 + * + * @param userId . + * @param roleIds . + * @return . + */ + int saveUserRole(@Param("userId") String userId, @Param("roleIds") Set roleIds); + + /** + * 根据用户ID删除用户角色 + * + * @param userId . + * @return . + */ + int delUserRoleByUserid(@Param("userId") String userId); + + /** + * 根据用户ID删除用户角色 + * + * @param userIds . + * @return . + */ + int delUserRoleByUserids(@Param("userIds") List userIds); + + /** + * 重置密码 + * + * @param username . + * @param password . + * @return . + */ + int resetPassword(@Param("username") String username, @Param("password") String password); +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysUserRoleMapper.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..5fa47ee --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,13 @@ +package com.hb0730.boot.admin.modules.sys.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUserRole; + +/** + * 用户角色 + * + * @author hb0730 + * @date 2023/2/4 + */ +public interface SysUserRoleMapper extends BaseMapper { +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysConfigMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysConfigMapper.xml new file mode 100644 index 0000000..8eeef6a --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysConfigMapper.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysOrgMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysOrgMapper.xml new file mode 100644 index 0000000..7723863 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysOrgMapper.xml @@ -0,0 +1,47 @@ + + + + + t.id, + t.parent_id, + t.name, + t.code, + t.is_enable, + t.created, + t.created_by, + t.modified, + t.modified_by, + t.path, + t.link_man, + t.link_tel, + t.province_id, + t.city_id, + t.county_id, + t.address, + t.longitude, + t.memo, + t.is_system, + t.is_enable + + + \ No newline at end of file diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysPermissionMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysPermissionMapper.xml new file mode 100644 index 0000000..ab2c4e6 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysPermissionMapper.xml @@ -0,0 +1,110 @@ + + + + + p.id, + p.parent_id, + p.path, + p.name, + p.title, + p.icon, + p.show_link, + p.`rank`, + p.component, + p.show_parent, + p.keep_alive, + p.is_frame, + p.menu_type, + p.perms, + p.is_enable, + p.created, + p.created_by, + p.modified, + p.modified_by + + + + + + + + + + + diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysRoleMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysRoleMapper.xml new file mode 100644 index 0000000..5c63864 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysRoleMapper.xml @@ -0,0 +1,5 @@ + + + + diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysRolePermissionMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysRolePermissionMapper.xml new file mode 100644 index 0000000..2bddff4 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysRolePermissionMapper.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysUserMapper.xml b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysUserMapper.xml new file mode 100644 index 0000000..6ca2f59 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/mapper/xml/SysUserMapper.xml @@ -0,0 +1,82 @@ + + + + + t.id,t.created_by + ,t.created,t.modified_by,t.modified,t.username,t.password,t.nickname,t.phone,t.is_enabled,t.email,t.org_id,t.is_manage + + + + + + + + + INSERT INTO sys_user_role (id,user_id, role_id) VALUES + + (md5(uuid()),#{userId}, #{item}) + + + + DELETE FROM sys_user_role WHERE user_id = #{userId} + + + DELETE FROM sys_user_role WHERE user_id in + + #{item} + + + + UPDATE sys_user + SET password = #{password} + WHERE username = #{username} + + + + diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/dto/PermissionTree.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/dto/PermissionTree.java new file mode 100644 index 0000000..72a41cc --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/dto/PermissionTree.java @@ -0,0 +1,70 @@ +package com.hb0730.boot.admin.modules.sys.system.model.dto; + +import com.hb0730.boot.admin.data.domain.TreeData; +import com.hb0730.boot.admin.data.enums.MenuTypeEnums; +import com.hb0730.boot.admin.data.enums.ValueEnum; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysPermission; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.ArrayList; +import java.util.List; + +/** + * 权限树 + * + * @author hb0730 + * @date 2023/2/6 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class PermissionTree extends SysPermission implements TreeData { + @Schema(description = "子菜单") + private List children = new ArrayList<>(); + + public PermissionTree setChildren(List children) { + this.children = children; + return this; + } + + public List getChildren() { + return children; + } + + + @Schema(description = "是否显示") + public boolean isShowLink() { + return getShowLink() == 1; + } + + @Schema(description = "是否显示父类") + public boolean isShowParent() { + return getShowParent() == 1; + } + + @Schema(description = "是否缓存") + public boolean isKeepAlive() { + return getKeepAlive() == 1; + } + + @Schema(description = "是否iframe") + public boolean isFrame() { + return getIsFrame() == 1; + } + + @Schema(description = "菜单类型名称") + public String getMenuTypeName() { + if (ValueEnum.hash(MenuTypeEnums.class, getMenuType())) { + return ValueEnum.valueToEnum(MenuTypeEnums.class, getMenuType()).getName(); + } + return null; + } + + @Schema(description = "是否启用") + public boolean isEnabled() { + return getEnabled() == 1; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysConfig.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysConfig.java new file mode 100644 index 0000000..c3600a5 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysConfig.java @@ -0,0 +1,38 @@ +package com.hb0730.boot.admin.modules.sys.system.model.entity; + +import com.hb0730.boot.admin.data.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 系统配置 + * + * @author hb0730 + * @date 2023/6/12 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class SysConfig extends BaseEntity { + /** + * 类型 + *
    + *
  • 1. 系统配置
  • + *
  • 2. 业务配置
  • + *
+ */ + private Integer type; + /** + * 配置项 + */ + private String code; + /** + * 配置值 + */ + private String value; + /** + * 备注,max 255 + */ + private String memo; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysOrganization.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysOrganization.java new file mode 100644 index 0000000..2293702 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysOrganization.java @@ -0,0 +1,97 @@ +package com.hb0730.boot.admin.modules.sys.system.model.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.transaction.annotation.Transactional; + +/** + * 网点机构 + * + * @author hb0730 + * @date 2023/3/2 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Transactional +@TableName("sys_org") +public class SysOrganization extends BaseEntity { + /** + * 父机构ID + */ + private String parentId; + /** + * 机构path + */ + private String path; + /** + * 机构代码 + */ + private String code; + /** + * 机构名称 + */ + private String name; + /** + * 联系人 + */ + private String linkMan; + + /** + * 联系电话 + */ + private String linkTel; + + /** + * 省份编码 + */ + private String provinceId; + + /** + * 省份名称 + */ + private String province; + + /** + * 城市编码 + */ + private String cityId; + + /** + * 城市名称 + */ + private String city; + + /** + * 区县编码 + */ + private String countyId; + + /** + * 区县名称 + */ + private String county; + /** + * 详细地址 + */ + private String address; + /** + * 详细地址的经纬度 + */ + private String longitude; + + /** + * 备注 + */ + private String memo; + /** + * 是否内置 + */ + private Integer isSystem; + + /** + * 是否启用 + */ + private Integer isEnable; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysPermission.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysPermission.java new file mode 100644 index 0000000..85b7d0e --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysPermission.java @@ -0,0 +1,114 @@ +package com.hb0730.boot.admin.modules.sys.system.model.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.Accessors; + +/** + * 菜单与权限 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@ToString +public class SysPermission extends BaseEntity { + /** + * 父类 + */ + @Schema(description = "父ID") + private String parentId; + /** + * 路由地址 + */ + @Schema(description = "路由地址") + private String path; + /** + * 路由名字 + */ + @Schema(description = "路由名称") + private String name; + /** + * 菜单名称 + */ + @Schema(description = "菜单名称") + private String title; + /** + * 菜单icon + */ + @Schema(description = "菜单icon") + private String icon; + /** + * 是否显示 + */ + @Schema(description = "是否显示") + private Integer showLink; + + public Integer getShowLink() { + return showLink == null ? 0 : showLink; + } + + /** + * 排序 + */ + @Schema(description = "排序") + @TableField(value = "`rank`") + private Integer rank; + /** + * 组件 + */ + @Schema(description = "组件地址") + private String component; + /** + * 是否显示父菜单 + */ + @Schema(description = "是否显示父菜单") + private Integer showParent; + + public Integer getShowParent() { + return showParent == null ? 0 : showParent; + } + + /** + * 是否缓存该路由页面(开启后,会保存该页面的整体状态,刷新后会清空状态) + */ + @Schema(description = "是否缓存该路由页面") + private Integer keepAlive; + + public Integer getKeepAlive() { + return keepAlive == null ? 0 : keepAlive; + } + + /** + * 是否iframe + */ + @Schema(description = "是否iframe") + private Integer isFrame; + + public Integer getIsFrame() { + return isFrame == null ? 0 : isFrame; + } + + /** + * 类型(0:目录;1:菜单 ;2:按钮权限) + */ + @Schema(description = "类型") + private Integer menuType; + /** + * 菜单权限编码,例如:“sys:schedule:list,sys:schedule:info”,多个逗号隔开 + */ + @Schema(description = "菜单权限编码") + private String perms; + /** + * 是否启用 + */ + @Schema(description = "是否启用") + @TableField("is_enable") + private Integer enabled; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysRole.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysRole.java new file mode 100644 index 0000000..dd42d15 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysRole.java @@ -0,0 +1,67 @@ +package com.hb0730.boot.admin.modules.sys.system.model.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 角色信息 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class SysRole extends BaseEntity { + /** + * 角色名称 + */ + @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "角色名称为空") + private String roleName; + + /** + * 角色编码 + */ + @Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "角色编码为空") + private String roleCode; + + /** + * 描述 + */ + @Schema(description = "描述") + private String description; + + /** + * 是否启用(1,启用,2禁用) + */ + @TableField("is_enable") + @Schema(description = "是否启用", defaultValue = "0") + private Integer enabled; + + public Integer getEnabled() { + if (null == enabled) { + return 0; + } + return enabled; + } + + /** + * 总部标识:1是,0:否 + */ + @Schema(description = "总部标识", defaultValue = "0") + private Integer isSystem; + + public Integer getIsSystem() { + if (null == isSystem) { + return 0; + } + return isSystem; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysRolePermission.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysRolePermission.java new file mode 100644 index 0000000..a101847 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysRolePermission.java @@ -0,0 +1,52 @@ +package com.hb0730.boot.admin.modules.sys.system.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 角色权限表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode +@ToString +public class SysRolePermission implements Serializable { + + /** + * ID + */ + @TableId(type = IdType.ASSIGN_ID) + protected String id; + + /** + * 角色id + */ + private String roleId; + + /** + * 权限id + */ + private String permissionId; + + /** + * 数据权限 + */ + private String dataRuleIds; + /** + * 创建时间 + */ + private LocalDateTime created; + /** + * 创建人 + */ + private String createdBy; + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUser.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUser.java new file mode 100644 index 0000000..03822b4 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUser.java @@ -0,0 +1,62 @@ +package com.hb0730.boot.admin.modules.sys.system.model.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.hb0730.boot.admin.data.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 用户表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@TableName +public class SysUser extends BaseEntity { + /** + * 用户名 + */ + private String username; + /** + * 用户密码 + */ + private String password; + /** + * 用户昵称 + */ + private String nickname; + /** + * 手机号 + */ + private String phone; + /** + * 是否启用 + */ + private Integer isEnabled; + /** + * 所属机构 + */ + private String orgId; + /** + * 是否网点管理员 + */ + private Integer isManage; + + /** + * 微信openId + */ + private String openId; + + /** + * 微信unionId + */ + private String unionId; + + public boolean isManager() { + return isManage == 1; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUserDepart.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUserDepart.java new file mode 100644 index 0000000..ea5d41c --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUserDepart.java @@ -0,0 +1,36 @@ +package com.hb0730.boot.admin.modules.sys.system.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户部门表 + * + * @author hb0730 + * @date 2023/6/8 + */ +@Data +@TableName("sys_user_depart") +public class SysUserDepart implements Serializable { + + /** + * ID + */ + @TableId(type = IdType.ASSIGN_ID) + protected String id; + + /** + * 用户id + */ + private String userId; + /** + * 部门id + */ + private String depId; + + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUserRole.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUserRole.java new file mode 100644 index 0000000..fb0e550 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/entity/SysUserRole.java @@ -0,0 +1,45 @@ +package com.hb0730.boot.admin.modules.sys.system.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +/** + * 用户角色表 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Data +@EqualsAndHashCode +@ToString +public class SysUserRole implements Serializable { + + /** + * ID + */ + @TableId(type = IdType.ASSIGN_ID) + protected String id; + + /** + * 用户id + */ + private String userId; + + /** + * 角色id + */ + private String roleId; + + public SysUserRole() { + } + + public SysUserRole(String userId, String roleId) { + this.userId = userId; + this.roleId = roleId; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/ConfigQuery.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/ConfigQuery.java new file mode 100644 index 0000000..6f27d31 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/ConfigQuery.java @@ -0,0 +1,24 @@ +package com.hb0730.boot.admin.modules.sys.system.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 系统配置查询 + * + * @author hb0730 + * @date 2023/6/12 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +@Schema(description = "系统配置查询") +public class ConfigQuery extends BasePageQuery { + @Schema(description = "类型 1系统配置 2业务配置") + private Integer type; + @Schema(description = "配置项") + private String code; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/OrganizationQuery.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/OrganizationQuery.java new file mode 100644 index 0000000..2608472 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/OrganizationQuery.java @@ -0,0 +1,45 @@ +package com.hb0730.boot.admin.modules.sys.system.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 机构查询 + * + * @author hb0730 + * @date 2023/6/3 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class OrganizationQuery extends BasePageQuery { + /** + * 所属机构 + */ + @Parameter(description = "所属机构ID") + private String parentId; + /** + * 机构名称 + */ + @Parameter(description = "机构名称") + private String name; + /** + * 机构编码 + */ + @Parameter(description = "机构编码") + private String code; + /** + * 联系人电话 + */ + @Parameter(description = "联系人电话") + private String linkTel; + /** + * 状态 + */ + @Parameter(description = "状态") + private Integer isEnable; + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/PermissionTreeQuery.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/PermissionTreeQuery.java new file mode 100644 index 0000000..9312c82 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/PermissionTreeQuery.java @@ -0,0 +1,32 @@ +package com.hb0730.boot.admin.modules.sys.system.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 菜单权限树形查询参数 + * + * @author hb0730 + * @date 2023/2/12 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class PermissionTreeQuery extends BasePageQuery { + /** + * 菜单名称 + */ + @Schema(description = "菜单名称") + @Parameter(description = "菜单名称") + private String title; + /** + * 菜单状态 + */ + @Schema(description = "菜单状态") + @Parameter(description = "菜单状态") + private Integer enabled; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/RoleQuery.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/RoleQuery.java new file mode 100644 index 0000000..fb01e40 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/RoleQuery.java @@ -0,0 +1,34 @@ +package com.hb0730.boot.admin.modules.sys.system.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 权限查询 + * + * @author hb0730 + * @date 2023/2/28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class RoleQuery extends BasePageQuery { + /** + * 角色code + */ + @Parameter(description = "角色code") + private String roleCode; + /** + * 角色name + */ + @Parameter(description = "角色name") + private String roleName; + /** + * 是否启用 + */ + @Parameter(description = "是否启用") + private Integer enabled; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/UserQuery.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/UserQuery.java new file mode 100644 index 0000000..3cf7a25 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/query/UserQuery.java @@ -0,0 +1,44 @@ +package com.hb0730.boot.admin.modules.sys.system.model.query; + +import com.hb0730.boot.admin.data.domain.BasePageQuery; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 用户查询参数 + * + * @author hb0730 + * @date 2023/6/8 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class UserQuery extends BasePageQuery { + /** + * 所属机构 + */ + @Parameter(description = "所属机构") + private String orgId; + /** + * 用户帐号 + */ + @Parameter(description = "用户帐号") + private String username; + /** + * 姓名 + */ + @Parameter(description = "姓名") + private String nickname; + /** + * 联系电话 + */ + @Parameter(description = "联系电话") + private String phone; + /** + * 状态 + */ + @Parameter(description = "状态") + private Integer enable; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/ConfigVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/ConfigVO.java new file mode 100644 index 0000000..fb34c24 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/ConfigVO.java @@ -0,0 +1,70 @@ +package com.hb0730.boot.admin.modules.sys.system.model.vo; + +import com.hb0730.boot.admin.data.enums.ConfigTypeEnums; +import com.hb0730.boot.admin.data.enums.ValueEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author hb0730 + * @date 2023/6/12 + */ +@Data +@EqualsAndHashCode +@ToString +public class ConfigVO implements Serializable { + @Schema(description = "主键") + private String id; + @Schema(description = "类型 1系统配置 2业务配置") + @NotBlank(message = "类型不能为空") + @Min(value = 1, message = "类型错误") + @Max(value = 2, message = "类型错误") + private Integer type; + + @Schema(description = "类型名称,只作用与响应数据") + public String getTypeName() { + if (null == type) { + return ""; + } + return ValueEnum.valueToEnum(ConfigTypeEnums.class, type, ConfigTypeEnums.CONFIG_TYPE01).getName(); + } + + @Schema(description = "配置项") + private String code; + @Schema(description = "配置值") + private String value; + @Schema(description = "备注") + @Max(value = 255, message = "备注长度不能超过255") + private String memo; + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/OrganizationTree.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/OrganizationTree.java new file mode 100644 index 0000000..2c645da --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/OrganizationTree.java @@ -0,0 +1,22 @@ +package com.hb0730.boot.admin.modules.sys.system.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.ArrayList; +import java.util.List; + +/**树形结构-机构信息 + * @author hb0730 + * @date 2023/6/3 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString +public class OrganizationTree extends OrganizationVO { + @Schema(description = "子节点") + private List children=new ArrayList<>(); + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/OrganizationVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/OrganizationVO.java new file mode 100644 index 0000000..168a5cb --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/OrganizationVO.java @@ -0,0 +1,182 @@ +package com.hb0730.boot.admin.modules.sys.system.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 机构信息 + * + * @author hb0730 + * @date 2023/6/3 + */ +@Data +@EqualsAndHashCode +@ToString +public class OrganizationVO implements Serializable { + + /** + * ID + */ + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; + /** + * 父类 + */ + @Schema(description = "父ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "父ID不能为空") + private String parentId; + @Schema(description = "所属机构名称") + private String parentName; + @Schema(description = "所属机构编码") + private String parentCode; + /** + * 机构代码 + */ + @Schema(description = "机构代码") + private String code; + /** + * 机构名称 + */ + @Schema(description = "机构名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "机构名称不能为空") + private String name; + /** + * 机构path + */ + @Schema(description = "机构path") + private String path; + /** + * 联系人 + */ + @Schema(description = "联系人") + private String linkMan; + + /** + * 联系电话 + */ + @Schema(description = "联系电话") + private String linkTel; + + /** + * 省份编码 + */ + @Schema(description = "省份ID") + private String provinceId; + + /** + * 省份名称 + */ + @Schema(description = "省份名称") + private String province; + + /** + * 城市编码 + */ + @Schema(description = "城市ID") + private String cityId; + + /** + * 城市名称 + */ + @Schema(description = "城市名称") + private String city; + + /** + * 区县编码 + */ + @Schema(description = "区县ID") + private String countyId; + + /** + * 区县名称 + */ + @Schema(description = "区县名称") + private String county; + /** + * 城镇、街道编码 + */ + @Schema(description = "街道ID") + private String townId; + + /** + * 城镇、街道名称 + */ + @Schema(description = "街道名称") + private String town; + /** + * 详细地址 + */ + @Schema(description = "详细地址") + private String address; + /** + * 详细地址的经纬度 + */ + @Schema(description = "详细地址的经纬度") + private String longitude; + + /** + * 备注 + */ + @Schema(description = "备注") + private String memo; + /** + * 是否内置 + */ + @Schema(description = "是否内置") + private Integer isSystem; + + /** + * 是否内存 + * + * @return . + */ + @Schema(description = "是否内置") + public boolean isSystem() { + return isSystem != null && isSystem == 1; + } + + /** + * 是否启用 + */ + @Schema(description = "是否启用") + private Integer isEnable; + + /** + * 是否启用 + * + * @return . + */ + public boolean isEnable() { + return isEnable != null && isEnable == 1; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/PermissionVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/PermissionVO.java new file mode 100644 index 0000000..5c4cff7 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/PermissionVO.java @@ -0,0 +1,148 @@ +package com.hb0730.boot.admin.modules.sys.system.model.vo; + +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author hb0730 + * @date 2023/2/25 + */ +@Data +@EqualsAndHashCode +@ToString +public class PermissionVO implements Serializable { + + /** + * ID + */ + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; + /** + * 父类 + */ + @Schema(description = "父ID") + private String parentId; + /** + * 路由地址 + */ + @Schema(description = "路由地址") + private String path; + /** + * 路由名字 + */ + @Schema(description = "路由名称") + private String name; + /** + * 菜单名称 + */ + @Schema(description = "菜单名称") + private String title; + /** + * 菜单icon + */ + @Schema(description = "菜单icon") + private String icon; + /** + * 是否显示 + */ + @Schema(description = "是否显示") + private boolean showLink; + + public Integer getShowLink() { + return showLink ? 1 : 0; + } + + /** + * 排序 + */ + @Schema(description = "排序") + @TableField(value = "`rank`") + private Integer rank; + /** + * 组件 + */ + @Schema(description = "组件地址") + private String component; + /** + * 是否显示父菜单 + */ + @Schema(description = "是否显示父菜单") + private boolean showParent; + + public Integer getShowParent() { + return showParent ? 1 : 0; + } + + /** + * 是否缓存该路由页面(开启后,会保存该页面的整体状态,刷新后会清空状态) + */ + @Schema(description = "是否缓存该路由页面") + private boolean keepAlive; + + public Integer getKeepAlive() { + return keepAlive ? 1 : 0; + } + + /** + * 是否iframe + */ + @Schema(description = "是否iframe") + private Integer isFrame; + + /** + * 需要内嵌的iframe链接地址 + */ + @Schema(description = "需要内嵌的iframe链接地址") + private String frameSrc; + /** + * 类型(0:目录;1:菜单 ;2:按钮权限) + */ + @Schema(description = "类型") + @NotNull(message = "菜单类型不为空") + private Integer menuType; + /** + * 菜单权限编码,例如:“sys:schedule:list,sys:schedule:info”,多个逗号隔开 + */ + @Schema(description = "菜单权限编码") + private String perms; + /** + * 是否启用 + */ + @Schema(description = "是否启用") + private boolean enabled; + + public Integer getEnabled() { + return enabled ? 1 : 0; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/RestPasswdVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/RestPasswdVO.java new file mode 100644 index 0000000..b04d24d --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/RestPasswdVO.java @@ -0,0 +1,38 @@ +package com.hb0730.boot.admin.modules.sys.system.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +/** + * 重置密码 + * + * @author hb0730 + * @date 2023/6/11 + */ +@Data +@EqualsAndHashCode +@ToString +public class RestPasswdVO implements Serializable { + /** + * 旧密码 + */ + @Schema(description = "旧密码") + private String oldPassword; + /** + * 新密码 + */ + @Schema(description = "新密码",requiredMode= Schema.RequiredMode.REQUIRED) + @NotBlank(message = "新密码不能为空") + private String newPassword; + /** + * 确认密码 + */ + @Schema(description = "确认密码",requiredMode= Schema.RequiredMode.REQUIRED) + @NotBlank(message = "确认密码不能为空") + private String confirmPassword; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/UserVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/UserVO.java new file mode 100644 index 0000000..5510b94 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/UserVO.java @@ -0,0 +1,138 @@ +package com.hb0730.boot.admin.modules.sys.system.model.vo; + +import cn.hutool.core.util.StrUtil; +import com.hb0730.boot.admin.base.util.AesEncryptUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户信息 + * + * @author hb0730 + * @date 2023/6/8 + */ +@Data +@EqualsAndHashCode +@ToString +public class UserVO implements Serializable { + /** + * ID + */ + @Schema(description = "id") + protected String id; + + /** + * 创建人 + */ + @Schema(description = "创建人") + protected String createdBy; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + protected LocalDateTime created; + + /** + * 更新人 + */ + @Schema(description = "更新人") + protected String modifiedBy; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + protected LocalDateTime modified; + /** + * 用户名 + */ + @Schema(description = "用户帐号") + @NotBlank(message = "用户帐号不能为空") + private String username; + /** + * 用户密码 + */ + @Schema(description = "用户密码") + private String password; + /** + * 用户昵称 + */ + @Schema(description = "用户昵称") + private String nickname; + /** + * 手机号 + */ + @Schema(description = "手机号") + private String phone; + + public String getPhone() { + if (StrUtil.isBlank(phone)) { + return null; + } + // 有可能没有加密 + try { + return AesEncryptUtil.desEncrypt(phone); + } catch (Exception e) { + return phone; + } + } + + /** + * 邮箱 + */ + @Schema(description = "邮箱") + private String email; + /** + * 是否启用 + */ + @Schema(description = "是否启用") + private Integer isEnabled; + + /** + * 是否启用 + * + * @return . + */ + @Schema(description = "是否启用") + public boolean isEnabled() { + if (null == isEnabled) { + return false; + } + return isEnabled == 1; + } + + /** + * 所属机构 + */ + @Schema(description = "所属机构") + private String orgId; + /** + * 机构code + */ + @Schema(description = "机构code") + private String orgCode; + /** + * 机构名称 + */ + @Schema(description = "机构名称") + private String orgName; + /** + * 是否网点管理员 + */ + @Schema(description = "是否网点管理员") + private Integer isManage; + + /** + * 角色id集合 + */ + @Schema(description = "角色id集合") + private List roleIds; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/VueMenuRouteMeta.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/VueMenuRouteMeta.java new file mode 100644 index 0000000..4ac4f81 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/VueMenuRouteMeta.java @@ -0,0 +1,57 @@ +package com.hb0730.boot.admin.modules.sys.system.model.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; + +/** + * 菜单路由 mate + * + * @author hb0730 + * @date 2023/2/6 + */ +@Data +@EqualsAndHashCode +@ToString +@JsonInclude(value = JsonInclude.Include.NON_NULL) +public class VueMenuRouteMeta implements Serializable { + /** + * title + */ + @Schema(description = "title") + private String title; + /** + * 菜单图标 + */ + @Schema(description = "菜单图标") + private String icon; + /** + * 是否显示该菜单 + */ + @Schema(description = "是否显示该菜单") + private Boolean showLink; + /** + * 菜单排序,值越高排的越后(只针对顶级路由) + */ + @Schema(description = "菜单排序") + private Integer rank; + /** + * 是否显示父级菜单 + */ + @Schema(description = "是否显示父级菜单") + private Boolean showParent; + /** + * 是否缓存该路由页面(开启后,会保存该页面的整体状态,刷新后会清空状态) + */ + @Schema(description = "是否缓存该路由页面") + private Boolean keepAlive; + /** + * 需要内嵌的iframe链接地址 + */ + @Schema(description = "需要内嵌的iframe链接地址") + private String frameSrc; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/VueMenuRouteVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/VueMenuRouteVO.java new file mode 100644 index 0000000..c9c61d5 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/model/vo/VueMenuRouteVO.java @@ -0,0 +1,50 @@ +package com.hb0730.boot.admin.modules.sys.system.model.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.util.List; + +/** + * vue 路由菜单 + * + * @author hb0730 + * @date 2023/2/6 + */ +@Data +@EqualsAndHashCode +@ToString +@JsonInclude(value = JsonInclude.Include.NON_NULL) +@Schema(description = "vue 路由菜单") +public class VueMenuRouteVO implements Serializable { + /** + * 路由地址 + */ + @Schema(description = "路由地址") + private String path; + /** + * 路由名字(必须保持唯一) + */ + @Schema(description = "路由名字") + private String name; + /** + * 按需加载需要展示的页面 + */ + @Schema(description = "组件") + private String component; + /** + * 路由元信息 + */ + @Schema(description = "路由元信息") + private VueMenuRouteMeta meta; + /** + * 菜单 + */ + @Schema(description = "菜单") + @JsonInclude(JsonInclude.Include.NON_NULL) + private List children; +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysConfigService.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysConfigService.java new file mode 100644 index 0000000..fdbc533 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysConfigService.java @@ -0,0 +1,109 @@ +package com.hb0730.boot.admin.modules.sys.system.service; + +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.core.service.BaseServiceImpl; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.system.cache.ConfigCache; +import com.hb0730.boot.admin.modules.sys.system.mapper.SysConfigMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysConfig; +import com.hb0730.boot.admin.modules.sys.system.model.query.ConfigQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.ConfigVO; +import jakarta.annotation.Nonnull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 系统配置 SERVICE + * + * @author hb0730 + * @date 2023/6/12 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysConfigService extends BaseServiceImpl { + private final ConfigCache cache; + + /** + * 分页查询 + * + * @param query . + * @return . + */ + public R> queryPage(ConfigQuery query) { + Page page = new Page<>(query.getCurrent(), query.getSize()); + List list = baseMapper.queryPage(page, query); + page.setRecords(list); + BasePage _page = new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), page.getRecords()); + return R.OK(_page); + } + + /** + * 列表查询 + * + * @param query . + * @return . + */ + public R> queryList(ConfigQuery query) { + List list = baseMapper.queryPage(null, query); + return R.OK(list); + } + + public boolean save(SysConfig entity) { + if (null == entity) { + return false; + } + boolean save = super.save(entity); + cache.putCache(entity); + return save; + } + + /** + * 更新ID + * + * @param entity 实体对象 . + * @return . + */ + public boolean updateById(SysConfig entity) { + if (null == entity) { + return false; + } + if (null == entity.getId()) { + return false; + } + boolean update = super.updateById(entity); + cache.putCache(entity); + return update; + } + + /** + * 删除 + * + * @param ids . + * @return . + */ + public boolean removeByIds(List ids) { + if (null == ids || ids.isEmpty()) { + return false; + } + List configs = listByIds(ids); + if (CollectionUtil.isNotEmpty(configs)) { + configs.stream().map(SysConfig::getCode).forEach(cache::delCache); + } + return super.removeByIds(ids); + } + + public R refreshCache(@Nonnull String id){ + SysConfig config = getById(id); + if (null == config) { + return R.NG("配置不存在"); + } + cache.putCache(config); + return R.OK("刷新成功"); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysOrgService.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysOrgService.java new file mode 100644 index 0000000..ccd0c09 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysOrgService.java @@ -0,0 +1,153 @@ +package com.hb0730.boot.admin.modules.sys.system.service; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.core.service.BaseServiceImpl; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.system.mapper.SysOrgMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysOrganization; +import com.hb0730.boot.admin.modules.sys.system.model.query.OrganizationQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.OrganizationTree; +import com.hb0730.boot.admin.modules.sys.system.model.vo.OrganizationVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 机构 Service + * + * @author hb0730 + * @date 2023/6/3 + */ +@Service +@Slf4j +public class SysOrgService extends BaseServiceImpl { + + /** + * 获取机构分页 + * + * @param query . + * @return . + */ + public BasePage queryPage(OrganizationQuery query) { + Page page = new Page<>(query.getCurrent(), query.getSize()); + List records = this.baseMapper.queryPage(page, query); + return new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), records); + } + + /** + * 获取机构列表 + * + * @param query . + * @return . + */ + public List queryList(OrganizationQuery query) { + return this.baseMapper.queryPage(null, query); + } + + /** + * 构建机构树 + * + * @param query . + * @return . + */ + public List queryTree(OrganizationQuery query) { + List listData = this.queryList(query); + return buildTree(listData); + } + + /** + * 保存机构 + * + * @param vo . + * @return . + */ + public R save(OrganizationVO vo) { + String parentId = vo.getParentId(); + SysOrganization parentOrg = this.getById(parentId); + if (null == parentOrg) { + return R.NG("父机构不存在"); + } + // set Id + vo.setId(IdUtil.fastSimpleUUID()); + // set Id + vo.setCode(IdUtil.getSnowflakeNextIdStr()); + // 机构path = 上级网点path+本级ID + vo.setPath(parentOrg.getPath() + "," + vo.getId()); + // save + SysOrganization entity = BeanUtil.toBean(vo, SysOrganization.class); + save(entity); + return R.OK(vo); + } + + /** + * 更新机构 + * + * @param id . + * @param vo . + * @return . + */ + public R updateById(String id, OrganizationVO vo) { + SysOrganization organization = getById(id); + BeanUtil.copyProperties(vo, organization, "id", "code", "path", "isSystem"); + updateById(organization); + return R.OK(vo); + } + + /** + * 批量删除 + * + * @param ids . + * @return . + */ + @Transactional(rollbackFor = Exception.class) + public R batchDel(List ids) { + if (CollectionUtil.isEmpty(ids)) { + return R.NG("参数为空"); + } + List organizations = this.listByIds(ids); + if (CollectionUtil.isEmpty(organizations)) { + return R.NG("机构不存在"); + } + if (organizations.stream().anyMatch(e -> e.getIsSystem() == 1)) { + return R.NG("系统机构不允许删除"); + } + this.removeByIds(ids); + return R.OK(); + } + + public List buildTree(List listData) { + List treeList = BeanUtil.copyToList(listData, OrganizationTree.class); + List treeDataList = new ArrayList<>(); + Set ids = new HashSet<>(); + for (OrganizationTree treeData : treeList) { + if (StrUtil.isBlank(treeData.getParentId())) { + treeDataList.add(treeData); + } + for (OrganizationTree tree : treeList) { + if (treeData.getId().equals(tree.getParentId())) { + if (treeData.getChildren() == null) { + treeData.setChildren(new ArrayList<>()); + } + treeData.getChildren().add(tree); + + ids.add(tree.getId()); + } + } + } + if (treeDataList.size() == 0) { + treeDataList = treeList.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList()); + } + return treeDataList; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysPermissionService.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysPermissionService.java new file mode 100644 index 0000000..6388430 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysPermissionService.java @@ -0,0 +1,301 @@ +package com.hb0730.boot.admin.modules.sys.system.service; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hb0730.boot.admin.core.service.BaseServiceImpl; +import com.hb0730.boot.admin.data.enums.MenuTypeEnums; +import com.hb0730.boot.admin.modules.sys.system.mapper.SysPermissionMapper; +import com.hb0730.boot.admin.modules.sys.system.model.dto.PermissionTree; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysPermission; +import com.hb0730.boot.admin.modules.sys.system.model.query.PermissionTreeQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.PermissionVO; +import com.hb0730.boot.admin.modules.sys.system.model.vo.VueMenuRouteMeta; +import com.hb0730.boot.admin.modules.sys.system.model.vo.VueMenuRouteVO; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysPermissionService extends BaseServiceImpl { + @Resource + @Lazy + private SysUserService sysUserService; + private final ApplicationContext applicationContext; + + /** + * 获取权限ID集合 BY 角色ID结合 + * + * @param roleIds 角色ID集合 + * @return 权限ID集合 + */ + @Nonnull + public Set listPermissionIdsByRoleIds(@Nonnull List roleIds) { + List permissions = this.baseMapper.listByRoleIds(roleIds, true); + if (null == permissions) { + return Collections.emptySet(); + } + return permissions.stream().map(SysPermission::getId).collect(Collectors.toSet()); + } + + /** + * 根据ID查询已启用的权限code + * + * @param permissionIds ID + * @return 已启用的权限code + */ + @Nonnull + public Set listPermissionPreByIds(@Nonnull List permissionIds) { + List permissions = this.baseMapper.listPermission(permissionIds, true); + if (permissions == null) { + return Collections.emptySet(); + } + return permissions.stream().map(SysPermission::getPerms).collect(Collectors.toSet()); + } + + /** + * 获取全部的权限信息 + * + * @return . + */ + @Nonnull + public Set allPermissionPre() { + List permissions = this.baseMapper.listPermission(null, true); + if (null == permissions) { + return Collections.emptySet(); + } + return permissions.stream().map(SysPermission::getPerms).collect(Collectors.toSet()); + } + + /** + * 获取全部的ID + * + * @return . + */ + @Nonnull + public Set allPermissionIds() { + List permissions = this.baseMapper.list(true); + if (null == permissions) { + return Collections.emptySet(); + } + return permissions.stream().map(SysPermission::getId).collect(Collectors.toSet()); + } + + /** + * 根据用户获取菜单路由 + * + * @param userid 用户ID + * @return 菜单路由 + */ + public List queryRouteByUserid(String userid) { + Set roleIds = sysUserService.queryRoleIdsByUserId(userid); + Set permissionsIds = listPermissionIdsByRoleIds(List.copyOf(roleIds)); + return queryRouteByIds(List.copyOf(permissionsIds)); + } + + /** + * 根据ID查询已启用的路由信息 + * + * @param ids ID + * @return 路由信息 + */ + @Nonnull + public List queryRouteByIds(@Nonnull List ids) { + List sysPermissions = this.baseMapper.listMenuByIds(ids, true); + if (null == sysPermissions) { + return Collections.emptyList(); + } + List trees = buildTree(sysPermissions); + return buildRoute(trees); + } + + /** + * 将菜单路由权限集合构建为树形 + * + * @param permissions 菜单路由权限 + * @return . + */ + public List buildTree(@Nonnull List permissions) { + List permissionTrees = BeanUtil.copyToList(permissions, PermissionTree.class); + List trees = new ArrayList<>(); + Set ids = new HashSet<>(); + for (PermissionTree permissionTree : permissionTrees) { + if (StrUtil.isBlank(permissionTree.getParentId())) { + trees.add(permissionTree); + } + for (PermissionTree tree : permissionTrees) { + if (permissionTree.getId().equals(tree.getParentId())) { + if (permissionTree.getChildren() == null) { + permissionTree.setChildren(new ArrayList<>()); + } + permissionTree.getChildren().add(tree); + + ids.add(tree.getId()); + } + } + } + if (trees.size() == 0) { + trees = permissionTrees.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList()); + } + return trees; + } + + /** + * 构建菜单路由 + * + * @param permissionTrees 菜单路由权限树集合 + * @return 菜单路由 + */ + public List buildRoute(@Nonnull List permissionTrees) { + List menuRouteList = new ArrayList<>(); + for (PermissionTree permissionTree : permissionTrees) { + menuRouteList.add(buildRoute(permissionTree)); + } + return menuRouteList; + } + + + /** + * 构建菜单路由 + * + * @param permissionTree 菜单路由权限树 + * @return 菜单路由 + */ + private VueMenuRouteVO buildRoute(PermissionTree permissionTree) { + VueMenuRouteVO menuRoute = new VueMenuRouteVO(); + Integer menuType = permissionTree.getMenuType(); + // 路由地址 必须有个 `/` + menuRoute.setPath(StrUtil.addPrefixIfNot(permissionTree.getPath(), "/")); + // 路由名字(必须保持唯一) + menuRoute.setName(permissionTree.getName()); + // 元信息 + VueMenuRouteMeta routeMeta = new VueMenuRouteMeta(); + // 菜单名称 + routeMeta.setTitle(permissionTree.getTitle()); + // 菜单图标 + routeMeta.setIcon(permissionTree.getIcon()); + // 是否显示 + routeMeta.setShowLink(permissionTree.getShowLink() == 1); + // 目录 + if (MenuTypeEnums.dir.getValue().equals(menuType)) { + // 菜单排序,值越高排的越后(只针对顶级路由) + // TODO 其实这里已经时有序取出了,所以可以不需要给RouteMeta设置rank + routeMeta.setRank(permissionTree.getRank()); + } + //菜单 + else if (MenuTypeEnums.menu.getValue().equals(menuType)) { + // 按需加载需要展示的页面 不需要 '/' + menuRoute.setComponent(StrUtil.removePrefix(permissionTree.getComponent(), "/")); + // 是否显示父级菜单 + routeMeta.setShowParent(permissionTree.getShowParent() == 1); + // 是否缓存该路由页面 + routeMeta.setKeepAlive(permissionTree.getKeepAlive() == 1); + // 需要内嵌的iframe链接地址 + if (permissionTree.getIsFrame() == 1) { + routeMeta.setFrameSrc(permissionTree.getPath()); + } + } + menuRoute.setMeta(routeMeta); + + if (CollectionUtil.isNotEmpty(permissionTree.getChildren())) { + menuRoute.setChildren(buildRoute(permissionTree.getChildren())); + } + return menuRoute; + } + /*==============================================================================*/ + + + /** + * 查询菜单与权限列表 + * + * @param query . + * @return . + */ + public Optional> listPermission(PermissionTreeQuery query) { + LambdaQueryWrapper queryWrapper = buildQuery(query); + return Optional.ofNullable(this.list(queryWrapper)); + } + + /** + * 只查询菜单列表 + * + * @param query . + * @return . + */ + public Optional> listMenu(PermissionTreeQuery query) { + LambdaQueryWrapper queryWrapper = buildQuery(query); + queryWrapper.ne(SysPermission::getMenuType, MenuTypeEnums.permission.getValue()); + return Optional.ofNullable(this.list(queryWrapper)); + } + + /** + * 保存 + * + * @param vo . + * @return . + */ + @Transactional(rollbackFor = Exception.class) + public Optional save(PermissionVO vo) { + SysPermission permission = BeanUtil.toBean(vo, SysPermission.class); + log.info("【菜单与权限】新增菜单与权限,参数: {}", permission); + this.save(permission); + PermissionTree bean = BeanUtil.toBean(permission, PermissionTree.class); + return Optional.of(bean); + } + + /** + * 根据ID更新 + * + * @param vo . + * @param id . + * @return , + */ + @Transactional(rollbackFor = Exception.class) + public Optional updateById(PermissionVO vo, @Nonnull String id) { + SysPermission permission = BeanUtil.toBean(vo, SysPermission.class); + permission.setId(id); + log.info("【菜单与权限】根据ID更新菜单与权限,参数: id--->{} data:---> {}", id, permission); + this.updateById(permission); + PermissionTree bean = BeanUtil.toBean(permission, PermissionTree.class); + return Optional.of(bean); + } + + + private LambdaQueryWrapper buildQuery(@Nullable PermissionTreeQuery query) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysPermission.class); + queryWrapper.orderByAsc(SysPermission::getRank); + if (null == query) { + return queryWrapper; + } + if (StrUtil.isNotBlank(query.getTitle())) { + queryWrapper.like(SysPermission::getTitle, query.getTitle()); + } + if (null != query.getEnabled()) { + queryWrapper.eq(SysPermission::getEnabled, query.getEnabled()); + } + return queryWrapper; + } + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysRolePermissionService.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysRolePermissionService.java new file mode 100644 index 0000000..6c4cf81 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysRolePermissionService.java @@ -0,0 +1,97 @@ +package com.hb0730.boot.admin.modules.sys.system.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hb0730.boot.admin.core.service.BaseServiceImpl; +import com.hb0730.boot.admin.modules.sys.system.event.RefreshOnlineUserRouteEvent; +import com.hb0730.boot.admin.modules.sys.system.mapper.SysRolePermissionMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysRolePermission; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author hb0730 + * @date 2023/3/2 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysRolePermissionService extends BaseServiceImpl { + private final ApplicationContext applicationContext; + + /** + * 获取角色对应的权限 + * + * @param id 角色ID + * @return 权限ID + */ + public Optional> findPermissionIdByRole(String id) { +// LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysRolePermission.class) +// .eq(SysRolePermission::getRoleId, id); +// return Optional.of(this.baseMapper.selectList(queryWrapper).stream().map(SysRolePermission::getPermissionId).collect(Collectors.toList())); + return Optional.ofNullable(this.baseMapper.getPermissionIdByRoleId(id)); + } + + /** + * 更新角色权 + * + * @param id id + * @param permissionIds 权限集合,如果权限为空,则该角色没有权限,只有最后一级 + * @return . + */ + @Transactional(rollbackFor = Exception.class) + public boolean updatePermissionByRoles(@Nonnull String id, @Nullable List permissionIds) { + if (CollectionUtil.isEmpty(permissionIds)) { + // 删除所有权限 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysRolePermission.class) + .eq(SysRolePermission::getRoleId, id); + return this.baseMapper.delete(queryWrapper) > 0; + } + // 根据最后一级查找所有的父级 + List permissionIdList = permissionIds.stream().map(SysRolePermission::getPermissionId).toList(); + Set parentContainer = CollectionUtil.newHashSet(); + parentContainer = getParentId(permissionIdList, parentContainer); + parentContainer.addAll(permissionIdList); + parentContainer= parentContainer.stream().filter(ObjectUtil::isNotEmpty).collect(Collectors.toSet()); + // 删除所有权限 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysRolePermission.class) + .eq(SysRolePermission::getRoleId, id); + this.baseMapper.delete(queryWrapper); + // 保存权限 + List rolePermissions = parentContainer.stream().map(permissionId -> { + SysRolePermission rolePermission = new SysRolePermission(); + rolePermission.setRoleId(id); + rolePermission.setPermissionId(permissionId); + rolePermission.setCreated(LocalDateTime.now()); + rolePermission.setCreatedBy(permissionIds.get(0).getCreatedBy()); + return rolePermission; + }).toList(); + boolean success = this.saveBatch(rolePermissions); + // 刷新在线用户权限 + applicationContext.publishEvent(new RefreshOnlineUserRouteEvent(this)); + return success; + } + + private Set getParentId(List permissionIdList, Set container) { + List parentIds = this.baseMapper.getParentIdByPermissionIds(permissionIdList); + if (CollectionUtil.isNotEmpty(parentIds)) { + container.addAll(parentIds); + return getParentId(parentIds, container); + } + return container; + } + +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysRoleService.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysRoleService.java new file mode 100644 index 0000000..e7523cd --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysRoleService.java @@ -0,0 +1,146 @@ +package com.hb0730.boot.admin.modules.sys.system.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.core.service.BaseServiceImpl; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.system.mapper.SysRoleMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysRole; +import com.hb0730.boot.admin.modules.sys.system.model.query.RoleQuery; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 角色信息 + * + * @author hb0730 + * @date 2023/2/28 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysRoleService extends BaseServiceImpl { + /** + * 分页查询 + * + * @param query . + * @return . + */ + public BasePage queryPage(RoleQuery query) { + LambdaQueryWrapper queryWrapper = buildQuery(query); + IPage page = new Page<>(query.getCurrent(), query.getSize()); + page = this.page(page, queryWrapper); + return new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), page.getRecords()); + } + + /** + * 列表查询 + * + * @param query . + * @return . + */ + public List queryList(RoleQuery query) { + LambdaQueryWrapper queryWrapper = buildQuery(query); + return this.list(queryWrapper); + } + + /** + * 检查code是否重复 + * + * @param code . + * @param id 需要排查的ID,可以为空 + * @return . + */ + public boolean checkCode(@Nonnull String code, @Nullable String id) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysRole.class) + .eq(SysRole::getRoleCode, code); + if (StrUtil.isNotBlank(id)) { + queryWrapper.ne(SysRole::getId, id); + } + return count(queryWrapper) > 0; + } + + /** + * 保存 + * + * @param sysRole . + * @return . + */ + @Transactional(rollbackFor = Exception.class) + public R saveRole(SysRole sysRole) { + if (StrUtil.isBlank(sysRole.getRoleName()) || StrUtil.isBlank(sysRole.getRoleCode())) { + return R.NG("参数错误,请检查参数"); + } + boolean checkCode = checkCode(sysRole.getRoleCode(), null); + if (checkCode) { + return R.NG("角色编码: " + sysRole.getRoleCode() + "重复"); + } + save(sysRole); + return R.OK(sysRole); + } + + /** + * 更新角色 + * + * @param sysRole . + * @return . + */ + public R updateRole(SysRole sysRole) { + if (StrUtil.isBlank(sysRole.getRoleName()) || StrUtil.isBlank(sysRole.getRoleCode())) { + return R.NG("参数错误,请检查参数"); + } + boolean checkCode = checkCode(sysRole.getRoleCode(), sysRole.getId()); + if (checkCode) { + return R.NG("角色编码: " + sysRole.getRoleCode() + "重复"); + } + updateById(sysRole); + return R.OK(sysRole); + } + + /** + * 根据ID删除角色 + * + * @param ids . + * @return . + */ + @Transactional(rollbackFor = Exception.class) + public R deleteByIds(@Nonnull List ids) { + if (CollectionUtil.isEmpty(ids)) { + return R.NG("删除失败"); + } + boolean remove = removeByIds(ids); + if (remove) { + return R.OK("删除成功"); + } + return R.NG("删除失败"); + + } + + private LambdaQueryWrapper buildQuery(RoleQuery query) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysRole.class); + if (null == query) { + return queryWrapper; + } + if (StrUtil.isNotBlank(query.getRoleCode())) { + queryWrapper.eq(SysRole::getRoleCode, query.getRoleCode()); + } + if (StrUtil.isNotBlank(query.getRoleName())) { + queryWrapper.like(SysRole::getRoleName, query.getRoleName()); + } + if (null != query.getEnabled()) { + queryWrapper.eq(SysRole::getEnabled, query.getEnabled()); + } + return queryWrapper; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysUserService.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysUserService.java new file mode 100644 index 0000000..b894326 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/service/SysUserService.java @@ -0,0 +1,283 @@ +package com.hb0730.boot.admin.modules.sys.system.service; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.base.util.AesEncryptUtil; +import com.hb0730.boot.admin.base.util.PasswordUtil; +import com.hb0730.boot.admin.core.service.BaseServiceImpl; +import com.hb0730.boot.admin.data.domain.BasePage; +import com.hb0730.boot.admin.modules.sys.system.mapper.SysUserMapper; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUser; +import com.hb0730.boot.admin.modules.sys.system.model.query.UserQuery; +import com.hb0730.boot.admin.modules.sys.system.model.vo.UserVO; +import jakarta.annotation.Nonnull; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * 用户服务 + * + * @author hb0730 + * @date 2023/2/4 + */ +@Slf4j +@Service +public class SysUserService extends BaseServiceImpl { + + /** + * 根据用户名获取用户信息 + * + * @param username 用户名 + * @return . + */ + public Optional loadUserByUsername(String username) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysUser.class) + .eq(SysUser::getUsername, username); + return Optional.ofNullable(getOne(queryWrapper)); + } + + /** + * 获取用户角色编码 + * + * @param username 用户名称 + * @return 角色编码 + */ + @Nonnull + public Set getRoleCodeByUsername(String username) { + Set res = this.baseMapper.getRoleCodeByUsername(username); + return res == null ? Collections.emptySet() : res; + } + + /** + * 获取全部的角色编码 + * + * @return . + */ + public Set allRoleCode() { + Set res = this.baseMapper.allRoleCode(); + return res == null ? Collections.emptySet() : res; + } + + + /** + * 根据用户ID 获取对应的角色ID集合 + * + * @param userId 角色ID + * @return 角色ID集合 + */ + public Set queryRoleIdsByUserId(String userId) { + Set res = baseMapper.queryUserRole(userId); + return res == null ? Collections.emptySet() : res; + } + /*===================================================*/ + + /** + * 分页查询 + * + * @param query . + * @return . + */ + public BasePage queryPage(UserQuery query) { + Page page = new Page<>(query.getCurrent(), query.getSize()); + List vos = this.baseMapper.queryPage(page, query); + return new BasePage<>(page.getCurrent(), page.getSize(), page.getTotal(), vos); + } + + /** + * 列表查询 + * + * @param query . + * @return . + */ + public List queryList(UserQuery query) { + return this.baseMapper.queryPage(null, query); + } + + /** + * 帐号是否存在 + * + * @param username . + * @return . + */ + public R hashUsername(String username) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysUser.class) + .eq(SysUser::getUsername, username); + return R.OK(this.count(queryWrapper) > 0); + } + + /** + * 根据ID获取详情 + * + * @param id . + * @return . + */ + public R detail(String id) { + SysUser user = getById(id); + UserVO res = BeanUtil.toBean(user, UserVO.class); + res.setPassword(null); + return R.OK(res); + } + + /** + * 根据用户名获取详情 + * + * @param username . + * @return . + */ + public R detailByUsername(String username) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(SysUser.class) + .eq(SysUser::getUsername, username); + SysUser user = getOne(queryWrapper); + UserVO res = BeanUtil.toBean(user, UserVO.class); + res.setPassword(null); + return R.OK(res); + } + + /** + * 根据用户ID获取角色ID集合 + * + * @param id . + * @return . + */ + public R> getRoleIdsByUserId(String id) { + Set roleIds = this.queryRoleIdsByUserId(id); + return R.OK(new ArrayList<>(roleIds)); + } + + @Transactional(rollbackFor = Exception.class) + public R save(UserVO vo) { + String username = vo.getUsername(); + if (this.hashUsername(username).getResult()) { + return R.NG("帐号已存在"); + } + String password = vo.getPassword(); + if (StrUtil.isBlank(password)) { + return R.NG("密码不能为空"); + } + String orgId = vo.getOrgId(); + if (StrUtil.isBlank(orgId)) { + return R.NG("组织不能为空"); + } + String newPassword = PasswordUtil.encoder(vo.getPassword()); + SysUser user = BeanUtil.toBean(vo, SysUser.class); + user.setPassword(newPassword); + if (StrUtil.isNotBlank(vo.getPhone())) { + user.setPhone(AesEncryptUtil.encrypt(vo.getPhone())); + } + save(user); + List roleIds = vo.getRoleIds(); + if (CollectionUtil.isNotEmpty(roleIds)) { + baseMapper.saveUserRole(user.getId(), new HashSet<>(roleIds)); + } + return R.OK(vo); + } + + /** + * 更新用户 + * + * @param id . + * @param vo . + * @return . + */ + public R updateById(String id, UserVO vo) { + SysUser user = getById(id); + if (null == user) { + return R.NG("用户不存在"); + } + BeanUtil.copyProperties(vo, user); + if (StrUtil.isNotBlank(vo.getPhone())) { + user.setPhone(AesEncryptUtil.encrypt(vo.getPhone())); + } + updateById(user); + List roleIds = vo.getRoleIds(); + baseMapper.delUserRoleByUserid(user.getId()); + if (CollectionUtil.isNotEmpty(roleIds)) { + baseMapper.saveUserRole(user.getId(), new HashSet<>(roleIds)); + } + return R.OK(vo); + } + + @Transactional(rollbackFor = Exception.class) + public R deleteByIds(List ids) { + if (CollectionUtil.isEmpty(ids)) { + return R.NG("参数不能为空"); + } + removeByIds(ids); + baseMapper.delUserRoleByUserids(ids); + return R.OK(); + } + + /** + * 重置密码 + * + * @param username . + * @param passwd . + * @return . + */ + public R resetPassword(@Nonnull String username, @Nonnull String passwd) { + String newPassword = PasswordUtil.encoder(passwd); + this.baseMapper.resetPassword(username, newPassword); + return R.OK(); + } + + /** + * 修改密码 + * + * @param username . + * @param oldPasswd . + * @param newPasswd . + * @return . + */ + public R changePasswd(@Nonnull String username, @Nonnull String oldPasswd, @Nonnull String newPasswd) { + SysUser user = baseMapper.getByUsername(username); + if (null == user) { + return R.NG("用户不存在"); + } + if (!PasswordUtil.matches(oldPasswd, user.getPassword())) { + return R.NG("原密码错误"); + } + String newPassword = PasswordUtil.encoder(newPasswd); + this.baseMapper.resetPassword(username, newPassword); + return R.OK(); + } + + public SysUser getUserByOpenId(String openId) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(SysUser::getOpenId, openId); + SysUser sysUser = this.baseMapper.selectOne(lambdaQueryWrapper); + + return sysUser; + } + + public R updatePassword(String id, String newPassword) { + + SysUser sysUser = this.baseMapper.selectById(id); + + if (null == sysUser) { + return R.NG("用户不存在"); + } + sysUser.setPassword(PasswordUtil.encoder(newPassword)); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", id).set("password", sysUser.getPassword()); + this.baseMapper.update(sysUser, updateWrapper); + return R.OK(); + } + + public SysUser getByOpenId(String opeId) { + return this.baseMapper.selectOne(new LambdaQueryWrapper().eq(SysUser::getOpenId, opeId)); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/modules/sys/system/vo/SelectOptionVO.java b/src/main/java/com/hb0730/boot/admin/modules/sys/system/vo/SelectOptionVO.java new file mode 100644 index 0000000..9d496dd --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/modules/sys/system/vo/SelectOptionVO.java @@ -0,0 +1,36 @@ +package com.hb0730.boot.admin.modules.sys.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.io.Serializable; + +/** + * 枚举 + * + * @author hb0730 + * @date 2023/1/11 + */ +@Data +@EqualsAndHashCode +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SelectOptionVO implements Serializable { + /** + * 名称 + */ + @Schema(description = "名称") + private String name; + /** + * 值 + */ + @Schema(description = "值") + private String value; +} diff --git a/src/main/java/com/hb0730/boot/admin/security/config/LoginProperties.java b/src/main/java/com/hb0730/boot/admin/security/config/LoginProperties.java new file mode 100644 index 0000000..9f85930 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/config/LoginProperties.java @@ -0,0 +1,19 @@ +package com.hb0730.boot.admin.security.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author hb0730 + * @date 2023/2/5 + */ +@ConfigurationProperties(prefix = "security.login") +@Configuration +@Data +public class LoginProperties { + /** + * 登录私钥 + */ + private String rsaPrivateKey; +} diff --git a/src/main/java/com/hb0730/boot/admin/security/config/SecurityProperties.java b/src/main/java/com/hb0730/boot/admin/security/config/SecurityProperties.java new file mode 100644 index 0000000..daeaeab --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/config/SecurityProperties.java @@ -0,0 +1,38 @@ +package com.hb0730.boot.admin.security.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * Jwt参数配置 + * + * @author hb0730 + * @date 2023/2/3 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "security.jwt") +public class SecurityProperties { + /** + * jwt加密密钥 + */ + private String jwtSecret = "ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI="; + + /** + * 令牌有效期 此处单位/s, + * 默认:2小时 + */ + private Integer tokenValidity = 2 * 60 * 60; + /** + * 自动延长token + * 默认:true + */ + private boolean delayToken = true; + + /** + * token 续期检查,单位秒 + * 默认: 30分钟 + */ + private Integer tokenDetect = 60 * 30; +} diff --git a/src/main/java/com/hb0730/boot/admin/security/config/WebSecurityConfiguration.java b/src/main/java/com/hb0730/boot/admin/security/config/WebSecurityConfiguration.java new file mode 100644 index 0000000..05531f7 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/config/WebSecurityConfiguration.java @@ -0,0 +1,145 @@ +package com.hb0730.boot.admin.security.config; + +import com.hb0730.boot.admin.base.util.PasswordUtil; +import com.hb0730.boot.admin.security.filter.JwtTokenAuthenticationFilter; +import com.hb0730.boot.admin.security.handler.TokenAccessDeniedHandler; +import com.hb0730.boot.admin.security.handler.TokenAuthenticationEntryPoint; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.core.GrantedAuthorityDefaults; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.filter.CorsFilter; + +/** + * Spring Security 配置 + * + * @author hb0730 + * @date 2023/1/11 + */ +@Configuration +// web 支持 +@EnableWebSecurity +// 对注解 +// @PreAuthorize, @PostAuthorize, @PreFilte +@EnableMethodSecurity +@RequiredArgsConstructor +public class WebSecurityConfiguration { + private final UserDetailsService userDetailsService; + private final CorsFilter corsFilter; + private final JwtTokenAuthenticationFilter tokenAuthenticationFilter; + private final TokenAccessDeniedHandler tokenAccessDeniedHandler; + private final TokenAuthenticationEntryPoint authenticationEntryPoint; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + // csrf 禁用 + .csrf().disable() + // 异常处理 + .exceptionHandling() +// // 认证异常 + .authenticationEntryPoint(authenticationEntryPoint) +// // 授权异常 + .accessDeniedHandler(tokenAccessDeniedHandler) + .and() + .userDetailsService(userDetailsService) + // 防止iframe 造成跨域 + .headers() + .frameOptions() + .disable() + .and() + // session 禁用,采用token方式 + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .formLogin().disable() + .httpBasic().disable() + // 授权 + .authorizeHttpRequests() + // swagger 文档 + .requestMatchers("/swagger-ui.html").permitAll() + .requestMatchers("/swagger-resources/**").permitAll() + .requestMatchers("/webjars/**").permitAll() + .requestMatchers("/*/api-docs/**").permitAll() + // 静态资源等等 + .requestMatchers( + HttpMethod.GET, + "/*.html", + "/*/*.html", + "/*/*.css", + "/*/*.js", + "/webSocket/**" + ).permitAll() +// .requestMatchers("/**").permitAll() + //对于登录login 开放 + .requestMatchers("/auth/**", "/favicon.ico","/wx/**").permitAll() + // options 开放 + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .requestMatchers(HttpMethod.GET).permitAll() + .requestMatchers("/buiness/shop").permitAll() + .requestMatchers("/buiness/shop/**").permitAll() + .requestMatchers("/buiness/user").permitAll() + .requestMatchers("/buiness/box/**").permitAll() + .requestMatchers("/buiness/oss/**").permitAll() + // 文件 + .requestMatchers("/avatar/**").permitAll() + .requestMatchers("/file/**").permitAll() + // 其余认证访问 + .anyRequest() + .authenticated() + .and() + // filter + .addFilterBefore(corsFilter, CorsFilter.class) + .addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + return http.build(); + } +// @Bean +// public AuthenticationManager authenticationManager(ObjectPostProcessor builder) throws Exception { +// return new AuthenticationManagerBuilder(builder) +// .authenticationProvider(new CaptchaAuthenticationProvider(captchaUserDetailsService, captchaService)) +// .authenticationProvider(new OpenIdAuthenticationProvider(openIdDetailsService)) +// .build(); +// } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + +// @Bean +// public AuthenticationManager authenticationManager(AuthenticationManagerBuilder builder) throws Exception { +// return builder +// .userDetailsService(userDetailsService) +// .passwordEncoder(passwordEncoder()) +// .and() +// .build(); +// } + + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordUtil.defaultPasswordEncoder(); + } + + /** + * 移除{@code ROLE_}前缀, + * 方便使用{@link com.hb0730.boot.admin.security.expression.PermissionService#hashPermission(String)}或者Spring + * Security自己的方法 + * + * @return . + * @see org.springframework.security.config.annotation.method.configuration.PrePostMethodSecurityConfiguration + */ + @Bean + public GrantedAuthorityDefaults grantedAuthorityDefaults() { + return new GrantedAuthorityDefaults(""); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/expression/PermissionService.java b/src/main/java/com/hb0730/boot/admin/security/expression/PermissionService.java new file mode 100644 index 0000000..9d46742 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/expression/PermissionService.java @@ -0,0 +1,68 @@ +package com.hb0730.boot.admin.security.expression; + +import com.hb0730.boot.admin.security.model.Authority; +import com.hb0730.boot.admin.security.util.SecurityUtil; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.security.config.core.GrantedAuthorityDefaults; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +@Service("permission") +public class PermissionService { + private final GrantedAuthorityDefaults grantedAuthorityDefaults; + + public PermissionService(ObjectProvider provider) { + this.grantedAuthorityDefaults = provider.getIfAvailable(); + } + + /** + * 是否有对应的权限或者角色 + * + * @param anyPermission 权限或者角色 + * @return 是否授权 + */ + public boolean hashPermission(String anyPermission) { + Collection authorities = SecurityUtil.getCurrentPermission(); + List permission = authorities.stream().map(Authority::getAuthority).toList(); + String role = null; + if (null != this.grantedAuthorityDefaults) { + role = getRoleWithDefaultPrefix(this.grantedAuthorityDefaults.getRolePrefix(), anyPermission); + } + return permission.contains(role); + } + + /** + * 是否有对应的权限或者角色 + * + * @param anyPermission 权限或者角色 + * @return 是否授权 + */ + public boolean hashPermission(String... anyPermission) { + for (String permission : anyPermission) { + if (hashPermission(permission)) { + + return true; + } + } + return false; + } + + private static String getRoleWithDefaultPrefix(String defaultRolePrefix, String role) { + if (role == null) { + return role; + } + if (defaultRolePrefix == null || defaultRolePrefix.length() == 0) { + return role; + } + if (role.startsWith(defaultRolePrefix)) { + return role; + } + return defaultRolePrefix + role; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/filter/JwtTokenAuthenticationFilter.java b/src/main/java/com/hb0730/boot/admin/security/filter/JwtTokenAuthenticationFilter.java new file mode 100644 index 0000000..bbaceb0 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/filter/JwtTokenAuthenticationFilter.java @@ -0,0 +1,70 @@ +package com.hb0730.boot.admin.security.filter; + +import cn.hutool.core.util.StrUtil; +import com.hb0730.boot.admin.base.util.JwtUtil; +import com.hb0730.boot.admin.security.model.OnlineUser; +import com.hb0730.boot.admin.security.service.UserDetailServiceImpl; +import com.hb0730.boot.admin.security.token.JwtTokenRedisCacheProvider; +import com.hb0730.boot.admin.security.token.UserCacheProvider; +import jakarta.annotation.Resource; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.Optional; + +/** + * token认证过滤器 + * + * @author hb0730 + * @date 2023/1/30 + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class JwtTokenAuthenticationFilter extends OncePerRequestFilter { + private final JwtTokenRedisCacheProvider jwtTokenRedisCacheProvider; + private final UserDetailServiceImpl userDetailService; + @Lazy + @Resource + private UserCacheProvider userCacheProvider; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + String _jwtToken = JwtUtil.getTokenByRequest(request); + if (StrUtil.isNotBlank(_jwtToken)) { + Optional online = jwtTokenRedisCacheProvider.getOnlineFromToken(_jwtToken); + if (online.isPresent()) { + if (SecurityContextHolder.getContext().getAuthentication() == null) { + UserDetails userDetails = userDetailService.loadUserByUsername(JwtUtil.getUsername(_jwtToken)); + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken( + userDetails.getUsername(), + userDetails, + userDetails.getAuthorities() + ); + authenticationToken.setDetails( + new WebAuthenticationDetailsSource().buildDetails(request) + ); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + } + } else { + userCacheProvider.clearUser(JwtUtil.getUsername(_jwtToken)); + } + jwtTokenRedisCacheProvider.checkRenewal(_jwtToken); + } + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/handler/TokenAccessDeniedHandler.java b/src/main/java/com/hb0730/boot/admin/security/handler/TokenAccessDeniedHandler.java new file mode 100644 index 0000000..2c76c6c --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/handler/TokenAccessDeniedHandler.java @@ -0,0 +1,33 @@ +package com.hb0730.boot.admin.security.handler; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.JakartaServletUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.base.util.JsonUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +/** + * token 权限不足 + * + * @author hb0730 + * @date 2023/2/3 + */ +@Component +public class TokenAccessDeniedHandler implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { + //当用户在没有授权的情况下访问受保护的REST资源时,将调用此方法发送403 Forbidden响应 + int code = HttpStatus.FORBIDDEN.value(); + String msg = StrUtil.format("请求访问:{} ,没有访问权限!", request.getRequestURI()); + JakartaServletUtil.write(response, JsonUtil.DEFAULT.toJson(R.NG(code, msg)), MediaType.APPLICATION_JSON_UTF8_VALUE); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/handler/TokenAuthenticationEntryPoint.java b/src/main/java/com/hb0730/boot/admin/security/handler/TokenAuthenticationEntryPoint.java new file mode 100644 index 0000000..547f78e --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/handler/TokenAuthenticationEntryPoint.java @@ -0,0 +1,33 @@ +package com.hb0730.boot.admin.security.handler; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.JakartaServletUtil; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.base.util.JsonUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +/** + * token 授权异常 + * + * @author hb0730 + * @date 2023/2/3 + */ +@Component +public class TokenAuthenticationEntryPoint implements AuthenticationEntryPoint { + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { + // 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应 + int code = HttpStatus.UNAUTHORIZED.value(); + String msg = StrUtil.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); + JakartaServletUtil.write(response, JsonUtil.DEFAULT.toJson(R.NG(code, msg)), MediaType.APPLICATION_JSON_UTF8_VALUE); + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/model/Authority.java b/src/main/java/com/hb0730/boot/admin/security/model/Authority.java new file mode 100644 index 0000000..05e8dab --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/model/Authority.java @@ -0,0 +1,19 @@ +package com.hb0730.boot.admin.security.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; + +/** + * 避免序列化问题 + * + * @author hb0730 + * @date 2023/1/30 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Authority implements GrantedAuthority { + private String authority; +} diff --git a/src/main/java/com/hb0730/boot/admin/security/model/OnlineUser.java b/src/main/java/com/hb0730/boot/admin/security/model/OnlineUser.java new file mode 100644 index 0000000..b0207a6 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/model/OnlineUser.java @@ -0,0 +1,64 @@ +package com.hb0730.boot.admin.security.model; + +import jakarta.annotation.Nonnull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 在线用户 + * + * @author hb0730 + * @date 2023/2/3 + */ +@Data +@EqualsAndHashCode +@ToString +public class OnlineUser implements Serializable { + /** + * 用户名 + */ + private String username; + /** + * 昵称 + */ + private String nickName; + + /** + * 岗位 + */ + private String dept; + /** + * token + */ + private String key; + /** + * 浏览器 + */ + private String browser; + + /** + * IP + */ + private String ip; + + /** + * 地址 + */ + private String address; + + /** + * 登录时间 + */ + private LocalDateTime loginTime; + + + public static OnlineUser convert(@Nonnull UserInfo userInfo) { + OnlineUser onlineUser = new OnlineUser(); + onlineUser.setUsername(userInfo.getUsername()); + return onlineUser; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/model/UserInfo.java b/src/main/java/com/hb0730/boot/admin/security/model/UserInfo.java new file mode 100644 index 0000000..53345a1 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/model/UserInfo.java @@ -0,0 +1,116 @@ +package com.hb0730.boot.admin.security.model; + +import cn.hutool.core.collection.CollectionUtil; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUser; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * user_info + * + * @author hb0730 + * @date 2023/1/30 + */ +@Data +@EqualsAndHashCode +@ToString +public class UserInfo implements UserDetails { + /** + * 用户ID + */ + private String userid; + /** + * username + */ + private String username; + /** + * nickname + */ + private String nickname; + /** + * password + */ + private String password; + /** + * enabled + */ + private Integer isEnabled; + + /** + * 权限 + */ + private List permissions; + /** + * 角色 + */ + private List roles; + + /** + * 是否为管理员 + */ + private boolean isManger; + + @Override + public Collection getAuthorities() { + List authorities = new ArrayList<>(); + //角色+权限 + if (CollectionUtil.isNotEmpty(this.permissions)) { + authorities.addAll(this.permissions.stream().map(Authority::new).toList()); + } + if (CollectionUtil.isNotEmpty(this.roles)) { + authorities.addAll( + this.roles.stream().map(Authority::new).toList() + ); + } + return authorities; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return this.isEnabled == 1; + } + + public static UserInfo convert(SysUser user, List roleCodes, + List permissionCodes) { + UserInfo userInfo = new UserInfo(); + // 用户ID + userInfo.setUserid(user.getId()); + // 用户名 + userInfo.setUsername(user.getUsername()); + // nickname + userInfo.setNickname(user.getNickname()); + // 密码 + userInfo.setPassword(user.getPassword()); + // 角色 + userInfo.setRoles(roleCodes); + // 权限 + userInfo.setPermissions(permissionCodes); + // 是否启用 + userInfo.setIsEnabled(user.getIsEnabled()); + // 是否为管理员 + userInfo.setManger(user.isManager()); + + return userInfo; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/service/UserDetailServiceImpl.java b/src/main/java/com/hb0730/boot/admin/security/service/UserDetailServiceImpl.java new file mode 100644 index 0000000..db9243f --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/service/UserDetailServiceImpl.java @@ -0,0 +1,75 @@ +package com.hb0730.boot.admin.security.service; + +import cn.hutool.core.collection.CollectionUtil; +import com.hb0730.boot.admin.base.util.PasswordUtil; +import com.hb0730.boot.admin.modules.sys.system.model.entity.SysUser; +import com.hb0730.boot.admin.modules.sys.system.service.SysPermissionService; +import com.hb0730.boot.admin.modules.sys.system.service.SysUserService; +import com.hb0730.boot.admin.security.model.UserInfo; +import com.hb0730.boot.admin.security.token.RedisCacheUserProvider; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * @author hb0730 + * @date 2023/1/11 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class UserDetailServiceImpl implements UserDetailsService { + private final RedisCacheUserProvider redisCacheUserProvider; + private final SysUserService sysUserService; + private final SysPermissionService sysPermissionService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + log.info("获取授权用户信息: username: {}", username); + Optional optional = redisCacheUserProvider.getUser(username); + if (optional.isPresent()) { + UserInfo userInfo = optional.get(); + log.info("获取授权用户信息->缓存获取 : {}", userInfo); + return userInfo; + } + log.info("获取授权用户信息->重新从库获取"); + // 测试用例 +// UserInfo info = new UserInfo(); +// info.setPassword(PasswordUtil.encoder("123456")); +// info.setUsername("admin"); +// info.setRoles(Arrays.asList("ROLE_ADMIN")); +// info.setPermissions(Arrays.asList("test::query", "test:add")); +// info.setIsEnabled(1); + // 正式 + Optional userOptional = sysUserService.loadUserByUsername(username); + SysUser user = userOptional.orElseThrow(() -> new UsernameNotFoundException("根据用户名未找到用户信息")); + // 角色code + Set roleCodes; + // 权限code + Set preCodes = new HashSet<>(); + if (user.isManager()) { + roleCodes = sysUserService.allRoleCode(); + preCodes = sysPermissionService.allPermissionPre(); + } else { + // 查找角色 + roleCodes = sysUserService.getRoleCodeByUsername(username); + // 用户信息ID 获取 用户角色ID集合 + Set roleIds = sysUserService.queryRoleIdsByUserId(user.getId()); + if (CollectionUtil.isNotEmpty(roleIds)) { + Set permissionIds = sysPermissionService.listPermissionIdsByRoleIds(List.copyOf(roleIds)); + preCodes = sysPermissionService.listPermissionPreByIds(List.copyOf(permissionIds)); + } + } + UserInfo userInfo = UserInfo.convert( + user, + List.copyOf(roleCodes), + List.copyOf(preCodes)); + redisCacheUserProvider.cacheUser(username, userInfo); + return userInfo; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/test/TestController.java b/src/main/java/com/hb0730/boot/admin/security/test/TestController.java new file mode 100644 index 0000000..68edd64 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/test/TestController.java @@ -0,0 +1,27 @@ +package com.hb0730.boot.admin.security.test; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +@RestController +@RequestMapping("/test") +public class TestController { + + @GetMapping("/a1") + @PreAuthorize("hasAnyRole('ROLE_ADMIN')") + public String test1() { + return "角色认证成功"; + } + + @GetMapping("/a2") + @PreAuthorize("@permission.hashPermission('test:query')") + public String test2() { + return "自定义权限认证成功"; + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/token/JwtTokenRedisCacheProvider.java b/src/main/java/com/hb0730/boot/admin/security/token/JwtTokenRedisCacheProvider.java new file mode 100644 index 0000000..5899429 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/token/JwtTokenRedisCacheProvider.java @@ -0,0 +1,93 @@ +package com.hb0730.boot.admin.security.token; + +import com.hb0730.boot.admin.base.util.JsonUtil; +import com.hb0730.boot.admin.base.util.JwtUtil; +import com.hb0730.boot.admin.config.cache.BootAdminCache; +import com.hb0730.boot.admin.config.cache.CacheUtil; +import com.hb0730.boot.admin.config.cache.KeyValue; +import com.hb0730.boot.admin.security.config.SecurityProperties; +import com.hb0730.boot.admin.security.model.OnlineUser; +import com.hb0730.boot.admin.security.model.UserInfo; +import jakarta.servlet.http.HttpServletRequest; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +/** + * 创建 jwt,并且存储与redis + * + * @author hb0730 + * @date 2023/2/3 + */ +@Component +@RequiredArgsConstructor +public class JwtTokenRedisCacheProvider implements TokenProvider, CacheUtil { + private final SecurityProperties properties; + private final BootAdminCache cache; + + @Override + public String createToken(UserInfo userInfo) { + return createToken(userInfo, null); + } + + @Override + public String createToken(UserInfo userInfo, HttpServletRequest request) { + String _jwtToken = JwtUtil.sign(userInfo.getUsername(), properties.getJwtSecret()); + OnlineUser onlineUser = OnlineUser.convert(userInfo); + String json = JsonUtil.DEFAULT.toJson(onlineUser); + String key = getCacheKey(CacheKeyValue.online_user_cache, _jwtToken); + cache.set(key, json, properties.getTokenValidity()); + return _jwtToken; + } + + @Override + public Optional getOnlineFromToken(String token) { + String cacheKey = getCacheKey(CacheKeyValue.online_user_cache, token); + Optional optional = cache.getStr(cacheKey); + return optional.flatMap( + json -> Optional.ofNullable( + JsonUtil.DEFAULT.fromJson(json, OnlineUser.class) + ) + ); + } + + @Override + public boolean checkRenewal(String token) { + if (!properties.isDelayToken()) { + return false; + } + // 获取剩余时间 单位/秒 + String key = getCacheKey(CacheKeyValue.online_user_cache, token); + long expire = cache.getExpire(key); + // 是否小于30 + if (expire < properties.getTokenDetect() && expire != 0) { + // 重新设置过期时间 + cache.expire(key, properties.getTokenValidity()); + } + return true; + } + + @Override + public boolean removeToken(String token) { + String cacheKey = getCacheKey(CacheKeyValue.online_user_cache, token); + return cache.del(cacheKey); + } + + @Getter + public enum CacheKeyValue implements KeyValue { + online_user_cache( + "token", + "在线用户" + ), + ; + private final String prefix; + private final String name; + + CacheKeyValue(String prefix, String name) { + this.prefix = prefix; + this.name = name; + } + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/token/RedisCacheUserProvider.java b/src/main/java/com/hb0730/boot/admin/security/token/RedisCacheUserProvider.java new file mode 100644 index 0000000..36c4601 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/token/RedisCacheUserProvider.java @@ -0,0 +1,90 @@ +package com.hb0730.boot.admin.security.token; + +import cn.hutool.core.collection.CollectionUtil; +import com.hb0730.boot.admin.base.util.JsonUtil; +import com.hb0730.boot.admin.config.cache.BootAdminCache; +import com.hb0730.boot.admin.config.cache.CacheUtil; +import com.hb0730.boot.admin.config.cache.KeyValue; +import com.hb0730.boot.admin.security.config.SecurityProperties; +import com.hb0730.boot.admin.security.model.UserInfo; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class RedisCacheUserProvider implements UserCacheProvider, CacheUtil { + private final BootAdminCache cache; + private final SecurityProperties properties; + + @Override + public boolean cacheUser(String key, UserInfo userInfo) { + String json = JsonUtil.DEFAULT.toJson(userInfo); + String cacheKey = getCacheKey(CacheKeyValue.login_user_cache, key); + log.info("【缓存登录用户】 获取登录用户信息: key {} value {}", cacheKey, json); + return cache.set(cacheKey, json, properties.getTokenValidity()); + } + + @Override + public boolean clearUser(String key) { + String cacheKey = getCacheKey(CacheKeyValue.login_user_cache, key); + log.info("【缓存登录用户】清理登录用户信息: key {}", cacheKey); + return cache.del(cacheKey); + } + + @Override + public Optional getUser(String key) { + String cacheKey = getCacheKey(CacheKeyValue.login_user_cache, key); + log.info("【缓存登录用户】 获取登录用户信息: {}", cacheKey); + return cache.getStr(cacheKey).flatMap(json -> + Optional.ofNullable(JsonUtil.DEFAULT.fromJson(json, UserInfo.class)) + ); + } + + @Override + public Optional> getCacheUsers() { + // 获取所有的用户缓存KEYS + String cacheKey = getCacheKey(CacheKeyValue.login_user_cache, "*"); + Set keys = cache.getKeys(cacheKey); + if (CollectionUtil.isEmpty(keys)) { + log.info("【缓存登录用户】 未获取到登录用户信息"); + return Optional.empty(); + } + List userInfoList=new ArrayList<>(); + for (String key : keys) { + Optional cacheValue = cache.defaultGet(key); + if (cacheValue.isPresent()) { + UserInfo cacheUserInfo = JsonUtil.DEFAULT.fromJson(cacheValue.get(), UserInfo.class); + userInfoList.add(cacheUserInfo); + } + } + return Optional.of(userInfoList); + } + + @Getter + public enum CacheKeyValue implements KeyValue { + login_user_cache( + "login-user", + "登录用户" + ), + ; + private final String prefix; + private final String name; + + CacheKeyValue(String prefix, String name) { + this.prefix = prefix; + this.name = name; + } + } +} diff --git a/src/main/java/com/hb0730/boot/admin/security/token/TokenProvider.java b/src/main/java/com/hb0730/boot/admin/security/token/TokenProvider.java new file mode 100644 index 0000000..fc7df81 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/token/TokenProvider.java @@ -0,0 +1,56 @@ +package com.hb0730.boot.admin.security.token; + +import com.hb0730.boot.admin.security.model.OnlineUser; +import com.hb0730.boot.admin.security.model.UserInfo; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import jakarta.servlet.http.HttpServletRequest; + +import java.util.Optional; + +/** + * @author hb0730 + * @date 2023/2/3 + */ +public interface TokenProvider { + /** + * 创建token + * + * @param userInfo . + * @return token + */ + String createToken(@Nonnull UserInfo userInfo); + + /** + * 创建token + * + * @param userInfo . + * @param request . + * @return token + */ + String createToken(@Nonnull UserInfo userInfo, @Nullable HttpServletRequest request); + + /** + * 获取在线用户 + * + * @param token . + * @return . + */ + Optional getOnlineFromToken(@Nonnull String token); + + /** + * 是否延长token时间 + * + * @param token . + * @return . + */ + boolean checkRenewal(@Nonnull String token); + + /** + * 移除token + * + * @param token . + * @return . + */ + boolean removeToken(String token); +} diff --git a/src/main/java/com/hb0730/boot/admin/security/token/UserCacheProvider.java b/src/main/java/com/hb0730/boot/admin/security/token/UserCacheProvider.java new file mode 100644 index 0000000..22bfde1 --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/token/UserCacheProvider.java @@ -0,0 +1,46 @@ +package com.hb0730.boot.admin.security.token; + +import com.hb0730.boot.admin.security.model.UserInfo; + +import java.util.List; +import java.util.Optional; + +/** + * 登录用户缓存 + * + * @author hb0730 + * @date 2023/2/4 + */ +public interface UserCacheProvider { + /** + * 缓存登录用户 + * + * @param key key/username + * @param userInfo 登录用户信息 + * @return . + */ + boolean cacheUser(String key, UserInfo userInfo); + + /** + * 获取所有缓存的登录用户 + * + * @return . + */ + Optional> getCacheUsers(); + + /** + * 清理登录用户 + * + * @param key key/username + * @return . + */ + boolean clearUser(String key); + + /** + * 获取登录用户 + * + * @param key key/username + * @return . + */ + Optional getUser(String key); +} diff --git a/src/main/java/com/hb0730/boot/admin/security/util/SecurityUtil.java b/src/main/java/com/hb0730/boot/admin/security/util/SecurityUtil.java new file mode 100644 index 0000000..943a60d --- /dev/null +++ b/src/main/java/com/hb0730/boot/admin/security/util/SecurityUtil.java @@ -0,0 +1,45 @@ +package com.hb0730.boot.admin.security.util; + +import com.hb0730.boot.admin.security.model.Authority; +import com.hb0730.boot.admin.security.model.UserInfo; +import lombok.experimental.UtilityClass; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.Collection; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +@UtilityClass +public class SecurityUtil { + /** + * 获取当前用户 + * + * @return . + */ + public UserInfo getCurrentUser() { + SecurityContext context = SecurityContextHolder.getContext(); + return (UserInfo) context.getAuthentication() + .getCredentials(); + } + + /** + * 获取当前用户名 + * + * @return . + */ + public String getCurrentUsername() { + return (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } + + /** + * 获取当前权限, 权限是: 权限+角色 + * + * @return . + */ + public Collection getCurrentPermission() { + return getCurrentUser().getAuthorities(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..de5a3ba --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,142 @@ +application: + version: 5.0.0 +server: + port: 8088 +spring: + application: + name: boot-admin + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:mysql://localhost:3306/shop_h5?characterEncoding=UTF-8&useSSL=false&useUnicode=true&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=true + username: msgg + password: Msgg123! + +# driver-class-name: com.mysql.cj.jdbc.Driver +# type: com.zaxxer.hikari.HikariDataSource +# url: jdbc:mysql://localhost:3306/shop_h5?characterEncoding=UTF-8&useSSL=false&useUnicode=true&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=true +# username: root +# password: 12345678 + data: + redis: + host: localhost + port: 6379 + database: 4 + password: 123456 + quartz: + # 数据库存储 + job-store-type: jdbc + # Scheduler 名字。 + # scheduler-name: clusteredScheduler + # Quartz 是否自动启动 + auto-startup: true + # 延迟 N 秒启动 + startup-delay: 0 + # 应用关闭时,是否等待定时任务执行完成 + wait-for-jobs-to-complete-on-shutdown: true + # 启动时更新己存在的Job + overwrite-existing-jobs: true + # jdbc + jdbc: + # 初始化scheme + initialize-schema: never + # 添加 Quartz Scheduler 附加属性,更多可以看 http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 文档 + properties: + org: + quartz: + scheduler: + instanceName: MyScheduler + instanceId: AUTO + jobStore: + # org.springframework.scheduling.quartz.ScheduleFactoryBean L575 + class: org.springframework.scheduling.quartz.LocalDataSourceJobStore + driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate + tablePrefix: QRTZ_ + isClustered: true + misfireThreshold: 60000 + clusterCheckinInterval: 10000 + threadPool: + class: org.quartz.simpl.SimpleThreadPool + threadCount: 10 + threadPriority: 5 + threadsInheritContextClassLoaderOfInitializingThread: true + servlet: + multipart: + max-file-size: 1000MB + enabled: true + max-request-size: 100MB +# mybatis plus 设置 +mybatis-plus: + mapper-locations: + - classpath*:com/hb0730/boot/admin/**/xml/*.xml + global-config: + # 关闭MP3.0自带的banner + banner: false + configuration: + # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用 + #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + # 返回类型为Map,显示null对应的字段 + call-setters-on-nulls: true +logging: + level: + root: info + com.hb0730: debug +boot: + admin: + cache: + prefix: boot:admin:cache + refresh-routes: true + +springdoc: + swagger-ui: + path: /swagger-ui.html + tags-sorter: alpha + operations-sorter: alpha + api-docs: + path: /v3/api-docs + group-configs: + - group: 'system' + display-name: "系统管理" + paths-to-match: + - /sys/** + - group: "auth" + display-name: "权限管理" + paths-to-match: + - /auth/** + - group: "monitor" + display-name: "监控管理" + paths-to-match: + - /monitor/** + - group: "buiness" + display-name: "我的接口" + paths-to-match: + - /buiness/** + - group: "wx" + display-name: "微信接口" + paths-to-match: + - /wx/** + default-produces-media-type: application/json;charset=UTF-8 + default-consumes-media-type: application/json;charset=UTF-8 + +# 增强 swaager +knife4j: + enable: true + setting: + language: zh_cn + +security: + jwt: + # token有效时间 2小时 + token-validity: 7200 + # 自动延长token 默认:true + delay-token: true + # token 续期检查,单位秒 默认: 30分钟 + token-detect: 1800 + # jwt 密钥 + jwt-secret: "ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=" + login: + # 登录私钥 + rsa-private-key: "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMrQcDp20jeUyb5rLO3jg3R6UlA0/U6WdzSXn7T4Sz7Z/F5hxeYiJ+F7+WsXbhGF085O4xivW0eeSZkrEKiO/ssaXELfE106vS3J9izYQNKKMM92chalWWSb7nLNLjhHnERiZpZKTdjRmqDc1NeyO7UoY3dIX1vmetPClFKeZDZ9AgMBAAECgYA8MOQ91anJ6RR+uNwatdz7opnvR+qteiZiq2UwlkfunU8yy52qERT47Iw3Zjq6ZJdZsTvgxZo3hRieppNJEzc2k8tQNtSEGG/WqSVhz3E5QuFxE0nse7qpEG2vuJH6CoyXZ4T3dqL+AybUxxqXDcke+YEAZrVEPqPeUF1B1NgK2QJBAMxIXI/2nXA5teIBktt7jAoao6fsapsi+yrkvBNVKjTWZbb/dAUGp5Jh+2izkQAZZoDArZleIfUaL/F6oDvDYNcCQQD+KOfwcSGmm821hK+dYq7fjd3TYQF96toRNYPJLCALrvf3IcHnbWf486A+CuzSMbkZuVlCDfReubvY81cec3TLAkBF+ygSfWZz0qFXWjioDcvsjjGwThI7MSGgERnI+azqyuOvbBWfvybaw8wvkwxCX3E4/Ei8OH4jjCQOcna/4m+jAkB5oxAmBa7KMwTHW8JEe4cf3KCOWn3BSpWk6MyyidioXsuzzcckQDsjbU2Cg+4FRuDEi+1I7K7IavGZChTmsPDzAkAudsivcNXIiWJBVuBwywwnMxLytK856FW0yEf/ffIs4NKFXUubCuCer0sCCSVeYXdzCGv2nnPxce5oqfcerHK1" + # 登录公钥 + rsa-public-key: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK0HA6dtI3lMm+ayzt44N0elJQNP1Olnc0l5+0+Es+2fxeYcXmIifhe/lrF24RhdPOTuMYr1tHnkmZKxCojv7LGlxC3xNdOr0tyfYs2EDSijDPdnIWpVlkm+5yzS44R5xEYmaWSk3Y0Zqg3NTXsju1KGN3SF9b5nrTwpRSnmQ2fQIDAQAB" + diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000..2a53d44 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,11 @@ + + +${AnsiColor.BRIGHT_YELLOW} +.-. .-. .-. _ +: : .' `. : : :_; +: `-. .--. .--.`. .'_____ .--. .-' :,-.,-.,-..-.,-.,-. +' .; :' .; :' .; :: ::_____:' .; ; ' .; :: ,. ,. :: :: ,. : +`.__.'`.__.'`.__.':_; `.__,_;`.__.':_;:_;:_;:_;:_;:_; +${AnsiColor.BRIGHT_RED} +Application Version: ${application.version}${application.formatted-version} +Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version} \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..45a3812 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + + + ${LOG_HOME}/boot-admin-%d{yyyy-MM-dd}.%i.log + + 30 + 20MB + + + ${FILE_LOG_PATTERN} + + + + + + 0 + + 10000 + true + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/com/hb0730/boot/admin/base/util/AesEncryptUtilTest.java b/src/test/java/com/hb0730/boot/admin/base/util/AesEncryptUtilTest.java new file mode 100644 index 0000000..f70ff11 --- /dev/null +++ b/src/test/java/com/hb0730/boot/admin/base/util/AesEncryptUtilTest.java @@ -0,0 +1,18 @@ +package com.hb0730.boot.admin.base.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +class AesEncryptUtilTest { + + @Test + @DisplayName("测试aes加密与解密是否一致") + void testAesEncrypt() { + String content = "qwe123!@#"; + String data = AesEncryptUtil.encrypt(content); + String _data = AesEncryptUtil.desEncrypt(data); + Assertions.assertEquals(content, _data, "加密失败,加密前数据与解密结果不一致"); + } +} diff --git a/src/test/java/com/hb0730/boot/admin/base/util/PasswordUtilTest.java b/src/test/java/com/hb0730/boot/admin/base/util/PasswordUtilTest.java new file mode 100644 index 0000000..ed71f27 --- /dev/null +++ b/src/test/java/com/hb0730/boot/admin/base/util/PasswordUtilTest.java @@ -0,0 +1,16 @@ +package com.hb0730.boot.admin.base.util; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +@Slf4j +class PasswordUtilTest { + + @Test + void encoder() { + String password = PasswordUtil.encoder("123456"); + log.info(password); + } +} diff --git a/src/test/java/com/hb0730/boot/admin/base/util/RsaUtilTest.java b/src/test/java/com/hb0730/boot/admin/base/util/RsaUtilTest.java new file mode 100644 index 0000000..00ffdf8 --- /dev/null +++ b/src/test/java/com/hb0730/boot/admin/base/util/RsaUtilTest.java @@ -0,0 +1,42 @@ +package com.hb0730.boot.admin.base.util; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@Slf4j +class RsaUtilTest { + + @Test + @DisplayName("公钥加密私钥解密") + void encryptByPublicKey() { + RsaUtil.RsaKeyPair keyPair = RsaUtil.generateKey(); + String test = "测试测试"; + String encryptData = RsaUtil.encryptByPublicKey(test, keyPair.getPublicKeyBase64()); + log.info("【公钥加密】加密后内容: {}", encryptData); + String decryptData = RsaUtil.decryptByPrivateKey(encryptData, keyPair.getPrivateKeyBase64()); + log.info("【私钥解密】解密后的内容: {}", decryptData); + Assertions.assertEquals(test, decryptData, "解密后的内容与原内容不一致"); + } + + + @Test + @DisplayName("私钥加密公钥解密") + void encryptByPrivateKey() { + RsaUtil.RsaKeyPair keyPair = RsaUtil.generateKey(); + String test = "测试123101923爱上"; + String encryptData = RsaUtil.encryptByPrivateKey(test, keyPair.getPrivateKeyBase64()); + log.info("【私钥加密】加密后内容: {}", encryptData); + String decryptData = RsaUtil.decryptByPublicKey(encryptData, keyPair.getPublicKeyBase64()); + log.info("【公钥解密】解密后的内容: {}", decryptData); + Assertions.assertEquals(test, decryptData, "解密后的内容与原内容不一致"); + } + + @Test + void decryptByPrivateKey() { + String data= + "13a461ef6a0c3847c01824b5d8707f140c3f4214c96ac95783116839893e2bf50cb06ed3beb483066a8ecf8c94c4910b920c4df4db96981640c84175fc8369bfd57fe9ca2c31413f014cea4cec631b5875216cf7593e512723bc90fa2e3d84e6e1402ac50419c6e76bbf5d7aacffdbe0f3558032764e3bf6e4c07beb807a132a"; + RsaUtil.decryptByPrivateKey(data,"MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMrQcDp20jeUyb5rLO3jg3R6UlA0/U6WdzSXn7T4Sz7Z/F5hxeYiJ+F7+WsXbhGF085O4xivW0eeSZkrEKiO/ssaXELfE106vS3J9izYQNKKMM92chalWWSb7nLNLjhHnERiZpZKTdjRmqDc1NeyO7UoY3dIX1vmetPClFKeZDZ9AgMBAAECgYA8MOQ91anJ6RR+uNwatdz7opnvR+qteiZiq2UwlkfunU8yy52qERT47Iw3Zjq6ZJdZsTvgxZo3hRieppNJEzc2k8tQNtSEGG/WqSVhz3E5QuFxE0nse7qpEG2vuJH6CoyXZ4T3dqL+AybUxxqXDcke+YEAZrVEPqPeUF1B1NgK2QJBAMxIXI/2nXA5teIBktt7jAoao6fsapsi+yrkvBNVKjTWZbb/dAUGp5Jh+2izkQAZZoDArZleIfUaL/F6oDvDYNcCQQD+KOfwcSGmm821hK+dYq7fjd3TYQF96toRNYPJLCALrvf3IcHnbWf486A+CuzSMbkZuVlCDfReubvY81cec3TLAkBF+ygSfWZz0qFXWjioDcvsjjGwThI7MSGgERnI+azqyuOvbBWfvybaw8wvkwxCX3E4/Ei8OH4jjCQOcna/4m+jAkB5oxAmBa7KMwTHW8JEe4cf3KCOWn3BSpWk6MyyidioXsuzzcckQDsjbU2Cg+4FRuDEi+1I7K7IavGZChTmsPDzAkAudsivcNXIiWJBVuBwywwnMxLytK856FW0yEf/ffIs4NKFXUubCuCer0sCCSVeYXdzCGv2nnPxce5oqfcerHK1"); + } +} diff --git a/src/test/java/com/hb0730/boot/admin/security/Login.java b/src/test/java/com/hb0730/boot/admin/security/Login.java new file mode 100644 index 0000000..12f62cc --- /dev/null +++ b/src/test/java/com/hb0730/boot/admin/security/Login.java @@ -0,0 +1,44 @@ +package com.hb0730.boot.admin.security; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.hb0730.boot.admin.base.R; +import com.hb0730.boot.admin.base.util.AesEncryptUtil; +import com.hb0730.boot.admin.base.util.JsonUtil; +import com.hb0730.boot.admin.modules.sys.auth.model.LoginRequest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import java.util.Map; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +public class Login { + protected String login(MockMvc mockMvc) throws Exception { + LoginRequest loginBody = new LoginRequest(); + String password = AesEncryptUtil.encrypt("123456"); + loginBody.setUsername("admin"); + loginBody.setPassword(password); + MvcResult result = mockMvc.perform( + MockMvcRequestBuilders + .post("/auth/login") + .content(JsonUtil.DEFAULT.toJson(loginBody)) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .accept(MediaType.APPLICATION_JSON_UTF8) + + ).andReturn(); + String body = result.getResponse().getContentAsString(); + R> res = JsonUtil.DEFAULT.fromJson( + body, + new TypeReference>>() { + } + ); + if (res.isSuccess()) { + return res.getResult().get("token").toString(); + } + throw new RuntimeException(res.getMessage()); + } +} diff --git a/src/test/java/com/hb0730/boot/admin/security/LoginTest.java b/src/test/java/com/hb0730/boot/admin/security/LoginTest.java new file mode 100644 index 0000000..fe32dee --- /dev/null +++ b/src/test/java/com/hb0730/boot/admin/security/LoginTest.java @@ -0,0 +1,44 @@ +package com.hb0730.boot.admin.security; + +import com.hb0730.boot.admin.base.util.AesEncryptUtil; +import com.hb0730.boot.admin.base.util.JsonUtil; +import com.hb0730.boot.admin.modules.sys.auth.model.LoginRequest; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +/** + * @author hb0730 + * @date 2023/2/4 + */ +@SpringBootTest +@AutoConfigureMockMvc +@Slf4j +public class LoginTest { + @Test + @DisplayName("测试登录") + void login(@Autowired MockMvc mockMvc) throws Exception { + LoginRequest loginBody = new LoginRequest(); + String password = AesEncryptUtil.encrypt("123456"); + loginBody.setUsername("admin"); + loginBody.setPassword(password); + MvcResult result = mockMvc.perform( + MockMvcRequestBuilders + .post("/auth/login") + .content(JsonUtil.DEFAULT.toJson(loginBody)) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .accept(MediaType.APPLICATION_JSON_UTF8) + + ).andReturn(); + String body = result.getResponse().getContentAsString(); + log.info("login response: {}", body); + } + +} diff --git a/src/test/java/com/hb0730/boot/admin/security/test/TestControllerTest.java b/src/test/java/com/hb0730/boot/admin/security/test/TestControllerTest.java new file mode 100644 index 0000000..194a86a --- /dev/null +++ b/src/test/java/com/hb0730/boot/admin/security/test/TestControllerTest.java @@ -0,0 +1,42 @@ +package com.hb0730.boot.admin.security.test; + +import com.hb0730.boot.admin.base.BootAdminConst; +import com.hb0730.boot.admin.security.Login; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +@SpringBootTest +@AutoConfigureMockMvc +@Slf4j +class TestControllerTest extends Login { + + @Test + void test1(@Autowired MockMvc mockMvc) throws Exception { + String token = login(mockMvc); + MvcResult result = mockMvc.perform( + MockMvcRequestBuilders + .get("/test/a1") + .header(BootAdminConst.X_ACCESS_TOKEN, token) + ).andReturn(); + String body = result.getResponse().getContentAsString(); + log.info(body); + } + + @Test + void test2(@Autowired MockMvc mockMvc) throws Exception { + String token = login(mockMvc); + MvcResult result = mockMvc.perform( + MockMvcRequestBuilders + .get("/test/a2") + .header(BootAdminConst.X_ACCESS_TOKEN, token) + ).andReturn(); + String body = result.getResponse().getContentAsString(); + log.info(body); + } +}