elasticsearch 结合 mybatis 动态拼接dsl

一、简单结构,没有业务层

elasticsearch 结合 mybatis 动态拼接dsl

二、pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cfl</groupId>
    <artifactId>MybatisElasticsearch</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <slf4j-version>1.7.19</slf4j-version>
        <log4j-version>1.2.17</log4j-version>
        <elasticsearch.version>6.4.2</elasticsearch.version>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
        <!-- mybatis和spring的集成包 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- 阿里巴巴开发的数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>0.2.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <!-- io工具 -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
        <!-- poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.9</version>
        </dependency>
        <!-- es -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
    </dependencies>
</project>

三、配置

1、MyBatisConfig

package com.cfl.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import com.alibaba.druid.pool.DruidDataSource;

@Configuration
public class MyBatisConfig {

	@Bean(destroyMethod="close")
	public DruidDataSource dataSource() {
		DruidDataSource dataSource = new DruidDataSource();
		return dataSource;
	}

	@Bean
	public SqlSessionFactoryBean sqlSessionFactory() throws Exception {
		// 设置数据源
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource());

		// 设置mybatis的主配置文件
		sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/cfl/dao/*.xml"));
		return sqlSessionFactoryBean;
	}
}

2、MapperScannerConfig

package com.cfl.config;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@AutoConfigureAfter(MyBatisConfig.class) //保证在MyBatisConfig实例化之后再实例化该类
public class MapperScannerConfig {

	@Bean
	public MapperScannerConfigurer mapperScannerConfigurer() throws Exception {
		MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
		mapperScannerConfigurer.setBasePackage("com.cfl.dao");
		return mapperScannerConfigurer;
	}
}

3、EsRestClientConfig

package com.cfl.config;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.util.Arrays;
import java.util.Objects;

@Configuration
@PropertySource(value={"classpath:config.properties"})
public class EsRestClientConfig {
    private static final int ADDRESS_LENGTH = 2;
    private static final String HTTP_SCHEME = "http";

    /**
     * 使用冒号隔开ip和端口1
     */
    @Value("${elasticsearch.ip}")
    String[] ipAddress;

    @Bean
    public RestClientBuilder restClientBuilder() {
        HttpHost[] hosts = Arrays.stream(ipAddress)
                .map(this::makeHttpHost)
                .filter(Objects::nonNull)
                .toArray(HttpHost[]::new);
        return RestClient.builder(hosts);
    }

    private HttpHost makeHttpHost(String s) {
        assert StringUtils.isNotEmpty(s);
        String[] address = s.split(":");
        if (address.length == ADDRESS_LENGTH) {
            String ip = address[0];
            int port = Integer.parseInt(address[1]);
            return new HttpHost(ip, port, HTTP_SCHEME);
        } else {
            return null;
        }
    }
}

4、EsUtil

package com.cfl.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.cfl.model.base.BaseModel;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.session.SqlSessionFactory;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class EsUtil {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @Autowired
    private RestClient restClient;

    /**
     * 获取es数据
     * @param tableName 表名称
     * @param mappedStatement mybatis 中的方法(包名.方法名) 如:com.cfl.dao.UserDao.findByName
     * @param paramMap 参数
     * @return
     * @throws Exception
     */
    public BaseModel getEsData(String tableName, String mappedStatement, Map<String, Object> paramMap) throws Exception {
        // 通过mybatis动态获取dsl
        BoundSql bSql = sqlSessionFactory.getConfiguration().getMappedStatement(mappedStatement).getBoundSql(paramMap);
        List<ParameterMapping> paramValues = bSql.getParameterMappings();
        String sql = getEsSql(bSql.getSql(),paramValues,paramMap);
        System.out.println("sql: \n" + sql);

        // 通过dsl查询es
        String method = "GET";
        String endpoint = "/"+tableName+"/_search";
        HttpEntity entity = new NStringEntity(sql, ContentType.APPLICATION_JSON);
        Response response = restClient.performRequest(method, endpoint, Collections.emptyMap(), entity);
        String responseJson = EntityUtils.toString(response.getEntity()).replace("WHERE","");
        BaseModel<HashMap<String,Object>> baseModel = JSON.parseObject(responseJson, new TypeReference<BaseModel<HashMap<String,Object>>>(){});
        return baseModel;
    }

    /**
     * 获取可执行sql
     * @param sql 获取的sql
     * @param paramValues 动态参key
     * @param map 动态参valur
     * @return
     */
    private String getEsSql(String sql, List<ParameterMapping> paramValues,Map map) {
        while(sql.indexOf("?") != -1 && paramValues.size() > 0) {
            String paramName = paramValues.get(0).getProperty();
            String paramValue = map.get(paramName).toString();
            String value = "";
            if (paramValue instanceof String) {
                value = "'" + paramValue + "'";
            }
            sql = sql.replaceFirst("\\?", value);
            paramValues.remove(0);
        }
        return sql.replaceAll("[\\s\\t\\n\\r]", "").replace("'","\"").replace(",}","}").replace(",]","]");
    }
}

