diff --git a/sop-example/sop-book/pom.xml b/sop-example/sop-book/pom.xml
new file mode 100644
index 00000000..6a343033
--- /dev/null
+++ b/sop-example/sop-book/pom.xml
@@ -0,0 +1,15 @@
+
+
+ 4.0.0
+ com.gitee.sop
+ sop-book-parent
+ 1.0.0-SNAPSHOT
+ pom
+
+
+ sop-book-api
+ sop-book-web
+
+
\ No newline at end of file
diff --git a/sop-example/sop-book/sop-book-api/.gitignore b/sop-example/sop-book/sop-book-api/.gitignore
new file mode 100644
index 00000000..c456c4a3
--- /dev/null
+++ b/sop-example/sop-book/sop-book-api/.gitignore
@@ -0,0 +1,25 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
diff --git a/sop-example/sop-book/sop-book-api/pom.xml b/sop-example/sop-book/sop-book-api/pom.xml
new file mode 100644
index 00000000..c47d23c4
--- /dev/null
+++ b/sop-example/sop-book/sop-book-api/pom.xml
@@ -0,0 +1,46 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.2.RELEASE
+
+
+ com.gitee.sop
+ sop-book-api
+ 1.0-SNAPSHOT
+
+
+ 1.8
+ Greenwich.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+ provided
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
\ No newline at end of file
diff --git a/sop-example/sop-book/sop-book-api/src/main/java/com/hhdd/book/api/domain/Book.java b/sop-example/sop-book/sop-book-api/src/main/java/com/hhdd/book/api/domain/Book.java
new file mode 100644
index 00000000..b09d939a
--- /dev/null
+++ b/sop-example/sop-book/sop-book-api/src/main/java/com/hhdd/book/api/domain/Book.java
@@ -0,0 +1,12 @@
+package com.hhdd.book.api.domain;
+
+import lombok.Data;
+
+/**
+ * @author tanghc
+ */
+@Data
+public class Book {
+ private int id;
+ private String name;
+}
diff --git a/sop-example/sop-book/sop-book-api/src/main/java/com/hhdd/book/api/service/BookService.java b/sop-example/sop-book/sop-book-api/src/main/java/com/hhdd/book/api/service/BookService.java
new file mode 100644
index 00000000..1076be9d
--- /dev/null
+++ b/sop-example/sop-book/sop-book-api/src/main/java/com/hhdd/book/api/service/BookService.java
@@ -0,0 +1,14 @@
+package com.hhdd.book.api.service;
+
+import com.gitee.book.api.domain.Book;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * @author tanghc
+ */
+@RequestMapping("/book")
+public interface BookService {
+ @RequestMapping("/getBook")
+ Book getBook(@RequestParam("id") int id);
+}
diff --git a/sop-example/sop-book/sop-book-web/.gitignore b/sop-example/sop-book/sop-book-web/.gitignore
new file mode 100644
index 00000000..c456c4a3
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/.gitignore
@@ -0,0 +1,25 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
diff --git a/sop-example/sop-book/sop-book-web/pom.xml b/sop-example/sop-book/sop-book-web/pom.xml
new file mode 100644
index 00000000..232bf99f
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/pom.xml
@@ -0,0 +1,89 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.2.RELEASE
+
+
+ com.gitee.sop
+ sop-book-web
+ 0.0.1-SNAPSHOT
+ sop-story
+ Demo project for Spring Boot
+
+
+ 1.8
+ Greenwich.RELEASE
+
+
+
+
+ com.gitee.sop
+ sop-service-common
+ 1.0.0-SNAPSHOT
+
+
+ com.gitee.sop
+ sop-book-api
+ 1.0-SNAPSHOT
+
+
+ com.gitee.sop
+ sop-story-api
+ 1.0-SNAPSHOT
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+ compile
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+
+
+
diff --git a/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/SopBookApplication.java b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/SopBookApplication.java
new file mode 100644
index 00000000..cfb16be7
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/SopBookApplication.java
@@ -0,0 +1,20 @@
+package com.gitee.sop.bookweb;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+// 允许调用其他服务
+@EnableFeignClients
+// 服务注册
+@EnableDiscoveryClient
+@SpringBootApplication
+public class SopBookApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SopBookApplication.class, args);
+ }
+
+}
+
diff --git a/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java
new file mode 100644
index 00000000..21018635
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java
@@ -0,0 +1,22 @@
+package com.gitee.sop.bookweb.config;
+
+import com.gitee.sop.servercommon.configuration.AlipayServiceConfiguration;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 使用支付宝开放平台功能
+ * @author tanghc
+ */
+@Configuration
+public class OpenServiceConfig extends AlipayServiceConfiguration {
+
+}
+
+/**
+ * 使用淘宝开放平台功能
+ * @author tanghc
+ */
+//@Configuration
+//public class OpenServiceConfig extends TaobaoServiceConfiguration {
+//
+//}
diff --git a/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/consumer/StoryServiceConsumer.java b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/consumer/StoryServiceConsumer.java
new file mode 100644
index 00000000..cce5945b
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/consumer/StoryServiceConsumer.java
@@ -0,0 +1,14 @@
+package com.gitee.sop.bookweb.consumer;
+
+import com.gitee.sop.story.api.service.StoryService;
+import org.springframework.cloud.openfeign.FeignClient;
+
+/**
+ * 调用story服务
+ *
+ * @author tanghc
+ */
+// value对应的spring.application.name
+@FeignClient("story-service")
+public interface StoryServiceConsumer extends StoryService {
+}
diff --git a/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayBookController.java b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayBookController.java
new file mode 100644
index 00000000..814daf9a
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayBookController.java
@@ -0,0 +1,40 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.gitee.sop.bookweb.consumer.StoryServiceConsumer;
+import com.gitee.sop.servercommon.annotation.ApiMapping;
+import com.gitee.sop.story.api.domain.Story;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+
+/**
+ * 支付宝服务端,假设签名验证通过后,到达这里进行具体的业务处理。
+ * 这里演示如何接受业务参数。
+ * @author tanghc
+ */
+@RestController
+public class AlipayBookController {
+
+ @Autowired
+ StoryServiceConsumer storyServiceConsumer;
+
+ @ApiMapping(value = "alipay.book.get")
+ public Story getBook() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("白雪公主(alipay.book.get)");
+ return story;
+ }
+
+ // 调用story服务
+ @ApiMapping(value = "alipay.book.story.get")
+ public Object getBook2() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("白雪公主(alipay.book.story.get)");
+ Story story2 = storyServiceConsumer.getStory(1);
+ return Arrays.asList(story, story2);
+ }
+
+}
diff --git a/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/ApiResult.java b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/ApiResult.java
new file mode 100644
index 00000000..a39434b8
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/ApiResult.java
@@ -0,0 +1,74 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import lombok.Data;
+
+/**
+ * 默认的结果封装类.
+ *
+ *
+ * xml返回结果:
+ *
+ * 50
+ * Remote service error
+ * isv.invalid-parameter
+ * 非法参数
+ *
+ * 成功情况:
+ *
+ * 0
+ * 成功消息
+ *
+ * ...返回内容
+ *
+ *
+ *
+ * json返回格式:
+ * {
+ * "code":"50",
+ * "msg":"Remote service error",
+ * "sub_code":"isv.invalid-parameter",
+ * "sub_msg":"非法参数"
+ * }
+ * 成功情况:
+ * {
+ * "code":"0",
+ * "msg":"成功消息内容。。。",
+ * "data":{
+ * ...返回内容
+ * }
+ * }
+ *
+ *
+ * 字段说明:
+ * code:网关异常码
+ * msg:网关异常信息
+ * sub_code:业务异常码
+ * sub_msg:业务异常信息
+ *
+ * @author tanghc
+ */
+@XStreamAlias("response")
+@Data
+public class ApiResult {
+
+ /**
+ * 网关异常信息
+ */
+ private String msg;
+
+ /**
+ * 业务异常码
+ */
+ private String sub_msg;
+
+ /**
+ * 业务异常信息
+ */
+ private String sub_code;
+
+ /**
+ * 返回结果
+ */
+ private Object data;
+}
diff --git a/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/BookController.java b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/BookController.java
new file mode 100644
index 00000000..bde5634e
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/BookController.java
@@ -0,0 +1,73 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.gitee.book.api.domain.Book;
+import com.gitee.sop.bookweb.consumer.StoryServiceConsumer;
+import com.gitee.sop.bookweb.param.BookParam;
+import com.gitee.sop.story.api.domain.Story;
+import com.hhdd.book.api.service.BookService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+
+/**
+ * book服务
+ *
+ * @author tanghc
+ */
+@RestController
+public class BookController implements BookService {
+
+ @Autowired
+ StoryServiceConsumer storyServiceConsumer;
+
+ @Override
+ public Book getBook(int id) {
+ Book book = new Book();
+ book.setId(id);
+ book.setName("汪汪队");
+ return book;
+ }
+
+ @RequestMapping("listBookAndStory")
+ public Object listBookAndStory(int id) {
+ Book book = new Book();
+ book.setId(id);
+ book.setName("汪汪队");
+
+ // 调用story服务
+ Story story = storyServiceConsumer.getStory(id);
+
+ return Arrays.asList(book, story);
+ }
+
+ @RequestMapping("getBook2")
+ public Object getBookError(int id) {
+ if (id == 0) {
+ throw new RuntimeException("id不能为空");
+ }
+ Book book = new Book();
+ book.setId(id);
+ book.setName("汪汪队");
+ return Arrays.asList(book);
+ }
+
+
+
+ @RequestMapping("getBook3")
+ public Object getBook3(@RequestBody BookParam param) {
+ if (param.getId() == 0) {
+ throw new RuntimeException("id不能为空");
+ }
+ Book book = new Book();
+ book.setId(param.getId());
+ book.setName("小马宝莉");
+
+ ApiResult apiResult = new ApiResult();
+ apiResult.setData(book);
+ return apiResult;
+ }
+
+}
diff --git a/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/param/BookParam.java b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/param/BookParam.java
new file mode 100644
index 00000000..47703b09
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/param/BookParam.java
@@ -0,0 +1,11 @@
+package com.gitee.sop.bookweb.param;
+
+import lombok.Data;
+
+/**
+ * @author tanghc
+ */
+@Data
+public class BookParam {
+ private int id;
+}
diff --git a/sop-example/sop-book/sop-book-web/src/main/resources/application.yml b/sop-example/sop-book/sop-book-web/src/main/resources/application.yml
new file mode 100644
index 00000000..2a74db4e
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/resources/application.yml
@@ -0,0 +1,9 @@
+server:
+ port: 3333
+
+eureka:
+ port: 1111
+ host: localhost
+ client:
+ serviceUrl:
+ defaultZone: http://${eureka.host}:${eureka.port}/eureka/
\ No newline at end of file
diff --git a/sop-example/sop-book/sop-book-web/src/main/resources/bootstrap.yml b/sop-example/sop-book/sop-book-web/src/main/resources/bootstrap.yml
new file mode 100644
index 00000000..ca23c4f1
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/main/resources/bootstrap.yml
@@ -0,0 +1,7 @@
+spring:
+ application:
+ name: book-service
+
+ cloud:
+ zookeeper:
+ connect-string: localhost:2181
\ No newline at end of file
diff --git a/sop-example/sop-book/sop-book-web/src/test/java/com/gitee/sop/bookweb/SopBookApplicationTests.java b/sop-example/sop-book/sop-book-web/src/test/java/com/gitee/sop/bookweb/SopBookApplicationTests.java
new file mode 100644
index 00000000..6fa12ac2
--- /dev/null
+++ b/sop-example/sop-book/sop-book-web/src/test/java/com/gitee/sop/bookweb/SopBookApplicationTests.java
@@ -0,0 +1,17 @@
+package com.gitee.sop.bookweb;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class SopBookApplicationTests {
+
+ @Test
+ public void contextLoads() {
+ }
+
+}
+
diff --git a/sop-example/sop-story/pom.xml b/sop-example/sop-story/pom.xml
new file mode 100644
index 00000000..b2da4384
--- /dev/null
+++ b/sop-example/sop-story/pom.xml
@@ -0,0 +1,15 @@
+
+
+ 4.0.0
+ com.gitee.sop-story
+ sop-story-parent
+ 1.0.0-SNAPSHOT
+ pom
+
+
+ sop-story-api
+ sop-story-web
+
+
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-api/.gitignore b/sop-example/sop-story/sop-story-api/.gitignore
new file mode 100644
index 00000000..c456c4a3
--- /dev/null
+++ b/sop-example/sop-story/sop-story-api/.gitignore
@@ -0,0 +1,25 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
diff --git a/sop-example/sop-story/sop-story-api/pom.xml b/sop-example/sop-story/sop-story-api/pom.xml
new file mode 100644
index 00000000..103848c1
--- /dev/null
+++ b/sop-example/sop-story/sop-story-api/pom.xml
@@ -0,0 +1,46 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.2.RELEASE
+
+
+ com.gitee.sop
+ sop-story-api
+ 1.0-SNAPSHOT
+
+
+ 1.8
+ Greenwich.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+ provided
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-api/src/main/java/com/gitee/sop/story/api/domain/Story.java b/sop-example/sop-story/sop-story-api/src/main/java/com/gitee/sop/story/api/domain/Story.java
new file mode 100644
index 00000000..d2cfbae0
--- /dev/null
+++ b/sop-example/sop-story/sop-story-api/src/main/java/com/gitee/sop/story/api/domain/Story.java
@@ -0,0 +1,18 @@
+package com.gitee.sop.story.api.domain;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author tanghc
+ */
+@Data
+public class Story {
+ private int id;
+
+ @NotBlank(message = "name不能为空")
+ @Length(max = 20, message = "name长度不能超过20")
+ private String name;
+}
diff --git a/sop-example/sop-story/sop-story-api/src/main/java/com/gitee/sop/story/api/service/StoryService.java b/sop-example/sop-story/sop-story-api/src/main/java/com/gitee/sop/story/api/service/StoryService.java
new file mode 100644
index 00000000..0b3c9794
--- /dev/null
+++ b/sop-example/sop-story/sop-story-api/src/main/java/com/gitee/sop/story/api/service/StoryService.java
@@ -0,0 +1,15 @@
+package com.gitee.sop.story.api.service;
+
+import com.gitee.sop.story.api.domain.Story;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * @author tanghc
+ */
+@RequestMapping("/story")
+public interface StoryService {
+ @RequestMapping("/getStory")
+ Story getStory(@RequestParam("id")/* 必须指定@RequestParam,且value不能少 */
+ int id);
+}
diff --git a/sop-example/sop-story/sop-story-web/.gitignore b/sop-example/sop-story/sop-story-web/.gitignore
new file mode 100644
index 00000000..c456c4a3
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/.gitignore
@@ -0,0 +1,25 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
diff --git a/sop-example/sop-story/sop-story-web/pom.xml b/sop-example/sop-story/sop-story-web/pom.xml
new file mode 100644
index 00000000..e03b1d40
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/pom.xml
@@ -0,0 +1,84 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.2.RELEASE
+
+
+ com.gitee.sop
+ sop-story-web
+ 0.0.1-SNAPSHOT
+ sop-story
+ Demo project for Spring Boot
+
+
+ 1.8
+ Greenwich.RELEASE
+
+
+
+
+ com.gitee.sop
+ sop-service-common
+ 1.0.0-SNAPSHOT
+
+
+ com.gitee.sop
+ sop-story-api
+ 1.0-SNAPSHOT
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+ provided
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+
+
+
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/SopStoryApplication.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/SopStoryApplication.java
new file mode 100644
index 00000000..16617166
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/SopStoryApplication.java
@@ -0,0 +1,16 @@
+package com.gitee.sop.bookweb;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+@EnableDiscoveryClient
+@SpringBootApplication
+public class SopStoryApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SopStoryApplication.class, args);
+ }
+
+}
+
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java
new file mode 100644
index 00000000..4aeba862
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java
@@ -0,0 +1,31 @@
+package com.gitee.sop.bookweb.config;
+
+import com.gitee.sop.servercommon.bean.ServiceConfig;
+import com.gitee.sop.servercommon.configuration.AlipayServiceConfiguration;
+import com.gitee.sop.servercommon.configuration.TaobaoServiceConfiguration;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * 使用支付宝开放平台功能
+ * @author tanghc
+ */
+@Configuration
+public class OpenServiceConfig extends AlipayServiceConfiguration {
+
+
+ static {
+ ServiceConfig.getInstance().getI18nModules().add("i18n/isp/goods_error");
+ }
+
+}
+
+/**
+ * 使用淘宝开放平台功能
+ * @author tanghc
+ */
+//@Configuration
+//public class OpenServiceConfig extends TaobaoServiceConfiguration {
+//
+//}
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayController.java
new file mode 100644
index 00000000..ab433fd0
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayController.java
@@ -0,0 +1,27 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.gitee.sop.servercommon.annotation.ApiMapping;
+import com.gitee.sop.story.api.domain.Story;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 支付宝服务端,假设签名验证通过后,到达这里进行具体的业务处理。
+ * 这里演示如何接受业务参数。
+ * @author tanghc
+ */
+@RestController
+public class AlipayController {
+
+ @ApiMapping(value = "alipay.story.get")
+ public Story getStory() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队(alipay.story.get)");
+ return story;
+ }
+
+ @ApiMapping(value = "alipay.story.get", version = "1.2")
+ public Story getStory11(Story story) {
+ return story;
+ }
+}
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/JSR303DemoController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/JSR303DemoController.java
new file mode 100644
index 00000000..f04340d5
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/JSR303DemoController.java
@@ -0,0 +1,18 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.gitee.sop.bookweb.controller.param.GoodsParam;
+import com.gitee.sop.servercommon.annotation.ApiMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 演示参数验证
+ * @author tanghc
+ */
+@RestController
+public class JSR303DemoController {
+
+ @ApiMapping(value = "goods.add")
+ public Object addGoods(GoodsParam param) {
+ return param;
+ }
+}
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/Story2Controller.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/Story2Controller.java
new file mode 100644
index 00000000..6f37e27a
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/Story2Controller.java
@@ -0,0 +1,46 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.gitee.sop.servercommon.annotation.ApiAbility;
+import com.gitee.sop.servercommon.annotation.ApiMapping;
+import com.gitee.sop.story.api.domain.Story;
+import com.gitee.sop.story.api.service.StoryService;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author tanghc
+ */
+@ApiAbility // 放在这里,下面所有的接口都具备接口提供能力
+@RestController
+@RequestMapping("story2")
+public class Story2Controller{
+
+ @RequestMapping("getStory4")
+ public Story getStory4() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队(getStory4)");
+ return story;
+ }
+
+ // 优先使用方法上@ApiAbility
+ @ApiAbility(version = "1.4")
+ @RequestMapping("getStory4")
+ public Story storyget() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队(1.4)");
+ return story;
+ }
+
+ // 优先使用@ApiMapping
+ @ApiMapping(value = "story.get2")
+ public Story getStory2() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队story.get2");
+ return story;
+ }
+
+
+}
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/StoryController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/StoryController.java
new file mode 100644
index 00000000..d2233e6f
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/StoryController.java
@@ -0,0 +1,85 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.gitee.sop.servercommon.annotation.ApiMapping;
+import com.gitee.sop.servercommon.annotation.ApiAbility;
+import com.gitee.sop.story.api.domain.Story;
+import com.gitee.sop.story.api.service.StoryService;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author tanghc
+ */
+@RestController
+public class StoryController implements StoryService {
+
+ // 提供给Feign的服务
+ @Override
+ public Story getStory(int id) {
+ Story story = new Story();
+ story.setId(id);
+ story.setName("海底小纵队(Feign)");
+ return story;
+ }
+
+ // http://localhost:2222/story/story_get
+ // 原生的接口,可正常调用
+ @RequestMapping("story_get")
+ public Story getStory4() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队(原生)");
+ return story;
+ }
+
+ // http://localhost:2222/story/story.get/
+ // 接口名,使用默认版本号
+ @ApiMapping(value = "story.get")
+ public Story storyget() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队(默认版本号)");
+ return story;
+ }
+
+ // http://localhost:2222/story/story.get/?version=1.1
+ // 接口名 + 版本号
+ @ApiMapping(value = "story.get", version = "1.1")
+ public Story getStory2() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队1.0");
+ return story;
+ }
+
+ // http://localhost:2222/story/story.get/?version=2.0
+ // 接口名 + 版本号
+ @ApiMapping(value = "story.get", version = "2.0")
+ public Story getStory20(Story story) {
+ return story;
+ }
+
+ // http://localhost:2222/story/getStory2
+ // 遗留接口具备开放平台能力
+ @ApiAbility
+ @RequestMapping("getStory2")
+ public Story getStory2_0() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队(默认版本号)");
+ return story;
+ }
+
+ // http://localhost:2222/story/getStory2?version=2.1
+ // 在原来的基础上加版本号
+ @ApiAbility(version = "2.1")
+ @RequestMapping("getStory2")
+ public Story getStory2_1() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("海底小纵队2.1");
+ return story;
+ }
+
+
+}
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/StoryDemoController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/StoryDemoController.java
new file mode 100644
index 00000000..fbc8a31f
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/StoryDemoController.java
@@ -0,0 +1,21 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.gitee.sop.servercommon.annotation.ApiMapping;
+import com.gitee.sop.story.api.domain.Story;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author tanghc
+ */
+@RestController
+public class StoryDemoController {
+
+ @ApiMapping(value = "story.demo.get")
+ public Story getStory() {
+ Story story = new Story();
+ story.setId(1);
+ story.setName("白雪公主");
+ return story;
+ }
+
+}
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/ThrowExceptionDemoController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/ThrowExceptionDemoController.java
new file mode 100644
index 00000000..8fe8b7db
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/ThrowExceptionDemoController.java
@@ -0,0 +1,33 @@
+package com.gitee.sop.bookweb.controller;
+
+import com.gitee.sop.bookweb.controller.param.GoodsUpdateParam;
+import com.gitee.sop.bookweb.message.GoodsErrorEnum;
+import com.gitee.sop.servercommon.annotation.ApiMapping;
+import com.gitee.sop.servercommon.exception.ServiceException;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 演示如何抛出异常
+ * @author tanghc
+ */
+@RestController
+public class ThrowExceptionDemoController {
+
+ @ApiMapping(value = "goods.update")
+ public Object updateGoods(GoodsUpdateParam param) {
+ // 方式1
+ if ("iphone6".equals(param.getGoods_name())) {
+ throw new ServiceException("不能更新iphone6");
+ }
+ // 方式2,国际化
+ if (StringUtils.isEmpty(param.getGoods_name())) {
+ throw GoodsErrorEnum.NO_GOODS_NAME.getErrorMeta().getException();
+ }
+ // 方式3,国际化传参
+ if (param.getGoods_name().length() <= 3) {
+ throw GoodsErrorEnum.LESS_GOODS_NAME_LEN.getErrorMeta().getException(3);
+ }
+ return param;
+ }
+}
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/param/GoodsParam.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/param/GoodsParam.java
new file mode 100644
index 00000000..333cd59d
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/param/GoodsParam.java
@@ -0,0 +1,19 @@
+package com.gitee.sop.bookweb.controller.param;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotEmpty;
+
+@Data
+public class GoodsParam {
+// @NotEmpty(message = "商品名称不能为空")
+ private String goods_name;
+
+ @NotEmpty(message = "{goods.remark.notNull}")
+ private String goods_remark;
+
+ // 传参的格式:{xxx}=value1,value2...
+ @Length(min = 3, max = 20, message = "{goods.comment.length}=3,20")
+ private String goods_comment;
+}
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/param/GoodsUpdateParam.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/param/GoodsUpdateParam.java
new file mode 100644
index 00000000..3aab1d06
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/param/GoodsUpdateParam.java
@@ -0,0 +1,9 @@
+package com.gitee.sop.bookweb.controller.param;
+
+import lombok.Data;
+
+@Data
+public class GoodsUpdateParam {
+ private String goods_name;
+
+}
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/message/GoodsErrorEnum.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/message/GoodsErrorEnum.java
new file mode 100644
index 00000000..77a3265a
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/message/GoodsErrorEnum.java
@@ -0,0 +1,20 @@
+package com.gitee.sop.bookweb.message;
+
+import com.gitee.sop.servercommon.message.ServiceErrorMeta;
+
+public enum GoodsErrorEnum {
+ /** 参数错误 */
+ NO_GOODS_NAME("100"),
+ /** 参数长度太短 */
+ LESS_GOODS_NAME_LEN("101"),
+ ;
+ private ServiceErrorMeta errorMeta;
+
+ GoodsErrorEnum(String subCode) {
+ this.errorMeta = new ServiceErrorMeta("isp.goods_error_", subCode);
+ }
+
+ public ServiceErrorMeta getErrorMeta() {
+ return errorMeta;
+ }
+}
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/message/StoryErrorEnum.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/message/StoryErrorEnum.java
new file mode 100644
index 00000000..23c29395
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/message/StoryErrorEnum.java
@@ -0,0 +1,21 @@
+package com.gitee.sop.bookweb.message;
+
+import com.gitee.sop.servercommon.message.ServiceErrorMeta;
+
+/**
+ * @author tanghc
+ */
+public enum StoryErrorEnum {
+ /** 参数错误 */
+ param_error("isv.invalid-parameter"),
+ ;
+ private ServiceErrorMeta errorMeta;
+
+ StoryErrorEnum(String subCode) {
+ this.errorMeta = new ServiceErrorMeta("isp.error_", subCode);
+ }
+
+ public ServiceErrorMeta getErrorMeta() {
+ return errorMeta;
+ }
+}
diff --git a/sop-example/sop-story/sop-story-web/src/main/resources/application.yml b/sop-example/sop-story/sop-story-web/src/main/resources/application.yml
new file mode 100644
index 00000000..2972c510
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/resources/application.yml
@@ -0,0 +1,9 @@
+server:
+ port: 2222
+
+eureka:
+ port: 1111
+ host: localhost
+ client:
+ serviceUrl:
+ defaultZone: http://${eureka.host}:${eureka.port}/eureka/
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-web/src/main/resources/bootstrap.yml b/sop-example/sop-story/sop-story-web/src/main/resources/bootstrap.yml
new file mode 100644
index 00000000..0a4dcf3e
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/resources/bootstrap.yml
@@ -0,0 +1,8 @@
+spring:
+ application:
+ name: story-service
+ description: story服务
+
+ cloud:
+ zookeeper:
+ connect-string: localhost:2181
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/bizerror_en.properties b/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/bizerror_en.properties
new file mode 100644
index 00000000..48d134c8
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/bizerror_en.properties
@@ -0,0 +1,10 @@
+# 错误配置
+
+# 系统配置
+isp.error_isv.common-error=The system is busy.
+isp.error_isv.invalid-parameter=Invalid parameter, {0}
+
+# ==== 参数配置 ====
+
+goods.remark.notNull=The goods_remark can not be null
+goods.comment.length=The goods_comment length must >= {0} and <= {1}
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/bizerror_zh_CN.properties b/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/bizerror_zh_CN.properties
new file mode 100644
index 00000000..4ac48428
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/bizerror_zh_CN.properties
@@ -0,0 +1,14 @@
+# 错误配置
+
+# 系统繁忙
+isp.error_isv.common-error=\u7cfb\u7edf\u7e41\u5fd9
+# 参数无效
+isp.error_isv.invalid-parameter=\u53c2\u6570\u65e0\u6548, {0}
+
+# ==== 参数配置 ====
+
+# 商品备注不能为空
+goods.remark.notNull=\u5546\u54c1\u5907\u6ce8\u4e0d\u80fd\u4e3a\u7a7a
+# 商品评论长度必须在{0}和{1}之间
+goods.comment.length=\u5546\u54c1\u8bc4\u8bba\u957f\u5ea6\u5fc5\u987b\u5728{0}\u548c{1}\u4e4b\u95f4
+
diff --git a/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/goods_error_en.properties b/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/goods_error_en.properties
new file mode 100644
index 00000000..195c7d2b
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/goods_error_en.properties
@@ -0,0 +1,2 @@
+isp.goods_error_100=the goods_name can NOT be null
+isp.goods_error_101=the goods_name must bigger than {0}
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/goods_error_zh_CN.properties b/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/goods_error_zh_CN.properties
new file mode 100644
index 00000000..af1a43bc
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/main/resources/i18n/isp/goods_error_zh_CN.properties
@@ -0,0 +1,5 @@
+# 商品名字不能为空
+isp.goods_error_100=\u5546\u54C1\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
+
+# 商品名称太短,不能小于{0}个字
+isp.goods_error_101=\u5546\u54C1\u540D\u79F0\u592A\u77ED\uFF0C\u4E0D\u80FD\u5C0F\u4E8E{0}\u4E2A\u5B57
\ No newline at end of file
diff --git a/sop-example/sop-story/sop-story-web/src/test/java/com/gitee/sop/bookweb/SopStoryApplicationTests.java b/sop-example/sop-story/sop-story-web/src/test/java/com/gitee/sop/bookweb/SopStoryApplicationTests.java
new file mode 100644
index 00000000..ba442149
--- /dev/null
+++ b/sop-example/sop-story/sop-story-web/src/test/java/com/gitee/sop/bookweb/SopStoryApplicationTests.java
@@ -0,0 +1,17 @@
+package com.gitee.sop.bookweb;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class SopStoryApplicationTests {
+
+ @Test
+ public void contextLoads() {
+ }
+
+}
+