(二十)在线教育网站搭建一采用dubbo服务注册和发现

dubbo构建项目

1. dubbo配置

1
2
3
4
5
6
7
8
9
10
11
#teacher
server.port=8001
dubbo.application.name=edu-teacher
dubbo.registry.address=zookeeper://192.168.0.100:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=28001
dubbo.consumer.check=false

#aliyun
server.port=8002

2. Spring-Data-Elasticsearch

https://docs.spring.io/spring-data/elasticsearch/docs/

https://docs.spring.io/spring-data/elasticsearch/docs/3.2.4.RELEASE/reference/html/#preface.versions

Spring Data Release Train Spring Data Elasticsearch Elasticsearch Spring Boot
Moore 3.2.x 6.8.4 2.2.x
Lovelace 3.1.x 6.2.2 2.1.x
Kay[1] 3.0.x[1] 5.5.0 2.0.x[1]
Ingalls[1] 2.1.x[1] 2.4.0 1.5.x[1]

版本不相配!!

3. Elasticsearch+jestClient

3.1. Maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!-- elasticsearch-5.6.11 -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.6.11</version>
</dependency>

<!-- jestclient -->
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>5.3.3</version>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

3.2. 配置application.properties

1
2
3
4
server.port=9999

spring.elasticsearch.jest.uris= http://192.168.0.101:9200
spring.elasticsearch.jest.read-timeout=6s

3.3. 创建index和mapping

https://github.com/searchbox-io/Jest/tree/master/jest

在索引online下创建teacher类型的mapping

name, intro, career 采用ik分词器,分的时候用ik_max_word 尽量分最大词,查找的时候用ik_smart智能查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
void TestMapping() throws IOException {
String str = "{\"mappings\": {\"user\":{ \"properties\":{\n" +
" \"id\":{\"type\":\"text\"},\n" +
" \"name\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\"},\n"
" \"password\":{\"type\":\"text\"},\n" +
" \"video\":{\"type\":\"text\"}\n"
" }}}\n" +
"}";
System.out.println(str);
CreateIndex index = new CreateIndex.Builder("online").settings(str).build();
JestResult execute = jestClient.execute(index);
System.out.println(execute.getJsonObject());
}

3.4. CRUD

3.4.1. 新增

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RunWith(SpringRunner.class)
@SpringBootTest
class TestApplicationTests {

//@Autowired
//UserRepository userRepository;

@Autowired
JestClient jestClient;

@Test
void TestElastic() throws IOException {

User user= new User();
user.setId("1");
user.setUsername("abc");
user.setPassword("123456");
Index index = new Index.Builder(user).index("online").type("user").id("1").build();

DocumentResult execute = jestClient.execute(index);

System.out.println(execute.getJsonString());
}
}

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"_index":"online",
"_type":"user",
"_id":"1",
"_version":1,
"result":"created",
"_shards":{
"total":2,
"successful":2,
"failed":0
},
"created":true
}

3.4.1.1. 源代码-默认有id用PUT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package io.searchbox.core;

import io.searchbox.action.AbstractAction;
import io.searchbox.action.BulkableAction;
import io.searchbox.action.SingleResultAbstractDocumentTargetedAction;
import java.util.Collection;

public class Index extends SingleResultAbstractDocumentTargetedAction implements BulkableAction<DocumentResult> {
protected Index(Index.Builder builder) {
super(builder);
this.payload = builder.source;
}

public String getPathToResult() {
return "ok";
}

public String getRestMethodName() {
return this.id != null ? "PUT" : "POST";
}

public String getBulkMethodName() {
Collection<Object> opType = this.getParameter("op_type");
if (opType != null) {
if (opType.size() > 1) {
throw new IllegalArgumentException("Expecting a single value for OP_TYPE parameter, you provided: " + opType.size());
} else {
return opType.size() == 1 && opType.iterator().next().toString().equalsIgnoreCase("create") ? "create" : "index";
}
} else {
return "index";
}
}

public static class Builder extends io.searchbox.action.AbstractDocumentTargetedAction.Builder<Index, Index.Builder> {
private final Object source;

public Builder(Object source) {
this.source = source;
this.id(AbstractAction.getIdFromSource(source));
}

public Index build() {
return new Index(this);
}
}
}