5、application.yml

server:
  port: 9010
  servlet:
    context-path: /
spring:
  thymeleaf:
  cache: false

6、config.properties

hibernate.dialect=org.hibernate.dialect.MySQLDialect
driverClassName=com.mysql.jdbc.Driver
validationQuery=SELECT 1
elasticsearch.ip=localhost:9200

五、模型:get、set因太长没有展示出来,需自己添加

1、BaseHits

public class BaseHits<T> {
    private String _index;
    private String _type;
    private String _id;
    private Integer _score;
    private T _source;
}

2、BaseHitsCount

public class BaseHitsCount<T> {
    private Integer total;
    private Integer max_score;
    private List<BaseHits<T>> hits;
}

3、BaseModel

public class BaseModel<T> {
    private Integer took;
    private Boolean timed_out;
    private BaseShards _shards;
    private BaseHitsCount<T> hits;

    /**
     * 获取返回内容
     * @return
     */
    public List<T> getContent() {
        List<T> list = new ArrayList<T>();
        for(BaseHits<T> hits : this.hits.getHits()) {
            list.add(hits.get_source());
        }
        return list;
    }
}

4、BaseShards

public class BaseShards {
    private Integer total;
    private Integer successful;
    private Integer skipped;
    private Integer failed;
}

5、User

public class User {
    private Integer id;
    private String name;
    private String password;
    private String head;
    private String jobNumber;
    private Integer roleId;
    private Integer status;
    private Date createDate;
}

六、其它

1、TestController

package com.cfl.controller;

import com.cfl.model.base.BaseModel;
import com.cfl.util.EsUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping(value = "/test/")
public class TestController {

    @Autowired
    private EsUtil esUtil;

    @RequestMapping(value = "list")
    public Object test(String oid, String pno, String source, String ios, Integer size) {
        try {
            Map<String, Object> paramMap = new HashMap<String,Object>();
            if(StringUtils.isNotEmpty(oid)) {
                paramMap.put("oid",oid);
            }
            if(StringUtils.isNotEmpty(pno)) {
                paramMap.put("pno",pno);
            }
            if(StringUtils.isNotEmpty(source)) {
                paramMap.put("source",source);
            }
            if(StringUtils.isNotEmpty(ios)) {
                paramMap.put("ios",ios);
            }
            paramMap.put("size",size);
            BaseModel baseModel = esUtil.getEsData("user_log","com.cfl.dao.UserDao.findByName",paramMap);
            return baseModel.getContent();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}

2、UserDao

package com.cfl.dao;

import com.cfl.model.User;
import org.apache.ibatis.annotations.Param;

public interface UserDao {
    User findByName(@Param("name") String name);
}

3、UserDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.cfl.dao.UserDao" >
  <select id="findByName" parameterType="java.lang.String">
    {
      <if test="size != null">"size": #{size},</if>
      <if test="size == null">"size": 10,</if>
      "query": {
        "bool": {
          "must": [
            <if test="oid != null">{"match": {"oid": #{oid}}},</if>
            <if test="pno != null">{"match": {"pno": #{pno}}},</if>
            <if test="source != null">{"match": {"source": #{source}}},</if>
            <if test="ios != null">{"match": {"ios": #{ios}}},</if>
          ]
        }
      }
    }
  </select>
</mapper>

4、App

package com.cfl;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
@ComponentScan(basePackages = {"com.cfl"})
public class App 
{
	public static void main(String[] args) throws Exception {
		SpringApplication.run(App.class, args);
	}
}

 

上一篇:python| Django Elasticsearch DSL


下一篇:使用switch表达式简化switch语句