Centos7 Elasticsearch7.6 + Kibana + elasticsearch-head 搭建集群与全文检索, 及springboot项目整合es增删改查

环境基于 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

 

 

 

官方配置地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html#path-settings

 

 

 

 

        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:

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值