3.4.2. 更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
void TestUpdate() throws IOException {
User user= new User();
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
user.setVideo(list);
Index index = new Index.Builder(user).index("online").type("user").id("1").build();

DocumentResult execute = jestClient.execute(index);
System.out.println(execute.getJsonString());
}

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"_index":"online",
"_type":"user",
"_id":"1",
"_version":3,
"result":"updated",
"_shards":{
"total":2,
"successful":2,
"failed":0
},
"created":false
}

3.4.3. 查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
void TestSearch() throws IOException {

String str="{\n" +
" \"query\":{\n" +
" \"match_all\":{}\n" +
" }\n" +
" \n" +
"}";
Search search = new Search.Builder(str).addIndex("online").build();
SearchResult execute = jestClient.execute(search);

List<SearchResult.Hit<User, Void>> hits = execute.getHits(User.class);
for (SearchResult.Hit<User, Void> hit:hits) {
System.out.println(hit.source);
}
}

结果

User{id='null', username='null', password='null', video=[1, 2, 3, 4]}

3.4.3.1. 源代码-采用 POST 请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package io.searchbox.core;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import io.searchbox.action.AbstractAction;
import io.searchbox.action.AbstractMultiTypeActionBuilder;
import io.searchbox.client.config.ElasticsearchVersion;
import io.searchbox.core.search.sort.Sort;
import io.searchbox.params.SearchType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

