上篇我们讲到了 Elasticsearch 全文检索的原理《别只会搜日志了,求你懂点原理吧》,通过在本地搭建一套 ES 服务,以多个案例来分析了 ES 的原理以及基础使用。这次我们来讲下 Spring Boot 中如何整合 ES,以及如何在 Spring Cloud 微服务项目中使用 ES 来实现全文检索,来达到搜索题库的功能。
而且题库的数据量是非常大的,题目的答案也是非常长的,通过 ES 正好可以解决 mysql 模糊搜索的低效性。
(资料图片)
通过本实战您可以学到如下知识点:
Spring Boot 如何整合 ES。微服务中 ES 的 API 使用。项目中如何使用 ES 来达到全文检索。本篇主要内容如下:
本文案例都是基于 PassJava 实战项目来演示的。
:+1:Github 地址:https://github.com/Jackson0714/PassJava-Platform
在讲解之前,我在这里再次提下全文检索是什么:
全文检索:指以全部文本信息作为检索对象的一种信息检索技术。而我们使用的数据库,如 Mysql,MongoDB 对文本信息检索能力特别是中文检索并没有 ES 强大。所以我们来看下 ES 在项目中是如何来代替 SQL 来工作的。
我使用的 Elasticsearch 服务是 7.4.2 的版本,然后采用官方提供的 Elastiscsearch-Rest-Client 库来操作 ES,而且官方库的 API 上手简单。
该组件库的官方文档地址:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html
另外这个组件库是支持多种语言的:
注意:Elasticsearch Clients
就是指如何用 API 操作 ES 服务的组件库。
可能有同学会提问,Elasticsearch 的组件库中写着 JavaScript API,是不是可以直接在前端访问 ES 服务?可以是可以,但是会暴露 ES 服务的端口和 IP 地址,会非常不安全。所以我们还是用后端服务来访问 ES 服务。
我们这个项目是 Java 项目,自然就是用上面的两种:Java Rest Client
或者 Java API
。我们先看下 Java API,但是会发现已经废弃了。如下图所示:
所以我们只能用 Java REST Client 了。而它又分成两种:高级和低级的。高级包含更多的功能,如果把高级比作MyBatis的话,那么低级就相当于JDBC。所以我们用高级的 Client。
我们把检索服务单独作为一个服务。就称作 passjava-search 模块吧。
首先我们在 PassJava-Platform 模块创建一个 搜索服务模块 passjava-search。然后勾选 spring web 服务。如下图所示。
第一步:选择 Spring Initializr,然后点击 Next。
第二步:填写模块信息,然后点击 Next。
第三步:选择 Web->Spring Web 依赖,然后点击 Next。
进入到 ES 官方网站,可以看到有低级和高级的 Rest Client,我们选择高阶的(High Level Rest Client)。然后进入到高阶 Rest Client 的 Maven 仓库。官网地址如下所示:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.9/index.html
对应文件路径:\passjava-search\pom.xml
org.elasticsearch.client elasticsearch-rest-high-level-client 7.4.2
配置 elasticsearch 的版本为7.4.2因加上 Maven 依赖后,elasticsearch 版本为 7.6.2,所以遇到这种版本不一致的情况时,需要手动改掉。
对应文件路径:\passjava-search\pom.xml
7.4.2
刷新 Maven Project 后,可以看到引入的 elasticsearch 都是 7.4.2 版本了,如下图所示:
Common 模块是 PassJava 项目独立的出来的公共模块,引入了很多公共组件依赖,其他模块引入 Common 模块依赖后,就不需要单独引入这些公共组件了,非常方便。
对应文件路径:\passjava-search\pom.xml
com.jackson0714.passjava passjava-common 0.0.1-SNAPSHOT
添加完依赖后,我们就可以将搜索服务注册到 Nacos
注册中心了。 Nacos 注册中心的用法在前面几篇文章中也详细讲解过,这里需要注意的是要先启动 Nacos 注册中心,才能正常注册 passjava-search 服务。
修改配置文件:src/main/resources/application.properties。配置应用程序名、注册中心地址、注册中心的命名中间。
spring.application.name=passjava-searchspring.cloud.nacos.config.server-addr=127.0.0.1:8848spring.cloud.nacos.config.namespace=passjava-search
给启动类
添加服务发现注解:@EnableDiscoveryClient
。这样 passjava-search 服务就可以被注册中心发现了。
因 Common 模块依赖数据源,但 search 模块不依赖数据源,所以 search 模块需要移除数据源依赖:
exclude = DataSourceAutoConfiguration.class
以上的两个注解如下所示:
@EnableDiscoveryClient@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)public class PassjavaSearchApplication { public static void main(String[] args) { SpringApplication.run(PassjavaSearchApplication.class, args); }}
接下来我们添加一个 ES 服务的专属配置类,主要目的是自动加载一个 ES Client 来供后续 ES API 使用,不用每次都 new 一个 ES Client。
配置类:PassJavaElasticsearchConfig.java
核心方法就是 RestClient.builder 方法,设置好 ES 服务的 IP 地址、端口号、传输协议就可以了。最后自动加载了 RestHighLevelClient。
package com.jackson0714.passjava.search.config;import org.apache.http.HttpHost;import org.elasticsearch.client.RestClient;import org.elasticsearch.client.RestHighLevelClient;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @Author: 公众号 | 悟空聊架构 * @Date: 2020/10/8 17:02 * @Site: www.passjava.cn * @Github: https://github.com/Jackson0714/PassJava-Platform */@Configurationpublic class PassJavaElasticsearchConfig { @Bean // 给容器注册一个 RestHighLevelClient,用来操作 ES // 参考官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.9/java-rest-high-getting-started-initialization.html public RestHighLevelClient restHighLevelClient() { return new RestHighLevelClient( RestClient.builder( new HttpHost("192.168.56.10", 9200, "http"))); }}
接下来我们测试下 ES Client 是否自动加载成功。
在测试类 PassjavaSearchApplicationTests 中编写测试方法,打印出自动加载的 ES Client。期望结果是一个 RestHighLevelClient 对象。
package com.jackson0714.passjava.search;import org.elasticsearch.client.RestHighLevelClient;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.boot.test.context.SpringBootTest;@SpringBootTestclass PassjavaSearchApplicationTests { @Qualifier("restHighLevelClient") @Autowired private RestHighLevelClient client; @Test public void contextLoads() { System.out.println(client); }}
运行结果如下所示,打印出了 RestHighLevelClient。说明自定义的 ES Client 自动装载成功。
测试方法 testIndexData,省略 User 类。users 索引在我的 ES 中是没有记录的,所以期望结果是 ES 中新增了一条 users 数据。
/** * 测试存储数据到 ES。 * */@Testpublic void testIndexData() throws IOException { IndexRequest request = new IndexRequest("users"); request.id("1"); // 文档的 id //构造 User 对象 User user = new User(); user.setUserName("PassJava"); user.setAge("18"); user.setGender("Man"); //User 对象转为 JSON 数据 String jsonString = JSON.toJSONString(user); // JSON 数据放入 request 中 request.source(jsonString, XContentType.JSON); // 执行插入操作 IndexResponse response = client.index(request, RequestOptions.DEFAULT); System.out.println(response);}
执行 test 方法,我们可以看到控制台输出以下结果,说明数据插入到 ES 成功。另外需要注意的是结果中的 result 字段为 updated,是因为我本地为了截图,多执行了几次插入操作,但因为 id = 1,所以做的都是 updated 操作,而不是 created 操作。
我们再来到 ES 中看下 users 索引中数据。查询 users 索引:
GET users/_search
结果如下所示:
可以从图中看到有一条记录被查询出来,查询出来的数据的 _id = 1,和插入的文档 id 一致。另外几个字段的值也是一致的。说明插入的数据没有问题。
"age" : "18","gender" : "Man","userName" : "PassJava"
示例:搜索 bank 索引,address 字段中包含 big 的所有人的年龄分布 ( 前 10 条 ) 以及平均年龄,以及平均薪资。
我们可以参照官方文档给出的示例来创建一个 SearchRequest 对象,指定要查询的索引为 bank,然后创建一个 SearchSourceBuilder 来组装查询条件。总共有三种条件需要组装:
address 中包含 road 的所有人。按照年龄分布进行聚合。计算平均薪资。代码如下所示,需要源码请到我的 Github/PassJava 上下载。
将打印出来的检索参数复制出来,然后放到 JSON 格式化工具中格式化一下,再粘贴到 ES 控制台执行,发现执行结果是正确的。
用在线工具格式化 JSON 字符串,结果如下所示:
然后我们去掉其中的一些默认参数,最后简化后的检索参数放到 Kibana 中执行。
Kibana Dev Tools 控制台中执行检索语句如下图所示,检索结果如下图所示:
找到总记录数:29 条。
第一条命中记录的详情如下:
平均 balance:13136。
平均年龄:26。
地址中包含 Road 的:263 Aviation Road。
和 IDEA 中执行的测试结果一致,说明复杂检索的功能已经成功实现。
而获取命中记录的详情数据,则需要通过两次 getHists() 方法拿到,如下所示:
// 3.1)获取查到的数据。SearchHits hits = response.getHits();// 3.2)获取真正命中的结果SearchHit[] searchHits = hits.getHits();
我们可以通过遍历 searchHits 的方式打印出所有命中结果的详情。
// 3.3)、遍历命中结果for (SearchHit hit: searchHits) { String hitStr = hit.getSourceAsString(); BankMember bankMember = JSON.parseObject(hitStr, BankMember.class);}
拿到每条记录的 hitStr 是个 JSON 数据,如下所示:
{"account_number": 431,"balance": 13136,"firstname": "Laurie","lastname": "Shaw","age": 26,"gender": "F","address": "263 Aviation Road","employer": "Zillanet","email": "laurieshaw@zillanet.com","city": "Harmon","state": "WV"}
而 BankMember 是根据返回的结果详情定义的的 JavaBean。可以通过工具自动生成。在线生成 JavaBean 的网站如下:
https://www.bejson.com/json2javapojo/new/
把这个 JavaBean 加到 PassjavaSearchApplicationTests 类中:
@ToString@Datastatic class BankMember { private int account_number; private int balance; private String firstname; private String lastname; private int age; private String gender; private String address; private String employer; private String email; private String city; private String state;}
然后将 bankMember 打印出来:
System.out.println(bankMember);
得到的结果确实是我们封装的 BankMember 对象,而且里面的属性值也都拿到了。
ES 返回的 response 中,年龄分布的数据是按照 ES 的格式返回的,如果想按照我们自己的格式来返回,就需要将 response 进行处理。
如下图所示,这个是查询到的年龄分布结果,我们需要将其中某些字段取出来,比如 buckets,它代表了分布在 21 岁的有 4 个。
下面是代码实现:
Aggregations aggregations = response.getAggregations();Terms ageAgg1 = aggregations.get("ageAgg");for (Terms.Bucket bucket : ageAgg1.getBuckets()) { String keyAsString = bucket.getKeyAsString(); System.out.println("用户年龄: " + keyAsString + " 人数:" + bucket.getDocCount());}
最后打印的结果如下,21 岁的有 4 人,26 岁的有 4 人,等等。
现在来看看平均薪资如何按照所需的格式返回,ES 返回的结果如下图所示,我们需要获取 balanceAvg 字段的 value 值。
代码实现:
Avg balanceAvg1 = aggregations.get("balanceAvg");System.out.println("平均薪资:" + balanceAvg1.getValue());
打印结果如下,平均薪资 28578 元。
PassJava 这个项目可以用来配置题库,如果我们想通过关键字来搜索题库,该怎么做呢?
类似于百度搜索,输入几个关键字就可以搜到关联的结果,我们这个功能也是类似,通过 Elasticsearch 做检索引擎,后台管理界面和小程序作为搜索入口,只需要在小程序上输入关键字,就可以检索相关的题目和答案。
首先我们需要把题目和答案保存到 ES 中,在存之前,第一步是定义索引的模型,如下所示,模型中有 title
和 answer
字段,表示题目和答案。
"id": { "type": "long"},"title": { "type": "text", "analyzer": "ik_smart"},"answer": { "type": "text", "analyzer": "ik_smart"},"typeName": { "type": "keyword"}
上面我们已经定义了索引结构,接着就是在 ES 中创建索引。
在 Kibana 控制台中执行以下语句:
PUT question{"mappings" : { "properties": { "id": { "type": "long" }, "title": { "type": "text", "analyzer": "ik_smart" }, "answer": { "type": "text", "analyzer": "ik_smart" }, "typeName": { "type": "keyword" }} }}
执行结果如下所示:
我们可以通过以下命令来查看 question 索引是否在 ES 中:
GET _cat/indices
执行结果如下图所示:
上面我们定义 ES 的索引,接着就是定义索引对应的模型,将数据存到这个模型中,然后再存到 ES 中。
ES 模型如下,共四个字段:id、title、answer、typeName。和 ES 索引是相互对应的。
@Datapublic class QuestionEsModel { private Long id; private String title; private String answer; private String typeName;}
当我们在后台创建题目或保存题目时,先将数据保存到 mysql 数据库,然后再保存到 ES 中。
如下图所示,在管理后台创建题目时,触发保存数据到 ES 。
第一步,保存数据到 mysql 中,项目中已经包含此功能,就不再讲解了,直接进入第二步:保存数据到 ES 中。
而保存数据到 ES 中,需要将数据组装成 ES 索引对应的数据,所以我用了一个 ES model,先将数据保存到 ES model 中。
这里的关键代码时 copyProperties
,可以将 question
对象的数据取出,然后赋值到 ES model 中。不过 ES model 中还有些字段是 question 中没有的,所以需要单独拎出来赋值,比如 typeName 字段,question 对象中没有这个字段,它对应的字段是 question.type,所以我们把 type 取出来赋值到 ES model 的 typeName 字段上。如下图所示:
我在 passjava-search 微服务中写了一个保存题目的 api 用来保存数据到 ES 中。
然后在 passjava-question 微服务中调用 search 微服务的保存 ES 的方法就可以了。
// 调用 passjava-search 服务,将数据发送到 ES 中保存。searchFeignService.saveQuestion(esModel);
我们可以通过 kibana 的控制台来查看 question 索引中的文档。通过以下命令来查看:
GET question/_search
执行结果如下图所示,有一条记录:
另外大家有没有疑问:可以重复更新题目吗?
答案是可以的,保存到 ES 的数据是幂等的,因为保存的时候带了一个类似数据库主键的 id。
我们已经将数据同步到了 ES 中,现在就是前端怎么去查询 ES 数据中,这里我们还是使用 Postman 来模拟前端查询请求。
请求参数我定义了三个:
keyword:用来匹配问题或者答案。id:用来匹配题目 id。pageNum:用来分页查询数据。这里我将这三个参数定义为一个类:
@Datapublic class SearchParam { private String keyword; // 全文匹配的关键字 private String id; // 题目 id private Integer pageNum; // 查询第几页数据}
返回的 response 我也定义了四个字段:
questionList:查询到的题目列表。pageNum:第几页数据。total:查询到的总条数。totalPages:总页数。定义的类如下所示:
@Datapublic class SearchQuestionResponse { private List questionList; // 题目列表 private Integer pageNum; // 查询第几页数据 private Long total; // 总条数 private Integer totalPages; // 总页数}
调用 ES 的查询 API 时,需要构建查询参数。
组装查询参数的核心代码如下所示:
ES 返回的数据是 ES 定义的格式,真正的数据被嵌套在 ES 的 response 中,所以需要格式化返回的数据。
核心代码如下图所示:
我们现在想要验证 title 字段是否能匹配到,传的请求参数 keyword = 111,匹配到了 title = 111 的数据,且只有一条。页码 pageNum 我传的 1,表示返回第一页数据。如下图所示:
我们现在想要验证 answer 字段是否能匹配到,传的请求参数 keyword = 测试答案,匹配到了 title = 测试答案的数据,且只有一条,说明查询成功。如下图所示:
我们现在想要匹配题目 id 的话,需要传请求参数 id,而且 id 是精确匹配。另外 id 和 keyword 是取并集,所以不能传 keyword 字段。
请求参数 id = 5,返回结果也是 id =5 的数据,说明查询成功。如下图所示:
本文通过我的开源项目 passjava 来讲解 ES 的整合,ES 的 API 使用以及测试。非常详细地讲解了每一步该如何做,相信通过阅读本篇后,再加上自己的实践,一定能掌握前后端该如何使用 ES 来达到高效搜索的目的。
当然,ES API 还有很多功能未在本文实践,有兴趣的同学可以到 ES 官网进行查阅和学习。
最新推荐
上篇我们讲到了Elasticsearch全文检索的原理《别只会搜日志了,求你懂点原理吧》,通过在本地搭建一套ES...
1、二氧化硅和二氧化矽应该只是叫法不同,他们在英文中都翻译为Silica是矽线石么化学组成:同蓝晶石。2、...
鞭牛士2月28日消息,据BusinessInsider消息,字节跳动已在英国和美国市场推出名为Lemon8的生活方式社区...
前几篇文章中我和大家一起聊了我们国家货币发行的数量,我仔细看了大家的留言,了解了大家很多的想法。...
继2019年后,近日,中水物资咨询公司再次通过国家高新技术企业的认定,正式收到由北京市科学技术委员会...
1、1、简短好听群聊名称:七姐妹、时代姐妹花、童趣萌妹、单身贵族、快乐一家、温馨港湾、浪漫满屋、八朵...
春节旅游大火之后,业界预期即将到来的春季旅游旺季会迎来报复性增长。各地正在大力促进消费回补,在春...
抚州新型冠状病毒肺炎疫情:2月28日抚州疫情最新消息今天数据统计情况通报,截至2月28日10时30分抚州疫情...
2月10日,黄海造船有限公司举行为山东海事局建造的60米级B型巡逻船“海巡0561”号下水仪式,黄海造船有...
1、Truffles,动画《HappyTreeFriends》中的角色。2、身穿水手服的青蓝色小猪,与Lammy
一直以来英国皇室的瓜是让人吃的不亦乐乎,尤其是两位王妃进门之后就开始了各种八卦。现在关于哈里王子...
本报讯(周保华朱冬桥)“省42条”“市56条”发布后,市农业农村局第一时间组建专班研究制定配套政策措...
1、起源:源于姬姓出自周武王之弟的封地郕,属于以国名为氏。2、成氏族人大多尊奉成叔武为得姓始祖。3、...
随着用车需求不断变化,越来越多消费者都开始选择豪华车,毕竟豪华车能给人更好的用车体验,最近也有很...
封面新闻记者刘恪生2月下旬,自贡市富顺县召开2023年春耕生产现场会,部署今年春耕生产重点工作,推广大...
1、C。本文到此分享完毕,希望对大家有所帮助。
佛山机动车“免检”范围一、限定车型:小型、微型非营运载客汽车(面包车除外)、大型轿车、摩托车。二、...
行情表现2月27日收盘价当日涨跌幅五日涨跌幅纸浆6476 00元 吨-0 49%-1 97%品种基本面 据同花顺iF...
北京时间2月27日,NBA常规赛,掘金主场对阵快船。半场战罢,掘金球星贾马尔-穆雷稳定输出,投篮10中5,...
1、网站上买房哪个也不靠谱,网站只是把信息用网络形式发布出来,还得亲自去看。2、建议看看58赶集等综...
本文转自【央视新闻客户端】;今天(27日)上午,2022年度全国十大考古新发现初评结果在北京揭晓,22个...
西藏自治区山南市错那县的勒布边境派出所内,副所长侯强打开刚到的包裹——竹笋、米粉,都是家乡四川绵...
当前大家对于凤歌GL都是颇为感兴趣的,大家都想要了解一下凤歌GL,那么小美也是在网络上收集了一些关于...
1、上海郊外是一家做地道本帮菜的餐厅,食材的选自都非常新鲜。2、口味不输给一些大饭店,价格不贵,性...
来源:证券日报本报记者李亚男2月25日上机数控发布定增预案,公司拟向特定对象发行股票,募集资金总额不...
1、【实验】有机实验之硝基苯的制备硝基苯的制备目的原理主反应:Ar+HONO2+H2SO4®Ar-NO2
1、丕阐,读音pīchǎn,汉语词语,意思是犹言大显。2、。文章到此就分享结束,希望对大家有所帮助。
欢迎观看本篇文章,小升来为大家解答以上问题。内勤岗位职责,内勤的岗位职责是什么很多人还不知道,现...
东渡河流程总长26 3公里,流域面积127 08平方公里,年平均流量1 49秒立米,年径流量0 47亿立米。水能资源0
草长莺飞二月天,拂堤杨柳醉春烟。兔年春季在满目翠绿的花开时节徐徐走来,在温暖的春天里,摄影人迎来...
凭借一句“冷热酸甜,想吃就吃”的广告语,“冷酸灵”成为一代人的记忆。如今冷酸灵母公司也要IPO了。重...
1、《中医古籍珍本集成:医案医话医论卷--续医说》是2014年湖南科学技术出版社出版的图书。2、。文章到...
近日,中交上航局上海交建公司承建的上海航塘港南延伸工程顺利通过完工验收。该工程为浦东片南排杭州湾...
1、河北外国语学院是同属院校还是不错的,不过学校的整体就业情况还是不错的,尤其是外语类专业,好多小...
1、《中国和尼泊尔的故事》是五洲传播出版社出版的图书。文章到此就分享结束,希望对大家有所帮助。
1、根据我的经验,跑步1 如果是短跑的话:起跑很重要,半弯着身子,前脚放前,后脚半钩,做蓄力状;此外...
1、在疾病早期,肝癌患者可能没有临床症状和表现。2、随着病情进展,患者可出现右上腹胀痛、厌食、食欲...
1、《中国藏文报刊发展史》主要内容包括:中国少数民族语言媒介史的拓荒之作、难得的“第一桶金”、填补...
小年已过,大年即将来临。民间有“过了大寒就是年”的说法,如今大寒也即将来临,那么春节也就不远了。...
1、天宝寺,位于福建省屏南县长桥村东南约1公里的屏琴山(又名龙江冈)上。2、寺院坐南朝北,形似五龙落...
天津市北部的宝坻区有这么一个地方,就在几年前还是一片阡陌村庄,而现在则崛起成为京津中关村科技城;...
1、赌场(Casino)dǔchǎng是指专供赌博的场所赌场,常指合法经营的多种赌博场所;同时赌场也指非法的...
1、临潼区新丰街道长条村志愿服务队是由临潼区乡村志愿服务队领导下的志愿团体。2、成立于2020年8月14日...
在梦幻西游诸多大佬中,神威土豪萌大奶无疑是最亮眼的几人之一。近日,奶哥又花费重金打造出了全服第一5...
栀子花开票房是赚是亏,栀子花开票房这个很多人还不知道,现在让我们一起来看看吧!1、《栀子花开》仅仅...
1、乐布是江苏乐比琪母婴护理科技有限公司旗下品牌。2、主营纸尿裤、拉拉裤。3、以“乐享其中,爱布释手...
好心女孩路遇流浪大叔,为其买面条还将其送医
02月24日从杭州出发到河源的防疫政策(数据来源:本地宝)1、出杭州-:正常通行2、到河源-:【最新消息】...
1、鲁比(Rubi),全名:霍安·弗兰塞斯克·费雷尔·西西利亚(JoanFrancescFerrerSicilia
1、第一部盗墓笔记导演是,罗永昌、罗国辉,终极笔记导演是,邹曦,卫立州。2、怒海替沙刘国辉。3、沙海...
成都抗疫的外籍志愿者:愿为城市“康复”贡献力量
阿里新型冠状病毒肺炎疫情:2月24日阿里疫情最新消息今天数据统计情况通报_环球观点
焦点热文:欧联杯天使迪玛利亚帽子戏法!意甲尤文图斯3-0 球王梅西开心笑了
环球动态:阿联酋这个富二代挺努力的,要造无人版歼20,还要送宇航员上太空
信息:量子信息技术3大方向:中国有2项全球第一,1项全球第二
振东制药:融资净买入493.85万元,融资余额3.22亿元(02-22)
郑州民警李天晓等18位民警获得2022河南“最美基层民警”荣誉称号_焦点热文
西蒙斯曾与比尔赌5000美金自己两罚全进 随即罚丢一球-环球关注
《狂飙》何黎明的权力有多大?别看他是副书记,权力可不输一把手-全球短讯
今日预售,才8万多,拥有20万的实力!有排面,新车终于来了 全球今头条
每日速讯:塔牌集团:2月20日获融资买入431.50万元,占当日流入资金比例10.56%
怎样把360浏览器改为极速模式_如何把360浏览器改为极速模式
杜兰特确定复出日期 太阳没人搞破坏比篮网专注 带保罗夺冠没问题
人口大省:常住人口连续两年减少,人口自然增长率62年来首现负增长!云南、长沙、沈阳等地出台生育支持政策 全球聚看点
新时达董秘回复:公司经营情况敬请关注公司在指定披露媒体巨潮资讯网披露的定期报告_看点
岳阳如何查询社保缴费记录和缴费明细呢,一文带你了解|天天播报
高仪、美标、唯宝、班尼戈、松下、杜拉维特、马斯科、箭牌、九牧、惠达、玫瑰岛、中宇、心海伽蓝等最新动态 天天观速讯
今热点:英媒:消息人士透露,巴西总统卢拉计划于3月28日访华
【速看料】桑乔社媒:很高兴取得进球,但重点转移到未来重要的一周
Copyright © 2015-2022 欧洲律师网版权所有 备案号:沪ICP备2022005074号-23 联系邮箱: 58 55 97 3@qq.com