提交 a6844100 编写于 作者: zlt2000's avatar zlt2000

update to v2.0.0,新增搜索中心,并集成用户中心和日志中心;首页新增流量统计

上级 5d4c30df
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
- 服务限流(url/方法级别) - 服务限流(url/方法级别)
- 统一配置中心 - 统一配置中心
- 统一日志中心 - 统一日志中心
- 统一搜索中心
- 统一分布式缓存操作类、cacheManager配置扩展 - 统一分布式缓存操作类、cacheManager配置扩展
- 分布式锁 - 分布式锁
- 分布式任务调度器 - 分布式任务调度器
...@@ -134,6 +135,10 @@ central-platform -- 父项目,公共依赖 ...@@ -134,6 +135,10 @@ central-platform -- 父项目,公共依赖
## 5. 截图(点击可大图预览) ## 5. 截图(点击可大图预览)
<table> <table>
<tr>
<td><img src="https://gitee.com/zlt2000/images/raw/master/首页.png"/></td>
<td><img src="https://gitee.com/zlt2000/images/raw/master/用户搜索.png"/></td>
</tr>
<tr> <tr>
<td><img src="https://gitee.com/zlt2000/images/raw/master/server_metrics.png"/></td> <td><img src="https://gitee.com/zlt2000/images/raw/master/server_metrics.png"/></td>
<td><img src="https://gitee.com/zlt2000/images/raw/master/application_metrics.png"/></td> <td><img src="https://gitee.com/zlt2000/images/raw/master/application_metrics.png"/></td>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
<redisson.version>3.9.1</redisson.version> <redisson.version>3.9.1</redisson.version>
<kaptcha.version>0.0.9</kaptcha.version> <kaptcha.version>0.0.9</kaptcha.version>
<hutool.version>4.3.1</hutool.version> <hutool.version>4.3.1</hutool.version>
<mybatis-plus-boot-starter.version>3.0.6</mybatis-plus-boot-starter.version> <mybatis-plus-boot-starter.version>3.1.1</mybatis-plus-boot-starter.version>
<aliyun-sdk-oss>3.4.2</aliyun-sdk-oss> <aliyun-sdk-oss>3.4.2</aliyun-sdk-oss>
<qiniu-java-sdk>7.2.18</qiniu-java-sdk> <qiniu-java-sdk>7.2.18</qiniu-java-sdk>
<easypoi.version>4.0.0</easypoi.version> <easypoi.version>4.0.0</easypoi.version>
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
<commons-configuration.version>1.10</commons-configuration.version> <commons-configuration.version>1.10</commons-configuration.version>
<txlcn.version>5.0.2.RELEASE</txlcn.version> <txlcn.version>5.0.2.RELEASE</txlcn.version>
<fastdfs-client.version>1.26.5</fastdfs-client.version> <fastdfs-client.version>1.26.5</fastdfs-client.version>
<userAgent.version>1.21</userAgent.version>
<platform-bom>Cairo-SR3</platform-bom> <platform-bom>Cairo-SR3</platform-bom>
<spring-cloud-alibaba-dependencies.version>0.2.2.RELEASE</spring-cloud-alibaba-dependencies.version> <spring-cloud-alibaba-dependencies.version>0.2.2.RELEASE</spring-cloud-alibaba-dependencies.version>
<spring-boot-dependencies.version>2.0.9.RELEASE</spring-boot-dependencies.version> <spring-boot-dependencies.version>2.0.9.RELEASE</spring-boot-dependencies.version>
...@@ -291,6 +292,16 @@ ...@@ -291,6 +292,16 @@
<artifactId>fastdfs-client</artifactId> <artifactId>fastdfs-client</artifactId>
<version>${fastdfs-client.version}</version> <version>${fastdfs-client.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>search-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>${userAgent.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
...@@ -385,4 +396,18 @@ ...@@ -385,4 +396,18 @@
<!-- demo --> <!-- demo -->
<module>zlt-demo</module> <module>zlt-demo</module>
</modules> </modules>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<name>LeTao Zhu</name>
<email>zltdiablo@163.com</email>
</developer>
</developers>
</project> </project>
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-business</artifactId> <artifactId>zlt-business</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>code-generator</artifactId> <artifactId>code-generator</artifactId>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-business</artifactId> <artifactId>zlt-business</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>file-center</artifactId> <artifactId>file-center</artifactId>
<description>文件中心</description> <description>文件中心</description>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-business</artifactId> <artifactId>zlt-business</artifactId>
<description>业务中心</description> <description>业务中心</description>
...@@ -16,5 +16,7 @@ ...@@ -16,5 +16,7 @@
<module>file-center</module> <module>file-center</module>
<!-- 代码生成器 --> <!-- 代码生成器 -->
<module>code-generator</module> <module>code-generator</module>
<!-- 搜索中心 -->
<module>search-center</module>
</modules> </modules>
</project> </project>
\ No newline at end of file
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zlt</groupId>
<artifactId>zlt-business</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>search-center</artifactId>
<description>搜索中心</description>
<packaging>pom</packaging>
<modules>
<!-- 客户端sdk -->
<module>search-client</module>
<!-- 服务端 -->
<module>search-server</module>
</modules>
</project>
\ No newline at end of file
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zlt</groupId>
<artifactId>search-center</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>search-client</artifactId>
<description>搜索中心客户端</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-ribbon-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-sentinel-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.central.search.annotation;
import com.central.search.client.service.impl.QueryServiceImpl;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 控制是否加载搜索中心客户端的Service
*
* @author zlt
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableFeignClients
@Import(QueryServiceImpl.class)
public @interface EnableSearchClient {
}
package com.central.search.client.feign;
import com.central.common.constant.ServiceNameConstants;
import com.central.search.client.feign.fallback.SearchServiceFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.Map;
/**
* @author zlt
*/
@FeignClient(name = ServiceNameConstants.SEARCH_SERVICE, fallbackFactory = SearchServiceFallbackFactory.class, decode404 = true)
public interface AggregationService {
/**
* 查询文档列表
* @param indexName 索引名
* @param routing es的路由
*/
@GetMapping(value = "/agg/requestStat/{indexName}/{routing}")
Map<String, Object> requestStatAgg(@PathVariable("indexName") String indexName, @PathVariable("routing") String routing);
}
package com.central.search.client.feign;
import com.alibaba.fastjson.JSONObject;
import com.central.common.constant.ServiceNameConstants;
import com.central.common.model.PageResult;
import com.central.search.client.feign.fallback.SearchServiceFallbackFactory;
import com.central.search.model.SearchDto;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
/**
* @author zlt
*/
@FeignClient(name = ServiceNameConstants.SEARCH_SERVICE, fallbackFactory = SearchServiceFallbackFactory.class, decode404 = true)
public interface SearchService {
/**
* 查询文档列表
* @param indexName 索引名
* @param searchDto 搜索Dto
*/
@PostMapping(value = "/search/{indexName}")
PageResult<JSONObject> strQuery(@PathVariable("indexName") String indexName, @RequestBody SearchDto searchDto);
}
package com.central.search.client.feign.fallback;
import cn.hutool.core.map.MapUtil;
import com.central.search.client.feign.AggregationService;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* searchService降级工场
*
* @author zlt
*/
@Slf4j
@Component
public class AggregationServiceFallbackFactory implements FallbackFactory<AggregationService> {
@Override
public AggregationService create(Throwable throwable) {
return (indexName, routing) -> {
log.error("通过索引{}搜索异常:{}", indexName, throwable);
return MapUtil.newHashMap(0);
};
}
}
package com.central.search.client.feign.fallback;
import com.alibaba.fastjson.JSONObject;
import com.central.common.model.PageResult;
import com.central.search.client.feign.SearchService;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* searchService降级工场
*
* @author zlt
*/
@Slf4j
@Component
public class SearchServiceFallbackFactory implements FallbackFactory<SearchService> {
@Override
public SearchService create(Throwable throwable) {
return (indexName, searchDto) -> {
log.error("通过索引{}搜索异常:{}", indexName, throwable);
return PageResult.<JSONObject>builder().build();
};
}
}
package com.central.search.client.service;
import com.alibaba.fastjson.JSONObject;
import com.central.common.model.PageResult;
import com.central.search.model.LogicDelDto;
import com.central.search.model.SearchDto;
import java.util.Map;
/**
* 搜索客户端接口
*
* @author zlt
* @date 2019/4/24
*/
public interface IQueryService {
/**
* 查询文档列表
* @param indexName 索引名
* @param searchDto 搜索Dto
*/
PageResult<JSONObject> strQuery(String indexName, SearchDto searchDto);
/**
* 查询文档列表
* @param indexName 索引名
* @param searchDto 搜索Dto
* @param logicDelDto 逻辑删除Dto
*/
PageResult<JSONObject> strQuery(String indexName, SearchDto searchDto, LogicDelDto logicDelDto);
/**
* 访问统计聚合查询
* @param indexName 索引名
* @param routing es的路由
*/
Map<String, Object> requestStatAgg(String indexName, String routing);
}
package com.central.search.client.service.impl;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.central.common.model.PageResult;
import com.central.search.client.feign.AggregationService;
import com.central.search.client.feign.SearchService;
import com.central.search.client.service.IQueryService;
import com.central.search.model.LogicDelDto;
import com.central.search.model.SearchDto;
import javax.annotation.Resource;
import java.util.Map;
/**
* 搜索客户端Service
*
* @author zlt
* @date 2019/4/24
*/
public class QueryServiceImpl implements IQueryService {
@Resource
private SearchService searchService;
@Resource
private AggregationService aggregationService;
@Override
public PageResult<JSONObject> strQuery(String indexName, SearchDto searchDto) {
return strQuery(indexName, searchDto, null);
}
@Override
public PageResult<JSONObject> strQuery(String indexName, SearchDto searchDto, LogicDelDto logicDelDto) {
setLogicDelQueryStr(searchDto, logicDelDto);
return searchService.strQuery(indexName, searchDto);
}
/**
* 拼装逻辑删除的条件
* @param searchDto 搜索dto
* @param logicDelDto 逻辑删除dto
*/
private void setLogicDelQueryStr(SearchDto searchDto, LogicDelDto logicDelDto) {
if (logicDelDto != null
&& StrUtil.isNotEmpty(logicDelDto.getLogicDelField())
&& StrUtil.isNotEmpty(logicDelDto.getLogicNotDelValue())) {
String result;
//搜索条件
String queryStr = searchDto.getQueryStr();
//拼凑逻辑删除的条件
String logicStr = logicDelDto.getLogicDelField() + ":" + logicDelDto.getLogicNotDelValue();
if (StrUtil.isNotEmpty(queryStr)) {
result = "(" + queryStr + ") AND " + logicStr;
} else {
result = logicStr;
}
searchDto.setQueryStr(result);
}
}
/**
* 访问统计聚合查询
* @param indexName 索引名
* @param routing es的路由
*/
@Override
public Map<String, Object> requestStatAgg(String indexName, String routing) {
return aggregationService.requestStatAgg(indexName, routing);
}
}
package com.central.search.model;
import lombok.Getter;
import lombok.Setter;
/**
* 聚合Item
*
* @author zlt
*/
@Setter
@Getter
public class AggItemVo {
private String name;
private Long value;
}
\ No newline at end of file
package com.central.search.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
/**
* 逻辑删除条件对象
*
* @author zlt
* @date 2019/4/25
*/
@Setter
@Getter
@AllArgsConstructor
public class LogicDelDto {
/**
* 逻辑删除字段名
*/
private String logicDelField;
/**
* 逻辑删除字段未删除的值
*/
private String logicNotDelValue;
}
package com.central.search.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* @author zlt
* @date 2019/4/24
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class SearchDto implements Serializable {
private static final long serialVersionUID = -2084416068307485742L;
/**
* 搜索关键字
*/
private String queryStr;
/**
* 当前页数
*/
private Integer page;
/**
* 每页显示数
*/
private Integer limit;
/**
* 排序字段
*/
private String sortCol;
/**
* 是否显示高亮
*/
private Boolean isHighlighter;
/**
* es的路由
*/
private String routing;
}
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zlt</groupId>
<artifactId>search-center</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>search-server</artifactId>
<description>搜索中心服务端</description>
<dependencies>
<!-- 公共实体类模块 -->
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-config</artifactId>
</dependency>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>search-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
</dependency>
<!-- swagger -->
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-swagger2-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<imageName>${docker.image.prefix}/${project.artifactId}</imageName>
<imageTags>
<imageTag>${project.version}</imageTag>
<imageTag>latest</imageTag>
</imageTags>
<forceTags>true</forceTags>
<baseImage>${docker.baseImage}</baseImage>
<volumes>${docker.volumes}</volumes>
<env>
<JAVA_OPTS>${docker.java.opts}</JAVA_OPTS>
</env>
<entryPoint>["sh","-c","java $JAVA_OPTS ${docker.java.security.egd} -jar /${project.build.finalName}.jar"]</entryPoint>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
</project>
\ No newline at end of file
package com.central;
import com.central.admin.properties.IndexProperties;
import com.central.common.annotation.EnableLoginArgResolver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author zlt
*/
@EnableLoginArgResolver
@EnableDiscoveryClient
@SpringBootApplication
@EnableConfigurationProperties(IndexProperties.class)
public class SearchCenterApp {
public static void main(String[] args) {
SpringApplication.run(SearchCenterApp.class, args);
}
}
package com.central.admin.controller;
import com.central.admin.model.IndexDto;
import com.central.admin.model.IndexVo;
import com.central.admin.properties.IndexProperties;
import com.central.admin.service.IIndexService;
import com.central.common.model.PageResult;
import com.central.common.model.Result;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* 索引管理
*
* @author zlt
*/
@Slf4j
@RestController
@Api(tags = "索引管理api")
@RequestMapping("/admin")
public class IndexController {
@Autowired
private IIndexService indexService;
@Autowired
private IndexProperties indexProperties;
@PostMapping("/index")
public Result createIndex(@RequestBody IndexDto indexDto) {
if (indexDto.getNumberOfShards() == null) {
indexDto.setNumberOfShards(1);
}
if (indexDto.getNumberOfReplicas() == null) {
indexDto.setNumberOfReplicas(0);
}
indexService.create(indexDto);
return Result.succeed("操作成功");
}
/**
* 索引列表
*/
@GetMapping("/indices")
public PageResult<IndexVo> list(@RequestParam(required = false) String queryStr) {
return indexService.list(queryStr, indexProperties.getShow());
}
/**
* 索引明细
*/
@GetMapping("/index/{indexName}")
public Result<Map<String, Object>> showIndex(@PathVariable String indexName) {
Map<String, Object> result = indexService.show(indexName);
return Result.succeed(result);
}
/**
* 删除索引
*/
@DeleteMapping("/index/{indexName}")
public Result deleteIndex(@PathVariable String indexName) {
indexService.delete(indexName);
return Result.succeed("操作成功");
}
}
package com.central.admin.model;
import lombok.Data;
/**
* @author zlt
*/
@Data
public class IndexDto {
/**
* 索引名
*/
private String indexName;
/**
* 分片数 number_of_shards
*/
private Integer numberOfShards;
/**
* 副本数 number_of_replicas
*/
private Integer numberOfReplicas;
/**
* 类型
*/
private String type;
/**
* mappings内容
*/
private String mappingsSource;
}
\ No newline at end of file
package com.central.admin.model;
import lombok.Data;
/**
* @author zlt
*/
@Data
public class IndexVo {
/**
* 索引名
*/
private String indexName;
/**
* 文档数
*/
private Long docsCount;
/**
* 文档删除数
*/
private Long docsDeleted;
/**
* 索引大小(kb)
*/
private Double storeSizeInBytes;
/**
* 总查询数
*/
private Long queryCount;
/**
* 总查询耗时(s)
*/
private Double queryTimeInMillis;
}
\ No newline at end of file
package com.central.admin.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
/**
* 索引配置
*
* @author zlt
*/
@Setter
@Getter
@ConfigurationProperties(prefix = "zlt.indices")
@RefreshScope
public class IndexProperties {
/**
* 配置过滤的索引名:默认只显示这些索引
*/
private String[] show;
}
package com.central.admin.service;
import com.central.admin.model.IndexDto;
import com.central.admin.model.IndexVo;
import com.central.common.model.PageResult;
import java.util.Map;
/**
* 索引
*
* @author zlt
* @date 2019/4/23
*/
public interface IIndexService {
/**
* 创建索引
*/
void create(IndexDto indexDto);
/**
* 删除索引
* @param indexName 索引名
*/
void delete(String indexName);
/**
* 索引列表
* @param queryStr 搜索字符串
* @param indices 默认显示的索引名
*/
PageResult<IndexVo> list(String queryStr, String... indices);
/**
* 显示索引明细
* @param indexName 索引名
*/
Map<String, Object> show(String indexName);
}
package com.central.admin.service.impl;
import cn.hutool.core.util.StrUtil;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.central.admin.model.IndexDto;
import com.central.admin.model.IndexVo;
import com.central.admin.service.IIndexService;
import com.central.common.model.PageResult;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.stats.IndexStats;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequestBuilder;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.search.stats.SearchStats;
import org.elasticsearch.index.shard.DocsStats;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 索引
*
* @author zlt
* @date 2019/4/23
*/
@Service
public class IndexServiceImpl implements IIndexService {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Override
public void create(IndexDto indexDto) {
// setting
Settings settings = Settings.builder()
.put("index.number_of_shards", indexDto.getNumberOfShards())
.put("index.number_of_replicas", indexDto.getNumberOfReplicas())
.build();
CreateIndexRequestBuilder builder = elasticsearchTemplate.getClient().admin()
.indices()
.prepareCreate(indexDto.getIndexName())
.setSettings(settings);
if (StrUtil.isNotEmpty(indexDto.getType()) && StrUtil.isNotEmpty(indexDto.getMappingsSource())) {
//mappings
builder.addMapping(indexDto.getType(), indexDto.getMappingsSource(), XContentType.JSON);
}
builder.get();
}
@Override
public void delete(String indexName) {
elasticsearchTemplate.getClient().admin().indices()
.prepareDelete(indexName)
.execute().actionGet();
}
@Override
public PageResult<IndexVo> list(String queryStr, String... indices) {
IndicesStatsRequestBuilder indicesBuilder = elasticsearchTemplate.getClient().admin().indices()
.prepareStats(indices);
if (StrUtil.isNotEmpty(queryStr)) {
indicesBuilder.setIndices(queryStr);
}
List<IndexVo> indexList = new ArrayList<>();
try {
IndicesStatsResponse response = indicesBuilder.execute().actionGet();
Map<String, IndexStats> indicesMap = response.getIndices();
for(IndexStats stat : indicesMap.values()) {
IndexVo vo = new IndexVo();
vo.setIndexName(stat.getIndex());
//获取文档数据
DocsStats docsStats = stat.getTotal().getDocs();
vo.setDocsCount(docsStats.getCount());
vo.setDocsDeleted(docsStats.getDeleted());
//获取存储数据
vo.setStoreSizeInBytes(getKB(stat.getTotal().getStore().getSizeInBytes()));
//获取查询数据
SearchStats.Stats searchStats = stat.getTotal().getSearch().getTotal();
vo.setQueryCount(searchStats.getQueryCount());
vo.setQueryTimeInMillis(searchStats.getQueryTimeInMillis() / 1000D);
indexList.add(vo);
}
} catch (IndexNotFoundException e) {}
return PageResult.<IndexVo>builder().data(indexList).code(0).build();
}
/**
* bytes 转换为 kb
*/
private Double getKB(Long bytes) {
if (bytes == null) {
return 0D;
}
return bytes / 1024D;
}
@Override
public Map<String, Object> show(String indexName) {
ImmutableOpenMap<String, IndexMetaData> stat = elasticsearchTemplate.getClient().admin().cluster()
.prepareState().setIndices(indexName).execute().actionGet()
.getState()
.getMetaData()
.getIndices();
IndexMetaData indexMetaData = stat.get(indexName);
//获取settings数据
Map<String, String> settMap = indexMetaData.getSettings().getAsMap();
ImmutableOpenMap<String, MappingMetaData> mappOpenMap = indexMetaData.getMappings();
ImmutableOpenMap<String, AliasMetaData> aliasesOpenMap = indexMetaData.getAliases();
Map<String, Object> result = new HashMap<>(1);
Map<String, Object> indexMap = new HashMap<>(3);
Map<String, Object> mappMap = new HashMap<>(mappOpenMap.size());
Map<String, Object> aliasesMap = new HashMap<>(aliasesOpenMap.size());
indexMap.put("aliases", aliasesMap);
indexMap.put("settings", settMap);
indexMap.put("mappings", mappMap);
result.put(indexName, indexMap);
//获取mappings数据
for (ObjectCursor<String> key : mappOpenMap.keys()) {
MappingMetaData data = mappOpenMap.get(key.value);
Map<String, Object> dataMap = data.getSourceAsMap();
mappMap.put(key.value, dataMap);
}
//获取aliases数据
for (ObjectCursor<String> key : aliasesOpenMap.keys()) {
AliasMetaData data = aliasesOpenMap.get(key.value);
aliasesMap.put(key.value, data.alias());
}
return result;
}
}
package com.central.common.config;
import org.springframework.context.annotation.Configuration;
/**
* 线程池配置、启用异步
* @Async quartz 需要使用
*
* @author zlt
*/
@Configuration
public class AsycTaskExecutorConfig extends DefaultAsycTaskConfig {
}
package com.central.common.config;
import com.central.common.exception.DefaultExceptionAdvice;
import org.springframework.web.bind.annotation.ControllerAdvice;
/**
* @author zlt
*/
@ControllerAdvice
public class ExceptionAdvice extends DefaultExceptionAdvice {
}
package com.central.search.controller;
import com.central.search.service.IAggregationService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 聚合统计
*
* @author zlt
* @date 2019/5/7
*/
@Slf4j
@RestController
@Api(tags = "搜索模块api")
@RequestMapping("/agg")
public class AggregationController {
@Autowired
private IAggregationService aggregationService;
/**
* 访问统计聚合查询
* @param indexName 索引名
* @param routing es的路由
*/
@GetMapping("/requestStat/{indexName}/{routing}")
public Map<String, Object> requestStatAgg(@PathVariable String indexName, @PathVariable String routing) {
return aggregationService.requestStatAgg(indexName, routing);
}
}
\ No newline at end of file
package com.central.search.controller;
import com.alibaba.fastjson.JSONObject;
import com.central.common.model.*;
import com.central.search.model.SearchDto;
import com.central.search.service.ISearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
/**
* 通用搜索
*
* @author zlt
*/
@Slf4j
@RestController
@Api(tags = "搜索模块api")
@RequestMapping("/search")
public class SearchController {
@Autowired
private ISearchService searchService;
/**
* 查询文档列表
* @param indexName 索引名
* @param searchDto 搜索Dto
*/
@PostMapping("/{indexName}")
public PageResult<JSONObject> strQuery(@PathVariable String indexName, @RequestBody(required = false) SearchDto searchDto) {
if (searchDto == null) {
searchDto = new SearchDto();
}
return searchService.strQuery(indexName, searchDto);
}
}
\ No newline at end of file
package com.central.search.service;
import java.util.Map;
/**
* @author zlt
* @date 2019/4/24
*/
public interface IAggregationService {
/**
* 访问统计聚合查询
* @param indexName 索引名
* @param routing es的路由
* @return
*/
Map<String, Object> requestStatAgg(String indexName, String routing);
}
package com.central.search.service;
import com.alibaba.fastjson.JSONObject;
import com.central.common.model.PageResult;
import com.central.search.model.SearchDto;
/**
* @author zlt
* @date 2019/4/24
*/
public interface ISearchService {
/**
* StringQuery通用搜索
* @param indexName 索引名
* @param searchDto 搜索Dto
* @return
*/
PageResult<JSONObject> strQuery(String indexName, SearchDto searchDto);
}
package com.central.search.service.impl;
import com.central.common.constant.CommonConstant;
import com.central.search.model.AggItemVo;
import com.central.search.service.IAggregationService;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.ExtendedBounds;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalDateHistogram;
import org.elasticsearch.search.aggregations.bucket.range.date.InternalDateRange;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.cardinality.Cardinality;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 聚合分析服务
*
* @author zlt
* @date 2019/5/7
*/
@Service
public class AggregationServiceImpl implements IAggregationService {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
/**
* 访问统计聚合查询,需要es里面提供以下结构的数据
* {
* ip, //访问ip
* browser, //浏览器
* operatingSystem, //操作系统
* timestamp //日志时间
* }
*
* @param indexName 索引名
* @param routing es的路由
* @return 返回结果样例如下
* {
* "currDate_uv": 219,
* "currDate_pv": 2730,
* "currWeek_pv": 10309,
* "browser_datas": [
* {
* "name": "CHROME",
* "value": 7416
* },
* {
* "name": "SAFARI",
* "value": 232
* },
* ...
* ],
* "browser_legendData": [
* "CHROME",
* "SAFARI",
* ...
* ],
* "operatingSystem_datas": [
* {
* "name": "WINDOWS_10",
* "value": 6123
* },
* {
* "name": "MAC_OS_X",
* "value": 1455
* },
* ...
* ],
* "currMonth_pv": 10311,
* "statWeek_uv": [
* 487,
* 219,
* ...
* ],
* "operatingSystem_legendData": [
* "WINDOWS_10",
* "MAC_OS_X",
* ...
* ],
* "statWeek_items": [
* "2019-05-08",
* "2019-05-09",
* ...
* ],
* "statWeek_pv": [
* 7567,
* 2730
* ...
* ]
* }
*/
@Override
public Map<String, Object> requestStatAgg(String indexName, String routing) {
DateTime currDt = DateTime.now();
LocalDate localDate = LocalDate.now();
SearchResponse response = elasticsearchTemplate.getClient().prepareSearch(indexName)
.setRouting(routing)
.addAggregation(
//聚合查询当天的数据
AggregationBuilders
.dateRange("currDate")
.field("timestamp")
.addRange(
currDt.withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0), currDt
)
.subAggregation(
AggregationBuilders
.cardinality("uv")
.field("ip.keyword")
)
)
.addAggregation(
//聚合查询7天内的数据
AggregationBuilders
.dateRange("currWeek")
.field("timestamp")
.addRange(currDt.minusDays(7), currDt)
)
.addAggregation(
//聚合查询30天内的数据
AggregationBuilders
.dateRange("currMonth")
.field("timestamp")
.addRange(currDt.minusDays(30), currDt)
)
.addAggregation(
//聚合查询浏览器的数据
AggregationBuilders
.terms("browser")
.field("browser.keyword")
)
.addAggregation(
//聚合查询操作系统的数据
AggregationBuilders
.terms("operatingSystem")
.field("operatingSystem.keyword")
)
.addAggregation(
//聚合并且按日期分组查询7天内的数据
AggregationBuilders
.dateHistogram("statWeek")
.field("timestamp")
.dateHistogramInterval(DateHistogramInterval.DAY)
.format(CommonConstant.DATE_FORMAT)
//时区相差8小时
.timeZone(DateTimeZone.forOffsetHours(8))
.minDocCount(0)
.extendedBounds(new ExtendedBounds(
localDate.minusDays(7).format(DateTimeFormatter.ofPattern(CommonConstant.DATE_FORMAT)),
localDate.format(DateTimeFormatter.ofPattern(CommonConstant.DATE_FORMAT))
))
.subAggregation(
AggregationBuilders
.cardinality("uv")
.field("ip.keyword")
)
)
.setSize(0)
.execute().actionGet();
Aggregations aggregations = response.getAggregations();
Map<String, Object> result = new HashMap<>(9);
setCurrDate(result, aggregations);
setCurrWeek(result, aggregations);
setCurrMonth(result, aggregations);
setTermsData(result, aggregations, "browser");
setTermsData(result, aggregations, "operatingSystem");
setStatWeek(result, aggregations);
return result;
}
/**
* 赋值当天统计
*/
private void setCurrDate(Map<String, Object> result, Aggregations aggregations) {
InternalDateRange currDate = aggregations.get("currDate");
InternalDateRange.Bucket bucket = currDate.getBuckets().get(0);
Cardinality cardinality = bucket.getAggregations().get("uv");
result.put("currDate_pv", bucket.getDocCount());
result.put("currDate_uv", cardinality.getValue());
}
/**
* 赋值周统计
*/
private void setCurrWeek(Map<String, Object> result, Aggregations aggregations) {
InternalDateRange currWeek = aggregations.get("currWeek");
InternalDateRange.Bucket bucket = currWeek.getBuckets().get(0);
result.put("currWeek_pv", bucket.getDocCount());
}
/**
* 赋值月统计
*/
private void setCurrMonth(Map<String, Object> result, Aggregations aggregations) {
InternalDateRange currMonth = aggregations.get("currMonth");
InternalDateRange.Bucket bucket = currMonth.getBuckets().get(0);
result.put("currMonth_pv", bucket.getDocCount());
}
/**
* 赋值单字段统计
*/
private void setTermsData(Map<String, Object> result, Aggregations aggregations, String key) {
Terms terms = aggregations.get(key);
List<String> legendData = new ArrayList<>();
List<AggItemVo> datas = new ArrayList<>();
for (Terms.Bucket bucket : terms.getBuckets()) {
legendData.add((String)bucket.getKey());
AggItemVo item = new AggItemVo();
item.setName((String)bucket.getKey());
item.setValue(bucket.getDocCount());
datas.add(item);
}
result.put(key+"_legendData", legendData);
result.put(key+"_datas", datas);
}
/**
* 赋值周趋势统计
*/
private void setStatWeek(Map<String, Object> result, Aggregations aggregations) {
InternalDateHistogram agg = aggregations.get("statWeek");
List<String> items = new ArrayList<>();
List<Long> uv = new ArrayList<>();
List<Long> pv = new ArrayList<>();
Cardinality cardinality;
for (InternalDateHistogram.Bucket bucket : agg.getBuckets()) {
items.add(bucket.getKeyAsString());
pv.add(bucket.getDocCount());
cardinality = bucket.getAggregations().get("uv");
uv.add(cardinality.getValue());
}
result.put("statWeek_items", items);
result.put("statWeek_uv", uv);
result.put("statWeek_pv", pv);
}
}
package com.central.search.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.central.common.model.PageResult;
import com.central.search.model.SearchDto;
import com.central.search.service.ISearchService;
import com.central.search.util.SearchBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.stereotype.Service;
/**
* 通用搜索
*
* @author zlt
* @date 2019/4/24
*/
@Service
public class SearchServiceImpl implements ISearchService {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
/**
* StringQuery通用搜索
* @param indexName 索引名
* @param searchDto 搜索Dto
* @return
*/
@Override
public PageResult<JSONObject> strQuery(String indexName, SearchDto searchDto) {
return SearchBuilder.builder(elasticsearchTemplate, indexName)
.setStringQuery(searchDto.getQueryStr())
.addSort(searchDto.getSortCol(), SortOrder.DESC)
.setIsHighlight(searchDto.getIsHighlighter())
.getPage(searchDto.getPage(), searchDto.getLimit());
}
}
package com.central.search.util;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.central.common.model.PageResult;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.beanutils.PropertyUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* ES查询Builder
*
* @author zlt
* @date 2019/4/23
*/
@Setter
@Getter
public class SearchBuilder {
/**
* 高亮前缀
*/
private static final String HIGHLIGHTER_PRE_TAGS = "<mark>";
/**
* 高亮后缀
*/
private static final String HIGHLIGHTER_POST_TAGS = "</mark>";
private SearchRequestBuilder searchBuilder;
private SearchBuilder(SearchRequestBuilder searchBuilder) {
this.searchBuilder = searchBuilder;
}
/**
* 生成SearchBuilder实例
* @param elasticsearchTemplate
* @param indexName
*/
public static SearchBuilder builder(ElasticsearchTemplate elasticsearchTemplate, String indexName) {
SearchRequestBuilder searchBuilder = elasticsearchTemplate.getClient().prepareSearch(indexName);
return new SearchBuilder(searchBuilder);
}
/**
* 生成queryStringQuery查询
* @param queryStr 查询关键字
*/
public SearchBuilder setStringQuery(String queryStr) {
QueryBuilder queryBuilder;
if (StrUtil.isNotEmpty(queryStr)) {
queryBuilder = QueryBuilders.queryStringQuery(queryStr);
} else {
queryBuilder = QueryBuilders.matchAllQuery();
}
searchBuilder.setQuery(queryBuilder);
return this;
}
/**
* 设置分页
* @param page 当前页数
* @param limit 每页显示数
*/
public SearchBuilder setPage(Integer page, Integer limit) {
if (page != null && limit != null) {
searchBuilder.setFrom((page - 1) * limit)
.setSize(limit);
}
return this;
}
/**
* 增加排序
* @param field 排序字段
* @param order 顺序方向
*/
public SearchBuilder addSort(String field, SortOrder order) {
if (StrUtil.isNotEmpty(field) && order != null) {
searchBuilder.addSort(field, order);
}
return this;
}
/**
* 设置高亮
* @param preTags 高亮处理前缀
* @param postTags 高亮处理后缀
*/
public SearchBuilder setHighlight(String field, String preTags, String postTags) {
if (StrUtil.isNotEmpty(field) && StrUtil.isNotEmpty(preTags) && StrUtil.isNotEmpty(postTags)) {
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field(field)
.preTags(preTags)
.postTags(postTags);
searchBuilder.highlighter(highlightBuilder);
}
return this;
}
/**
* 设置是否需要高亮处理
* @param isHighlighter 是否需要高亮处理
*/
public SearchBuilder setIsHighlight(Boolean isHighlighter) {
if (BooleanUtil.isTrue(isHighlighter)) {
this.setHighlight("*"
, HIGHLIGHTER_PRE_TAGS, HIGHLIGHTER_POST_TAGS);
}
return this;
}
/**
* 设置查询路由
* @param routing 路由数组
*/
public SearchBuilder setRouting(String... routing) {
if (ArrayUtil.isNotEmpty(routing)) {
searchBuilder.setRouting(routing);
}
return this;
}
/**
* 返回结果 SearchResponse
*/
public SearchResponse get() {
return searchBuilder.execute().actionGet();
}
/**
* 返回列表结果 List<JSONObject>
*/
public List<JSONObject> getList() {
return getList(this.get().getHits());
}
/**
* 返回分页结果 PageResult<JSONObject>
*/
public PageResult<JSONObject> getPage() {
return this.getPage(null, null);
}
/**
* 返回分页结果 PageResult<JSONObject>
* @param page 当前页数
* @param limit 每页显示
*/
public PageResult<JSONObject> getPage(Integer page, Integer limit) {
this.setPage(page, limit);
SearchResponse response = this.get();
SearchHits searchHits = response.getHits();
long totalCnt = searchHits.getTotalHits();
List<JSONObject> list = getList(searchHits);
return PageResult.<JSONObject>builder().data(list).code(0).count(totalCnt).build();
}
/**
* 返回JSON列表数据
*/
private List<JSONObject> getList(SearchHits searchHits) {
List<JSONObject> list = new ArrayList<>();
if (searchHits != null) {
searchHits.forEach(item -> {
JSONObject jsonObject = JSON.parseObject(item.getSourceAsString());
jsonObject.put("id", item.getId());
Map<String, HighlightField> highlightFields = item.getHighlightFields();
if (highlightFields != null) {
populateHighLightedFields(jsonObject, highlightFields);
}
list.add(jsonObject);
});
}
return list;
}
/**
* 组装高亮字符
* @param result 目标对象
* @param highlightFields 高亮配置
*/
private <T> void populateHighLightedFields(T result, Map<String, HighlightField> highlightFields) {
for (HighlightField field : highlightFields.values()) {
try {
String name = field.getName();
if (!name.endsWith(".keyword")) {
PropertyUtils.setProperty(result, field.getName(), concat(field.fragments()));
}
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
throw new ElasticsearchException("failed to set highlighted value for field: " + field.getName()
+ " with value: " + Arrays.toString(field.getFragments()), e);
}
}
}
/**
* 拼凑数组为字符串
*/
private String concat(Text[] texts) {
StringBuffer sb = new StringBuffer();
for (Text text : texts) {
sb.append(text.toString());
}
return sb.toString();
}
}
spring:
data:
elasticsearch:
cluster-name: ${zlt.elasticsearch.cluster-name}
cluster-nodes: ${zlt.elasticsearch.cluster-nodes}
zlt:
indices:
show: sys-log-*, mysql-slowlog-*, sys_user, point-log-*
swagger:
enabled: true
title: 搜索中心
description: 搜索中心接口文档
version: 1.0
base-package: com.central.search.controller
\ No newline at end of file
server:
port: 7100
zlt:
nacos:
server-addr: 192.168.28.130:8848
spring:
application:
name: search-center
cloud:
nacos:
config:
server-addr: ${zlt.nacos.server-addr}
file-extension: yml
shared-dataids: common.yml
refreshable-dataids: common.yml
discovery:
server-addr: ${zlt.nacos.server-addr}
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-business</artifactId> <artifactId>zlt-business</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>user-center</artifactId> <artifactId>user-center</artifactId>
<description>用户中心</description> <description>用户中心</description>
...@@ -39,6 +39,10 @@ ...@@ -39,6 +39,10 @@
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-swagger2-spring-boot-starter</artifactId> <artifactId>zlt-swagger2-spring-boot-starter</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>search-client</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
......
package com.central; package com.central;
import com.central.common.annotation.EnableLoginArgResolver; import com.central.common.annotation.EnableLoginArgResolver;
import com.central.search.annotation.EnableSearchClient;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
...@@ -12,7 +13,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; ...@@ -12,7 +13,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
*/ */
@EnableLoginArgResolver @EnableLoginArgResolver
@EnableDiscoveryClient @EnableDiscoveryClient
@EnableFeignClients @EnableSearchClient
@EnableTransactionManagement @EnableTransactionManagement
@SpringBootApplication @SpringBootApplication
public class UserCenterApp { public class UserCenterApp {
......
package com.central.user.config; package com.central.user.config;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.central.db.config.DefaultMybatisPlusConfig; import com.central.db.config.DefaultMybatisPlusConfig;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
...@@ -14,11 +11,4 @@ import org.springframework.context.annotation.Configuration; ...@@ -14,11 +11,4 @@ import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
@MapperScan({"com.central.user.mapper*"}) @MapperScan({"com.central.user.mapper*"})
public class MybatisPlusConfig extends DefaultMybatisPlusConfig { public class MybatisPlusConfig extends DefaultMybatisPlusConfig {
/**
* 逻辑删除注入器
*/
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
} }
...@@ -7,10 +7,14 @@ import java.util.Map; ...@@ -7,10 +7,14 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.central.common.annotation.LoginUser; import com.central.common.annotation.LoginUser;
import com.central.common.constant.CommonConstant; import com.central.common.constant.CommonConstant;
import com.central.common.model.*; import com.central.common.model.*;
import com.central.common.utils.ExcelUtil; import com.central.common.utils.ExcelUtil;
import com.central.search.client.service.IQueryService;
import com.central.search.model.LogicDelDto;
import com.central.search.model.SearchDto;
import com.central.user.model.SysUserExcel; import com.central.user.model.SysUserExcel;
import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -40,9 +44,17 @@ import javax.servlet.http.HttpServletResponse; ...@@ -40,9 +44,17 @@ import javax.servlet.http.HttpServletResponse;
public class SysUserController { public class SysUserController {
private static final String ADMIN_CHANGE_MSG = "超级管理员不给予修改"; private static final String ADMIN_CHANGE_MSG = "超级管理员不给予修改";
/**
* 全文搜索逻辑删除Dto
*/
private static final LogicDelDto SEARCH_LOGIC_DEL_DTO = new LogicDelDto("isDel", "否");
@Autowired @Autowired
private ISysUserService appUserService; private ISysUserService appUserService;
@Autowired
private IQueryService queryService;
/** /**
* 当前登录用户 LoginAppUser * 当前登录用户 LoginAppUser
* *
...@@ -255,6 +267,19 @@ public class SysUserController { ...@@ -255,6 +267,19 @@ public class SysUserController {
return Result.succeed("导入数据成功,一共【"+rowNum+"】行"); return Result.succeed("导入数据成功,一共【"+rowNum+"】行");
} }
@ApiOperation(value = "用户全文搜索列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "分页起始位置", required = true, dataType = "Integer"),
@ApiImplicitParam(name = "limit", value = "分页结束位置", required = true, dataType = "Integer"),
@ApiImplicitParam(name = "queryStr", value = "搜索关键字", dataType = "String")
})
@GetMapping("/users/search")
public PageResult<JSONObject> search(SearchDto searchDto) {
searchDto.setIsHighlighter(true);
searchDto.setSortCol("createTime");
return queryService.strQuery("sys_user", searchDto, SEARCH_LOGIC_DEL_DTO);
}
/** /**
* 是否超级管理员 * 是否超级管理员
*/ */
......
package com.central.user.model; package com.central.user.model;
import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.excel.annotation.Excel;
import com.central.common.constant.CommonConstant;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
...@@ -26,9 +27,9 @@ public class SysUserExcel implements Serializable { ...@@ -26,9 +27,9 @@ public class SysUserExcel implements Serializable {
@Excel(name = "学生性别", replace = { "男_0", "女_1" }, suffix = "生", isImportField = "true_st") @Excel(name = "学生性别", replace = { "男_0", "女_1" }, suffix = "生", isImportField = "true_st")
private Integer sex; private Integer sex;
@Excel(name = "创建时间", format = "yyyy-MM-dd HH:mm:ss", isImportField = "true_st", width = 20) @Excel(name = "创建时间", format = CommonConstant.DATETIME_FORMAT, isImportField = "true_st", width = 20)
private Date createTime; private Date createTime;
@Excel(name = "修改时间", format = "yyyy-MM-dd HH:mm:ss", isImportField = "true_st", width = 20) @Excel(name = "修改时间", format = CommonConstant.DATETIME_FORMAT, isImportField = "true_st", width = 20)
private Date updateTime; private Date updateTime;
} }
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<description>通用组件</description> <description>通用组件</description>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-common-spring-boot-starter</artifactId> <artifactId>zlt-common-spring-boot-starter</artifactId>
<description>公共通用组件</description> <description>公共通用组件</description>
......
...@@ -12,4 +12,8 @@ public interface ServiceNameConstants { ...@@ -12,4 +12,8 @@ public interface ServiceNameConstants {
* 用户权限服务 * 用户权限服务
*/ */
String USER_SERVICE = "user-center"; String USER_SERVICE = "user-center";
/**
* 搜索中心服务
*/
String SEARCH_SERVICE = "search-center";
} }
...@@ -12,11 +12,12 @@ import java.util.Date; ...@@ -12,11 +12,12 @@ import java.util.Date;
/** /**
* 实体父类 * 实体父类
*
* @author zlt * @author zlt
*/ */
@Setter @Setter
@Getter @Getter
public class SuperEntity<T extends Model> extends Model<T> { public class SuperEntity<T extends Model<?>> extends Model<T> {
/** /**
* 主键ID * 主键ID
*/ */
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -27,4 +27,8 @@ public class PointUtil { ...@@ -27,4 +27,8 @@ public class PointUtil {
public static void info(String id, String type, String message) { public static void info(String id, String type, String message) {
log.info(id + SPLIT + type + SPLIT + message); log.info(id + SPLIT + type + SPLIT + message);
} }
public static void debug(String id, String type, String message) {
log.debug(id + SPLIT + type + SPLIT + message);
}
} }
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
<appender name="point_log" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="point_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_POINT_FILE}/point.log</file> <file>${LOG_POINT_FILE}/point.log</file>
<encoder> <encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss}|${APP_NAME}|%msg%n</pattern> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|${APP_NAME}|%msg%n</pattern>
<charset>UTF-8</charset> <charset>UTF-8</charset>
</encoder> </encoder>
<!-- 基于时间的分包策略 --> <!-- 基于时间的分包策略 -->
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
<discardingThreshold>0</discardingThreshold> <discardingThreshold>0</discardingThreshold>
<appender-ref ref="point_log"/> <appender-ref ref="point_log"/>
</appender> </appender>
<logger name="com.central.log.monitor" level="info" addtivity="false"> <logger name="com.central.log.monitor" level="debug" addtivity="false">
<appender-ref ref="point_log_async" /> <appender-ref ref="point_log_async" />
</logger> </logger>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-commons</artifactId> <artifactId>zlt-commons</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -14,7 +14,7 @@ zlt.elasticsearch.cluster-name=my-es ...@@ -14,7 +14,7 @@ zlt.elasticsearch.cluster-name=my-es
zlt.elasticsearch.cluster-nodes=192.168.28.130:9300 zlt.elasticsearch.cluster-nodes=192.168.28.130:9300
##### sentinel配置 ##### sentinel配置
zlt.sentinel.dashboard=127.0.0.1:6999 zlt.sentinel.dashboard=192.168.28.130:6999
##### fastDFS配置 ##### fastDFS配置
zlt.fdfs.web-url=192.168.28.130 zlt.fdfs.web-url=192.168.28.130
......
########################## 统一变量配置 ########################## ########################## 统一变量配置 ##########################
##### 数据库配置 ##### 数据库配置
zlt.datasource.ip=120.78.94.191 zlt.datasource.ip=120.78.94.191
zlt.datasource.username=root zlt.datasource.username=zlt
zlt.datasource.password=1q2w3e4r zlt.datasource.password=1q2w3e4r
##### redis配置 ##### redis配置
......
########################## 统一变量配置 ########################## ########################## 统一变量配置 ##########################
##### 数据库配置 ##### 数据库配置
zlt.datasource.ip=120.78.94.191 zlt.datasource.ip=120.78.94.191
zlt.datasource.username=root zlt.datasource.username=zlt
zlt.datasource.password=1q2w3e4r zlt.datasource.password=1q2w3e4r
##### redis配置 ##### redis配置
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-demo</artifactId> <artifactId>zlt-demo</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-demo</artifactId> <artifactId>zlt-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>rocketmq-demo</artifactId> <artifactId>rocketmq-demo</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>rocketmq-demo</artifactId> <artifactId>rocketmq-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>rocketmq-consume</artifactId> <artifactId>rocketmq-consume</artifactId>
<description>rocketMQ消费者demo</description> <description>rocketMQ消费者demo</description>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>rocketmq-demo</artifactId> <artifactId>rocketmq-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>rocketmq-produce</artifactId> <artifactId>rocketmq-produce</artifactId>
<description>rocketMQ生产者demo</description> <description>rocketMQ生产者demo</description>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>rocketmq-demo</artifactId> <artifactId>rocketmq-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>rocketmq-transactional</artifactId> <artifactId>rocketmq-transactional</artifactId>
<description>rocketMQ事务消息demo</description> <description>rocketMQ事务消息demo</description>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-demo</artifactId> <artifactId>zlt-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>sharding-jdbc-demo</artifactId> <artifactId>sharding-jdbc-demo</artifactId>
<description>sharding-jdbc分库分表demo</description> <description>sharding-jdbc分库分表demo</description>
......
package com.sharding.demo.config; package com.sharding.demo.config;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.central.db.config.DefaultMybatisPlusConfig; import com.central.db.config.DefaultMybatisPlusConfig;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
...@@ -13,11 +10,4 @@ import org.springframework.context.annotation.Configuration; ...@@ -13,11 +10,4 @@ import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
@MapperScan({"com.sharding.demo.mapper*"}) @MapperScan({"com.sharding.demo.mapper*"})
public class MybatisPlusConfig extends DefaultMybatisPlusConfig { public class MybatisPlusConfig extends DefaultMybatisPlusConfig {
/**
* 逻辑删除注入器
*/
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
} }
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-demo</artifactId> <artifactId>zlt-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>txlcn-demo</artifactId> <artifactId>txlcn-demo</artifactId>
<description>txlcn分布式事务demo</description> <description>txlcn分布式事务demo</description>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>txlcn-demo</artifactId> <artifactId>txlcn-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>txlcn-demo-common</artifactId> <artifactId>txlcn-demo-common</artifactId>
<name>demo-common</name> <name>demo-common</name>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>txlcn-demo</artifactId> <artifactId>txlcn-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>txlcn-demo</artifactId> <artifactId>txlcn-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>txlcn-demo-spring-service-b</artifactId> <artifactId>txlcn-demo-spring-service-b</artifactId>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>txlcn-demo</artifactId> <artifactId>txlcn-demo</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>txlcn-demo-spring-service-c</artifactId> <artifactId>txlcn-demo-spring-service-c</artifactId>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-gateway</artifactId> <artifactId>zlt-gateway</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-gateway</artifactId> <artifactId>zlt-gateway</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zuul-gateway</artifactId> <artifactId>zuul-gateway</artifactId>
<description>zuul网关</description> <description>zuul网关</description>
...@@ -91,6 +91,10 @@ ...@@ -91,6 +91,10 @@
<groupId>io.micrometer</groupId> <groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId> <artifactId>micrometer-registry-prometheus</artifactId>
</dependency> </dependency>
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
package com.central.gateway.filter.pre;
import com.central.log.monitor.PointUtil;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* 统计分析埋点过滤器
*
* @author zlt
* @date 2018/11/20
*/
@Slf4j
@Component
public class RequestStatisticsFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
UserAgent userAgent = UserAgent.parseUserAgentString(req.getHeader("User-Agent"));
//埋点
PointUtil.debug("0","request-statistics","ip="+this.getIpAddr(req)
+"&browser="+userAgent.getBrowser()
+"&operatingSystem="+userAgent.getOperatingSystem());
return null;
}
/**
* 获取Ip地址
*/
public String getIpAddr(HttpServletRequest request){
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
...@@ -108,6 +108,11 @@ zuul: ...@@ -108,6 +108,11 @@ zuul:
path: /api-generator/** path: /api-generator/**
service-id: code-generator service-id: code-generator
strip-prefix: true strip-prefix: true
search:
path: /api-search/**
service-id: search-center
strip-prefix: true
custom-sensitive-headers: true
ssl-hostname-validation-enabled: false ssl-hostname-validation-enabled: false
hystrix: hystrix:
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-job</artifactId> <artifactId>zlt-job</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>job-admin</artifactId> <artifactId>job-admin</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-job</artifactId> <artifactId>zlt-job</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>job-core</artifactId> <artifactId>job-core</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
......
package com.xxl.job.core.util; package com.xxl.job.core.util;
/** /**
* sharding vo * sharding model
* @author xuxueli 2017-07-25 21:26:38 * @author xuxueli 2017-07-25 21:26:38
*/ */
public class ShardingUtil { public class ShardingUtil {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-job</artifactId> <artifactId>zlt-job</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>job-executor-samples</artifactId> <artifactId>job-executor-samples</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-job</artifactId> <artifactId>zlt-job</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-monitor</artifactId> <artifactId>zlt-monitor</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>log-center</artifactId> <artifactId>log-center</artifactId>
<dependencies> <dependencies>
...@@ -26,15 +26,15 @@ ...@@ -26,15 +26,15 @@
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-swagger2-spring-boot-starter</artifactId> <artifactId>zlt-swagger2-spring-boot-starter</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>search-client</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
......
package com.central; package com.central;
import com.central.search.annotation.EnableSearchClient;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
...@@ -8,6 +9,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; ...@@ -8,6 +9,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
* @author zlt * @author zlt
*/ */
@EnableDiscoveryClient @EnableDiscoveryClient
@EnableSearchClient
@SpringBootApplication @SpringBootApplication
public class LogApp { public class LogApp {
public static void main(String[] args) { public static void main(String[] args) {
......
package com.central.log.controller;
import com.central.search.client.service.IQueryService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* 访问统计
*
* @author zlt
* @date 2019/5/8
*/
@RestController
public class AggregationController {
@Autowired
private IQueryService queryService;
@ApiOperation(value = "访问统计")
@GetMapping(value = "/requestStat")
public Map<String, Object> requestStatAgg() {
return queryService.requestStatAgg("point-log-*","request-statistics");
}
}
package com.central.log.controller;
import com.central.common.model.PageResult;
import org.apache.commons.collections4.MapUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
/**
* 日志父类
*
* @author zlt
*/
public class LogController<E> {
public PageResult<E> getPage(@RequestParam Map<String, Object> params, BoolQueryBuilder builder, ElasticsearchRepository repository) {
// 分页参数
Pageable pageable = PageRequest.of(MapUtils.getInteger(params, "page") - 1, MapUtils.getInteger(params, "limit")
, Sort.Direction.DESC, "timestamp");
SearchQuery query = new NativeSearchQueryBuilder().withQuery(builder).withPageable(pageable).build();
Page<E> result = (Page<E>)repository.search(query);
return PageResult.<E>builder().data(result.getContent()).code(0).count(result.getTotalElements()).build();
}
}
package com.central.log.controller; package com.central.log.controller;
import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject;
import com.central.common.model.PageResult; import com.central.common.model.PageResult;
import com.central.log.dao.SlowQueryLogDao; import com.central.search.client.service.IQueryService;
import com.central.log.model.SlowQueryLog; import com.central.search.model.SearchDto;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/** /**
* 慢查询日志 * 慢查询日志
* *
* @author zlt * @author zlt
*/ */
@RestController @RestController
public class SlowQueryLogController extends LogController<SlowQueryLog> { public class SlowQueryLogController {
private static final String ES_PARAM_QUERY = "query_str";
@Autowired @Autowired
public SlowQueryLogDao logDao; private IQueryService queryService;
@ApiOperation(value = "系统日志查询列表") @ApiOperation(value = "慢sql日志全文搜索列表")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "分页起始位置", required = true, dataType = "Integer"), @ApiImplicitParam(name = "page", value = "分页起始位置", required = true, dataType = "Integer"),
@ApiImplicitParam(name = "limit", value = "分页结束位置", required = true, dataType = "Integer") @ApiImplicitParam(name = "limit", value = "分页结束位置", required = true, dataType = "Integer"),
@ApiImplicitParam(name = "queryStr", value = "搜索关键字", dataType = "String")
}) })
@GetMapping(value = "/slowQueryLog") @GetMapping(value = "/slowQueryLog")
public PageResult<SlowQueryLog> getPage(@RequestParam Map<String, Object> params) { public PageResult<JSONObject> getPage(SearchDto searchDto) {
BoolQueryBuilder builder = QueryBuilders.boolQuery(); searchDto.setIsHighlighter(true);
String searchKey = (String) params.get("searchKey"); searchDto.setSortCol("timestamp");
String searchValue = (String) params.get("searchValue"); return queryService.strQuery("mysql-slowlog-*", searchDto);
if (StrUtil.isNotEmpty(searchKey) && StrUtil.isNotEmpty(searchValue)) {
// 模糊查询
builder.must(QueryBuilders.matchQuery(ES_PARAM_QUERY, searchValue));
}
return super.getPage(params, builder, logDao);
} }
} }
package com.central.log.controller; package com.central.log.controller;
import java.util.*; import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.util.StrUtil;
import com.central.common.model.PageResult; import com.central.common.model.PageResult;
import com.central.log.dao.SysLogDao; import com.central.search.client.service.IQueryService;
import com.central.log.model.SysLog; import com.central.search.model.SearchDto;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.elasticsearch.index.query.*;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
/** /**
...@@ -21,32 +17,20 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -21,32 +17,20 @@ import org.springframework.web.bind.annotation.RestController;
* @author zlt * @author zlt
*/ */
@RestController @RestController
public class SysLogController extends LogController<SysLog> { public class SysLogController {
private static final String ES_PARAM_MESSAGE = "message";
private static final String ES_PARAM_LOG_LEVEL = "logLevel";
private static final String ES_PARAM_APP_NAME = "appName";
private static final String ES_PARAM_CLASSNAME = "classname";
@Autowired @Autowired
public SysLogDao logDao; private IQueryService queryService;
@ApiOperation(value = "系统日志查询列表") @ApiOperation(value = "系统日志全文搜索列表")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "分页起始位置", required = true, dataType = "Integer"), @ApiImplicitParam(name = "page", value = "分页起始位置", required = true, dataType = "Integer"),
@ApiImplicitParam(name = "limit", value = "分页结束位置", required = true, dataType = "Integer") @ApiImplicitParam(name = "limit", value = "分页结束位置", required = true, dataType = "Integer"),
@ApiImplicitParam(name = "queryStr", value = "搜索关键字", dataType = "String")
}) })
@GetMapping(value = "/sysLog") @GetMapping(value = "/sysLog")
public PageResult<SysLog> getPage(@RequestParam Map<String, Object> params) { public PageResult<JSONObject> getPage(SearchDto searchDto) {
BoolQueryBuilder builder = QueryBuilders.boolQuery(); searchDto.setIsHighlighter(true);
String searchKey = (String) params.get("searchKey"); searchDto.setSortCol("timestamp");
String searchValue = (String) params.get("searchValue"); return queryService.strQuery("sys-log-*", searchDto);
if (StrUtil.isNotEmpty(searchKey) && StrUtil.isNotEmpty(searchValue)) {
if (ES_PARAM_LOG_LEVEL.equals(searchKey)) {
searchValue = searchValue.toUpperCase();
}
// 模糊查询
builder.must(QueryBuilders.matchQuery(searchKey, searchValue));
}
return super.getPage(params, builder, logDao);
} }
} }
package com.central.log.dao;
import com.central.log.model.SlowQueryLog;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Component;
/**
* @author zlt
*/
@Component
public interface SlowQueryLogDao extends ElasticsearchRepository<SlowQueryLog, String> {
}
\ No newline at end of file
package com.central.log.dao;
import com.central.log.model.SysLog;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Component;
/**
* @author zlt
*/
@Component
public interface SysLogDao extends ElasticsearchRepository<SysLog, String> {
}
\ No newline at end of file
package com.central.log.model;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import java.util.Date;
/**
* 慢查询日志对象
*
* @author zlt
*/
@Data
@Document(indexName = "mysql-slowlog-*", type = "doc")
public class SlowQueryLog {
@Id
private String id;
private Date timestamp;
private String query_str;
private String user;
private String clientip;
private Float query_time;
private Float lock_time;
private Long rows_sent;
private Long rows_examined;
}
\ No newline at end of file
package com.central.log.model;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import java.util.Date;
/**
* 系统日志对象
*
* @author zlt
*/
@Data
@Document(indexName = "sys-log-*", type = "doc")
public class SysLog {
@Id
private String id;
private Date timestamp;
private String message;
private String threadName;
private String serverPort;
private String serverIp;
private String logLevel;
private String appName;
private String classname;
}
\ No newline at end of file
spring:
data:
elasticsearch:
cluster-name: ${zlt.elasticsearch.cluster-name}
cluster-nodes: ${zlt.elasticsearch.cluster-nodes}
repositories:
enabled: true
zlt: zlt:
swagger: swagger:
enabled: true enabled: true
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-monitor</artifactId> <artifactId>zlt-monitor</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-monitor</artifactId> <artifactId>zlt-monitor</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>sc-admin</artifactId> <artifactId>sc-admin</artifactId>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-transaction</artifactId> <artifactId>zlt-transaction</artifactId>
<description>事务</description> <description>事务</description>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-transaction</artifactId> <artifactId>zlt-transaction</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>txlcn-tm</artifactId> <artifactId>txlcn-tm</artifactId>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>central-platform</artifactId> <artifactId>central-platform</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>zlt-uaa</artifactId> <artifactId>zlt-uaa</artifactId>
<description>认证中心</description> <description>认证中心</description>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>com.zlt</groupId> <groupId>com.zlt</groupId>
<artifactId>zlt-web</artifactId> <artifactId>zlt-web</artifactId>
<version>1.6.0</version> <version>2.0.0</version>
</parent> </parent>
<artifactId>back-web</artifactId> <artifactId>back-web</artifactId>
<description>后台管理前端</description> <description>后台管理前端</description>
......
...@@ -283,7 +283,7 @@ menus: [{ ...@@ -283,7 +283,7 @@ menus: [{
subMenus: [{ subMenus: [{
name: '用户管理', name: '用户管理',
url: '#!user', // 这里url不能带斜杠 url: '#!user', // 这里url不能带斜杠
path: 'system/user.html', path: user_search.html,
auth: 'post:/user/query' auth: 'post:/user/query'
}, { }, {
name: '角色管理', name: '角色管理',
......
...@@ -51,7 +51,7 @@ layui.define(function (exports) { ...@@ -51,7 +51,7 @@ layui.define(function (exports) {
// subMenus: [{ // subMenus: [{
// name: '用户管理', // name: '用户管理',
// url: '#!user', // 这里url不能带斜杠,因为是用递归循环进行关键字注册,带斜杠会被q.js理解为其他注册模式 // url: '#!user', // 这里url不能带斜杠,因为是用递归循环进行关键字注册,带斜杠会被q.js理解为其他注册模式
// path: 'system/user.html', // path: 'system/user_search.html',
// auth: 'back:user:query' // auth: 'back:user:query'
// }, { // }, {
// name: '角色管理', // name: '角色管理',
......
...@@ -6,16 +6,251 @@ ...@@ -6,16 +6,251 @@
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="../../assets/libs/layui/css/layui.css"/> <script type="text/javascript" src="../assets/libs/echarts.min.js"></script>
<link rel="stylesheet" href="../../assets/css/admin.css"/> <style>
.layui-card-header {
text-align:left;
}
.layuiadmin-badge {
float:right;
margin-top:12px;
}
.big-font {
text-align:left;
font-size: 250%;
height: 30px;
}
</style>
</head> </head>
<body> <body>
<div class="layui-card-body" style="text-align: center;"> <div class="layui-card-body" style="text-align: center;">
<!--h2-- style="margin-top: 170px;margin-bottom: 20px;font-size: 28px;color: #91ADDC;">&nbsp;</h2--> <div class="layui-row layui-col-space10">
<img src="../../assets/images/welcome.png" style="max-width: 100%;"> <div class="layui-col-sm3 layui-col-md3">
<div class="layui-card">
<div class="layui-card-header">PV
<span class="layui-badge layui-bg-green layuiadmin-badge"></span>
</div>
<div class="layui-card-body layuiadmin-card-list">
<p class="big-font" id="pv"></p>
</div>
</div>
</div>
<div class="layui-col-sm3 layui-col-md3">
<div class="layui-card">
<div class="layui-card-header">UV
<span class="layui-badge layui-bg-green layuiadmin-badge"></span>
</div>
<div class="layui-card-body layuiadmin-card-list">
<p class="big-font" id="uv"></p>
</div>
</div>
</div>
<div class="layui-col-sm3 layui-col-md3">
<div class="layui-card">
<div class="layui-card-header">周访问量
<span class="layui-badge layui-bg-blue layuiadmin-badge"></span>
</div>
<div class="layui-card-body layuiadmin-card-list">
<p class="big-font" id="weekPv"></p>
</div>
</div>
</div>
<div class="layui-col-sm3 layui-col-md3">
<div class="layui-card">
<div class="layui-card-header">月访问量
<span class="layui-badge layui-bg-orange layuiadmin-badge"></span>
</div>
<div class="layui-card-body layuiadmin-card-list">
<p class="big-font" id="monthPv"></p>
</div>
</div>
</div>
</div>
<div class="layui-row layui-col-space10">
<div class="layui-col-lg12 layui-col-md12">
<div class="layui-card">
<div class="card-block">
<div id="week-container" style="height:350px"></div>
</div>
</div>
</div>
</div>
<div class="layui-row layui-col-space10">
<div class="layui-col-lg6 layui-col-md6">
<div class="layui-card">
<div class="card-block">
<div id="browser-container" style="height:300px"></div>
</div>
</div>
</div>
<div class="layui-col-lg6 layui-col-lg6">
<div class="layui-card">
<div class="card-block">
<div id="operatingSystem-container" style="height:300px"></div>
</div>
</div>
</div>
</div>
</div> </div>
</body>
<script type="text/javascript">
layui.use(['admin'], function () {
let admin = layui.admin;
let browserChart = echarts.init(document.getElementById("browser-container"));
browserChart.setOption({
title : {
text: '浏览器分布',
subtext: '',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {},
series : []
});
browserChart.showLoading();
let osChart = echarts.init(document.getElementById("operatingSystem-container"));
osChart.setOption({
title : {
text: '系统分布',
subtext: '',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {},
series : []
});
osChart.showLoading();
let weekChart = echarts.init(document.getElementById("week-container"));
weekChart.setOption({
title: {
text: '流量趋势'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['访问量(PV)', '独立用户(UV)']
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: []
}
],
yAxis: [
{
type: 'value'
}
],
series: []
});
weekChart.showLoading();
admin.req('api-log/requestStat', {}, function (data) {
$('#pv').html(data.currDate_pv);
$('#uv').html(data.currDate_uv);
$('#weekPv').html(data.currWeek_pv);
$('#monthPv').html(data.currMonth_pv);
browserChart.hideLoading()
browserChart.setOption({
legend: {
orient: 'vertical',
left: 'left',
data: data.browser_legendData
},
series : [
{
name: '浏览器',
type: 'pie',
radius : '55%',
center: ['50%', '60%'],
data: data.browser_datas,
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
});
osChart.hideLoading()
osChart.setOption({
legend: {
orient: 'vertical',
left: 'left',
data: data.operatingSystem_legendData
},
series : [
{
name: '操作系统',
type: 'pie',
radius : '55%',
center: ['50%', '60%'],
data: data.operatingSystem_datas,
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
});
weekChart.hideLoading()
weekChart.setOption({
xAxis: [
{
type: 'category',
boundaryGap: false,
data: data.statWeek_items
}
],
series: [
{
name: '访问量(PV)',
type: 'line',
areaStyle: {},
label: {
normal: {
show: true,
position: 'top'
}
},
data: data.statWeek_pv
},
{
name: '独立用户(UV)',
type: 'line',
areaStyle: {},
data: data.statWeek_uv
}
]
});
}, 'GET');
});
</script>
</body>
</html> </html>
\ No newline at end of file
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册