org.apache.commons
diff --git a/sop-example/pom.xml b/sop-example/pom.xml
index a900cf0c..a3efa857 100644
--- a/sop-example/pom.xml
+++ b/sop-example/pom.xml
@@ -11,6 +11,7 @@
sop-story
sop-book
- sop-easyopen
+ sop-easyopen
+ sop-springmvc
\ No newline at end of file
diff --git a/sop-example/sop-springmvc/.gitignore b/sop-example/sop-springmvc/.gitignore
new file mode 100644
index 00000000..c456c4a3
--- /dev/null
+++ b/sop-example/sop-springmvc/.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-springmvc/pom.xml b/sop-example/sop-springmvc/pom.xml
new file mode 100644
index 00000000..c2812bb7
--- /dev/null
+++ b/sop-example/sop-springmvc/pom.xml
@@ -0,0 +1,164 @@
+
+
+ 4.0.0
+ com.gitee.sop
+ sop-springmvc
+ sop-springmvc
+ war
+ 1.0.0-SNAPSHOT
+
+
+ 1.8
+ 5.0.7.RELEASE
+ 1.6.10
+ 1.6.6
+
+
+
+
+
+ com.gitee.sop
+ sop-service-common
+ 1.2.0-SNAPSHOT
+
+
+
+ com.netflix.eureka
+ eureka-client
+ 1.7.0
+
+
+
+
+
+
+ org.springframework
+ spring-context
+ ${org.springframework-version}
+
+
+ org.springframework
+ spring-webmvc
+ ${org.springframework-version}
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.9.6
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.9.6
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.9.6
+
+
+
+
+ org.aspectj
+ aspectjrt
+ ${org.aspectj-version}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${org.slf4j-version}
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${org.slf4j-version}
+ runtime
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${org.slf4j-version}
+ runtime
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+
+
+
+ javax.inject
+ javax.inject
+ 1
+
+
+
+
+ javax.servlet
+ servlet-api
+ 2.5
+ provided
+
+
+ javax.servlet.jsp
+ jsp-api
+ 2.1
+ provided
+
+
+ javax.servlet
+ jstl
+ 1.2
+
+
+
+
+ junit
+ junit
+ 4.8
+ test
+
+
+ org.springframework
+ spring-tx
+ 5.1.5.RELEASE
+ compile
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.18.1
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ ${java-version}
+ UTF-8
+
+
+
+
+
diff --git a/sop-example/sop-springmvc/src/main/java/com/gitee/app/HomeController.java b/sop-example/sop-springmvc/src/main/java/com/gitee/app/HomeController.java
new file mode 100644
index 00000000..4253fcaa
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/java/com/gitee/app/HomeController.java
@@ -0,0 +1,54 @@
+package com.gitee.app;
+
+import com.gitee.app.model.Goods;
+import com.gitee.sop.servercommon.annotation.ApiMapping;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.math.BigDecimal;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Handles requests for the application home page.
+ */
+@Controller
+public class HomeController {
+
+ private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
+
+ /**
+ * Simply selects the home view to render by returning its name.
+ */
+ @RequestMapping(value = "/", method = RequestMethod.GET)
+ public String home(Locale locale, Model model) {
+ logger.info("Welcome home! The client locale is {}.", locale);
+
+ Date date = new Date();
+ DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
+
+ String formattedDate = dateFormat.format(date);
+
+ model.addAttribute("serverTime", formattedDate );
+
+ return "home";
+ }
+
+
+ @ApiMapping(value = "springmvc.goods.get")
+ @ResponseBody
+ public Goods getGoods(Goods param) {
+ Goods goods = new Goods();
+ goods.setId(1L);
+ goods.setGoods_name(param.getGoods_name() + " 1");
+ goods.setPrice(new BigDecimal(5000));
+ return goods;
+ }
+
+}
diff --git a/sop-example/sop-springmvc/src/main/java/com/gitee/app/config/EurekaInitAndRegisterListener.java b/sop-example/sop-springmvc/src/main/java/com/gitee/app/config/EurekaInitAndRegisterListener.java
new file mode 100644
index 00000000..b42fc11a
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/java/com/gitee/app/config/EurekaInitAndRegisterListener.java
@@ -0,0 +1,61 @@
+package com.gitee.app.config;
+
+import com.netflix.appinfo.ApplicationInfoManager;
+import com.netflix.appinfo.InstanceInfo;
+import com.netflix.appinfo.MyDataCenterInstanceConfig;
+import com.netflix.discovery.DefaultEurekaClientConfig;
+import com.netflix.discovery.DiscoveryManager;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * 初始化Eureka Client
+ * @author thc
+ */
+@Slf4j
+public class EurekaInitAndRegisterListener implements ServletContextListener {
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ // 初始化Eureka Client
+ log.info("Eureka初始化完成,正在注册Eureka Server");
+ DiscoveryManager.getInstance().initComponent(new MyInstanceConfig(), new DefaultEurekaClientConfig());
+ ApplicationInfoManager.getInstance().setInstanceStatus(InstanceInfo.InstanceStatus.UP);
+ }
+
+ /**
+ * * Notification that the servlet context is about to be shut down.
+ * * All servlets and filters have been destroy()ed before any
+ * * ServletContextListeners are notified of context
+ * * destruction.
+ *
+ * @param sce
+ */
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ DiscoveryManager.getInstance().shutdownComponent();
+ }
+
+ @Configuration
+ @PropertySource(value = "classpath:eureka-client.properties")
+ public static class AppConfig {
+
+ }
+
+ public static class MyInstanceConfig extends MyDataCenterInstanceConfig {
+ @Override
+ public String getHostName(boolean refresh) {
+ try {
+ return InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ return super.getHostName(refresh);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/sop-example/sop-springmvc/src/main/java/com/gitee/app/config/OpenServiceConfig.java b/sop-example/sop-springmvc/src/main/java/com/gitee/app/config/OpenServiceConfig.java
new file mode 100644
index 00000000..8569ac3e
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/java/com/gitee/app/config/OpenServiceConfig.java
@@ -0,0 +1,20 @@
+package com.gitee.app.config;
+
+import com.gitee.sop.servercommon.configuration.AlipayServiceConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+/**
+ * 使用支付宝开放平台功能
+ *
+ * @author tanghc
+ */
+public class OpenServiceConfig extends AlipayServiceConfiguration {
+
+ @Bean
+ @Override
+ public RequestMappingHandlerMapping requestMappingHandlerMapping() {
+ return super.requestMappingHandlerMapping();
+ }
+
+}
diff --git a/sop-example/sop-springmvc/src/main/java/com/gitee/app/model/Goods.java b/sop-example/sop-springmvc/src/main/java/com/gitee/app/model/Goods.java
new file mode 100644
index 00000000..b5331a0a
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/java/com/gitee/app/model/Goods.java
@@ -0,0 +1,17 @@
+package com.gitee.app.model;
+
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.math.BigDecimal;
+
+@Data
+public class Goods {
+
+ private Long id;
+ @NotBlank(message = "goods_name不能为空")
+ private String goods_name;
+ private BigDecimal price;
+
+}
diff --git a/sop-example/sop-springmvc/src/main/resources/eureka-client.properties b/sop-example/sop-springmvc/src/main/resources/eureka-client.properties
new file mode 100644
index 00000000..aae80c66
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/resources/eureka-client.properties
@@ -0,0 +1,27 @@
+# tomcat端口,根据实际情况填
+server.port=2223
+# 应用名称serviceId,根据实际情况填
+spring.application.name=sop-springmvc
+# 注册中心地址,根据实际情况填
+eureka.url=http://localhost:1111/eureka/
+# zookeeper地址,根据实际情况填
+spring.cloud.zookeeper.connect-string=localhost:2181
+
+# ----------- 以下内容不用改 -----------
+
+# 控制是否注册自身到eureka中,本项目虽然不对外提供服务,但需要Eureka监控,在Eureka列表上显示
+eureka.registration.enabled=true
+# eureka相关配置
+# 默认为true,以实现更好的基于区域的负载平衡。
+eureka.preferSameZone=true
+# 是否要使用基于DNS的查找来确定其他eureka服务器
+eureka.shouldUseDns=false
+# 由于shouldUseDns为false,因此我们使用以下属性来明确指定到eureka服务器的路由(eureka Server地址)
+eureka.serviceUrl.default=${eureka.url}
+eureka.decoderName=JacksonJson
+# 客户识别此服务的虚拟主机名,这里指的是eureka服务本身
+eureka.vipAddress=${spring.application.name}
+#服务指定应用名,这里指的是eureka服务本身
+eureka.name=${spring.application.name}
+#服务将被识别并将提供请求的端口
+eureka.port=${server.port}
diff --git a/sop-example/sop-springmvc/src/main/resources/log4j.xml b/sop-example/sop-springmvc/src/main/resources/log4j.xml
new file mode 100644
index 00000000..ef6038bc
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/resources/log4j.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sop-example/sop-springmvc/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
new file mode 100644
index 00000000..2956e9bb
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sop-example/sop-springmvc/src/main/webapp/WEB-INF/spring/root-context.xml b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/spring/root-context.xml
new file mode 100644
index 00000000..de9a5ddd
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/spring/root-context.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
diff --git a/sop-example/sop-springmvc/src/main/webapp/WEB-INF/views/home.jsp b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/views/home.jsp
new file mode 100644
index 00000000..e65155c0
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/views/home.jsp
@@ -0,0 +1,15 @@
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ page session="false" pageEncoding="utf-8" %>
+
+
+
+ Home
+
+
+
+ Hello world!
+
+
+ The time on the server is ${serverTime}.
+
+
diff --git a/sop-example/sop-springmvc/src/main/webapp/WEB-INF/web.xml b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..405adcf1
--- /dev/null
+++ b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+ contextConfigLocation
+ /WEB-INF/spring/root-context.xml
+
+
+
+
+ org.springframework.web.context.ContextLoaderListener
+
+
+
+ com.gitee.app.config.EurekaInitAndRegisterListener
+
+
+
+
+ appServlet
+ org.springframework.web.servlet.DispatcherServlet
+
+ contextConfigLocation
+ /WEB-INF/spring/appServlet/servlet-context.xml
+
+ 1
+
+
+
+ appServlet
+ /
+
+
+
diff --git a/sop-example/sop-springmvc/src/test/resources/log4j.xml b/sop-example/sop-springmvc/src/test/resources/log4j.xml
new file mode 100644
index 00000000..e807a3a7
--- /dev/null
+++ b/sop-example/sop-springmvc/src/test/resources/log4j.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sop-test/src/test/java/com/gitee/sop/SpringmvcDemoPostTest.java b/sop-test/src/test/java/com/gitee/sop/SpringmvcDemoPostTest.java
new file mode 100644
index 00000000..540216cc
--- /dev/null
+++ b/sop-test/src/test/java/com/gitee/sop/SpringmvcDemoPostTest.java
@@ -0,0 +1,57 @@
+package com.gitee.sop;
+
+import com.alibaba.fastjson.JSON;
+import com.gitee.sop.alipay.AlipaySignature;
+import org.junit.Test;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 模仿支付宝客户端请求接口
+ */
+public class SpringmvcDemoPostTest extends TestBase {
+
+ String url = "http://localhost:8081/api"; // zuul
+ String appId = "2019032617262200001";
+ // 支付宝私钥
+ String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ=";
+
+
+ @Test
+ public void testPost() throws Exception {
+
+ // 公共请求参数
+ Map params = new HashMap();
+ params.put("app_id", appId);
+ params.put("method", "springmvc.goods.get");
+ params.put("format", "json");
+ params.put("charset", "utf-8");
+ params.put("sign_type", "RSA2");
+ params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ params.put("version", "1.0");
+
+ // 业务参数
+ Map bizContent = new HashMap<>();
+ bizContent.put("goods_name", "iphone6");
+
+ params.put("biz_content", JSON.toJSONString(bizContent));
+
+ System.out.println("----------- 请求信息 -----------");
+ System.out.println("请求参数:" + buildParamQuery(params));
+ System.out.println("商户秘钥:" + privateKey);
+ String content = AlipaySignature.getSignContent(params);
+ System.out.println("待签名内容:" + content);
+ String sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8");
+ System.out.println("签名(sign):" + sign);
+
+ params.put("sign", sign);
+
+ System.out.println("----------- 返回结果 -----------");
+ String responseData = post(url, params);// 发送请求
+ System.out.println(responseData);
+ }
+
+}