/**
-
目标:创建索引的type的映射
-
1.获取客户端
-
2.创建mapping请求对象:需要设置index,type,请求体
-
3.创建JSON请求体:参考第一天的设置Mapping的JSON数据
-
4.请求对象执行发送请求操作,请求完成会获取响应对象
-
5.关闭客户端
*/
@Test
public void createMapping() throws IOException, ExecutionException,
InterruptedException {
//配置集群名称,注意采用的事情TCP接口调用
Settings settings = Settings.builder().put(“cluster.name”,
“elasticsearch”).build();
//配置请求地址和端口
InetSocketTransportAddress address = new
InetSocketTransportAddress(InetAddress.getByName(“127.0.0.1”), 9300);
PreBuiltTransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(address);
//* 1.获取客户端
//* 2.创建mapping请求对象:需要设置index,type,请求体
PutMappingRequestBuilder request =
client.admin().indices().preparePutMapping(“blog3”);
request.setType(“article”);//设置type
//* 3.创建JSON请求体:参考第一天的设置Mapping的JSON数据
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
jsonBuilder.startObject()
.startObject(“article”)
.startObject(“properties”)
.startObject(“id”).field(“type”,“long”).field(“store”,“yes”).field(“index”,"not_
analyzed")
.endObject()
.startObject(“title”).field(“type”,“string”).field(“store”,“yes”).field(“index”,
“analyzed”).field(“analyzer”,“ik_smart”)
.endObject()
.startObject(“content”).field(“type”,“string”).field(“store”,“yes”).field("index
",“analyzed”).field(“analyzer”,“ik_smart”)
.endObject()
.endObject()
.endObject()
.endObject();
request.setSource(jsonBuilder);//设置请求体
//* 4.请求对象执行发送请求操作,请求完成会获取响应对象
PutMappingResponse response = request.get();
System.out.println(response.toString());
//* 5.关闭客户端
client.close();
}
4.建立文档document
创建文档(通过XContentBuilder)
/**
-
目标:创建文档
-
1.获取客户端
-
2.创建索引设置文档请求对象:需要设置index,type,id,请求体
-
3.创建JSON请求体:参考第一天的设置创建文档的JSON数据
-
4.请求对象执行发送请求操作,请求完成会获取响应对象
-
5.关闭客户端
*/
@Test
public void createDocument() throws IOException {
//* 1.获取客户端:设置集群名称,设置请求地址和端口TCP的
Settings settings = Settings.builder().put(“cluster.name”,
“elasticsearch”).build();
InetSocketTransportAddress address = new
InetSocketTransportAddress(InetAddress.getByName(“127.0.0.1”), 9300);
PreBuiltTransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(address);
//* 3.创建JSON请求体:参考第一天的设置创建文档的JSON数据
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
jsonBuilder.startObject()
.field(“id”,“1”)
.field(“title”,“ELasticSearch是一个基于Lucene的搜索服务器”)
.field(“content”,"content它提供了一个分布式多用户能力的全文搜索引擎,基于
RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当
前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。")
.endObject();
//* 2.创建索引设置文档请求对象:需要设置index,type,id,请求体
IndexRequestBuilder requestBuilder = client.prepareIndex(“blog3”, “article”,
“1”);
requestBuilder.setSource(jsonBuilder);
//* 4.请求对象执行发送请求操作,请求完成会获取响应对象
IndexResponse indexResponse = requestBuilder.get();
System.out.println(indexResponse.toString());
//* 5.关闭客户端
client.close();
}
创建文档(使用Jackson转换实体)
5.查询文档操作
关键词查询
/**
-
目标:term关键词的查询
-
1.获取客户端
-
2.创建搜索请求对象:需要设置index,type,查询对象
-
3.创建Term查询对象,设置查询字段,和关键词
-
4.请求对象执行发送请求操作,请求完成会获取响应对象
-
5.响应对象中获取命中数据,循环遍历输出
-
6.关闭客户端
*/
@Test
public void testTermQuery() throws UnknownHostException {
//* 1.获取客户端
PreBuiltTransportClient client = TransPortClientUtil.getClient();
//* 2.创建搜索请求对象:需要设置index,type,查询对象
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(“blog3”);
//* 3.创建Term查询对象,设置查询字段,和关键词
searchRequestBuilder.setQuery(QueryBuilders.termQuery(“title”,“搜索”));
//* 4.请求对象执行发送请求操作,请求完成会获取响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
//* 5.响应对象中获取命中数据,循环遍历输出
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
System.out.println(hit.getSource().get(“id”));
System.out.println(hit.getSource().get(“title”));
System.out.println(hit.getSource().get(“content”));
}
//* 6.关闭客户端
client.close();
}
字符串查询
/**
-
目标:查询,带分词器的字符串查询
-
1.获取客户端
-
2.创建搜索请求对象:需要设置index,type,查询对象
-
3.创建Query_string查询对象,传入查询字符串
-
4.请求对象执行发送请求操作,请求完成会获取响应对象
-
5.响应对象中获取命中数据,循环遍历输出
-
6.关闭客户端
*/
@Test
public void testStringQuery() throws UnknownHostException {
//1.获取客户端
PreBuiltTransportClient client = TransPortClientUtil.getClient();
//2.创建搜索请求对象:需要设置index,type,查询对象
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(“blog2”);
searchRequestBuilder.setTypes(“article”);
//3.创建Query_string查询对象,传入查询字符串
searchRequestBuilder.setQuery(QueryBuilders.queryStringQuery(“搜索”));
//4.请求对象执行发送请求操作,请求完成会获取响应对象
SearchResponse searchResponse = searchRequestBuilder.get();//发送请求获取响应
//5.响应对象中获取命中数据,循环遍历输出
SearchHits hits = searchResponse.getHits();
System.out.println(“搜索结果有:[” + hits.getTotalHits() + “]条”);
Iterator iterator = hits.iterator();
while (iterator.hasNext()){
SearchHit next = iterator.next();
System.out.println(“ID:”+next.getSource().get(“id”));
System.out.println(“title:”+next.getSource().get(“title”));
System.out.println(“content:”+next.getSource().get(“content”));
}
//6.关闭客户端
client.close();
}
使用文档ID查询文档
/**
-
目标:查询,使用ID查询
-
1.获取客户端
-
2.创建搜索请求对象:需要设置index,type,查询对象
-
3.创建idsQuery查询对象,填入id
-
4.请求对象执行发送请求操作,请求完成会获取响应对象
-
5.响应对象中获取命中数据,循环遍历输出
-
6.关闭客户端
*/
@Test
public void findById() throws UnknownHostException {
//1.获取客户端
PreBuiltTransportClient client = TransPortClientUtil.getClient();
//2.创建搜索请求对象:需要设置index,type,查询对象
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(“blog1”);
searchRequestBuilder.setTypes(“article”);
//3.创建idsQuery查询对象,填入id
searchRequestBuilder.setQuery(QueryBuilders.idsQuery().addIds(“1”));
//4.请求对象执行发送请求操作,请求完成会获取响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
//5.响应对象中获取命中数据,循环遍历输出
SearchHits hits = searchResponse.getHits();
System.out.println(“搜索结果有:[” + hits.getTotalHits() + “]条”);
Iterator iterator = hits.iterator();
while (iterator.hasNext()){
SearchHit next = iterator.next();
System.out.println(“ID:”+next.getSource().get(“id”));
System.out.println(“title:”+next.getSource().get(“title”));
System.out.println(“content:”+next.getSource().get(“content”));
}
//6.关闭客户端
client.close();
}
6.查询文档分页操作
批量插入数据
/**
-
分页查询的准备:批量插入100条数据
-
1.获取客户端
-
循环100次2,3,4的操作:
-
2.创建索引新增文档请求对象:需要设置index,type,id,请求体
-
3.创建JSON请求体:参考第一天的设置创建文档的JSON数据
-
4.请求对象执行发送请求操作,请求完成会获取响应对象
-
5.关闭客户端
*/
@Test
public void testSaveList() throws UnknownHostException, JsonProcessingException
{
//1.获取客户端
PreBuiltTransportClient client = TransPortClientUtil.getClient();
ObjectMapper objectMapper = new ObjectMapper();
//循环100次2,3,4的操作:
for (int i = 0; i < 100; i++) {
//3.创建JSON请求体:参考第一天的设置创建文档的JSON数据
Article article = new Article();
article.setId(i);
article.setTitle(“[”+i+“] 搜索工作其实很快乐”);
article.setContent(“[”+i+"] 我们希望我们的搜索解决方案要快,我们希望有一个零配置
和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务
器始终可用,我们希望能够一台开始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一
个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的问题。");
//对象转换为JSON数据
String jsonArticle = objectMapper.writeValueAsString(article);
//2.创建索引新增文档请求对象:需要设置index,type,id,请求体
IndexRequestBuilder indexRequestBuilder = client.prepareIndex(“blog2”,
“article”, “” + i);
indexRequestBuilder.setSource(jsonArticle, XContentType.JSON);//设置请求体
//4.请求对象执行发送请求操作,请求完成会获取响应对象
IndexResponse indexResponse = indexRequestBuilder.get();
System.out.println(jsonArticle);
System.out.println(indexResponse.toString());
}
//5.关闭客户端
client.close();
}
分页查询
/**
-
目标:查询,分页查询
-
1.获取客户端
-
2.创建搜索请求对象:需要设置index,type,查询对象
-
3.创建查询所有记录对象,并设置分页信息:form表示起始页,size表示每页多少条
-
4.请求对象执行发送请求操作,请求完成会获取响应对象
-
5.响应对象中获取命中数据,循环遍历输出
-
6.关闭客户端
*/
@Test
public void findByPageable() throws UnknownHostException {
//1.获取客户端
PreBuiltTransportClient client = TransPortClientUtil.getClient();
//2.创建搜索请求对象:需要设置index,type,查询对象
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(“blog2”);
searchRequestBuilder.setTypes(“article”);
//3.创建查询所有记录对象,并设置分页信息:form表示起始页,size表示每页多少条
searchRequestBuilder.setQuery(QueryBuilders.matchAllQuery());//默认每页10条
searchRequestBuilder.setFrom(0);//form表示起始页
searchRequestBuilder.setSize(20);//size表示每页多少条
//4.请求对象执行发送请求操作,请求完成会获取响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
//5.响应对象中获取命中数据,循环遍历输出
SearchHits hits = searchResponse.getHits();
System.out.println(“搜索结果有:[” + hits.getTotalHits() + “]条”);
System.out.println(“当前页有:[” + hits.getHits().length + “]条”);
Iterator iterator = hits.iterator();
while (iterator.hasNext()){
SearchHit next = iterator.next();
System.out.println(“ID:”+next.getSource().get(“id”));
System.out.println(“title:”+next.getSource().get(“title”));
System.out.println(“content:”+next.getSource().get(“content”));
}
//6.关闭客户端
client.close();
}
7.查询结果高亮操作
什么是高亮显示
高亮显示的html分析
高亮显示代码实现
/**
-
目标:搜索结果高亮
-
1.获取客户端
-
2.创建搜索请求对象:需要设置index,type,查询对象
-
3.创建Term查询对象,设置查询字段,和关键词
-
3.1 查询对象设置数据高亮配置:配置高亮标签font,配置高亮字段title
-
4.请求对象执行发送请求操作,请求完成会获取响应对象
-
5.响应对象中获取命中数据,循环遍历输出
-
6.关闭客户端
*/
@Test
public void testHighLight() throws UnknownHostException {
//1.获取客户端
PreBuiltTransportClient client = TransPortClientUtil.getClient();
//2.创建搜索请求对象:需要设置index,type,查询对象
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(“blog2”);
searchRequestBuilder.setTypes(“article”);
//3.创建Term查询对象,设置查询字段,和关键词
searchRequestBuilder.setQuery(QueryBuilders.termQuery(“title”,“搜索”));//默认
每页10条
//3.1 查询对象设置数据高亮配置
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags(“”);
highlightBuilder.postTags(“”);
highlightBuilder.field(“title”);
searchRequestBuilder.highlighter(highlightBuilder);
//4.请求对象执行发送请求操作,请求完成会获取响应对象
SearchResponse searchResponse = searchRequestBuilder.get();
//5.响应对象中获取命中数据,循环遍历输出
SearchHits hits = searchResponse.getHits();
System.out.println(“共搜索到:[” + hits.getTotalHits() + “]条结果”);
for (SearchHit hit : hits) {
System.out.println(“String方式打印高亮内容:”);
System.out.println(hit.getSourceAsString());
System.out.println(“Map方式打印高亮内容:”);
System.out.println(hit.getHighlightFields());
Map<String, HighlightField> highlightFieldMap =
hit.getHighlightFields();
Text[] titles = hit.getHighlightFields().get(“title”).fragments();
for (Text title : titles) {
System.out.println(title);
}
}
//6.关闭客户端
client.close();
}
八、Spring Data ElasticSearch 使用
1.Spring Data ElasticSearch简介
什么是Spring Data
什么是Spring Data ElasticSearch
2.Spring Data ElasticSearch环境搭建
<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">
4.0.0
com.itheima
itheima_elasticsearch_demo3
1.0-SNAPSHOT
org.elasticsearch
elasticsearch
5.6.8
org.elasticsearch.client
transport
5.6.8
org.apache.logging.log4j
log4j-to-slf4j
2.9.1
org.slf4j
slf4j-api
1.7.24
org.slf4j
slf4j-simple
1.7.21
log4j
log4j
1.2.12
junit
junit
4.12
com.fasterxml.jackson.core
jackson-core
2.8.1
com.fasterxml.jackson.core
jackson-databind
2.8.1
com.fasterxml.jackson.core
jackson-annotations
2.8.1
org.springframework.data
spring-data-elasticsearch
3.0.5.RELEASE
org.elasticsearch.plugin
transport-netty4-client
org.springframework
spring-test
5.0.4.RELEASE
<beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:context=“http://www.springframework.org/schema/context”
xmlns:elasticsearch=“http://www.springframework.org/schema/data/elasticsearch”
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-
elasticsearch-1.0.xsd">
package com.itheima.domain;
public class Article {
private Integer id;
private String title;
private String content;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return “Article [id=” + id + “, title=” + title + “, content=” + content
- “]”;
}
}
package com.itheima.dao;
import com.itheima.domain.Article;
import
org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
@Repository
public interface ArticleRepository extends ElasticsearchRepository<Article,
Integer> {
}
package com.itheima.service;
import com.itheima.domain.Article;
public interface ArticleService {
public void save(Article article);
}
package com.itheima.service.impl;
import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepository articleRepository;
public void save(Article article) {
articleRepository.save(article);
}
}
<beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:context=“http://www.springframework.org/schema/context”
xmlns:elasticsearch=“http://www.springframework.org/schema/data/elasticsearch”
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-
elasticsearch-1.0.xsd
">
<elasticsearch:repositories base-package=“com.itheima.dao”/>
<context:component-scan base-package=“com.itheima.service”/>
<elasticsearch:transport-client id=“client” cluster-nodes=“localhost:9300”
cluster-name=“elasticsearch”/>
<bean id=“elasticsearchTemplate”
class=“org.springframework.data.elasticsearch.core.ElasticsearchTemplate”>
package com.itheima.domain;
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;
//@Document 文档对象 (索引信息、文档类型 )
@Document(indexName=“blog3”,type=“article”)
public class Article {
//@Id 文档主键 唯一标识
@Id
//@Field 每个文档的字段配置(类型、是否分词、是否存储、分词器 )
@Field(store=true, index = false,type = FieldType.Integer)
private Integer id;
@Field(index=true,analyzer=“ik_smart”,store=true,searchAnalyzer=“ik_smart”,type
= FieldType.text)
private String title;
@Field(index=true,analyzer=“ik_smart”,store=true,searchAnalyzer=“ik_smart”,type
= FieldType.text)
private String content;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return “Article [id=” + id + “, title=” + title + “, content=” + content
- “]”;
}
}
package com.itheima.test;
import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations=“classpath:applicationContext.xml”)
public class SpringDataESTest {
@Autowired
private ArticleService articleService;
@Autowired
private TransportClient client;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
/*创建索引和映射/
@Test
public void createIndex(){
elasticsearchTemplate.createIndex(Article.class);
elasticsearchTemplate.putMapping(Article.class);
}
/*测试保存文档/
@Test
public void saveArticle(){
Article article = new Article();
article.setId(100);
article.setTitle(“测试SpringData ElasticSearch”);
article.setContent("Spring Data ElasticSearch 基于 spring data API 简化
elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装Spring Data为
Elasticsearch Elasticsearch项目提供集成搜索引擎");
articleService.save(article);
}
}
3.Spring Data ElasticSearch的常用操作
增删改查方法测试
package com.itheima.service;
import com.itheima.domain.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface ArticleService {
//保存
public void save(Article article);
//删除
public void delete(Article article);
//查询全部
public Iterable
//分页查询
public Page
}
package com.itheima.service.impl;
import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepository articleRepository;
public void save(Article article) {
articleRepository.save(article);
}
public void delete(Article article) {
articleRepository.delete(article);
}
public Iterable
Iterable
return iter;
}
public Page
return articleRepository.findAll(pageable);
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
package com.itheima.service.impl;
import com.itheima.dao.ArticleRepository;
import com.itheima.domain.Article;
import com.itheima.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepository articleRepository;
public void save(Article article) {
articleRepository.save(article);
}
public void delete(Article article) {
articleRepository.delete(article);
}
public Iterable
Iterable
return iter;
}
public Page
return articleRepository.findAll(pageable);
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-zTaaQCJo-1715670377292)]
[外链图片转存中…(img-qFordwMU-1715670377293)]
[外链图片转存中…(img-az11JzHv-1715670377293)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!