一、需求二、设计
1、背景2、思路 三、Java代码实现四、DSL表达式五、前端拼接 DSL 字符串六、Java使用ES查询DSL字符串七、通过 Apifox 测试八、前端展示效果
一、需求1、实现一个搜索框,可以实现所有的字段的查询,并且每个字段可以支持不同的查询方式
如下图所示
2、点击任何一个字段,弹出该字段支持的查询方式
由于项目是前后端分离项目,这里就需要前端的配合
由于我们的数据库选择是 mysql+es
今天这篇文章主要是使用es进行业务查询
如何获取该表的所有列字段?如果根据字段类型给与对应的查询条件?
这里我是使用 Java开发的,所以第一点直接想到的就是使用反射
实现思路
首先需要将所有列表,创建对应的实体类(即:每一列对应实体每个字段)然后前端传入具体为哪一个类的类型,通过反射获取其所有字段名然后我们这里会根据字段的数据类型,决定使用的判断方式(即:string:使用 “=”, “!=”, “:”, “!:” )最后组装数据返回前端前端使用 DSL 表达式 ,拼接 DSL字符串回传java进行查询Java根据DSL表达式查询 并返回结果 三、Java代码实现
这里定义了2种判断条件
STRING = {"=", “!=”, “:”, “!:”};OTHER = {"=", “>”, “<”, “!=”};
@Slf4j
@Service("AwsScanService")
public class AwsScanServiceImpl implements AwsScanService {
// string 类型下
private static final String[] STRING = {"=", "!=", ":", "!:"};
// 非 string 类型下
private static final String[] OTHER = {"=", ">", "<", "!="};
@Override
public R getScanSearchFields(ScanBasicVo index) {
Class cls = getObject(index.getServiceId());
log.info("获取当前对象的类型为:" + cls);
Field[] fields = cls.getDeclaredFields();
Map res = new HashMap<>();
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
f.setAccessible(true);
try {
//f.getName()得到对应字段的属性名,f.get(o)得到对应字段属性值,f.getGenericType()得到对应字段的类型
log.info("属性名:" + f.getName() + ";字段类型:" + f.getGenericType());
if ("class java.lang.String".equals(f.getGenericType())) {
res.put(f.getName(), STRING);
}
res.put(f.getName(), OTHER);
} catch (IllegalArgumentException e) {
e.printStackTrace();
log.info("ReflectUtil error:" + e.toString());
}
}
return R.ok().put("data", res);
}
private Class getObject(int serviceId) {
switch (serviceId) {
case 1:
return AwsDynamodbVo.class;
case 2:
return AwsEc2CompareVo.class;
case 3:
return AwsEc2Vo.class;
case 4:
return AwsElasticacheVo.class;
case 5:
return AwsIAMVo.class;
case 6:
return AwsOpensearchVo.class;
case 7:
return AwsRdsVo.class;
case 8:
return AwsRiVo.class;
case 9:
return AwsS3Vo.class;
case 10:
return AwsVpcVo.class;
}
return null;
}
}
具体的对应的每个vo就不在这里一一展示了
下面来看一下最后的执行返回结果
{
"msg": "success",
"code": 20000,
"data": {
"dyTableName": [
"=",
">",
"<",
"!="
],
"tableStatus": [
"=",
">",
"<",
"!="
],
"tableSizeBytes": [
"=",
">",
"<",
"!="
],
"itemCount": [
"=",
">",
"<",
"!="
]
}
}
四、DSL表达式
# 等于
GET /aws_1_1_ec2/_search
{
"query": {
"match": {
"instanceName": "unipus-ucont-apiworker102"
}
}
}
# 不等于
GET /aws_1_1_ec2/_search
{
"query": {
"bool": {
"must_not": {
"term": {
"instanceName": "unipus-ucont-apiworker102"
}
}
}
}
}
# 模糊查询
GET /aws_1_1_ec2/_search
{
"query": {
"wildcard": {
"instanceName":{
"value":"*ucont*"
}
}
}
}
# 不包含
GET aws_1_1_ec2/_search
{
"query":{
"bool" : {
"must_not" : {
"wildcard" : {
"type" : "*c4*"
}
}
}
}
}
# 范围内查询
GET /aws_1_1_ec2/_search
{
"query": {
"bool": {
"must": {
"range": {
"cpuMax": {
"gte": 15,
"lte": 18
}
}
}
}
}
}
# 多关系查询
GET aws_1_1_ec2/_search
{
"query": {
"bool": {
"should": [
{
"wildcard": {
"type": "*c5*"
}
},
{
"bool": {
"must_not": [
{
"wildcard": {
"vpcName": {
"value": "*Test*"
}
}
}
]
}
}
]
}
}
}
五、前端拼接 DSL 字符串
这里需要注意,java接收的dsl字符串不能包含最外层的 「query」关键字
比如上面的DSL查询转化为字符串
"{ “match”:{ “platform”:“windows” } } "
这里目前还没有给前端找到更好的插件,也欢迎在前端拼接过DSL的朋友留言!!!
六、Java使用ES查询DSL字符串查询dsl字符串查询es的方法
@PostMapping("/dsl/query")
public PageUtils queryDslToEs(@RequestBody ScanCommonVo scanCommonVo) throws IOException {
String dsl = scanCommonVo.getDsl();
String index = scanCommonVo.getIndex();
//分页
long curPage = scanCommonVo.getPage() == 0 ? 1 : scanCommonVo.getPage();
long limit = scanCommonVo.getLimit() == 0 ? 10 : scanCommonVo.getLimit();
// 返回结果
List
传入的vo
@Data
public class ScanCommonVo extends BasicVo {
@NotBlank(message = "dsl 表达式不能为空")
private String dsl;
@NotBlank(message = "索引")
private String index;
}
@Data
@ApiModel(description = " aws 基类")
public class BasicVo {
@ApiModelProperty(value = "当前页索引")
private Long page;
@ApiModelProperty(value = "每页大小")
private Long limit;
}
七、通过 Apifox 测试
关键词查询与分页查询都ok



