diff --git a/sop-common/pom.xml b/sop-common/pom.xml index fc4fea87..af8a267e 100644 --- a/sop-common/pom.xml +++ b/sop-common/pom.xml @@ -29,6 +29,8 @@ 3.8.1 1.11 3.4.12 + 2.0.1.Final + 6.0.13.Final @@ -74,6 +76,7 @@ + org.apache.zookeeper zookeeper @@ -92,6 +95,18 @@ ${fastjson.version} + + javax.validation + validation-api + ${validation-api.version} + + + org.hibernate + hibernate-validator + ${hibernate-validator.version} + + + 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} + ${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); + } + +}