Authored by meijiajie

init

Showing 47 changed files with 4813 additions and 0 deletions

Too many changes to show.

To preserve performance only 47 of 47+ files are displayed.

  1 +# http://editorconfig.org
  2 +root = true
  3 +
  4 +# 空格替代Tab缩进在各种编辑工具下效果一致
  5 +[*]
  6 +indent_style = space
  7 +indent_size = 4
  8 +charset = utf-8
  9 +end_of_line = lf
  10 +trim_trailing_whitespace = true
  11 +insert_final_newline = true
  12 +
  13 +[*.{json,yml,yaml}]
  14 +indent_size = 2
  15 +
  16 +[*.md]
  17 +insert_final_newline = false
  18 +trim_trailing_whitespace = false
  1 +######################################################################
  2 +# Build Tools
  3 +
  4 +.gradle
  5 +/build/
  6 +!gradle/wrapper/gradle-wrapper.jar
  7 +
  8 +target/
  9 +!.mvn/wrapper/maven-wrapper.jar
  10 +
  11 +######################################################################
  12 +# IDE
  13 +
  14 +### STS ###
  15 +.apt_generated
  16 +.classpath
  17 +.factorypath
  18 +.project
  19 +.settings
  20 +.springBeans
  21 +
  22 +### IntelliJ IDEA ###
  23 +.idea
  24 +*.iws
  25 +*.iml
  26 +*.ipr
  27 +
  28 +### JRebel ###
  29 +rebel.xml
  30 +
  31 +### NetBeans ###
  32 +nbproject/private/
  33 +build/*
  34 +nbbuild/
  35 +nbdist/
  36 +.nb-gradle/
  37 +
  38 +######################################################################
  39 +# Others
  40 +*.log
  41 +*.xml.versionsBackup
  42 +*.swp
  43 +
  44 +!*/build/*.java
  45 +!*/build/*.html
  46 +!*/build/*.xml
  1 +<component name="ProjectRunConfigurationManager">
  2 + <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
  3 + <deployment type="dockerfile">
  4 + <settings>
  5 + <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:4.8.2" />
  6 + <option name="buildOnly" value="true" />
  7 + <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
  8 + </settings>
  9 + </deployment>
  10 + <method v="2" />
  11 + </configuration>
  12 +</component>
  1 +<component name="ProjectRunConfigurationManager">
  2 + <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
  3 + <deployment type="dockerfile">
  4 + <settings>
  5 + <option name="imageTag" value="ruoyi/ruoyi-server:4.8.2" />
  6 + <option name="buildOnly" value="true" />
  7 + <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
  8 + </settings>
  9 + </deployment>
  10 + <method v="2" />
  11 + </configuration>
  12 +</component>
  1 +<component name="ProjectRunConfigurationManager">
  2 + <configuration default="false" name="ruoyi-xxl-job-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
  3 + <deployment type="dockerfile">
  4 + <settings>
  5 + <option name="imageTag" value="ruoyi/ruoyi-xxl-job-admin:4.8.2" />
  6 + <option name="buildOnly" value="true" />
  7 + <option name="sourceFilePath" value="ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile" />
  8 + </settings>
  9 + </deployment>
  10 + <method v="2" />
  11 + </configuration>
  12 +</component>
  1 +The MIT License (MIT)
  2 +
  3 +Copyright (c) 2019 RuoYi-Vue-Plus
  4 +
  5 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  6 +this software and associated documentation files (the "Software"), to deal in
  7 +the Software without restriction, including without limitation the rights to
  8 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9 +the Software, and to permit persons to whom the Software is furnished to do so,
  10 +subject to the following conditions:
  11 +
  12 +The above copyright notice and this permission notice shall be included in all
  13 +copies or substantial portions of the Software.
  14 +
  15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  1 +接口地址:https://sapi.007vin.com/
  2 +open_id:489c1079b6ab49d359eced61d7d83804
  3 +token:8e9b584b2e09db0fb6829fc237f88efd
  4 +
  5 +7874
  6 +7504
  7 +
  8 +询价单号:
  9 +XJD20250610004666382
  10 +定损单号:
  11 +61348110
  12 +车架号:
  13 +LFV2A1151L6029426
  14 +车牌号:
  15 +浙F7DV79
  16 +车型名称:
  17 +2020 一汽大众 宝来 三厢 1.5L 手动档 时尚型(FV7152NAMCG)
  18 +
  19 +
  20 +车型: 大众上汽大众 帕萨特 修改
  21 +vin码: LSVCF6C44LN0196051
  22 +
  23 +
  24 +询价单号:
  25 +XJD20250610004667219
  26 +定损单号:
  27 +61427326
  28 +车架号:
  29 +LFV2A21K0H4306789
  30 +车牌号:
  31 +浙FY201E
  32 +车型名称:
  33 +2018 一汽大众 速腾 三厢 1.6L 手自一体 舒适型(FV7166BABBG)
  34 +
  35 +
  36 +询价单号:
  37 +XJD20250609004660147
  38 +定损单号:
  39 +61398539
  40 +车架号:
  41 +LSVAF40C7KN112351
  42 +车牌号:
  43 +皖K537K6
  44 +车型名称:
  45 +2018 上汽大众 朗逸 三厢 1.5L 手自一体
  46 +
  47 +询价单号:
  48 +XJD20250604004626210
  49 +定损单号:
  50 +61321667
  51 +车架号:
  52 +WBALS2102J0Z29641
  53 +车牌号:
  54 +苏L8L760
  55 +车型名称:
  56 +2018 宝马 宝马X5 SUV 2.0T 手自一体 (BMW X5 28i)
  57 +
  58 +大众平均 2.5元
  59 +宝马平均 10元
  60 +奥迪平均 3.5元
  61 +
  62 +
  63 +LFV2A2BS6H4560229 x
  64 +LFV2B2C13M3816698 x
  65 +LSVY460T6S2051608 x
  66 +LFV2A28V7J5392246 x
  67 +LFV2A28V0H5024498 x
  68 +LFV3B2FY1J3513783 x
  69 +LFV3B2FY4P3383572 x
  70 +LFV3A24KXR3152230
  71 +LBV61AF08NS321734
  72 +LBV8V3101GMD46730
  73 +LBVFP3904BSE35458 x
  74 +
  75 +
  76 +
  77 +
  78 +fCVkbmMlPSclPzE3JXo%3D
  79 +fCVkbmMlPSclMzQwJXo%3D
  80 +
  81 +
  82 +LFV2A1151L6029426
  83 +LFV2A2151G3063539
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 +
  7 + <groupId>com.scm</groupId>
  8 + <artifactId>fp_scm</artifactId>
  9 + <version>4.8.2</version>
  10 +
  11 + <name>fp_scm</name>
  12 + <description>凡配供应链系统</description>
  13 +
  14 + <properties>
  15 + <fp-scm.version>4.8.2</fp-scm.version>
  16 + <spring-boot.version>2.7.18</spring-boot.version>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  19 + <java.version>1.8</java.version>
  20 + <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
  21 + <spring-boot.mybatis>2.2.2</spring-boot.mybatis>
  22 + <springdoc.version>1.6.15</springdoc.version>
  23 + <poi.version>5.2.3</poi.version>
  24 + <easyexcel.version>3.3.2</easyexcel.version>
  25 + <velocity.version>2.3</velocity.version>
  26 + <satoken.version>1.37.0</satoken.version>
  27 + <mybatis-plus.version>3.5.4</mybatis-plus.version>
  28 + <p6spy.version>3.9.1</p6spy.version>
  29 + <hutool.version>5.8.22</hutool.version>
  30 + <okhttp.version>4.10.0</okhttp.version>
  31 + <spring-boot-admin.version>2.7.11</spring-boot-admin.version>
  32 + <redisson.version>3.20.1</redisson.version>
  33 + <lock4j.version>2.2.3</lock4j.version>
  34 + <dynamic-ds.version>4.3.1</dynamic-ds.version>
  35 + <alibaba-ttl.version>2.14.2</alibaba-ttl.version>
  36 + <xxl-job.version>2.4.0</xxl-job.version>
  37 + <lombok.version>1.18.30</lombok.version>
  38 + <bouncycastle.version>1.72</bouncycastle.version>
  39 + <!-- 离线IP地址定位库 -->
  40 + <ip2region.version>2.7.0</ip2region.version>
  41 +
  42 + <!-- OSS 配置 -->
  43 + <aws-java-sdk-s3.version>1.12.540</aws-java-sdk-s3.version>
  44 + <!-- SMS 配置 -->
  45 + <sms4j.version>2.2.0</sms4j.version>
  46 + <sharding-sphere.version>4.0.0</sharding-sphere.version>
  47 + </properties>
  48 +
  49 + <profiles>
  50 + <profile>
  51 + <id>local</id>
  52 + <properties>
  53 + <!-- 环境标识,需要与配置文件的名称相对应 -->
  54 + <profiles.active>local</profiles.active>
  55 + <logging.level>info</logging.level>
  56 + </properties>
  57 + </profile>
  58 + <profile>
  59 + <id>dev</id>
  60 + <properties>
  61 + <!-- 环境标识,需要与配置文件的名称相对应 -->
  62 + <profiles.active>dev</profiles.active>
  63 + <logging.level>info</logging.level>
  64 + </properties>
  65 + <activation>
  66 + <!-- 默认环境 -->
  67 + <activeByDefault>true</activeByDefault>
  68 + </activation>
  69 + </profile>
  70 + <profile>
  71 + <id>prod</id>
  72 + <properties>
  73 + <profiles.active>prod</profiles.active>
  74 + <logging.level>warn</logging.level>
  75 + </properties>
  76 + </profile>
  77 + </profiles>
  78 +
  79 + <!-- 依赖声明 -->
  80 + <dependencyManagement>
  81 + <dependencies>
  82 +
  83 + <!-- SpringBoot的依赖配置-->
  84 + <dependency>
  85 + <groupId>org.springframework.boot</groupId>
  86 + <artifactId>spring-boot-dependencies</artifactId>
  87 + <version>${spring-boot.version}</version>
  88 + <type>pom</type>
  89 + <scope>import</scope>
  90 + </dependency>
  91 +
  92 + <!-- hutool 的依赖配置-->
  93 + <dependency>
  94 + <groupId>cn.hutool</groupId>
  95 + <artifactId>hutool-bom</artifactId>
  96 + <version>${hutool.version}</version>
  97 + <type>pom</type>
  98 + <scope>import</scope>
  99 + </dependency>
  100 +
  101 + <dependency>
  102 + <groupId>org.springdoc</groupId>
  103 + <artifactId>springdoc-openapi-webmvc-core</artifactId>
  104 + <version>${springdoc.version}</version>
  105 + </dependency>
  106 +
  107 + <dependency>
  108 + <groupId>org.springdoc</groupId>
  109 + <artifactId>springdoc-openapi-javadoc</artifactId>
  110 + <version>${springdoc.version}</version>
  111 + </dependency>
  112 +
  113 + <dependency>
  114 + <groupId>org.projectlombok</groupId>
  115 + <artifactId>lombok</artifactId>
  116 + <version>${lombok.version}</version>
  117 + </dependency>
  118 +
  119 + <dependency>
  120 + <groupId>org.apache.poi</groupId>
  121 + <artifactId>poi</artifactId>
  122 + <version>${poi.version}</version>
  123 + </dependency>
  124 + <dependency>
  125 + <groupId>org.apache.poi</groupId>
  126 + <artifactId>poi-ooxml</artifactId>
  127 + <version>${poi.version}</version>
  128 + </dependency>
  129 + <dependency>
  130 + <groupId>com.alibaba</groupId>
  131 + <artifactId>easyexcel</artifactId>
  132 + <version>${easyexcel.version}</version>
  133 + <exclusions>
  134 + <exclusion>
  135 + <groupId>org.apache.poi</groupId>
  136 + <artifactId>poi-ooxml-schemas</artifactId>
  137 + </exclusion>
  138 + </exclusions>
  139 + </dependency>
  140 +
  141 + <!-- velocity代码生成使用模板 -->
  142 + <dependency>
  143 + <groupId>org.apache.velocity</groupId>
  144 + <artifactId>velocity-engine-core</artifactId>
  145 + <version>${velocity.version}</version>
  146 + </dependency>
  147 +
  148 + <!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
  149 + <dependency>
  150 + <groupId>cn.dev33</groupId>
  151 + <artifactId>sa-token-spring-boot-starter</artifactId>
  152 + <version>${satoken.version}</version>
  153 + </dependency>
  154 + <!-- Sa-Token 整合 jwt -->
  155 + <dependency>
  156 + <groupId>cn.dev33</groupId>
  157 + <artifactId>sa-token-jwt</artifactId>
  158 + <version>${satoken.version}</version>
  159 + <exclusions>
  160 + <exclusion>
  161 + <groupId>cn.hutool</groupId>
  162 + <artifactId>hutool-all</artifactId>
  163 + </exclusion>
  164 + </exclusions>
  165 + </dependency>
  166 +
  167 + <!-- dynamic-datasource 多数据源-->
  168 + <dependency>
  169 + <groupId>com.baomidou</groupId>
  170 + <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  171 + <version>${dynamic-ds.version}</version>
  172 + </dependency>
  173 +
  174 + <dependency>
  175 + <groupId>com.baomidou</groupId>
  176 + <artifactId>mybatis-plus-boot-starter</artifactId>
  177 + <version>${mybatis-plus.version}</version>
  178 + </dependency>
  179 +
  180 + <!-- sql性能分析插件 -->
  181 + <dependency>
  182 + <groupId>p6spy</groupId>
  183 + <artifactId>p6spy</artifactId>
  184 + <version>${p6spy.version}</version>
  185 + </dependency>
  186 +
  187 + <dependency>
  188 + <groupId>com.squareup.okhttp3</groupId>
  189 + <artifactId>okhttp</artifactId>
  190 + <version>${okhttp.version}</version>
  191 + </dependency>
  192 +
  193 + <dependency>
  194 + <groupId>com.amazonaws</groupId>
  195 + <artifactId>aws-java-sdk-s3</artifactId>
  196 + <version>${aws-java-sdk-s3.version}</version>
  197 + </dependency>
  198 +
  199 + <!--短信sms4j-->
  200 + <dependency>
  201 + <groupId>org.dromara.sms4j</groupId>
  202 + <artifactId>sms4j-spring-boot-starter</artifactId>
  203 + <version>${sms4j.version}</version>
  204 + </dependency>
  205 +
  206 + <dependency>
  207 + <groupId>de.codecentric</groupId>
  208 + <artifactId>spring-boot-admin-starter-server</artifactId>
  209 + <version>${spring-boot-admin.version}</version>
  210 + </dependency>
  211 + <dependency>
  212 + <groupId>de.codecentric</groupId>
  213 + <artifactId>spring-boot-admin-starter-client</artifactId>
  214 + <version>${spring-boot-admin.version}</version>
  215 + </dependency>
  216 +
  217 + <!--redisson-->
  218 + <dependency>
  219 + <groupId>org.redisson</groupId>
  220 + <artifactId>redisson-spring-boot-starter</artifactId>
  221 + <version>${redisson.version}</version>
  222 + <exclusions>
  223 + <exclusion>
  224 + <groupId>org.redisson</groupId>
  225 + <artifactId>redisson-spring-data-30</artifactId>
  226 + </exclusion>
  227 + </exclusions>
  228 + </dependency>
  229 + <dependency>
  230 + <groupId>org.redisson</groupId>
  231 + <artifactId>redisson-spring-data-27</artifactId>
  232 + <version>${redisson.version}</version>
  233 + </dependency>
  234 +
  235 + <dependency>
  236 + <groupId>com.baomidou</groupId>
  237 + <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
  238 + <version>${lock4j.version}</version>
  239 + </dependency>
  240 +
  241 + <!-- xxl-job-core -->
  242 + <dependency>
  243 + <groupId>com.xuxueli</groupId>
  244 + <artifactId>xxl-job-core</artifactId>
  245 + <version>${xxl-job.version}</version>
  246 + </dependency>
  247 +
  248 + <dependency>
  249 + <groupId>com.alibaba</groupId>
  250 + <artifactId>transmittable-thread-local</artifactId>
  251 + <version>${alibaba-ttl.version}</version>
  252 + </dependency>
  253 +
  254 + <!-- 离线IP地址定位库 ip2region -->
  255 + <dependency>
  256 + <groupId>org.lionsoul</groupId>
  257 + <artifactId>ip2region</artifactId>
  258 + <version>${ip2region.version}</version>
  259 + </dependency>
  260 +
  261 + <!-- 加密包引入 -->
  262 + <dependency>
  263 + <groupId>org.bouncycastle</groupId>
  264 + <artifactId>bcprov-jdk15to18</artifactId>
  265 + <version>${bouncycastle.version}</version>
  266 + </dependency>
  267 +
  268 + <dependency>
  269 + <groupId>org.apache.shardingsphere</groupId>
  270 + <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
  271 + <version>${sharding-sphere.version}</version>
  272 + </dependency>
  273 +
  274 + <dependency>
  275 + <groupId>org.apache.shardingsphere</groupId>
  276 + <artifactId>shardingsphere-jdbc</artifactId>
  277 + <version>5.5.0</version>
  278 + </dependency>
  279 +
  280 + <!-- 定时任务 -->
  281 + <dependency>
  282 + <groupId>com.scm</groupId>
  283 + <artifactId>scm-job</artifactId>
  284 + <version>${fp-scm.version}</version>
  285 + </dependency>
  286 +
  287 + <!-- 代码生成-->
  288 + <dependency>
  289 + <groupId>com.scm</groupId>
  290 + <artifactId>scm-generator</artifactId>
  291 + <version>${fp-scm.version}</version>
  292 + </dependency>
  293 +
  294 + <!-- 核心模块-->
  295 + <dependency>
  296 + <groupId>com.scm</groupId>
  297 + <artifactId>scm-framework</artifactId>
  298 + <version>${fp-scm.version}</version>
  299 + </dependency>
  300 +
  301 + <!-- 系统模块-->
  302 + <dependency>
  303 + <groupId>com.scm</groupId>
  304 + <artifactId>scm-system</artifactId>
  305 + <version>${fp-scm.version}</version>
  306 + </dependency>
  307 +
  308 + <!-- 通用工具-->
  309 + <dependency>
  310 + <groupId>com.scm</groupId>
  311 + <artifactId>scm-common</artifactId>
  312 + <version>${fp-scm.version}</version>
  313 + </dependency>
  314 +
  315 + <!-- OSS对象存储模块 -->
  316 + <dependency>
  317 + <groupId>com.scm</groupId>
  318 + <artifactId>scm-oss</artifactId>
  319 + <version>${fp-scm.version}</version>
  320 + </dependency>
  321 +
  322 + <!-- SMS短信模块 -->
  323 + <dependency>
  324 + <groupId>com.scm</groupId>
  325 + <artifactId>scm-sms</artifactId>
  326 + <version>${fp-scm.version}</version>
  327 + </dependency>
  328 + </dependencies>
  329 + </dependencyManagement>
  330 +
  331 + <modules>
  332 + <module>scm-admin</module>
  333 + <module>scm-framework</module>
  334 + <module>scm-system</module>
  335 + <module>scm-job</module>
  336 + <module>scm-generator</module>
  337 + <module>scm-common</module>
  338 + <module>scm-extend</module>
  339 + <module>scm-oss</module>
  340 + <module>scm-sms</module>
  341 + </modules>
  342 + <packaging>pom</packaging>
  343 +
  344 + <build>
  345 + <plugins>
  346 + <plugin>
  347 + <groupId>org.apache.maven.plugins</groupId>
  348 + <artifactId>maven-compiler-plugin</artifactId>
  349 + <version>3.9.0</version>
  350 + <configuration>
  351 + <source>${java.version}</source>
  352 + <target>${java.version}</target>
  353 + <encoding>${project.build.sourceEncoding}</encoding>
  354 + <annotationProcessorPaths>
  355 + <path>
  356 + <groupId>com.github.therapi</groupId>
  357 + <artifactId>therapi-runtime-javadoc-scribe</artifactId>
  358 + <version>0.15.0</version>
  359 + </path>
  360 + <path>
  361 + <groupId>org.projectlombok</groupId>
  362 + <artifactId>lombok</artifactId>
  363 + <version>${lombok.version}</version>
  364 + </path>
  365 + <path>
  366 + <groupId>org.springframework.boot</groupId>
  367 + <artifactId>spring-boot-configuration-processor</artifactId>
  368 + <version>${spring-boot.version}</version>
  369 + </path>
  370 + </annotationProcessorPaths>
  371 + </configuration>
  372 + </plugin>
  373 + <!-- 单元测试使用 -->
  374 + <plugin>
  375 + <groupId>org.apache.maven.plugins</groupId>
  376 + <artifactId>maven-surefire-plugin</artifactId>
  377 + <version>2.22.2</version>
  378 + <configuration>
  379 + <argLine>-Dfile.encoding=UTF-8</argLine>
  380 + <!-- 根据打包环境执行对应的@Tag测试方法 -->
  381 + <groups>${profiles.active}</groups>
  382 + <!-- 排除标签 -->
  383 + <excludedGroups>exclude</excludedGroups>
  384 + </configuration>
  385 + </plugin>
  386 + </plugins>
  387 + <resources>
  388 + <resource>
  389 + <directory>src/main/resources</directory>
  390 + <!-- 关闭过滤 -->
  391 + <filtering>false</filtering>
  392 + </resource>
  393 + <resource>
  394 + <directory>src/main/resources</directory>
  395 + <!-- 引入所有 匹配文件进行过滤 -->
  396 + <includes>
  397 + <include>application*</include>
  398 + <include>bootstrap*</include>
  399 + <include>banner*</include>
  400 + </includes>
  401 + <!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
  402 + <filtering>true</filtering>
  403 + </resource>
  404 + </resources>
  405 + </build>
  406 +
  407 + <repositories>
  408 + <repository>
  409 + <id>public</id>
  410 + <name>huawei nexus</name>
  411 + <url>https://mirrors.huaweicloud.com/repository/maven/</url>
  412 + <releases>
  413 + <enabled>true</enabled>
  414 + </releases>
  415 + </repository>
  416 + </repositories>
  417 +
  418 + <pluginRepositories>
  419 + <pluginRepository>
  420 + <id>public</id>
  421 + <name>huawei nexus</name>
  422 + <url>https://mirrors.huaweicloud.com/repository/maven/</url>
  423 + <releases>
  424 + <enabled>true</enabled>
  425 + </releases>
  426 + <snapshots>
  427 + <enabled>false</enabled>
  428 + </snapshots>
  429 + </pluginRepository>
  430 + </pluginRepositories>
  431 +
  432 +</project>
  433 +
  434 +
  1 +FROM anapsix/alpine-java:8_server-jre_unlimited
  2 +
  3 +MAINTAINER Lion Li
  4 +
  5 +RUN mkdir -p /ruoyi/server/logs \
  6 + /ruoyi/server/temp \
  7 + /ruoyi/skywalking/agent
  8 +
  9 +WORKDIR /ruoyi/server
  10 +
  11 +ENV SERVER_PORT=8080
  12 +
  13 +EXPOSE ${SERVER_PORT}
  14 +
  15 +ADD ./target/ruoyi-admin.jar ./app.jar
  16 +
  17 +ENTRYPOINT ["java", \
  18 + "-Djava.security.egd=file:/dev/./urandom", \
  19 + "-Dserver.port=${SERVER_PORT}", \
  20 + # 应用名称 如果想区分集群节点监控 改成不同的名称即可
  21 +# "-Dskywalking.agent.service_name=ruoyi-server", \
  22 +# "-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar", \
  23 + "-jar", "app.jar"]
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <artifactId>fp_scm</artifactId>
  7 + <groupId>com.scm</groupId>
  8 + <version>4.8.2</version>
  9 + </parent>
  10 + <modelVersion>4.0.0</modelVersion>
  11 + <packaging>jar</packaging>
  12 + <artifactId>scm-admin</artifactId>
  13 +
  14 + <description>
  15 + web服务入口
  16 + </description>
  17 +
  18 + <dependencies>
  19 +
  20 + <!-- spring-boot-devtools -->
  21 + <dependency>
  22 + <groupId>org.springframework.boot</groupId>
  23 + <artifactId>spring-boot-devtools</artifactId>
  24 + <optional>true</optional> <!-- 表示依赖不会传递 -->
  25 + </dependency>
  26 +
  27 + <!-- Mysql驱动包 -->
  28 + <dependency>
  29 + <groupId>com.mysql</groupId>
  30 + <artifactId>mysql-connector-j</artifactId>
  31 + </dependency>
  32 + <!-- Oracle -->
  33 + <dependency>
  34 + <groupId>com.oracle.database.jdbc</groupId>
  35 + <artifactId>ojdbc8</artifactId>
  36 + </dependency>
  37 + <!-- PostgreSql -->
  38 + <dependency>
  39 + <groupId>org.postgresql</groupId>
  40 + <artifactId>postgresql</artifactId>
  41 + </dependency>
  42 + <!-- SqlServer -->
  43 + <dependency>
  44 + <groupId>com.microsoft.sqlserver</groupId>
  45 + <artifactId>mssql-jdbc</artifactId>
  46 + </dependency>
  47 +
  48 + <!-- 核心模块-->
  49 + <dependency>
  50 + <groupId>com.scm</groupId>
  51 + <artifactId>scm-framework</artifactId>
  52 + </dependency>
  53 +
  54 + <dependency>
  55 + <groupId>com.scm</groupId>
  56 + <artifactId>scm-system</artifactId>
  57 + </dependency>
  58 +
  59 +<!--
  60 + <dependency>
  61 + <groupId>com.scm</groupId>
  62 + <artifactId>ruoyi-job</artifactId>
  63 + </dependency>
  64 +-->
  65 +
  66 + <dependency>
  67 + <groupId>com.scm</groupId>
  68 + <artifactId>scm-oss</artifactId>
  69 + </dependency>
  70 +
  71 + <!-- 代码生成-->
  72 + <dependency>
  73 + <groupId>com.scm</groupId>
  74 + <artifactId>scm-generator</artifactId>
  75 + </dependency>
  76 +
  77 + <dependency>
  78 + <groupId>org.springframework.boot</groupId>
  79 + <artifactId>spring-boot-starter-test</artifactId>
  80 + <scope>test</scope>
  81 + </dependency>
  82 +
  83 + <!-- skywalking 整合 logback -->
  84 +<!-- <dependency>-->
  85 +<!-- <groupId>org.apache.skywalking</groupId>-->
  86 +<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>-->
  87 +<!-- <version>${与你的agent探针版本保持一致}</version>-->
  88 +<!-- </dependency>-->
  89 +<!-- <dependency>-->
  90 +<!-- <groupId>org.apache.skywalking</groupId>-->
  91 +<!-- <artifactId>apm-toolkit-trace</artifactId>-->
  92 +<!-- <version>${与你的agent探针版本保持一致}</version>-->
  93 +<!-- </dependency>-->
  94 +
  95 + </dependencies>
  96 +
  97 + <build>
  98 + <finalName>${project.artifactId}</finalName>
  99 + <plugins>
  100 + <plugin>
  101 + <groupId>org.springframework.boot</groupId>
  102 + <artifactId>spring-boot-maven-plugin</artifactId>
  103 + <version>${spring-boot.version}</version>
  104 + <configuration>
  105 + <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
  106 + </configuration>
  107 + <executions>
  108 + <execution>
  109 + <goals>
  110 + <goal>repackage</goal>
  111 + </goals>
  112 + </execution>
  113 + </executions>
  114 + </plugin>
  115 + <plugin>
  116 + <groupId>org.apache.maven.plugins</groupId>
  117 + <artifactId>maven-war-plugin</artifactId>
  118 + <version>3.2.2</version>
  119 + <configuration>
  120 + <failOnMissingWebXml>false</failOnMissingWebXml>
  121 + <warName>${project.artifactId}</warName>
  122 + </configuration>
  123 + </plugin>
  124 + </plugins>
  125 + </build>
  126 +
  127 +</project>
  1 +package com.ruoyi;
  2 +
  3 +import org.springframework.boot.SpringApplication;
  4 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  5 +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
  6 +
  7 +/**
  8 + * 启动程序
  9 + *
  10 + * @author ruoyi
  11 + */
  12 +
  13 +@SpringBootApplication
  14 +public class RuoYiApplication {
  15 +
  16 + public static void main(String[] args) {
  17 + System.setProperty("spring.devtools.restart.enabled", "false");
  18 + SpringApplication application = new SpringApplication(RuoYiApplication.class);
  19 + application.setApplicationStartup(new BufferingApplicationStartup(2048));
  20 + application.run(args);
  21 + System.out.println("(♥◠‿◠)ノ゙ RuoYi-Vue-Plus启动成功 ლ(´ڡ`ლ)゙");
  22 + }
  23 +
  24 +}
  1 +package com.ruoyi;
  2 +
  3 +import org.springframework.boot.builder.SpringApplicationBuilder;
  4 +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
  5 +
  6 +/**
  7 + * web容器中进行部署
  8 + *
  9 + * @author ruoyi
  10 + */
  11 +public class RuoYiServletInitializer extends SpringBootServletInitializer {
  12 +
  13 + @Override
  14 + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  15 + return application.sources(RuoYiApplication.class);
  16 + }
  17 +
  18 +}
  1 +package com.ruoyi.web.controller.common;
  2 +
  3 +import cn.dev33.satoken.annotation.SaIgnore;
  4 +import cn.hutool.captcha.AbstractCaptcha;
  5 +import cn.hutool.captcha.generator.CodeGenerator;
  6 +import cn.hutool.core.util.IdUtil;
  7 +import cn.hutool.core.util.RandomUtil;
  8 +import com.ruoyi.common.constant.CacheConstants;
  9 +import com.ruoyi.common.constant.Constants;
  10 +import com.ruoyi.common.core.domain.R;
  11 +import com.ruoyi.common.enums.CaptchaType;
  12 +import com.ruoyi.common.utils.StringUtils;
  13 +import com.ruoyi.common.utils.email.MailUtils;
  14 +import com.ruoyi.common.utils.redis.RedisUtils;
  15 +import com.ruoyi.common.utils.reflect.ReflectUtils;
  16 +import com.ruoyi.common.utils.spring.SpringUtils;
  17 +import com.ruoyi.framework.config.properties.CaptchaProperties;
  18 +import com.ruoyi.framework.config.properties.MailProperties;
  19 +import com.ruoyi.system.service.ISysConfigService;
  20 +import lombok.RequiredArgsConstructor;
  21 +import lombok.extern.slf4j.Slf4j;
  22 +import org.dromara.sms4j.api.SmsBlend;
  23 +import org.dromara.sms4j.api.entity.SmsResponse;
  24 +import org.dromara.sms4j.core.factory.SmsFactory;
  25 +import org.dromara.sms4j.provider.enumerate.SupplierType;
  26 +import org.springframework.expression.Expression;
  27 +import org.springframework.expression.ExpressionParser;
  28 +import org.springframework.expression.spel.standard.SpelExpressionParser;
  29 +import org.springframework.validation.annotation.Validated;
  30 +import org.springframework.web.bind.annotation.GetMapping;
  31 +import org.springframework.web.bind.annotation.RestController;
  32 +
  33 +import javax.validation.constraints.NotBlank;
  34 +import java.time.Duration;
  35 +import java.util.HashMap;
  36 +import java.util.LinkedHashMap;
  37 +import java.util.Map;
  38 +
  39 +/**
  40 + * 验证码操作处理
  41 + *
  42 + * @author Lion Li
  43 + */
  44 +@SaIgnore
  45 +@Slf4j
  46 +@Validated
  47 +@RequiredArgsConstructor
  48 +@RestController
  49 +public class CaptchaController {
  50 +
  51 + private final CaptchaProperties captchaProperties;
  52 + private final ISysConfigService configService;
  53 + private final MailProperties mailProperties;
  54 +
  55 + /**
  56 + * 短信验证码
  57 + *
  58 + * @param phonenumber 用户手机号
  59 + */
  60 + @GetMapping("/captchaSms")
  61 + public R<Void> smsCaptcha(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
  62 + String key = CacheConstants.CAPTCHA_CODE_KEY + phonenumber;
  63 + String code = RandomUtil.randomNumbers(4);
  64 + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
  65 + // 验证码模板id 自行处理 (查数据库或写死均可)
  66 + String templateId = "";
  67 + LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
  68 + map.put("code", code);
  69 + SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
  70 + SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
  71 + if (!"OK".equals(smsResponse.getCode())) {
  72 + log.error("验证码短信发送异常 => {}", smsResponse);
  73 + return R.fail(smsResponse.getMessage());
  74 + }
  75 + return R.ok();
  76 + }
  77 +
  78 + /**
  79 + * 邮箱验证码
  80 + *
  81 + * @param email 邮箱
  82 + */
  83 + @GetMapping("/captchaEmail")
  84 + public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
  85 + if (!mailProperties.getEnabled()) {
  86 + return R.fail("当前系统没有开启邮箱功能!");
  87 + }
  88 + String key = CacheConstants.CAPTCHA_CODE_KEY + email;
  89 + String code = RandomUtil.randomNumbers(4);
  90 + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
  91 + try {
  92 + MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
  93 + } catch (Exception e) {
  94 + log.error("验证码短信发送异常 => {}", e.getMessage());
  95 + return R.fail(e.getMessage());
  96 + }
  97 + return R.ok();
  98 + }
  99 +
  100 + /**
  101 + * 生成验证码
  102 + */
  103 + @GetMapping("/captchaImage")
  104 + public R<Map<String, Object>> getCode() {
  105 + Map<String, Object> ajax = new HashMap<>();
  106 + boolean captchaEnabled = configService.selectCaptchaEnabled();
  107 + ajax.put("captchaEnabled", captchaEnabled);
  108 + if (!captchaEnabled) {
  109 + return R.ok(ajax);
  110 + }
  111 + // 保存验证码信息
  112 + String uuid = IdUtil.simpleUUID();
  113 + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
  114 + // 生成验证码
  115 + CaptchaType captchaType = captchaProperties.getType();
  116 + boolean isMath = CaptchaType.MATH == captchaType;
  117 + Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
  118 + CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
  119 + AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
  120 + captcha.setGenerator(codeGenerator);
  121 + captcha.createCode();
  122 + String code = captcha.getCode();
  123 + if (isMath) {
  124 + ExpressionParser parser = new SpelExpressionParser();
  125 + Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
  126 + code = exp.getValue(String.class);
  127 + }
  128 + RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
  129 + ajax.put("uuid", uuid);
  130 + ajax.put("img", captcha.getImageBase64());
  131 + return R.ok(ajax);
  132 + }
  133 +
  134 +}
  1 +package com.ruoyi.web.controller.monitor;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import cn.hutool.core.collection.CollUtil;
  5 +import com.ruoyi.common.constant.CacheConstants;
  6 +import com.ruoyi.common.constant.CacheNames;
  7 +import com.ruoyi.common.core.domain.R;
  8 +import com.ruoyi.common.utils.JsonUtils;
  9 +import com.ruoyi.common.utils.StringUtils;
  10 +import com.ruoyi.common.utils.redis.CacheUtils;
  11 +import com.ruoyi.common.utils.redis.RedisUtils;
  12 +import com.ruoyi.system.domain.SysCache;
  13 +import lombok.RequiredArgsConstructor;
  14 +import org.redisson.spring.data.connection.RedissonConnectionFactory;
  15 +import org.springframework.data.redis.connection.RedisConnection;
  16 +import org.springframework.web.bind.annotation.*;
  17 +
  18 +import java.util.*;
  19 +import java.util.stream.Collectors;
  20 +
  21 +/**
  22 + * 缓存监控
  23 + *
  24 + * @author Lion Li
  25 + */
  26 +@RequiredArgsConstructor
  27 +@RestController
  28 +@RequestMapping("/monitor/cache")
  29 +public class CacheController {
  30 +
  31 + private final RedissonConnectionFactory connectionFactory;
  32 +
  33 + private final static List<SysCache> CACHES = new ArrayList<>();
  34 +
  35 + static {
  36 + CACHES.add(new SysCache(CacheConstants.ONLINE_TOKEN_KEY, "在线用户"));
  37 + CACHES.add(new SysCache(CacheNames.SYS_CONFIG, "配置信息"));
  38 + CACHES.add(new SysCache(CacheNames.SYS_DICT, "数据字典"));
  39 + CACHES.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
  40 + CACHES.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
  41 + CACHES.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
  42 + CACHES.add(new SysCache(CacheNames.SYS_OSS_CONFIG, "OSS配置"));
  43 + CACHES.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
  44 + }
  45 +
  46 + /**
  47 + * 获取缓存监控列表
  48 + */
  49 + @SaCheckPermission("monitor:cache:list")
  50 + @GetMapping()
  51 + public R<Map<String, Object>> getInfo() throws Exception {
  52 + RedisConnection connection = connectionFactory.getConnection();
  53 + Properties info = connection.info();
  54 + Properties commandStats = connection.info("commandstats");
  55 + Long dbSize = connection.dbSize();
  56 +
  57 + Map<String, Object> result = new HashMap<>(3);
  58 + result.put("info", info);
  59 + result.put("dbSize", dbSize);
  60 +
  61 + List<Map<String, String>> pieList = new ArrayList<>();
  62 + if (commandStats != null) {
  63 + commandStats.stringPropertyNames().forEach(key -> {
  64 + Map<String, String> data = new HashMap<>(2);
  65 + String property = commandStats.getProperty(key);
  66 + data.put("name", StringUtils.removeStart(key, "cmdstat_"));
  67 + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
  68 + pieList.add(data);
  69 + });
  70 + }
  71 + result.put("commandStats", pieList);
  72 + return R.ok(result);
  73 + }
  74 +
  75 + /**
  76 + * 获取缓存监控缓存名列表
  77 + */
  78 + @SaCheckPermission("monitor:cache:list")
  79 + @GetMapping("/getNames")
  80 + public R<List<SysCache>> cache() {
  81 + return R.ok(CACHES);
  82 + }
  83 +
  84 + /**
  85 + * 获取缓存监控Key列表
  86 + *
  87 + * @param cacheName 缓存名
  88 + */
  89 + @SaCheckPermission("monitor:cache:list")
  90 + @GetMapping("/getKeys/{cacheName}")
  91 + public R<Collection<String>> getCacheKeys(@PathVariable String cacheName) {
  92 + Collection<String> cacheKeys = new HashSet<>(0);
  93 + if (isCacheNames(cacheName)) {
  94 + Set<Object> keys = CacheUtils.keys(cacheName);
  95 + if (CollUtil.isNotEmpty(keys)) {
  96 + cacheKeys = keys.stream().map(Object::toString).collect(Collectors.toList());
  97 + }
  98 + } else {
  99 + cacheKeys = RedisUtils.keys(cacheName + "*");
  100 + }
  101 + return R.ok(cacheKeys);
  102 + }
  103 +
  104 + /**
  105 + * 获取缓存监控缓存值详情
  106 + *
  107 + * @param cacheName 缓存名
  108 + * @param cacheKey 缓存key
  109 + */
  110 + @SaCheckPermission("monitor:cache:list")
  111 + @GetMapping("/getValue/{cacheName}/{cacheKey}")
  112 + public R<SysCache> getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) {
  113 + Object cacheValue;
  114 + if (isCacheNames(cacheName)) {
  115 + cacheValue = CacheUtils.get(cacheName, cacheKey);
  116 + } else {
  117 + cacheValue = RedisUtils.getCacheObject(cacheKey);
  118 + }
  119 + SysCache sysCache = new SysCache(cacheName, cacheKey, JsonUtils.toJsonString(cacheValue));
  120 + return R.ok(sysCache);
  121 + }
  122 +
  123 + /**
  124 + * 清理缓存监控缓存名
  125 + *
  126 + * @param cacheName 缓存名
  127 + */
  128 + @SaCheckPermission("monitor:cache:list")
  129 + @DeleteMapping("/clearCacheName/{cacheName}")
  130 + public R<Void> clearCacheName(@PathVariable String cacheName) {
  131 + if (isCacheNames(cacheName)) {
  132 + CacheUtils.clear(cacheName);
  133 + } else {
  134 + RedisUtils.deleteKeys(cacheName + "*");
  135 + }
  136 + return R.ok();
  137 + }
  138 +
  139 + /**
  140 + * 清理缓存监控Key
  141 + *
  142 + * @param cacheKey key名
  143 + */
  144 + @SaCheckPermission("monitor:cache:list")
  145 + @DeleteMapping("/clearCacheKey/{cacheName}/{cacheKey}")
  146 + public R<Void> clearCacheKey(@PathVariable String cacheName, @PathVariable String cacheKey) {
  147 + if (isCacheNames(cacheName)) {
  148 + CacheUtils.evict(cacheName, cacheKey);
  149 + } else {
  150 + RedisUtils.deleteObject(cacheKey);
  151 + }
  152 + return R.ok();
  153 + }
  154 +
  155 + /**
  156 + * 清理全部缓存监控
  157 + */
  158 + @SaCheckPermission("monitor:cache:list")
  159 + @DeleteMapping("/clearCacheAll")
  160 + public R<Void> clearCacheAll() {
  161 + RedisUtils.deleteKeys("*");
  162 + return R.ok();
  163 + }
  164 +
  165 + private boolean isCacheNames(String cacheName) {
  166 + return !StringUtils.contains(cacheName, ":");
  167 + }
  168 +}
  1 +package com.ruoyi.web.controller.monitor;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import com.ruoyi.common.annotation.Log;
  5 +import com.ruoyi.common.constant.CacheConstants;
  6 +import com.ruoyi.common.core.controller.BaseController;
  7 +import com.ruoyi.common.core.domain.PageQuery;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.page.TableDataInfo;
  10 +import com.ruoyi.common.enums.BusinessType;
  11 +import com.ruoyi.common.utils.poi.ExcelUtil;
  12 +import com.ruoyi.common.utils.redis.RedisUtils;
  13 +import com.ruoyi.system.domain.SysLogininfor;
  14 +import com.ruoyi.system.service.ISysLogininforService;
  15 +import lombok.RequiredArgsConstructor;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import javax.servlet.http.HttpServletResponse;
  20 +import java.util.List;
  21 +
  22 +/**
  23 + * 系统访问记录
  24 + *
  25 + * @author Lion Li
  26 + */
  27 +@Validated
  28 +@RequiredArgsConstructor
  29 +@RestController
  30 +@RequestMapping("/monitor/logininfor")
  31 +public class SysLogininforController extends BaseController {
  32 +
  33 + private final ISysLogininforService logininforService;
  34 +
  35 + /**
  36 + * 获取系统访问记录列表
  37 + */
  38 + @SaCheckPermission("monitor:logininfor:list")
  39 + @GetMapping("/list")
  40 + public TableDataInfo<SysLogininfor> list(SysLogininfor logininfor, PageQuery pageQuery) {
  41 + return logininforService.selectPageLogininforList(logininfor, pageQuery);
  42 + }
  43 +
  44 + /**
  45 + * 导出系统访问记录列表
  46 + */
  47 + @Log(title = "登录日志", businessType = BusinessType.EXPORT)
  48 + @SaCheckPermission("monitor:logininfor:export")
  49 + @PostMapping("/export")
  50 + public void export(SysLogininfor logininfor, HttpServletResponse response) {
  51 + List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
  52 + ExcelUtil.exportExcel(list, "登录日志", SysLogininfor.class, response);
  53 + }
  54 +
  55 + /**
  56 + * 批量删除登录日志
  57 + * @param infoIds 日志ids
  58 + */
  59 + @SaCheckPermission("monitor:logininfor:remove")
  60 + @Log(title = "登录日志", businessType = BusinessType.DELETE)
  61 + @DeleteMapping("/{infoIds}")
  62 + public R<Void> remove(@PathVariable Long[] infoIds) {
  63 + return toAjax(logininforService.deleteLogininforByIds(infoIds));
  64 + }
  65 +
  66 + /**
  67 + * 清理系统访问记录
  68 + */
  69 + @SaCheckPermission("monitor:logininfor:remove")
  70 + @Log(title = "登录日志", businessType = BusinessType.CLEAN)
  71 + @DeleteMapping("/clean")
  72 + public R<Void> clean() {
  73 + logininforService.cleanLogininfor();
  74 + return R.ok();
  75 + }
  76 +
  77 + @SaCheckPermission("monitor:logininfor:unlock")
  78 + @Log(title = "账户解锁", businessType = BusinessType.OTHER)
  79 + @GetMapping("/unlock/{userName}")
  80 + public R<Void> unlock(@PathVariable("userName") String userName) {
  81 + String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName;
  82 + if (RedisUtils.hasKey(loginName)) {
  83 + RedisUtils.deleteObject(loginName);
  84 + }
  85 + return R.ok();
  86 + }
  87 +
  88 +}
  1 +package com.ruoyi.web.controller.monitor;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import com.ruoyi.common.annotation.Log;
  5 +import com.ruoyi.common.core.controller.BaseController;
  6 +import com.ruoyi.common.core.domain.PageQuery;
  7 +import com.ruoyi.common.core.domain.R;
  8 +import com.ruoyi.common.core.page.TableDataInfo;
  9 +import com.ruoyi.common.enums.BusinessType;
  10 +import com.ruoyi.common.utils.poi.ExcelUtil;
  11 +import com.ruoyi.system.domain.SysOperLog;
  12 +import com.ruoyi.system.service.ISysOperLogService;
  13 +import lombok.RequiredArgsConstructor;
  14 +import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.*;
  16 +
  17 +import javax.servlet.http.HttpServletResponse;
  18 +import java.util.List;
  19 +
  20 +/**
  21 + * 操作日志记录
  22 + *
  23 + * @author Lion Li
  24 + */
  25 +@Validated
  26 +@RequiredArgsConstructor
  27 +@RestController
  28 +@RequestMapping("/monitor/operlog")
  29 +public class SysOperlogController extends BaseController {
  30 +
  31 + private final ISysOperLogService operLogService;
  32 +
  33 + /**
  34 + * 获取操作日志记录列表
  35 + */
  36 + @SaCheckPermission("monitor:operlog:list")
  37 + @GetMapping("/list")
  38 + public TableDataInfo<SysOperLog> list(SysOperLog operLog, PageQuery pageQuery) {
  39 + return operLogService.selectPageOperLogList(operLog, pageQuery);
  40 + }
  41 +
  42 + /**
  43 + * 导出操作日志记录列表
  44 + */
  45 + @Log(title = "操作日志", businessType = BusinessType.EXPORT)
  46 + @SaCheckPermission("monitor:operlog:export")
  47 + @PostMapping("/export")
  48 + public void export(SysOperLog operLog, HttpServletResponse response) {
  49 + List<SysOperLog> list = operLogService.selectOperLogList(operLog);
  50 + ExcelUtil.exportExcel(list, "操作日志", SysOperLog.class, response);
  51 + }
  52 +
  53 + /**
  54 + * 批量删除操作日志记录
  55 + * @param operIds 日志ids
  56 + */
  57 + @Log(title = "操作日志", businessType = BusinessType.DELETE)
  58 + @SaCheckPermission("monitor:operlog:remove")
  59 + @DeleteMapping("/{operIds}")
  60 + public R<Void> remove(@PathVariable Long[] operIds) {
  61 + return toAjax(operLogService.deleteOperLogByIds(operIds));
  62 + }
  63 +
  64 + /**
  65 + * 清理操作日志记录
  66 + */
  67 + @Log(title = "操作日志", businessType = BusinessType.CLEAN)
  68 + @SaCheckPermission("monitor:operlog:remove")
  69 + @DeleteMapping("/clean")
  70 + public R<Void> clean() {
  71 + operLogService.cleanOperLog();
  72 + return R.ok();
  73 + }
  74 +}
  1 +package com.ruoyi.web.controller.monitor;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import cn.dev33.satoken.exception.NotLoginException;
  5 +import cn.dev33.satoken.stp.StpUtil;
  6 +import cn.hutool.core.bean.BeanUtil;
  7 +import com.ruoyi.common.annotation.Log;
  8 +import com.ruoyi.common.constant.CacheConstants;
  9 +import com.ruoyi.common.core.controller.BaseController;
  10 +import com.ruoyi.common.core.domain.R;
  11 +import com.ruoyi.common.core.domain.dto.UserOnlineDTO;
  12 +import com.ruoyi.common.core.page.TableDataInfo;
  13 +import com.ruoyi.common.enums.BusinessType;
  14 +import com.ruoyi.common.utils.StreamUtils;
  15 +import com.ruoyi.common.utils.StringUtils;
  16 +import com.ruoyi.common.utils.redis.RedisUtils;
  17 +import com.ruoyi.system.domain.SysUserOnline;
  18 +import lombok.RequiredArgsConstructor;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import java.util.ArrayList;
  22 +import java.util.Collections;
  23 +import java.util.List;
  24 +
  25 +/**
  26 + * 在线用户监控
  27 + *
  28 + * @author Lion Li
  29 + */
  30 +@RequiredArgsConstructor
  31 +@RestController
  32 +@RequestMapping("/monitor/online")
  33 +public class SysUserOnlineController extends BaseController {
  34 +
  35 + /**
  36 + * 获取在线用户监控列表
  37 + *
  38 + * @param ipaddr IP地址
  39 + * @param userName 用户名
  40 + */
  41 + @SaCheckPermission("monitor:online:list")
  42 + @GetMapping("/list")
  43 + public TableDataInfo<SysUserOnline> list(String ipaddr, String userName) {
  44 + // 获取所有未过期的 token
  45 + List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
  46 + List<UserOnlineDTO> userOnlineDTOList = new ArrayList<>();
  47 + for (String key : keys) {
  48 + String token = StringUtils.substringAfterLast(key, ":");
  49 + // 如果已经过期则跳过
  50 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
  51 + continue;
  52 + }
  53 + userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token));
  54 + }
  55 + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) {
  56 + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
  57 + StringUtils.equals(ipaddr, userOnline.getIpaddr()) &&
  58 + StringUtils.equals(userName, userOnline.getUserName())
  59 + );
  60 + } else if (StringUtils.isNotEmpty(ipaddr)) {
  61 + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
  62 + StringUtils.equals(ipaddr, userOnline.getIpaddr())
  63 + );
  64 + } else if (StringUtils.isNotEmpty(userName)) {
  65 + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
  66 + StringUtils.equals(userName, userOnline.getUserName())
  67 + );
  68 + }
  69 + Collections.reverse(userOnlineDTOList);
  70 + userOnlineDTOList.removeAll(Collections.singleton(null));
  71 + List<SysUserOnline> userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class);
  72 + return TableDataInfo.build(userOnlineList);
  73 + }
  74 +
  75 + /**
  76 + * 强退用户
  77 + *
  78 + * @param tokenId token值
  79 + */
  80 + @SaCheckPermission("monitor:online:forceLogout")
  81 + @Log(title = "在线用户", businessType = BusinessType.FORCE)
  82 + @DeleteMapping("/{tokenId}")
  83 + public R<Void> forceLogout(@PathVariable String tokenId) {
  84 + try {
  85 + StpUtil.kickoutByTokenValue(tokenId);
  86 + } catch (NotLoginException ignored) {
  87 + }
  88 + return R.ok();
  89 + }
  90 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import com.ruoyi.common.annotation.Log;
  5 +import com.ruoyi.common.constant.UserConstants;
  6 +import com.ruoyi.common.core.controller.BaseController;
  7 +import com.ruoyi.common.core.domain.PageQuery;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.page.TableDataInfo;
  10 +import com.ruoyi.common.enums.BusinessType;
  11 +import com.ruoyi.common.utils.poi.ExcelUtil;
  12 +import com.ruoyi.system.domain.SysConfig;
  13 +import com.ruoyi.system.service.ISysConfigService;
  14 +import lombok.RequiredArgsConstructor;
  15 +import org.springframework.validation.annotation.Validated;
  16 +import org.springframework.web.bind.annotation.*;
  17 +
  18 +import javax.servlet.http.HttpServletResponse;
  19 +import java.util.List;
  20 +
  21 +/**
  22 + * 参数配置 信息操作处理
  23 + *
  24 + * @author Lion Li
  25 + */
  26 +@Validated
  27 +@RequiredArgsConstructor
  28 +@RestController
  29 +@RequestMapping("/system/config")
  30 +public class SysConfigController extends BaseController {
  31 +
  32 + private final ISysConfigService configService;
  33 +
  34 + /**
  35 + * 获取参数配置列表
  36 + */
  37 + @SaCheckPermission("system:config:list")
  38 + @GetMapping("/list")
  39 + public TableDataInfo<SysConfig> list(SysConfig config, PageQuery pageQuery) {
  40 + return configService.selectPageConfigList(config, pageQuery);
  41 + }
  42 +
  43 + /**
  44 + * 导出参数配置列表
  45 + */
  46 + @Log(title = "参数管理", businessType = BusinessType.EXPORT)
  47 + @SaCheckPermission("system:config:export")
  48 + @PostMapping("/export")
  49 + public void export(SysConfig config, HttpServletResponse response) {
  50 + List<SysConfig> list = configService.selectConfigList(config);
  51 + ExcelUtil.exportExcel(list, "参数数据", SysConfig.class, response);
  52 + }
  53 +
  54 + /**
  55 + * 根据参数编号获取详细信息
  56 + *
  57 + * @param configId 参数ID
  58 + */
  59 + @SaCheckPermission("system:config:query")
  60 + @GetMapping(value = "/{configId}")
  61 + public R<SysConfig> getInfo(@PathVariable Long configId) {
  62 + return R.ok(configService.selectConfigById(configId));
  63 + }
  64 +
  65 + /**
  66 + * 根据参数键名查询参数值
  67 + *
  68 + * @param configKey 参数Key
  69 + */
  70 + @GetMapping(value = "/configKey/{configKey}")
  71 + public R<Void> getConfigKey(@PathVariable String configKey) {
  72 + return R.ok(configService.selectConfigByKey(configKey));
  73 + }
  74 +
  75 + /**
  76 + * 新增参数配置
  77 + */
  78 + @SaCheckPermission("system:config:add")
  79 + @Log(title = "参数管理", businessType = BusinessType.INSERT)
  80 + @PostMapping
  81 + public R<Void> add(@Validated @RequestBody SysConfig config) {
  82 + if (!configService.checkConfigKeyUnique(config)) {
  83 + return R.fail("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
  84 + }
  85 + configService.insertConfig(config);
  86 + return R.ok();
  87 + }
  88 +
  89 + /**
  90 + * 修改参数配置
  91 + */
  92 + @SaCheckPermission("system:config:edit")
  93 + @Log(title = "参数管理", businessType = BusinessType.UPDATE)
  94 + @PutMapping
  95 + public R<Void> edit(@Validated @RequestBody SysConfig config) {
  96 + if (!configService.checkConfigKeyUnique(config)) {
  97 + return R.fail("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
  98 + }
  99 + configService.updateConfig(config);
  100 + return R.ok();
  101 + }
  102 +
  103 + /**
  104 + * 根据参数键名修改参数配置
  105 + */
  106 + @SaCheckPermission("system:config:edit")
  107 + @Log(title = "参数管理", businessType = BusinessType.UPDATE)
  108 + @PutMapping("/updateByKey")
  109 + public R<Void> updateByKey(@RequestBody SysConfig config) {
  110 + configService.updateConfig(config);
  111 + return R.ok();
  112 + }
  113 +
  114 + /**
  115 + * 删除参数配置
  116 + *
  117 + * @param configIds 参数ID串
  118 + */
  119 + @SaCheckPermission("system:config:remove")
  120 + @Log(title = "参数管理", businessType = BusinessType.DELETE)
  121 + @DeleteMapping("/{configIds}")
  122 + public R<Void> remove(@PathVariable Long[] configIds) {
  123 + configService.deleteConfigByIds(configIds);
  124 + return R.ok();
  125 + }
  126 +
  127 + /**
  128 + * 刷新参数缓存
  129 + */
  130 + @SaCheckPermission("system:config:remove")
  131 + @Log(title = "参数管理", businessType = BusinessType.CLEAN)
  132 + @DeleteMapping("/refreshCache")
  133 + public R<Void> refreshCache() {
  134 + configService.resetConfigCache();
  135 + return R.ok();
  136 + }
  137 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import cn.hutool.core.convert.Convert;
  5 +import com.ruoyi.common.annotation.Log;
  6 +import com.ruoyi.common.constant.UserConstants;
  7 +import com.ruoyi.common.core.controller.BaseController;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.domain.entity.SysDept;
  10 +import com.ruoyi.common.enums.BusinessType;
  11 +import com.ruoyi.common.utils.StringUtils;
  12 +import com.ruoyi.system.service.ISysDeptService;
  13 +import lombok.RequiredArgsConstructor;
  14 +import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.*;
  16 +
  17 +import java.util.List;
  18 +
  19 +/**
  20 + * 部门信息
  21 + *
  22 + * @author Lion Li
  23 + */
  24 +@Validated
  25 +@RequiredArgsConstructor
  26 +@RestController
  27 +@RequestMapping("/system/dept")
  28 +public class SysDeptController extends BaseController {
  29 +
  30 + private final ISysDeptService deptService;
  31 +
  32 + /**
  33 + * 获取部门列表
  34 + */
  35 + @SaCheckPermission("system:dept:list")
  36 + @GetMapping("/list")
  37 + public R<List<SysDept>> list(SysDept dept) {
  38 + List<SysDept> depts = deptService.selectDeptList(dept);
  39 + return R.ok(depts);
  40 + }
  41 +
  42 + /**
  43 + * 查询部门列表(排除节点)
  44 + *
  45 + * @param deptId 部门ID
  46 + */
  47 + @SaCheckPermission("system:dept:list")
  48 + @GetMapping("/list/exclude/{deptId}")
  49 + public R<List<SysDept>> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) {
  50 + List<SysDept> depts = deptService.selectDeptList(new SysDept());
  51 + depts.removeIf(d -> d.getDeptId().equals(deptId)
  52 + || StringUtils.splitList(d.getAncestors()).contains(Convert.toStr(deptId)));
  53 + return R.ok(depts);
  54 + }
  55 +
  56 + /**
  57 + * 根据部门编号获取详细信息
  58 + *
  59 + * @param deptId 部门ID
  60 + */
  61 + @SaCheckPermission("system:dept:query")
  62 + @GetMapping(value = "/{deptId}")
  63 + public R<SysDept> getInfo(@PathVariable Long deptId) {
  64 + deptService.checkDeptDataScope(deptId);
  65 + return R.ok(deptService.selectDeptById(deptId));
  66 + }
  67 +
  68 + /**
  69 + * 新增部门
  70 + */
  71 + @SaCheckPermission("system:dept:add")
  72 + @Log(title = "部门管理", businessType = BusinessType.INSERT)
  73 + @PostMapping
  74 + public R<Void> add(@Validated @RequestBody SysDept dept) {
  75 + if (!deptService.checkDeptNameUnique(dept)) {
  76 + return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
  77 + }
  78 + return toAjax(deptService.insertDept(dept));
  79 + }
  80 +
  81 + /**
  82 + * 修改部门
  83 + */
  84 + @SaCheckPermission("system:dept:edit")
  85 + @Log(title = "部门管理", businessType = BusinessType.UPDATE)
  86 + @PutMapping
  87 + public R<Void> edit(@Validated @RequestBody SysDept dept) {
  88 + Long deptId = dept.getDeptId();
  89 + deptService.checkDeptDataScope(deptId);
  90 + if (!deptService.checkDeptNameUnique(dept)) {
  91 + return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
  92 + } else if (dept.getParentId().equals(deptId)) {
  93 + return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
  94 + } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())) {
  95 + if (deptService.selectNormalChildrenDeptById(deptId) > 0) {
  96 + return R.fail("该部门包含未停用的子部门!");
  97 + } else if (deptService.checkDeptExistUser(deptId)) {
  98 + return R.fail("该部门下存在已分配用户,不能禁用!");
  99 + }
  100 + }
  101 + return toAjax(deptService.updateDept(dept));
  102 + }
  103 +
  104 + /**
  105 + * 删除部门
  106 + *
  107 + * @param deptId 部门ID
  108 + */
  109 + @SaCheckPermission("system:dept:remove")
  110 + @Log(title = "部门管理", businessType = BusinessType.DELETE)
  111 + @DeleteMapping("/{deptId}")
  112 + public R<Void> remove(@PathVariable Long deptId) {
  113 + if (deptService.hasChildByDeptId(deptId)) {
  114 + return R.warn("存在下级部门,不允许删除");
  115 + }
  116 + if (deptService.checkDeptExistUser(deptId)) {
  117 + return R.warn("部门存在用户,不允许删除");
  118 + }
  119 + deptService.checkDeptDataScope(deptId);
  120 + return toAjax(deptService.deleteDeptById(deptId));
  121 + }
  122 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import cn.hutool.core.util.ObjectUtil;
  5 +import com.ruoyi.common.annotation.Log;
  6 +import com.ruoyi.common.core.controller.BaseController;
  7 +import com.ruoyi.common.core.domain.PageQuery;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.domain.entity.SysDictData;
  10 +import com.ruoyi.common.core.page.TableDataInfo;
  11 +import com.ruoyi.common.enums.BusinessType;
  12 +import com.ruoyi.common.utils.poi.ExcelUtil;
  13 +import com.ruoyi.system.service.ISysDictDataService;
  14 +import com.ruoyi.system.service.ISysDictTypeService;
  15 +import lombok.RequiredArgsConstructor;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import javax.servlet.http.HttpServletResponse;
  20 +import java.util.ArrayList;
  21 +import java.util.List;
  22 +
  23 +/**
  24 + * 数据字典信息
  25 + *
  26 + * @author Lion Li
  27 + */
  28 +@Validated
  29 +@RequiredArgsConstructor
  30 +@RestController
  31 +@RequestMapping("/system/dict/data")
  32 +public class SysDictDataController extends BaseController {
  33 +
  34 + private final ISysDictDataService dictDataService;
  35 + private final ISysDictTypeService dictTypeService;
  36 +
  37 + /**
  38 + * 查询字典数据列表
  39 + */
  40 + @SaCheckPermission("system:dict:list")
  41 + @GetMapping("/list")
  42 + public TableDataInfo<SysDictData> list(SysDictData dictData, PageQuery pageQuery) {
  43 + return dictDataService.selectPageDictDataList(dictData, pageQuery);
  44 + }
  45 +
  46 + /**
  47 + * 导出字典数据列表
  48 + */
  49 + @Log(title = "字典数据", businessType = BusinessType.EXPORT)
  50 + @SaCheckPermission("system:dict:export")
  51 + @PostMapping("/export")
  52 + public void export(SysDictData dictData, HttpServletResponse response) {
  53 + List<SysDictData> list = dictDataService.selectDictDataList(dictData);
  54 + ExcelUtil.exportExcel(list, "字典数据", SysDictData.class, response);
  55 + }
  56 +
  57 + /**
  58 + * 查询字典数据详细
  59 + *
  60 + * @param dictCode 字典code
  61 + */
  62 + @SaCheckPermission("system:dict:query")
  63 + @GetMapping(value = "/{dictCode}")
  64 + public R<SysDictData> getInfo(@PathVariable Long dictCode) {
  65 + return R.ok(dictDataService.selectDictDataById(dictCode));
  66 + }
  67 +
  68 + /**
  69 + * 根据字典类型查询字典数据信息
  70 + *
  71 + * @param dictType 字典类型
  72 + */
  73 + @GetMapping(value = "/type/{dictType}")
  74 + public R<List<SysDictData>> dictType(@PathVariable String dictType) {
  75 + List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
  76 + if (ObjectUtil.isNull(data)) {
  77 + data = new ArrayList<>();
  78 + }
  79 + return R.ok(data);
  80 + }
  81 +
  82 + /**
  83 + * 新增字典类型
  84 + */
  85 + @SaCheckPermission("system:dict:add")
  86 + @Log(title = "字典数据", businessType = BusinessType.INSERT)
  87 + @PostMapping
  88 + public R<Void> add(@Validated @RequestBody SysDictData dict) {
  89 + dictDataService.insertDictData(dict);
  90 + return R.ok();
  91 + }
  92 +
  93 + /**
  94 + * 修改保存字典类型
  95 + */
  96 + @SaCheckPermission("system:dict:edit")
  97 + @Log(title = "字典数据", businessType = BusinessType.UPDATE)
  98 + @PutMapping
  99 + public R<Void> edit(@Validated @RequestBody SysDictData dict) {
  100 + dictDataService.updateDictData(dict);
  101 + return R.ok();
  102 + }
  103 +
  104 + /**
  105 + * 删除字典类型
  106 + *
  107 + * @param dictCodes 字典code串
  108 + */
  109 + @SaCheckPermission("system:dict:remove")
  110 + @Log(title = "字典类型", businessType = BusinessType.DELETE)
  111 + @DeleteMapping("/{dictCodes}")
  112 + public R<Void> remove(@PathVariable Long[] dictCodes) {
  113 + dictDataService.deleteDictDataByIds(dictCodes);
  114 + return R.ok();
  115 + }
  116 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import com.ruoyi.common.annotation.Log;
  5 +import com.ruoyi.common.constant.UserConstants;
  6 +import com.ruoyi.common.core.controller.BaseController;
  7 +import com.ruoyi.common.core.domain.PageQuery;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.domain.entity.SysDictType;
  10 +import com.ruoyi.common.core.page.TableDataInfo;
  11 +import com.ruoyi.common.enums.BusinessType;
  12 +import com.ruoyi.common.utils.poi.ExcelUtil;
  13 +import com.ruoyi.system.service.ISysDictTypeService;
  14 +import lombok.RequiredArgsConstructor;
  15 +import org.springframework.validation.annotation.Validated;
  16 +import org.springframework.web.bind.annotation.*;
  17 +
  18 +import javax.servlet.http.HttpServletResponse;
  19 +import java.util.List;
  20 +
  21 +/**
  22 + * 数据字典信息
  23 + *
  24 + * @author Lion Li
  25 + */
  26 +@Validated
  27 +@RequiredArgsConstructor
  28 +@RestController
  29 +@RequestMapping("/system/dict/type")
  30 +public class SysDictTypeController extends BaseController {
  31 +
  32 + private final ISysDictTypeService dictTypeService;
  33 +
  34 + /**
  35 + * 查询字典类型列表
  36 + */
  37 + @SaCheckPermission("system:dict:list")
  38 + @GetMapping("/list")
  39 + public TableDataInfo<SysDictType> list(SysDictType dictType, PageQuery pageQuery) {
  40 + return dictTypeService.selectPageDictTypeList(dictType, pageQuery);
  41 + }
  42 +
  43 + /**
  44 + * 导出字典类型列表
  45 + */
  46 + @Log(title = "字典类型", businessType = BusinessType.EXPORT)
  47 + @SaCheckPermission("system:dict:export")
  48 + @PostMapping("/export")
  49 + public void export(SysDictType dictType, HttpServletResponse response) {
  50 + List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
  51 + ExcelUtil.exportExcel(list, "字典类型", SysDictType.class, response);
  52 + }
  53 +
  54 + /**
  55 + * 查询字典类型详细
  56 + *
  57 + * @param dictId 字典ID
  58 + */
  59 + @SaCheckPermission("system:dict:query")
  60 + @GetMapping(value = "/{dictId}")
  61 + public R<SysDictType> getInfo(@PathVariable Long dictId) {
  62 + return R.ok(dictTypeService.selectDictTypeById(dictId));
  63 + }
  64 +
  65 + /**
  66 + * 新增字典类型
  67 + */
  68 + @SaCheckPermission("system:dict:add")
  69 + @Log(title = "字典类型", businessType = BusinessType.INSERT)
  70 + @PostMapping
  71 + public R<Void> add(@Validated @RequestBody SysDictType dict) {
  72 + if (!dictTypeService.checkDictTypeUnique(dict)) {
  73 + return R.fail("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
  74 + }
  75 + dictTypeService.insertDictType(dict);
  76 + return R.ok();
  77 + }
  78 +
  79 + /**
  80 + * 修改字典类型
  81 + */
  82 + @SaCheckPermission("system:dict:edit")
  83 + @Log(title = "字典类型", businessType = BusinessType.UPDATE)
  84 + @PutMapping
  85 + public R<Void> edit(@Validated @RequestBody SysDictType dict) {
  86 + if (!dictTypeService.checkDictTypeUnique(dict)) {
  87 + return R.fail("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
  88 + }
  89 + dictTypeService.updateDictType(dict);
  90 + return R.ok();
  91 + }
  92 +
  93 + /**
  94 + * 删除字典类型
  95 + *
  96 + * @param dictIds 字典ID串
  97 + */
  98 + @SaCheckPermission("system:dict:remove")
  99 + @Log(title = "字典类型", businessType = BusinessType.DELETE)
  100 + @DeleteMapping("/{dictIds}")
  101 + public R<Void> remove(@PathVariable Long[] dictIds) {
  102 + dictTypeService.deleteDictTypeByIds(dictIds);
  103 + return R.ok();
  104 + }
  105 +
  106 + /**
  107 + * 刷新字典缓存
  108 + */
  109 + @SaCheckPermission("system:dict:remove")
  110 + @Log(title = "字典类型", businessType = BusinessType.CLEAN)
  111 + @DeleteMapping("/refreshCache")
  112 + public R<Void> refreshCache() {
  113 + dictTypeService.resetDictCache();
  114 + return R.ok();
  115 + }
  116 +
  117 + /**
  118 + * 获取字典选择框列表
  119 + */
  120 + @GetMapping("/optionselect")
  121 + public R<List<SysDictType>> optionselect() {
  122 + List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
  123 + return R.ok(dictTypes);
  124 + }
  125 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaIgnore;
  4 +import com.ruoyi.common.config.RuoYiConfig;
  5 +import com.ruoyi.common.utils.StringUtils;
  6 +import lombok.RequiredArgsConstructor;
  7 +import org.springframework.web.bind.annotation.GetMapping;
  8 +import org.springframework.web.bind.annotation.RestController;
  9 +
  10 +/**
  11 + * 首页
  12 + *
  13 + * @author Lion Li
  14 + */
  15 +@RequiredArgsConstructor
  16 +@RestController
  17 +public class SysIndexController {
  18 +
  19 + /**
  20 + * 系统基础配置
  21 + */
  22 + private final RuoYiConfig ruoyiConfig;
  23 +
  24 + /**
  25 + * 访问首页,提示语
  26 + */
  27 + @SaIgnore
  28 + @GetMapping("/")
  29 + public String index() {
  30 + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());
  31 + }
  32 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaIgnore;
  4 +import com.ruoyi.common.constant.Constants;
  5 +import com.ruoyi.common.core.domain.R;
  6 +import com.ruoyi.common.core.domain.entity.SysMenu;
  7 +import com.ruoyi.common.core.domain.entity.SysUser;
  8 +import com.ruoyi.common.core.domain.model.EmailLoginBody;
  9 +import com.ruoyi.common.core.domain.model.LoginBody;
  10 +import com.ruoyi.common.core.domain.model.LoginUser;
  11 +import com.ruoyi.common.core.domain.model.SmsLoginBody;
  12 +import com.ruoyi.common.helper.LoginHelper;
  13 +import com.ruoyi.system.domain.vo.RouterVo;
  14 +import com.ruoyi.system.service.ISysMenuService;
  15 +import com.ruoyi.system.service.ISysUserService;
  16 +import com.ruoyi.system.service.SysLoginService;
  17 +import lombok.RequiredArgsConstructor;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.GetMapping;
  20 +import org.springframework.web.bind.annotation.PostMapping;
  21 +import org.springframework.web.bind.annotation.RequestBody;
  22 +import org.springframework.web.bind.annotation.RestController;
  23 +
  24 +import javax.validation.constraints.NotBlank;
  25 +import java.util.HashMap;
  26 +import java.util.List;
  27 +import java.util.Map;
  28 +
  29 +/**
  30 + * 登录验证
  31 + *
  32 + * @author Lion Li
  33 + */
  34 +@Validated
  35 +@RequiredArgsConstructor
  36 +@RestController
  37 +public class SysLoginController {
  38 +
  39 + private final SysLoginService loginService;
  40 + private final ISysMenuService menuService;
  41 + private final ISysUserService userService;
  42 +
  43 + /**
  44 + * 登录方法
  45 + *
  46 + * @param loginBody 登录信息
  47 + * @return 结果
  48 + */
  49 + @SaIgnore
  50 + @PostMapping("/login")
  51 + public R<Map<String, Object>> login(@Validated @RequestBody LoginBody loginBody) {
  52 + Map<String, Object> ajax = new HashMap<>();
  53 + // 生成令牌
  54 + String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
  55 + loginBody.getUuid());
  56 + ajax.put(Constants.TOKEN, token);
  57 + return R.ok(ajax);
  58 + }
  59 +
  60 + /**
  61 + * 短信登录
  62 + *
  63 + * @param smsLoginBody 登录信息
  64 + * @return 结果
  65 + */
  66 + @SaIgnore
  67 + @PostMapping("/smsLogin")
  68 + public R<Map<String, Object>> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) {
  69 + Map<String, Object> ajax = new HashMap<>();
  70 + // 生成令牌
  71 + String token = loginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode());
  72 + ajax.put(Constants.TOKEN, token);
  73 + return R.ok(ajax);
  74 + }
  75 +
  76 + /**
  77 + * 邮件登录
  78 + *
  79 + * @param body 登录信息
  80 + * @return 结果
  81 + */
  82 + @PostMapping("/emailLogin")
  83 + public R<Map<String, Object>> emailLogin(@Validated @RequestBody EmailLoginBody body) {
  84 + Map<String, Object> ajax = new HashMap<>();
  85 + // 生成令牌
  86 + String token = loginService.emailLogin(body.getEmail(), body.getEmailCode());
  87 + ajax.put(Constants.TOKEN, token);
  88 + return R.ok(ajax);
  89 + }
  90 +
  91 + /**
  92 + * 小程序登录(示例)
  93 + *
  94 + * @param xcxCode 小程序code
  95 + * @return 结果
  96 + */
  97 + @SaIgnore
  98 + @PostMapping("/xcxLogin")
  99 + public R<Map<String, Object>> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) {
  100 + Map<String, Object> ajax = new HashMap<>();
  101 + // 生成令牌
  102 + String token = loginService.xcxLogin(xcxCode);
  103 + ajax.put(Constants.TOKEN, token);
  104 + return R.ok(ajax);
  105 + }
  106 +
  107 + /**
  108 + * 退出登录
  109 + */
  110 + @SaIgnore
  111 + @PostMapping("/logout")
  112 + public R<Void> logout() {
  113 + loginService.logout();
  114 + return R.ok("退出成功");
  115 + }
  116 +
  117 + /**
  118 + * 获取用户信息
  119 + *
  120 + * @return 用户信息
  121 + */
  122 + @GetMapping("getInfo")
  123 + public R<Map<String, Object>> getInfo() {
  124 + LoginUser loginUser = LoginHelper.getLoginUser();
  125 + SysUser user = userService.selectUserById(loginUser.getUserId());
  126 + Map<String, Object> ajax = new HashMap<>();
  127 + ajax.put("user", user);
  128 + ajax.put("roles", loginUser.getRolePermission());
  129 + ajax.put("permissions", loginUser.getMenuPermission());
  130 + return R.ok(ajax);
  131 + }
  132 +
  133 + /**
  134 + * 获取路由信息
  135 + *
  136 + * @return 路由信息
  137 + */
  138 + @GetMapping("getRouters")
  139 + public R<List<RouterVo>> getRouters() {
  140 + Long userId = LoginHelper.getUserId();
  141 + List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
  142 + return R.ok(menuService.buildMenus(menus));
  143 + }
  144 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import cn.hutool.core.lang.tree.Tree;
  5 +import com.ruoyi.common.annotation.Log;
  6 +import com.ruoyi.common.constant.UserConstants;
  7 +import com.ruoyi.common.core.controller.BaseController;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.domain.entity.SysMenu;
  10 +import com.ruoyi.common.enums.BusinessType;
  11 +import com.ruoyi.common.utils.StringUtils;
  12 +import com.ruoyi.system.service.ISysMenuService;
  13 +import lombok.RequiredArgsConstructor;
  14 +import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.*;
  16 +
  17 +import java.util.HashMap;
  18 +import java.util.List;
  19 +import java.util.Map;
  20 +
  21 +/**
  22 + * 菜单信息
  23 + *
  24 + * @author Lion Li
  25 + */
  26 +@Validated
  27 +@RequiredArgsConstructor
  28 +@RestController
  29 +@RequestMapping("/system/menu")
  30 +public class SysMenuController extends BaseController {
  31 +
  32 + private final ISysMenuService menuService;
  33 +
  34 + /**
  35 + * 获取菜单列表
  36 + */
  37 + @SaCheckPermission("system:menu:list")
  38 + @GetMapping("/list")
  39 + public R<List<SysMenu>> list(SysMenu menu) {
  40 + List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
  41 + return R.ok(menus);
  42 + }
  43 +
  44 + /**
  45 + * 根据菜单编号获取详细信息
  46 + *
  47 + * @param menuId 菜单ID
  48 + */
  49 + @SaCheckPermission("system:menu:query")
  50 + @GetMapping(value = "/{menuId}")
  51 + public R<SysMenu> getInfo(@PathVariable Long menuId) {
  52 + return R.ok(menuService.selectMenuById(menuId));
  53 + }
  54 +
  55 + /**
  56 + * 获取菜单下拉树列表
  57 + */
  58 + @GetMapping("/treeselect")
  59 + public R<List<Tree<Long>>> treeselect(SysMenu menu) {
  60 + List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
  61 + return R.ok(menuService.buildMenuTreeSelect(menus));
  62 + }
  63 +
  64 + /**
  65 + * 加载对应角色菜单列表树
  66 + *
  67 + * @param roleId 角色ID
  68 + */
  69 + @GetMapping(value = "/roleMenuTreeselect/{roleId}")
  70 + public R<Map<String, Object>> roleMenuTreeselect(@PathVariable("roleId") Long roleId) {
  71 + List<SysMenu> menus = menuService.selectMenuList(getUserId());
  72 + Map<String, Object> ajax = new HashMap<>();
  73 + ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
  74 + ajax.put("menus", menuService.buildMenuTreeSelect(menus));
  75 + return R.ok(ajax);
  76 + }
  77 +
  78 + /**
  79 + * 新增菜单
  80 + */
  81 + @SaCheckPermission("system:menu:add")
  82 + @Log(title = "菜单管理", businessType = BusinessType.INSERT)
  83 + @PostMapping
  84 + public R<Void> add(@Validated @RequestBody SysMenu menu) {
  85 + if (!menuService.checkMenuNameUnique(menu)) {
  86 + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
  87 + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
  88 + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
  89 + }
  90 + return toAjax(menuService.insertMenu(menu));
  91 + }
  92 +
  93 + /**
  94 + * 修改菜单
  95 + */
  96 + @SaCheckPermission("system:menu:edit")
  97 + @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
  98 + @PutMapping
  99 + public R<Void> edit(@Validated @RequestBody SysMenu menu) {
  100 + if (!menuService.checkMenuNameUnique(menu)) {
  101 + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
  102 + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
  103 + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
  104 + } else if (menu.getMenuId().equals(menu.getParentId())) {
  105 + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
  106 + }
  107 + return toAjax(menuService.updateMenu(menu));
  108 + }
  109 +
  110 + /**
  111 + * 删除菜单
  112 + *
  113 + * @param menuId 菜单ID
  114 + */
  115 + @SaCheckPermission("system:menu:remove")
  116 + @Log(title = "菜单管理", businessType = BusinessType.DELETE)
  117 + @DeleteMapping("/{menuId}")
  118 + public R<Void> remove(@PathVariable("menuId") Long menuId) {
  119 + if (menuService.hasChildByMenuId(menuId)) {
  120 + return R.warn("存在子菜单,不允许删除");
  121 + }
  122 + if (menuService.checkMenuExistRole(menuId)) {
  123 + return R.warn("菜单已分配,不允许删除");
  124 + }
  125 + return toAjax(menuService.deleteMenuById(menuId));
  126 + }
  127 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import com.ruoyi.common.annotation.Log;
  5 +import com.ruoyi.common.core.controller.BaseController;
  6 +import com.ruoyi.common.core.domain.PageQuery;
  7 +import com.ruoyi.common.core.domain.R;
  8 +import com.ruoyi.common.core.page.TableDataInfo;
  9 +import com.ruoyi.common.enums.BusinessType;
  10 +import com.ruoyi.system.domain.SysNotice;
  11 +import com.ruoyi.system.service.ISysNoticeService;
  12 +import lombok.RequiredArgsConstructor;
  13 +import org.springframework.validation.annotation.Validated;
  14 +import org.springframework.web.bind.annotation.*;
  15 +
  16 +/**
  17 + * 公告 信息操作处理
  18 + *
  19 + * @author Lion Li
  20 + */
  21 +@Validated
  22 +@RequiredArgsConstructor
  23 +@RestController
  24 +@RequestMapping("/system/notice")
  25 +public class SysNoticeController extends BaseController {
  26 +
  27 + private final ISysNoticeService noticeService;
  28 +
  29 + /**
  30 + * 获取通知公告列表
  31 + */
  32 + @SaCheckPermission("system:notice:list")
  33 + @GetMapping("/list")
  34 + public TableDataInfo<SysNotice> list(SysNotice notice, PageQuery pageQuery) {
  35 + return noticeService.selectPageNoticeList(notice, pageQuery);
  36 + }
  37 +
  38 + /**
  39 + * 根据通知公告编号获取详细信息
  40 + *
  41 + * @param noticeId 公告ID
  42 + */
  43 + @SaCheckPermission("system:notice:query")
  44 + @GetMapping(value = "/{noticeId}")
  45 + public R<SysNotice> getInfo(@PathVariable Long noticeId) {
  46 + return R.ok(noticeService.selectNoticeById(noticeId));
  47 + }
  48 +
  49 + /**
  50 + * 新增通知公告
  51 + */
  52 + @SaCheckPermission("system:notice:add")
  53 + @Log(title = "通知公告", businessType = BusinessType.INSERT)
  54 + @PostMapping
  55 + public R<Void> add(@Validated @RequestBody SysNotice notice) {
  56 + return toAjax(noticeService.insertNotice(notice));
  57 + }
  58 +
  59 + /**
  60 + * 修改通知公告
  61 + */
  62 + @SaCheckPermission("system:notice:edit")
  63 + @Log(title = "通知公告", businessType = BusinessType.UPDATE)
  64 + @PutMapping
  65 + public R<Void> edit(@Validated @RequestBody SysNotice notice) {
  66 + return toAjax(noticeService.updateNotice(notice));
  67 + }
  68 +
  69 + /**
  70 + * 删除通知公告
  71 + *
  72 + * @param noticeIds 公告ID串
  73 + */
  74 + @SaCheckPermission("system:notice:remove")
  75 + @Log(title = "通知公告", businessType = BusinessType.DELETE)
  76 + @DeleteMapping("/{noticeIds}")
  77 + public R<Void> remove(@PathVariable Long[] noticeIds) {
  78 + return toAjax(noticeService.deleteNoticeByIds(noticeIds));
  79 + }
  80 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import com.ruoyi.common.annotation.Log;
  5 +import com.ruoyi.common.annotation.RepeatSubmit;
  6 +import com.ruoyi.common.core.controller.BaseController;
  7 +import com.ruoyi.common.core.domain.PageQuery;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.page.TableDataInfo;
  10 +import com.ruoyi.common.core.validate.AddGroup;
  11 +import com.ruoyi.common.core.validate.EditGroup;
  12 +import com.ruoyi.common.core.validate.QueryGroup;
  13 +import com.ruoyi.common.enums.BusinessType;
  14 +import com.ruoyi.system.domain.bo.SysOssConfigBo;
  15 +import com.ruoyi.system.domain.vo.SysOssConfigVo;
  16 +import com.ruoyi.system.service.ISysOssConfigService;
  17 +import lombok.RequiredArgsConstructor;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import javax.validation.constraints.NotEmpty;
  22 +import javax.validation.constraints.NotNull;
  23 +import java.util.Arrays;
  24 +
  25 +/**
  26 + * 对象存储配置
  27 + *
  28 + * @author Lion Li
  29 + * @author 孤舟烟雨
  30 + * @date 2021-08-13
  31 + */
  32 +@Validated
  33 +@RequiredArgsConstructor
  34 +@RestController
  35 +@RequestMapping("/system/oss/config")
  36 +public class SysOssConfigController extends BaseController {
  37 +
  38 + private final ISysOssConfigService iSysOssConfigService;
  39 +
  40 + /**
  41 + * 查询对象存储配置列表
  42 + */
  43 + @SaCheckPermission("system:oss:list")
  44 + @GetMapping("/list")
  45 + public TableDataInfo<SysOssConfigVo> list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) {
  46 + return iSysOssConfigService.queryPageList(bo, pageQuery);
  47 + }
  48 +
  49 + /**
  50 + * 获取对象存储配置详细信息
  51 + *
  52 + * @param ossConfigId OSS配置ID
  53 + */
  54 + @SaCheckPermission("system:oss:query")
  55 + @GetMapping("/{ossConfigId}")
  56 + public R<SysOssConfigVo> getInfo(@NotNull(message = "主键不能为空")
  57 + @PathVariable Long ossConfigId) {
  58 + return R.ok(iSysOssConfigService.queryById(ossConfigId));
  59 + }
  60 +
  61 + /**
  62 + * 新增对象存储配置
  63 + */
  64 + @SaCheckPermission("system:oss:add")
  65 + @Log(title = "对象存储配置", businessType = BusinessType.INSERT)
  66 + @RepeatSubmit()
  67 + @PostMapping()
  68 + public R<Void> add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) {
  69 + return toAjax(iSysOssConfigService.insertByBo(bo));
  70 + }
  71 +
  72 + /**
  73 + * 修改对象存储配置
  74 + */
  75 + @SaCheckPermission("system:oss:edit")
  76 + @Log(title = "对象存储配置", businessType = BusinessType.UPDATE)
  77 + @RepeatSubmit()
  78 + @PutMapping()
  79 + public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) {
  80 + return toAjax(iSysOssConfigService.updateByBo(bo));
  81 + }
  82 +
  83 + /**
  84 + * 删除对象存储配置
  85 + *
  86 + * @param ossConfigIds OSS配置ID串
  87 + */
  88 + @SaCheckPermission("system:oss:remove")
  89 + @Log(title = "对象存储配置", businessType = BusinessType.DELETE)
  90 + @DeleteMapping("/{ossConfigIds}")
  91 + public R<Void> remove(@NotEmpty(message = "主键不能为空")
  92 + @PathVariable Long[] ossConfigIds) {
  93 + return toAjax(iSysOssConfigService.deleteWithValidByIds(Arrays.asList(ossConfigIds), true));
  94 + }
  95 +
  96 + /**
  97 + * 状态修改
  98 + */
  99 + @SaCheckPermission("system:oss:edit")
  100 + @Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE)
  101 + @PutMapping("/changeStatus")
  102 + public R<Void> changeStatus(@RequestBody SysOssConfigBo bo) {
  103 + return toAjax(iSysOssConfigService.updateOssConfigStatus(bo));
  104 + }
  105 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +
  4 +import cn.dev33.satoken.annotation.SaCheckPermission;
  5 +import cn.hutool.core.util.ObjectUtil;
  6 +import com.ruoyi.common.annotation.Log;
  7 +import com.ruoyi.common.core.controller.BaseController;
  8 +import com.ruoyi.common.core.domain.PageQuery;
  9 +import com.ruoyi.common.core.domain.R;
  10 +import com.ruoyi.common.core.page.TableDataInfo;
  11 +import com.ruoyi.common.core.validate.QueryGroup;
  12 +import com.ruoyi.common.enums.BusinessType;
  13 +import com.ruoyi.system.domain.bo.SysOssBo;
  14 +import com.ruoyi.system.domain.vo.SysOssVo;
  15 +import com.ruoyi.system.service.ISysOssService;
  16 +import lombok.RequiredArgsConstructor;
  17 +import org.springframework.http.MediaType;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
  20 +import org.springframework.web.multipart.MultipartFile;
  21 +
  22 +import javax.servlet.http.HttpServletResponse;
  23 +import javax.validation.constraints.NotEmpty;
  24 +import java.io.IOException;
  25 +import java.util.Arrays;
  26 +import java.util.HashMap;
  27 +import java.util.List;
  28 +import java.util.Map;
  29 +
  30 +/**
  31 + * 文件上传 控制层
  32 + *
  33 + * @author Lion Li
  34 + */
  35 +@Validated
  36 +@RequiredArgsConstructor
  37 +@RestController
  38 +@RequestMapping("/system/oss")
  39 +public class SysOssController extends BaseController {
  40 +
  41 + private final ISysOssService iSysOssService;
  42 +
  43 + /**
  44 + * 查询OSS对象存储列表
  45 + */
  46 + @SaCheckPermission("system:oss:list")
  47 + @GetMapping("/list")
  48 + public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) {
  49 + return iSysOssService.queryPageList(bo, pageQuery);
  50 + }
  51 +
  52 + /**
  53 + * 查询OSS对象基于id串
  54 + *
  55 + * @param ossIds OSS对象ID串
  56 + */
  57 + @SaCheckPermission("system:oss:list")
  58 + @GetMapping("/listByIds/{ossIds}")
  59 + public R<List<SysOssVo>> listByIds(@NotEmpty(message = "主键不能为空")
  60 + @PathVariable Long[] ossIds) {
  61 + List<SysOssVo> list = iSysOssService.listByIds(Arrays.asList(ossIds));
  62 + return R.ok(list);
  63 + }
  64 +
  65 + /**
  66 + * 上传OSS对象存储
  67 + *
  68 + * @param file 文件
  69 + */
  70 + @SaCheckPermission("system:oss:upload")
  71 + @Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
  72 + @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  73 + public R<Map<String, String>> upload(@RequestPart("file") MultipartFile file) {
  74 + if (ObjectUtil.isNull(file)) {
  75 + return R.fail("上传文件不能为空");
  76 + }
  77 + SysOssVo oss = iSysOssService.upload(file);
  78 + Map<String, String> map = new HashMap<>(2);
  79 + map.put("url", oss.getUrl());
  80 + map.put("fileName", oss.getOriginalName());
  81 + map.put("ossId", oss.getOssId().toString());
  82 + return R.ok(map);
  83 + }
  84 +
  85 + /**
  86 + * 下载OSS对象
  87 + *
  88 + * @param ossId OSS对象ID
  89 + */
  90 + @SaCheckPermission("system:oss:download")
  91 + @GetMapping("/download/{ossId}")
  92 + public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
  93 + iSysOssService.download(ossId,response);
  94 + }
  95 +
  96 + /**
  97 + * 删除OSS对象存储
  98 + *
  99 + * @param ossIds OSS对象ID串
  100 + */
  101 + @SaCheckPermission("system:oss:remove")
  102 + @Log(title = "OSS对象存储", businessType = BusinessType.DELETE)
  103 + @DeleteMapping("/{ossIds}")
  104 + public R<Void> remove(@NotEmpty(message = "主键不能为空")
  105 + @PathVariable Long[] ossIds) {
  106 + return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true));
  107 + }
  108 +
  109 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import com.ruoyi.common.annotation.Log;
  5 +import com.ruoyi.common.constant.UserConstants;
  6 +import com.ruoyi.common.core.controller.BaseController;
  7 +import com.ruoyi.common.core.domain.PageQuery;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.page.TableDataInfo;
  10 +import com.ruoyi.common.enums.BusinessType;
  11 +import com.ruoyi.common.utils.poi.ExcelUtil;
  12 +import com.ruoyi.system.domain.SysPost;
  13 +import com.ruoyi.system.service.ISysPostService;
  14 +import lombok.RequiredArgsConstructor;
  15 +import org.springframework.validation.annotation.Validated;
  16 +import org.springframework.web.bind.annotation.*;
  17 +
  18 +import javax.servlet.http.HttpServletResponse;
  19 +import java.util.List;
  20 +
  21 +/**
  22 + * 岗位信息操作处理
  23 + *
  24 + * @author Lion Li
  25 + */
  26 +@Validated
  27 +@RequiredArgsConstructor
  28 +@RestController
  29 +@RequestMapping("/system/post")
  30 +public class SysPostController extends BaseController {
  31 +
  32 + private final ISysPostService postService;
  33 +
  34 + /**
  35 + * 获取岗位列表
  36 + */
  37 + @SaCheckPermission("system:post:list")
  38 + @GetMapping("/list")
  39 + public TableDataInfo<SysPost> list(SysPost post, PageQuery pageQuery) {
  40 + return postService.selectPagePostList(post, pageQuery);
  41 + }
  42 +
  43 + /**
  44 + * 导出岗位列表
  45 + */
  46 + @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
  47 + @SaCheckPermission("system:post:export")
  48 + @PostMapping("/export")
  49 + public void export(SysPost post, HttpServletResponse response) {
  50 + List<SysPost> list = postService.selectPostList(post);
  51 + ExcelUtil.exportExcel(list, "岗位数据", SysPost.class, response);
  52 + }
  53 +
  54 + /**
  55 + * 根据岗位编号获取详细信息
  56 + *
  57 + * @param postId 岗位ID
  58 + */
  59 + @SaCheckPermission("system:post:query")
  60 + @GetMapping(value = "/{postId}")
  61 + public R<SysPost> getInfo(@PathVariable Long postId) {
  62 + return R.ok(postService.selectPostById(postId));
  63 + }
  64 +
  65 + /**
  66 + * 新增岗位
  67 + */
  68 + @SaCheckPermission("system:post:add")
  69 + @Log(title = "岗位管理", businessType = BusinessType.INSERT)
  70 + @PostMapping
  71 + public R<Void> add(@Validated @RequestBody SysPost post) {
  72 + if (!postService.checkPostNameUnique(post)) {
  73 + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
  74 + } else if (!postService.checkPostCodeUnique(post)) {
  75 + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
  76 + }
  77 + return toAjax(postService.insertPost(post));
  78 + }
  79 +
  80 + /**
  81 + * 修改岗位
  82 + */
  83 + @SaCheckPermission("system:post:edit")
  84 + @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
  85 + @PutMapping
  86 + public R<Void> edit(@Validated @RequestBody SysPost post) {
  87 + if (!postService.checkPostNameUnique(post)) {
  88 + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
  89 + } else if (!postService.checkPostCodeUnique(post)) {
  90 + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
  91 + } else if (UserConstants.POST_DISABLE.equals(post.getStatus())
  92 + && postService.countUserPostById(post.getPostId()) > 0) {
  93 + return R.fail("该岗位下存在已分配用户,不能禁用!");
  94 + }
  95 + return toAjax(postService.updatePost(post));
  96 + }
  97 +
  98 + /**
  99 + * 删除岗位
  100 + *
  101 + * @param postIds 岗位ID串
  102 + */
  103 + @SaCheckPermission("system:post:remove")
  104 + @Log(title = "岗位管理", businessType = BusinessType.DELETE)
  105 + @DeleteMapping("/{postIds}")
  106 + public R<Void> remove(@PathVariable Long[] postIds) {
  107 + return toAjax(postService.deletePostByIds(postIds));
  108 + }
  109 +
  110 + /**
  111 + * 获取岗位选择框列表
  112 + */
  113 + @GetMapping("/optionselect")
  114 + public R<List<SysPost>> optionselect() {
  115 + SysPost post = new SysPost();
  116 + post.setStatus(UserConstants.POST_NORMAL);
  117 + List<SysPost> posts = postService.selectPostList(post);
  118 + return R.ok(posts);
  119 + }
  120 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.secure.BCrypt;
  4 +import cn.hutool.core.io.FileUtil;
  5 +import com.ruoyi.common.annotation.Log;
  6 +import com.ruoyi.common.constant.UserConstants;
  7 +import com.ruoyi.common.core.controller.BaseController;
  8 +import com.ruoyi.common.core.domain.R;
  9 +import com.ruoyi.common.core.domain.entity.SysUser;
  10 +import com.ruoyi.common.enums.BusinessType;
  11 +import com.ruoyi.common.helper.LoginHelper;
  12 +import com.ruoyi.common.utils.StringUtils;
  13 +import com.ruoyi.common.utils.file.MimeTypeUtils;
  14 +import com.ruoyi.system.domain.SysOss;
  15 +import com.ruoyi.system.domain.vo.SysOssVo;
  16 +import com.ruoyi.system.service.ISysOssService;
  17 +import com.ruoyi.system.service.ISysUserService;
  18 +import lombok.RequiredArgsConstructor;
  19 +import org.springframework.http.MediaType;
  20 +import org.springframework.validation.annotation.Validated;
  21 +import org.springframework.web.bind.annotation.*;
  22 +import org.springframework.web.multipart.MultipartFile;
  23 +
  24 +import java.util.Arrays;
  25 +import java.util.HashMap;
  26 +import java.util.Map;
  27 +
  28 +/**
  29 + * 个人信息 业务处理
  30 + *
  31 + * @author Lion Li
  32 + */
  33 +@Validated
  34 +@RequiredArgsConstructor
  35 +@RestController
  36 +@RequestMapping("/system/user/profile")
  37 +public class SysProfileController extends BaseController {
  38 +
  39 + private final ISysUserService userService;
  40 + private final ISysOssService iSysOssService;
  41 +
  42 + /**
  43 + * 个人信息
  44 + */
  45 + @GetMapping
  46 + public R<Map<String, Object>> profile() {
  47 + SysUser user = userService.selectUserById(getUserId());
  48 + Map<String, Object> ajax = new HashMap<>();
  49 + ajax.put("user", user);
  50 + ajax.put("roleGroup", userService.selectUserRoleGroup(user.getUserName()));
  51 + ajax.put("postGroup", userService.selectUserPostGroup(user.getUserName()));
  52 + return R.ok(ajax);
  53 + }
  54 +
  55 + /**
  56 + * 修改用户
  57 + */
  58 + @Log(title = "个人信息", businessType = BusinessType.UPDATE)
  59 + @PutMapping
  60 + public R<Void> updateProfile(@RequestBody SysUser user) {
  61 + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
  62 + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
  63 + }
  64 + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
  65 + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
  66 + }
  67 + user.setUserId(getUserId());
  68 + user.setUserName(null);
  69 + user.setPassword(null);
  70 + user.setAvatar(null);
  71 + user.setDeptId(null);
  72 + if (userService.updateUserProfile(user) > 0) {
  73 + return R.ok();
  74 + }
  75 + return R.fail("修改个人信息异常,请联系管理员");
  76 + }
  77 +
  78 + /**
  79 + * 重置密码
  80 + *
  81 + * @param newPassword 新密码
  82 + * @param oldPassword 旧密码
  83 + */
  84 + @Log(title = "个人信息", businessType = BusinessType.UPDATE)
  85 + @PutMapping("/updatePwd")
  86 + public R<Void> updatePwd(String oldPassword, String newPassword) {
  87 + SysUser user = userService.selectUserById(LoginHelper.getUserId());
  88 + String userName = user.getUserName();
  89 + String password = user.getPassword();
  90 + if (!BCrypt.checkpw(oldPassword, password)) {
  91 + return R.fail("修改密码失败,旧密码错误");
  92 + }
  93 + if (BCrypt.checkpw(newPassword, password)) {
  94 + return R.fail("新密码不能与旧密码相同");
  95 + }
  96 +
  97 + if (userService.resetUserPwd(userName, BCrypt.hashpw(newPassword)) > 0) {
  98 + return R.ok();
  99 + }
  100 + return R.fail("修改密码异常,请联系管理员");
  101 + }
  102 +
  103 + /**
  104 + * 头像上传
  105 + *
  106 + * @param avatarfile 用户头像
  107 + */
  108 + @Log(title = "用户头像", businessType = BusinessType.UPDATE)
  109 + @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  110 + public R<Map<String, Object>> avatar(@RequestPart("avatarfile") MultipartFile avatarfile) {
  111 + Map<String, Object> ajax = new HashMap<>();
  112 + if (!avatarfile.isEmpty()) {
  113 + String extension = FileUtil.extName(avatarfile.getOriginalFilename());
  114 + if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) {
  115 + return R.fail("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式");
  116 + }
  117 + SysOssVo oss = iSysOssService.upload(avatarfile);
  118 + String avatar = oss.getUrl();
  119 + if (userService.updateUserAvatar(getUsername(), avatar)) {
  120 + ajax.put("imgUrl", avatar);
  121 + return R.ok(ajax);
  122 + }
  123 + }
  124 + return R.fail("上传图片异常,请联系管理员");
  125 + }
  126 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaIgnore;
  4 +import com.ruoyi.common.core.controller.BaseController;
  5 +import com.ruoyi.common.core.domain.R;
  6 +import com.ruoyi.common.core.domain.model.RegisterBody;
  7 +import com.ruoyi.system.service.ISysConfigService;
  8 +import com.ruoyi.system.service.SysRegisterService;
  9 +import lombok.RequiredArgsConstructor;
  10 +import org.springframework.validation.annotation.Validated;
  11 +import org.springframework.web.bind.annotation.PostMapping;
  12 +import org.springframework.web.bind.annotation.RequestBody;
  13 +import org.springframework.web.bind.annotation.RestController;
  14 +
  15 +/**
  16 + * 注册验证
  17 + *
  18 + * @author Lion Li
  19 + */
  20 +@Validated
  21 +@RequiredArgsConstructor
  22 +@RestController
  23 +public class SysRegisterController extends BaseController {
  24 +
  25 + private final SysRegisterService registerService;
  26 + private final ISysConfigService configService;
  27 +
  28 + /**
  29 + * 用户注册
  30 + */
  31 + @SaIgnore
  32 + @PostMapping("/register")
  33 + public R<Void> register(@Validated @RequestBody RegisterBody user) {
  34 + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
  35 + return R.fail("当前系统没有开启注册功能!");
  36 + }
  37 + registerService.register(user);
  38 + return R.ok();
  39 + }
  40 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import com.ruoyi.common.annotation.Log;
  5 +import com.ruoyi.common.core.controller.BaseController;
  6 +import com.ruoyi.common.core.domain.PageQuery;
  7 +import com.ruoyi.common.core.domain.R;
  8 +import com.ruoyi.common.core.domain.entity.SysDept;
  9 +import com.ruoyi.common.core.domain.entity.SysRole;
  10 +import com.ruoyi.common.core.domain.entity.SysUser;
  11 +import com.ruoyi.common.core.page.TableDataInfo;
  12 +import com.ruoyi.common.enums.BusinessType;
  13 +import com.ruoyi.common.utils.poi.ExcelUtil;
  14 +import com.ruoyi.system.domain.SysUserRole;
  15 +import com.ruoyi.system.service.ISysDeptService;
  16 +import com.ruoyi.system.service.ISysRoleService;
  17 +import com.ruoyi.system.service.ISysUserService;
  18 +import com.ruoyi.system.service.SysPermissionService;
  19 +import lombok.RequiredArgsConstructor;
  20 +import org.springframework.validation.annotation.Validated;
  21 +import org.springframework.web.bind.annotation.*;
  22 +
  23 +import javax.servlet.http.HttpServletResponse;
  24 +import java.util.HashMap;
  25 +import java.util.List;
  26 +import java.util.Map;
  27 +
  28 +/**
  29 + * 角色信息
  30 + *
  31 + * @author Lion Li
  32 + */
  33 +@Validated
  34 +@RequiredArgsConstructor
  35 +@RestController
  36 +@RequestMapping("/system/role")
  37 +public class SysRoleController extends BaseController {
  38 +
  39 + private final ISysRoleService roleService;
  40 + private final ISysUserService userService;
  41 + private final ISysDeptService deptService;
  42 + private final SysPermissionService permissionService;
  43 +
  44 + /**
  45 + * 获取角色信息列表
  46 + */
  47 + @SaCheckPermission("system:role:list")
  48 + @GetMapping("/list")
  49 + public TableDataInfo<SysRole> list(SysRole role, PageQuery pageQuery) {
  50 + return roleService.selectPageRoleList(role, pageQuery);
  51 + }
  52 +
  53 + /**
  54 + * 导出角色信息列表
  55 + */
  56 + @Log(title = "角色管理", businessType = BusinessType.EXPORT)
  57 + @SaCheckPermission("system:role:export")
  58 + @PostMapping("/export")
  59 + public void export(SysRole role, HttpServletResponse response) {
  60 + List<SysRole> list = roleService.selectRoleList(role);
  61 + ExcelUtil.exportExcel(list, "角色数据", SysRole.class, response);
  62 + }
  63 +
  64 + /**
  65 + * 根据角色编号获取详细信息
  66 + *
  67 + * @param roleId 角色ID
  68 + */
  69 + @SaCheckPermission("system:role:query")
  70 + @GetMapping(value = "/{roleId}")
  71 + public R<SysRole> getInfo(@PathVariable Long roleId) {
  72 + roleService.checkRoleDataScope(roleId);
  73 + return R.ok(roleService.selectRoleById(roleId));
  74 + }
  75 +
  76 + /**
  77 + * 新增角色
  78 + */
  79 + @SaCheckPermission("system:role:add")
  80 + @Log(title = "角色管理", businessType = BusinessType.INSERT)
  81 + @PostMapping
  82 + public R<Void> add(@Validated @RequestBody SysRole role) {
  83 + roleService.checkRoleAllowed(role);
  84 + if (!roleService.checkRoleNameUnique(role)) {
  85 + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
  86 + } else if (!roleService.checkRoleKeyUnique(role)) {
  87 + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
  88 + }
  89 + return toAjax(roleService.insertRole(role));
  90 +
  91 + }
  92 +
  93 + /**
  94 + * 修改保存角色
  95 + */
  96 + @SaCheckPermission("system:role:edit")
  97 + @Log(title = "角色管理", businessType = BusinessType.UPDATE)
  98 + @PutMapping
  99 + public R<Void> edit(@Validated @RequestBody SysRole role) {
  100 + roleService.checkRoleAllowed(role);
  101 + roleService.checkRoleDataScope(role.getRoleId());
  102 + if (!roleService.checkRoleNameUnique(role)) {
  103 + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
  104 + } else if (!roleService.checkRoleKeyUnique(role)) {
  105 + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
  106 + }
  107 +
  108 + if (roleService.updateRole(role) > 0) {
  109 + roleService.cleanOnlineUserByRole(role.getRoleId());
  110 + return R.ok();
  111 + }
  112 + return R.fail("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
  113 + }
  114 +
  115 + /**
  116 + * 修改保存数据权限
  117 + */
  118 + @SaCheckPermission("system:role:edit")
  119 + @Log(title = "角色管理", businessType = BusinessType.UPDATE)
  120 + @PutMapping("/dataScope")
  121 + public R<Void> dataScope(@RequestBody SysRole role) {
  122 + roleService.checkRoleAllowed(role);
  123 + roleService.checkRoleDataScope(role.getRoleId());
  124 + return toAjax(roleService.authDataScope(role));
  125 + }
  126 +
  127 + /**
  128 + * 状态修改
  129 + */
  130 + @SaCheckPermission("system:role:edit")
  131 + @Log(title = "角色管理", businessType = BusinessType.UPDATE)
  132 + @PutMapping("/changeStatus")
  133 + public R<Void> changeStatus(@RequestBody SysRole role) {
  134 + roleService.checkRoleAllowed(role);
  135 + roleService.checkRoleDataScope(role.getRoleId());
  136 + return toAjax(roleService.updateRoleStatus(role));
  137 + }
  138 +
  139 + /**
  140 + * 删除角色
  141 + *
  142 + * @param roleIds 角色ID串
  143 + */
  144 + @SaCheckPermission("system:role:remove")
  145 + @Log(title = "角色管理", businessType = BusinessType.DELETE)
  146 + @DeleteMapping("/{roleIds}")
  147 + public R<Void> remove(@PathVariable Long[] roleIds) {
  148 + return toAjax(roleService.deleteRoleByIds(roleIds));
  149 + }
  150 +
  151 + /**
  152 + * 获取角色选择框列表
  153 + */
  154 + @SaCheckPermission("system:role:query")
  155 + @GetMapping("/optionselect")
  156 + public R<List<SysRole>> optionselect() {
  157 + return R.ok(roleService.selectRoleAll());
  158 + }
  159 +
  160 + /**
  161 + * 查询已分配用户角色列表
  162 + */
  163 + @SaCheckPermission("system:role:list")
  164 + @GetMapping("/authUser/allocatedList")
  165 + public TableDataInfo<SysUser> allocatedList(SysUser user, PageQuery pageQuery) {
  166 + return userService.selectAllocatedList(user, pageQuery);
  167 + }
  168 +
  169 + /**
  170 + * 查询未分配用户角色列表
  171 + */
  172 + @SaCheckPermission("system:role:list")
  173 + @GetMapping("/authUser/unallocatedList")
  174 + public TableDataInfo<SysUser> unallocatedList(SysUser user, PageQuery pageQuery) {
  175 + return userService.selectUnallocatedList(user, pageQuery);
  176 + }
  177 +
  178 + /**
  179 + * 取消授权用户
  180 + */
  181 + @SaCheckPermission("system:role:edit")
  182 + @Log(title = "角色管理", businessType = BusinessType.GRANT)
  183 + @PutMapping("/authUser/cancel")
  184 + public R<Void> cancelAuthUser(@RequestBody SysUserRole userRole) {
  185 + return toAjax(roleService.deleteAuthUser(userRole));
  186 + }
  187 +
  188 + /**
  189 + * 批量取消授权用户
  190 + *
  191 + * @param roleId 角色ID
  192 + * @param userIds 用户ID串
  193 + */
  194 + @SaCheckPermission("system:role:edit")
  195 + @Log(title = "角色管理", businessType = BusinessType.GRANT)
  196 + @PutMapping("/authUser/cancelAll")
  197 + public R<Void> cancelAuthUserAll(Long roleId, Long[] userIds) {
  198 + return toAjax(roleService.deleteAuthUsers(roleId, userIds));
  199 + }
  200 +
  201 + /**
  202 + * 批量选择用户授权
  203 + *
  204 + * @param roleId 角色ID
  205 + * @param userIds 用户ID串
  206 + */
  207 + @SaCheckPermission("system:role:edit")
  208 + @Log(title = "角色管理", businessType = BusinessType.GRANT)
  209 + @PutMapping("/authUser/selectAll")
  210 + public R<Void> selectAuthUserAll(Long roleId, Long[] userIds) {
  211 + roleService.checkRoleDataScope(roleId);
  212 + return toAjax(roleService.insertAuthUsers(roleId, userIds));
  213 + }
  214 +
  215 + /**
  216 + * 获取对应角色部门树列表
  217 + *
  218 + * @param roleId 角色ID
  219 + */
  220 + @SaCheckPermission("system:role:list")
  221 + @GetMapping(value = "/deptTree/{roleId}")
  222 + public R<Map<String, Object>> roleDeptTreeselect(@PathVariable("roleId") Long roleId) {
  223 + Map<String, Object> ajax = new HashMap<>();
  224 + ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
  225 + ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
  226 + return R.ok(ajax);
  227 + }
  228 +}
  1 +package com.ruoyi.web.controller.system;
  2 +
  3 +import cn.dev33.satoken.annotation.SaCheckPermission;
  4 +import cn.dev33.satoken.secure.BCrypt;
  5 +import cn.hutool.core.bean.BeanUtil;
  6 +import cn.hutool.core.lang.tree.Tree;
  7 +import cn.hutool.core.util.ArrayUtil;
  8 +import cn.hutool.core.util.ObjectUtil;
  9 +import com.ruoyi.common.annotation.Log;
  10 +import com.ruoyi.common.constant.UserConstants;
  11 +import com.ruoyi.common.core.controller.BaseController;
  12 +import com.ruoyi.common.core.domain.PageQuery;
  13 +import com.ruoyi.common.core.domain.R;
  14 +import com.ruoyi.common.core.domain.entity.SysDept;
  15 +import com.ruoyi.common.core.domain.entity.SysRole;
  16 +import com.ruoyi.common.core.domain.entity.SysUser;
  17 +import com.ruoyi.common.core.page.TableDataInfo;
  18 +import com.ruoyi.common.enums.BusinessType;
  19 +import com.ruoyi.common.excel.ExcelResult;
  20 +import com.ruoyi.common.helper.LoginHelper;
  21 +import com.ruoyi.common.utils.StreamUtils;
  22 +import com.ruoyi.common.utils.StringUtils;
  23 +import com.ruoyi.common.utils.poi.ExcelUtil;
  24 +import com.ruoyi.system.domain.SysPost;
  25 +import com.ruoyi.system.domain.vo.SysUserExportVo;
  26 +import com.ruoyi.system.domain.vo.SysUserImportVo;
  27 +import com.ruoyi.system.listener.SysUserImportListener;
  28 +import com.ruoyi.system.service.ISysDeptService;
  29 +import com.ruoyi.system.service.ISysPostService;
  30 +import com.ruoyi.system.service.ISysRoleService;
  31 +import com.ruoyi.system.service.ISysUserService;
  32 +import lombok.RequiredArgsConstructor;
  33 +import org.springframework.http.MediaType;
  34 +import org.springframework.validation.annotation.Validated;
  35 +import org.springframework.web.bind.annotation.*;
  36 +import org.springframework.web.multipart.MultipartFile;
  37 +
  38 +import javax.servlet.http.HttpServletResponse;
  39 +import java.util.ArrayList;
  40 +import java.util.HashMap;
  41 +import java.util.List;
  42 +import java.util.Map;
  43 +
  44 +/**
  45 + * 用户信息
  46 + *
  47 + * @author Lion Li
  48 + */
  49 +@Validated
  50 +@RequiredArgsConstructor
  51 +@RestController
  52 +@RequestMapping("/system/user")
  53 +public class SysUserController extends BaseController {
  54 +
  55 + private final ISysUserService userService;
  56 + private final ISysRoleService roleService;
  57 + private final ISysPostService postService;
  58 + private final ISysDeptService deptService;
  59 +
  60 + /**
  61 + * 获取用户列表
  62 + */
  63 + @SaCheckPermission("system:user:list")
  64 + @GetMapping("/list")
  65 + public TableDataInfo<SysUser> list(SysUser user, PageQuery pageQuery) {
  66 + return userService.selectPageUserList(user, pageQuery);
  67 + }
  68 +
  69 + /**
  70 + * 导出用户列表
  71 + */
  72 + @Log(title = "用户管理", businessType = BusinessType.EXPORT)
  73 + @SaCheckPermission("system:user:export")
  74 + @PostMapping("/export")
  75 + public void export(SysUser user, HttpServletResponse response) {
  76 + List<SysUser> list = userService.selectUserList(user);
  77 + List<SysUserExportVo> listVo = BeanUtil.copyToList(list, SysUserExportVo.class);
  78 + for (int i = 0; i < list.size(); i++) {
  79 + SysDept dept = list.get(i).getDept();
  80 + SysUserExportVo vo = listVo.get(i);
  81 + if (ObjectUtil.isNotEmpty(dept)) {
  82 + vo.setDeptName(dept.getDeptName());
  83 + vo.setLeader(dept.getLeader());
  84 + }
  85 + }
  86 + ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response);
  87 + }
  88 +
  89 + /**
  90 + * 导入数据
  91 + *
  92 + * @param file 导入文件
  93 + * @param updateSupport 是否更新已存在数据
  94 + */
  95 + @Log(title = "用户管理", businessType = BusinessType.IMPORT)
  96 + @SaCheckPermission("system:user:import")
  97 + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  98 + public R<Void> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception {
  99 + ExcelResult<SysUserImportVo> result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport));
  100 + return R.ok(result.getAnalysis());
  101 + }
  102 +
  103 + /**
  104 + * 获取导入模板
  105 + */
  106 + @PostMapping("/importTemplate")
  107 + public void importTemplate(HttpServletResponse response) {
  108 + ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response);
  109 + }
  110 +
  111 + /**
  112 + * 根据用户编号获取详细信息
  113 + *
  114 + * @param userId 用户ID
  115 + */
  116 + @SaCheckPermission("system:user:query")
  117 + @GetMapping(value = {"/", "/{userId}"})
  118 + public R<Map<String, Object>> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
  119 + userService.checkUserDataScope(userId);
  120 + Map<String, Object> ajax = new HashMap<>();
  121 + SysRole role = new SysRole();
  122 + role.setStatus(UserConstants.ROLE_NORMAL);
  123 + SysPost post = new SysPost();
  124 + post.setStatus(UserConstants.POST_NORMAL);
  125 + List<SysRole> roles = roleService.selectRoleList(role);
  126 + ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin()));
  127 + ajax.put("posts", postService.selectPostList(post));
  128 + if (ObjectUtil.isNotNull(userId)) {
  129 + SysUser sysUser = userService.selectUserById(userId);
  130 + ajax.put("user", sysUser);
  131 + ajax.put("postIds", postService.selectPostListByUserId(userId));
  132 + ajax.put("roleIds", StreamUtils.toList(sysUser.getRoles(), SysRole::getRoleId));
  133 + }
  134 + return R.ok(ajax);
  135 + }
  136 +
  137 + /**
  138 + * 新增用户
  139 + */
  140 + @SaCheckPermission("system:user:add")
  141 + @Log(title = "用户管理", businessType = BusinessType.INSERT)
  142 + @PostMapping
  143 + public R<Void> add(@Validated @RequestBody SysUser user) {
  144 + deptService.checkDeptDataScope(user.getDeptId());
  145 + if (!userService.checkUserNameUnique(user)) {
  146 + return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
  147 + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
  148 + return R.fail("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
  149 + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
  150 + return R.fail("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
  151 + }
  152 + user.setPassword(BCrypt.hashpw(user.getPassword()));
  153 + return toAjax(userService.insertUser(user));
  154 + }
  155 +
  156 + /**
  157 + * 修改用户
  158 + */
  159 + @SaCheckPermission("system:user:edit")
  160 + @Log(title = "用户管理", businessType = BusinessType.UPDATE)
  161 + @PutMapping
  162 + public R<Void> edit(@Validated @RequestBody SysUser user) {
  163 + userService.checkUserAllowed(user);
  164 + userService.checkUserDataScope(user.getUserId());
  165 + deptService.checkDeptDataScope(user.getDeptId());
  166 + if (!userService.checkUserNameUnique(user)) {
  167 + return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
  168 + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
  169 + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
  170 + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
  171 + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
  172 + }
  173 + return toAjax(userService.updateUser(user));
  174 + }
  175 +
  176 + /**
  177 + * 删除用户
  178 + *
  179 + * @param userIds 角色ID串
  180 + */
  181 + @SaCheckPermission("system:user:remove")
  182 + @Log(title = "用户管理", businessType = BusinessType.DELETE)
  183 + @DeleteMapping("/{userIds}")
  184 + public R<Void> remove(@PathVariable Long[] userIds) {
  185 + if (ArrayUtil.contains(userIds, getUserId())) {
  186 + return R.fail("当前用户不能删除");
  187 + }
  188 + return toAjax(userService.deleteUserByIds(userIds));
  189 + }
  190 +
  191 + /**
  192 + * 重置密码
  193 + */
  194 + @SaCheckPermission("system:user:resetPwd")
  195 + @Log(title = "用户管理", businessType = BusinessType.UPDATE)
  196 + @PutMapping("/resetPwd")
  197 + public R<Void> resetPwd(@RequestBody SysUser user) {
  198 + userService.checkUserAllowed(user);
  199 + userService.checkUserDataScope(user.getUserId());
  200 + user.setPassword(BCrypt.hashpw(user.getPassword()));
  201 + return toAjax(userService.resetPwd(user));
  202 + }
  203 +
  204 + /**
  205 + * 状态修改
  206 + */
  207 + @SaCheckPermission("system:user:edit")
  208 + @Log(title = "用户管理", businessType = BusinessType.UPDATE)
  209 + @PutMapping("/changeStatus")
  210 + public R<Void> changeStatus(@RequestBody SysUser user) {
  211 + userService.checkUserAllowed(user);
  212 + userService.checkUserDataScope(user.getUserId());
  213 + return toAjax(userService.updateUserStatus(user));
  214 + }
  215 +
  216 + /**
  217 + * 根据用户编号获取授权角色
  218 + *
  219 + * @param userId 用户ID
  220 + */
  221 + @SaCheckPermission("system:user:query")
  222 + @GetMapping("/authRole/{userId}")
  223 + public R<Map<String, Object>> authRole(@PathVariable Long userId) {
  224 + SysUser user = userService.selectUserById(userId);
  225 + List<SysRole> roles = roleService.selectRolesByUserId(userId);
  226 + Map<String, Object> ajax = new HashMap<>();
  227 + ajax.put("user", user);
  228 + ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin()));
  229 + return R.ok(ajax);
  230 + }
  231 +
  232 + /**
  233 + * 用户授权角色
  234 + *
  235 + * @param userId 用户Id
  236 + * @param roleIds 角色ID串
  237 + */
  238 + @SaCheckPermission("system:user:edit")
  239 + @Log(title = "用户管理", businessType = BusinessType.GRANT)
  240 + @PutMapping("/authRole")
  241 + public R<Void> insertAuthRole(Long userId, Long[] roleIds) {
  242 + userService.checkUserDataScope(userId);
  243 + userService.insertUserAuth(userId, roleIds);
  244 + return R.ok();
  245 + }
  246 +
  247 + /**
  248 + * 获取部门树列表
  249 + */
  250 + @SaCheckPermission("system:user:list")
  251 + @GetMapping("/deptTree")
  252 + public R<List<Tree<Long>>> deptTree(SysDept dept) {
  253 + return R.ok(deptService.selectDeptTreeList(dept));
  254 + }
  255 +
  256 +}
  1 +--- # 监控中心配置
  2 +spring.boot.admin.client:
  3 + # 增加客户端开关
  4 + enabled: true
  5 + url: http://localhost:9090/admin
  6 + instance:
  7 + service-host-type: IP
  8 + username: ruoyi
  9 + password: 123456
  10 +
  11 +--- # xxl-job 配置
  12 +xxl.job:
  13 + # 执行器开关
  14 + enabled: true
  15 + # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
  16 + admin-addresses: http://localhost:9100/xxl-job-admin
  17 + # 执行器通讯TOKEN:非空时启用
  18 + access-token: xxl-job
  19 + executor:
  20 + # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册
  21 + appname: xxl-job-executor
  22 + # 28080 端口 随着主应用端口飘逸 避免集群冲突
  23 + port: 2${server.port}
  24 + # 执行器注册:默认IP:PORT
  25 + address:
  26 + # 执行器IP:默认自动获取IP
  27 + ip:
  28 + # 执行器运行日志文件存储磁盘路径
  29 + logpath: ./logs/xxl-job
  30 + # 执行器日志文件保存天数:大于3生效
  31 + logretentiondays: 30
  32 +
  33 +--- # 数据源配置
  34 +spring:
  35 + datasource:
  36 + type: com.zaxxer.hikari.HikariDataSource
  37 + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
  38 + dynamic:
  39 + # 性能分析插件(有性能损耗 不建议生产环境使用)
  40 + p6spy: true
  41 + # 设置默认的数据源或者数据源组,默认值即为 master
  42 + primary: master
  43 + # 严格模式 匹配不到数据源则报错
  44 + strict: true
  45 + datasource:
  46 + # 主库数据源
  47 + master:
  48 + type: ${spring.datasource.type}
  49 + driverClassName: com.mysql.cj.jdbc.Driver
  50 + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
  51 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
  52 + url: jdbc:mysql://192.168.1.18:3306/ruoyi-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
  53 + username: root
  54 + password: root
  55 + # 从库数据源
  56 + slave:
  57 + lazy: true
  58 + type: ${spring.datasource.type}
  59 + driverClassName: com.mysql.cj.jdbc.Driver
  60 + url: jdbc:mysql://192.168.1.18:3306/ruoyi-vue2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
  61 + username: root
  62 + password: root
  63 + hikari:
  64 + # 最大连接池数量
  65 + maxPoolSize: 20
  66 + # 最小空闲线程数量
  67 + minIdle: 10
  68 + # 配置获取连接等待超时的时间
  69 + connectionTimeout: 30000
  70 + # 校验超时时间
  71 + validationTimeout: 5000
  72 + # 空闲连接存活最大时间,默认10分钟
  73 + idleTimeout: 600000
  74 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
  75 + maxLifetime: 1800000
  76 + # 多久检查一次连接的活性
  77 + keepaliveTime: 30000
  78 + shardingsphere:
  79 + datasource:
  80 + names: ds0,ds1
  81 + ds0:
  82 + type: com.zaxxer.hikari.HikariDataSource
  83 + driver-class-name: com.mysql.cj.jdbc.Driver
  84 + url: jdbc:mysql://192.168.1.18:3306/ruoyi-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
  85 + username: root
  86 + password: root
  87 + ds1:
  88 + type: com.zaxxer.hikari.HikariDataSource
  89 + driver-class-name: com.mysql.cj.jdbc.Driver
  90 + url: jdbc:mysql://192.168.1.18:3306/ruoyi-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
  91 + username: root
  92 + password: root
  93 + rules: # 配置表规则
  94 + sharding:
  95 + # 表策略配置
  96 + tables:
  97 + # iot_device_log 是逻辑表
  98 + iot_device_log:
  99 + actualDataNodes: ds0.iot_device_log_$->{2025}0$->{1..9},ds0.iot_device_log_$->{2025}1$->{0..2}
  100 + tableStrategy:
  101 + # 使用标准分片策略
  102 + standard:
  103 + # 配置分片字段
  104 + shardingColumn: create_time
  105 + # 分片算法名称,不支持大写字母和下划线,否则启动就会报错
  106 + shardingAlgorithmName: time-sharding-algorithm
  107 + # 分片算法配置
  108 + shardingAlgorithms:
  109 + # 分片算法名称,不支持大写字母和下划线,否则启动就会报错
  110 + time-sharding-algorithm:
  111 + # 类型:自定义策略
  112 + type: CLASS_BASED
  113 + props:
  114 + # 分片策略
  115 + strategy: standard
  116 + # 分片算法类
  117 + algorithmClassName: com.ruoyi.framework.config.sharding.TimeShardingAlgorithm
  118 + props:
  119 + sql-show: true # 是否打印 ShardingSphere 生成的 SQL
  120 + show-process-log: true # 是否显示处理日志
  121 +
  122 +
  123 +
  124 +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
  125 +spring:
  126 + redis:
  127 + # 地址
  128 + host: 192.168.1.18
  129 + # 端口,默认为6379
  130 + port: 6379
  131 + # 数据库索引
  132 + database: 0
  133 + # 密码(如没有密码请注释掉)
  134 + password: zkqk666888
  135 + # 连接超时时间
  136 + timeout: 10s
  137 + # 是否开启ssl
  138 + ssl: false
  139 +
  140 +redisson:
  141 + # redis key前缀
  142 + keyPrefix:
  143 + # 线程池数量
  144 + threads: 4
  145 + # Netty线程池数量
  146 + nettyThreads: 8
  147 + # 单节点配置
  148 + singleServerConfig:
  149 + # 客户端名称
  150 + clientName: ${ruoyi.name}
  151 + # 最小空闲连接数
  152 + connectionMinimumIdleSize: 8
  153 + # 连接池大小
  154 + connectionPoolSize: 32
  155 + # 连接空闲超时,单位:毫秒
  156 + idleConnectionTimeout: 10000
  157 + # 命令等待超时,单位:毫秒
  158 + timeout: 3000
  159 + # 发布和订阅连接池大小
  160 + subscriptionConnectionPoolSize: 50
  161 +
  162 +--- # mail 邮件发送
  163 +mail:
  164 + enabled: false
  165 + host: smtp.163.com
  166 + port: 465
  167 + # 是否需要用户名密码验证
  168 + auth: true
  169 + # 发送方,遵循RFC-822标准
  170 + from: xxx@163.com
  171 + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
  172 + user: xxx@163.com
  173 + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
  174 + pass: xxxxxxxxxx
  175 + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
  176 + starttlsEnable: true
  177 + # 使用SSL安全连接
  178 + sslEnable: true
  179 + # SMTP超时时长,单位毫秒,缺省值不超时
  180 + timeout: 0
  181 + # Socket连接超时值,单位毫秒,缺省值不超时
  182 + connectionTimeout: 0
  183 +
  184 +--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
  185 +# https://wind.kim/doc/start 文档地址 各个厂商可同时使用
  186 +sms:
  187 + # 阿里云 dysmsapi.aliyuncs.com
  188 + alibaba:
  189 + #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
  190 + requestUrl: dysmsapi.aliyuncs.com
  191 + #阿里云的accessKey
  192 + accessKeyId: xxxxxxx
  193 + #阿里云的accessKeySecret
  194 + accessKeySecret: xxxxxxx
  195 + #短信签名
  196 + signature: 测试
  197 + tencent:
  198 + #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置
  199 + requestUrl: sms.tencentcloudapi.com
  200 + #腾讯云的accessKey
  201 + accessKeyId: xxxxxxx
  202 + #腾讯云的accessKeySecret
  203 + accessKeySecret: xxxxxxx
  204 + #短信签名
  205 + signature: 测试
  206 + #短信sdkAppId
  207 + sdkAppId: appid
  208 + #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
  209 + territory: ap-guangzhou
  1 +--- # 临时文件存储位置 避免临时文件被系统清理报错
  2 +spring.servlet.multipart.location: /ruoyi/server/temp
  3 +
  4 +--- # 监控中心配置
  5 +spring.boot.admin.client:
  6 + # 增加客户端开关
  7 + enabled: true
  8 + url: http://localhost:9090/admin
  9 + instance:
  10 + service-host-type: IP
  11 + username: ruoyi
  12 + password: 123456
  13 +
  14 +--- # xxl-job 配置
  15 +xxl.job:
  16 + # 执行器开关
  17 + enabled: true
  18 + # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
  19 + admin-addresses: http://localhost:9100/xxl-job-admin
  20 + # 执行器通讯TOKEN:非空时启用
  21 + access-token: xxl-job
  22 + executor:
  23 + # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册
  24 + appname: xxl-job-executor
  25 + # 28080 端口 随着主应用端口飘逸 避免集群冲突
  26 + port: 2${server.port}
  27 + # 执行器注册:默认IP:PORT
  28 + address:
  29 + # 执行器IP:默认自动获取IP
  30 + ip:
  31 + # 执行器运行日志文件存储磁盘路径
  32 + logpath: ./logs/xxl-job
  33 + # 执行器日志文件保存天数:大于3生效
  34 + logretentiondays: 30
  35 +
  36 +--- # 数据源配置
  37 +spring:
  38 + datasource:
  39 + type: com.zaxxer.hikari.HikariDataSource
  40 + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
  41 + dynamic:
  42 + # 性能分析插件(有性能损耗 不建议生产环境使用)
  43 + p6spy: false
  44 + # 设置默认的数据源或者数据源组,默认值即为 master
  45 + primary: master
  46 + # 严格模式 匹配不到数据源则报错
  47 + strict: true
  48 + datasource:
  49 + # 主库数据源
  50 + master:
  51 + type: ${spring.datasource.type}
  52 + driverClassName: com.mysql.cj.jdbc.Driver
  53 + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
  54 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
  55 + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
  56 + username: root
  57 + password: root
  58 + # 从库数据源
  59 + slave:
  60 + lazy: true
  61 + type: ${spring.datasource.type}
  62 + driverClassName: com.mysql.cj.jdbc.Driver
  63 + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
  64 + username:
  65 + password:
  66 +# oracle:
  67 +# type: ${spring.datasource.type}
  68 +# driverClassName: oracle.jdbc.OracleDriver
  69 +# url: jdbc:oracle:thin:@//localhost:1521/XE
  70 +# username: ROOT
  71 +# password: root
  72 +# postgres:
  73 +# type: ${spring.datasource.type}
  74 +# driverClassName: org.postgresql.Driver
  75 +# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
  76 +# username: root
  77 +# password: root
  78 +# sqlserver:
  79 +# type: ${spring.datasource.type}
  80 +# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
  81 +# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
  82 +# username: SA
  83 +# password: root
  84 + hikari:
  85 + # 最大连接池数量
  86 + maxPoolSize: 20
  87 + # 最小空闲线程数量
  88 + minIdle: 10
  89 + # 配置获取连接等待超时的时间
  90 + connectionTimeout: 30000
  91 + # 校验超时时间
  92 + validationTimeout: 5000
  93 + # 空闲连接存活最大时间,默认10分钟
  94 + idleTimeout: 600000
  95 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
  96 + maxLifetime: 1800000
  97 + # 多久检查一次连接的活性
  98 + keepaliveTime: 30000
  99 +
  100 +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
  101 +spring:
  102 + redis:
  103 + # 地址
  104 + host: localhost
  105 + # 端口,默认为6379
  106 + port: 6379
  107 + # 数据库索引
  108 + database: 0
  109 + # 密码(如没有密码请注释掉)
  110 + # password:
  111 + # 连接超时时间
  112 + timeout: 10s
  113 + # 是否开启ssl
  114 + ssl: false
  115 +
  116 +redisson:
  117 + # redis key前缀
  118 + keyPrefix:
  119 + # 线程池数量
  120 + threads: 16
  121 + # Netty线程池数量
  122 + nettyThreads: 32
  123 + # 单节点配置
  124 + singleServerConfig:
  125 + # 客户端名称
  126 + clientName: ${ruoyi.name}
  127 + # 最小空闲连接数
  128 + connectionMinimumIdleSize: 32
  129 + # 连接池大小
  130 + connectionPoolSize: 64
  131 + # 连接空闲超时,单位:毫秒
  132 + idleConnectionTimeout: 10000
  133 + # 命令等待超时,单位:毫秒
  134 + timeout: 3000
  135 + # 发布和订阅连接池大小
  136 + subscriptionConnectionPoolSize: 50
  137 +
  138 +--- # mail 邮件发送
  139 +mail:
  140 + enabled: false
  141 + host: smtp.163.com
  142 + port: 465
  143 + # 是否需要用户名密码验证
  144 + auth: true
  145 + # 发送方,遵循RFC-822标准
  146 + from: xxx@163.com
  147 + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
  148 + user: xxx@163.com
  149 + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
  150 + pass: xxxxxxxxxx
  151 + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
  152 + starttlsEnable: true
  153 + # 使用SSL安全连接
  154 + sslEnable: true
  155 + # SMTP超时时长,单位毫秒,缺省值不超时
  156 + timeout: 0
  157 + # Socket连接超时值,单位毫秒,缺省值不超时
  158 + connectionTimeout: 0
  159 +
  160 +--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
  161 +# https://wind.kim/doc/start 文档地址 各个厂商可同时使用
  162 +sms:
  163 + # 阿里云 dysmsapi.aliyuncs.com
  164 + alibaba:
  165 + #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
  166 + requestUrl: dysmsapi.aliyuncs.com
  167 + #阿里云的accessKey
  168 + accessKeyId: xxxxxxx
  169 + #阿里云的accessKeySecret
  170 + accessKeySecret: xxxxxxx
  171 + #短信签名
  172 + signature: 测试
  173 + tencent:
  174 + #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置
  175 + requestUrl: sms.tencentcloudapi.com
  176 + #腾讯云的accessKey
  177 + accessKeyId: xxxxxxx
  178 + #腾讯云的accessKeySecret
  179 + accessKeySecret: xxxxxxx
  180 + #短信签名
  181 + signature: 测试
  182 + #短信sdkAppId
  183 + sdkAppId: appid
  184 + #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
  185 + territory: ap-guangzhou
  1 +# 项目相关配置
  2 +ruoyi:
  3 + # 名称
  4 + name: RuoYi-Vue-Plus
  5 + # 版本
  6 + version: ${ruoyi-vue-plus.version}
  7 + # 版权年份
  8 + copyrightYear: 2023
  9 + # 缓存懒加载
  10 + cacheLazy: false
  11 +
  12 +captcha:
  13 + # 页面 <参数设置> 可开启关闭 验证码校验
  14 + # 验证码类型 math 数组计算 char 字符验证
  15 + type: MATH
  16 + # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
  17 + category: CIRCLE
  18 + # 数字验证码位数
  19 + numberLength: 1
  20 + # 字符验证码长度
  21 + charLength: 4
  22 +
  23 +# 开发环境配置
  24 +server:
  25 + # 服务器的HTTP端口,默认为8080
  26 + port: 8080
  27 + servlet:
  28 + # 应用的访问路径
  29 + context-path: /
  30 + # undertow 配置
  31 + undertow:
  32 + # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
  33 + max-http-post-size: -1
  34 + # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
  35 + # 每块buffer的空间大小,越小的空间被利用越充分
  36 + buffer-size: 512
  37 + # 是否分配的直接内存
  38 + direct-buffers: true
  39 + threads:
  40 + # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
  41 + io: 8
  42 + # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
  43 + worker: 256
  44 +
  45 +# 日志配置
  46 +logging:
  47 + level:
  48 + com.ruoyi: @logging.level@
  49 + org.springframework: warn
  50 + config: classpath:logback-plus.xml
  51 +
  52 +# 用户配置
  53 +user:
  54 + password:
  55 + # 密码最大错误次数
  56 + maxRetryCount: 5
  57 + # 密码锁定时间(默认10分钟)
  58 + lockTime: 10
  59 +
  60 +# Spring配置
  61 +spring:
  62 + application:
  63 + name: ${ruoyi.name}
  64 + # 资源信息
  65 + messages:
  66 + # 国际化资源文件路径
  67 + basename: i18n/messages
  68 + profiles:
  69 + active: @profiles.active@
  70 + # 文件上传
  71 + servlet:
  72 + multipart:
  73 + # 单个文件大小
  74 + max-file-size: 10MB
  75 + # 设置总上传的文件大小
  76 + max-request-size: 20MB
  77 + # 服务模块
  78 + devtools:
  79 + restart:
  80 + # 热部署开关
  81 + enabled: true
  82 + mvc:
  83 + format:
  84 + date-time: yyyy-MM-dd HH:mm:ss
  85 + jackson:
  86 + # 日期格式化
  87 + date-format: yyyy-MM-dd HH:mm:ss
  88 + serialization:
  89 + # 格式化输出
  90 + indent_output: false
  91 + # 忽略无法转换的对象
  92 + fail_on_empty_beans: false
  93 + deserialization:
  94 + # 允许对象忽略json中不存在的属性
  95 + fail_on_unknown_properties: false
  96 +
  97 +# Sa-Token配置
  98 +sa-token:
  99 + # token名称 (同时也是cookie名称)
  100 + token-name: Authorization
  101 + # token有效期 设为一天 (必定过期) 单位: 秒
  102 + timeout: 86400
  103 + # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义
  104 + # token最低活跃时间 (指定时间无操作就过期) 单位: 秒
  105 + active-timeout: 1800
  106 + # 允许动态设置 token 有效期
  107 + dynamic-active-timeout: true
  108 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
  109 + is-concurrent: true
  110 + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
  111 + is-share: false
  112 + # 是否尝试从header里读取token
  113 + is-read-header: true
  114 + # 是否尝试从cookie里读取token
  115 + is-read-cookie: false
  116 + # token前缀
  117 + token-prefix: "Bearer"
  118 + # jwt秘钥
  119 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz
  120 +
  121 +# security配置
  122 +security:
  123 + # 排除路径
  124 + excludes:
  125 + # 静态资源
  126 + - /*.html
  127 + - /**/*.html
  128 + - /**/*.css
  129 + - /**/*.js
  130 + # 公共路径
  131 + - /favicon.ico
  132 + - /error
  133 + # swagger 文档配置
  134 + - /*/api-docs
  135 + - /*/api-docs/**
  136 + # actuator 监控配置
  137 + - /actuator
  138 + - /actuator/**
  139 + - /test/**
  140 +
  141 +# MyBatisPlus配置
  142 +# https://baomidou.com/config/
  143 +mybatis-plus:
  144 + # 不支持多包, 如有需要可在注解配置 或 提升扫包等级
  145 + # 例如 com.**.**.mapper
  146 + mapperPackage: com.ruoyi.**.mapper
  147 + # 对应的 XML 文件位置
  148 + mapperLocations: classpath*:mapper/**/*Mapper.xml
  149 + # 实体扫描,多个package用逗号或者分号分隔
  150 + typeAliasesPackage: com.ruoyi.**.domain
  151 + # 启动时是否检查 MyBatis XML 文件的存在,默认不检查
  152 + checkConfigLocation: false
  153 + configuration:
  154 + # 自动驼峰命名规则(camel case)映射
  155 + mapUnderscoreToCamelCase: true
  156 + # MyBatis 自动映射策略
  157 + # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
  158 + autoMappingBehavior: PARTIAL
  159 + # MyBatis 自动映射时未知列或未知属性处理策
  160 + # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
  161 + autoMappingUnknownColumnBehavior: NONE
  162 + # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
  163 + # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
  164 + # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
  165 + logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
  166 + global-config:
  167 + # 是否打印 Logo banner
  168 + banner: true
  169 + dbConfig:
  170 + # 主键类型
  171 + # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
  172 + idType: ASSIGN_ID
  173 + # 逻辑已删除值
  174 + logicDeleteValue: 2
  175 + # 逻辑未删除值
  176 + logicNotDeleteValue: 0
  177 + # 字段验证策略之 insert,在 insert 的时候的字段验证策略
  178 + # IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL
  179 + insertStrategy: NOT_NULL
  180 + # 字段验证策略之 update,在 update 的时候的字段验证策略
  181 + updateStrategy: NOT_NULL
  182 + # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
  183 + where-strategy: NOT_NULL
  184 +
  185 +# 数据加密
  186 +mybatis-encryptor:
  187 + # 是否开启加密
  188 + enable: false
  189 + # 默认加密算法
  190 + algorithm: BASE64
  191 + # 编码方式 BASE64/HEX。默认BASE64
  192 + encode: BASE64
  193 + # 安全秘钥 对称算法的秘钥 如:AES,SM4
  194 + password:
  195 + # 公私钥 非对称算法的公私钥 如:SM2,RSA
  196 + publicKey:
  197 + privateKey:
  198 +
  199 +springdoc:
  200 + api-docs:
  201 + # 是否开启接口文档
  202 + enabled: true
  203 +# swagger-ui:
  204 +# # 持久化认证数据
  205 +# persistAuthorization: true
  206 + info:
  207 + # 标题
  208 + title: '标题:${ruoyi.name}后台管理系统_接口文档'
  209 + # 描述
  210 + description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
  211 + # 版本
  212 + version: '版本号: ${ruoyi-vue-plus.version}'
  213 + # 作者信息
  214 + contact:
  215 + name: Lion Li
  216 + email: crazylionli@163.com
  217 + url: https://gitee.com/dromara/RuoYi-Vue-Plus
  218 + components:
  219 + # 鉴权方式配置
  220 + security-schemes:
  221 + apiKey:
  222 + type: APIKEY
  223 + in: HEADER
  224 + name: ${sa-token.token-name}
  225 + #这里定义了两个分组,可定义多个,也可以不定义
  226 + group-configs:
  227 + - group: 1.演示模块
  228 + packages-to-scan: com.ruoyi.demo
  229 + - group: 2.系统模块
  230 + packages-to-scan: com.ruoyi.web
  231 + - group: 3.代码生成模块
  232 + packages-to-scan: com.ruoyi.generator
  233 +
  234 +# 防止XSS攻击
  235 +xss:
  236 + # 过滤开关
  237 + enabled: true
  238 + # 排除链接(多个用逗号分隔)
  239 + excludes: /system/notice
  240 + # 匹配链接
  241 + urlPatterns: /system/*,/monitor/*,/tool/*
  242 +
  243 +# 全局线程池相关配置
  244 +thread-pool:
  245 + # 是否开启线程池
  246 + enabled: false
  247 + # 队列最大长度
  248 + queueCapacity: 128
  249 + # 线程池维护线程所允许的空闲时间
  250 + keepAliveSeconds: 300
  251 +
  252 +--- # 分布式锁 lock4j 全局配置
  253 +lock4j:
  254 + # 获取分布式锁超时时间,默认为 3000 毫秒
  255 + acquire-timeout: 3000
  256 + # 分布式锁的超时时间,默认为 30 秒
  257 + expire: 30000
  258 +
  259 +--- # Actuator 监控端点的配置项
  260 +management:
  261 + endpoints:
  262 + web:
  263 + exposure:
  264 + include: '*'
  265 + endpoint:
  266 + health:
  267 + show-details: ALWAYS
  268 + logfile:
  269 + external-file: ./logs/sys-console.log
  1 +Application Version: ${ruoyi-vue-plus.version}
  2 +Spring Boot Version: ${spring-boot.version}
  3 +__________ _____.___.__ ____ ____ __________.__
  4 +\______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______
  5 + | _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/
  6 + | | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \
  7 + |____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ >
  8 + \/ \/ \/ \/
  1 +#错误消息
  2 +not.null=* 必须填写
  3 +user.jcaptcha.error=验证码错误
  4 +user.jcaptcha.expire=验证码已失效
  5 +user.not.exists=对不起, 您的账号:{0} 不存在.
  6 +user.password.not.match=用户不存在/密码错误
  7 +user.password.retry.limit.count=密码输入错误{0}次
  8 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
  9 +user.password.delete=对不起,您的账号:{0} 已被删除
  10 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
  11 +role.blocked=角色已封禁,请联系管理员
  12 +user.logout.success=退出成功
  13 +length.not.valid=长度必须在{min}到{max}个字符之间
  14 +user.username.not.blank=用户名不能为空
  15 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
  16 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间
  17 +user.password.not.blank=用户密码不能为空
  18 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
  19 +user.password.not.valid=* 5-50个字符
  20 +user.email.not.valid=邮箱格式错误
  21 +user.email.not.blank=邮箱不能为空
  22 +user.phonenumber.not.blank=用户手机号不能为空
  23 +user.mobile.phone.number.not.valid=手机号格式错误
  24 +user.login.success=登录成功
  25 +user.register.success=注册成功
  26 +user.register.save.error=保存用户 {0} 失败,注册账号已存在
  27 +user.register.error=注册失败,请联系系统管理人员
  28 +user.notfound=请重新登录
  29 +user.forcelogout=管理员强制退出,请重新登录
  30 +user.unknown.error=未知错误,请重新登录
  31 +##文件上传消息
  32 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
  33 +upload.filename.exceed.length=上传的文件名最长{0}个字符
  34 +##权限
  35 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
  36 +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
  37 +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
  38 +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
  39 +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
  40 +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
  41 +repeat.submit.message=不允许重复提交,请稍候再试
  42 +rate.limiter.message=访问过于频繁,请稍候再试
  43 +sms.code.not.blank=短信验证码不能为空
  44 +sms.code.retry.limit.count=短信验证码输入错误{0}次
  45 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
  46 +email.code.not.blank=邮箱验证码不能为空
  47 +email.code.retry.limit.count=邮箱验证码输入错误{0}次
  48 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
  49 +xcx.code.not.blank=小程序code不能为空
  1 +#错误消息
  2 +not.null=* Required fill in
  3 +user.jcaptcha.error=Captcha error
  4 +user.jcaptcha.expire=Captcha invalid
  5 +user.not.exists=Sorry, your account: {0} does not exist
  6 +user.password.not.match=User does not exist/Password error
  7 +user.password.retry.limit.count=Password input error {0} times
  8 +user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes
  9 +user.password.delete=Sorry, your account:{0} has been deleted
  10 +user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
  11 +role.blocked=Role disabled,please contact administrators
  12 +user.logout.success=Exit successful
  13 +length.not.valid=The length must be between {min} and {max} characters
  14 +user.username.not.blank=Username cannot be blank
  15 +user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number
  16 +user.username.length.valid=Account length must be between {min} and {max} characters
  17 +user.password.not.blank=Password cannot be empty
  18 +user.password.length.valid=Password length must be between {min} and {max} characters
  19 +user.password.not.valid=* 5-50 characters
  20 +user.email.not.valid=Mailbox format error
  21 +user.email.not.blank=Mailbox cannot be blank
  22 +user.phonenumber.not.blank=Phone number cannot be blank
  23 +user.mobile.phone.number.not.valid=Phone number format error
  24 +user.login.success=Login successful
  25 +user.register.success=Register successful
  26 +user.register.save.error=Failed to save user {0}, The registered account already exists
  27 +user.register.error=Register failed, please contact system administrator
  28 +user.notfound=Please login again
  29 +user.forcelogout=The administrator is forced to exit,please login again
  30 +user.unknown.error=Unknown error, please login again
  31 +##文件上传消息
  32 +upload.exceed.maxSize=The uploaded file size exceeds the limit file size!<br/>the maximum allowed file size is:{0}MB!
  33 +upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters
  34 +##权限
  35 +no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}]
  36 +no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}]
  37 +no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}]
  38 +no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}]
  39 +no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}]
  40 +no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}]
  41 +repeat.submit.message=Repeat submit is not allowed, please try again later
  42 +rate.limiter.message=Visit too frequently, please try again later
  43 +sms.code.not.blank=Sms code cannot be blank
  44 +sms.code.retry.limit.count=Sms code input error {0} times
  45 +sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes
  46 +email.code.not.blank=Email code cannot be blank
  47 +email.code.retry.limit.count=Email code input error {0} times
  48 +email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes
  49 +xcx.code.not.blank=Mini program code cannot be blank
  1 +#错误消息
  2 +not.null=* 必须填写
  3 +user.jcaptcha.error=验证码错误
  4 +user.jcaptcha.expire=验证码已失效
  5 +user.not.exists=对不起, 您的账号:{0} 不存在.
  6 +user.password.not.match=用户不存在/密码错误
  7 +user.password.retry.limit.count=密码输入错误{0}次
  8 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
  9 +user.password.delete=对不起,您的账号:{0} 已被删除
  10 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
  11 +role.blocked=角色已封禁,请联系管理员
  12 +user.logout.success=退出成功
  13 +length.not.valid=长度必须在{min}到{max}个字符之间
  14 +user.username.not.blank=用户名不能为空
  15 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
  16 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间
  17 +user.password.not.blank=用户密码不能为空
  18 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
  19 +user.password.not.valid=* 5-50个字符
  20 +user.email.not.valid=邮箱格式错误
  21 +user.email.not.blank=邮箱不能为空
  22 +user.phonenumber.not.blank=用户手机号不能为空
  23 +user.mobile.phone.number.not.valid=手机号格式错误
  24 +user.login.success=登录成功
  25 +user.register.success=注册成功
  26 +user.register.save.error=保存用户 {0} 失败,注册账号已存在
  27 +user.register.error=注册失败,请联系系统管理人员
  28 +user.notfound=请重新登录
  29 +user.forcelogout=管理员强制退出,请重新登录
  30 +user.unknown.error=未知错误,请重新登录
  31 +##文件上传消息
  32 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
  33 +upload.filename.exceed.length=上传的文件名最长{0}个字符
  34 +##权限
  35 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
  36 +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
  37 +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
  38 +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
  39 +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
  40 +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
  41 +repeat.submit.message=不允许重复提交,请稍候再试
  42 +rate.limiter.message=访问过于频繁,请稍候再试
  43 +sms.code.not.blank=短信验证码不能为空
  44 +sms.code.retry.limit.count=短信验证码输入错误{0}次
  45 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
  46 +email.code.not.blank=邮箱验证码不能为空
  47 +email.code.retry.limit.count=邮箱验证码输入错误{0}次
  48 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
  49 +xcx.code.not.blank=小程序code不能为空
No preview for this file type
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<configuration>
  3 + <property name="log.path" value="./logs"/>
  4 + <property name="console.log.pattern"
  5 + value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
  6 + <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
  7 +
  8 + <!-- 控制台输出 -->
  9 + <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
  10 + <encoder>
  11 + <pattern>${console.log.pattern}</pattern>
  12 + <charset>utf-8</charset>
  13 + </encoder>
  14 + </appender>
  15 +
  16 + <!-- 控制台输出 -->
  17 + <appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
  18 + <file>${log.path}/sys-console.log</file>
  19 + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  20 + <!-- 日志文件名格式 -->
  21 + <fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern>
  22 + <!-- 日志最大 1天 -->
  23 + <maxHistory>1</maxHistory>
  24 + </rollingPolicy>
  25 + <encoder>
  26 + <pattern>${log.pattern}</pattern>
  27 + <charset>utf-8</charset>
  28 + </encoder>
  29 + <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  30 + <!-- 过滤的级别 -->
  31 + <level>INFO</level>
  32 + </filter>
  33 + </appender>
  34 +
  35 + <!-- 系统日志输出 -->
  36 + <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
  37 + <file>${log.path}/sys-info.log</file>
  38 + <!-- 循环政策:基于时间创建日志文件 -->
  39 + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  40 + <!-- 日志文件名格式 -->
  41 + <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
  42 + <!-- 日志最大的历史 60天 -->
  43 + <maxHistory>60</maxHistory>
  44 + </rollingPolicy>
  45 + <encoder>
  46 + <pattern>${log.pattern}</pattern>
  47 + </encoder>
  48 + <filter class="ch.qos.logback.classic.filter.LevelFilter">
  49 + <!-- 过滤的级别 -->
  50 + <level>INFO</level>
  51 + <!-- 匹配时的操作:接收(记录) -->
  52 + <onMatch>ACCEPT</onMatch>
  53 + <!-- 不匹配时的操作:拒绝(不记录) -->
  54 + <onMismatch>DENY</onMismatch>
  55 + </filter>
  56 + </appender>
  57 +
  58 + <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
  59 + <file>${log.path}/sys-error.log</file>
  60 + <!-- 循环政策:基于时间创建日志文件 -->
  61 + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  62 + <!-- 日志文件名格式 -->
  63 + <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
  64 + <!-- 日志最大的历史 60天 -->
  65 + <maxHistory>60</maxHistory>
  66 + </rollingPolicy>
  67 + <encoder>
  68 + <pattern>${log.pattern}</pattern>
  69 + </encoder>
  70 + <filter class="ch.qos.logback.classic.filter.LevelFilter">
  71 + <!-- 过滤的级别 -->
  72 + <level>ERROR</level>
  73 + <!-- 匹配时的操作:接收(记录) -->
  74 + <onMatch>ACCEPT</onMatch>
  75 + <!-- 不匹配时的操作:拒绝(不记录) -->
  76 + <onMismatch>DENY</onMismatch>
  77 + </filter>
  78 + </appender>
  79 +
  80 + <!-- info异步输出 -->
  81 + <appender name="async_info" class="ch.qos.logback.classic.AsyncAppender">
  82 + <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  83 + <discardingThreshold>0</discardingThreshold>
  84 + <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  85 + <queueSize>512</queueSize>
  86 + <!-- 添加附加的appender,最多只能添加一个 -->
  87 + <appender-ref ref="file_info"/>
  88 + </appender>
  89 +
  90 + <!-- error异步输出 -->
  91 + <appender name="async_error" class="ch.qos.logback.classic.AsyncAppender">
  92 + <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  93 + <discardingThreshold>0</discardingThreshold>
  94 + <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  95 + <queueSize>512</queueSize>
  96 + <!-- 添加附加的appender,最多只能添加一个 -->
  97 + <appender-ref ref="file_error"/>
  98 + </appender>
  99 +
  100 + <!-- 整合 skywalking 控制台输出 tid -->
  101 +<!-- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">-->
  102 +<!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
  103 +<!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
  104 +<!-- <pattern>[%tid] ${console.log.pattern}</pattern>-->
  105 +<!-- </layout>-->
  106 +<!-- <charset>utf-8</charset>-->
  107 +<!-- </encoder>-->
  108 +<!-- </appender>-->
  109 +
  110 + <!-- 整合 skywalking 推送采集日志 -->
  111 +<!-- <appender name="sky_log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">-->
  112 +<!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
  113 +<!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
  114 +<!-- <pattern>[%tid] ${console.log.pattern}</pattern>-->
  115 +<!-- </layout>-->
  116 +<!-- <charset>utf-8</charset>-->
  117 +<!-- </encoder>-->
  118 +<!-- </appender>-->
  119 +
  120 + <!--系统操作日志-->
  121 + <root level="info">
  122 + <appender-ref ref="console" />
  123 + <appender-ref ref="async_info" />
  124 + <appender-ref ref="async_error" />
  125 + <appender-ref ref="file_console" />
  126 +<!-- <appender-ref ref="sky_log"/>-->
  127 + </root>
  128 +
  129 +</configuration>
  1 +# !!!数据源名称要和动态数据源中配置的名称一致
  2 +databaseName: master
  3 +
  4 +# 具体参看官网文档说明
  5 +dataSources:
  6 + coupon_user_db_0:
  7 + dataSourceClassName: com.zaxxer.hikari.HikariDataSource
  8 + driverClassName: com.mysql.jdbc.Driver
  9 + jdbcUrl: jdbc:mysql://192.168.1.18:3306/ruoyi-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
  10 + username: root
  11 + password: root
  12 +
  13 +rules:
  14 + - !SHARDING
  15 + tables: # 数据分片规则配置
  16 + coupon_user: # 逻辑表名称
  17 + actualDataNodes: coupon_user_db_0.coupon_user_$->{0..9} # 由数据源名 + 表名组成(参考 Inline 语法规则)
  18 + databaseStrategy: # 分库策略,缺省表示使用默认分库策略,以下的分片策略只能选其一
  19 + none:
  20 + tableStrategy: # 分表策略
  21 + standard: # 用于单分片键的标准分片场景
  22 + shardingColumn: user_id # 分片列名称
  23 + shardingAlgorithmName: user_inline
  24 + keyGenerateStrategy:
  25 + column: id
  26 + keyGeneratorName: snowflake
  27 + keyGenerators:
  28 + snowflake:
  29 + type: SNOWFLAKE
  30 + props:
  31 + worker-id: 123
  32 + # 分片算法配置
  33 + shardingAlgorithms:
  34 + user_inline:
  35 + type: INLINE
  36 + props:
  37 + algorithm-expression: coupon_user_$->{user_id % 10}
  38 +
  39 +props:
  40 + sql-show: true
  41 +
  1 +# p6spy 性能分析插件配置文件
  2 +modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
  3 +# 自定义日志打印
  4 +logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
  5 +#日志输出到控制台
  6 +appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
  7 +# 使用日志系统记录 sql
  8 +#appender=com.p6spy.engine.spy.appender.Slf4JLogger
  9 +# 设置 p6spy driver 代理
  10 +#deregisterdrivers=true
  11 +# 取消JDBC URL前缀
  12 +useprefix=true
  13 +# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
  14 +excludecategories=info,debug,result,commit,resultset
  15 +# 日期格式
  16 +dateformat=yyyy-MM-dd HH:mm:ss
  17 +# SQL语句打印时间格式
  18 +databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
  19 +# 实际驱动可多个
  20 +#driverlist=org.h2.Driver
  21 +# 是否开启慢SQL记录
  22 +outagedetection=true
  23 +# 慢SQL记录标准 2 秒
  24 +outagedetectioninterval=2
  25 +# 是否过滤 Log
  26 +filter=true
  27 +# 过滤 Log 时所排除的 sql 关键字,以逗号分隔
  28 +exclude=SELECT 1
  1 +package com.ruoyi.test;
  2 +
  3 +import cn.hutool.core.io.FileUtil;
  4 +import cn.hutool.core.text.UnicodeUtil;
  5 +import cn.hutool.http.HttpUtil;
  6 +import cn.hutool.json.JSONArray;
  7 +import cn.hutool.json.JSONObject;
  8 +import cn.hutool.json.JSONUtil;
  9 +import com.google.gson.Gson;
  10 +import com.google.gson.JsonElement;
  11 +import com.google.gson.JsonParser;
  12 +import com.ruoyi.system.domain.Api;
  13 +import com.ruoyi.system.mapper.ApiMapper;
  14 +import io.micrometer.core.instrument.util.StringEscapeUtils;
  15 +import org.junit.jupiter.api.BeforeAll;
  16 +import org.junit.jupiter.api.BeforeEach;
  17 +import org.junit.jupiter.api.DisplayName;
  18 +import org.junit.jupiter.api.Test;
  19 +import org.springframework.beans.factory.annotation.Autowired;
  20 +import org.springframework.boot.test.context.SpringBootTest;
  21 +import org.springframework.test.context.event.annotation.BeforeTestClass;
  22 +
  23 +import java.io.ByteArrayInputStream;
  24 +import java.util.Date;
  25 +import java.util.HashMap;
  26 +import java.util.Map;
  27 +
  28 +//@SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件
  29 +@DisplayName("调用零零汽API")
  30 +public class ApiTest {
  31 +
  32 + private ApiMapper apiMapper;
  33 +
  34 + private static final String BASE_API_URL = "https://sapi.007vin.com";
  35 + private static final String OPEN_ID = "489c1079b6ab49d359eced61d7d83804";
  36 + private static final String TOKEN = "8e9b584b2e09db0fb6829fc237f88efd";
  37 + private static final String VIN = "LFV3B2FY1J3513783";
  38 + private static final String MCID = "Yjt6cH07Izk7LSshO2Q%3D";
  39 +
  40 + Map<String, Object> params = new HashMap<>();
  41 +
  42 + @BeforeEach
  43 + public void setUp() {
  44 + params.put("open_id", OPEN_ID);
  45 + params.put("token", TOKEN);
  46 + params.put("vin", VIN);
  47 + }
  48 +
  49 + /**
  50 + * 基础车型选择
  51 + */
  52 + @DisplayName("基础车型选择")
  53 + @Test
  54 + public void chooseMode() {
  55 + params.remove("vin");
  56 + params.put("brandCode", "vwag");
  57 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/models", params);
  58 + JSONObject json = JSONUtil.parseObj(response);
  59 + System.out.println(json);
  60 + String targetFilePath = "E:\\data\\基础车型选择.json"; // 定义目标文件路径
  61 + FileUtil.writeFromStream(new ByteArrayInputStream(json.toString().getBytes()), FileUtil.file(targetFilePath));
  62 + }
  63 +
  64 + /**
  65 + * 车架号解析全车件车型配置
  66 + */
  67 + @DisplayName("车架号解析全车件车型配置")
  68 + @Test
  69 + public void test1000() {
  70 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/vin", params);
  71 + JSONObject json = JSONUtil.parseObj(response);
  72 + System.out.println(json);
  73 + String targetFilePath = "E:\\data\\01车架号解析全车件车型配置.json"; // 定义目标文件路径
  74 + FileUtil.writeFromStream(new ByteArrayInputStream(json.toString().getBytes()), FileUtil.file(targetFilePath));
  75 + }
  76 +
  77 +
  78 + /**
  79 + * 全车件主组查询
  80 + */
  81 + @DisplayName("全车件主组查询")
  82 + @Test
  83 + public void test1002() {
  84 + params.put("mcid", MCID);
  85 + params.put("brandCode", "vwag");
  86 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/group", params);
  87 + JSONObject json = JSONUtil.parseObj(response);
  88 + System.out.println(json);
  89 + String targetFilePath = "E:\\data\\02全车件主组查询.json"; // 定义目标文件路径
  90 + FileUtil.writeFromStream(new ByteArrayInputStream(json.toString().getBytes()), FileUtil.file(targetFilePath));
  91 + }
  92 +
  93 + /**
  94 + * 全车件分组查询
  95 + */
  96 + @DisplayName("全车件分组查询")
  97 + @Test
  98 + public void test1003() {
  99 + params.put("mcid", MCID);
  100 + params.put("brandCode", "vwag");
  101 + params.put("num", "0");
  102 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/structure", params);
  103 + JSONObject json = JSONUtil.parseObj(response);
  104 + System.out.println(json);
  105 + String targetFilePath = "E:\\data\\03全车件分组查询.json"; // 定义目标文件路径
  106 + FileUtil.writeFromStream(new ByteArrayInputStream(json.toString().getBytes()), FileUtil.file(targetFilePath));
  107 + }
  108 +
  109 + /**
  110 + * 全车件零件列表查询
  111 + */
  112 + @DisplayName("全车件零件列表查询")
  113 + @Test
  114 + public void test1005() {
  115 + params.put("mcid", MCID);
  116 + params.put("brandCode", "audi");
  117 + params.put("num", "6");
  118 + params.put("mid", "615040");
  119 + params.put("subgroup", "15");
  120 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/part", params);
  121 + JSONObject json = JSONUtil.parseObj(response);
  122 + System.out.println(json);
  123 + String targetFilePath = "E:\\data\\04全车件零件列表查询.json"; // 定义目标文件路径
  124 + FileUtil.writeFromStream(new ByteArrayInputStream(json.toString().getBytes()), FileUtil.file(targetFilePath));
  125 + }
  126 +
  127 + /**
  128 + * 基础车型选择
  129 + */
  130 + @DisplayName("品牌覆盖列表")
  131 + @Test
  132 + public void test0000() {
  133 + String response = HttpUtil.get(BASE_API_URL + "/api/brands", params);
  134 + JSONObject json = JSONUtil.parseObj(response);
  135 + System.out.println(json);
  136 + String targetFilePath = "E:\\data\\品牌覆盖列表.json";
  137 + FileUtil.writeFromStream(new ByteArrayInputStream(json.toString().getBytes()), FileUtil.file(targetFilePath));
  138 + }
  139 +
  140 + /**
  141 + * 基础车型选择
  142 + */
  143 + @DisplayName("基础车型选择")
  144 + @Test
  145 + public void test5000() {
  146 + params.put("mcid", MCID);
  147 + params.put("brandCode", "audi");
  148 + params.put("num", "6");
  149 + params.put("mid", "615040");
  150 + params.put("subgroup", "15");
  151 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/part", params);
  152 + JSONObject json = JSONUtil.parseObj(response);
  153 + System.out.println(json);
  154 + String targetFilePath = "E:\\data\\04全车件零件列表查询.json"; // 定义目标文件路径
  155 + FileUtil.writeFromStream(new ByteArrayInputStream(json.toString().getBytes()), FileUtil.file(targetFilePath));
  156 + }
  157 +}
  1 +package com.ruoyi.test;
  2 +
  3 +import org.junit.jupiter.api.Assertions;
  4 +import org.junit.jupiter.api.DisplayName;
  5 +import org.junit.jupiter.api.Test;
  6 +
  7 +/**
  8 + * 断言单元测试案例
  9 + *
  10 + * @author Lion Li
  11 + */
  12 +@DisplayName("断言单元测试案例")
  13 +public class AssertUnitTest {
  14 +
  15 + @DisplayName("测试 assertEquals 方法")
  16 + @Test
  17 + public void testAssertEquals() {
  18 + Assertions.assertEquals("666", new String("666"));
  19 + Assertions.assertNotEquals("666", new String("666"));
  20 + }
  21 +
  22 + @DisplayName("测试 assertSame 方法")
  23 + @Test
  24 + public void testAssertSame() {
  25 + Object obj = new Object();
  26 + Object obj1 = obj;
  27 + Assertions.assertSame(obj, obj1);
  28 + Assertions.assertNotSame(obj, obj1);
  29 + }
  30 +
  31 + @DisplayName("测试 assertTrue 方法")
  32 + @Test
  33 + public void testAssertTrue() {
  34 + Assertions.assertTrue(true);
  35 + Assertions.assertFalse(true);
  36 + }
  37 +
  38 + @DisplayName("测试 assertNull 方法")
  39 + @Test
  40 + public void testAssertNull() {
  41 + Assertions.assertNull(null);
  42 + Assertions.assertNotNull(null);
  43 + }
  44 +
  45 +}
  1 +package com.ruoyi.test;
  2 +
  3 +import cn.hutool.core.io.FileUtil;
  4 +import cn.hutool.http.HttpUtil;
  5 +import cn.hutool.json.JSONArray;
  6 +import cn.hutool.json.JSONObject;
  7 +import cn.hutool.json.JSONUtil;
  8 +import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  9 +import com.ruoyi.system.domain.BrandInfo;
  10 +import com.ruoyi.system.domain.Api;
  11 +import com.ruoyi.system.mapper.ApiMapper;
  12 +import com.ruoyi.system.mapper.BrandInfoMapper;
  13 +import org.junit.jupiter.api.BeforeEach;
  14 +import org.junit.jupiter.api.DisplayName;
  15 +import org.junit.jupiter.api.Test;
  16 +import org.springframework.beans.factory.annotation.Autowired;
  17 +import org.springframework.boot.test.context.SpringBootTest;
  18 +
  19 +import java.io.ByteArrayInputStream;
  20 +import java.util.Date;
  21 +import java.util.HashMap;
  22 +import java.util.Map;
  23 +
  24 +@SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件
  25 +@DisplayName("调用零零汽API")
  26 +public class CarDataSpider {
  27 +
  28 + @Autowired
  29 + private ApiMapper apiMapper;
  30 + @Autowired
  31 + private BrandInfoMapper brandInfoMapper;
  32 +
  33 + private static final String BASE_API_URL = "https://sapi.007vin.com";
  34 + private static final String OPEN_ID = "489c1079b6ab49d359eced61d7d83804";
  35 + private static final String TOKEN = "8e9b584b2e09db0fb6829fc237f88efd";
  36 + private static final String VIN = "LBVFP3904BSE35458";
  37 + private static String name = null;
  38 + private static String modelName = null;
  39 +
  40 + Map<String, Object> params = new HashMap<>();
  41 +
  42 + @BeforeEach
  43 + public void setUp() {
  44 + params.put("open_id", OPEN_ID);
  45 + params.put("token", TOKEN);
  46 + params.put("vin", VIN);
  47 + }
  48 +
  49 + @DisplayName("获取品牌信息")
  50 + @Test
  51 + public void saveBandInfo() {
  52 + String response = HttpUtil.get(BASE_API_URL + "/api/brands", params);
  53 + System.out.println(response);
  54 + JSONObject json = JSONUtil.parseObj(response);
  55 + String targetFilePath = "E:\\data\\所有品牌信息.json"; // 定义目标文件路径
  56 + FileUtil.writeFromStream(new ByteArrayInputStream(json.toString().getBytes()), FileUtil.file(targetFilePath));
  57 + Integer code = json.getInt("code");
  58 + if (code != 1) {
  59 + System.out.println("获取品牌信息失败");
  60 + return;
  61 + }
  62 + JSONArray data = json.getJSONArray("data");
  63 + for (int i = 0; i < data.size(); i++) {
  64 + BrandInfo brandInfo = new BrandInfo();
  65 + brandInfo.setBrandCode(data.getJSONObject(i).getStr("brandcode"));
  66 + brandInfo.setName(data.getJSONObject(i).getStr("name"));
  67 + brandInfo.setBrandName(data.getJSONObject(i).getStr("brandname"));
  68 + brandInfo.setAcronym(data.getJSONObject(i).getStr("acronym"));
  69 + brandInfo.setAreasId(data.getJSONObject(i).getInt("areas_id"));
  70 + brandInfo.setHasStandardModel(data.getJSONObject(i).getBool("has_standard_model"));
  71 + brandInfo.setMaintenance(data.getJSONObject(i).getInt("maintenance"));
  72 + brandInfo.setIsHot(data.getJSONObject(i).getBool("is_hot"));
  73 + brandInfo.setVin(data.getJSONObject(i).getBool("vin"));
  74 + brandInfo.setVehicleType(data.getJSONObject(i).getInt("vehicle_type"));
  75 + brandInfo.setImg(data.getJSONObject(i).getStr("img"));
  76 + brandInfo.setUri(data.getJSONObject(i).getStr("uri"));
  77 + brandInfo.setAreaName(data.getJSONObject(i).getStr("area_name"));
  78 + System.out.println(brandInfo);
  79 + brandInfoMapper.insert(brandInfo);
  80 + }
  81 +
  82 + }
  83 +
  84 + /**
  85 + * 车架号解析全车件车型配置
  86 + */
  87 + @DisplayName("全车型零件查询")
  88 + @Test
  89 + public void test1000() {
  90 +
  91 + Long count = apiMapper.selectCount(Wrappers.lambdaQuery(Api.class).eq(Api::getVin, VIN));
  92 + if (count > 1) {
  93 + System.out.println("车架号已解析");
  94 + return;
  95 + }
  96 +
  97 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/vin", params);
  98 +// String decodedResponse = UnicodeUtil.toString(response);
  99 + JSONObject json = JSONUtil.parseObj(response);
  100 + Integer code = json.getInt("code");
  101 +
  102 + Api api = new Api();
  103 + api.setUrl("/api/cars/vin");
  104 + api.setUrlNo("1000");
  105 + api.setVin(VIN);
  106 + api.setRequest(JSONUtil.toJsonStr(params));
  107 + api.setResponse(json.toString());
  108 + api.setCreateTime(new Date());
  109 +
  110 + if (code != 1) {
  111 + System.out.println("车架号解析失败");
  112 + System.out.println(response);
  113 + apiMapper.insert(api);
  114 + return;
  115 + }
  116 + JSONObject data = json.getJSONObject("data");
  117 + String mcid = data.getStr("mcid");
  118 + String brandCode = data.getStr("brandCode");
  119 + name = data.getStr("name");
  120 + modelName = data.getStr("model_name");
  121 + api.setBrandCode(brandCode);
  122 + api.setName(name);
  123 + api.setModelName(modelName);
  124 + api.setData(data.toString());
  125 + apiMapper.insert(api);
  126 + getMasterGroup(mcid, brandCode);
  127 + }
  128 +
  129 + /**
  130 + * 获取主组
  131 + * @param mcid
  132 + */
  133 + public void getMasterGroup(String mcid, String brandCode) {
  134 + params.put("mcid", mcid);
  135 + params.put("brandCode", brandCode);
  136 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/group", params);
  137 +// String decodedResponse = UnicodeUtil.toString(response);
  138 + JSONObject json = JSONUtil.parseObj(response);
  139 + Integer code = json.getInt("code");
  140 +
  141 + Api api = new Api();
  142 + api.setUrl("/api/cars/group");
  143 + api.setUrlNo("1002");
  144 + api.setVin(VIN);
  145 + api.setRequest(JSONUtil.toJsonStr(params));
  146 + api.setResponse(json.toString());
  147 + api.setCreateTime(new Date());
  148 + api.setBrandCode(brandCode);
  149 + api.setName(name);
  150 + api.setModelName(modelName);
  151 +
  152 + if (code != 1) {
  153 + System.out.println("查询全车主组失败");
  154 + System.out.println(response);
  155 + apiMapper.insert(api);
  156 + return;
  157 + }
  158 +
  159 + JSONArray jsonArray = json.getJSONArray("data");
  160 + api.setNum(jsonArray.size());
  161 + api.setData(jsonArray.toString());
  162 + apiMapper.insert(api);
  163 +
  164 + for (int i = 0; i < jsonArray.size(); i++) {
  165 + JSONObject jsonObject = jsonArray.getJSONObject(i);
  166 + String num = jsonObject.getStr("num");
  167 + params.clear();
  168 + getChildGroup(mcid, brandCode, num);
  169 + }
  170 +
  171 + }
  172 +
  173 + /**
  174 + * 获取分组
  175 + * @param num
  176 + */
  177 + private void getChildGroup(String mcid, String brandCode, String num) {
  178 +
  179 + Map<String, Object> params = new HashMap<>();
  180 + params.put("open_id", OPEN_ID);
  181 + params.put("token", TOKEN);
  182 + params.put("vin", VIN);
  183 + params.put("mcid", mcid);
  184 + params.put("brandCode", brandCode);
  185 + params.put("num", num);
  186 +
  187 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/structure", params);
  188 +// String decodedResponse = UnicodeUtil.toString(response);
  189 + JSONObject json = JSONUtil.parseObj(response);
  190 +
  191 + Api api = new Api();
  192 + api.setUrl("/api/cars/structure");
  193 + api.setUrlNo("1003");
  194 + api.setVin(VIN);
  195 + api.setRequest(JSONUtil.toJsonStr(params));
  196 + api.setResponse(json.toString());
  197 + api.setCreateTime(new Date());
  198 + api.setBrandCode(brandCode);
  199 + api.setName(name);
  200 + api.setModelName(modelName);
  201 +
  202 + Integer code = json.getInt("code");
  203 + if (code != 1) {
  204 + System.out.println("查询取分组失败");
  205 + System.out.println(response);
  206 + apiMapper.insert(api);
  207 + return;
  208 + }
  209 + JSONArray jsonArray = json.getJSONArray("data");
  210 +
  211 +
  212 + api.setNum(jsonArray.size());
  213 + api.setData(jsonArray.toString());
  214 + apiMapper.insert(api);
  215 +
  216 + for (int i = 0; i < jsonArray.size(); i++) {
  217 + JSONObject jsonObject = jsonArray.getJSONObject(i);
  218 + String mid = jsonObject.getStr("mid");
  219 + String subgroup = jsonObject.getStr("subgroup");
  220 +
  221 + getLj(mcid, brandCode, num, mid, subgroup);
  222 + }
  223 + }
  224 +
  225 + /**
  226 + * 全车件零件列表查询
  227 + */
  228 + private void getLj(String mcid, String brandCode, String num, String mid, String subgroup) {
  229 +
  230 + Map<String, Object> params = new HashMap<>();
  231 + params.put("open_id", OPEN_ID);
  232 + params.put("token", TOKEN);
  233 + params.put("vin", VIN);
  234 + params.put("mcid", mcid);
  235 + params.put("brandCode", brandCode);
  236 + params.put("num", num);
  237 + params.put("mid", mid);
  238 + params.put("subgroup", subgroup);
  239 +
  240 + String response = HttpUtil.get(BASE_API_URL + "/api/cars/part", params);
  241 +// String decodedResponse = UnicodeUtil.toString(response);
  242 + JSONObject json = JSONUtil.parseObj(response);
  243 +
  244 + Api api = new Api();
  245 + api.setUrl("/api/cars/part");
  246 + api.setUrlNo("1005");
  247 + api.setVin(VIN);
  248 + api.setRequest(JSONUtil.toJsonStr(params));
  249 + api.setResponse(json.toString());
  250 + api.setCreateTime(new Date());
  251 + api.setBrandCode(brandCode);
  252 + api.setName(name);
  253 + api.setModelName(modelName);
  254 +
  255 + Integer code = json.getInt("code");
  256 + if (code != 1) {
  257 + System.out.println("查询零件列表失败");
  258 + System.out.println(response);
  259 + apiMapper.insert(api);
  260 + return;
  261 + }
  262 + JSONObject jsonObject = json.getJSONObject("data");
  263 +
  264 +
  265 +
  266 + api.setData(jsonObject.toString());
  267 +
  268 + if (jsonObject.containsKey("part_detail")) {
  269 + JSONArray partDetail = jsonObject.getJSONArray("part_detail");
  270 + api.setNum(partDetail.size());
  271 + }
  272 + apiMapper.insert(api);
  273 +
  274 + }
  275 +}
  1 +package com.ruoyi.test;
  2 +
  3 +import com.ruoyi.common.config.RuoYiConfig;
  4 +import org.junit.jupiter.api.*;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.boot.test.context.SpringBootTest;
  7 +
  8 +import java.util.concurrent.TimeUnit;
  9 +
  10 +/**
  11 + * 单元测试案例
  12 + *
  13 + * @author Lion Li
  14 + */
  15 +@SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件
  16 +@DisplayName("单元测试案例")
  17 +public class DemoUnitTest {
  18 +
  19 + @Autowired
  20 + private RuoYiConfig ruoYiConfig;
  21 +
  22 + @DisplayName("测试 @SpringBootTest @Test @DisplayName 注解")
  23 + @Test
  24 + public void testTest() {
  25 + System.out.println(ruoYiConfig);
  26 + }
  27 +
  28 + @Disabled
  29 + @DisplayName("测试 @Disabled 注解")
  30 + @Test
  31 + public void testDisabled() {
  32 + System.out.println(ruoYiConfig);
  33 + }
  34 +
  35 + @Timeout(value = 2L, unit = TimeUnit.SECONDS)
  36 + @DisplayName("测试 @Timeout 注解")
  37 + @Test
  38 + public void testTimeout() throws InterruptedException {
  39 + Thread.sleep(3000);
  40 + System.out.println(ruoYiConfig);
  41 + }
  42 +
  43 +
  44 + @DisplayName("测试 @RepeatedTest 注解")
  45 + @RepeatedTest(3)
  46 + public void testRepeatedTest() {
  47 + System.out.println(666);
  48 + }
  49 +
  50 + @BeforeAll
  51 + public static void testBeforeAll() {
  52 + System.out.println("@BeforeAll ==================");
  53 + }
  54 +
  55 + @BeforeEach
  56 + public void testBeforeEach() {
  57 + System.out.println("@BeforeEach ==================");
  58 + }
  59 +
  60 + @AfterEach
  61 + public void testAfterEach() {
  62 + System.out.println("@AfterEach ==================");
  63 + }
  64 +
  65 + @AfterAll
  66 + public static void testAfterAll() {
  67 + System.out.println("@AfterAll ==================");
  68 + }
  69 +
  70 +}