public class Search extends AbstractAction<SearchResult> {
private String query;
private List<Sort> sortList;
protected List<String> includePatternList;
protected List<String> excludePatternList;
private final String templateSuffix;

protected Search(Search.Builder builder) {
this(builder, "");
}

protected Search(Search.TemplateBuilder templatedBuilder) {
this(templatedBuilder, "/template");
}

private Search(Search.Builder builder, String templateSuffix) {
super(builder);
this.query = builder.query;
this.sortList = builder.sortList;
this.includePatternList = builder.includePatternList;
this.excludePatternList = builder.excludePatternList;
this.templateSuffix = templateSuffix;
}

public SearchResult createNewElasticSearchResult(String responseBody, int statusCode, String reasonPhrase, Gson gson) {
return (SearchResult)this.createNewElasticSearchResult(new SearchResult(gson), responseBody, statusCode, reasonPhrase, gson);
}

public String getIndex() {
return this.indexName;
}

public String getType() {
return this.typeName;
}

protected String buildURI(ElasticsearchVersion elasticsearchVersion) {
return super.buildURI(elasticsearchVersion) + "/_search" + this.templateSuffix;
}

public String getPathToResult() {
return "hits/hits/_source";
}

public String getRestMethodName() {
return "POST";
}

public String getData(Gson gson) {
String data;
if (this.sortList.isEmpty() && this.includePatternList.isEmpty() && this.excludePatternList.isEmpty()) {
data = this.query;
} else {
JsonObject queryObject = (JsonObject)gson.fromJson(this.query, JsonObject.class);
if (queryObject == null) {
queryObject = new JsonObject();
}

if (!this.sortList.isEmpty()) {
JsonArray sortArray = normalizeSortClause(queryObject);
Iterator var5 = this.sortList.iterator();

while(var5.hasNext()) {
Sort sort = (Sort)var5.next();
sortArray.add(sort.toJsonObject());
}
}

if (!this.includePatternList.isEmpty() || !this.excludePatternList.isEmpty()) {
JsonObject sourceObject = normalizeSourceClause(queryObject);
addPatternListToSource(sourceObject, "includes", this.includePatternList);
addPatternListToSource(sourceObject, "excludes", this.excludePatternList);
}

data = gson.toJson(queryObject);
}

return data;
}

private static JsonArray normalizeSortClause(JsonObject queryObject) {
JsonArray sortArray;
if (queryObject.has("sort")) {
JsonElement sortElement = queryObject.get("sort");
if (sortElement.isJsonArray()) {
sortArray = sortElement.getAsJsonArray();
} else if (sortElement.isJsonObject()) {
sortArray = new JsonArray();
sortArray.add(sortElement.getAsJsonObject());
} else {
if (!sortElement.isJsonPrimitive() || !sortElement.getAsJsonPrimitive().isString()) {
throw new JsonSyntaxException("_source must be an array, an object or a string");
}

String sortField = sortElement.getAsString();
sortArray = new JsonArray();
queryObject.add("sort", sortArray);
String order;
if ("_score".equals(sortField)) {
order = "desc";
} else {
order = "asc";
}

JsonObject sortOrder = new JsonObject();
sortOrder.add("order", new JsonPrimitive(order));
JsonObject sortDefinition = new JsonObject();
sortDefinition.add(sortField, sortOrder);
sortArray.add(sortDefinition);
}
} else {
sortArray = new JsonArray();
}

queryObject.add("sort", sortArray);
return sortArray;
}

private static JsonObject normalizeSourceClause(JsonObject queryObject) {
JsonObject sourceObject;
if (queryObject.has("_source")) {
JsonElement sourceElement = queryObject.get("_source");
if (sourceElement.isJsonObject()) {
sourceObject = sourceElement.getAsJsonObject();
} else if (sourceElement.isJsonArray()) {
sourceObject = new JsonObject();
queryObject.add("_source", sourceObject);
sourceObject.add("includes", sourceElement.getAsJsonArray());
} else {
if (!sourceElement.isJsonPrimitive() || !sourceElement.getAsJsonPrimitive().isBoolean()) {
throw new JsonSyntaxException("_source must be an object, an array or a boolean");
}

sourceObject = new JsonObject();
}
} else {
sourceObject = new JsonObject();
}

queryObject.add("_source", sourceObject);
return sourceObject;
}

private static void addPatternListToSource(JsonObject sourceObject, String rule, List<String> patternList) {
if (!patternList.isEmpty()) {
JsonArray ruleArray;
if (sourceObject.has(rule)) {
ruleArray = sourceObject.get(rule).getAsJsonArray();
} else {
ruleArray = new JsonArray();
sourceObject.add(rule, ruleArray);
}

Iterator var4 = patternList.iterator();

while(var4.hasNext()) {
String pattern = (String)var4.next();
ruleArray.add(pattern);
}
}

}

public int hashCode() {
return Objects.hash(new Object[]{super.hashCode(), this.query, this.sortList, this.includePatternList, this.excludePatternList});
}

public boolean equals(Object obj) {
if (obj == null) {
return false;
} else if (obj == this) {
return true;
} else if (obj.getClass() != this.getClass()) {
return false;
} else {
Search rhs = (Search)obj;
return super.equals(obj) && Objects.equals(this.query, rhs.query) && Objects.equals(this.sortList, rhs.sortList) && Objects.equals(this.includePatternList, rhs.includePatternList) && Objects.equals(this.excludePatternList, rhs.excludePatternList);
}
}

public static class TemplateBuilder extends Search.Builder {
public TemplateBuilder(String templatedQuery) {
super(templatedQuery);
}

public Search build() {
return new Search(this);
}
}

public static class VersionBuilder extends Search.Builder {
public VersionBuilder(String query) {
super(query);
this.setParameter("version", "true");
}
}

public static class Builder extends AbstractMultiTypeActionBuilder<Search, Search.Builder> {
protected String query;
protected List<Sort> sortList = new LinkedList();
protected List<String> includePatternList = new ArrayList();
protected List<String> excludePatternList = new ArrayList();

public Builder(String query) {
this.query = query;
}

public Search.Builder setSearchType(SearchType searchType) {
return (Search.Builder)this.setParameter("search_type", searchType);
}

public Search.Builder enableTrackScores() {
this.setParameter("track_scores", true);
return this;
}

public Search.Builder addSort(Sort sort) {
this.sortList.add(sort);
return this;
}

public Search.Builder addSourceExcludePattern(String excludePattern) {
this.excludePatternList.add(excludePattern);
return this;
}

public Search.Builder addSourceIncludePattern(String includePattern) {
this.includePatternList.add(includePattern);
return this;
}

public Search.Builder addSort(Collection<Sort> sorts) {
this.sortList.addAll(sorts);
return this;
}

public Search build() {
return new Search(this);
}
}
}

