Pre Merge pull request !1364 from 邓飞鹏/feature_CatagoryInit
This commit is contained in:
commit
09ab0f9d2c
16
pom.xml
16
pom.xml
|
@ -15,14 +15,14 @@
|
|||
<!-- 各种 module 拓展 -->
|
||||
<module>yudao-module-system</module>
|
||||
<module>yudao-module-infra</module>
|
||||
<!-- <module>yudao-module-member</module>-->
|
||||
<!-- <module>yudao-module-bpm</module>-->
|
||||
<!-- <module>yudao-module-report</module>-->
|
||||
<!-- <module>yudao-module-mp</module>-->
|
||||
<!-- <module>yudao-module-pay</module>-->
|
||||
<!-- <module>yudao-module-mall</module>-->
|
||||
<!-- <module>yudao-module-crm</module>-->
|
||||
<!-- <module>yudao-module-erp</module>-->
|
||||
<module>yudao-module-member</module>
|
||||
<module>yudao-module-bpm</module>
|
||||
<module>yudao-module-report</module>
|
||||
<module>yudao-module-mp</module>
|
||||
<module>yudao-module-pay</module>
|
||||
<module>yudao-module-mall</module>
|
||||
<module>yudao-module-crm</module>
|
||||
<module>yudao-module-erp</module>
|
||||
<!-- <module>yudao-module-iot</module>-->
|
||||
<!-- AI 大模型的开启,请参考 https://doc.iocoder.cn/ai/build/ 文档,对 JDK 版本要要求! -->
|
||||
<!-- <module>yudao-module-ai</module>-->
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"info": {
|
||||
"_postman_id": "44c9067c-39e0-4ba4-b164-67f65d9988a5",
|
||||
"name": "Elasticsearch",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"_exporter_id": "40143787"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "http://192.168.172.128:9200/",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://192.168.172.128:9200/",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"192",
|
||||
"168",
|
||||
"172",
|
||||
"128"
|
||||
],
|
||||
"port": "9200",
|
||||
"path": [
|
||||
""
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
# ======================== Elasticsearch Configuration =========================
|
||||
#
|
||||
# NOTE: Elasticsearch comes with reasonable defaults for most settings.
|
||||
# Before you set out to tweak and tune the configuration, make sure you
|
||||
# understand what are you trying to accomplish and the consequences.
|
||||
#
|
||||
# The primary way of configuring a node is via this file. This template lists
|
||||
# the most important settings you may want to configure for a production cluster.
|
||||
#
|
||||
# Please consult the documentation for further information on configuration options:
|
||||
# https://www.elastic.co/guide/en/elasticsearch/reference/index.html
|
||||
#
|
||||
# ---------------------------------- Cluster -----------------------------------
|
||||
#
|
||||
# Use a descriptive name for your cluster:
|
||||
#
|
||||
cluster.name: my-application
|
||||
#
|
||||
# ------------------------------------ Node ------------------------------------
|
||||
#
|
||||
# Use a descriptive name for the node:
|
||||
#
|
||||
node.name: node-1
|
||||
#
|
||||
# Add custom attributes to the node:
|
||||
#
|
||||
#node.attr.rack: r1
|
||||
#
|
||||
# ----------------------------------- Paths ------------------------------------
|
||||
#
|
||||
# Path to directory where to store the data (separate multiple locations by comma):
|
||||
#
|
||||
path.data: /var/lib/elasticsearch
|
||||
#
|
||||
# Path to log files:
|
||||
#
|
||||
path.logs: /var/log/elasticsearch
|
||||
#
|
||||
# ----------------------------------- Memory -----------------------------------
|
||||
#
|
||||
# Lock the memory on startup:
|
||||
#
|
||||
#bootstrap.memory_lock: true
|
||||
#
|
||||
# Make sure that the heap size is set to about half the memory available
|
||||
# on the system and that the owner of the process is allowed to use this
|
||||
# limit.
|
||||
#
|
||||
# Elasticsearch performs poorly when the system is swapping the memory.
|
||||
#
|
||||
# ---------------------------------- Network -----------------------------------
|
||||
#
|
||||
# By default Elasticsearch is only accessible on localhost. Set a different
|
||||
# address here to expose this node on the network:
|
||||
#
|
||||
network.host: 0.0.0.0
|
||||
#
|
||||
# By default Elasticsearch listens for HTTP traffic on the first free port it
|
||||
# finds starting at 9200. Set a specific HTTP port here:
|
||||
#
|
||||
http.port: 9200
|
||||
#
|
||||
# For more information, consult the network module documentation.
|
||||
#
|
||||
# --------------------------------- Discovery ----------------------------------
|
||||
#
|
||||
# Pass an initial list of hosts to perform discovery when this node is started:
|
||||
# The default list of hosts is ["127.0.0.1", "[::1]"]
|
||||
#
|
||||
discovery.seed_hosts: ["127.0.0.1"]
|
||||
#
|
||||
# Bootstrap the cluster using an initial set of master-eligible nodes:
|
||||
#
|
||||
cluster.initial_master_nodes: ["node-1"]
|
||||
#
|
||||
# For more information, consult the discovery and cluster formation module documentation.
|
||||
#
|
||||
# ---------------------------------- Various -----------------------------------
|
||||
#
|
||||
# Allow wildcard deletion of indices:
|
||||
#
|
||||
#action.destructive_requires_name: false
|
||||
|
||||
#----------------------- BEGIN SECURITY AUTO CONFIGURATION -----------------------
|
||||
#
|
||||
# The following settings, TLS certificates, and keys have been automatically
|
||||
# generated to configure Elasticsearch security features on 02-12-2024 11:13:43
|
||||
#
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
# Enable security features
|
||||
xpack.security.enabled: false
|
||||
|
||||
xpack.security.enrollment.enabled: false
|
||||
|
||||
# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
|
||||
xpack.security.http.ssl:
|
||||
enabled: false
|
||||
keystore.path: certs/http.p12
|
||||
|
||||
# Enable encryption and mutual authentication between cluster nodes
|
||||
xpack.security.transport.ssl:
|
||||
enabled: false
|
||||
verification_mode: certificate
|
||||
keystore.path: certs/transport.p12
|
||||
truststore.path: certs/transport.p12
|
||||
# Create a new cluster with the current node only
|
||||
# Additional nodes can still join the cluster later
|
||||
#cluster.initial_master_nodes: ["localhost"]
|
||||
|
||||
# Allow HTTP API connections from anywhere
|
||||
# Connections are encrypted and require user authentication
|
||||
#http.host: 0.0.0.0
|
||||
|
||||
# Allow other nodes to join the cluster from anywhere
|
||||
# Connections are encrypted and mutually authenticated
|
||||
#transport.host: 0.0.0.0
|
||||
|
||||
#----------------------- END SECURITY AUTO CONFIGURATION -------------------------
|
|
@ -0,0 +1,4 @@
|
|||
rpm -ivh elasticsearch-8.16.1-x86_64.rpm
|
||||
|
||||
systemctl start elasticsearch.service
|
||||
systemctl enable elasticsearch.service
|
Binary file not shown.
|
@ -0,0 +1,36 @@
|
|||
mysqldump -u root -p123456 ruoyi-vue-pro > all_tables_backup.sql
|
||||
|
||||
systemctl stop firewalld.service
|
||||
systemctl disable firewalld.service
|
||||
|
||||
一、安装mysql
|
||||
yum install mysql-server
|
||||
设置表名带小写敏感忽略
|
||||
vim /etc/my.cnf.d/mysql-server.cnf 末尾添加lower_case_table_names=1
|
||||
|
||||
systemctl start mysqld #启动MYSQL 服务
|
||||
systemctl enable mysqld #将MYSQL 服务设置为开机启动
|
||||
|
||||
mysql -uroot #新安装MYSQL 可以使用ROOT 无密码直接登录
|
||||
use mysql; #选择系统数据库
|
||||
alter user 'root'@'localhost' identified by '123456'; #将123456 替换成自己的密码
|
||||
update user set host='%' where user='root';
|
||||
flush privileges; #刷新权限表
|
||||
|
||||
|
||||
CREATE database if NOT EXISTS `ruoyi-vue-pro` default character set utf8mb4 collate utf8mb4_general_ci;
|
||||
USE `ruoyi-vue-pro`;
|
||||
|
||||
|
||||
|
||||
安装Redis
|
||||
#添加EPEL仓库
|
||||
sudo yum install epel-release
|
||||
#更新yum源
|
||||
sudo yum update
|
||||
安装
|
||||
yum install redis
|
||||
systemctl start redis
|
||||
systemctl enable redis
|
||||
vim /etc/redis/redis.conf
|
||||
systemctl restart redis
|
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
@InterceptorIgnore(tenantLine = "true")
|
||||
|
||||
ElasticSearch 命令行乱码:
|
||||
到 \config 文件下找到 jvm.options 文件 打开后 在文件末尾空白处 添加 -Dfile.encoding=GBK 保存后重启即可。
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-framework</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>yudao-spring-boot-starter-elasticsearch</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>Elasticsearch 封装拓展</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- elasticsearch 相关 -->
|
||||
<dependency>
|
||||
<groupId>co.elastic.clients</groupId>
|
||||
<artifactId>elasticsearch-java</artifactId>
|
||||
<version>8.16.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,100 @@
|
|||
package cn.iocoder.yudao.framework.elasticsearch;
|
||||
|
||||
import cn.iocoder.yudao.framework.elasticsearch.dataobject.ProductInfo;
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
|
||||
import co.elastic.clients.elasticsearch.core.*;
|
||||
import co.elastic.clients.elasticsearch.indices.Alias;
|
||||
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
|
||||
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.client.RestClientBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ClientUtil {
|
||||
|
||||
/**
|
||||
* 初始化客户端
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static ElasticsearchClient initClient() {
|
||||
String hostname = "192.168.*.*";
|
||||
int port = 9200;
|
||||
String username = "your username";
|
||||
String password = "your password";
|
||||
// 基本的用户名密码认证
|
||||
BasicCredentialsProvider basicCredentialsProvider = new BasicCredentialsProvider();
|
||||
basicCredentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
|
||||
RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(hostname, port, "http"));
|
||||
restClientBuilder.setHttpClientConfigCallback(httpAsyncClientBuilder ->
|
||||
httpAsyncClientBuilder.setDefaultCredentialsProvider(basicCredentialsProvider));
|
||||
RestClient restClient = restClientBuilder.build();
|
||||
ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
|
||||
return new ElasticsearchClient(transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建索引
|
||||
*/
|
||||
private static void createIndex() throws IOException {
|
||||
ElasticsearchClient esClient = initClient();
|
||||
CreateIndexResponse createIndexResponse = esClient.indices().create(
|
||||
new CreateIndexRequest.Builder()
|
||||
.index("product_info")
|
||||
.aliases("product_info_alias",
|
||||
new Alias.Builder().isWriteIndex(true).build()
|
||||
).build());
|
||||
if (createIndexResponse.acknowledged()) {
|
||||
System.out.println("创建索引成功!");
|
||||
} else {
|
||||
System.out.println("创建索引失败!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void addData() throws IOException {
|
||||
ElasticsearchClient esClient = initClient();
|
||||
ProductInfo productInfo = new ProductInfo("红米手机", "红米 Note,智能手机,价格便宜", "蓝色", 999);
|
||||
CreateResponse createResponse = esClient.create(createRequest -> createRequest.id("1003").index("product_info").document(productInfo));
|
||||
System.out.println("添加索引请求结果:" + createResponse.result());
|
||||
}
|
||||
|
||||
private static void delDataVidId(String id) throws IOException {
|
||||
ElasticsearchClient esClient = initClient();
|
||||
DeleteResponse deleteResponse = esClient.delete(deleteReqest -> deleteReqest.index("product_info").id(id));
|
||||
System.out.println("按照 ID 删除索引数据结果:" + deleteResponse.result());
|
||||
}
|
||||
|
||||
private static void delDataVidQuery(String value) throws IOException {
|
||||
ElasticsearchClient esClient = initClient();
|
||||
DeleteByQueryResponse deleteByQueryResponse = esClient.deleteByQuery(deleteByQuery ->
|
||||
deleteByQuery.index("product_info").query(query ->
|
||||
query.match(MatchQuery.of(builder ->
|
||||
builder.field("productName").query(value)))));
|
||||
System.out.println("按照条件删除索引数据结果:" + deleteByQueryResponse.deleted());
|
||||
}
|
||||
|
||||
private static void updateViaId(String id) throws IOException {
|
||||
ElasticsearchClient esClient = initClient();
|
||||
ProductInfo productInfo = new ProductInfo("苹果手机", "苹果智能手机,价格实惠便宜", "黑色", 5999);
|
||||
UpdateResponse<ProductInfo> updateResponse = esClient.update(updateRequest -> updateRequest.index("product_info").id(id).doc(productInfo), ProductInfo.class);
|
||||
System.out.println("根据 ID 修改:" + updateResponse.result());
|
||||
}
|
||||
|
||||
private static void query(String value) throws IOException {
|
||||
ElasticsearchClient esClient = initClient();
|
||||
SearchResponse<ProductInfo> searchResponse = esClient.search(searchRequest ->
|
||||
searchRequest.index("product_info").query(q -> q.match(MatchQuery.of(builder ->
|
||||
builder.field("productName").query(value)))), ProductInfo.class);
|
||||
searchResponse.hits().hits().forEach(productInfoHit -> System.out.println(productInfoHit));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,554 @@
|
|||
package cn.iocoder.yudao.framework.elasticsearch.core;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 关于 ElasticSearch 的一些方法(创建索引、添加数据、查询等)
|
||||
*
|
||||
* @author sunjianlei
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "elasticsearch", name = "cluster-nodes")
|
||||
public class JeecgElasticsearchTemplate {
|
||||
/**
|
||||
* es服务地址
|
||||
*/
|
||||
private String baseUrl;
|
||||
private final String FORMAT_JSON = "format=json";
|
||||
/**
|
||||
* Elasticsearch 的版本号
|
||||
*/
|
||||
private String version = null;
|
||||
|
||||
/**
|
||||
* ElasticSearch 最大可返回条目数
|
||||
*/
|
||||
public static final int ES_MAX_SIZE = 10000;
|
||||
|
||||
/**
|
||||
* es7
|
||||
*/
|
||||
public static final String IE_SEVEN = "7";
|
||||
|
||||
/**
|
||||
* url not found 404
|
||||
*/
|
||||
public static final String URL_NOT_FOUND = "404 Not Found";
|
||||
|
||||
public JeecgElasticsearchTemplate(@Value("${elasticsearch.cluster-nodes}") String baseUrl, @Value("${elasticsearch.check-enabled}") boolean checkEnabled) {
|
||||
log.debug("JeecgElasticsearchTemplate BaseURL:" + baseUrl);
|
||||
if (StringUtils.isNotEmpty(baseUrl)) {
|
||||
this.baseUrl = baseUrl;
|
||||
// 验证配置的ES地址是否有效
|
||||
if (checkEnabled) {
|
||||
try {
|
||||
this.getElasticsearchVersion();
|
||||
log.info("ElasticSearch 服务连接成功");
|
||||
log.info("ElasticSearch version: " + this.version);
|
||||
} catch (Exception e) {
|
||||
this.version = "";
|
||||
log.warn("ElasticSearch 服务连接失败,原因:配置未通过。可能是BaseURL未配置或配置有误,也可能是Elasticsearch服务未启动。接下来将会拒绝执行任何方法!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Elasticsearch 的版本号信息,失败返回null
|
||||
*/
|
||||
private void getElasticsearchVersion() {
|
||||
if (this.version == null) {
|
||||
String url = this.getBaseUrl().toString();
|
||||
JSONObject result = RestUtil.get(url);
|
||||
if (result != null) {
|
||||
JSONObject v = result.getJSONObject("version");
|
||||
this.version = v.getString("number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StringBuilder getBaseUrl(String indexName, String typeName) {
|
||||
typeName = typeName.trim().toLowerCase();
|
||||
return this.getBaseUrl(indexName).append("/").append(typeName);
|
||||
}
|
||||
|
||||
public StringBuilder getBaseUrl(String indexName) {
|
||||
indexName = indexName.trim().toLowerCase();
|
||||
return this.getBaseUrl().append("/").append(indexName);
|
||||
}
|
||||
|
||||
public StringBuilder getBaseUrl() {
|
||||
return new StringBuilder("http://").append(this.baseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* cat 查询ElasticSearch系统数据,返回json
|
||||
*/
|
||||
private <T> ResponseEntity<T> cat(String urlAfter, Class<T> responseType) {
|
||||
String url = this.getBaseUrl().append("/_cat").append(urlAfter).append("?").append(FORMAT_JSON).toString();
|
||||
return RestUtil.request(url, HttpMethod.GET, null, null, null, responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有索引
|
||||
* <p>
|
||||
* 查询地址:GET http://{baseUrl}/_cat/indices
|
||||
*/
|
||||
public JSONArray getIndices() {
|
||||
return getIndices(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询单个索引
|
||||
* <p>
|
||||
* 查询地址:GET http://{baseUrl}/_cat/indices/{indexName}
|
||||
*/
|
||||
public JSONArray getIndices(String indexName) {
|
||||
StringBuilder urlAfter = new StringBuilder("/indices");
|
||||
if (!StringUtils.isEmpty(indexName)) {
|
||||
urlAfter.append("/").append(indexName.trim().toLowerCase());
|
||||
}
|
||||
return cat(urlAfter.toString(), JSONArray.class).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 索引是否存在
|
||||
*/
|
||||
public boolean indexExists(String indexName) {
|
||||
try {
|
||||
JSONArray array = getIndices(indexName);
|
||||
return array != null;
|
||||
} catch (org.springframework.web.client.HttpClientErrorException ex) {
|
||||
if (HttpStatus.NOT_FOUND == ex.getStatusCode()) {
|
||||
return false;
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取索引数据,未查询到返回null
|
||||
* <p>
|
||||
* 查询地址:GET http://{baseUrl}/{indexName}/{typeName}/{dataId}
|
||||
*
|
||||
* @param indexName 索引名称
|
||||
* @param typeName type,一个任意字符串,用于分类
|
||||
* @param dataId 数据id
|
||||
* @return
|
||||
*/
|
||||
public JSONObject getDataById(String indexName, String typeName, String dataId) {
|
||||
String url = this.getBaseUrl(indexName, typeName).append("/").append(dataId).toString();
|
||||
log.info("url:" + url);
|
||||
JSONObject result = RestUtil.get(url);
|
||||
boolean found = result.getBoolean("found");
|
||||
if (found) {
|
||||
return result.getJSONObject("_source");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建索引
|
||||
* <p>
|
||||
* 查询地址:PUT http://{baseUrl}/{indexName}
|
||||
*/
|
||||
public boolean createIndex(String indexName) {
|
||||
String url = this.getBaseUrl(indexName).toString();
|
||||
|
||||
/* 返回结果 (仅供参考)
|
||||
"createIndex": {
|
||||
"shards_acknowledged": true,
|
||||
"acknowledged": true,
|
||||
"index": "hello_world"
|
||||
}
|
||||
*/
|
||||
try {
|
||||
return RestUtil.put(url).getBoolean("acknowledged");
|
||||
} catch (org.springframework.web.client.HttpClientErrorException ex) {
|
||||
if (HttpStatus.BAD_REQUEST == ex.getStatusCode()) {
|
||||
log.warn("索引创建失败:" + indexName + " 已存在,无需再创建");
|
||||
} else {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除索引
|
||||
* <p>
|
||||
* 查询地址:DELETE http://{baseUrl}/{indexName}
|
||||
*/
|
||||
public boolean removeIndex(String indexName) {
|
||||
String url = this.getBaseUrl(indexName).toString();
|
||||
try {
|
||||
return RestUtil.delete(url).getBoolean("acknowledged");
|
||||
} catch (org.springframework.web.client.HttpClientErrorException ex) {
|
||||
if (HttpStatus.NOT_FOUND == ex.getStatusCode()) {
|
||||
log.warn("索引删除失败:" + indexName + " 不存在,无需删除");
|
||||
} else {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取索引字段映射(可获取字段类型)
|
||||
* <p>
|
||||
*
|
||||
* @param indexName 索引名称
|
||||
* @param typeName 分类名称
|
||||
* @return
|
||||
*/
|
||||
public JSONObject getIndexMapping(String indexName, String typeName) {
|
||||
String url = this.getBaseUrl(indexName, typeName).append("/_mapping?").append(FORMAT_JSON).toString();
|
||||
// 针对 es 7.x 版本做兼容
|
||||
this.getElasticsearchVersion();
|
||||
if (StringUtils.isNotEmpty(this.version) && this.version.startsWith(IE_SEVEN)) {
|
||||
url += "&include_type_name=true";
|
||||
}
|
||||
log.info("getIndexMapping-url:" + url);
|
||||
/*
|
||||
* 参考返回JSON结构:
|
||||
*
|
||||
*{
|
||||
* // 索引名称
|
||||
* "[indexName]": {
|
||||
* "mappings": {
|
||||
* // 分类名称
|
||||
* "[typeName]": {
|
||||
* "properties": {
|
||||
* // 字段名
|
||||
* "input_number": {
|
||||
* // 字段类型
|
||||
* "type": "long"
|
||||
* },
|
||||
* "input_string": {
|
||||
* "type": "text",
|
||||
* "fields": {
|
||||
* "keyword": {
|
||||
* "type": "keyword",
|
||||
* "ignore_above": 256
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
try {
|
||||
return RestUtil.get(url);
|
||||
} catch (org.springframework.web.client.HttpClientErrorException e) {
|
||||
String message = e.getMessage();
|
||||
if (message != null && message.contains(URL_NOT_FOUND)) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取索引字段映射,返回Java实体类
|
||||
*
|
||||
* @param indexName
|
||||
* @param typeName
|
||||
* @return
|
||||
*/
|
||||
public <T> Map<String, T> getIndexMappingFormat(String indexName, String typeName, Class<T> clazz) {
|
||||
JSONObject mapping = this.getIndexMapping(indexName, typeName);
|
||||
Map<String, T> map = new HashMap<>(5);
|
||||
if (mapping == null) {
|
||||
return map;
|
||||
}
|
||||
// 获取字段属性
|
||||
JSONObject properties = mapping.getJSONObject(indexName)
|
||||
.getJSONObject("mappings")
|
||||
.getJSONObject(typeName)
|
||||
.getJSONObject("properties");
|
||||
// 封装成 java类型
|
||||
for (String key : properties.keySet()) {
|
||||
T entity = properties.getJSONObject(key).toJavaObject(clazz);
|
||||
map.put(key, entity);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据,详见:saveOrUpdate
|
||||
*/
|
||||
public boolean save(String indexName, String typeName, String dataId, JSONObject data) {
|
||||
return this.saveOrUpdate(indexName, typeName, dataId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据,详见:saveOrUpdate
|
||||
*/
|
||||
public boolean update(String indexName, String typeName, String dataId, JSONObject data) {
|
||||
return this.saveOrUpdate(indexName, typeName, dataId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存或修改索引数据
|
||||
* <p>
|
||||
* 查询地址:PUT http://{baseUrl}/{indexName}/{typeName}/{dataId}
|
||||
*
|
||||
* @param indexName 索引名称
|
||||
* @param typeName type,一个任意字符串,用于分类
|
||||
* @param dataId 数据id
|
||||
* @param data 要存储的数据
|
||||
* @return
|
||||
*/
|
||||
public boolean saveOrUpdate(String indexName, String typeName, String dataId, JSONObject data) {
|
||||
String url = this.getBaseUrl(indexName, typeName).append("/").append(dataId).append("?refresh=wait_for").toString();
|
||||
/* 返回结果(仅供参考)
|
||||
"createIndexA2": {
|
||||
"result": "created",
|
||||
"_shards": {
|
||||
"total": 2,
|
||||
"successful": 1,
|
||||
"failed": 0
|
||||
},
|
||||
"_seq_no": 0,
|
||||
"_index": "test_index_1",
|
||||
"_type": "test_type_1",
|
||||
"_id": "a2",
|
||||
"_version": 1,
|
||||
"_primary_term": 1
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
// 去掉 data 中为空的值
|
||||
Set<String> keys = data.keySet();
|
||||
List<String> emptyKeys = new ArrayList<>(keys.size());
|
||||
for (String key : keys) {
|
||||
String value = data.getString(key);
|
||||
//1、剔除空值
|
||||
if (StringUtils.isEmpty(value) || "[]".equals(value)) {
|
||||
emptyKeys.add(key);
|
||||
}
|
||||
//2、剔除上传控件值(会导致ES同步失败,报异常failed to parse field [ge_pic] of type [text] )
|
||||
if (StringUtils.isNotEmpty(value) && value.indexOf("[{") != -1) {
|
||||
emptyKeys.add(key);
|
||||
log.info("-------剔除上传控件字段------------key: " + key);
|
||||
}
|
||||
}
|
||||
for (String key : emptyKeys) {
|
||||
data.remove(key);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
String result = RestUtil.put(url, data).getString("result");
|
||||
return "created".equals(result) || "updated".equals(result);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage() + "\n-- url: " + url + "\n-- data: " + data.toJSONString());
|
||||
//TODO 打印接口返回异常json
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量保存数据
|
||||
*
|
||||
* @param indexName 索引名称
|
||||
* @param typeName type,一个任意字符串,用于分类
|
||||
* @param dataList 要存储的数据数组,每行数据必须包含id
|
||||
* @return
|
||||
*/
|
||||
public boolean saveBatch(String indexName, String typeName, JSONArray dataList) {
|
||||
String url = this.getBaseUrl().append("/_bulk").append("?refresh=wait_for").toString();
|
||||
StringBuilder bodySb = new StringBuilder();
|
||||
for (int i = 0; i < dataList.size(); i++) {
|
||||
JSONObject data = dataList.getJSONObject(i);
|
||||
String id = data.getString("id");
|
||||
// 该行的操作
|
||||
// {"create": {"_id":"${id}", "_index": "${indexName}", "_type": "${typeName}"}}
|
||||
JSONObject action = new JSONObject();
|
||||
JSONObject actionInfo = new JSONObject();
|
||||
actionInfo.put("_id", id);
|
||||
actionInfo.put("_index", indexName);
|
||||
actionInfo.put("_type", typeName);
|
||||
action.put("create", actionInfo);
|
||||
bodySb.append(action.toJSONString()).append("\n");
|
||||
// 该行的数据
|
||||
data.remove("id");
|
||||
bodySb.append(data.toJSONString()).append("\n");
|
||||
}
|
||||
System.out.println("+-+-+-: bodySb.toString(): " + bodySb.toString());
|
||||
HttpHeaders headers = RestUtil.getHeaderApplicationJson();
|
||||
RestUtil.request(url, HttpMethod.PUT, headers, null, bodySb, JSONObject.class);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除索引数据
|
||||
* <p>
|
||||
* 请求地址:DELETE http://{baseUrl}/{indexName}/{typeName}/{dataId}
|
||||
*/
|
||||
public boolean delete(String indexName, String typeName, String dataId) {
|
||||
String url = this.getBaseUrl(indexName, typeName).append("/").append(dataId).toString();
|
||||
/* 返回结果(仅供参考)
|
||||
{
|
||||
"_index": "es_demo",
|
||||
"_type": "docs",
|
||||
"_id": "001",
|
||||
"_version": 3,
|
||||
"result": "deleted",
|
||||
"_shards": {
|
||||
"total": 1,
|
||||
"successful": 1,
|
||||
"failed": 0
|
||||
},
|
||||
"_seq_no": 28,
|
||||
"_primary_term": 18
|
||||
}
|
||||
*/
|
||||
try {
|
||||
return "deleted".equals(RestUtil.delete(url).getString("result"));
|
||||
} catch (org.springframework.web.client.HttpClientErrorException ex) {
|
||||
if (HttpStatus.NOT_FOUND == ex.getStatusCode()) {
|
||||
return false;
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* = = = 以下关于查询和查询条件的方法 = = =*/
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
* <p>
|
||||
* 请求地址:POST http://{baseUrl}/{indexName}/{typeName}/_search
|
||||
*/
|
||||
public JSONObject search(String indexName, String typeName, JSONObject queryObject) {
|
||||
String url = this.getBaseUrl(indexName, typeName).append("/_search").toString();
|
||||
|
||||
log.info("url:" + url + " ,search: " + queryObject.toJSONString());
|
||||
JSONObject res = RestUtil.post(url, queryObject);
|
||||
log.info("url:" + url + " ,return res: \n" + res.toJSONString());
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source (源滤波器)指定返回的字段,传null返回所有字段
|
||||
* @param query
|
||||
* @param from 从第几条数据开始
|
||||
* @param size 返回条目数
|
||||
* @return { "query": query }
|
||||
*/
|
||||
public JSONObject buildQuery(List<String> source, JSONObject query, int from, int size) {
|
||||
JSONObject json = new JSONObject();
|
||||
if (source != null) {
|
||||
json.put("_source", source);
|
||||
}
|
||||
json.put("query", query);
|
||||
json.put("from", from);
|
||||
json.put("size", size);
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return { "bool" : { "must": must, "must_not": mustNot, "should": should } }
|
||||
*/
|
||||
public JSONObject buildBoolQuery(JSONArray must, JSONArray mustNot, JSONArray should) {
|
||||
JSONObject bool = new JSONObject();
|
||||
if (must != null) {
|
||||
bool.put("must", must);
|
||||
}
|
||||
if (mustNot != null) {
|
||||
bool.put("must_not", mustNot);
|
||||
}
|
||||
if (should != null) {
|
||||
bool.put("should", should);
|
||||
}
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("bool", bool);
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field 要查询的字段
|
||||
* @param args 查询参数,参考: *哈哈* OR *哒* NOT *呵* OR *啊*
|
||||
* @return
|
||||
*/
|
||||
public JSONObject buildQueryString(String field, String... args) {
|
||||
if (field == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(field).append(":(");
|
||||
if (args != null) {
|
||||
for (String arg : args) {
|
||||
sb.append(arg).append(" ");
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return this.buildQueryString(sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return { "query_string": { "query": query } }
|
||||
*/
|
||||
public JSONObject buildQueryString(String query) {
|
||||
JSONObject queryString = new JSONObject();
|
||||
queryString.put("query", query);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("query_string", queryString);
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param field 查询字段
|
||||
* @param min 最小值
|
||||
* @param max 最大值
|
||||
* @param containMin 范围内是否包含最小值
|
||||
* @param containMax 范围内是否包含最大值
|
||||
* @return { "range" : { field : { 『 "gt『e』?containMin" : min 』?min!=null , 『 "lt『e』?containMax" : max 』}} }
|
||||
*/
|
||||
public JSONObject buildRangeQuery(String field, Object min, Object max, boolean containMin, boolean containMax) {
|
||||
JSONObject inner = new JSONObject();
|
||||
if (min != null) {
|
||||
if (containMin) {
|
||||
inner.put("gte", min);
|
||||
} else {
|
||||
inner.put("gt", min);
|
||||
}
|
||||
}
|
||||
if (max != null) {
|
||||
if (containMax) {
|
||||
inner.put("lte", max);
|
||||
} else {
|
||||
inner.put("lt", max);
|
||||
}
|
||||
}
|
||||
JSONObject range = new JSONObject();
|
||||
range.put(field, inner);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("range", range);
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package cn.iocoder.yudao.framework.elasticsearch.core;
|
||||
|
||||
/**
|
||||
* 用于创建 ElasticSearch 的 queryString
|
||||
*
|
||||
* @author sunjianlei
|
||||
*/
|
||||
public class QueryStringBuilder {
|
||||
|
||||
StringBuilder builder;
|
||||
|
||||
public QueryStringBuilder(String field, String str, boolean not, boolean addQuot) {
|
||||
builder = this.createBuilder(field, str, not, addQuot);
|
||||
}
|
||||
|
||||
public QueryStringBuilder(String field, String str, boolean not) {
|
||||
builder = this.createBuilder(field, str, not, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 StringBuilder
|
||||
*
|
||||
* @param field
|
||||
* @param str
|
||||
* @param not 是否是不匹配
|
||||
* @param addQuot 是否添加双引号
|
||||
* @return
|
||||
*/
|
||||
public StringBuilder createBuilder(String field, String str, boolean not, boolean addQuot) {
|
||||
StringBuilder sb = new StringBuilder(field).append(":(");
|
||||
if (not) {
|
||||
sb.append(" NOT ");
|
||||
}
|
||||
this.addQuotEffect(sb, str, addQuot);
|
||||
return sb;
|
||||
}
|
||||
|
||||
public QueryStringBuilder and(String str) {
|
||||
return this.and(str, true);
|
||||
}
|
||||
|
||||
public QueryStringBuilder and(String str, boolean addQuot) {
|
||||
builder.append(" AND ");
|
||||
this.addQuot(str, addQuot);
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryStringBuilder or(String str) {
|
||||
return this.or(str, true);
|
||||
}
|
||||
|
||||
public QueryStringBuilder or(String str, boolean addQuot) {
|
||||
builder.append(" OR ");
|
||||
this.addQuot(str, addQuot);
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryStringBuilder not(String str) {
|
||||
return this.not(str, true);
|
||||
}
|
||||
|
||||
public QueryStringBuilder not(String str, boolean addQuot) {
|
||||
builder.append(" NOT ");
|
||||
this.addQuot(str, addQuot);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加双引号(模糊查询,不能加双引号)
|
||||
*/
|
||||
private QueryStringBuilder addQuot(String str, boolean addQuot) {
|
||||
return this.addQuotEffect(this.builder, str, addQuot);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在两边加上双引号
|
||||
* @param builder
|
||||
* @param str
|
||||
* @param addQuot
|
||||
* @return
|
||||
*/
|
||||
private QueryStringBuilder addQuotEffect(StringBuilder builder, String str, boolean addQuot) {
|
||||
if (addQuot) {
|
||||
builder.append('"');
|
||||
}
|
||||
builder.append(str);
|
||||
if (addQuot) {
|
||||
builder.append('"');
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return builder.append(")").toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
package cn.iocoder.yudao.framework.elasticsearch.core;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 调用 Restful 接口 Util
|
||||
*
|
||||
* @author sunjianlei
|
||||
*/
|
||||
@Slf4j
|
||||
public class RestUtil {
|
||||
|
||||
/**
|
||||
* RestAPI 调用器
|
||||
*/
|
||||
private final static RestTemplate RT;
|
||||
|
||||
static {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
requestFactory.setConnectTimeout(3000);
|
||||
requestFactory.setReadTimeout(3000);
|
||||
RT = new RestTemplate(requestFactory);
|
||||
// 解决乱码问题
|
||||
RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static RestTemplate getRestTemplate() {
|
||||
return RT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 get 请求
|
||||
*/
|
||||
public static JSONObject get(String url) {
|
||||
return getNative(url, null, null).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 get 请求
|
||||
*/
|
||||
public static JSONObject get(String url, JSONObject variables) {
|
||||
return getNative(url, variables, null).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 get 请求
|
||||
*/
|
||||
public static JSONObject get(String url, JSONObject variables, JSONObject params) {
|
||||
return getNative(url, variables, params).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 get 请求,返回原生 ResponseEntity 对象
|
||||
*/
|
||||
public static ResponseEntity<JSONObject> getNative(String url, JSONObject variables, JSONObject params) {
|
||||
return request(url, HttpMethod.GET, variables, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 Post 请求
|
||||
*/
|
||||
public static JSONObject post(String url) {
|
||||
return postNative(url, null, null).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 Post 请求
|
||||
*/
|
||||
public static JSONObject post(String url, JSONObject params) {
|
||||
return postNative(url, null, params).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 Post 请求
|
||||
*/
|
||||
public static JSONObject post(String url, JSONObject variables, JSONObject params) {
|
||||
return postNative(url, variables, params).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 POST 请求,返回原生 ResponseEntity 对象
|
||||
*/
|
||||
public static ResponseEntity<JSONObject> postNative(String url, JSONObject variables, JSONObject params) {
|
||||
return request(url, HttpMethod.POST, variables, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 put 请求
|
||||
*/
|
||||
public static JSONObject put(String url) {
|
||||
return putNative(url, null, null).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 put 请求
|
||||
*/
|
||||
public static JSONObject put(String url, JSONObject params) {
|
||||
return putNative(url, null, params).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 put 请求
|
||||
*/
|
||||
public static JSONObject put(String url, JSONObject variables, JSONObject params) {
|
||||
return putNative(url, variables, params).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 put 请求,返回原生 ResponseEntity 对象
|
||||
*/
|
||||
public static ResponseEntity<JSONObject> putNative(String url, JSONObject variables, JSONObject params) {
|
||||
return request(url, HttpMethod.PUT, variables, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 delete 请求
|
||||
*/
|
||||
public static JSONObject delete(String url) {
|
||||
return deleteNative(url, null, null).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 delete 请求
|
||||
*/
|
||||
public static JSONObject delete(String url, JSONObject variables, JSONObject params) {
|
||||
return deleteNative(url, variables, params).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 delete 请求,返回原生 ResponseEntity 对象
|
||||
*/
|
||||
public static ResponseEntity<JSONObject> deleteNative(String url, JSONObject variables, JSONObject params) {
|
||||
return request(url, HttpMethod.DELETE, null, variables, params, JSONObject.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送请求
|
||||
*/
|
||||
public static ResponseEntity<JSONObject> request(String url, HttpMethod method, JSONObject variables, JSONObject params) {
|
||||
return request(url, method, getHeaderApplicationJson(), variables, params, JSONObject.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送请求
|
||||
*
|
||||
* @param url 请求地址
|
||||
* @param method 请求方式
|
||||
* @param headers 请求头 可空
|
||||
* @param variables 请求url参数 可空
|
||||
* @param params 请求body参数 可空
|
||||
* @param responseType 返回类型
|
||||
* @return ResponseEntity<responseType>
|
||||
*/
|
||||
public static <T> ResponseEntity<T> request(String url, HttpMethod method, HttpHeaders headers, JSONObject variables, Object params, Class<T> responseType) {
|
||||
log.info(" RestUtil --- request --- url = "+ url);
|
||||
if (StringUtils.isEmpty(url)) {
|
||||
throw new RuntimeException("url 不能为空");
|
||||
}
|
||||
if (method == null) {
|
||||
throw new RuntimeException("method 不能为空");
|
||||
}
|
||||
if (headers == null) {
|
||||
headers = new HttpHeaders();
|
||||
}
|
||||
// 请求体
|
||||
String body = "";
|
||||
if (params != null) {
|
||||
if (params instanceof JSONObject) {
|
||||
body = ((JSONObject) params).toJSONString();
|
||||
|
||||
} else {
|
||||
body = params.toString();
|
||||
}
|
||||
}
|
||||
// 拼接 url 参数
|
||||
if (variables != null && !variables.isEmpty()) {
|
||||
url += ("?" + asUrlVariables(variables));
|
||||
}
|
||||
// 发送请求
|
||||
HttpEntity<String> request = new HttpEntity<>(body, headers);
|
||||
return RT.exchange(url, method, request, responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取JSON请求头
|
||||
*/
|
||||
public static HttpHeaders getHeaderApplicationJson() {
|
||||
return getHeader(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求头
|
||||
*/
|
||||
public static HttpHeaders getHeader(String mediaType) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.parseMediaType(mediaType));
|
||||
headers.add("Accept", mediaType);
|
||||
return headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 JSONObject 转为 a=1&b=2&c=3...&n=n 的形式
|
||||
*/
|
||||
public static String asUrlVariables(JSONObject variables) {
|
||||
Map<String, Object> source = variables.getInnerMap();
|
||||
Iterator<String> it = source.keySet().iterator();
|
||||
StringBuilder urlVariables = new StringBuilder();
|
||||
while (it.hasNext()) {
|
||||
String key = it.next();
|
||||
String value = "";
|
||||
Object object = source.get(key);
|
||||
if (object != null) {
|
||||
if (!StringUtils.isEmpty(object.toString())) {
|
||||
value = object.toString();
|
||||
}
|
||||
}
|
||||
urlVariables.append("&").append(key).append("=").append(value);
|
||||
}
|
||||
// 去掉第一个&
|
||||
return urlVariables.substring(1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package cn.iocoder.yudao.framework.elasticsearch.dataobject;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ProductInfo {
|
||||
private String productName;
|
||||
private String productDescription;
|
||||
private String color;
|
||||
private Integer price;
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* 采用 Spring Data Redis 操作 Redis,底层使用 Redisson 作为客户端
|
||||
*/
|
||||
package cn.iocoder.yudao.framework.elasticsearch;
|
|
@ -0,0 +1,2 @@
|
|||
cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration
|
||||
cn.iocoder.yudao.framework.redis.config.YudaoCacheAutoConfiguration
|
|
@ -71,5 +71,12 @@ public class ProductCategoryController {
|
|||
list.sort(Comparator.comparing(ProductCategoryDO::getSort));
|
||||
return success(BeanUtils.toBean(list, ProductCategoryRespVO.class));
|
||||
}
|
||||
@GetMapping("/init")
|
||||
@Operation(summary = "获得商品分类列表")
|
||||
@PreAuthorize("@ss.hasPermission('product:category:query')")
|
||||
public CommonResult<Boolean> initCategoryList() {
|
||||
categoryService.initCategory();
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,12 @@ public interface ProductCategoryService {
|
|||
*/
|
||||
void updateCategory(@Valid ProductCategorySaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 构造商品分类
|
||||
*
|
||||
*/
|
||||
void initCategory();
|
||||
|
||||
/**
|
||||
* 删除商品分类
|
||||
*
|
||||
|
|
|
@ -14,10 +14,10 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO.CATEGORY_LEVEL;
|
||||
|
@ -63,6 +63,75 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
|
|||
productCategoryMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initCategory() {
|
||||
List<String> firstCateNames = new ArrayList<>();
|
||||
Map<String, Long> firstCateNamesIds = new HashMap<>();
|
||||
List<String> secondCateNames = new ArrayList<>();
|
||||
Map<String, Long> secondCateNamesIds = new HashMap<>();
|
||||
Map<String, Integer> secondCateNamesIndexs = new HashMap<>();
|
||||
Map<String, Integer> thirdCateIndexs = new HashMap<>();
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\D\\Desktop\\商品分类.txt"));
|
||||
String line;
|
||||
String firstCateName = "";
|
||||
String highlight = "";
|
||||
String secondCateName = "";
|
||||
String thirdCateName = "";
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains("firstCateName")) {
|
||||
firstCateName = line.split(":")[1].replace("\"", "").replace(",", "");
|
||||
if (!firstCateNames.contains(firstCateName) && !firstCateName.contains("天猫榜单") && !firstCateName.contains("热卖频道")) {
|
||||
ProductCategoryDO category = new ProductCategoryDO();
|
||||
category.setName(firstCateName);
|
||||
category.setParentId(0L);
|
||||
category.setSort(firstCateNames.size() + 1);
|
||||
productCategoryMapper.insert(category);
|
||||
firstCateNamesIds.put(firstCateName, category.getId());
|
||||
firstCateNames.add(firstCateName);
|
||||
secondCateNamesIndexs.put(firstCateName, 1);
|
||||
}
|
||||
}
|
||||
if (line.contains("highlight")) {
|
||||
highlight = line.split(":")[1].replace("\"", "").replace(",", "");
|
||||
}
|
||||
if (line.contains("secondCateName")) {
|
||||
secondCateName = line.split(":")[1].replace("\"", "").replace(",", "");
|
||||
|
||||
if (!secondCateNames.contains(secondCateName) && !secondCateName.contains("天猫榜单") && !secondCateName.contains("热卖频道")) {
|
||||
int sort = secondCateNamesIndexs.get(firstCateName) + 1;
|
||||
secondCateNamesIndexs.put(firstCateName, sort + 1);
|
||||
ProductCategoryDO category = new ProductCategoryDO();
|
||||
category.setName(secondCateName);
|
||||
category.setParentId(firstCateNamesIds.get(firstCateName));
|
||||
category.setSort(sort + 1);
|
||||
productCategoryMapper.insert(category);
|
||||
secondCateNamesIds.put(firstCateName + "_" + secondCateName, category.getId());
|
||||
secondCateNames.add(secondCateName);
|
||||
|
||||
thirdCateIndexs.put(firstCateName + "_" + secondCateName, 1);
|
||||
System.out.println(",secondCateName:" + secondCateName);
|
||||
}
|
||||
}
|
||||
if (line.contains("thirdCateName") && !highlight.contains("true") && !secondCateName.contains("天猫榜单") && !secondCateName.contains("热卖频道")) {
|
||||
thirdCateName = line.split(":")[1].replace("\"", "").replace(",", "");
|
||||
System.out.println("firstCateName:" + firstCateName + ",secondCateName:" + secondCateName + ",thirdCateName:" + thirdCateName);
|
||||
int sort = thirdCateIndexs.get(firstCateName + "_" + secondCateName) + 1;
|
||||
thirdCateIndexs.put(firstCateName + "_" + secondCateName, sort + 1);
|
||||
|
||||
ProductCategoryDO category = new ProductCategoryDO();
|
||||
category.setName(thirdCateName);
|
||||
category.setParentId(secondCateNamesIds.get(firstCateName + "_" + secondCateName));
|
||||
category.setSort(sort + 1);
|
||||
productCategoryMapper.insert(category);
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteCategory(Long id) {
|
||||
// 校验分类是否存在
|
||||
|
|
|
@ -44,8 +44,8 @@ public class TenantController {
|
|||
@Operation(summary = "使用租户名,获得租户编号", description = "登录界面,根据用户的租户名,获得租户编号")
|
||||
@Parameter(name = "name", description = "租户名", required = true, example = "1024")
|
||||
public CommonResult<Long> getTenantIdByName(@RequestParam("name") String name) {
|
||||
TenantDO tenant = tenantService.getTenantByName(name);
|
||||
return success(tenant != null ? tenant.getId() : null);
|
||||
Long tenantId = tenantService.getTenantByUserName(name);
|
||||
return success(tenantId);
|
||||
}
|
||||
|
||||
@GetMapping({ "simple-list" })
|
||||
|
|
|
@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "管理后台 - 租户 Response VO")
|
||||
@Data
|
||||
|
@ -40,7 +41,7 @@ public class TenantRespVO {
|
|||
private String website;
|
||||
|
||||
@Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long packageId;
|
||||
private Set<Long> packageId;
|
||||
|
||||
@Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime expireTime;
|
||||
|
|
|
@ -11,6 +11,7 @@ import javax.validation.constraints.NotNull;
|
|||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "管理后台 - 租户创建/修改 Request VO")
|
||||
@Data
|
||||
|
@ -39,7 +40,7 @@ public class TenantSaveReqVO {
|
|||
|
||||
@Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "租户套餐编号不能为空")
|
||||
private Long packageId;
|
||||
private Set<Long> packageId;
|
||||
|
||||
@Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "过期时间不能为空")
|
||||
|
|
|
@ -5,10 +5,13 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
|||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 租户 DO
|
||||
|
@ -39,6 +42,32 @@ public class TenantDO extends BaseDO {
|
|||
* 租户名,唯一
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 门头
|
||||
*/
|
||||
private String doorHeaderImage;
|
||||
/**
|
||||
* 类型
|
||||
* <p>
|
||||
* 枚举 {@link TODO convenience_store_type 对应的类}
|
||||
*/
|
||||
private String storeType;
|
||||
/**
|
||||
* 省市区
|
||||
*/
|
||||
private Integer areaId;
|
||||
/**
|
||||
* 营业执照
|
||||
*/
|
||||
private String businessLicence;
|
||||
/**
|
||||
* 审批状态
|
||||
*/
|
||||
private Integer approveStatus;
|
||||
/**
|
||||
* 审批备注
|
||||
*/
|
||||
private String approveRemark;
|
||||
/**
|
||||
* 联系人的用户编号
|
||||
*
|
||||
|
@ -69,7 +98,8 @@ public class TenantDO extends BaseDO {
|
|||
* 关联 {@link TenantPackageDO#getId()}
|
||||
* 特殊逻辑:系统内置租户,不使用套餐,暂时使用 {@link #PACKAGE_ID_SYSTEM} 标识
|
||||
*/
|
||||
private Long packageId;
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Set<Long> packageId;
|
||||
/**
|
||||
* 过期时间
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
|
|||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 租户套餐 Service 接口
|
||||
|
@ -59,7 +60,7 @@ public interface TenantPackageService {
|
|||
* @param id 编号
|
||||
* @return 租户套餐
|
||||
*/
|
||||
TenantPackageDO validTenantPackage(Long id);
|
||||
List<TenantPackageDO> validTenantPackage(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得指定状态的租户套餐列表
|
||||
|
|
|
@ -17,7 +17,9 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
|
@ -101,7 +103,9 @@ public class TenantPackageServiceImpl implements TenantPackageService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TenantPackageDO validTenantPackage(Long id) {
|
||||
public List<TenantPackageDO> validTenantPackage(Set<Long> ids) {
|
||||
List<TenantPackageDO> tenantPackageDOS = new ArrayList<>();
|
||||
for(Long id :ids){
|
||||
TenantPackageDO tenantPackage = tenantPackageMapper.selectById(id);
|
||||
if (tenantPackage == null) {
|
||||
throw exception(TENANT_PACKAGE_NOT_EXISTS);
|
||||
|
@ -109,7 +113,9 @@ public class TenantPackageServiceImpl implements TenantPackageService {
|
|||
if (tenantPackage.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) {
|
||||
throw exception(TENANT_PACKAGE_DISABLE, tenantPackage.getName());
|
||||
}
|
||||
return tenantPackage;
|
||||
tenantPackageDOS.add(tenantPackage);
|
||||
}
|
||||
return tenantPackageDOS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -73,6 +73,14 @@ public interface TenantService {
|
|||
*/
|
||||
TenantDO getTenantByName(String name);
|
||||
|
||||
/**
|
||||
* 获得名字对应的租户
|
||||
*
|
||||
* @param userName 租户名
|
||||
* @return 租户
|
||||
*/
|
||||
Long getTenantByUserName(String userName);
|
||||
|
||||
/**
|
||||
* 获得域名对应的租户
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
|||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
|
||||
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
|
||||
|
@ -38,6 +39,7 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -104,7 +106,7 @@ public class TenantServiceImpl implements TenantService {
|
|||
// 校验租户域名是否重复
|
||||
validTenantWebsiteDuplicate(createReqVO.getWebsite(), null);
|
||||
// 校验套餐被禁用
|
||||
TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId());
|
||||
List<TenantPackageDO> tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId());
|
||||
|
||||
// 创建租户
|
||||
TenantDO tenant = BeanUtils.toBean(createReqVO, TenantDO.class);
|
||||
|
@ -129,14 +131,16 @@ public class TenantServiceImpl implements TenantService {
|
|||
return userId;
|
||||
}
|
||||
|
||||
private Long createRole(TenantPackageDO tenantPackage) {
|
||||
private Long createRole(List<TenantPackageDO> tenantPackage) {
|
||||
// 创建角色
|
||||
RoleSaveReqVO reqVO = new RoleSaveReqVO();
|
||||
reqVO.setName(RoleCodeEnum.TENANT_ADMIN.getName()).setCode(RoleCodeEnum.TENANT_ADMIN.getCode())
|
||||
.setSort(0).setRemark("系统自动生成");
|
||||
Long roleId = roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType());
|
||||
// 分配权限
|
||||
permissionService.assignRoleMenu(roleId, tenantPackage.getMenuIds());
|
||||
for(TenantPackageDO tenantPackageDO : tenantPackage){
|
||||
permissionService.assignRoleMenu(roleId, tenantPackageDO.getMenuIds());
|
||||
}
|
||||
return roleId;
|
||||
}
|
||||
|
||||
|
@ -150,14 +154,18 @@ public class TenantServiceImpl implements TenantService {
|
|||
// 校验租户域名是否重复
|
||||
validTenantWebsiteDuplicate(updateReqVO.getWebsite(), updateReqVO.getId());
|
||||
// 校验套餐被禁用
|
||||
TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId());
|
||||
List<TenantPackageDO> tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId());
|
||||
Set<Long> newMenuIds = new HashSet<>();
|
||||
for(TenantPackageDO tenantPackageDO : tenantPackage){
|
||||
newMenuIds.addAll(tenantPackageDO.getMenuIds());
|
||||
}
|
||||
|
||||
// 更新租户
|
||||
TenantDO updateObj = BeanUtils.toBean(updateReqVO, TenantDO.class);
|
||||
tenantMapper.updateById(updateObj);
|
||||
// 如果套餐发生变化,则修改其角色的权限
|
||||
if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) {
|
||||
updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds());
|
||||
updateTenantRoleMenu(tenant.getId(), newMenuIds);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,6 +260,12 @@ public class TenantServiceImpl implements TenantService {
|
|||
return tenantMapper.selectByName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTenantByUserName(String userName) {
|
||||
AdminUserDO userDO = userService.getUserByUsername(userName);
|
||||
return userDO != null ? userDO.getTenantId() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TenantDO getTenantByWebsite(String website) {
|
||||
return tenantMapper.selectByWebsite(website);
|
||||
|
@ -292,18 +306,21 @@ public class TenantServiceImpl implements TenantService {
|
|||
}
|
||||
// 获得租户,然后获得菜单
|
||||
TenantDO tenant = getTenant(TenantContextHolder.getRequiredTenantId());
|
||||
Set<Long> menuIds;
|
||||
Set<Long> menuIds = new HashSet<>();
|
||||
if (isSystemTenant(tenant)) { // 系统租户,菜单是全量的
|
||||
menuIds = CollectionUtils.convertSet(menuService.getMenuList(), MenuDO::getId);
|
||||
} else {
|
||||
menuIds = tenantPackageService.getTenantPackage(tenant.getPackageId()).getMenuIds();
|
||||
for(Long packageId : tenant.getPackageId()){
|
||||
Set<Long> tempMenuIds = tenantPackageService.getTenantPackage(packageId).getMenuIds();
|
||||
menuIds.addAll(tempMenuIds);
|
||||
}
|
||||
}
|
||||
// 执行处理器
|
||||
handler.handle(menuIds);
|
||||
}
|
||||
|
||||
private static boolean isSystemTenant(TenantDO tenant) {
|
||||
return Objects.equals(tenant.getPackageId(), TenantDO.PACKAGE_ID_SYSTEM);
|
||||
return tenant.getPackageId().contains(TenantDO.PACKAGE_ID_SYSTEM);
|
||||
}
|
||||
|
||||
private boolean isTenantDisable() {
|
||||
|
|
|
@ -33,73 +33,73 @@
|
|||
</dependency>
|
||||
|
||||
<!-- 会员中心。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-member</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-member</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据报表。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-report</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-report</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- 工作流。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-bpm</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-bpm</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- 支付服务。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-pay</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-pay</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 微信公众号模块。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-mp</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-mp</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 商城相关模块。默认注释,保证编译速度-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-product</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-promotion</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-trade</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-statistics</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-product</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-promotion</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-trade</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-statistics</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- CRM 相关模块。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-crm</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-crm</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ERP 相关模块。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-erp</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-erp</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- AI 大模型相关模块。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
|
|
|
@ -3,6 +3,7 @@ server:
|
|||
|
||||
--- #################### 数据库相关配置 ####################
|
||||
spring:
|
||||
# 数据源配置项
|
||||
autoconfigure:
|
||||
# noinspection SpringBootApplicationYaml
|
||||
exclude:
|
||||
|
@ -11,8 +12,8 @@ spring:
|
|||
- de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置
|
||||
- de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置
|
||||
- de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置
|
||||
- org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
|
||||
- org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
|
||||
# - org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
|
||||
# - org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
|
||||
# 数据源配置项
|
||||
datasource:
|
||||
druid: # Druid 【监控】相关的全局配置
|
||||
|
@ -49,7 +50,7 @@ spring:
|
|||
primary: master
|
||||
datasource:
|
||||
master:
|
||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
|
||||
url: jdbc:mysql://192.168.248.128:3306/new-ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
|
||||
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例
|
||||
# url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
|
||||
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
|
||||
|
@ -65,25 +66,25 @@ spring:
|
|||
# password: SYSDBA001 # DM 连接的示例
|
||||
# username: root # OpenGauss 连接的示例
|
||||
# password: Yudao@2024 # OpenGauss 连接的示例
|
||||
slave: # 模拟从库,可根据自己需要修改
|
||||
lazy: true # 开启懒加载,保证启动速度
|
||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
|
||||
username: root
|
||||
password: 123456
|
||||
# tdengine: # IoT 数据库(需要 IoT 物联网再开启噢!)
|
||||
# url: jdbc:TAOS-RS://127.0.0.1:6041/ruoyi_vue_pro
|
||||
# driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
|
||||
# username: root
|
||||
# password: taosdata
|
||||
# druid:
|
||||
# validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL
|
||||
# slave: # 模拟从库,可根据自己需要修改
|
||||
# lazy: true # 开启懒加载,保证启动速度
|
||||
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
|
||||
# username: root
|
||||
# password: 123456
|
||||
# tdengine: # IoT 数据库(需要 IoT 物联网再开启噢!)
|
||||
# url: jdbc:TAOS-RS://127.0.0.1:6041/ruoyi_vue_pro
|
||||
# driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
|
||||
# username: root
|
||||
# password: taosdata
|
||||
# druid:
|
||||
# validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL
|
||||
|
||||
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
|
||||
redis:
|
||||
host: 127.0.0.1 # 地址
|
||||
host: 192.168.248.128 # 地址
|
||||
port: 6379 # 端口
|
||||
database: 0 # 数据库索引
|
||||
# password: dev # 密码,建议生产环境开启
|
||||
password: 123456 # 密码,建议生产环境开启
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
|
@ -162,6 +163,11 @@ spring:
|
|||
# Spring Boot Admin Server 服务端的相关配置
|
||||
context-path: /admin # 配置 Spring
|
||||
|
||||
# MyBatis Plus 的配置项
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
# 日志文件配置
|
||||
logging:
|
||||
file:
|
||||
|
@ -194,10 +200,10 @@ debug: false
|
|||
--- #################### 微信公众号、小程序相关配置 ####################
|
||||
wx:
|
||||
mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档
|
||||
# app-id: wx041349c6f39b268b # 测试号(牛希尧提供的)
|
||||
# secret: 5abee519483bc9f8cb37ce280e814bd0
|
||||
# app-id: wx5b23ba7a5589ecbb # 测试号(自己的)
|
||||
# secret: 2a7b3b20c537e52e74afd395eb85f61f
|
||||
# app-id: wx041349c6f39b268b # 测试号(牛希尧提供的)
|
||||
# secret: 5abee519483bc9f8cb37ce280e814bd0
|
||||
# app-id: wx5b23ba7a5589ecbb # 测试号(自己的)
|
||||
# secret: 2a7b3b20c537e52e74afd395eb85f61f
|
||||
app-id: wxf56b1542b9e85f8a # 测试号(Kongdy 提供的)
|
||||
secret: 496379dcef1ba869e9234de8d598cfd3
|
||||
# 存储配置,解决 AccessToken 的跨节点的共享
|
||||
|
@ -208,12 +214,12 @@ wx:
|
|||
miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档
|
||||
# appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的)
|
||||
# secret: 333ae72f41552af1e998fe1f54e1584a
|
||||
# appid: wx63c280fe3248a3e7 # wenhualian的接口测试号
|
||||
# secret: 6f270509224a7ae1296bbf1c8cb97aed
|
||||
# appid: wx63c280fe3248a3e7 # wenhualian的接口测试号
|
||||
# secret: 6f270509224a7ae1296bbf1c8cb97aed
|
||||
appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的)
|
||||
secret: 4a1a04e07f6a4a0751b39c3064a92c8b
|
||||
# appid: wx66186af0759f47c9 # 测试号(puhui 提供的)
|
||||
# secret: 3218bcbd112cbc614c7264ceb20144ac
|
||||
# appid: wx66186af0759f47c9 # 测试号(puhui 提供的)
|
||||
# secret: 3218bcbd112cbc614c7264ceb20144ac
|
||||
config-storage:
|
||||
type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取
|
||||
key-prefix: wa # Redis Key 的前缀
|
||||
|
@ -269,5 +275,5 @@ justauth:
|
|||
|
||||
--- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 ####################
|
||||
pf4j:
|
||||
# pluginsDir: /tmp/
|
||||
# pluginsDir: /tmp/
|
||||
pluginsDir: ../plugins
|
|
@ -69,10 +69,10 @@ mybatis-plus:
|
|||
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
|
||||
# id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库
|
||||
# id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
|
||||
# id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解
|
||||
id-type: ASSIGN_ID # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
|
||||
# id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库
|
||||
# id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
|
||||
# id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解
|
||||
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
|
||||
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
|
||||
banner: false # 关闭控制台的 Banner 打印
|
||||
|
|
Loading…
Reference in New Issue