├── .DS_Store
├── .gitignore
├── .mvn
└── wrapper
│ └── maven-wrapper.properties
├── Dockerfile
├── LICENSE
├── README.md
├── doc
├── swagger.png
├── 图片1.png
├── 图片2.png
├── 图片3.PNG
├── 图片4.PNG
└── 图片5.PNG
├── mvnw
├── mvnw.cmd
├── pom.xml
├── sql
├── create_table.sql
└── post_es_mapping.json
└── src
├── .DS_Store
├── main
├── java
│ └── com
│ │ └── jl
│ │ └── springbootinit
│ │ ├── MainApplication.java
│ │ ├── annotation
│ │ └── AuthCheck.java
│ │ ├── aop
│ │ ├── AuthInterceptor.java
│ │ └── LogInterceptor.java
│ │ ├── common
│ │ ├── BaseResponse.java
│ │ ├── DeleteRequest.java
│ │ ├── ErrorCode.java
│ │ ├── PageRequest.java
│ │ └── ResultUtils.java
│ │ ├── config
│ │ ├── CorsConfig.java
│ │ ├── JsonConfig.java
│ │ ├── Knife4jConfig.java
│ │ ├── MyBatisPlusConfig.java
│ │ ├── RedissonConfig.java
│ │ ├── ThreadPoolConfig.java
│ │ └── WebSocketConfig.java
│ │ ├── constant
│ │ ├── CommonConstant.java
│ │ └── UserConstant.java
│ │ ├── controller
│ │ ├── ChartController.java
│ │ ├── ScoreController.java
│ │ └── UserController.java
│ │ ├── exception
│ │ ├── BusinessException.java
│ │ ├── GlobalExceptionHandler.java
│ │ └── ThrowUtils.java
│ │ ├── job
│ │ └── cycle
│ │ │ └── UpdateSignStatus.java
│ │ ├── manager
│ │ ├── RedisCacheManager.java
│ │ ├── RedisLimiterManager.java
│ │ └── TaskManager.java
│ │ ├── mapper
│ │ ├── ChartMapper.java
│ │ ├── ScoreMapper.java
│ │ └── UserMapper.java
│ │ ├── model
│ │ ├── dto
│ │ │ ├── chart
│ │ │ │ ├── ChartAddRequest.java
│ │ │ │ ├── ChartEditRequest.java
│ │ │ │ ├── ChartQueryRequest.java
│ │ │ │ ├── ChartUpdateRequest.java
│ │ │ │ └── GenChartByAiRequest.java
│ │ │ └── user
│ │ │ │ ├── UserAddRequest.java
│ │ │ │ ├── UserLoginRequest.java
│ │ │ │ ├── UserQueryRequest.java
│ │ │ │ ├── UserRegisterRequest.java
│ │ │ │ ├── UserUpdateMyRequest.java
│ │ │ │ └── UserUpdateRequest.java
│ │ ├── entity
│ │ │ ├── Chart.java
│ │ │ ├── Score.java
│ │ │ └── User.java
│ │ ├── enums
│ │ │ └── UserRoleEnum.java
│ │ └── vo
│ │ │ ├── BiResponse.java
│ │ │ ├── LoginUserVO.java
│ │ │ └── UserVO.java
│ │ ├── mq
│ │ ├── DeadMessageConsumer.java
│ │ ├── InitMain.java
│ │ ├── MessageConsumer.java
│ │ ├── MessageProducer.java
│ │ └── MqConstant.java
│ │ ├── service
│ │ ├── ChartService.java
│ │ ├── OpenaiService.java
│ │ ├── ScoreService.java
│ │ ├── UserService.java
│ │ └── impl
│ │ │ ├── ChartServiceImpl.java
│ │ │ ├── OpenaiServiceImpl.java
│ │ │ ├── ScoreServiceImpl.java
│ │ │ └── UserServiceImpl.java
│ │ ├── utils
│ │ ├── Csv2String.java
│ │ ├── ExcelUtils.java
│ │ ├── SpringContextUtils.java
│ │ └── SqlUtils.java
│ │ └── ws
│ │ └── WebSocketServer.java
└── resources
│ ├── META-INF
│ └── additional-spring-configuration-metadata.json
│ ├── application.yml
│ └── mapper
│ ├── ChartMapper.xml
│ ├── ScoreMapper.xml
│ └── UserMapper.xml
└── test
└── .DS_Store
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Luojlong/bi-project-core/719e86b9b97384aa1fec31cb1fd156ba0b1dd15f/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### @author 程序员鱼皮 ###
2 | ### @from 编程导航知识星球 ###
3 |
4 | HELP.md
5 | target/
6 | !.mvn/wrapper/maven-wrapper.jar
7 | !**/src/main/**/target/
8 | !**/src/test/**/target/
9 |
10 | ### STS ###
11 | .apt_generated
12 | .classpath
13 | .factorypath
14 | .project
15 | .settings
16 | .springBeans
17 | .sts4-cache
18 |
19 | ### IntelliJ IDEA ###
20 | .idea
21 | *.iws
22 | *.iml
23 | *.ipr
24 |
25 | ### NetBeans ###
26 | /nbproject/private/
27 | /nbbuild/
28 | /dist/
29 | /nbdist/
30 | /.nb-gradle/
31 | build/
32 | !**/src/main/**/build/
33 | !**/src/test/**/build/
34 |
35 | ### VS Code ###
36 | .vscode/
37 | ### Java template
38 | # Compiled class file
39 | *.class
40 |
41 | # Log file
42 | *.log
43 |
44 | # BlueJ files
45 | *.ctxt
46 |
47 | # Mobile Tools for Java (J2ME)
48 | .mtj.tmp/
49 |
50 | # Package Files #
51 | *.jar
52 | *.war
53 | *.nar
54 | *.ear
55 | *.zip
56 | *.tar.gz
57 | *.rar
58 |
59 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
60 | hs_err_pid*
61 |
62 | ### Maven template
63 | target/
64 | pom.xml.tag
65 | pom.xml.releaseBackup
66 | pom.xml.versionsBackup
67 | pom.xml.next
68 | release.properties
69 | dependency-reduced-pom.xml
70 | buildNumber.properties
71 | .mvn/timing.properties
72 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar
73 | .mvn/wrapper/maven-wrapper.jar
74 |
75 | ### JetBrains template
76 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
77 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
78 |
79 | # User-specific stuff
80 | .idea/**/workspace.xml
81 | .idea/**/tasks.xml
82 | .idea/**/usage.statistics.xml
83 | .idea/**/dictionaries
84 | .idea/**/shelf
85 |
86 | # Generated files
87 | .idea/**/contentModel.xml
88 |
89 | # Sensitive or high-churn files
90 | .idea/**/dataSources/
91 | .idea/**/dataSources.ids
92 | .idea/**/dataSources.local.xml
93 | .idea/**/sqlDataSources.xml
94 | .idea/**/dynamic.xml
95 | .idea/**/uiDesigner.xml
96 | .idea/**/dbnavigator.xml
97 |
98 | # Gradle
99 | .idea/**/gradle.xml
100 | .idea/**/libraries
101 |
102 | # Gradle and Maven with auto-import
103 | # When using Gradle or Maven with auto-import, you should exclude module files,
104 | # since they will be recreated, and may cause churn. Uncomment if using
105 | # auto-import.
106 | # .idea/artifacts
107 | # .idea/compiler.xml
108 | # .idea/jarRepositories.xml
109 | # .idea/modules.xml
110 | # .idea/*.iml
111 | # .idea/modules
112 | # *.iml
113 | # *.ipr
114 |
115 | # CMake
116 | cmake-build-*/
117 |
118 | # Mongo Explorer plugin
119 | .idea/**/mongoSettings.xml
120 |
121 | # File-based project format
122 | *.iws
123 |
124 | # IntelliJ
125 | out/
126 |
127 | # mpeltonen/sbt-idea plugin
128 | .idea_modules/
129 |
130 | # JIRA plugin
131 | atlassian-ide-plugin.xml
132 |
133 | # Cursive Clojure plugin
134 | .idea/replstate.xml
135 |
136 | # Crashlytics plugin (for Android Studio and IntelliJ)
137 | com_crashlytics_export_strings.xml
138 | crashlytics.properties
139 | crashlytics-build.properties
140 | fabric.properties
141 |
142 | # Editor-based Rest Client
143 | .idea/httpRequests
144 |
145 | # Android studio 3.1+ serialized cache file
146 | .idea/caches/build_file_checksums.ser
147 |
148 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
3 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Docker 镜像构建
2 | # @author 程序员鱼皮
3 | # @from 编程导航知识星球
4 | FROM maven:3.8.1-jdk-8-slim as builder
5 |
6 | # Copy local code to the container image.
7 | WORKDIR /app
8 | COPY pom.xml .
9 | COPY src ./src
10 |
11 | # Build a release artifact.
12 | RUN mvn package -DskipTests
13 |
14 | # Run the web service on container startup.
15 | CMD ["java","-jar","/app/target/bi-project-core-0.0.1-SNAPSHOT.jar","--spring.profiles.active=prod"]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 基于Openai的智能BI平台
2 |
3 | > 作者:JL
4 |
5 |
6 | 利用大语言模型分析图表数据并自动生成图表分析结论及图表数据可视化图。快速高效处理复杂的数据分析过程。
7 |
8 |
9 | ## 项目介绍
10 |
11 | ### 主要框架及技术使用
12 |
13 | - Spring Boot 2.7.2
14 | - Spring MVC
15 | - MyBatis + MyBatis Plus 数据访问
16 | - Openai API
17 | - Spring Scheduler 定时任务
18 | - Guava 重试机制
19 | - RabbitMQ 消息队列持久化任务
20 | - Redission 的 RateLimiter 限流及图表查询缓存
21 | - WebSocket 任务消息实时发送
22 | - Ant design pro(React)
23 | - Echarts 图表展示
24 | - MySQL 数据库
25 |
26 | ### 基本功能
27 |
28 | - 用户可输入分析目标、图表类型、图表名称后上传文件进行分析,支持仅上传文件
29 | - 分析模式支持两种模型(同步和异步分析)提高用户体验
30 | - 我的图表支持用户查看图表原始数据
31 | - 支持根据图表名称、图表类型、图表分析目标查看和检索图表
32 | - 支持用户对失败的图表进行手动重试
33 | - 支持图表管理页面手动刷新,保证获取到图表的最新状态
34 | - 加入积分系统,每次调用分析消耗积分,可通过签到获取积分
35 | - 任务执行成功或失败,弹出实时消息通知
36 |
37 |
38 | ### 核心流程
39 | 
40 | 
41 |
42 | ### 项目细节
43 |
44 | - 精心设计大语言模型 Prompt 提高 AI 生成的准确性并提升冗余度
45 | - 为节约计算成本,使用 Easy Excel 解析用户上传的 XLSX 表格数据文件并压缩为 CSV,同时实测提高了 20% 的单次输入数据量
46 | - 为防止某用户恶意占用系统资源,基于 Redisson 的 RateLimiter 买现分布式限流,控制单用户访问的频率
47 | - 由于 AI 分析时间较长,基于自定义IO密集型线程池+任务队列实现了 AIGC 的并发执行和异步化,提高用户体验
48 | - 由于本地任务队列重启丢失数据,使用 RabbitMQ (分布式消息队列)来接受并持久化任务消息,通过 Direct 交换机转发给解耦的 Al 生成模块消费并处理任务,提高了系统的可靠性
49 | - 使用死信队列处理异步分析异常情况,同时将图表状态设为失败
50 | - 若任务未提交到队列中(或队列满时),通过定时任务将失败状态图表放入队列中
51 | - 给任务的执行增加 guava Retrying 重试机制,保证同步分析系统可靠性和稳定性。
52 | - 任务成功或失败通过Websocket实时反馈给用户,并更新图表页面,同时可对失败任务手动重试
53 | - 每个用户注册可获得10个积分,每次进行分析需消耗一个积分,可通过每日签到增加积分数
54 | - 使用 Redission 进行用户静态的图表数据缓存,用于提高加载速度
55 |
56 | ### 项目界面
57 | 
58 | 
59 | 
--------------------------------------------------------------------------------
/doc/swagger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Luojlong/bi-project-core/719e86b9b97384aa1fec31cb1fd156ba0b1dd15f/doc/swagger.png
--------------------------------------------------------------------------------
/doc/图片1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Luojlong/bi-project-core/719e86b9b97384aa1fec31cb1fd156ba0b1dd15f/doc/图片1.png
--------------------------------------------------------------------------------
/doc/图片2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Luojlong/bi-project-core/719e86b9b97384aa1fec31cb1fd156ba0b1dd15f/doc/图片2.png
--------------------------------------------------------------------------------
/doc/图片3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Luojlong/bi-project-core/719e86b9b97384aa1fec31cb1fd156ba0b1dd15f/doc/图片3.PNG
--------------------------------------------------------------------------------
/doc/图片4.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Luojlong/bi-project-core/719e86b9b97384aa1fec31cb1fd156ba0b1dd15f/doc/图片4.PNG
--------------------------------------------------------------------------------
/doc/图片5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Luojlong/bi-project-core/719e86b9b97384aa1fec31cb1fd156ba0b1dd15f/doc/图片5.PNG
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /usr/local/etc/mavenrc ] ; then
40 | . /usr/local/etc/mavenrc
41 | fi
42 |
43 | if [ -f /etc/mavenrc ] ; then
44 | . /etc/mavenrc
45 | fi
46 |
47 | if [ -f "$HOME/.mavenrc" ] ; then
48 | . "$HOME/.mavenrc"
49 | fi
50 |
51 | fi
52 |
53 | # OS specific support. $var _must_ be set to either true or false.
54 | cygwin=false;
55 | darwin=false;
56 | mingw=false
57 | case "`uname`" in
58 | CYGWIN*) cygwin=true ;;
59 | MINGW*) mingw=true;;
60 | Darwin*) darwin=true
61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
63 | if [ -z "$JAVA_HOME" ]; then
64 | if [ -x "/usr/libexec/java_home" ]; then
65 | export JAVA_HOME="`/usr/libexec/java_home`"
66 | else
67 | export JAVA_HOME="/Library/Java/Home"
68 | fi
69 | fi
70 | ;;
71 | esac
72 |
73 | if [ -z "$JAVA_HOME" ] ; then
74 | if [ -r /etc/gentoo-release ] ; then
75 | JAVA_HOME=`java-config --jre-home`
76 | fi
77 | fi
78 |
79 | if [ -z "$M2_HOME" ] ; then
80 | ## resolve links - $0 may be a link to maven's home
81 | PRG="$0"
82 |
83 | # need this for relative symlinks
84 | while [ -h "$PRG" ] ; do
85 | ls=`ls -ld "$PRG"`
86 | link=`expr "$ls" : '.*-> \(.*\)$'`
87 | if expr "$link" : '/.*' > /dev/null; then
88 | PRG="$link"
89 | else
90 | PRG="`dirname "$PRG"`/$link"
91 | fi
92 | done
93 |
94 | saveddir=`pwd`
95 |
96 | M2_HOME=`dirname "$PRG"`/..
97 |
98 | # make it fully qualified
99 | M2_HOME=`cd "$M2_HOME" && pwd`
100 |
101 | cd "$saveddir"
102 | # echo Using m2 at $M2_HOME
103 | fi
104 |
105 | # For Cygwin, ensure paths are in UNIX format before anything is touched
106 | if $cygwin ; then
107 | [ -n "$M2_HOME" ] &&
108 | M2_HOME=`cygpath --unix "$M2_HOME"`
109 | [ -n "$JAVA_HOME" ] &&
110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
111 | [ -n "$CLASSPATH" ] &&
112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
113 | fi
114 |
115 | # For Mingw, ensure paths are in UNIX format before anything is touched
116 | if $mingw ; then
117 | [ -n "$M2_HOME" ] &&
118 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
119 | [ -n "$JAVA_HOME" ] &&
120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
121 | fi
122 |
123 | if [ -z "$JAVA_HOME" ]; then
124 | javaExecutable="`which javac`"
125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
126 | # readlink(1) is not available as standard on Solaris 10.
127 | readLink=`which readlink`
128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
129 | if $darwin ; then
130 | javaHome="`dirname \"$javaExecutable\"`"
131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
132 | else
133 | javaExecutable="`readlink -f \"$javaExecutable\"`"
134 | fi
135 | javaHome="`dirname \"$javaExecutable\"`"
136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
137 | JAVA_HOME="$javaHome"
138 | export JAVA_HOME
139 | fi
140 | fi
141 | fi
142 |
143 | if [ -z "$JAVACMD" ] ; then
144 | if [ -n "$JAVA_HOME" ] ; then
145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
146 | # IBM's JDK on AIX uses strange locations for the executables
147 | JAVACMD="$JAVA_HOME/jre/sh/java"
148 | else
149 | JAVACMD="$JAVA_HOME/bin/java"
150 | fi
151 | else
152 | JAVACMD="`\\unset -f command; \\command -v java`"
153 | fi
154 | fi
155 |
156 | if [ ! -x "$JAVACMD" ] ; then
157 | echo "Error: JAVA_HOME is not defined correctly." >&2
158 | echo " We cannot execute $JAVACMD" >&2
159 | exit 1
160 | fi
161 |
162 | if [ -z "$JAVA_HOME" ] ; then
163 | echo "Warning: JAVA_HOME environment variable is not set."
164 | fi
165 |
166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
167 |
168 | # traverses directory structure from process work directory to filesystem root
169 | # first directory with .mvn subdirectory is considered project base directory
170 | find_maven_basedir() {
171 |
172 | if [ -z "$1" ]
173 | then
174 | echo "Path not specified to find_maven_basedir"
175 | return 1
176 | fi
177 |
178 | basedir="$1"
179 | wdir="$1"
180 | while [ "$wdir" != '/' ] ; do
181 | if [ -d "$wdir"/.mvn ] ; then
182 | basedir=$wdir
183 | break
184 | fi
185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
186 | if [ -d "${wdir}" ]; then
187 | wdir=`cd "$wdir/.."; pwd`
188 | fi
189 | # end of workaround
190 | done
191 | echo "${basedir}"
192 | }
193 |
194 | # concatenates all lines of a file
195 | concat_lines() {
196 | if [ -f "$1" ]; then
197 | echo "$(tr -s '\n' ' ' < "$1")"
198 | fi
199 | }
200 |
201 | BASE_DIR=`find_maven_basedir "$(pwd)"`
202 | if [ -z "$BASE_DIR" ]; then
203 | exit 1;
204 | fi
205 |
206 | ##########################################################################################
207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
208 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
209 | ##########################################################################################
210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Found .mvn/wrapper/maven-wrapper.jar"
213 | fi
214 | else
215 | if [ "$MVNW_VERBOSE" = true ]; then
216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
217 | fi
218 | if [ -n "$MVNW_REPOURL" ]; then
219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
220 | else
221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
222 | fi
223 | while IFS="=" read key value; do
224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
225 | esac
226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
227 | if [ "$MVNW_VERBOSE" = true ]; then
228 | echo "Downloading from: $jarUrl"
229 | fi
230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
231 | if $cygwin; then
232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
233 | fi
234 |
235 | if command -v wget > /dev/null; then
236 | if [ "$MVNW_VERBOSE" = true ]; then
237 | echo "Found wget ... using wget"
238 | fi
239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
241 | else
242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
243 | fi
244 | elif command -v curl > /dev/null; then
245 | if [ "$MVNW_VERBOSE" = true ]; then
246 | echo "Found curl ... using curl"
247 | fi
248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
249 | curl -o "$wrapperJarPath" "$jarUrl" -f
250 | else
251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
252 | fi
253 |
254 | else
255 | if [ "$MVNW_VERBOSE" = true ]; then
256 | echo "Falling back to using Java to download"
257 | fi
258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
259 | # For Cygwin, switch paths to Windows format before running javac
260 | if $cygwin; then
261 | javaClass=`cygpath --path --windows "$javaClass"`
262 | fi
263 | if [ -e "$javaClass" ]; then
264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
265 | if [ "$MVNW_VERBOSE" = true ]; then
266 | echo " - Compiling MavenWrapperDownloader.java ..."
267 | fi
268 | # Compiling the Java class
269 | ("$JAVA_HOME/bin/javac" "$javaClass")
270 | fi
271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
272 | # Running the downloader
273 | if [ "$MVNW_VERBOSE" = true ]; then
274 | echo " - Running MavenWrapperDownloader.java ..."
275 | fi
276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
277 | fi
278 | fi
279 | fi
280 | fi
281 | ##########################################################################################
282 | # End of extension
283 | ##########################################################################################
284 |
285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
286 | if [ "$MVNW_VERBOSE" = true ]; then
287 | echo $MAVEN_PROJECTBASEDIR
288 | fi
289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
290 |
291 | # For Cygwin, switch paths to Windows format before running java
292 | if $cygwin; then
293 | [ -n "$M2_HOME" ] &&
294 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
295 | [ -n "$JAVA_HOME" ] &&
296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
297 | [ -n "$CLASSPATH" ] &&
298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
299 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
301 | fi
302 |
303 | # Provide a "standardized" way to retrieve the CLI args that will
304 | # work with both Windows and non-Windows executions.
305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
306 | export MAVEN_CMD_LINE_ARGS
307 |
308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
309 |
310 | exec "$JAVACMD" \
311 | $MAVEN_OPTS \
312 | $MAVEN_DEBUG_OPTS \
313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
314 | "-Dmaven.home=${M2_HOME}" \
315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
317 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
124 |
125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% ^
162 | %JVM_CONFIG_MAVEN_PROPS% ^
163 | %MAVEN_OPTS% ^
164 | %MAVEN_DEBUG_OPTS% ^
165 | -classpath %WRAPPER_JAR% ^
166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
168 | if ERRORLEVEL 1 goto error
169 | goto end
170 |
171 | :error
172 | set ERROR_CODE=1
173 |
174 | :end
175 | @endlocal & set ERROR_CODE=%ERROR_CODE%
176 |
177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
181 | :skipRcPost
182 |
183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause
185 |
186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
187 |
188 | cmd /C exit /B %ERROR_CODE%
189 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 | 4.0.0
8 |
9 | org.springframework.boot
10 | spring-boot-starter-parent
11 | 2.7.2
12 |
13 |
14 | com.jl
15 | bi-project-core
16 | 0.0.1-SNAPSHOT
17 | bi-project-core
18 |
19 | 1.8
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-amqp
25 | 2.7.2
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-websocket
30 | 2.7.2
31 |
32 |
33 |
34 | com.google.guava
35 | guava
36 | 32.0.1-jre
37 |
38 |
39 |
40 | com.github.rholder
41 | guava-retrying
42 | 2.0.0
43 |
44 |
45 | com.rabbitmq
46 | amqp-client
47 | 5.17.0
48 |
49 |
50 | org.redisson
51 | redisson
52 | 3.21.3
53 |
54 |
55 | com.theokanning.openai-gpt3-java
56 | service
57 | 0.12.0
58 |
59 |
60 | com.google.code.gson
61 | gson
62 | 2.9.1
63 |
64 |
65 | com.fasterxml.jackson.core
66 | jackson-databind
67 |
68 |
69 | com.fasterxml.jackson.core
70 | jackson-annotations
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-starter-freemarker
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-starter-web
79 |
80 |
81 | org.springframework.boot
82 | spring-boot-starter-aop
83 |
84 |
85 | org.mybatis.spring.boot
86 | mybatis-spring-boot-starter
87 | 2.2.2
88 |
89 |
90 |
91 | com.baomidou
92 | mybatis-plus-boot-starter
93 | 3.5.2
94 |
95 |
96 |
97 | org.springframework.boot
98 | spring-boot-starter-data-redis
99 |
100 |
101 | org.springframework.session
102 | spring-session-data-redis
103 |
104 |
105 |
106 | org.springframework.boot
107 | spring-boot-starter-data-elasticsearch
108 |
109 |
110 |
111 | com.github.binarywang
112 | wx-java-mp-spring-boot-starter
113 | 4.4.0
114 |
115 |
116 |
117 | com.github.xiaoymin
118 | knife4j-spring-boot-starter
119 | 3.0.3
120 |
121 |
122 |
123 | com.qcloud
124 | cos_api
125 | 5.6.89
126 |
127 |
128 |
129 | org.apache.commons
130 | commons-lang3
131 |
132 |
133 |
134 | com.google.code.gson
135 | gson
136 | 2.9.1
137 |
138 |
139 |
140 | com.alibaba
141 | easyexcel
142 | 3.1.1
143 |
144 |
145 |
146 | cn.hutool
147 | hutool-all
148 | 5.8.8
149 |
150 |
151 | org.springframework.boot
152 | spring-boot-devtools
153 | runtime
154 | true
155 |
156 |
157 | mysql
158 | mysql-connector-java
159 | 8.0.29
160 | runtime
161 |
162 |
163 | org.springframework.boot
164 | spring-boot-configuration-processor
165 | true
166 |
167 |
168 | org.projectlombok
169 | lombok
170 | true
171 |
172 |
173 | org.springframework.boot
174 | spring-boot-starter-test
175 | test
176 |
177 |
178 |
179 |
180 |
181 |
182 | org.springframework.boot
183 | spring-boot-maven-plugin
184 |
185 |
186 |
187 | org.projectlombok
188 | lombok
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/sql/create_table.sql:
--------------------------------------------------------------------------------
1 | # 数据库初始化
2 | # @author 程序员鱼皮
3 | # @from 编程导航知识星球
4 |
5 | -- 创建库
6 | create database if not exists bidb;
7 |
8 | -- 切换库
9 | use bidb;
10 |
11 | -- 用户表
12 | create table if not exists user
13 | (
14 | id bigint auto_increment comment 'id' primary key,
15 | userAccount varchar(256) not null comment '账号',
16 | userPassword varchar(512) not null comment '密码',
17 | userName varchar(256) null comment '用户昵称',
18 | userAvatar varchar(1024) null comment '用户头像',
19 | userRole varchar(256) default 'user' not null comment '用户角色:user/admin',
20 | createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
21 | updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
22 | isDelete tinyint default 0 not null comment '是否删除', index idx_userAccount (userAccount)
23 | ) comment '用户' collate = utf8mb4_unicode_ci;
24 |
25 | -- 图表表
26 | create table if not exists chart
27 | (
28 | id bigint auto_increment comment 'id' primary key,
29 | goal text null comment '分析目标',
30 | chartData text null comment '图表数据',
31 | chartType varchar(128) null comment '图表类型',
32 | genChart text null comment '生成的图表数据',
33 | genResult text null comment '生成的分析结论',
34 | userId bigint null comment '创建用户 id',
35 | createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
36 | updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
37 | isDelete tinyint default 0 not null comment '是否删除',
38 | `name` varchar(128) null comment '图表名称',
39 | status varchar(128) default 'wait' not null comment '图表状态',
40 | execMessage text null comment '图表状态执行信息',
41 | retry int default 0 not null comment '图表分析重试次数'
42 | ) comment '图表信息表' collate = utf8mb4_unicode_ci;
43 |
44 | -- 积分表
45 | create table if not exists score
46 | (
47 | id bigint auto_increment comment 'id' primary key,
48 | userId bigint comment '创建用户id',
49 | scoreTotal bigint null comment '总积分' default 0,
50 | isSign tinyint comment '0表示未签到,1表示已签到' default 0,
51 | createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
52 | updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
53 | isDelete tinyint default 0 not null comment '是否删除'
54 | ) comment '积分表' collate = utf8mb4_unicode_ci;
55 |
--------------------------------------------------------------------------------
/sql/post_es_mapping.json:
--------------------------------------------------------------------------------
1 | {
2 | "aliases": {
3 | "post": {}
4 | },
5 | "mappings": {
6 | "properties": {
7 | "title": {
8 | "type": "text",
9 | "analyzer": "ik_max_word",
10 | "search_analyzer": "ik_smart",
11 | "fields": {
12 | "keyword": {
13 | "type": "keyword",
14 | "ignore_above": 256
15 | }
16 | }
17 | },
18 | "content": {
19 | "type": "text",
20 | "analyzer": "ik_max_word",
21 | "search_analyzer": "ik_smart",
22 | "fields": {
23 | "keyword": {
24 | "type": "keyword",
25 | "ignore_above": 256
26 | }
27 | }
28 | },
29 | "tags": {
30 | "type": "keyword"
31 | },
32 | "thumbNum": {
33 | "type": "long"
34 | },
35 | "favourNum": {
36 | "type": "long"
37 | },
38 | "userId": {
39 | "type": "keyword"
40 | },
41 | "createTime": {
42 | "type": "date"
43 | },
44 | "updateTime": {
45 | "type": "date"
46 | },
47 | "isDelete": {
48 | "type": "keyword"
49 | }
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Luojlong/bi-project-core/719e86b9b97384aa1fec31cb1fd156ba0b1dd15f/src/.DS_Store
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit;
2 |
3 | import org.mybatis.spring.annotation.MapperScan;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
7 | import org.springframework.context.annotation.EnableAspectJAutoProxy;
8 | import org.springframework.scheduling.annotation.EnableScheduling;
9 | import org.springframework.web.socket.config.annotation.EnableWebSocket;
10 |
11 | /**
12 | * 主类(项目启动入口)
13 | *
14 | */
15 | // todo 如需开启 Redis,须移除 exclude 中的内容
16 | @SpringBootApplication(exclude = {RedisAutoConfiguration.class})
17 | @MapperScan("com.jl.springbootinit.mapper")
18 | @EnableScheduling
19 | @EnableWebSocket
20 | @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
21 | public class MainApplication {
22 |
23 | public static void main(String[] args) {
24 | SpringApplication.run(MainApplication.class, args);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/annotation/AuthCheck.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 权限校验
10 | *
11 | */
12 | @Target(ElementType.METHOD)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | public @interface AuthCheck {
15 |
16 | /**
17 | * 必须有某个角色
18 | *
19 | * @return
20 | */
21 | String mustRole() default "";
22 |
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/aop/AuthInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.aop;
2 |
3 | import com.jl.springbootinit.annotation.AuthCheck;
4 | import com.jl.springbootinit.common.ErrorCode;
5 | import com.jl.springbootinit.exception.BusinessException;
6 | import com.jl.springbootinit.model.entity.User;
7 | import com.jl.springbootinit.model.enums.UserRoleEnum;
8 | import com.jl.springbootinit.service.UserService;
9 | import javax.annotation.Resource;
10 | import javax.servlet.http.HttpServletRequest;
11 | import org.apache.commons.lang3.StringUtils;
12 | import org.aspectj.lang.ProceedingJoinPoint;
13 | import org.aspectj.lang.annotation.Around;
14 | import org.aspectj.lang.annotation.Aspect;
15 | import org.springframework.stereotype.Component;
16 | import org.springframework.web.context.request.RequestAttributes;
17 | import org.springframework.web.context.request.RequestContextHolder;
18 | import org.springframework.web.context.request.ServletRequestAttributes;
19 |
20 | /**
21 | * 权限校验 AOP
22 | *
23 | */
24 | @Aspect
25 | @Component
26 | public class AuthInterceptor {
27 |
28 | @Resource
29 | private UserService userService;
30 |
31 | /**
32 | * 执行拦截
33 | *
34 | * @param joinPoint
35 | * @param authCheck
36 | * @return
37 | */
38 | @Around("@annotation(authCheck)")
39 | public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
40 | String mustRole = authCheck.mustRole();
41 | RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
42 | HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
43 | // 当前登录用户
44 | User loginUser = userService.getLoginUser(request);
45 | // 必须有该权限才通过
46 | if (StringUtils.isNotBlank(mustRole)) {
47 | UserRoleEnum mustUserRoleEnum = UserRoleEnum.getEnumByValue(mustRole);
48 | if (mustUserRoleEnum == null) {
49 | throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
50 | }
51 | String userRole = loginUser.getUserRole();
52 | // 如果被封号,直接拒绝
53 | if (UserRoleEnum.BAN.equals(mustUserRoleEnum)) {
54 | throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
55 | }
56 | // 必须有管理员权限
57 | if (UserRoleEnum.ADMIN.equals(mustUserRoleEnum)) {
58 | if (!mustRole.equals(userRole)) {
59 | throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
60 | }
61 | }
62 | }
63 | // 通过权限校验,放行
64 | return joinPoint.proceed();
65 | }
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/aop/LogInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.aop;
2 |
3 | import java.util.UUID;
4 | import javax.servlet.http.HttpServletRequest;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.apache.commons.lang3.StringUtils;
7 | import org.aspectj.lang.ProceedingJoinPoint;
8 | import org.aspectj.lang.annotation.Around;
9 | import org.aspectj.lang.annotation.Aspect;
10 | import org.springframework.stereotype.Component;
11 | import org.springframework.util.StopWatch;
12 | import org.springframework.web.context.request.RequestAttributes;
13 | import org.springframework.web.context.request.RequestContextHolder;
14 | import org.springframework.web.context.request.ServletRequestAttributes;
15 |
16 | /**
17 | * 请求响应日志 AOP
18 | *
19 | **/
20 | @Aspect
21 | @Component
22 | @Slf4j
23 | public class LogInterceptor {
24 |
25 | /**
26 | * 执行拦截
27 | */
28 | @Around("execution(* com.jl.springbootinit.controller.*.*(..))")
29 | public Object doInterceptor(ProceedingJoinPoint point) throws Throwable {
30 | // 计时
31 | StopWatch stopWatch = new StopWatch();
32 | stopWatch.start();
33 | // 获取请求路径
34 | RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
35 | HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
36 | // 生成请求唯一 id
37 | String requestId = UUID.randomUUID().toString();
38 | String url = httpServletRequest.getRequestURI();
39 | // 获取请求参数
40 | Object[] args = point.getArgs();
41 | String reqParam = "[" + StringUtils.join(args, ", ") + "]";
42 | // 输出请求日志
43 | log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url,
44 | httpServletRequest.getRemoteHost(), reqParam);
45 | // 执行原方法
46 | Object result = point.proceed();
47 | // 输出响应日志
48 | stopWatch.stop();
49 | long totalTimeMillis = stopWatch.getTotalTimeMillis();
50 | log.info("request end, id: {}, cost: {}ms", requestId, totalTimeMillis);
51 | return result;
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/common/BaseResponse.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.common;
2 |
3 | import java.io.Serializable;
4 | import lombok.Data;
5 |
6 | /**
7 | * 通用返回类
8 | *
9 | * @param
10 | * @author 程序员鱼皮
11 | * @from 编程导航知识星球
12 | */
13 | @Data
14 | public class BaseResponse implements Serializable {
15 |
16 | private int code;
17 |
18 | private T data;
19 |
20 | private String message;
21 |
22 | public BaseResponse(int code, T data, String message) {
23 | this.code = code;
24 | this.data = data;
25 | this.message = message;
26 | }
27 |
28 | public BaseResponse(int code, T data) {
29 | this(code, data, "");
30 | }
31 |
32 | public BaseResponse(ErrorCode errorCode) {
33 | this(errorCode.getCode(), null, errorCode.getMessage());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/common/DeleteRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.common;
2 |
3 | import java.io.Serializable;
4 | import lombok.Data;
5 |
6 | /**
7 | * 删除请求
8 | *
9 | */
10 | @Data
11 | public class DeleteRequest implements Serializable {
12 |
13 | /**
14 | * id
15 | */
16 | private Long id;
17 |
18 | private static final long serialVersionUID = 1L;
19 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/common/ErrorCode.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.common;
2 |
3 | /**
4 | * 自定义错误码
5 | *
6 | */
7 | public enum ErrorCode {
8 |
9 | SUCCESS(0, "ok"),
10 | PARAMS_ERROR(40000, "请求参数错误"),
11 | NOT_LOGIN_ERROR(40100, "未登录"),
12 | NO_AUTH_ERROR(40101, "无权限"),
13 | NOT_FOUND_ERROR(40400, "请求数据不存在"),
14 | TO_MANY_REQUEST(42900, "请求频繁"),
15 | FORBIDDEN_ERROR(40300, "禁止访问"),
16 | SYSTEM_ERROR(50000, "系统内部异常"),
17 | OPERATION_ERROR(50001, "操作失败");
18 |
19 | /**
20 | * 状态码
21 | */
22 | private final int code;
23 |
24 | /**
25 | * 信息
26 | */
27 | private final String message;
28 |
29 | ErrorCode(int code, String message) {
30 | this.code = code;
31 | this.message = message;
32 | }
33 |
34 | public int getCode() {
35 | return code;
36 | }
37 |
38 | public String getMessage() {
39 | return message;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/common/PageRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.common;
2 |
3 | import com.jl.springbootinit.constant.CommonConstant;
4 | import lombok.Data;
5 |
6 | /**
7 | * 分页请求
8 | *
9 | */
10 | @Data
11 | public class PageRequest {
12 |
13 | /**
14 | * 当前页号
15 | */
16 | private long current = 1;
17 |
18 | /**
19 | * 页面大小
20 | */
21 | private long pageSize = 10;
22 |
23 | /**
24 | * 排序字段
25 | */
26 | private String sortField;
27 |
28 | /**
29 | * 排序顺序(默认升序)
30 | */
31 | private String sortOrder = CommonConstant.SORT_ORDER_ASC;
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/common/ResultUtils.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.common;
2 |
3 | /**
4 | * 返回工具类
5 | *
6 | */
7 | public class ResultUtils {
8 |
9 | /**
10 | * 成功
11 | *
12 | * @param data
13 | * @param
14 | * @return
15 | */
16 | public static BaseResponse success(T data) {
17 | return new BaseResponse<>(0, data, "ok");
18 | }
19 |
20 | /**
21 | * 失败
22 | *
23 | * @param errorCode
24 | * @return
25 | */
26 | public static BaseResponse error(ErrorCode errorCode) {
27 | return new BaseResponse<>(errorCode);
28 | }
29 |
30 | /**
31 | * 失败
32 | *
33 | * @param code
34 | * @param message
35 | * @return
36 | */
37 | public static BaseResponse error(int code, String message) {
38 | return new BaseResponse(code, null, message);
39 | }
40 |
41 | /**
42 | * 失败
43 | *
44 | * @param errorCode
45 | * @return
46 | */
47 | public static BaseResponse error(ErrorCode errorCode, String message) {
48 | return new BaseResponse(errorCode.getCode(), null, message);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/config/CorsConfig.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.web.servlet.config.annotation.CorsRegistry;
5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
6 |
7 | /**
8 | * 全局跨域配置
9 | *
10 | */
11 | @Configuration
12 | public class CorsConfig implements WebMvcConfigurer {
13 |
14 | @Override
15 | public void addCorsMappings(CorsRegistry registry) {
16 | // 覆盖所有请求
17 | registry.addMapping("/**")
18 | // 允许发送 Cookie
19 | .allowCredentials(true)
20 | // 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突)
21 | .allowedOriginPatterns("*")
22 | .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
23 | .allowedHeaders("*")
24 | .exposedHeaders("*");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/config/JsonConfig.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.fasterxml.jackson.databind.module.SimpleModule;
5 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
6 | import org.springframework.boot.jackson.JsonComponent;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
9 |
10 | /**
11 | * Spring MVC Json 配置
12 | *
13 | */
14 | @JsonComponent
15 | public class JsonConfig {
16 |
17 | /**
18 | * 添加 Long 转 json 精度丢失的配置
19 | */
20 | @Bean
21 | public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
22 | ObjectMapper objectMapper = builder.createXmlMapper(false).build();
23 | SimpleModule module = new SimpleModule();
24 | module.addSerializer(Long.class, ToStringSerializer.instance);
25 | module.addSerializer(Long.TYPE, ToStringSerializer.instance);
26 | objectMapper.registerModule(module);
27 | return objectMapper;
28 | }
29 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/config/Knife4jConfig.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.context.annotation.Profile;
6 | import springfox.documentation.builders.ApiInfoBuilder;
7 | import springfox.documentation.builders.PathSelectors;
8 | import springfox.documentation.builders.RequestHandlerSelectors;
9 | import springfox.documentation.spi.DocumentationType;
10 | import springfox.documentation.spring.web.plugins.Docket;
11 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
12 |
13 | /**
14 | * Knife4j 接口文档配置
15 | * https://doc.xiaominfo.com/knife4j/documentation/get_start.html
16 | *
17 | */
18 | @Configuration
19 | @EnableSwagger2
20 | @Profile({"dev", "test"})
21 | public class Knife4jConfig {
22 |
23 | @Bean
24 | public Docket defaultApi2() {
25 | return new Docket(DocumentationType.SWAGGER_2)
26 | .apiInfo(new ApiInfoBuilder()
27 | .title("接口文档")
28 | .description("bi-project-core")
29 | .version("1.0")
30 | .build())
31 | .select()
32 | // 指定 Controller 扫描包路径
33 | .apis(RequestHandlerSelectors.basePackage("com.jl.springbootinit.controller"))
34 | .paths(PathSelectors.any())
35 | .build();
36 | }
37 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/config/MyBatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.config;
2 |
3 | import com.baomidou.mybatisplus.annotation.DbType;
4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
5 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
6 | import org.mybatis.spring.annotation.MapperScan;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 | /**
11 | * MyBatis Plus 配置
12 | *
13 | * @author https://github.com/liyupi
14 | */
15 | @Configuration
16 | @MapperScan("com.jl.springbootinit.mapper")
17 | public class MyBatisPlusConfig {
18 |
19 | /**
20 | * 拦截器配置
21 | *
22 | * @return
23 | */
24 | @Bean
25 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
26 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
27 | // 分页插件
28 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
29 | return interceptor;
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/config/RedissonConfig.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.config;
2 |
3 | import lombok.Data;
4 | import org.redisson.Redisson;
5 | import org.redisson.api.RedissonClient;
6 | import org.redisson.config.Config;
7 | import org.springframework.boot.context.properties.ConfigurationProperties;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 |
11 | @Configuration
12 | @ConfigurationProperties(prefix = "spring.redis")
13 | @Data
14 | public class RedissonConfig {
15 |
16 | private String host;
17 |
18 | private Integer port;
19 | // 上线密码
20 | private String password;
21 | @Bean
22 | public RedissonClient redissonClient() {
23 | Config config = new Config();
24 | config.useSingleServer()
25 | .setDatabase(1)
26 | .setAddress("redis://" + host + ":" + port)
27 | .setPassword(password);
28 | RedissonClient redisson = Redisson.create(config);
29 | return redisson;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/config/ThreadPoolConfig.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.config;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | import java.util.concurrent.ArrayBlockingQueue;
8 | import java.util.concurrent.ThreadFactory;
9 | import java.util.concurrent.ThreadPoolExecutor;
10 | import java.util.concurrent.TimeUnit;
11 |
12 | @Configuration
13 | public class ThreadPoolConfig {
14 | @Bean
15 | public ThreadPoolExecutor threadPoolExecutor(){
16 | ThreadFactory threadFactory = new ThreadFactory() {
17 | private int count = 1;
18 |
19 | @Override
20 | public Thread newThread(@NotNull Runnable r) {
21 | Thread thread = new Thread(r);
22 | thread.setName("线程" + count);
23 | return thread;
24 | }
25 | };
26 | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
27 | 2,
28 | 4,
29 | 100,
30 | TimeUnit.SECONDS,
31 | new ArrayBlockingQueue<>(100),
32 | threadFactory);
33 | return threadPoolExecutor;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/config/WebSocketConfig.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.socket.server.standard.ServerEndpointExporter;
6 |
7 | /**
8 | * WebSocket配置类。开启WebSocket的支持
9 | */
10 | @Configuration
11 | public class WebSocketConfig {
12 |
13 | /**
14 | * bean注册:会自动扫描带有@ServerEndpoint注解声明的Websocket Endpoint(端点),注册成为Websocket bean。
15 | */
16 | @Bean
17 | public ServerEndpointExporter serverEndpointExporter() {
18 | return new ServerEndpointExporter();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/constant/CommonConstant.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.constant;
2 |
3 | /**
4 | * 通用常量
5 | *
6 | */
7 | public interface CommonConstant {
8 |
9 | /**
10 | * 升序
11 | */
12 | String SORT_ORDER_ASC = "ascend";
13 |
14 | /**
15 | * 降序
16 | */
17 | String SORT_ORDER_DESC = " descend";
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/constant/UserConstant.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.constant;
2 |
3 | /**
4 | * 用户常量
5 | *
6 | */
7 | public interface UserConstant {
8 |
9 | /**
10 | * 用户登录态键
11 | */
12 | String USER_LOGIN_STATE = "user_login";
13 |
14 | // region 权限
15 |
16 | /**
17 | * 默认角色
18 | */
19 | String DEFAULT_ROLE = "user";
20 |
21 | /**
22 | * 管理员角色
23 | */
24 | String ADMIN_ROLE = "admin";
25 |
26 | /**
27 | * 被封号
28 | */
29 | String BAN_ROLE = "ban";
30 |
31 | // endregion
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/controller/ChartController.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.controller;
2 |
3 | import cn.hutool.core.io.FileUtil;
4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
5 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
6 | import com.google.gson.*;
7 | import com.jl.springbootinit.annotation.AuthCheck;
8 | import com.jl.springbootinit.common.BaseResponse;
9 | import com.jl.springbootinit.common.DeleteRequest;
10 | import com.jl.springbootinit.common.ErrorCode;
11 | import com.jl.springbootinit.common.ResultUtils;
12 | import com.jl.springbootinit.constant.CommonConstant;
13 | import com.jl.springbootinit.constant.UserConstant;
14 | import com.jl.springbootinit.exception.BusinessException;
15 | import com.jl.springbootinit.exception.ThrowUtils;
16 | import com.jl.springbootinit.manager.RedisCacheManager;
17 | import com.jl.springbootinit.manager.RedisLimiterManager;
18 | import com.jl.springbootinit.manager.TaskManager;
19 | import com.jl.springbootinit.model.dto.chart.*;
20 | import com.jl.springbootinit.model.entity.Chart;
21 | import com.jl.springbootinit.model.entity.User;
22 | import com.jl.springbootinit.model.vo.BiResponse;
23 | import com.jl.springbootinit.mq.MessageProducer;
24 | import com.jl.springbootinit.service.ChartService;
25 | import com.jl.springbootinit.service.OpenaiService;
26 | import com.jl.springbootinit.service.ScoreService;
27 | import com.jl.springbootinit.service.UserService;
28 | import com.jl.springbootinit.utils.Csv2String;
29 | import com.jl.springbootinit.utils.ExcelUtils;
30 | import com.jl.springbootinit.utils.SqlUtils;
31 | import com.sun.org.apache.xpath.internal.operations.Bool;
32 | import lombok.extern.slf4j.Slf4j;
33 | import org.apache.commons.lang3.ObjectUtils;
34 | import org.apache.commons.lang3.StringUtils;
35 | import org.redisson.api.RMap;
36 | import org.springframework.beans.BeanUtils;
37 | import org.springframework.web.bind.annotation.*;
38 | import org.springframework.web.multipart.MultipartFile;
39 | import javax.annotation.Resource;
40 | import javax.servlet.http.HttpServletRequest;
41 | import java.util.Arrays;
42 | import java.util.List;
43 | import java.util.Objects;
44 | import java.util.concurrent.*;
45 |
46 | import static com.jl.springbootinit.service.impl.OpenaiServiceImpl.SYNCHRO_MAX_TOKEN;
47 |
48 | /**
49 | * 图表接口
50 | *
51 | */
52 | @RestController
53 | @RequestMapping("/chart")
54 | @Slf4j
55 | public class ChartController {
56 |
57 | @Resource
58 | private ChartService chartService;
59 |
60 | @Resource
61 | private UserService userService;
62 |
63 | @Resource
64 | private OpenaiService openaiService;
65 |
66 | @Resource
67 | private ScoreService scoreService;
68 |
69 | @Resource
70 | private RedisCacheManager redisCacheManager;
71 |
72 | @Resource
73 | private RedisLimiterManager redisLimiterManager;
74 |
75 | @Resource
76 | private ThreadPoolExecutor threadPoolExecutor;
77 |
78 | @Resource
79 | private MessageProducer messageProducer;
80 |
81 | @Resource
82 | private TaskManager taskManager;
83 |
84 | /**
85 | * 文件AI分析
86 | *
87 | * @param multipartFile
88 | * @param genChartByAiRequest
89 | * @param request
90 | * @return
91 | */
92 | @PostMapping("/gen")
93 | public BaseResponse genChartByAi(@RequestPart("file") MultipartFile multipartFile,
94 | GenChartByAiRequest genChartByAiRequest, HttpServletRequest request) {
95 | String name = genChartByAiRequest.getName();
96 | String goal = genChartByAiRequest.getGoal();
97 | String chartType = genChartByAiRequest.getChartType();
98 | // 校验
99 | ThrowUtils.throwIf(StringUtils.isNotBlank(name) && name.length() > 100, ErrorCode.PARAMS_ERROR, "名称过长");
100 | User loginUser = userService.getLoginUser(request);
101 | // 校验文件大小及后缀
102 | long size = multipartFile.getSize();
103 | final long TEN_MB = 10 * 1024 * 1024L;
104 | ThrowUtils.throwIf(size > TEN_MB, ErrorCode.PARAMS_ERROR, "文件大小大于1M");
105 | String fileName = multipartFile.getOriginalFilename();
106 | String suffix = FileUtil.getSuffix(fileName);
107 | final List validFileSuffix = Arrays.asList("xlsx", "csv", "xls");
108 | ThrowUtils.throwIf(!validFileSuffix.contains(suffix), ErrorCode.PARAMS_ERROR, "文件后缀非法");
109 | // 每个用户限流
110 | redisLimiterManager.doRateLimit("genChartByAi" + loginUser.getId());
111 | // 构造用户输入
112 | StringBuilder userInput = new StringBuilder();
113 | userInput.append("分析需求:\n");
114 | // 拼接分析目标
115 | String userGoal = "请帮我合理的分析一下数据";
116 | if (StringUtils.isNotBlank(goal))
117 | userGoal = goal;
118 | // 分析输入加入图表类型
119 | if (StringUtils.isNotBlank(chartType))
120 | userGoal += ",请使用" + chartType;
121 | userInput.append(userGoal).append("\n");
122 | userInput.append("原始数据:\n");
123 | // 压缩数据
124 | String userData = "";
125 | if (Objects.equals(suffix, "csv"))
126 | userData = Csv2String.MultipartFileToString(multipartFile);
127 | else
128 | userData = ExcelUtils.excel2Csv(multipartFile);
129 | BiResponse biResponse = new BiResponse();
130 | Chart chart = new Chart();
131 | // 数据规模校验 gpt3.5分析时长超过30s
132 | if (userData.length() > SYNCHRO_MAX_TOKEN){
133 | biResponse.setGenChart("");
134 | biResponse.setGenResult("large_size");
135 | biResponse.setChartId(chart.getId());
136 | return ResultUtils.success(biResponse);
137 | }
138 | userInput.append(userData).append("\n");
139 | String result = "";
140 | try {
141 | // 执行重试逻辑
142 | result = openaiService.doChatWithRetry(userInput.toString());
143 | } catch (Exception e) {
144 | // 如果重试过程中出现异常,返回错误信息
145 | throw new BusinessException(ErrorCode.SYSTEM_ERROR, e + ",AI生成错误");
146 | }
147 | scoreService.deductPoints(loginUser.getId(),1L);
148 | String[] splits = result.split("【【【【【");
149 |
150 | String genChart = splits[1].trim();
151 | String genResult = splits[2].trim();
152 | // Echarts代码过滤 "var option ="
153 | if (genChart.startsWith("var option =")) {
154 | // 去除 "var option ="
155 | genChart = genChart.replaceFirst("var\\s+option\\s*=\\s*", "");
156 | }
157 |
158 | JsonObject chartJson = JsonParser.parseString(genChart).getAsJsonObject();
159 |
160 | // 自动加入图表名称结尾并设置图表名称
161 | if (StringUtils.isEmpty(name)){
162 | String genChartName = String.valueOf(chartJson.getAsJsonObject("title").get("text"));
163 | genChartName = genChartName.replace("\"","");
164 | if ( !genChartName.endsWith("图") && !genChartName.endsWith("表") && !genChartName.endsWith("图表"))
165 | genChartName = genChartName + "图";
166 | chart.setName(genChartName);
167 | } else
168 | chart.setName(name);
169 | // 自动添加图表类型
170 | if (StringUtils.isEmpty(chartType)){
171 | JsonArray seriesArray = chartJson.getAsJsonArray("series");
172 | if (seriesArray.size() > 0) {
173 | JsonObject firstSeries = seriesArray.get(0).getAsJsonObject();
174 | String typeChart = firstSeries.getAsJsonObject().get("type").getAsString();
175 | String CnChartType = chartService.getChartTypeToCN(typeChart);
176 | chart.setChartType(CnChartType);
177 | }
178 | }else
179 | chart.setChartType(chartType);
180 | // 加入下载按钮
181 | JsonObject toolbox = new JsonObject();
182 | toolbox.addProperty("show", true);
183 | JsonObject saveAsImage = new JsonObject();
184 | saveAsImage.addProperty("show", true);
185 | saveAsImage.addProperty("excludeComponents", "['toolbox']");
186 | saveAsImage.addProperty("pixelRatio", 2);
187 | JsonObject feature = new JsonObject();
188 | feature.add("saveAsImage", saveAsImage);
189 | toolbox.add("feature", feature);
190 | chartJson.add("toolbox", toolbox);
191 | chartJson.remove("title");
192 | String updatedGenChart = chartJson.toString();
193 | chart.setGoal(userGoal);
194 | chart.setChartData(userData);
195 | chart.setGenChart(updatedGenChart);
196 | chart.setGenResult(genResult);
197 | chart.setUserId(loginUser.getId());
198 | chart.setStatus("succeed");
199 | boolean saveResult = chartService.save(chart);
200 | if (!saveResult)
201 | handleChartUpdateError(chart.getId(),"图表信息保存失败");
202 | biResponse.setGenChart(updatedGenChart);
203 | biResponse.setGenResult(genResult);
204 | biResponse.setChartId(chart.getId());
205 | return ResultUtils.success(biResponse);
206 | }
207 |
208 | /**
209 | * 图表错误状态处理
210 | * @param chartId
211 | * @param execMessage
212 | */
213 | private void handleChartUpdateError(long chartId, String execMessage){
214 | Chart updateChart = new Chart();
215 | updateChart.setId(chartId);
216 | updateChart.setStatus("failed");
217 | updateChart.setExecMessage(execMessage);
218 | boolean b = chartService.updateById(updateChart);
219 | if (!b)
220 | log.error("更新图表失败状态错误" + chartId + ":" + execMessage);
221 | }
222 |
223 | /**
224 | * 文件AI分析
225 | *
226 | * @param multipartFile
227 | * @param genChartByAiRequest
228 | * @param request
229 | * @return
230 | */
231 | @PostMapping("/gen/async")
232 | public BaseResponse genChartByAiAsync(@RequestPart("file") MultipartFile multipartFile,
233 | GenChartByAiRequest genChartByAiRequest, HttpServletRequest request) {
234 | String name = genChartByAiRequest.getName();
235 | String goal = genChartByAiRequest.getGoal();
236 | String chartType = genChartByAiRequest.getChartType();
237 | // 校验
238 | ThrowUtils.throwIf(StringUtils.isNotBlank(name) && name.length() > 100, ErrorCode.PARAMS_ERROR, "名称过长");
239 | User loginUser = userService.getLoginUser(request);
240 | // 校验文件大小及后缀
241 | long size = multipartFile.getSize();
242 | final long TEN_MB = 10 * 1024 * 1024L;
243 | ThrowUtils.throwIf(size > TEN_MB, ErrorCode.PARAMS_ERROR, "文件大小大于10M");
244 | String fileName = multipartFile.getOriginalFilename();
245 | String suffix = FileUtil.getSuffix(fileName);
246 | final List validFileSuffix = Arrays.asList("xlsx", "csv", "xls");
247 | ThrowUtils.throwIf(!validFileSuffix.contains(suffix), ErrorCode.PARAMS_ERROR, "文件后缀非法");
248 | // 每个用户限流
249 | redisLimiterManager.doRateLimit("genChartByAi" + loginUser.getId());
250 | // 构造用户输入
251 | StringBuilder userInput = new StringBuilder();
252 | userInput.append("分析需求:\n");
253 | // 拼接分析目标
254 | String userGoal = "请帮我合理的分析一下数据";
255 | if (StringUtils.isNotBlank(goal))
256 | userGoal = goal;
257 | // 分析输入加入图表类型
258 | if (StringUtils.isNotBlank(chartType))
259 | userGoal += ",请使用" + chartType;
260 | userInput.append(userGoal).append("\n");
261 | userInput.append("原始数据:\n");
262 | // 压缩数据
263 | String userData = ExcelUtils.excel2Csv(multipartFile);
264 | userInput.append(userData).append("\n");
265 |
266 | // 插入数据库
267 | Chart chart = new Chart();
268 | chart.setStatus("wait");
269 | chart.setGoal(userGoal);
270 | chart.setChartData(userData);
271 | if (!StringUtils.isEmpty(name))
272 | chart.setName(name);
273 | if (!StringUtils.isEmpty(chartType))
274 | chart.setChartType(chartType);
275 | chart.setUserId(loginUser.getId());
276 | boolean saveResult = chartService.save(chart);
277 | if (!saveResult)
278 | handleChartUpdateError(chart.getId(), "图表初始数据保存失败");
279 | BiResponse biResponse = new BiResponse();
280 | biResponse.setChartId(chart.getId());
281 | // TODO: 用try catch解决任务队列满了抛异常
282 | CompletableFuture.runAsync(()->{
283 | Chart updateChart = new Chart();
284 | updateChart.setId(chart.getId());
285 | updateChart.setStatus("running");
286 | boolean bool = chartService.updateById(updateChart);
287 | if (!bool) {
288 | handleChartUpdateError(updateChart.getId(), "图表执行状态保存失败");
289 | return;
290 | }
291 | String result = openaiService.doChat(userInput.toString());
292 | String[] splits = result.split("【【【【【");
293 | if (splits.length < 3)
294 | throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI生成错误");
295 | String genChart = splits[1].trim();
296 | String genResult = splits[2].trim();
297 | // Echarts代码过滤 "var option ="
298 | if (genChart.startsWith("var option =")) {
299 | // 去除 "var option ="
300 | genChart = genChart.replaceFirst("var\\s+option\\s*=\\s*", "");
301 | }
302 | Chart updateResult = new Chart();
303 | updateResult.setId(chart.getId());
304 | JsonObject chartJson;
305 | String genChartName;
306 | String updatedGenChart = "";
307 | try {
308 | chartJson = JsonParser.parseString(genChart).getAsJsonObject();
309 | } catch (JsonSyntaxException e) {
310 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "json代码解析异常");
311 | }
312 | // 自动添加图表类型
313 | if (StringUtils.isEmpty(chart.getName())) {
314 | JsonArray seriesArray = chartJson.getAsJsonArray("series");
315 | for (JsonElement i : seriesArray) {
316 | String typeChart = i.getAsJsonObject().get("type").getAsString();
317 | String CnChartType = chartService.getChartTypeToCN(typeChart);
318 | updateResult.setChartType(CnChartType);
319 | }
320 | }
321 | // 自动加入图表名称结尾并设置图表名称
322 | if (StringUtils.isEmpty(chart.getName())) {
323 | try {
324 | genChartName = String.valueOf(chartJson.getAsJsonObject("title").get("text"));
325 | } catch (JsonSyntaxException e) {
326 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "json代码不存在title字段");
327 | }
328 | genChartName = genChartName.replace("\"", "");
329 | if ( !genChartName.endsWith("图") && !genChartName.endsWith("表") && !genChartName.endsWith("图表"))
330 | genChartName = genChartName + "图";
331 | updateResult.setName(genChartName);
332 | // 加入下载按钮
333 | JsonObject toolbox = new JsonObject();
334 | toolbox.addProperty("show", true);
335 | JsonObject saveAsImage = new JsonObject();
336 | saveAsImage.addProperty("show", true);
337 | saveAsImage.addProperty("excludeComponents", "['toolbox']");
338 | saveAsImage.addProperty("pixelRatio", 2);
339 | JsonObject feature = new JsonObject();
340 | feature.add("saveAsImage", saveAsImage);
341 | toolbox.add("feature", feature);
342 | chartJson.add("toolbox", toolbox);
343 | chartJson.remove("title");
344 | updatedGenChart = chartJson.toString();
345 | }
346 | updateResult.setGenChart(updatedGenChart);
347 | // TODO:枚举值实现
348 | updateResult.setStatus("succeed");
349 | boolean code = chartService.updateById(updateResult);
350 | if (!code)
351 | handleChartUpdateError(updateResult.getId(), "图表代码保存失败");
352 | biResponse.setGenChart(updatedGenChart);
353 | biResponse.setGenResult(genResult);
354 | }, threadPoolExecutor);
355 | return ResultUtils.success(biResponse);
356 | }
357 |
358 | /**
359 | * 文件AI分析
360 | *
361 | * @param multipartFile
362 | * @param genChartByAiRequest
363 | * @param request
364 | * @return
365 | */
366 | @PostMapping("/gen/async/mq")
367 | public BaseResponse genChartByAiAsyncMq(@RequestPart("file") MultipartFile multipartFile,
368 | GenChartByAiRequest genChartByAiRequest, HttpServletRequest request) {
369 | String name = genChartByAiRequest.getName();
370 | String goal = genChartByAiRequest.getGoal();
371 | String chartType = genChartByAiRequest.getChartType();
372 | // 校验
373 | ThrowUtils.throwIf(StringUtils.isNotBlank(name) && name.length() > 100, ErrorCode.PARAMS_ERROR, "名称过长");
374 | User loginUser = userService.getLoginUser(request);
375 | // 校验文件大小及后缀
376 | long size = multipartFile.getSize();
377 | final long TEN_MB = 10 * 1024 * 1024L;
378 | ThrowUtils.throwIf(size > TEN_MB, ErrorCode.PARAMS_ERROR, "文件大小大于10M");
379 | String fileName = multipartFile.getOriginalFilename();
380 | String suffix = FileUtil.getSuffix(fileName);
381 | final List validFileSuffix = Arrays.asList("xlsx", "csv", "xls");
382 | ThrowUtils.throwIf(!validFileSuffix.contains(suffix), ErrorCode.PARAMS_ERROR, "文件后缀非法");
383 | // 每个用户限流
384 | redisLimiterManager.doRateLimit("genChartByAi" + loginUser.getId());
385 | // 构造用户输入
386 | StringBuilder userInput = new StringBuilder();
387 | userInput.append("分析需求:\n");
388 | // 拼接分析目标
389 | String userGoal = "请帮我合理的分析一下数据";
390 | if (StringUtils.isNotBlank(goal))
391 | userGoal = goal;
392 | // 分析输入加入图表类型
393 | if (StringUtils.isNotBlank(chartType))
394 | userGoal += ",请使用" + chartType;
395 | userInput.append(userGoal).append("\n");
396 | userInput.append("原始数据:\n");
397 | // 压缩数据
398 | String userData = ExcelUtils.excel2Csv(multipartFile);
399 | userInput.append(userData).append("\n");
400 | // 插入数据库
401 | Chart chart = new Chart();
402 | chart.setStatus("wait");
403 | chart.setGoal(userGoal);
404 | chart.setChartData(userData);
405 | if (!StringUtils.isEmpty(name))
406 | chart.setName(name);
407 | if (!StringUtils.isEmpty(chartType))
408 | chart.setChartType(chartType);
409 | chart.setUserId(loginUser.getId());
410 | taskManager.startTaskTimer(loginUser.getId());
411 | boolean saveResult = chartService.save(chart);
412 | if (!saveResult)
413 | handleChartUpdateError(chart.getId(), "图表初始数据保存失败");
414 | long newChartId = chart.getId();
415 | messageProducer.sendMessage(String.valueOf(newChartId));
416 | BiResponse biResponse = new BiResponse();
417 | biResponse.setChartId(newChartId);
418 | return ResultUtils.success(biResponse);
419 | }
420 |
421 | /**
422 | * 分析错误重试
423 | *
424 | * @param id
425 | * @return
426 | */
427 | @GetMapping("/gen/async/mq/retry")
428 | public BaseResponse retryGenChartByAiAsyncMq(@RequestParam Long id) {
429 | log.info(String.valueOf(id));
430 | Chart byId = chartService.getById(id);
431 | String userGoal = byId.getGoal();
432 | String userData = byId.getChartData();
433 | String userStatus = byId.getStatus();
434 | // 防止多次重试
435 | if (StringUtils.equals(userStatus, "wait"))
436 | return null;
437 | // 构造用户输入
438 | StringBuilder userInput = new StringBuilder();
439 | userInput.append("分析需求:\n");
440 | // 拼接分析目标
441 | userInput.append(userGoal).append("\n");
442 | userInput.append("原始数据:\n");
443 | userInput.append(userData).append("\n");
444 | // 插入数据库
445 | Chart chart = new Chart();
446 | chart.setStatus("wait");
447 | chart.setId(id);
448 | taskManager.startTaskTimer(id);
449 | boolean saveResult = chartService.updateById(chart);
450 | if (!saveResult)
451 | handleChartUpdateError(chart.getId(), "图表状态更新失败");
452 | long newChartId = chart.getId();
453 | messageProducer.sendMessage(String.valueOf(newChartId));
454 | BiResponse biResponse = new BiResponse();
455 | biResponse.setChartId(newChartId);
456 | return ResultUtils.success(biResponse);
457 | }
458 | /**
459 | * 创建
460 | *
461 | * @param chartAddRequest
462 | * @param request
463 | * @return
464 | */
465 | @PostMapping("/add")
466 | public BaseResponse addchart(@RequestBody ChartAddRequest chartAddRequest, HttpServletRequest request) {
467 | if (chartAddRequest == null) {
468 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
469 | }
470 | Chart chart = new Chart();
471 | BeanUtils.copyProperties(chartAddRequest, chart);
472 | User loginUser = userService.getLoginUser(request);
473 | chart.setUserId(loginUser.getId());
474 | boolean result = chartService.save(chart);
475 | ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
476 | long newchartId = chart.getId();
477 | return ResultUtils.success(newchartId);
478 | }
479 |
480 | /**
481 | * 删除
482 | *
483 | * @param deleteRequest
484 | * @param request
485 | * @return
486 | */
487 | @PostMapping("/delete")
488 | public BaseResponse deletechart(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
489 | if (deleteRequest == null || deleteRequest.getId() <= 0) {
490 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
491 | }
492 | User user = userService.getLoginUser(request);
493 | long id = deleteRequest.getId();
494 | // 判断是否存在
495 | Chart oldchart = chartService.getById(id);
496 | ThrowUtils.throwIf(oldchart == null, ErrorCode.NOT_FOUND_ERROR);
497 | // 仅本人或管理员可删除
498 | if (!oldchart.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
499 | throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
500 | }
501 | boolean b = chartService.removeById(id);
502 | return ResultUtils.success(b);
503 | }
504 |
505 | /**
506 | * 更新(仅管理员)
507 | *
508 | * @param chartUpdateRequest
509 | * @return
510 | */
511 | @PostMapping("/update")
512 | @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
513 | public BaseResponse updatechart(@RequestBody ChartUpdateRequest chartUpdateRequest) {
514 | if (chartUpdateRequest == null || chartUpdateRequest.getId() <= 0) {
515 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
516 | }
517 | Chart chart = new Chart();
518 | BeanUtils.copyProperties(chartUpdateRequest, chart);
519 | long id = chartUpdateRequest.getId();
520 | // 判断是否存在
521 | Chart oldchart = chartService.getById(id);
522 | ThrowUtils.throwIf(oldchart == null, ErrorCode.NOT_FOUND_ERROR);
523 | boolean result = chartService.updateById(chart);
524 | return ResultUtils.success(result);
525 | }
526 |
527 | /**
528 | * 根据 id 获取
529 | *
530 | * @param id
531 | * @return
532 | */
533 | @GetMapping("/get")
534 | public BaseResponse getchartById(long id, HttpServletRequest request) {
535 | if (id <= 0) {
536 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
537 | }
538 | Chart chart = chartService.getById(id);
539 | if (chart == null) {
540 | throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
541 | }
542 | return ResultUtils.success(chart);
543 | }
544 |
545 | /**
546 | * 分页获取列表(封装类)
547 | *
548 | * @param chartQueryRequest
549 | * @param request
550 | * @return
551 | */
552 | @PostMapping("/list/page")
553 | public BaseResponse> listchartByPage(@RequestBody ChartQueryRequest chartQueryRequest,
554 | HttpServletRequest request) {
555 | long current = chartQueryRequest.getCurrent();
556 | long size = chartQueryRequest.getPageSize();
557 | // 限制爬虫
558 | ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
559 | Page chartPage = chartService.page(new Page<>(current, size),
560 | getQueryWrapper(chartQueryRequest));
561 | return ResultUtils.success(chartPage);
562 | }
563 |
564 | /**
565 | * 分页获取当前用户创建的资源列表
566 | *
567 | * @param chartQueryRequest
568 | * @param request
569 | * @return
570 | */
571 | @PostMapping("/my/list/page")
572 | public BaseResponse> listMychartByPage(@RequestBody ChartQueryRequest chartQueryRequest,
573 | HttpServletRequest request) {
574 | if (chartQueryRequest == null) {
575 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
576 | }
577 | User loginUser = userService.getLoginUser(request);
578 | chartQueryRequest.setUserId(loginUser.getId());
579 | long current = chartQueryRequest.getCurrent();
580 | long size = chartQueryRequest.getPageSize();
581 | // 限制爬虫
582 | ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
583 | String cacheKey = "ChartController_listMyChartVOByPage_" + chartQueryRequest.getId();
584 | Page cachedChartPage = redisCacheManager.getCachedResult(cacheKey);
585 | if (cachedChartPage != null) {
586 | // 缓存命中,比较缓存数据与数据库数据是否一致
587 | Page databaseChartPage = chartService.page(new Page<>(current, size),
588 | getQueryWrapper(chartQueryRequest));
589 | if (!chartService.isSamePage(cachedChartPage, databaseChartPage)) {
590 | redisCacheManager.putCachedResult(cacheKey, databaseChartPage);
591 | }
592 | return ResultUtils.success(cachedChartPage);
593 | } else {
594 | // 缓存未命中,从数据库中查询数据,并放入缓存
595 | Page chartPage = chartService.page(new Page<>(current, size),
596 | getQueryWrapper(chartQueryRequest));
597 | redisCacheManager.asyncPutCachedResult(cacheKey, chartPage);
598 | return ResultUtils.success(chartPage);
599 | }
600 | }
601 |
602 |
603 | /**
604 | * 编辑(用户)
605 | *
606 | * @param chartEditRequest
607 | * @param request
608 | * @return
609 | */
610 | @PostMapping("/edit")
611 | public BaseResponse editchart(@RequestBody ChartEditRequest chartEditRequest, HttpServletRequest request) {
612 | if (chartEditRequest == null || chartEditRequest.getId() <= 0) {
613 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
614 | }
615 | Chart chart = new Chart();
616 | BeanUtils.copyProperties(chartEditRequest, chart);
617 | User loginUser = userService.getLoginUser(request);
618 | long id = chartEditRequest.getId();
619 | // 判断是否存在
620 | Chart oldchart = chartService.getById(id);
621 | ThrowUtils.throwIf(oldchart == null, ErrorCode.NOT_FOUND_ERROR);
622 | // 仅本人或管理员可编辑
623 | if (!oldchart.getUserId().equals(loginUser.getId()) && !userService.isAdmin(loginUser)) {
624 | throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
625 | }
626 | boolean result = chartService.updateById(chart);
627 | return ResultUtils.success(result);
628 | }
629 |
630 | /**
631 | * 获取查询包装类
632 | *
633 | * @param chartQueryRequest
634 | * @return
635 | */
636 | private QueryWrapper getQueryWrapper(ChartQueryRequest chartQueryRequest) {
637 | QueryWrapper queryWrapper = new QueryWrapper<>();
638 | if (chartQueryRequest == null) {
639 | return queryWrapper;
640 | }
641 | Long id = chartQueryRequest.getId();
642 | String goal = chartQueryRequest.getGoal();
643 | String chartType = chartQueryRequest.getChartType();
644 | String name = chartQueryRequest.getName();
645 | Long userId = chartQueryRequest.getUserId();
646 | String sortField = chartQueryRequest.getSortField();
647 | String sortOrder = chartQueryRequest.getSortOrder();
648 | // 当我进行图表查询时
649 | if(StringUtils.isNotBlank(goal) && StringUtils.isNotBlank(name) && StringUtils.isNotBlank(chartType))
650 | queryWrapper.and(wrapper -> wrapper
651 | .like(StringUtils.isNotBlank(goal), "goal", "%" + goal + "%")
652 | .or()
653 | .like(StringUtils.isNotBlank(name), "name", "%" + name + "%")
654 | .or()
655 | .like(StringUtils.isNotBlank(chartType), "chartType", "%" + chartType + "%"))
656 | .eq(ObjectUtils.isNotEmpty(userId), "userId", userId)
657 | .eq("isDelete", false)
658 | .orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
659 | sortField);
660 | else{
661 | queryWrapper.eq(id != null && id > 0, "id", id);
662 | queryWrapper.like(StringUtils.isNotBlank(goal), "goal", goal);
663 | queryWrapper.like(StringUtils.isNotBlank(name), "name", name);
664 | queryWrapper.like(StringUtils.isNotBlank(chartType), "chartType", chartType);
665 | queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
666 | queryWrapper.eq("isDelete", false);
667 | queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
668 | sortField);
669 | }
670 | return queryWrapper;
671 | }
672 | }
673 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/controller/ScoreController.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.controller;
2 |
3 | import com.jl.springbootinit.common.BaseResponse;
4 | import com.jl.springbootinit.common.ResultUtils;
5 | import com.jl.springbootinit.model.entity.User;
6 | import com.jl.springbootinit.service.ScoreService;
7 | import com.jl.springbootinit.service.UserService;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.PostMapping;
11 | import org.springframework.web.bind.annotation.RequestMapping;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | import javax.annotation.Resource;
15 | import javax.servlet.http.HttpServletRequest;
16 |
17 | @RestController
18 | @RequestMapping("/score")
19 | @Slf4j
20 | public class ScoreController {
21 | @Resource
22 | private UserService userService;
23 |
24 | @Resource
25 | private ScoreService scoreService;
26 |
27 | /**
28 | * 用于签到时添加积分
29 | * @param request
30 | * @return
31 | */
32 | @PostMapping("/checkIn")
33 | public BaseResponse checkIn(HttpServletRequest request) {
34 | User loginUser = userService.getLoginUser(request);
35 | scoreService.checkIn(loginUser.getId());
36 | return ResultUtils.success("签到成功");
37 | }
38 |
39 | /**
40 | * 查询积分
41 | *
42 | * @param request
43 | * @return
44 | */
45 | @GetMapping("/get")
46 | public BaseResponse getUserById(HttpServletRequest request) {
47 | User loginUser = userService.getLoginUser(request);
48 | Long totalPoints = scoreService.getUserPoints(loginUser.getId());
49 | return ResultUtils.success(totalPoints);
50 | }
51 |
52 | /**
53 | * 查询签到状态
54 | *
55 | * @param request
56 | * @return
57 | */
58 | @GetMapping("/getSign")
59 | public BaseResponse getSignById(HttpServletRequest request) {
60 | User loginUser = userService.getLoginUser(request);
61 | int isSign = scoreService.getIsSign(loginUser.getId());
62 | return ResultUtils.success(isSign);
63 | }
64 | }
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.controller;
2 |
3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
4 | import com.jl.springbootinit.annotation.AuthCheck;
5 | import com.jl.springbootinit.common.BaseResponse;
6 | import com.jl.springbootinit.common.DeleteRequest;
7 | import com.jl.springbootinit.common.ErrorCode;
8 | import com.jl.springbootinit.common.ResultUtils;
9 | import com.jl.springbootinit.constant.UserConstant;
10 | import com.jl.springbootinit.exception.BusinessException;
11 | import com.jl.springbootinit.exception.ThrowUtils;
12 | import com.jl.springbootinit.model.dto.user.UserAddRequest;
13 | import com.jl.springbootinit.model.dto.user.UserLoginRequest;
14 | import com.jl.springbootinit.model.dto.user.UserQueryRequest;
15 | import com.jl.springbootinit.model.dto.user.UserRegisterRequest;
16 | import com.jl.springbootinit.model.dto.user.UserUpdateMyRequest;
17 | import com.jl.springbootinit.model.dto.user.UserUpdateRequest;
18 | import com.jl.springbootinit.model.entity.User;
19 | import com.jl.springbootinit.model.vo.LoginUserVO;
20 | import com.jl.springbootinit.model.vo.UserVO;
21 | import com.jl.springbootinit.service.UserService;
22 | import java.util.List;
23 | import javax.annotation.Resource;
24 | import javax.servlet.http.HttpServletRequest;
25 |
26 | import lombok.extern.slf4j.Slf4j;
27 | import org.apache.commons.lang3.StringUtils;
28 | import org.springframework.beans.BeanUtils;
29 | import org.springframework.web.bind.annotation.GetMapping;
30 | import org.springframework.web.bind.annotation.PostMapping;
31 | import org.springframework.web.bind.annotation.RequestBody;
32 | import org.springframework.web.bind.annotation.RequestMapping;
33 | import org.springframework.web.bind.annotation.RestController;
34 |
35 | /**
36 | * 用户接口
37 | *
38 | */
39 | @RestController
40 | @RequestMapping("/user")
41 | @Slf4j
42 | public class UserController {
43 |
44 | @Resource
45 | private UserService userService;
46 |
47 |
48 |
49 | /**
50 | * 用户注册
51 | *
52 | * @param userRegisterRequest
53 | * @return
54 | */
55 | @PostMapping("/register")
56 | public BaseResponse userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
57 | if (userRegisterRequest == null) {
58 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
59 | }
60 | String userAccount = userRegisterRequest.getUserAccount();
61 | String userPassword = userRegisterRequest.getUserPassword();
62 | String checkPassword = userRegisterRequest.getCheckPassword();
63 | if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {
64 | return null;
65 | }
66 | long result = userService.userRegister(userAccount, userPassword, checkPassword);
67 | return ResultUtils.success(result);
68 | }
69 |
70 | /**
71 | * 用户登录
72 | *
73 | * @param userLoginRequest
74 | * @param request
75 | * @return
76 | */
77 | @PostMapping("/login")
78 | public BaseResponse userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
79 | if (userLoginRequest == null) {
80 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
81 | }
82 | String userAccount = userLoginRequest.getUserAccount();
83 | String userPassword = userLoginRequest.getUserPassword();
84 | if (StringUtils.isAnyBlank(userAccount, userPassword)) {
85 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
86 | }
87 | LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request);
88 | return ResultUtils.success(loginUserVO);
89 | }
90 |
91 |
92 | /**
93 | * 用户注销
94 | *
95 | * @param request
96 | * @return
97 | */
98 | @PostMapping("/logout")
99 | public BaseResponse userLogout(HttpServletRequest request) {
100 | if (request == null) {
101 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
102 | }
103 | boolean result = userService.userLogout(request);
104 | return ResultUtils.success(result);
105 | }
106 |
107 | /**
108 | * 获取当前登录用户
109 | *
110 | * @param request
111 | * @return
112 | */
113 | @GetMapping("/get/login")
114 | public BaseResponse getLoginUser(HttpServletRequest request) {
115 | User user = userService.getLoginUser(request);
116 | return ResultUtils.success(userService.getLoginUserVO(user));
117 | }
118 |
119 | // endregion
120 |
121 | // region 增删改查
122 |
123 | /**
124 | * 创建用户
125 | *
126 | * @param userAddRequest
127 | * @param request
128 | * @return
129 | */
130 | @PostMapping("/add")
131 | @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
132 | public BaseResponse addUser(@RequestBody UserAddRequest userAddRequest, HttpServletRequest request) {
133 | if (userAddRequest == null) {
134 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
135 | }
136 | User user = new User();
137 | BeanUtils.copyProperties(userAddRequest, user);
138 | boolean result = userService.save(user);
139 | ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
140 | return ResultUtils.success(user.getId());
141 | }
142 |
143 | /**
144 | * 删除用户
145 | *
146 | * @param deleteRequest
147 | * @param request
148 | * @return
149 | */
150 | @PostMapping("/delete")
151 | @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
152 | public BaseResponse deleteUser(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
153 | if (deleteRequest == null || deleteRequest.getId() <= 0) {
154 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
155 | }
156 | boolean b = userService.removeById(deleteRequest.getId());
157 | return ResultUtils.success(b);
158 | }
159 |
160 | /**
161 | * 更新用户
162 | *
163 | * @param userUpdateRequest
164 | * @param request
165 | * @return
166 | */
167 | @PostMapping("/update")
168 | @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
169 | public BaseResponse updateUser(@RequestBody UserUpdateRequest userUpdateRequest,
170 | HttpServletRequest request) {
171 | if (userUpdateRequest == null || userUpdateRequest.getId() == null) {
172 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
173 | }
174 | User user = new User();
175 | BeanUtils.copyProperties(userUpdateRequest, user);
176 | boolean result = userService.updateById(user);
177 | ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
178 | return ResultUtils.success(true);
179 | }
180 |
181 | /**
182 | * 根据 id 获取用户(仅管理员)
183 | *
184 | * @param id
185 | * @param request
186 | * @return
187 | */
188 | @GetMapping("/get")
189 | @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
190 | public BaseResponse getUserById(long id, HttpServletRequest request) {
191 | if (id <= 0) {
192 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
193 | }
194 | User user = userService.getById(id);
195 | ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR);
196 | return ResultUtils.success(user);
197 | }
198 |
199 | /**
200 | * 根据 id 获取包装类
201 | *
202 | * @param id
203 | * @param request
204 | * @return
205 | */
206 | @GetMapping("/get/vo")
207 | public BaseResponse getUserVOById(long id, HttpServletRequest request) {
208 | BaseResponse response = getUserById(id, request);
209 | User user = response.getData();
210 | return ResultUtils.success(userService.getUserVO(user));
211 | }
212 |
213 | /**
214 | * 分页获取用户列表(仅管理员)
215 | *
216 | * @param userQueryRequest
217 | * @param request
218 | * @return
219 | */
220 | @PostMapping("/list/page")
221 | @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
222 | public BaseResponse> listUserByPage(@RequestBody UserQueryRequest userQueryRequest,
223 | HttpServletRequest request) {
224 | long current = userQueryRequest.getCurrent();
225 | long size = userQueryRequest.getPageSize();
226 | Page userPage = userService.page(new Page<>(current, size),
227 | userService.getQueryWrapper(userQueryRequest));
228 | return ResultUtils.success(userPage);
229 | }
230 |
231 | /**
232 | * 分页获取用户封装列表
233 | *
234 | * @param userQueryRequest
235 | * @param request
236 | * @return
237 | */
238 | @PostMapping("/list/page/vo")
239 | public BaseResponse> listUserVOByPage(@RequestBody UserQueryRequest userQueryRequest,
240 | HttpServletRequest request) {
241 | if (userQueryRequest == null) {
242 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
243 | }
244 | long current = userQueryRequest.getCurrent();
245 | long size = userQueryRequest.getPageSize();
246 | // 限制爬虫
247 | ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
248 | Page userPage = userService.page(new Page<>(current, size),
249 | userService.getQueryWrapper(userQueryRequest));
250 | Page userVOPage = new Page<>(current, size, userPage.getTotal());
251 | List userVO = userService.getUserVO(userPage.getRecords());
252 | userVOPage.setRecords(userVO);
253 | return ResultUtils.success(userVOPage);
254 | }
255 |
256 | // endregion
257 |
258 | /**
259 | * 更新个人信息
260 | *
261 | * @param userUpdateMyRequest
262 | * @param request
263 | * @return
264 | */
265 | @PostMapping("/update/my")
266 | public BaseResponse updateMyUser(@RequestBody UserUpdateMyRequest userUpdateMyRequest,
267 | HttpServletRequest request) {
268 | if (userUpdateMyRequest == null) {
269 | throw new BusinessException(ErrorCode.PARAMS_ERROR);
270 | }
271 | User loginUser = userService.getLoginUser(request);
272 | User user = new User();
273 | BeanUtils.copyProperties(userUpdateMyRequest, user);
274 | user.setId(loginUser.getId());
275 | boolean result = userService.updateById(user);
276 | ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
277 | return ResultUtils.success(true);
278 | }
279 | }
280 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/exception/BusinessException.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.exception;
2 |
3 | import com.jl.springbootinit.common.ErrorCode;
4 |
5 | /**
6 | * 自定义异常类
7 | *
8 | */
9 | public class BusinessException extends RuntimeException {
10 |
11 | /**
12 | * 错误码
13 | */
14 | private final int code;
15 |
16 | public BusinessException(int code, String message) {
17 | super(message);
18 | this.code = code;
19 | }
20 |
21 | public BusinessException(ErrorCode errorCode) {
22 | super(errorCode.getMessage());
23 | this.code = errorCode.getCode();
24 | }
25 |
26 | public BusinessException(ErrorCode errorCode, String message) {
27 | super(message);
28 | this.code = errorCode.getCode();
29 | }
30 |
31 | public int getCode() {
32 | return code;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/exception/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.exception;
2 |
3 | import com.jl.springbootinit.common.BaseResponse;
4 | import com.jl.springbootinit.common.ErrorCode;
5 | import com.jl.springbootinit.common.ResultUtils;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.web.bind.annotation.ExceptionHandler;
8 | import org.springframework.web.bind.annotation.RestControllerAdvice;
9 |
10 | /**
11 | * 全局异常处理器
12 | *
13 | */
14 | @RestControllerAdvice
15 | @Slf4j
16 | public class GlobalExceptionHandler {
17 |
18 | @ExceptionHandler(BusinessException.class)
19 | public BaseResponse> businessExceptionHandler(BusinessException e) {
20 | log.error("BusinessException", e);
21 | return ResultUtils.error(e.getCode(), e.getMessage());
22 | }
23 |
24 | @ExceptionHandler(RuntimeException.class)
25 | public BaseResponse> runtimeExceptionHandler(RuntimeException e) {
26 | log.error("RuntimeException", e);
27 | return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/exception/ThrowUtils.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.exception;
2 |
3 | import com.jl.springbootinit.common.ErrorCode;
4 |
5 | /**
6 | * 抛异常工具类
7 | *
8 | */
9 | public class ThrowUtils {
10 |
11 | /**
12 | * 条件成立则抛异常
13 | *
14 | * @param condition
15 | * @param runtimeException
16 | */
17 | public static void throwIf(boolean condition, RuntimeException runtimeException) {
18 | if (condition) {
19 | throw runtimeException;
20 | }
21 | }
22 |
23 | /**
24 | * 条件成立则抛异常
25 | *
26 | * @param condition
27 | * @param errorCode
28 | */
29 | public static void throwIf(boolean condition, ErrorCode errorCode) {
30 | throwIf(condition, new BusinessException(errorCode));
31 | }
32 |
33 | /**
34 | * 条件成立则抛异常
35 | *
36 | * @param condition
37 | * @param errorCode
38 | * @param message
39 | */
40 | public static void throwIf(boolean condition, ErrorCode errorCode, String message) {
41 | throwIf(condition, new BusinessException(errorCode, message));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/job/cycle/UpdateSignStatus.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.job.cycle;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
4 | import com.jl.springbootinit.common.ErrorCode;
5 | import com.jl.springbootinit.exception.ThrowUtils;
6 | import com.jl.springbootinit.model.entity.Score;
7 | import com.jl.springbootinit.service.ScoreService;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.scheduling.annotation.Scheduled;
10 | import org.springframework.stereotype.Component;
11 |
12 | import javax.annotation.Resource;
13 |
14 | @Component
15 | @Slf4j
16 | public class UpdateSignStatus {
17 |
18 | @Resource
19 | private ScoreService scoreService;
20 |
21 | /**
22 | * 每天凌晨0点更新积分表的isSign为0
23 | */
24 | @Scheduled(cron = "0 0 0 * * ?")
25 | public void sendMessageToClient() {
26 | UpdateWrapper updateWrapper = new UpdateWrapper<>();
27 | //更新Score表中isSign为1的数据
28 | updateWrapper.set("isSign",0)
29 | .eq("isSign",1);
30 | boolean updateResult = scoreService.update(updateWrapper);
31 | ThrowUtils.throwIf(!updateResult, ErrorCode.OPERATION_ERROR);
32 | log.info("Check-in status has been updated!");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/manager/RedisCacheManager.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.manager;
2 |
3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
4 | import com.jl.springbootinit.model.entity.Chart;
5 | import org.redisson.api.RMap;
6 | import org.redisson.api.RedissonClient;
7 | import org.springframework.scheduling.annotation.Async;
8 | import org.springframework.stereotype.Service;
9 |
10 | import javax.annotation.Resource;
11 | import java.time.Duration;
12 |
13 | @Service
14 | public class RedisCacheManager {
15 | @Resource
16 | private RedissonClient redissonClient;
17 |
18 | public Page getCachedResult(String cacheKey) {
19 | // 从缓存中获取数据
20 | RMap cache = redissonClient.getMap(cacheKey);
21 | return (Page) cache.get(cacheKey);
22 | }
23 |
24 | public void putCachedResult(String cacheKey, Page chartPage) {
25 | // 放入缓存
26 | RMap cache = redissonClient.getMap(cacheKey);
27 | cache.put(cacheKey, chartPage);
28 | // 设置缓存过期时间为60秒
29 | cache.expire(Duration.ofSeconds(60));
30 | }
31 |
32 | @Async
33 | public void asyncPutCachedResult(String cacheKey, Page chartPage){
34 | putCachedResult(cacheKey, chartPage);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/manager/RedisLimiterManager.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.manager;
2 |
3 | import com.jl.springbootinit.common.ErrorCode;
4 | import com.jl.springbootinit.exception.BusinessException;
5 | import org.redisson.api.RRateLimiter;
6 | import org.redisson.api.RateIntervalUnit;
7 | import org.redisson.api.RateType;
8 | import org.redisson.api.RedissonClient;
9 | import org.springframework.stereotype.Service;
10 |
11 | import javax.annotation.Resource;
12 |
13 | @Service
14 | public class RedisLimiterManager {
15 |
16 | @Resource
17 | private RedissonClient redissonClient;
18 |
19 | /**
20 | *
21 | * 限流
22 | * @param key 区分不同的限流器
23 | */
24 | public void doRateLimit(String key){
25 | // OVERALL意味着限制是基于所有请求的总体频率,而不是针对单个用户或客户端。
26 | // 2:这是速率的数量。在这个例子中,它表示允许的最大请求数量。也就是令牌数
27 | // 1:这是速率的时间间隔。与RateIntervalUnit.SECONDS结合使用时,这表示在1秒钟内。
28 | // RateIntervalUnit.SECONDS:这是时间间隔的单位。在这里,它指的是秒。
29 | // 这里的限制是每秒最多2次
30 | RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
31 | rateLimiter.trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS);
32 | // 来了一个操作后请求一个令牌
33 | boolean canOperate = rateLimiter.tryAcquire(1);
34 | // TODO:服务降级
35 | if(!canOperate){
36 | throw new BusinessException(ErrorCode.TO_MANY_REQUEST, "该服务被调用次数过多");
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/manager/TaskManager.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.manager;
2 | import com.jl.springbootinit.model.entity.Chart;
3 | import com.jl.springbootinit.service.ChartService;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.scheduling.annotation.Scheduled;
6 | import org.springframework.stereotype.Service;
7 |
8 | import javax.annotation.Resource;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 | import java.util.Objects;
12 |
13 | /**
14 | * 定时任务 4分钟自动设为失败
15 | */
16 | @Service
17 | @Slf4j
18 | public class TaskManager {
19 | // 存储任务ID与开始时间的映射
20 | private Map taskStartTimeMap = new HashMap<>();
21 |
22 | @Resource
23 | private ChartService chartService;
24 |
25 | // 开始计时某个任务
26 | public void startTaskTimer(long taskId) {
27 | taskStartTimeMap.put(taskId, System.currentTimeMillis());
28 | }
29 |
30 | // 清除计时某个任务
31 | public void clearTaskTimer(long taskId) {
32 | taskStartTimeMap.remove(taskId);
33 | }
34 |
35 | // 定时任务方法,当任务ID与开始时间的映射不为空时才运行
36 | // TODO:修改为消息队列实现
37 | @Scheduled(fixedRate = 80000) // 每隔80秒执行一次
38 | public void checkRunningTasks() {
39 | // 检查任务ID与开始时间的映射是否为空
40 | if (!taskStartTimeMap.isEmpty()) {
41 | // 遍历任务ID与开始时间的映射
42 | for (Map.Entry entry : taskStartTimeMap.entrySet()) {
43 | long taskId = entry.getKey();
44 | long startTime = entry.getValue();
45 | long currentTime = System.currentTimeMillis();
46 | long duration = currentTime - startTime;
47 |
48 | if (duration > 4 * 60 * 1000) {
49 | Chart chart = chartService.getById(taskId);
50 | if (Objects.equals(chart.getStatus(), "succeed"))
51 | clearTaskTimer(taskId);
52 | else {
53 | Chart update = new Chart();
54 | update.setId(taskId);
55 | update.setStatus("failed");
56 | boolean saveResult = chartService.updateById(update);
57 | if (!saveResult)
58 | handleChartUpdateError(update.getId(), "图表状态更新失败");
59 | clearTaskTimer(taskId);
60 | }
61 | }
62 | }
63 | }
64 | }
65 |
66 | private void handleChartUpdateError(long chartId, String execMessage){
67 | Chart updateChart = new Chart();
68 | updateChart.setId(chartId);
69 | updateChart.setStatus("failed");
70 | updateChart.setExecMessage(execMessage);
71 | boolean b = chartService.updateById(updateChart);
72 | if (!b)
73 | log.error("更新图表失败状态错误" + chartId + ":" + execMessage);
74 | }
75 |
76 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/mapper/ChartMapper.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.mapper;
2 |
3 | import com.jl.springbootinit.model.entity.Chart;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | * @author 99367
8 | * @description 针对表【chart(图表信息表)】的数据库操作Mapper
9 | * @createDate 2023-12-25 16:07:42
10 | * @Entity generator.domain.Chart
11 | */
12 | public interface ChartMapper extends BaseMapper {
13 |
14 | }
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/mapper/ScoreMapper.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.jl.springbootinit.model.entity.Score;
5 |
6 | /**
7 | * @author 99367
8 | * @description 针对表【score(积分表)】的数据库操作Mapper
9 | * @createDate 2024-01-28 16:15:09
10 | * @Entity generator.domain.Score
11 | */
12 | public interface ScoreMapper extends BaseMapper {
13 |
14 | }
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/mapper/UserMapper.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.mapper;
2 |
3 | import com.jl.springbootinit.model.entity.User;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | * @author 99367
8 | * @description 针对表【user(用户)】的数据库操作Mapper
9 | * @createDate 2023-12-25 16:07:42
10 | * @Entity generator.domain.User
11 | */
12 | public interface UserMapper extends BaseMapper {
13 |
14 | }
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/chart/ChartAddRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.chart;
2 |
3 |
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 |
9 | /**
10 | * 创建请求
11 | *
12 | */
13 | @Data
14 | public class ChartAddRequest implements Serializable {
15 | /**
16 | * 分析目标
17 | */
18 | private String goal;
19 |
20 | /**
21 | * 名称
22 | */
23 | private String name;
24 |
25 | /**
26 | * 图表数据
27 | */
28 | private String chartData;
29 |
30 | /**
31 | * 图表类型
32 | */
33 | private String chartType;
34 |
35 |
36 | private static final long serialVersionUID = 1L;
37 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/chart/ChartEditRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.chart;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 |
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 |
10 |
11 | /**
12 | * 编辑请求
13 | *
14 | */
15 | @Data
16 | public class ChartEditRequest implements Serializable {
17 | /**
18 | * id
19 | */
20 | @TableId(type = IdType.ASSIGN_ID)
21 | private Long id;
22 |
23 | /**
24 | * 名称
25 | */
26 | private String name;
27 |
28 | /**
29 | * 分析目标
30 | */
31 | private String goal;
32 |
33 | /**
34 | * 图表数据
35 | */
36 | private String chartData;
37 |
38 | /**
39 | * 图表类型
40 | */
41 | private String chartType;
42 |
43 | private static final long serialVersionUID = 1L;
44 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/chart/ChartQueryRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.chart;
2 |
3 | import com.jl.springbootinit.common.PageRequest;
4 | import lombok.Data;
5 | import lombok.EqualsAndHashCode;
6 |
7 | import java.io.Serializable;
8 |
9 | /**
10 | * 查询请求
11 | *
12 | */
13 | @EqualsAndHashCode(callSuper = true)
14 | @Data
15 | public class ChartQueryRequest extends PageRequest implements Serializable {
16 |
17 | private Long id;
18 |
19 | /**
20 | * 分析目标
21 | */
22 | private String goal;
23 |
24 | private Long userId;
25 | /**
26 | * 图表类型
27 | */
28 | private String chartType;
29 |
30 | /**
31 | * 名称
32 | */
33 | private String name;
34 |
35 | private static final long serialVersionUID = 1L;
36 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/chart/ChartUpdateRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.chart;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableLogic;
6 | import lombok.Data;
7 |
8 | import java.io.Serializable;
9 | import java.util.Date;
10 |
11 | /**
12 | * 更新请求
13 | *
14 | */
15 | @Data
16 | public class ChartUpdateRequest implements Serializable {
17 | /**
18 | * id
19 | */
20 | @TableId(type = IdType.ASSIGN_ID)
21 | private Long id;
22 |
23 | /**
24 | * 名称
25 | */
26 | private String name;
27 |
28 | /**
29 | * 分析目标
30 | */
31 | private String goal;
32 |
33 | /**
34 | * 图表数据
35 | */
36 | private String chartData;
37 |
38 | /**
39 | * 图表类型
40 | */
41 | private String chartType;
42 |
43 | /**
44 | * 生成的图表数据
45 | */
46 | private String genChart;
47 |
48 | /**
49 | * 生成的分析结论
50 | */
51 | private String genResult;
52 |
53 | /**
54 | * 任务状态
55 | */
56 | private String status;
57 |
58 | /**
59 | * 执行信息
60 | */
61 | private String execMessage;
62 |
63 | /**
64 | * 用户 id
65 | */
66 | private Long userId;
67 |
68 | /**
69 | * 创建时间
70 | */
71 | private Date createTime;
72 |
73 | /**
74 | * 更新时间
75 | */
76 | private Date updateTime;
77 |
78 | /**
79 | * 是否删除
80 | */
81 | @TableLogic
82 | private Integer isDelete;
83 |
84 | private static final long serialVersionUID = 1L;
85 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/chart/GenChartByAiRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.chart;
2 |
3 | import lombok.Data;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * 文件上传请求
9 | *
10 | */
11 | @Data
12 | public class GenChartByAiRequest implements Serializable {
13 |
14 | /**
15 | * 分析目标
16 | */
17 | private String goal;
18 |
19 | /**
20 | * 名称
21 | */
22 | private String name;
23 |
24 |
25 | /**
26 | * 图表类型
27 | */
28 | private String chartType;
29 | private static final long serialVersionUID = 1L;
30 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/user/UserAddRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.user;
2 |
3 | import java.io.Serializable;
4 | import lombok.Data;
5 |
6 | /**
7 | * 用户创建请求
8 | *
9 | */
10 | @Data
11 | public class UserAddRequest implements Serializable {
12 |
13 | /**
14 | * 用户昵称
15 | */
16 | private String userName;
17 |
18 | /**
19 | * 账号
20 | */
21 | private String userAccount;
22 |
23 | /**
24 | * 用户头像
25 | */
26 | private String userAvatar;
27 |
28 | /**
29 | * 用户角色: user, admin
30 | */
31 | private String userRole;
32 |
33 | private static final long serialVersionUID = 1L;
34 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/user/UserLoginRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.user;
2 |
3 | import java.io.Serializable;
4 | import lombok.Data;
5 |
6 | /**
7 | * 用户登录请求
8 | *
9 | */
10 | @Data
11 | public class UserLoginRequest implements Serializable {
12 |
13 | private static final long serialVersionUID = 3191241716373120793L;
14 |
15 | private String userAccount;
16 |
17 | private String userPassword;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/user/UserQueryRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.user;
2 |
3 | import com.jl.springbootinit.common.PageRequest;
4 | import java.io.Serializable;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 |
8 | /**
9 | * 用户查询请求
10 | *
11 | */
12 | @EqualsAndHashCode(callSuper = true)
13 | @Data
14 | public class UserQueryRequest extends PageRequest implements Serializable {
15 | /**
16 | * id
17 | */
18 | private Long id;
19 |
20 | /**
21 | * 开放平台id
22 | */
23 | private String unionId;
24 |
25 | /**
26 | * 公众号openId
27 | */
28 | private String mpOpenId;
29 |
30 | /**
31 | * 用户昵称
32 | */
33 | private String userName;
34 |
35 | /**
36 | * 简介
37 | */
38 | private String userProfile;
39 |
40 | /**
41 | * 用户角色:user/admin/ban
42 | */
43 | private String userRole;
44 |
45 | private static final long serialVersionUID = 1L;
46 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/user/UserRegisterRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.user;
2 |
3 | import java.io.Serializable;
4 | import lombok.Data;
5 |
6 | /**
7 | * 用户注册请求体
8 | *
9 | */
10 | @Data
11 | public class UserRegisterRequest implements Serializable {
12 |
13 | private static final long serialVersionUID = 3191241716373120793L;
14 |
15 | private String userAccount;
16 |
17 | private String userPassword;
18 |
19 | private String checkPassword;
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/user/UserUpdateMyRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.user;
2 |
3 | import java.io.Serializable;
4 | import lombok.Data;
5 |
6 | /**
7 | * 用户更新个人信息请求
8 | *
9 | */
10 | @Data
11 | public class UserUpdateMyRequest implements Serializable {
12 |
13 | /**
14 | * 用户昵称
15 | */
16 | private String userName;
17 |
18 | /**
19 | * 用户头像
20 | */
21 | private String userAvatar;
22 |
23 | /**
24 | * 简介
25 | */
26 | private String userProfile;
27 |
28 | private static final long serialVersionUID = 1L;
29 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/dto/user/UserUpdateRequest.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.dto.user;
2 |
3 | import java.io.Serializable;
4 | import lombok.Data;
5 |
6 | /**
7 | * 用户更新请求
8 | *
9 | */
10 | @Data
11 | public class UserUpdateRequest implements Serializable {
12 | /**
13 | * id
14 | */
15 | private Long id;
16 |
17 | /**
18 | * 用户昵称
19 | */
20 | private String userName;
21 |
22 | /**
23 | * 用户头像
24 | */
25 | private String userAvatar;
26 |
27 | /**
28 | * 简介
29 | */
30 | private String userProfile;
31 |
32 | /**
33 | * 用户角色:user/admin/ban
34 | */
35 | private String userRole;
36 |
37 | private static final long serialVersionUID = 1L;
38 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/entity/Chart.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.*;
4 |
5 | import java.io.Serializable;
6 | import java.util.Date;
7 | import lombok.Data;
8 |
9 | /**
10 | * 图表信息表
11 | * @TableName chart
12 | */
13 | @TableName(value ="chart")
14 | @Data
15 | public class Chart implements Serializable {
16 | /**
17 | * id
18 | */
19 | @TableId(type = IdType.ASSIGN_ID)
20 | private Long id;
21 |
22 | /**
23 | * 名称
24 | */
25 | private String name;
26 |
27 | /**
28 | * 分析目标
29 | */
30 | private String goal;
31 |
32 | /**
33 | * 图表数据
34 | */
35 | private String chartData;
36 |
37 | /**
38 | * 图表类型
39 | */
40 | private String chartType;
41 |
42 | /**
43 | * 生成的图表数据
44 | */
45 | private String genChart;
46 |
47 | /**
48 | * 生成的分析结论
49 | */
50 | private String genResult;
51 |
52 | /**
53 | * 任务状态
54 | */
55 | private String status;
56 |
57 | /**
58 | * 执行信息
59 | */
60 | private String execMessage;
61 |
62 | /**
63 | * 用户 id
64 | */
65 | private Long userId;
66 |
67 | /**
68 | * 创建时间
69 | */
70 | private Date createTime;
71 |
72 | /**
73 | * 更新时间
74 | */
75 | private Date updateTime;
76 |
77 | /**
78 | * 重试次数
79 | */
80 | private Integer retry;
81 |
82 | /**
83 | * 是否删除
84 | */
85 | @TableLogic
86 | private Integer isDelete;
87 |
88 | @TableField(exist = false)
89 | private static final long serialVersionUID = 1L;
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/entity/Score.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.entity;
2 | import com.baomidou.mybatisplus.annotation.*;
3 | import lombok.Data;
4 |
5 | import java.io.Serializable;
6 | import java.util.Date;
7 | /**
8 | * 积分表
9 | * @TableName score
10 | */
11 | @TableName(value ="score")
12 | @Data
13 | public class Score implements Serializable {
14 | /**
15 | * id
16 | */
17 | @TableId(type = IdType.ASSIGN_ID)
18 | private Long id;
19 |
20 | /**
21 | * 创建用户id
22 | */
23 | private Long userId;
24 |
25 | /**
26 | * 0表示未签到,1表示已签到
27 | */
28 | private Integer isSign;
29 |
30 | /**
31 | * 总积分
32 | */
33 | private Long scoreTotal;
34 |
35 | /**
36 | * 创建时间
37 | */
38 | private Date createTime;
39 |
40 | /**
41 | * 更新时间
42 | */
43 | private Date updateTime;
44 |
45 | /**
46 | * 是否删除
47 | */
48 | @TableLogic
49 | private Integer isDelete;
50 |
51 | @TableField(exist = false)
52 | private static final long serialVersionUID = 1L;
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/entity/User.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.*;
4 |
5 | import java.io.Serializable;
6 | import java.util.Date;
7 | import lombok.Data;
8 |
9 | /**
10 | * 用户
11 | * @TableName user
12 | */
13 | @TableName(value ="user")
14 | @Data
15 | public class User implements Serializable {
16 | /**
17 | * id
18 | */
19 | @TableId(type = IdType.ASSIGN_ID)
20 | private Long id;
21 |
22 | /**
23 | * 账号
24 | */
25 | private String userAccount;
26 |
27 | /**
28 | * 密码
29 | */
30 | private String userPassword;
31 |
32 | /**
33 | * 用户昵称
34 | */
35 | private String userName;
36 |
37 | /**
38 | * 用户头像
39 | */
40 | private String userAvatar;
41 |
42 | /**
43 | * 用户角色:user/admin
44 | */
45 | private String userRole;
46 |
47 | /**
48 | * 创建时间
49 | */
50 | private Date createTime;
51 |
52 | /**
53 | * 更新时间
54 | */
55 | private Date updateTime;
56 |
57 | /**
58 | * 是否删除
59 | */
60 | @TableLogic
61 | private Integer isDelete;
62 |
63 | @TableField(exist = false)
64 | private static final long serialVersionUID = 1L;
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/enums/UserRoleEnum.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.enums;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 | import java.util.stream.Collectors;
6 | import org.apache.commons.lang3.ObjectUtils;
7 |
8 | /**
9 | * 用户角色枚举
10 | *
11 | */
12 | public enum UserRoleEnum {
13 |
14 | USER("用户", "user"),
15 | ADMIN("管理员", "admin"),
16 | BAN("被封号", "ban");
17 |
18 | private final String text;
19 |
20 | private final String value;
21 |
22 | UserRoleEnum(String text, String value) {
23 | this.text = text;
24 | this.value = value;
25 | }
26 |
27 | /**
28 | * 获取值列表
29 | *
30 | * @return
31 | */
32 | public static List getValues() {
33 | return Arrays.stream(values()).map(item -> item.value).collect(Collectors.toList());
34 | }
35 |
36 | /**
37 | * 根据 value 获取枚举
38 | *
39 | * @param value
40 | * @return
41 | */
42 | public static UserRoleEnum getEnumByValue(String value) {
43 | if (ObjectUtils.isEmpty(value)) {
44 | return null;
45 | }
46 | for (UserRoleEnum anEnum : UserRoleEnum.values()) {
47 | if (anEnum.value.equals(value)) {
48 | return anEnum;
49 | }
50 | }
51 | return null;
52 | }
53 |
54 | public String getValue() {
55 | return value;
56 | }
57 |
58 | public String getText() {
59 | return text;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/vo/BiResponse.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.vo;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * bi 返回结果
7 | */
8 | @Data
9 | public class BiResponse {
10 | /**
11 | * 生成的图表json代码
12 | */
13 | private String genChart;
14 |
15 | /**
16 | * 生成的分析结果
17 | */
18 | private String genResult;
19 |
20 | /**
21 | * 图标id
22 | */
23 | private Long chartId;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/vo/LoginUserVO.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.vo;
2 |
3 | import java.io.Serializable;
4 | import java.util.Date;
5 | import lombok.Data;
6 |
7 | /**
8 | * 已登录用户视图(脱敏)
9 | *
10 | **/
11 | @Data
12 | public class LoginUserVO implements Serializable {
13 |
14 | /**
15 | * 用户 id
16 | */
17 | private Long id;
18 |
19 | /**
20 | * 用户昵称
21 | */
22 | private String userName;
23 |
24 | /**
25 | * 用户头像
26 | */
27 | private String userAvatar;
28 |
29 | /**
30 | * 用户简介
31 | */
32 | private String userProfile;
33 |
34 | /**
35 | * 用户角色:user/admin/ban
36 | */
37 | private String userRole;
38 |
39 | /**
40 | * 创建时间
41 | */
42 | private Date createTime;
43 |
44 | /**
45 | * 更新时间
46 | */
47 | private Date updateTime;
48 |
49 | private static final long serialVersionUID = 1L;
50 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/model/vo/UserVO.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.model.vo;
2 |
3 | import java.io.Serializable;
4 | import java.util.Date;
5 | import lombok.Data;
6 |
7 | /**
8 | * 用户视图(脱敏)
9 | *
10 | */
11 | @Data
12 | public class UserVO implements Serializable {
13 |
14 | /**
15 | * id
16 | */
17 | private Long id;
18 |
19 | /**
20 | * 用户昵称
21 | */
22 | private String userName;
23 |
24 | /**
25 | * 用户头像
26 | */
27 | private String userAvatar;
28 |
29 | /**
30 | * 用户简介
31 | */
32 | private String userProfile;
33 |
34 | /**
35 | * 用户角色:user/admin/ban
36 | */
37 | private String userRole;
38 |
39 | /**
40 | * 创建时间
41 | */
42 | private Date createTime;
43 |
44 | private static final long serialVersionUID = 1L;
45 | }
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/mq/DeadMessageConsumer.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.mq;
2 |
3 | import com.rabbitmq.client.Channel;
4 | import com.jl.springbootinit.common.ErrorCode;
5 | import com.jl.springbootinit.exception.BusinessException;
6 | import com.jl.springbootinit.model.entity.Chart;
7 | import com.jl.springbootinit.service.ChartService;
8 | import com.jl.springbootinit.ws.WebSocketServer;
9 | import lombok.SneakyThrows;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.apache.commons.lang3.StringUtils;
12 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
13 | import org.springframework.amqp.support.AmqpHeaders;
14 | import org.springframework.messaging.handler.annotation.Header;
15 | import org.springframework.stereotype.Component;
16 |
17 | import javax.annotation.Resource;
18 |
19 | @Slf4j
20 | @Component
21 | public class DeadMessageConsumer {
22 |
23 | @Resource
24 | private ChartService chartService;
25 |
26 | @Resource
27 | private WebSocketServer webSocketService;
28 |
29 | /**
30 | * @param message 接收到的消息内容。
31 | * @param channel 与 RabbitMQ 通信的通道对象。
32 | * @param deliveryTag 消息的交付标签,用来唯一标识消息的标签,用于手动确认消息。初始值为1
33 | */
34 | // 指定程序监听的消息队列和确认机制
35 | @SneakyThrows
36 | @RabbitListener(queues = {MqConstant.DEAD_QUEUE_NAME}, ackMode = "MANUAL")
37 | public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
38 | if (StringUtils.isEmpty(message)) {
39 | channel.basicAck(deliveryTag, false);
40 | throw new BusinessException(ErrorCode.SYSTEM_ERROR, "消息为空");
41 | }
42 | log.info("Dead message:{}", message);
43 | long chartId = Long.parseLong(message);
44 | Chart chart = chartService.getById(chartId);
45 | if (chart == null) {
46 | // 如果找不到图表,记录错误并确认消息
47 | log.error("死信队列中的图表ID {} 不存在", chartId);
48 | channel.basicAck(deliveryTag, false);
49 | return;
50 | }
51 | chart.setId(chartId);
52 | chart.setStatus("failed");
53 | boolean b = chartService.updateById(chart);
54 | if (!b)
55 | log.error("更新图表失败状态错误" + chartId);
56 | webSocketService.sendToAllClient("坏了,分析好像出了点问题 ~~");
57 | channel.basicAck(deliveryTag, false);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/mq/InitMain.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.mq;
2 |
3 | import com.rabbitmq.client.Channel;
4 | import com.rabbitmq.client.Connection;
5 | import com.rabbitmq.client.ConnectionFactory;
6 | import lombok.SneakyThrows;
7 |
8 | import java.io.IOException;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | import static com.jl.springbootinit.mq.MqConstant.*;
13 |
14 | public class InitMain {
15 | @SneakyThrows
16 | public static void main(String[] args) {
17 | try {
18 | ConnectionFactory factory = new ConnectionFactory();
19 | factory.setHost("localhost");
20 | Connection connection = factory.newConnection();
21 | Channel channel = connection.createChannel();
22 |
23 | // 声明死信队列及交换机
24 | channel.exchangeDeclare(DEAD_EXCHANGE, "direct");
25 | channel.queueDeclare(DEAD_QUEUE_NAME, true, false, false, null);
26 | channel.queueBind(DEAD_QUEUE_NAME, DEAD_EXCHANGE, DEAD_ROUTING_KEY);
27 |
28 | // 声明正常队列添加死信队列相关设置
29 | Map arguments = new HashMap<>();
30 | arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);
31 | arguments.put("x-dead-letter-routing-key", DEAD_ROUTING_KEY);
32 |
33 | // 声明正常队列及交换机
34 | channel.queueDeclare(QUEUE_NAME, true, false, false, arguments);
35 | channel.exchangeDeclare(EXCHANGE_NAME, "direct");
36 | channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);
37 | } catch (IOException e) {
38 | e.printStackTrace();
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/mq/MessageConsumer.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.mq;
2 |
3 | import com.google.gson.*;
4 | import com.jl.springbootinit.manager.TaskManager;
5 | import com.jl.springbootinit.service.ScoreService;
6 | import com.rabbitmq.client.Channel;
7 | import com.jl.springbootinit.common.ErrorCode;
8 | import com.jl.springbootinit.exception.BusinessException;
9 | import com.jl.springbootinit.model.entity.Chart;
10 | import com.jl.springbootinit.service.ChartService;
11 | import com.jl.springbootinit.service.OpenaiService;
12 | import com.jl.springbootinit.ws.WebSocketServer;
13 | import lombok.SneakyThrows;
14 | import lombok.extern.slf4j.Slf4j;
15 | import org.apache.commons.lang3.StringUtils;
16 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
17 | import org.springframework.amqp.support.AmqpHeaders;
18 | import org.springframework.messaging.handler.annotation.Header;
19 | import org.springframework.stereotype.Component;
20 |
21 | import javax.annotation.Resource;
22 |
23 | import static com.jl.springbootinit.mq.MqConstant.QUEUE_NAME;
24 |
25 | @Component
26 | @Slf4j
27 | public class MessageConsumer {
28 | @Resource
29 | private ChartService chartService;
30 |
31 | @Resource
32 | private ScoreService scoreService;
33 |
34 | @Resource
35 | private OpenaiService openaiService;
36 |
37 | @Resource
38 | private WebSocketServer webSocketService;
39 |
40 | @Resource
41 | private TaskManager taskManager;
42 | // 指定程序监听的消息队列和确认机制
43 | @SneakyThrows
44 | @RabbitListener(queues = {QUEUE_NAME}, ackMode = "MANUAL")
45 | public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
46 | log.info("receiveMessage message = {}", message);
47 | if (StringUtils.isBlank(message)) {
48 | // 如果失败,消息拒绝
49 | channel.basicNack(deliveryTag, false, false);
50 | }
51 | long chartId = Long.parseLong(message);
52 | Chart chart = chartService.getById(chartId);
53 | Chart updateChart = new Chart();
54 | updateChart.setId(chart.getId());
55 | updateChart.setStatus("running");
56 | taskManager.startTaskTimer(chartId);
57 | // 将运行状态更新
58 | boolean bool = chartService.updateById(updateChart);
59 | if (!bool) {
60 | setChartErrorMessage(updateChart.getId(), "图表执行状态保存失败");
61 | channel.basicNack(deliveryTag, false, false);
62 | }
63 | String result = openaiService.doChat(handleUserInput(chart));
64 | scoreService.deductPoints(chart.getUserId(),1L);
65 | String[] splits = result.split("【【【【【");
66 | if (splits.length < 3){
67 | try {
68 | retryMessage(chartId, channel, deliveryTag, "AI生成格式错误");
69 | } catch (BusinessException e) {
70 | // 如果 retryMessage 抛出 BusinessException,记录错误并确认消息
71 | log.error("retryMessage 抛出 BusinessException: {}", e.getMessage(), e);
72 | channel.basicAck(deliveryTag, false);
73 | }
74 | }
75 | String genChart = splits[1].trim();
76 | String genResult = splits[2].trim();
77 | // Echarts代码过滤 "var option ="
78 | if (genChart.startsWith("var option =")) {
79 | genChart = genChart.replaceFirst("var\\s+option\\s*=\\s*", "");
80 | }
81 | Chart updateResult = new Chart();
82 | updateResult.setId(chartId);
83 | updateResult.setGenResult(genResult);
84 | JsonObject chartJson;
85 | String updatedGenChart = "";
86 | try {
87 | chartJson = JsonParser.parseString(genChart).getAsJsonObject();
88 | } catch (JsonSyntaxException e) {
89 | retryMessage(chartId, channel, deliveryTag, "图表json代码生成错误");
90 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "json代码解析异常,将重试");
91 | }
92 | // 自动添加图表类型
93 | if (StringUtils.isEmpty(chart.getChartType())) {
94 | if (chartJson.has("series") && chartJson.get("series").isJsonArray()) {
95 | JsonArray seriesArray = chartJson.getAsJsonArray("series");
96 | if (seriesArray.size() > 0) {
97 | JsonObject firstSeries = seriesArray.get(0).getAsJsonObject();
98 | if (firstSeries.has("type")) {
99 | String typeChart = firstSeries.get("type").getAsString();
100 | String CnChartType = chartService.getChartTypeToCN(typeChart);
101 | updateResult.setChartType(CnChartType);
102 | }
103 | }
104 | }
105 | }
106 | // 自动加入图表名称结尾并设置图表名称
107 | if (StringUtils.isEmpty(chart.getName())) {
108 | JsonElement titleElement = chartJson.getAsJsonObject("title").get("text");
109 | if (titleElement == null || titleElement.isJsonNull()) {
110 | try {
111 | retryMessage(chartId, channel, deliveryTag, "生成的json代码不存在title元素或无title.text元素");
112 | } catch (BusinessException e) {
113 | // 如果 retryMessage 抛出 BusinessException,记录错误并确认消息
114 | log.error("retryMessage 抛出 BusinessException: {}", e.getMessage(), e);
115 | channel.basicAck(deliveryTag, false);
116 | }
117 | }
118 | String titleText = titleElement.getAsString();
119 | if (titleText.isEmpty()) {
120 | try {
121 | retryMessage(chartId, channel, deliveryTag, "生成的json代码不存在text字段");
122 | } catch (BusinessException e) {
123 | // 如果 retryMessage 抛出 BusinessException,记录错误并确认消息
124 | log.error("retryMessage 抛出 BusinessException: {}", e.getMessage(), e);
125 | channel.basicAck(deliveryTag, false);
126 | }
127 | }
128 | String genChartName = String.valueOf(chartJson.getAsJsonObject("title").get("text"));
129 | genChartName = genChartName.replace("\"", "");
130 | if (! genChartName.endsWith("图") && ! genChartName.endsWith("表") && ! genChartName.endsWith("图表"))
131 | genChartName = genChartName + "图";
132 | updateResult.setName(genChartName);
133 | }
134 | // 加入下载按钮
135 | JsonObject toolbox = new JsonObject();
136 | toolbox.addProperty("show", true);
137 | JsonObject saveAsImage = new JsonObject();
138 | saveAsImage.addProperty("show", true);
139 | saveAsImage.addProperty("excludeComponents", "['toolbox']");
140 | saveAsImage.addProperty("pixelRatio", 2);
141 | JsonObject feature = new JsonObject();
142 | feature.add("saveAsImage", saveAsImage);
143 | toolbox.add("feature", feature);
144 | chartJson.add("toolbox", toolbox);
145 | chartJson.remove("title");
146 | updatedGenChart = chartJson.toString();
147 | updateResult.setGenChart(updatedGenChart);
148 | // TODO:枚举值实现
149 | updateResult.setStatus("succeed");
150 | boolean code = chartService.updateById(updateResult);
151 | if (!code){
152 | setChartErrorMessage(updateResult.getId(), "图表代码保存失败");
153 | channel.basicNack(deliveryTag, false, false);
154 | }
155 | taskManager.clearTaskTimer(chartId);
156 | webSocketService.sendToAllClient("图表生成好啦,快去看看吧!");
157 | channel.basicAck(deliveryTag, false);
158 | }
159 |
160 | private String handleUserInput(Chart chart){
161 | StringBuilder userInput = new StringBuilder();
162 | userInput.append("分析需求:\n");
163 | // 拼接分析目标
164 | String userGoal = chart.getGoal();
165 | String chartType = chart.getChartType();
166 |
167 | // 分析输入加入图表类型
168 | if (StringUtils.isNotBlank(chartType))
169 | userGoal += ",请使用" + chartType;
170 | userInput.append(userGoal).append("\n");
171 | userInput.append("原始数据:\n");
172 | // 压缩数据
173 | String userData = chart.getChartData();
174 | userInput.append(userData).append("\n");
175 | return userInput.toString();
176 | }
177 |
178 | /**
179 | * 设置图表错误信息
180 | * @param chartId
181 | * @param execMessage
182 | */
183 | private void setChartErrorMessage(long chartId, String execMessage){
184 | Chart updateChart = new Chart();
185 | updateChart.setId(chartId);
186 | updateChart.setExecMessage(execMessage);
187 | boolean b = chartService.updateById(updateChart);
188 | if (!b) {
189 | log.error("更新图表失败状态错误" + chartId + ":" + execMessage);
190 | }
191 | }
192 |
193 | /**
194 | *
195 | * 消息重试
196 | * @param chartId
197 | * @param channel
198 | * @param deliveryTag
199 | * @param execMessage
200 | */
201 | @SneakyThrows
202 | private void retryMessage(long chartId, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, String execMessage){
203 | Chart chart = chartService.getById(chartId);
204 | // 超过重试次数
205 | if (chart.getRetry() > 0) {
206 | setChartErrorMessage(chartId, execMessage);
207 | channel.basicNack(deliveryTag, false, false);
208 | }else {
209 | Chart updateRetryChart = new Chart();
210 | updateRetryChart.setId(chartId);
211 | updateRetryChart.setRetry(chart.getRetry() + 1);
212 | boolean updateBool = chartService.updateById(updateRetryChart);
213 | if (!updateBool) {
214 | setChartErrorMessage(chartId, "图表重试次数保存失败");
215 | channel.basicNack(deliveryTag, false, false);
216 | }
217 | log.info(execMessage + ",将重试");
218 | channel.basicNack(deliveryTag, false, true);
219 | }
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/mq/MessageProducer.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.mq;
2 |
3 | import org.springframework.amqp.core.Message;
4 | import org.springframework.amqp.core.MessageProperties;
5 | import org.springframework.amqp.rabbit.core.RabbitTemplate;
6 | import org.springframework.stereotype.Component;
7 |
8 | import javax.annotation.Resource;
9 |
10 | import static com.jl.springbootinit.mq.MqConstant.EXCHANGE_NAME;
11 | import static com.jl.springbootinit.mq.MqConstant.ROUTING_KEY;
12 |
13 | @Component
14 | public class MessageProducer {
15 | @Resource
16 | private RabbitTemplate rabbitTemplate;
17 |
18 | public void sendMessage(String message){
19 | MessageProperties messageProperties = new MessageProperties();
20 | // 设置超时时间为4分钟(240秒),其中模型处理时间为225s
21 | messageProperties.setExpiration("240000");
22 | Message msg = new Message(message.getBytes(), messageProperties);
23 | rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING_KEY, msg);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/mq/MqConstant.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.mq;
2 |
3 | public interface MqConstant {
4 | String EXCHANGE_NAME = "bi_exchange_16";
5 |
6 | String QUEUE_NAME = "bi_queue_16";
7 |
8 | String ROUTING_KEY = "bi_routing_key_16";
9 |
10 | String DEAD_QUEUE_NAME = "bi_dead_queue_16";
11 |
12 | String DEAD_EXCHANGE = "bi_dead_exchange_16";
13 |
14 | String DEAD_ROUTING_KEY = "bi_dead_routing_key_16";
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/service/ChartService.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.service;
2 |
3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
4 | import com.jl.springbootinit.model.entity.Chart;
5 | import com.baomidou.mybatisplus.extension.service.IService;
6 |
7 | /**
8 | * @author 99367
9 | * @description 针对表【chart(图表信息表)】的数据库操作Service
10 | * @createDate 2023-12-25 16:07:42
11 | */
12 | public interface ChartService extends IService {
13 |
14 | /**
15 | * 图表类型转换为中文
16 | * @param type
17 | * @return
18 | */
19 | String getChartTypeToCN(String type);
20 |
21 | /**
22 | * 查询图表分页是否相同
23 | * @param page1
24 | * @param page2
25 | * @return
26 | */
27 | boolean isSamePage(Page page1, Page page2);
28 |
29 | /**
30 | * 查询图表是否相同
31 | * @param chart1
32 | * @param chart2
33 | * @return
34 | */
35 | boolean isSameChart(Chart chart1, Chart chart2);
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/service/OpenaiService.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.service;
2 |
3 | /**
4 | * @author ljl
5 | * @description openaiApi接口类
6 | */
7 | public interface OpenaiService {
8 |
9 | /**
10 | * AI 对话
11 | * @param prompt
12 | * @return
13 | */
14 | String doChat(String prompt);
15 |
16 | /**
17 | * AI 对话错误重试
18 | * @param userPrompt
19 | * @return
20 | * @throws Exception
21 | */
22 | String doChatWithRetry(String userPrompt) throws Exception;
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/service/ScoreService.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.service;
2 |
3 | import com.baomidou.mybatisplus.extension.service.IService;
4 | import com.jl.springbootinit.model.entity.Score;
5 |
6 | public interface ScoreService extends IService {
7 | /**
8 | * 签到
9 | * @param userId
10 | * @return
11 | */
12 | void checkIn(Long userId);
13 |
14 | /**
15 | * 消耗积分
16 | * @param userId
17 | * @param points 积分数
18 | * @return
19 | */
20 | void deductPoints(Long userId, Long points);
21 |
22 | /**
23 | *获取积分
24 | * @param userId
25 | * @return
26 | */
27 | Long getUserPoints(Long userId);
28 |
29 | /**
30 | *
31 | * 获取是否签到状态
32 | * @param userId
33 | * @return
34 | */
35 | int getIsSign(Long userId);
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/service/UserService.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.service;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 | import com.jl.springbootinit.model.dto.user.UserQueryRequest;
6 | import com.jl.springbootinit.model.entity.User;
7 | import com.jl.springbootinit.model.vo.LoginUserVO;
8 | import com.jl.springbootinit.model.vo.UserVO;
9 | import java.util.List;
10 | import javax.servlet.http.HttpServletRequest;
11 |
12 | /**
13 | * 用户服务
14 | *
15 | */
16 | public interface UserService extends IService {
17 |
18 | /**
19 | * 用户注册
20 | *
21 | * @param userAccount 用户账户
22 | * @param userPassword 用户密码
23 | * @param checkPassword 校验密码
24 | * @return 新用户 id
25 | */
26 | long userRegister(String userAccount, String userPassword, String checkPassword);
27 |
28 | /**
29 | * 用户登录
30 | *
31 | * @param userAccount 用户账户
32 | * @param userPassword 用户密码
33 | * @param request
34 | * @return 脱敏后的用户信息
35 | */
36 | LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request);
37 |
38 |
39 | /**
40 | * 获取当前登录用户
41 | *
42 | * @param request
43 | * @return
44 | */
45 | User getLoginUser(HttpServletRequest request);
46 |
47 | /**
48 | * 获取当前登录用户(允许未登录)
49 | *
50 | * @param request
51 | * @return
52 | */
53 | User getLoginUserPermitNull(HttpServletRequest request);
54 |
55 | /**
56 | * 是否为管理员
57 | *
58 | * @param request
59 | * @return
60 | */
61 | boolean isAdmin(HttpServletRequest request);
62 |
63 | /**
64 | * 是否为管理员
65 | *
66 | * @param user
67 | * @return
68 | */
69 | boolean isAdmin(User user);
70 |
71 | /**
72 | * 用户注销
73 | *
74 | * @param request
75 | * @return
76 | */
77 | boolean userLogout(HttpServletRequest request);
78 |
79 | /**
80 | * 获取脱敏的已登录用户信息
81 | *
82 | * @return
83 | */
84 | LoginUserVO getLoginUserVO(User user);
85 |
86 | /**
87 | * 获取脱敏的用户信息
88 | *
89 | * @param user
90 | * @return
91 | */
92 | UserVO getUserVO(User user);
93 |
94 | /**
95 | * 获取脱敏的用户信息
96 | *
97 | * @param userList
98 | * @return
99 | */
100 | List getUserVO(List userList);
101 |
102 | /**
103 | * 获取查询条件
104 | *
105 | * @param userQueryRequest
106 | * @return
107 | */
108 | QueryWrapper getQueryWrapper(UserQueryRequest userQueryRequest);
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/service/impl/ChartServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.service.impl;
2 |
3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
5 | import com.jl.springbootinit.model.entity.Chart;
6 | import com.jl.springbootinit.service.ChartService;
7 | import com.jl.springbootinit.mapper.ChartMapper;
8 | import org.springframework.stereotype.Service;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * @author 99367
14 | * @description 针对表【chart(图表信息表)】的数据库操作Service实现
15 | * @createDate 2023-12-25 16:07:42
16 | */
17 | @Service
18 | public class ChartServiceImpl extends ServiceImpl
19 | implements ChartService{
20 |
21 | @Override
22 | public String getChartTypeToCN(String type) {
23 | switch (type){
24 | case "line":
25 | return "折线图";
26 | case "bar":
27 | return "柱状图";
28 | case "pie":
29 | return "饼图";
30 | case "scatter":
31 | return "散点图";
32 | case "radar":
33 | return "雷达图";
34 | case "map":
35 | return "地图";
36 | case "candlestick":
37 | return "K线图";
38 | case "heatmap":
39 | return "热力图";
40 | case "tree":
41 | return "树图";
42 | case "lines":
43 | return "路线图";
44 | case "graph":
45 | return "关系图";
46 | case "sunburst":
47 | return "旭日图";
48 | default:
49 | return "特殊图表";
50 | }
51 | }
52 | public boolean isSamePage(Page page1, Page page2) {
53 | // 检查两个分页对象是否为null
54 | if (page1 == null || page2 == null) {
55 | return false;
56 | }
57 | // 检查总页数是否相同
58 | if (page1.getPages() != page2.getPages()) {
59 | return false;
60 | }
61 | // 检查当前页数是否相同
62 | if (page1.getCurrent() != page2.getCurrent()) {
63 | return false;
64 | }
65 | // 检查每页大小是否相同
66 | if (page1.getSize() != page2.getSize()) {
67 | return false;
68 | }
69 | // 检查数据项是否相同
70 | List list1 = page1.getRecords();
71 | List list2 = page2.getRecords();
72 | // 如果数据项个数不同,则两个分页对象不同
73 | if (list1.size() != list2.size()) {
74 | return false;
75 | }
76 | // 检查每个数据项是否相同
77 | for (int i = 0; i < list1.size(); i++) {
78 | Chart chart1 = list1.get(i);
79 | Chart chart2 = list2.get(i);
80 | // 检查数据项是否相同,可以根据具体业务需求来定义
81 | if (!isSameChart(chart1, chart2)) {
82 | return false;
83 | }
84 | }
85 | return true;
86 | }
87 |
88 | // 检查两个图表对象是否相同,可以根据具体业务需求来定义
89 | public boolean isSameChart(Chart chart1, Chart chart2) {
90 | // 这里可以比较图表对象的各个属性是否相同,例如ID、名称、类型等等
91 | // 如果所有属性都相同,则返回true;否则返回false
92 | return chart1.getId().equals(chart2.getId())
93 | && chart1.getStatus().equals(chart2.getStatus());
94 | }
95 | }
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/service/impl/OpenaiServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.service.impl;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.github.rholder.retry.*;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonObject;
7 | import com.google.gson.JsonParser;
8 | import com.google.gson.JsonSyntaxException;
9 | import com.theokanning.openai.OpenAiApi;
10 | import com.theokanning.openai.completion.chat.ChatCompletionRequest;
11 | import com.theokanning.openai.completion.chat.ChatMessage;
12 | import com.theokanning.openai.completion.chat.ChatMessageRole;
13 | import com.theokanning.openai.service.OpenAiService;
14 | import com.jl.springbootinit.service.OpenaiService;
15 | import okhttp3.OkHttpClient;
16 | import org.springframework.beans.factory.annotation.Value;
17 | import org.springframework.stereotype.Service;
18 | import retrofit2.Retrofit;
19 |
20 | import java.net.InetSocketAddress;
21 | import java.net.Proxy;
22 | import java.time.Duration;
23 | import java.util.ArrayList;
24 | import java.util.List;
25 | import java.util.concurrent.Callable;
26 | import java.util.concurrent.TimeUnit;
27 |
28 | import static com.theokanning.openai.service.OpenAiService.*;
29 |
30 | @Service
31 | public class OpenaiServiceImpl implements OpenaiService {
32 |
33 | @Value("${openai.api.key}")
34 | private String openaiApiKey;
35 |
36 | @Value("${openai.model}")
37 | private String model;
38 |
39 | // @Value("${proxy.host}")
40 | // private String proxyHost;
41 | //
42 | // @Value("${proxy.port}")
43 | // private int proxyPort;
44 |
45 |
46 | // 超时时间
47 | private static final Duration TIMEOUT = Duration.ofSeconds(220L);
48 |
49 | // 理论最大处理数据条数,处理时间约为30s
50 | public static final Integer SYNCHRO_MAX_TOKEN = 340;
51 |
52 | // 设置重试,重试次数2次,重试间隔2s
53 | private final Retryer retryer = RetryerBuilder.newBuilder()
54 | .retryIfResult(result->(!isValidResult(result)))
55 | .withStopStrategy(StopStrategies.stopAfterAttempt(2))
56 | .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
57 | .build();
58 |
59 | public String doChat(String userPrompt) {
60 | ObjectMapper mapper = defaultObjectMapper();
61 | // Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
62 | OkHttpClient client = defaultClient(openaiApiKey, TIMEOUT)
63 | .newBuilder()
64 | // .proxy(proxy)
65 | .build();
66 | Retrofit retrofit = defaultRetrofit(client, mapper);
67 | OpenAiApi api = retrofit.create(OpenAiApi.class);
68 | OpenAiService service = new OpenAiService(api);
69 | List messages = new ArrayList<>();
70 | final String systemPrompt = "你是一个数据分析师和前端开发专家,接下来我会按照以下固定格式给你提供内容:\n" +
71 | "分析需求:\n" + "{数据分析的需求或者目标}\n" +
72 | "原始数据:\n" + "{csv格式的原始数据,用,作为分隔符}\n" +
73 | "请根据这两部分内容,按照以下指定格式生成内容,其中包括生成分隔符\"【【【【【\",同时分析结论请直接给出(此外不要输出任何多余的开头、结尾、注释)\n" +
74 | "【【【【【\n" +
75 | "{前端 Echarts V5 的 option 配置对象js代码(json格式),代码需要包括title.text(需要该图的名称)部分、图例部分(即legend元素,文字部分应为黑色,图例线颜色与图例颜色相同),合理地将数据进行可视化,图表要求:1、若图表有轴线请将轴线画出,如y轴线,颜色为黑色2、坐标字体为黑色,不要生成任何多余的内容,比如注释}\n" +
76 | "【【【【【\n" +
77 | "{请直接明确的数据分析结论、越详细越好(字数越多越好),不要生成多余的注释}";
78 | ChatMessage systemMessage = new ChatMessage(ChatMessageRole.USER.value(), systemPrompt);
79 | ChatMessage userMessage = new ChatMessage(ChatMessageRole.USER.value(), userPrompt);
80 | messages.add(systemMessage);
81 | messages.add(userMessage);
82 | ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest
83 | .builder()
84 | .model(model)
85 | .messages(messages)
86 | .build();
87 | ChatMessage responseMessage = service.createChatCompletion(chatCompletionRequest).getChoices().get(0).getMessage();
88 | return responseMessage.getContent();
89 | }
90 |
91 | @Override
92 | public String doChatWithRetry(String userPrompt) throws Exception {
93 | try {
94 | Callable callable = () -> {
95 | // 在这里调用你的doChat方法
96 | return doChat(userPrompt);
97 | };
98 | return retryer.call(callable);
99 | } catch (RetryException e) {
100 | throw new Exception("重试失败", e);
101 | }
102 | }
103 |
104 | /**
105 | * 分析结果是否存在错误
106 | * @param result
107 | * @return
108 | */
109 | private boolean isValidResult(String result) {
110 | String[] splits = result.split("【【【【【");
111 | if (splits.length < 3)
112 | return false;
113 | String genChart = splits[1].trim();
114 | try {
115 | JsonObject chartJson = JsonParser.parseString(genChart).getAsJsonObject();
116 | // 检查是否存在 "title" 字段
117 | if (!chartJson.has("title")) {
118 | return false;
119 | }
120 | // 检查 "title" 字段的内容是否为空或不含 "text" 字段
121 | JsonElement titleElement = chartJson.getAsJsonObject("title").get("text");
122 | if (titleElement == null || titleElement.isJsonNull()) {
123 | return false;
124 | }
125 | String titleText = titleElement.getAsString();
126 | if (titleText.isEmpty()) {
127 | return false;
128 | }
129 | } catch (JsonSyntaxException e) {
130 | // Json解析异常,直接返回 false
131 | return false;
132 | }
133 | return true;
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/service/impl/ScoreServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.service.impl;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
4 | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
6 | import com.jl.springbootinit.common.ErrorCode;
7 | import com.jl.springbootinit.exception.ThrowUtils;
8 | import com.jl.springbootinit.mapper.ScoreMapper;
9 | import com.jl.springbootinit.model.entity.Score;
10 | import com.jl.springbootinit.service.ScoreService;
11 | import org.springframework.stereotype.Service;
12 |
13 | /**
14 | * @author 99367
15 | * @description 针对表【score(积分表)】的数据库操作Service实现
16 | * @createDate 2024-01-28 16:15:09
17 | */
18 | @Service
19 | public class ScoreServiceImpl extends ServiceImpl
20 | implements ScoreService {
21 |
22 | @Override
23 | public void checkIn(Long userId) {
24 | QueryWrapper queryWrapper = new QueryWrapper<>();
25 | queryWrapper.eq("userId",userId);
26 | Score score = this.getOne(queryWrapper);
27 | ThrowUtils.throwIf(score == null, ErrorCode.NOT_FOUND_ERROR);
28 | ThrowUtils.throwIf(score.getIsSign()==1,ErrorCode.PARAMS_ERROR,"领取失败,今日已领取");
29 | Long scoreTotal = score.getScoreTotal();
30 | UpdateWrapper updateWrapper = new UpdateWrapper();
31 | updateWrapper
32 | //此处暂时写死签到积分
33 | .eq("userId",userId)
34 | .set("scoreTotal",scoreTotal+1)
35 | .set("isSign",1);
36 | boolean r = this.update(updateWrapper);
37 | ThrowUtils.throwIf(!r, ErrorCode.OPERATION_ERROR,"更新签到数据失败");
38 | }
39 |
40 | @Override
41 | public void deductPoints(Long userId, Long points) {
42 | QueryWrapper queryWrapper = new QueryWrapper<>();
43 | queryWrapper.eq("userId",userId);
44 | Score score = this.getOne(queryWrapper);
45 | ThrowUtils.throwIf(score.getScoreTotal() updateWrapper = new UpdateWrapper();
48 | updateWrapper
49 | .eq("userId",userId)
50 | .set("scoreTotal",scoreTotal-points);
51 | boolean r = this.update(updateWrapper);
52 | ThrowUtils.throwIf(!r, ErrorCode.OPERATION_ERROR);
53 | }
54 |
55 | @Override
56 | public Long getUserPoints(Long userId) {
57 | QueryWrapper queryWrapper = new QueryWrapper<>();
58 | queryWrapper.eq("userId",userId);
59 | Score score = this.getOne(queryWrapper);
60 | return score.getScoreTotal();
61 | }
62 |
63 | @Override
64 | public int getIsSign(Long userId){
65 | QueryWrapper queryWrapper = new QueryWrapper<>();
66 | queryWrapper.eq("userId",userId);
67 | Score score = this.getOne(queryWrapper);
68 | return score.getIsSign();
69 | }
70 | }
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/service/impl/UserServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.service.impl;
2 |
3 | import static com.jl.springbootinit.constant.UserConstant.USER_LOGIN_STATE;
4 |
5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
6 | import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
7 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
8 | import com.jl.springbootinit.common.ErrorCode;
9 | import com.jl.springbootinit.constant.CommonConstant;
10 | import com.jl.springbootinit.exception.BusinessException;
11 | import com.jl.springbootinit.exception.ThrowUtils;
12 | import com.jl.springbootinit.mapper.UserMapper;
13 | import com.jl.springbootinit.model.dto.user.UserQueryRequest;
14 | import com.jl.springbootinit.model.entity.Score;
15 | import com.jl.springbootinit.model.entity.User;
16 | import com.jl.springbootinit.model.enums.UserRoleEnum;
17 | import com.jl.springbootinit.model.vo.LoginUserVO;
18 | import com.jl.springbootinit.model.vo.UserVO;
19 | import com.jl.springbootinit.service.ScoreService;
20 | import com.jl.springbootinit.service.UserService;
21 | import com.jl.springbootinit.utils.SqlUtils;
22 | import java.util.ArrayList;
23 | import java.util.List;
24 | import java.util.stream.Collectors;
25 | import javax.annotation.Resource;
26 | import javax.servlet.http.HttpServletRequest;
27 | import lombok.extern.slf4j.Slf4j;
28 | import org.apache.commons.lang3.StringUtils;
29 | import org.springframework.beans.BeanUtils;
30 | import org.springframework.stereotype.Service;
31 | import org.springframework.util.DigestUtils;
32 |
33 | /**
34 | * 用户服务实现
35 | *
36 | */
37 | @Service
38 | @Slf4j
39 | public class UserServiceImpl extends ServiceImpl implements UserService {
40 |
41 | /**
42 | * 盐值,混淆密码
43 | */
44 | private static final String SALT = "jlong";
45 |
46 | @Resource
47 | private ScoreService scoreService;
48 |
49 | @Override
50 | public long userRegister(String userAccount, String userPassword, String checkPassword) {
51 | // 1. 校验
52 | if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {
53 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
54 | }
55 | if (userAccount.length() < 4) {
56 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
57 | }
58 | if (userPassword.length() < 8 || checkPassword.length() < 8) {
59 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
60 | }
61 | // 密码和校验密码相同
62 | if (!userPassword.equals(checkPassword)) {
63 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
64 | }
65 | synchronized (userAccount.intern()) {
66 | // 账户不能重复
67 | QueryWrapper queryWrapper = new QueryWrapper<>();
68 | queryWrapper.eq("userAccount", userAccount);
69 | long count = this.baseMapper.selectCount(queryWrapper);
70 | if (count > 0) {
71 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
72 | }
73 | // 2. 加密
74 | String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
75 | // 3. 插入数据
76 | User user = new User();
77 | user.setUserAccount(userAccount);
78 | user.setUserName(userAccount);
79 | user.setUserPassword(encryptPassword);
80 | user.setUserAvatar("https://img1.baidu.com/it/u=3379946556,946410391&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500");
81 | boolean saveResult = this.save(user);
82 | if (!saveResult) {
83 | throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败,数据库错误");
84 | }
85 | //注册成功后往Score表插入数据
86 | Score score = new Score();
87 | //未签到
88 | score.setIsSign(0);
89 | //初始积分10分
90 | score.setScoreTotal(10L);
91 | score.setUserId(user.getId());
92 | boolean scoreResult = scoreService.save(score);
93 | ThrowUtils.throwIf(!scoreResult,ErrorCode.OPERATION_ERROR,"注册积分异常");
94 | return user.getId();
95 | }
96 | }
97 |
98 | @Override
99 | public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
100 | // 1. 校验
101 | if (StringUtils.isAnyBlank(userAccount, userPassword)) {
102 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
103 | }
104 | if (userAccount.length() < 4) {
105 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误");
106 | }
107 | if (userPassword.length() < 8) {
108 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
109 | }
110 | // 2. 加密
111 | String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
112 | // 查询用户是否存在
113 | QueryWrapper queryWrapper = new QueryWrapper<>();
114 | queryWrapper.eq("userAccount", userAccount);
115 | queryWrapper.eq("userPassword", encryptPassword);
116 | User user = this.baseMapper.selectOne(queryWrapper);
117 | // 用户不存在
118 | if (user == null) {
119 | log.info("user login failed, userAccount cannot match userPassword");
120 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
121 | }
122 | // 3. 记录用户的登录态
123 | request.getSession().setAttribute(USER_LOGIN_STATE, user);
124 | return this.getLoginUserVO(user);
125 | }
126 |
127 |
128 | /**
129 | * 获取当前登录用户
130 | *
131 | * @param request
132 | * @return
133 | */
134 | @Override
135 | public User getLoginUser(HttpServletRequest request) {
136 | // 先判断是否已登录
137 | Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
138 | User currentUser = (User) userObj;
139 | if (currentUser == null || currentUser.getId() == null) {
140 | throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
141 | }
142 | // 从数据库查询(追求性能的话可以注释,直接走缓存)
143 | long userId = currentUser.getId();
144 | currentUser = this.getById(userId);
145 | if (currentUser == null) {
146 | throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
147 | }
148 | return currentUser;
149 | }
150 |
151 | /**
152 | * 获取当前登录用户(允许未登录)
153 | *
154 | * @param request
155 | * @return
156 | */
157 | @Override
158 | public User getLoginUserPermitNull(HttpServletRequest request) {
159 | // 先判断是否已登录
160 | Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
161 | User currentUser = (User) userObj;
162 | if (currentUser == null || currentUser.getId() == null) {
163 | return null;
164 | }
165 | // 从数据库查询(追求性能的话可以注释,直接走缓存)
166 | long userId = currentUser.getId();
167 | return this.getById(userId);
168 | }
169 |
170 | /**
171 | * 是否为管理员
172 | *
173 | * @param request
174 | * @return
175 | */
176 | @Override
177 | public boolean isAdmin(HttpServletRequest request) {
178 | // 仅管理员可查询
179 | Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
180 | User user = (User) userObj;
181 | return isAdmin(user);
182 | }
183 |
184 | @Override
185 | public boolean isAdmin(User user) {
186 | return user != null && UserRoleEnum.ADMIN.getValue().equals(user.getUserRole());
187 | }
188 |
189 | /**
190 | * 用户注销
191 | *
192 | * @param request
193 | */
194 | @Override
195 | public boolean userLogout(HttpServletRequest request) {
196 | if (request.getSession().getAttribute(USER_LOGIN_STATE) == null) {
197 | throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");
198 | }
199 | // 移除登录态
200 | request.getSession().removeAttribute(USER_LOGIN_STATE);
201 | return true;
202 | }
203 |
204 | @Override
205 | public LoginUserVO getLoginUserVO(User user) {
206 | if (user == null) {
207 | return null;
208 | }
209 | LoginUserVO loginUserVO = new LoginUserVO();
210 | BeanUtils.copyProperties(user, loginUserVO);
211 | return loginUserVO;
212 | }
213 |
214 | @Override
215 | public UserVO getUserVO(User user) {
216 | if (user == null) {
217 | return null;
218 | }
219 | UserVO userVO = new UserVO();
220 | BeanUtils.copyProperties(user, userVO);
221 | return userVO;
222 | }
223 |
224 | @Override
225 | public List getUserVO(List userList) {
226 | if (CollectionUtils.isEmpty(userList)) {
227 | return new ArrayList<>();
228 | }
229 | return userList.stream().map(this::getUserVO).collect(Collectors.toList());
230 | }
231 |
232 | @Override
233 | public QueryWrapper getQueryWrapper(UserQueryRequest userQueryRequest) {
234 | if (userQueryRequest == null) {
235 | throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
236 | }
237 | Long id = userQueryRequest.getId();
238 | String unionId = userQueryRequest.getUnionId();
239 | String mpOpenId = userQueryRequest.getMpOpenId();
240 | String userName = userQueryRequest.getUserName();
241 | String userProfile = userQueryRequest.getUserProfile();
242 | String userRole = userQueryRequest.getUserRole();
243 | String sortField = userQueryRequest.getSortField();
244 | String sortOrder = userQueryRequest.getSortOrder();
245 | QueryWrapper queryWrapper = new QueryWrapper<>();
246 | queryWrapper.eq(id != null, "id", id);
247 | queryWrapper.eq(StringUtils.isNotBlank(unionId), "unionId", unionId);
248 | queryWrapper.eq(StringUtils.isNotBlank(mpOpenId), "mpOpenId", mpOpenId);
249 | queryWrapper.eq(StringUtils.isNotBlank(userRole), "userRole", userRole);
250 | queryWrapper.like(StringUtils.isNotBlank(userProfile), "userProfile", userProfile);
251 | queryWrapper.like(StringUtils.isNotBlank(userName), "userName", userName);
252 | queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
253 | sortField);
254 | return queryWrapper;
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/utils/Csv2String.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.utils;
2 |
3 | import org.springframework.web.multipart.MultipartFile;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.IOException;
7 | import java.io.InputStreamReader;
8 | import java.nio.charset.StandardCharsets;
9 |
10 | public class Csv2String {
11 |
12 | public static String MultipartFileToString(MultipartFile multipartFile) {
13 | InputStreamReader isr;
14 | BufferedReader br;
15 | StringBuilder txtResult = new StringBuilder();
16 | try {
17 | isr = new InputStreamReader(multipartFile.getInputStream(), StandardCharsets.UTF_8);
18 | br = new BufferedReader(isr);
19 | String lineTxt;
20 | while ((lineTxt = br.readLine()) != null) {
21 | txtResult.append(lineTxt);
22 | }
23 | isr.close();
24 | br.close();
25 | return txtResult.toString();
26 | } catch (IOException e) {
27 | e.printStackTrace();
28 | return "";
29 | }
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/jl/springbootinit/utils/ExcelUtils.java:
--------------------------------------------------------------------------------
1 | package com.jl.springbootinit.utils;
2 |
3 | import cn.hutool.core.collection.CollUtil;
4 | import com.alibaba.excel.EasyExcel;
5 | import com.alibaba.excel.support.ExcelTypeEnum;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | import org.apache.commons.lang3.ObjectUtils;
9 |
10 | import org.apache.commons.lang3.StringUtils;
11 | import org.springframework.web.multipart.MultipartFile;
12 |
13 | import java.io.IOException;
14 | import java.util.LinkedHashMap;
15 | import java.util.List;
16 | import java.util.Map;
17 | import java.util.stream.Collectors;
18 |
19 | /**
20 | * Excel 工具类
21 | *
22 | */
23 | @Slf4j
24 | public class ExcelUtils {
25 |
26 | public static String excel2Csv(MultipartFile multipartFile) {
27 | // 读取数据
28 | List