put新增后,原ID,username,password不见了?

3.4.4. 新增属性用POST

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
void TestSearch() throws IOException {

List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
String str = "{\n" +
" \"doc\":{\n" +
" \"video\":"+list+"\n" +
" }\n" +
"}";
Update update = new Update.Builder(str).index("online").type("user").id("1").build();
DocumentResult execute = jestClient.execute(update);
System.out.println(execute.getJsonString());
}

3.4.4.1. 源码采用 POST的_update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package io.searchbox.core;

import io.searchbox.action.BulkableAction;
import io.searchbox.action.SingleResultAbstractDocumentTargetedAction;
import io.searchbox.client.config.ElasticsearchVersion;

public class Update extends SingleResultAbstractDocumentTargetedAction implements BulkableAction<DocumentResult> {
protected Update(Update.Builder builder) {
super(builder);
this.payload = builder.payload;
}

public String getBulkMethodName() {
return "update";
}

protected String buildURI(ElasticsearchVersion elasticsearchVersion) {
return super.buildURI(elasticsearchVersion) + "/_update";
}

public String getRestMethodName() {
return "POST";
}

public String getPathToResult() {
return "ok";
}

public static class VersionBuilder extends Update.Builder {
public VersionBuilder(Object payload, Long version) {
super(payload);
this.setParameter("version", version);
}
}

public static class Builder extends io.searchbox.action.AbstractDocumentTargetedAction.Builder<Update, Update.Builder> {
private final Object payload;

public Builder(Object payload) {
this.payload = payload;
}

public Update build() {
return new Update(this);
}
}
}

3.4.5. 删除

1
2
3
4
5
6
7
@Test
void TestDelete() throws IOException {
Delete delete = new Delete.Builder("").index("online").build();
DocumentResult execute = jestClient.execute(delete);
System.out.println(execute.isSucceeded());

}

3.4.5.1. 源代码 -DELETE请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package io.searchbox.core;

import io.searchbox.action.BulkableAction;
import io.searchbox.action.SingleResultAbstractDocumentTargetedAction;

public class Delete extends SingleResultAbstractDocumentTargetedAction implements BulkableAction<DocumentResult> {
protected Delete(Delete.Builder builder) {
super(builder);
}

public String getRestMethodName() {
return "DELETE";
}

public String getPathToResult() {
return "ok";
}

public String getBulkMethodName() {
return "delete";
}

public static class Builder extends io.searchbox.action.AbstractDocumentTargetedAction.Builder<Delete, Delete.Builder> {
public Builder(String id) {
this.id(id);
}

public Delete build() {
return new Delete(this);
}
}
}

4. dubbo集群容错

http://dubbo.apache.org/zh-cn/docs/source_code_guide/cluster.html

5. 图片无法传输

java.lang.IllegalStateException: Serialized class org.apache.catalina.core.ApplicationPart must implement java.io.Serializable

dubbo适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用 dubbo 协议传输大文件或超大字符串。

采用字节流传输

6. teacher-mapping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
void TestMapping() throws IOException {
String str = "{\"mappings\": {\"teacher\":{ \"properties\":{\n" +
" \"id\":{\"type\":\"text\"},\n" +
" \"avatar\":{\"type\":\"text\"},\n" +
" \"name\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\"},\n" +
" \"intro\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\"},\n" +
" \"career\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\"},\n" +
" \"level\":{\"type\":\"long\"},\n" +
" \"isDeleted\":{\"type\":\"boolean\"},\n" +
" \"gmtCreate\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss\"},\n" +
" \"gmtModified\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd HH:mm:ss\"},\n" +
" \"sort\":{\"type\":\"long\"}\n" +
" }}}\n" +
"}";
System.out.println(str);
CreateIndex index = new CreateIndex.Builder("online").settings(str).build();
JestResult execute = jestClient.execute(index);
System.out.println(execute.getJsonObject());
}
本文结束  感谢您的阅读