parent
							
								
									1c97e7f28e
								
							
						
					
					
						commit
						08bf664117
					
				| @ -0,0 +1,9 @@ | ||||
| # 开发文档 | ||||
| 
 | ||||
| 配合gitee pages服务使用,gitee pages服务指定docs目录。 | ||||
| 
 | ||||
| ## 本地查看开发文档 | ||||
| 
 | ||||
| - 前提:先安装好npm,[npm安装教程](https://blog.csdn.net/zhangwenwu2/article/details/52778521)。建议使用淘宝镜像。 | ||||
| - 安装docsify,执行npm命令`npm i docsify-cli -g --registry=https://registry.npm.taobao.org` | ||||
| - cd到当前目录,运行命令`docsify serve docs`,然后访问:`http://localhost:3000`即可查看。 | ||||
| @ -0,0 +1 @@ | ||||
| # 开发文档 | ||||
| @ -0,0 +1 @@ | ||||
| include: [_navbar,_sidebar] | ||||
| @ -0,0 +1,12 @@ | ||||
|  | ||||
| 
 | ||||
| # docsify <small>4.6.10</small> | ||||
| 
 | ||||
| > A magical documentation site generator. | ||||
| 
 | ||||
| * Simple and lightweight (~19kB gzipped) | ||||
| * No statically built html files | ||||
| * Multiple themes | ||||
| 
 | ||||
| [GitHub](https://github.com/QingWei-Li/docsify/) | ||||
| [Get Started](#docsify) | ||||
| @ -0,0 +1,3 @@ | ||||
| - 关于 | ||||
|   - [帮助](/zh-cn/) | ||||
|   - [API](/) | ||||
| @ -0,0 +1,6 @@ | ||||
| * 文档目录 | ||||
| 
 | ||||
|   * [错误处理](files/1004_错误处理.md?t=1553335182242) | ||||
|   * [新增接口](files/1002_新增接口.md?t=1553335182268) | ||||
|   * [快速体验](files/1001_快速体验.md?t=1553335182268) | ||||
|   * [业务参数校验](files/1003_业务参数校验.md?t=1553335182268) | ||||
| @ -0,0 +1,20 @@ | ||||
| # 快速体验 | ||||
| 
 | ||||
| > 运行环境:JDK8,Maven3,Zookeeper | ||||
| 
 | ||||
| - 安装并启动zookeeper,[安装教程](http://zookeeper.apache.org/doc/r3.4.13/zookeeperStarted.html) | ||||
| - IDE打开项目(IDEA下可以打开根pom.xml,然后open as project) | ||||
| - 启动注册中心,sop-registry(运行SopRegistryApplication.java) | ||||
| - 启动微服务:sop-story-web(运行SopStoryApplication.java) | ||||
| - 启动网关:sop-gateway(运行SopGatewayApplication.java) | ||||
| - 找到sop-test,打开测试用例,进行接口调用测试,运行com.gitee.sop.AlipayClientPostTest.testPost() | ||||
| 
 | ||||
| 确保注册中心先启动 | ||||
| 
 | ||||
| ## 使用admin | ||||
| 
 | ||||
| - 找到`sop-admin/sop-admin-server`工程,运行`com.gitee.sop.adminserver.SopAdminServerApplication.java` | ||||
| - 找到`sop-admin/sop-admin-front/index.html`文件,在IDEA下直接右键--Run'index.html' | ||||
| - 如果没有用到IDEA,则需要把sop-admin-front放到静态服务器中然后访问index.html | ||||
| 
 | ||||
| 
 | ||||
| @ -0,0 +1,140 @@ | ||||
| # 新增接口 | ||||
| 
 | ||||
| 以story服务为例,新增一个获取故事内容接口 | ||||
| 
 | ||||
| - 在controller下新建一个类,StoryDemoController.java | ||||
| - 加上`@RestController`注解 | ||||
| 
 | ||||
| ```java | ||||
| @RestController | ||||
| public class StoryDemoController { | ||||
|      | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| - 新增一个接口 | ||||
| 
 | ||||
| ```java | ||||
| @ApiMapping(value = "story.demo.get") | ||||
| public Story getStory() { | ||||
|     Story story = new Story(); | ||||
|     story.setId(1); | ||||
|     story.setName("白雪公主"); | ||||
|     return story; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 这里的`@ApiMapping`注解作用同`@RequestMapping`注解,可以理解为是它的扩展 | ||||
| 
 | ||||
| value就是接口名,对应客户端的`method`参数 | ||||
| 
 | ||||
| 如果要加上版本号,指定`version`参数:`@ApiMapping(value = "story.demo.get", version = "2.0")` | ||||
| 
 | ||||
| - 重启story服务,这样接口就可以使用了。 | ||||
| 
 | ||||
| ## 测试接口 | ||||
| 
 | ||||
| - 在sop-test工程下新建一个测试用例,`StoryDemoTest`,继承TestBase | ||||
| 
 | ||||
| ```java | ||||
| public class StoryDemoTest extends TestBase { | ||||
| 
 | ||||
|     String url = "http://localhost:8081/api"; // zuul | ||||
|     String appId = "alipay_test"; | ||||
|     // 私钥 | ||||
|     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 testDemo() throws Exception { | ||||
|         // 公共请求参数 | ||||
|         Map<String, String> params = new HashMap<String, String>(); | ||||
|         params.put("app_id", appId); | ||||
|         // 这里对应@ApiMapping.value属性 | ||||
|         params.put("method", "story.demo.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())); | ||||
|         // 这里对应@ApiMapping.version属性 | ||||
|         params.put("version", "1.0"); | ||||
| 
 | ||||
|         // 业务参数 | ||||
|         Map<String, String> bizContent = new HashMap<>(); | ||||
| 
 | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| - 请求成功后,控制台会打印: | ||||
| 
 | ||||
| ``` | ||||
| ----------- 请求信息 ----------- | ||||
| 请求参数:charset=utf-8&biz_content={}&method=story.demo.get&format=json&app_id=alipay_test&sign_type=RSA2&version=1.0×tamp=2019-03-23 15:41:22 | ||||
| 商户秘钥: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= | ||||
| 待签名内容:app_id=alipay_test&biz_content={}&charset=utf-8&format=json&method=story.demo.get&sign_type=RSA2×tamp=2019-03-23 15:41:22&version=1.0 | ||||
| 签名(sign):YMbxTPdovi6htcn1K3USTS6/Tbg6MOAMigG6x/kG0kQFCYH8ljvxXzcY86UT056nUG3OXxnj0xkw07eV6E03HMlu7bn3/jrT3PCcV3YguhA92aWz720x2xJWdfXY13OUPS9VOCC9zIVxu6EBD+PoZ7ojYChYvOfCR5I8bR/oOc0ZLjK63PWTBdf0eFS4sybXzRf81uNLMROsMhmBDDy0Fhml3ml77qzWBIpsmq5ECZ+89rMPbkNhAUcnFAe7ik7xZIL6WcUhAOhKVa8ZQK1GMjoGnAbGRed1FbuOHZGubgffg4/vMqrY10Bcy6h9jt/zK5w9L3HVgK3aPgQlfP16Gg== | ||||
| ----------- 返回结果 ----------- | ||||
| {"story_demo_get_response":{"msg":"Success","code":"10000","name":"白雪公主","id":1},"sign":"YMbxTPdovi6htcn1K3USTS6/Tbg6MOAMigG6x/kG0kQFCYH8ljvxXzcY86UT056nUG3OXxnj0xkw07eV6E03HMlu7bn3/jrT3PCcV3YguhA92aWz720x2xJWdfXY13OUPS9VOCC9zIVxu6EBD+PoZ7ojYChYvOfCR5I8bR/oOc0ZLjK63PWTBdf0eFS4sybXzRf81uNLMROsMhmBDDy0Fhml3ml77qzWBIpsmq5ECZ+89rMPbkNhAUcnFAe7ik7xZIL6WcUhAOhKVa8ZQK1GMjoGnAbGRed1FbuOHZGubgffg4/vMqrY10Bcy6h9jt/zK5w9L3HVgK3aPgQlfP16Gg=="} | ||||
| ``` | ||||
| 
 | ||||
| ## 开放现有接口 | ||||
| 
 | ||||
| 如果想把现有项目中的接口开放出去,提供给客户调用,具体操作如下: | ||||
| 
 | ||||
| 以springboot项目为例,springmvc目前暂不支持,以后可以支持。 | ||||
| 
 | ||||
| - 将现有项目注册到注册中心 | ||||
| - 在现有接口方法上加上一个注解`@ApiAbility`,如下面这个接口 | ||||
| 
 | ||||
| ```java | ||||
| // 遗留接口具备开放平台能力 | ||||
| @ApiAbility | ||||
| @RequestMapping("getStory2") | ||||
| public Story getStory2_0() { | ||||
|     Story story = new Story(); | ||||
|     story.setId(1); | ||||
|     story.setName("海底小纵队(默认版本号)"); | ||||
|     return story; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 这种情况下,老接口依然能正常访问,同时开放平台也能访问进来。 | ||||
| 
 | ||||
| **注意** 此时的开放接口对应的接口名为:类@RequestMapping.value + "." + 方法@RequestMapping.value | ||||
| 
 | ||||
| 举个列子: | ||||
| 
 | ||||
| ```java | ||||
| @RequestMapping("goods") | ||||
| public class MyController { | ||||
|     @ApiAbility | ||||
|     @RequestMapping("listGoods") | ||||
|     public Object fun() { | ||||
|          | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| fun接口对应的路径为:`/goods/listGoods` | ||||
| 
 | ||||
| 那么对应开放平台的接口名会转换成:`goods.listGoods`,客户端的method参数要填`goods.listGoods` | ||||
| 
 | ||||
| 当然也可以直接把@RequestMapping替换成`@ApiMapping`并指定接口名,这样的话不能兼容以前的访问形式。 | ||||
| 
 | ||||
| @ -0,0 +1,72 @@ | ||||
| # 业务参数校验 | ||||
| 
 | ||||
| 业务参数校验采用JSR-303方式,关于JSR-303介绍可以参考这篇博文:[JSR 303 - Bean Validation 介绍及最佳实践](https://www.ibm.com/developerworks/cn/java/j-lo-jsr303/) | ||||
| 
 | ||||
| 在参数中使用注解即可,框架会自动进行验证。如下面一个添加商品接口,它的参数是GoodsParam | ||||
| 
 | ||||
| ```java | ||||
| @ApiMapping(value = "goods.add") | ||||
| public void addGoods(GoodsParam param) { | ||||
|     ... | ||||
| } | ||||
| ``` | ||||
| 在GoodsParam中添加JSR-303注解: | ||||
| 
 | ||||
| ```java | ||||
| @Data | ||||
| public class GoodsParam { | ||||
|     @NotEmpty(message = "商品名称不能为空")     | ||||
|     private String goods_name; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 如果不传商品名称则返回 | ||||
| 
 | ||||
| ``` | ||||
| {"goods_add_response":{"msg":"Success","code":"10000","sub_msg":"商品名称不能为空","sub_code":"isv.invalid-parameter"},"sign":"Eh3Z5CxDCHsb4MyYFVxsPSmBpwVi1LISJdOkrzglxXoqG7RVyEOt4ef1kNpznUvMI3FDQU1suR7Rsmx6NjGdEVS6NSH2Kt0d8TFBRpLhWz8hApnxOtgzqMqbYeMuJie7X5gF6m8hTnvuuxF21IrkixMe+lyBcXw7dk0C3w1SwdEZkHQ+xC+M4bLqAZt5/3kl79/FWSMFJWHiZmg5YeEi8e8XhYCNcz+xlJRJL0x2Y87fFxqSY0UYWNxbQHgdVI8xRfn1n31nzkcLxiAtTh4LPtNRrG7w7absK/C1Oi/vczuBlFeq2EWUsYVWOVpKiJifUwvYVUUsztSLElzplzOjbg=="} | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| ## 参数校验国际化 | ||||
| 
 | ||||
| 国际化的配置方式如下: | ||||
| 
 | ||||
| ```java | ||||
| @NotEmpty(message = "{goods.remark.notNull}") | ||||
| private String goods_remark; | ||||
| ``` | ||||
| 
 | ||||
| 国际化资源文件`bizerror_en.properties`中添加: | ||||
| ``` | ||||
| goods.remark.notNull=The goods_remark can not be null | ||||
| ``` | ||||
| 
 | ||||
| bizerror_zh_CN.properties中添加: | ||||
| 
 | ||||
| ``` | ||||
| # 商品备注不能为空 | ||||
| goods.remark.notNull=\u5546\u54c1\u5907\u6ce8\u4e0d\u80fd\u4e3a\u7a7a | ||||
| ``` | ||||
| 
 | ||||
| ## 参数校验国际化传参 | ||||
| 
 | ||||
| 下面校验商品评论的长度,要求大于等于3且小于等于20。数字3和20要填充到国际化资源中去。 | ||||
| 
 | ||||
| ``` | ||||
| // 传参的格式:{xxx}=value1,value2... | ||||
| @Length(min = 3, max = 20, message = "{goods.comment.length}=3,20") | ||||
| private String goods_comment; | ||||
| ``` | ||||
| 
 | ||||
| bizerror_en.properties: | ||||
| ``` | ||||
| goods.comment.length=The goods_comment length must >= {0} and <= {1} | ||||
| ``` | ||||
| 
 | ||||
| bizerror_zh_CN.properties中添加: | ||||
| 
 | ||||
| ``` | ||||
| # 商品评论长度必须在{0}和{1}之间 | ||||
| goods.comment.length=\u5546\u54c1\u8bc4\u8bba\u957f\u5ea6\u5fc5\u987b\u5728{0}\u548c{1}\u4e4b\u95f4 | ||||
| ``` | ||||
| 这样value1,value2会分别填充到{0},{1}中 | ||||
| @ -0,0 +1,91 @@ | ||||
| # 错误处理 | ||||
| 
 | ||||
| SOP对错误处理已经封装好了,简单做法是`throw ServiceException`,在最顶层的Controller会做统一处理。例如: | ||||
| 
 | ||||
| ```java | ||||
| if(StringUtils.isEmpty(param.getGoods_name())) { | ||||
|     throw new ServiceException("goods_name不能为null"); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 为了保证编码风格的一致性,推荐统一使用ServiceException | ||||
| 
 | ||||
| ## i18n国际化 | ||||
| 
 | ||||
| SOP支持国际化消息。通过Request对象中的getLocale()来决定具体返回那种语言,客户端通过设置Accept-Language头部来决定返回哪种语言,中文是zh,英文是en。 | ||||
| 
 | ||||
| SOP通过模块化来管理国际化消息,这样做的好处结构清晰,维护方便。下面就来讲解如何设置国际化消息。 | ||||
| 
 | ||||
| 以story服务为例,假设我们要对商品模块进行设置,步骤如下: | ||||
| 
 | ||||
| - 在`resource/i18n/isp`目录下新建goods_error_zh_CN.properties属性文件 | ||||
| 
 | ||||
| 属性文件的文件名有规律, **i18n/isp/goods_error** 表示模块路径, **_zh_CN.properties** 表示中文错误消息。如果要使用英文错误,则新建一个`goods_error_en.properties`即可。 | ||||
| 
 | ||||
| - 在goods_error_zh_CN.properties中配置错误信息 | ||||
| 
 | ||||
| ``` | ||||
| # 商品名字不能为空 | ||||
| isp.goods_error_100=\u5546\u54C1\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A | ||||
| ``` | ||||
| 
 | ||||
| isp.goods_error_为固定前缀,100为错误码,这两个值后续会用到。 | ||||
| 
 | ||||
| 接下来是把属性文件加载到国际化容器当中。 | ||||
| 
 | ||||
| - 添加国际化配置,在OpenServiceConfig中的static块中添加,代码如下: | ||||
| 
 | ||||
| ```java | ||||
| @Configuration | ||||
| public class OpenServiceConfig extends AlipayServiceConfiguration { | ||||
| 
 | ||||
|     static { | ||||
|         ServiceConfig.getInstance().getI18nModules().add("i18n/isp/goods_error"); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| - 新建一个枚举用来定义错误 | ||||
| 
 | ||||
| ```java | ||||
| // 按模块来定义异常消息,团队开发可以分开进行 | ||||
| public enum  GoodsErrorEnum { | ||||
|     /** 参数错误 */ | ||||
|     NO_GOODS_NAME("100"), | ||||
|     ; | ||||
|     private ServiceErrorMeta errorMeta; | ||||
| 
 | ||||
|     StoryErrorEnum(String subCode) { | ||||
|         this.errorMeta = new ServiceErrorMeta("isp.goods_error_", subCode); | ||||
|     } | ||||
| 
 | ||||
|     public ServiceErrorMeta getErrorMeta() { | ||||
|         return errorMeta; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| 接下来就可以使用了 | ||||
| 
 | ||||
| ```java | ||||
| if (StringUtils.isEmpty(param.getGoods_name())) { | ||||
|     throw GoodsErrorEnum.NO_GOODS_NAME.getErrorMeta().getException(); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### 国际化消息传参 | ||||
| 
 | ||||
| 即代码中变量传入到properties文件中去,做法是采用{0},{1}占位符。0代表第一个参数,1表示第二个参数。 | ||||
| 
 | ||||
| ``` | ||||
| # 商品名称太短,不能小于{0}个字 | ||||
| isp.goods_error_101=\u5546\u54C1\u540D\u79F0\u592A\u77ED\uFF0C\u4E0D\u80FD\u5C0F\u4E8E{0}\u4E2A\u5B57 | ||||
| ``` | ||||
| 
 | ||||
| ```java | ||||
| if (param.getGoods_name().length() <= 3) { | ||||
|     throw GoodsErrorEnum.LESS_GOODS_NAME_LEN.getErrorMeta().getException(3); | ||||
| } | ||||
| ``` | ||||
| 直接放进getException(Object... params)方法参数中,因为是可变参数,可随意放。 | ||||
| @ -0,0 +1,68 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| 
 | ||||
| <head> | ||||
|   <meta charset="UTF-8"> | ||||
|   <title>SOP开发文档</title> | ||||
|   <link rel="icon" href="_media/favicon.ico"> | ||||
|   <meta name="google-site-verification" content="6t0LoIeFksrjF4c9sqUEsVXiQNxLp2hgoqo0KryT-sE" /> | ||||
|   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> | ||||
|   <meta name="keywords" content="doc,docs,documentation,gitbook,creator,generator,github,jekyll,github-pages"> | ||||
|   <meta name="description" content="A magical documentation generator."> | ||||
|   <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> | ||||
|   <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css" title="vue" > | ||||
|   <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/dark.css" title="dark" disabled> | ||||
|   <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/buble.css" title="buble" disabled> | ||||
|   <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/pure.css" title="pure" disabled> | ||||
|   <style> | ||||
|     nav.app-nav li ul { | ||||
|       min-width: 100px; | ||||
|     } | ||||
| 	/* 显示区域宽度 */ | ||||
| 	.markdown-section{ | ||||
| 		max-width: 90%; | ||||
| 	} | ||||
|     .sidebar li { | ||||
|       margin: 0px 0; | ||||
|     } | ||||
|   </style> | ||||
| </head> | ||||
| 
 | ||||
| <body> | ||||
|   <div id="app">加载中 ...</div> | ||||
|   <script> | ||||
|     window.$docsify = {       | ||||
|       auto2top: true, | ||||
|       coverpage: false, | ||||
|       executeScript: true, | ||||
|       loadSidebar: true, | ||||
|       loadNavbar: false, | ||||
|       mergeNavbar: true, | ||||
|       maxLevel: 4, | ||||
|       subMaxLevel: 2, | ||||
|       ga: 'UA-106147152-1', | ||||
|       name: '', | ||||
|       search: { | ||||
|         noData: { | ||||
|           '/zh-cn/': '没有结果!', | ||||
|           '/': '没有结果!' | ||||
|         }, | ||||
|         paths: 'auto', | ||||
|         placeholder: { | ||||
|           '/zh-cn/': '搜索', | ||||
|           '/': '搜索' | ||||
|         } | ||||
|       }, | ||||
|       formatUpdated: '{MM}/{DD} {HH}:{mm}'     | ||||
|     } | ||||
|   </script> | ||||
|   <script src="//unpkg.com/docsify/lib/docsify.min.js"></script> | ||||
|   <script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script> | ||||
|   <script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script> | ||||
|   <script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script> | ||||
|   <script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script> | ||||
|   <script src="//unpkg.com/prismjs/components/prism-java.min.js"></script> | ||||
|   <script src="//unpkg.com/prismjs/components/prism-json.min.js"></script> | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
| @ -0,0 +1,49 @@ | ||||
| <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"> | ||||
| 	<modelVersion>4.0.0</modelVersion> | ||||
| 	<groupId>com.gitee.sop</groupId> | ||||
| 	<artifactId>doc</artifactId> | ||||
| 	<version>1.0.0-SNAPSHOT</version> | ||||
| 
 | ||||
| 	<properties> | ||||
| 		<!-- Generic properties --> | ||||
| 		<java.version>1.8</java.version> | ||||
| 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
| 		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | ||||
| 	</properties> | ||||
| 
 | ||||
| 	<dependencies> | ||||
| 		<dependency> | ||||
| 			<groupId>junit</groupId> | ||||
| 			<artifactId>junit</artifactId> | ||||
| 			<version>4.8</version> | ||||
| 			<scope>test</scope> | ||||
| 		</dependency> | ||||
| 
 | ||||
| 	</dependencies> | ||||
| 
 | ||||
| 	<build> | ||||
| 		<plugins> | ||||
| 			<!-- 打包时跳过测试 --> | ||||
| 			<plugin> | ||||
| 				<groupId>org.apache.maven.plugins</groupId> | ||||
| 				<artifactId>maven-surefire-plugin</artifactId> | ||||
| 				<version>2.18.1</version> | ||||
| 				<configuration> | ||||
| 					<skipTests>true</skipTests> | ||||
| 				</configuration> | ||||
| 			</plugin> | ||||
| 			<plugin> | ||||
| 				<groupId>org.apache.maven.plugins</groupId> | ||||
| 				<artifactId>maven-compiler-plugin</artifactId> | ||||
| 				<version>2.3.2</version> | ||||
| 				<configuration> | ||||
| 					<source>${java.version}</source> | ||||
| 					<target>${java.version}</target> | ||||
| 					<encoding>${project.build.sourceEncoding}</encoding> | ||||
| 				</configuration> | ||||
| 			</plugin> | ||||
| 		</plugins> | ||||
| 	</build> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1 @@ | ||||
| docsify serve docs | ||||
| @ -0,0 +1,55 @@ | ||||
| const liveServer = require('live-server') | ||||
| const isSSR = !!process.env.SSR | ||||
| const middleware = [] | ||||
| 
 | ||||
| if (isSSR) { | ||||
|   const Renderer = require('./packages/docsify-server-renderer/build.js') | ||||
|   const renderer = new Renderer({ | ||||
|     template: ` | ||||
|   <!DOCTYPE html> | ||||
|   <html lang="en"> | ||||
|   <head> | ||||
|     <meta charset="UTF-8"> | ||||
|     <title>docsify</title> | ||||
|     <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> | ||||
|     <link rel="stylesheet" href="/themes/vue.css" title="vue"> | ||||
|   </head> | ||||
|   <body> | ||||
|     <!--inject-app--> | ||||
|     <!--inject-config--> | ||||
|   <script src="/lib/docsify.js"></script> | ||||
|   </body> | ||||
|   </html>`, | ||||
|     config: { | ||||
|       name: 'docsify', | ||||
|       repo: 'docsifyjs/docsify', | ||||
|       basePath: 'https://docsify.js.org/', | ||||
|       loadNavbar: true, | ||||
|       loadSidebar: true, | ||||
|       subMaxLevel: 3, | ||||
|       auto2top: true, | ||||
|       alias: { | ||||
|         '/de-de/changelog': '/changelog', | ||||
|         '/zh-cn/changelog': '/changelog', | ||||
|         '/changelog': | ||||
|           'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG' | ||||
|       } | ||||
|     }, | ||||
|     path: './' | ||||
|   }) | ||||
| 
 | ||||
|   middleware.push(function(req, res, next) { | ||||
|     if (/\.(css|js)$/.test(req.url)) { | ||||
|       return next() | ||||
|     } | ||||
|     renderer.renderToString(req.url).then(html => res.end(html)) | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| const params = { | ||||
|   port: 3000, | ||||
|   watch: ['lib', 'docs', 'themes'], | ||||
|   middleware | ||||
| } | ||||
| 
 | ||||
| liveServer.start(params) | ||||
| @ -0,0 +1,39 @@ | ||||
| package com.gitee.sop.doc; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| 
 | ||||
| /** | ||||
|  * 生成_sidebar.md文件,直接运行即可 | ||||
|  * @author tanghc | ||||
|  */ | ||||
| public class SidebarTest { | ||||
| 
 | ||||
| 	static String format = "  * [%s](files/%s?t=%s)\r\n"; | ||||
| 	static String sidebar_format = "* 文档目录\r\n\r\n%s"; | ||||
| 
 | ||||
| 	public static void main(String[] args) throws Exception { | ||||
| 		String path = SidebarTest.class.getClassLoader().getResource("").getPath(); | ||||
| 		String root = path.substring(0, path.indexOf("doc")) + "doc"; | ||||
| 		String fileDir = root + "/docs/files"; | ||||
| 		File dir = new File(fileDir); | ||||
| 		File[] files = dir.listFiles(); | ||||
| 		StringBuilder output = new StringBuilder(); | ||||
| 		for (File file : files) { | ||||
| 			String filename = file.getName(); | ||||
| 			String title = filename.substring(filename.indexOf("_") + 1, filename.length() - 3); | ||||
| 			String line = String.format(format, title, filename, System.currentTimeMillis()); | ||||
| 			output.append(line); | ||||
| 		} | ||||
| 
 | ||||
| 		String sidebarContent = String.format(sidebar_format, output.toString()); | ||||
| 
 | ||||
| 		System.out.println(sidebarContent); | ||||
| 
 | ||||
| 		String sidebarFilepath = root + "/docs/_sidebar.md"; | ||||
| 
 | ||||
| 		FileOutputStream out = new FileOutputStream(new File(sidebarFilepath)); | ||||
| 		out.write(sidebarContent.getBytes()); | ||||
| 		out.close(); | ||||
| 	} | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
| @ -0,0 +1,9 @@ | ||||
| package com.gitee.sop.bookweb.controller.param; | ||||
| 
 | ||||
| import lombok.Data; | ||||
| 
 | ||||
| @Data | ||||
| public class GoodsUpdateParam { | ||||
|     private String goods_name; | ||||
| 
 | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
| @ -1,3 +1,10 @@ | ||||
| # 错误配置 | ||||
| 
 | ||||
| isp.error_isv.invalid-parameter=Invalid parameter, {0} | ||||
| # 系统配置 | ||||
| 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} | ||||
| @ -1,4 +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 | ||||
| 
 | ||||
|  | ||||
| @ -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} | ||||
| @ -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 | ||||
| @ -0,0 +1,58 @@ | ||||
| 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; | ||||
| 
 | ||||
| /** | ||||
|  * @author tanghc | ||||
|  */ | ||||
| public class JSR303DemoTest extends TestBase { | ||||
| 
 | ||||
|     String url = "http://localhost:8081/api"; // zuul
 | ||||
|     String appId = "alipay_test"; | ||||
|     // 支付宝私钥
 | ||||
|     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 testGoodsAdd() throws Exception { | ||||
|         // 公共请求参数
 | ||||
|         Map<String, String> params = new HashMap<String, String>(); | ||||
|         params.put("app_id", appId); | ||||
|         params.put("method", "goods.add"); | ||||
|         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<String, String> bizContent = new HashMap<>(); | ||||
|         // 对应校验规则查看GoodsParam.java
 | ||||
|         bizContent.put("goods_name", "iphone6"); | ||||
|         bizContent.put("goods_remark", "iphone6"); | ||||
|         bizContent.put("goods_comment", "1"); | ||||
| 
 | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,87 @@ | ||||
| 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; | ||||
| 
 | ||||
| /** | ||||
|  * @author tanghc | ||||
|  */ | ||||
| public class StoryDemoTest extends TestBase { | ||||
| 
 | ||||
|     String url = "http://localhost:8081/api"; // zuul
 | ||||
|     String appId = "alipay_test"; | ||||
|     // 支付宝私钥
 | ||||
|     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 testDemo() throws Exception { | ||||
|         // 公共请求参数
 | ||||
|         Map<String, String> params = new HashMap<String, String>(); | ||||
|         params.put("app_id", appId); | ||||
|         params.put("method", "story.demo.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<String, String> bizContent = new HashMap<>(); | ||||
| 
 | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void testGoodsAdd() throws Exception { | ||||
|         // 公共请求参数
 | ||||
|         Map<String, String> params = new HashMap<String, String>(); | ||||
|         params.put("app_id", appId); | ||||
|         params.put("method", "goods.add"); | ||||
|         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<String, String> 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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,58 @@ | ||||
| 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; | ||||
| 
 | ||||
| /** | ||||
|  * @author tanghc | ||||
|  */ | ||||
| public class ThrowExceptionDemoTest extends TestBase { | ||||
| 
 | ||||
|     String url = "http://localhost:8081/api"; // zuul
 | ||||
|     String appId = "alipay_test"; | ||||
|     // 支付宝私钥
 | ||||
|     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 testGoodsAdd() throws Exception { | ||||
|         // 公共请求参数
 | ||||
|         Map<String, String> params = new HashMap<String, String>(); | ||||
|         params.put("app_id", appId); | ||||
|         params.put("method", "goods.update"); | ||||
|         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<String, String> bizContent = new HashMap<>(); | ||||
|         // 对应校验规则查看GoodsParam.java
 | ||||
|         bizContent.put("goods_name", "1"); | ||||
|         bizContent.put("goods_remark", "iphone6"); | ||||
|         bizContent.put("goods_comment", "1111"); | ||||
| 
 | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue