环境基于 centos7, es是java写的还需要jdk环境, jdk装1.8就行,
Es:优势:
一: 横向扩展方便, 增加服务器, 添加配置es, 就可以加入集群
二: 分片机制提供更好的分布性,同一个索引分成多个分片, 提升处理效率
三:提供复制机制,一个分片可以提供多个复制,使得集群下某台服务器宕机时,集群依旧可以运行,并且把宕机的节点的数 据复制恢复到其他可用的节点上。
json结构存储数据
1: 官方下载地址:https://www.elastic.co/cn/start
Elasticsearch : 面向文档数据库,全文搜索引擎, 核心是索引, 在很短的时间内,可以存储,搜索,分析大量的数据。
Kibana: Es的数据可视化操作展示界面工具。
另外: elk 分布式日志收集, e: Elasticsearch(存储), l: logstash(收集日志), k: kibana(展示)
elastjob: 跟xxl-job一样, 分布式任务调度。
2:检查java环境是否安装
java -version
3: 下载后上传至liunx目录: es非常占内存,初始化就是1G, 虚拟机内存需要加大一点。
解压es
tar -zxvf elasticsearch-7.6.0-linux-x86_64.tar.gz
目录介绍:
bin目录:二进制脚本启动es程序文件以及启动es插件目录
config目录:elasticsearch配置文件
data目录:默认Elasticsearch生成的索引/切片数据文件存放目录,可以指定多个位置来存储数据
lib目录:一些开发的jar包
logs目录:elasticsearch日志目录
modules目录:模块目录
plugins目录:elasticsearch插件目录,此版本tar包装后默认无插件
4: 配置修改:
主节点,数据节点, 机器学习节点等节点设置: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html
4.1: 修改ip和端口
进入:elasticsearch-7.6.0/config
修改: vim elasticsearch.yml
放开如下两个参数, ip改为自己服务器的ip, 端口不需要改, 放开就行。
4.2:修改重要系统参数:
内核参数:
vi /etc/security/limits.conf
#加入如下参数, 禁用内存交换必须设置的参数
#nofile文件数
#nproc 线程数
es soft nofile 65536
es hard nofile 65536
es soft nproc 4096
es hard nproc 4096
* hard memlock unlimited
* soft memlock unlimited
或者
* soft nofile 65536
* hard nofile 65536
* soft nproc 32000
* hard nproc 32000
* hard memlock unlimited
* soft memlock unlimited
vim /etc/systemd/system.conf
#修改如下参数, 51,53,54行
DefaultLimitNOFILE=65536
DefaultLimitNPROC=32000
DefaultLimitMEMLOCK=infinity
#让配置生效
systemctl daemon-reexec
虚拟内存:
进入
vim /etc/sysctl.conf
#加入如下参数
vm.max_map_count=262144
//立即生效
sysctl -p /etc/sysctl.conf
5: 创建用户启动Es, 用root是启动不了es的,
can not run elasticsearch as root
添加一个组:
groupadd es
添加一个用户并加入组:
useradd es -g es -p 123456
授权用户和组访问es
chown -R es:es 你的es安装目录(/es/elasticsearch-7.6.0)
切换用户
su es
启动
进入目录
cd /elasticsearch-7.6.0/bin
启动
./elasticsearch
出现如下错误
修改配置文件:
进入
cd elasticsearch-7.6.0/config
编辑:
vim elasticsearch.yml
修改如下两个配置:
节点名称:
初始化主节点:
6:加入开机启动: 在 /etc/init.d/ 目录下创建elasticsearch, 将如下脚本加入到elasticsearch, 目录改为自己的目录
#!/bin/sh
#chkconfig: 23456 80 05
#description: elasticsearch
export JAVA_HOME=/software/jdk1.8.0_181 #(你的jdk目录)
export JAVA_BIN=/software/jdk1.8.0_181/bin #(你的jdk目录)
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME JAVA_BIN PATH CLASSPATH
case "$1" in
start)
su es<<! #(你创建的es账号)
cd /software/es/elasticsearch-7.6.0 #(你的es目录)
./bin/elasticsearch -d
!
echo "elasticsearch startup"
;;
stop)
es_pid=`ps aux|grep elasticsearch | grep -v 'grep elasticsearch' | awk '{print $2}'`
kill -9 $es_pid
echo "elasticsearch stopped"
;;
restart)
es_pid=`ps aux|grep elasticsearch | grep -v 'grep elasticsearch' | awk '{print $2}'`
kill -9 $es_pid
echo "elasticsearch stopped"
su es<<! #(你创建的es账号)
cd /software/es/elasticsearch-7.6.0 #(你的es目录)
./bin/elasticsearch -d
!
echo "elasticsearch startup"
;;
*)
echo "start|stop|restart"
;;
esac
exit $?
赋予执行权限
chmod +x /etc/init.d/elasticsearch
加入开机启动
chkconfig --add elasticsearch
重启 reboot 或者 service elasticsearch start
查看是否启动, 进程是否存在
ps -ef|grep elasticsearch
如果没有正常启动:使用如下命令查看状态
systemctl status elasticsearch
没有成功启动的异常情况:
如下启动异常: 是因为这个目录是root, 需要改为es, 执行: chown -R es:es 你的es安装目录(/es/elasticsearch-7.6.0)
重启后成功开机启动的情况:
防火墙放开端口: 9200 外部访问, 9300es内部访问, 防火墙放开:9200. 切记不要关闭防火墙。
放开端口
firewall-cmd --zone=public --add-port=9200/tcp --permanent
重新加载
firewall-cmd --reload
浏览器访问:出现如下就是es安装成功。
liunx命令访问: curl :
kibana 可视化界面安装:
1: 解压: tar -zxvf kibana-7.6.0-linux-x86_64.tar.gz
2: 修改配置文件:
进入 config 目录
kibana-7.6.0-linux-x86_64/config
编辑 修改kibana.yml中的配置,下图
vim kibana.yml
1.1: 放开如下三个数字行的注释, 修改后保存
第一个: kibana的端口
第二个: 服务器ip地址
第三个:es的IP加端口,
3:启动kibana:
会提示不建议用root用户运行
./kibana
加上 --allow-root
./kibana --allow-root
出现如下入错误,是因为kibana不建议使用root运行, 要使用root 需要加上 --allow-root
出现如下就是启动成功了:
防火墙放开端口 5601, 切记不要直接关闭防火墙。
放开端口
firewall-cmd --zone=public --add-port=5601/tcp --permanent
重新加载
firewall-cmd --reload
浏览器访问: 192.168.xx.xx:5601, 出现如下界面就是成功了。
将kibana加入开机启动:
进入此目录
cd /etc/init.d
创建文件
touch kibana
赋权
chmod +x kibana
编辑
vim kibana
加入如下内容, 目录修改为你自己的安装目录。
#!/bin/bash
# chkconfig: 2345 98 02
# description: kibana
KIBANA_HOME=software/es/kibana-7.6.0-linux-x86_64
case $1 in
start) ./$KIBANA_HOME/bin/kibana --allow-root &;;
*) echo "require start";;
esac
加入开机启动
chkconfig --add kibana
4:重启 reboot 或者 service kibana start
5:查看是否成功自启
ps -ef | grep kibana
reboot后成功自启就可以了。
kibana的操作:
###创建索引
PUT /htcf
###查看索引
GET /htcf
##创建文档, 修改字段值重新执行为修改, cs(类型), 1(Id)主键
##每次操作version就会加1, version乐观锁, 版本控制
##
PUT /htcf/cs/1
{
"name":"tangjiandong",
"age":"28"
}
##version_type=external 检查仓库数据当前的version值是否小于请求中的version值
PUT /htcf/cs/2?version=5&version_type=external
{
"name":"zhansan",
"age":"28"
}
###查看文档
GET /htcf/cs/1
GET /htcf/cs/2
###删除
DELETE /htcf/cs/1
DELETE /htcf
PUT /htcf
GET /htcf
#静态映射
POST /htcf/_mapping/
{
"properties":{
"name":{
"type":"text",
"analyzer":"ik_smart"
},
"age":{
"type":"integer"
}
}
}
GET /htcf/_mapping/
#动态映射,类型自动映射
PUT /htcf/cs/1
{
"name":"tangjiandong",
"age":"28"
}
安装中文分词器插件, es的默认分词器不支持中文分词,使用国人开发的 es-ik插件
安装的es是什么版本就下载什么版本的ik
地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
我装的是7.6.0, 所以就下载下图版本的红色框框的文件。
在es新建一个目录ik解压下载的文件, 或者windows解压文件到一个ik文件夹中上传都可,
上传至es的目录: elasticsearch-7.6.0/plugins/
重启es.
systemctl stop elasticsearch
systemctl start elasticsearch
从日志中发现已经加载ik插件
测试中文分词器:
analyzer: standard 默认 改为: "analyzer":"ik_smart",
自定义添加扩展热词:
进入:
elasticsearch-7.6.0/plugins/ik/config/
新建一个目录:
创建文件夹
mkdir insert
赋权
chmod -R 7775 insert
复制文件
cp extra_main.dic new_word.dic
移动文件到新建文件夹
mv new_word.dic insert/
编辑文件
vim new_word.dic
加入如下内容
王者农药
王者荣耀
保存退出:wq
进入:如下目录
elasticsearch-7.6.0/plugins/ik/config
打开:
vim IKAnalyzer.cfg.xml
在ext_dict:尖括号中加入新增的目录和文件地址:
insert/new_word.dic
重启es.
进入es bin目录
cd elasticsearch-7.6.0/bin
elasticsearch stop
elasticsearch start
重启后日志中显示已加载 新建的热词文件。
测试新建的热词:
之前:
之后:
集群搭建:
es集群: 在单台es节点上, 随着业务的发展, 数据越来越大, 索引文件慢慢增多, 会影响查询效率及硬盘内存的存储。
es本来就是一个分布式全文检索框架,隐藏了复杂的处理机制,内部使用, 分片机制,集群发现,分片负载均衡请求路由。
es集群分片机制:
es分为主分片与副分片, 一个主分片对应一个副分片, 主分片数量定义好之后, 不能修改, 否则会导致数据查询不到。
因为es数据请求路由使用的是取余算法。 分片位置 = hash(id) % 主分片数量。 当主分片数量改变时,位置就会变化。
主分片对应的副分片不能同时存储在一台节点上, 副分片的作用是当节点损坏或者丢失时恢复数据用的。 存储在一台节点就
失去了副分片的作用。
当有多台节点时, es会自动水平扩展。但是主分片数量在一开时就固定了, 所以需要修改副分片的数量。
什么是分片: 一份索引数据拆分成多份存储在不同的节点山。
在三台虚拟机上装上es, 修改每台es的参数:
注意: 搭建集群时: 防火墙一定要开放9200与9300, 忘记开一个端口找了好久没找问题, 后面才发现端口没开放。
firewall-cmd --zone=public --add-port=9200/tcp --permanent
firewall-cmd --zone=public --add-port=9300/tcp --permanent
firewall-cmd --reload
vim elasticsearch-7.6.0/config/elasticsearch.yml 修改如下参数
# ======================== 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: elastic
#
# ------------------------------------ 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: /path/to/data
#
# Path to log files:
#
#path.logs: /path/to/logs
#
# ----------------------------------- 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 -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
# 局域网IP或者外网ip
#
network.host: 192.168.xx.xx
#
# Set a custom port for HTTP:
# http访问端口
#
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]"]
# 集群机器IP
#
discovery.seed_hosts: ["192.168.xx.xx", "192.18.xx.xx","192.168.xx.xx"]
#
# Bootstrap the cluster using an initial set of master-eligible nodes:
# 集群初始化主节点
#
cluster.initial_master_nodes: ["node-1", "node-2","node-3"]
首先启动主节点。 也就是:cluster.initial_master_nodes 配置的 node-1
node-1 主节点启动: 为 master, leader
node-2节点启动:显示节点已更改
node-1主节点会显示node-2节点已加入集群。
node-3 节点启动:显示节点已更改
node-1节点显示 node-3节点已加入集群。
查看集群节点状态
你的IP
http://192.168.xx.xx:9200/_cat/nodes?pretty
带*的节点为主节点。
把节点node-1 杀死后, node-2节点2被选举为主节点,
查看集群状态:
http://192.168.xx.xx:9200/_cluster/state?pretty
chrom 谷歌浏览器安装 ElasticSearch Head 可视化工具:
chrom 插件下载安装: 我上传至csdn了, 不需要梯子: 在地址栏输入:chrome://extensions/, 加载解压的文件夹就可以了。
csdn下载地址: https://download.csdn.net/download/tang_jian_dong/12411183
ch'ro'm 插件方式安装: 地址栏输入如下地址, 需要梯子才能访问
安装好后, 浏览器右上角点击 Elasticseach Head 就出现如下页面了。
地址栏输入es地址:
集群健康状态:
- green
最健康得状态,说明所有的分片包括备份都可用 - yellow
基本的分片可用,但是备份不可用(或者是没有备份) - red
部分的分片可用,表明分片有一部分损坏。此时执行查询部分数据仍然可以查到,遇到这种情况,还是赶快解决比较好
nginx http代理配置三台节点:
#配置你的节点IP
upstream service-es{
#ip_hash;
server 192.168.xx.xx:9200 weight=3;
server 192.168.xx.xx:9200 weight=1;
server 192.168.xx.xx:9200 weight=1;
check interval=3000 rise=1 fall=3 timeout=1000 type=http;
check_http_send "OPTIONS /es/ HTTP/1.0\r\n\r\n";
}
server {
listen 8080 default;
#listen 443 ssl;
server_name localhost;
client_max_body_size 100M;
charset utf-8;
#charset koi8-r;
#access_log logs/host.access.log main;
#打开目录浏览,这样当没有找到index文件,就也已浏览目录中的文件
autoindex on;
#防止nginx做web服务的时候,多server_name的问题
server_name_in_redirect off;
location /{
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
proxy_set_header REMONTE-HOST $remote_addr;
proxy_set_header Host $host;
proxy_pass http://service-es;
index index.html;
}
nginx访问:
nginx tcp 代理: 监听9400端口
使用默认的 健康检查, max_fails, 被动检查, 如需主动检查,需要安装 nginx_plus, 为商业版, health_check 检查
stream{
upstream tcp_es{
zone tcp_es 64k;
server 192.168.xx.xx:9300 weight=3 max_fails=2 fail_timeout=5s;
server 192.168.xx.xx:9300 weight=1 max_fails=2 fail_timeout=5s;
server 192.168.xx.xx:9300 weight=1 max_fails=2 fail_timeout=5s;
}
server {
listen 9400;
#listen 443 ssl;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass tcp_es;
#interval– NGINX Plus发送健康检查请求的频率(以秒为5 单位)(默认为秒)
#passes–服务器必须响应才能被视为健康的连续健康检查次数(默认为 1)
#fails–服务器必须不响应才能被视为不健康的连续健康检查次数(默认为 1)
#health_check interval=10 passes=2 fails=3;
}
}
如下图为 springboot 连接 9400.
springboot 整合es:
项目git地址: https://github.com/joranbo/Springboot-elasticsearch
如下图片显示: springboot的es客户端版本太低,最少需要6.8.0.
spring-boot-starter-data-elasticsearch 依赖包的官方api地址:
https://docs.spring.io/spring-data/elasticsearch/docs/4.0.0.RC2/reference/html/#reference
版本对应:
springboot pom.xml 依赖:
pom.xml 中 elasticsearch 的客户端版本与 服务器安装的版本需要对应。
客户端依赖
服务器安装版本:
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 解决unknow error 错误 -->
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- undertow 替代tomcat, 短连接, 高并发下性能比tomcat好, 基于NIO开发。 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- elasticsreah 客户端 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- freemarker 前端展示, 或者jsp -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 阿里巴巴json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
<profiles>
<profile>
<properties>
<maven.complier.encoding>UTF-8</maven.complier.encoding>
<project.bulid.sourceEncoding>UTF-8</project.bulid.sourceEncoding>
</properties>
</profile>
</profiles>
<build>
<plugins>
<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
项目总览:
model: TestPo
package com.tang.es.model;
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.stereotype.Component;
/**
* ClassName: TestPo
* Function: TODO ADD FUNCTION.
* date: 2020年5月6日 下午3:44:51
*
* @author tangjiandong
*
* shards 主分片数量
* replicas 副分片数量
*
* 7.x 版本移除了type
*/
@Document(indexName="testpo", shards=5, replicas=2)
public class TestPo implements Serializable{
/**
* serialVersionUID:(用一句话描述这个变量表示什么).
*/
private static final long serialVersionUID = 1L;
@Id
@Field(type = FieldType.Keyword, index = false)
private String id;
@Field(type = FieldType.Text, analyzer="ik_smart", searchAnalyzer="ik_smart")
private String name;
@Field(type = FieldType.Integer)
private int age;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
/**
* @return
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
/**
* @param obj
* @return
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TestPo other = (TestPo) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
/**
* @return
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "TestPo [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
dao: TestDao
package com.tang.es.dao;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import com.tang.es.model.TestPo;
/**
* ClassName: TestDao
* Function: TODO ADD FUNCTION.
* date: 2020年5月6日 下午3:47:26
*
* @author tangjiandong
*/
@Component
public interface TestDao extends CrudRepository<TestPo, String>{
/**
* findByName, 会计算分页参数, 比较耗性能
* (返回分页数据)
*
* @param name 参数
* @param pageable 分页参数, pageable 包含 sort排序字段。传入排序参数就行
* @return
*/
Page<TestPo> findByName(String name, Pageable pageable);
/**
*
* (返回slice类型数据) 不会计算分页参数, 性能比较好
*
* @param name
* @param pageable
* @return
*/
//Slice<TestPo> findByName(String name, Pageable pageable);
/**
*
* (排序)
*
* @param lastname
* @param sort 排序参数
* @return
*/
List<TestPo> findByName(String name, Sort sort);
/**
*
* (分页参数返回list数据)
*
* @param lastname
* @param pageable
* @return
*/
//List<TestPo> findByName(String name, Pageable pageable);
}
serviceImpl: TestServiceImpl , 这里没定义 service, 提供服务是必须写 service。
package com.tang.es.serviceImpl;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.EscapedErrors;
import com.tang.es.dao.TestDao;
import com.tang.es.model.TestPo;
/**
* ClassName: TestServiceImpl
* Function: TODO ADD FUNCTION.
* date: 2020年5月6日 下午3:48:17
*
* @author tangjiandong
*/
@Service("testService")
public class TestServiceImpl {
@Autowired
private TestDao testDao;
/**
* addTestPo
* (保存对象)
*
* @param testPo 参数对象
* @return
* @throws Exception
*/
public TestPo save(TestPo testPo)throws Exception
{
return testDao.save(testPo);
}
/**
* deleteById
* (根据id删除)
*
* @param id
* @throws Exception
*/
public void deleteById(String id)throws Exception
{
testDao.deleteById(id);
}
/**
* selectTestPo
* (查询对象)
*
* @param testPo 参数对象
* @return
* @throws Exception
*/
public Optional<TestPo> findById(String id)throws Exception
{
return testDao.findById(id);
}
/**
* findByName, 会计算分页参数, 比较耗性能
* (返回分页数据)
*
* @param name 参数
* @param pageable 分页参数
* @return
*/
public Page<TestPo> findByName(String name, Pageable pageable)throws Exception
{
return testDao.findByName(name, pageable);
}
}
controller: TestController ,
package com.tang.es.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tang.es.model.TestPo;
import com.tang.es.serviceImpl.TestServiceImpl;
import com.tang.es.utils.ActionResult;
import com.tang.es.utils.ActionResult.ActionResultBuilder;
import com.tang.es.utils.ActionResult.ActionResultStatus;
/**
* ClassName: TestController
* Function: TODO ADD FUNCTION.
* date: 2020年5月6日 下午3:55:06
*
* @author tangjiandong
*/
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private TestServiceImpl testService;
/**
* addTestPo
* (保存对象)
*
* @param testPo 参数对象
* @return
* @throws Exception
*/
@RequestMapping("/addTestPo")
public String addTestPo(TestPo testPo)
{
ActionResult ar = ActionResult.success().build();
if(StringUtils.isEmpty(testPo))
{
ar.setErrorCode(ActionResultStatus.valueOf(ActionResultStatus.VALIDATE_ERROR.getReasonPhrase()).getStatusCode());
ar.setErrorMsg("校验异常,参数为空!");
return JSON.toJSONString(ar);
}
try {
testService.save(testPo);
} catch (Exception e) {
e.printStackTrace();
ar.setErrorCode(ActionResultStatus.valueOf(ActionResultStatus.BUSINESS_ERROR.getReasonPhrase()).getStatusCode());
ar.setErrorMsg("数据保存异常,请检查数据问题!");
}
return JSON.toJSONString(ar);
}
/**
* deleteById
* (根据id删除)
*
* @param id
* @return
*/
@RequestMapping("/deleteById")
public String deleteById(String id)
{
ActionResult ar = ActionResult.success().build();
if(StringUtils.isEmpty(id))
{
ar.setErrorCode(ActionResultStatus.valueOf(ActionResultStatus.VALIDATE_ERROR.getReasonPhrase()).getStatusCode());
ar.setErrorMsg("校验异常,参数为空!");
return JSON.toJSONString(ar);
}
try {
testService.deleteById(id);
} catch (Exception e) {
e.printStackTrace();
ar.setErrorCode(ActionResultStatus.valueOf(ActionResultStatus.BUSINESS_ERROR.getReasonPhrase()).getStatusCode());
ar.setErrorMsg("数据删除异常!");
}
return JSON.toJSONString(ar);
}
/**
* findByName
* (根据分页参数查询分页数据)
*
* @param name
* @param pageable
* @return
*/
@RequestMapping("/findByName")
public String findByName(String name, Pageable pageable)
{
ActionResult ar = ActionResult.success().build();
if(StringUtils.isEmpty(name) || StringUtils.isEmpty(pageable))
{
ar.setErrorCode(ActionResultStatus.valueOf(ActionResultStatus.VALIDATE_ERROR.getReasonPhrase()).getStatusCode());
ar.setErrorMsg("校验异常,参数为空!");
return JSONObject.toJSON(ar).toString();
}
try {
Page<TestPo> findByName = testService.findByName(name, pageable);
ar.setData(findByName);
} catch (Exception e) {
e.printStackTrace();
ar.setErrorCode(ActionResultStatus.valueOf(ActionResultStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()).getStatusCode());
ar.setErrorMsg(ActionResultStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
}
return JSONObject.toJSON(ar).toString();
}
/**
* findById
* (查询对象)
*
* @param id id
* @return
* @throws Exception
*/
@RequestMapping("/findById")
public String findById(String id)
{
ActionResult ar = ActionResult.success().build();
if(StringUtils.isEmpty(id))
{
ar.setErrorCode(ActionResultStatus.valueOf(ActionResultStatus.VALIDATE_ERROR.getReasonPhrase()).getStatusCode());
ar.setErrorMsg("校验异常,参数为空!");
return JSON.toJSONString(ar);
}
try {
Optional<TestPo> findById = testService.findById(id);
ar.setData(findById.get());
} catch (Exception e) {
e.printStackTrace();
ar.setErrorCode(ActionResultStatus.valueOf(ActionResultStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()).getStatusCode());
ar.setErrorMsg(ActionResultStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
}
return JSON.toJSONString(ar);
}
}
utils: ActionResult, 这里只有部分代码
/**
* ActionResultStatus
* ClassName: ActionResultStatus
* Function: 状态枚举
* date: 2020年5月9日 下午5:27:24
*
* @author tangjiandong
*/
public enum ActionResultStatus
{
/**
* 成功
*/
SUCCESS(200, "SUCCESS"),
/**
* 服务器内部错误
*/
INTERNAL_SERVER_ERROR(500, "INTERNAL_SERVER_ERROR"),
/**
* 业务异常
*/
BUSINESS_ERROR(501, "BUSINESS_ERROR"),
/**
* 校验异常
*/
VALIDATE_ERROR(502, "VALIDATE_ERROR"),
/**
* 错误请求
*/
BAD_REQUEST(400, "BAD_REQUEST"),
/**
* 不可接收
*/
NOT_ACCEPTABLE(406, "NOT_ACCEPTABLE"),
/**
* 没有权限
*/
UNAUTHORIZED(401, "UNAUTHORIZED"),
/**
* 没有登录
*/
NOT_LOGIN(4010, "NOT_LOGIN"),
/**
* 禁止
*/
FORBIDDEN(403, "FORBIDDEN");
/**
* 状态代码
*/
private final int code;
/**
* 原因描述
*/
private final String reason;
ActionResultStatus(final int statusCode, final String reasonPhrase)
{
this.code = statusCode;
this.reason = reasonPhrase;
}
/**
* @return the code
*/
public int getStatusCode()
{
return code;
}
public String getReasonPhrase()
{
return toString();
}
@Override
public String toString()
{
return reason;
}
/**
*
* (通过code查找对象)
*
* @param code
* @return
*/
public static ActionResultStatus fromStatusCode(final int code)
{
for (ActionResultStatus s : ActionResultStatus.values())
{
if(s.code == code)
{
return s;
}
}
return null;
}
}
main: Main
package com.tang.es;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* ClassName: Main
* Function: TODO ADD FUNCTION.
* date: 2020年5月6日 下午3:59:51
*
* @author tangjiandong
*/
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
application: application.yml
spring:
elasticsearch:
rest:
uris: 192.168.xx.xx:8080 #es 7 不推荐使用TransportClient, 将在es8删除, 推荐使用 REST Client, 这里连接的是上面nginx代理的es集群ip与端口
connection-timeout: 5
freemarker:
# 设置模板后缀名
suffix: .ftl
# 设置文档类型
content-type: text/html
# 设置页面编码格式
charset: UTF-8
# 设置页面缓存
cache: false
# 设置ftl文件路径
template-loader-path:
- classpath:/templates
# 设置静态文件路径,js,css等
mvc:
static-path-pattern: /static/**
server:
port: 80
# Undertow 日志存放目录
undertow:
accesslog:
dir:
enabled: false # 是否启动日志
pattern: common # 日志格式
prefix: access_log # 日志文件名前缀
suffix: log # 日志文件名后缀
max-http-post-size: 0 # HTTP POST请求最大的大小
io-threads: 4 # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
worker-threads: 20 # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
buffer-size: 1024 # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理, 每块buffer的空间大小,越小的空间被利用越充分
buffers-per-region: 1024 # 每个区分配的buffer数量 , 所以pool的大小是buffer-size * buffers-per-region
direct-buffers: true # 是否分配的直接内存
增 :
查:
分页查:
删:
kibana: