最近在实现一个纯接口系统的需求,因为是支付类接口,所以考虑搭一套分布式的框架,跟后台系统隔离开来。
其实以前一直有疑问,接口是怎么调用与传输接收数据的呢?首先我们要了解:客户端与服务器常用数据交换格式xml、json、html;传输一般用http协议或者RPC协议
首先说xml
记得以前调过webService接口,就找了网上的例子当时好像是用的cxf框架,然后用xml配置暴露的接口,接口提供方可以用已实现序列化接口的对象来接收,当然,一般接口的数据结构没有那么简单,那我们也可以相对应的在我们要接收数据的对象里 加List或者对象属性来实现。cxf框架会自动把xml数据转化为我们所需的对象,底层传输的实际上是通过http协议传输xml数据(可以写一个拦截器获取发送的xml文件)。具体的可以参考:https://blog.csdn.net/a412588063/article/details/55049602
然后是json
xml传输数据的话一般是webSerivce,偏银行多一些;而Json则偏互联网多一些。暴露接口的话,我们可以写一个controller,用@RequestMapping("xxxx")来指定接口的调用地址;底层传输的都是json字符串,我们可以用String来接收,也可以用对象来接收(实现序列化接口),一般用的框架有阿里的fastjson跟springMvc自带的jackson
了解了如何调用和传输数据后,我们直接开始
首先附上一张框架的结构图(框架为开源框架,fork下来自己做了点调整,地址:https://gitee.com/jmdhappy/xxpay-master.git)
web包就是服务消费者,service包为服务提供者。消费者的controller里面只负责接收请求就可以了,具体的业务在服务提供者里面实现(common包跟dal包可以根据自己的选择放入web中或者单独拎出来),服务消费者跟服务提供者里都配有一个application.yml文件,其中消费者需要配置数据库连接,提供者因为只需要调用,正常不需要配置数据库;每个包里都有一个pom文件,最外层的父级pom设置packing为pom,其他Pom设置packing为jar,互相之间根据相互调用去引入依赖即可。附上各个Pom文件截图:
父级pom:
<?xml version="1.0" encoding="UTF-8"?> <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>org.xxpay</groupId> <artifactId>xxpay4dubbo</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <name>xxpay4dubbo</name> <description>xxpay4dubbo</description> <modules> <module>xxpay-common</module> <module>xxpay-dal</module> <module>xxpay4dubbo-api</module> <module>xxpay4dubbo-web</module> <module>xxpay4dubbo-service</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.6.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <springboot.version>1.5.6.RELEASE</springboot.version> <springboot.dubbo.version>1.0.0</springboot.dubbo.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>${springboot.dubbo.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${springboot.version}</version> </dependency> </dependencies> </dependencyManagement> </project>
api包pom:
<?xml version="1.0" encoding="UTF-8"?> <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>org.xxpay</groupId> <artifactId>xxpay4dubbo-api</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>xxpay4dubbo-api</name> <description>xxpay4dubbo-api</description> <parent> <groupId>org.xxpay</groupId> <artifactId>xxpay4dubbo</artifactId> <version>1.0.0</version> </parent> <properties> <commons.beanutils.version>1.7.0</commons.beanutils.version> </properties> <dependencies> <dependency> <groupId>org.xxpay</groupId> <artifactId>xxpay-common</artifactId> <version>1.0.0</version> </dependency> </dependencies> </project>
service包pom:
<?xml version="1.0" encoding="UTF-8"?> <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>org.xxpay</groupId> <artifactId>xxpay4dubbo-service</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>xxpay4dubbo-service</name> <description>xxpay4dubbo-service</description> <parent> <groupId>org.xxpay</groupId> <artifactId>xxpay4dubbo</artifactId> <version>1.0.0</version> </parent> <dependencies> <dependency> <groupId>org.xxpay</groupId> <artifactId>xxpay4dubbo-api</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.xxpay</groupId> <artifactId>xxpay-dal</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-activemq</artifactId> </dependency> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-pool</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--wx_pay--> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-pay</artifactId> <version>2.8.0</version> </dependency> <!--ali_pay--> <dependency> <groupId>com.alipay</groupId> <artifactId>sdk</artifactId> <version>1.5</version> <scope>system</scope> <systemPath>${basedir}/src/main/webapp/WEB-INF/lib/alipay-sdk-java20170818173712.jar</systemPath> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/webapp/WEB-INF/lib/</directory> <targetPath>BOOT-INF/lib/</targetPath> <includes> <include>**/*.jar</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <targetPath>BOOT-INF/classes/</targetPath> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${springboot.version}</version> </plugin> </plugins> </build> </project>
web包pom:
<?xml version="1.0" encoding="UTF-8"?> <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>org.xxpay</groupId> <artifactId>xxpay4dubbo-web</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>xxpay4dubbo-web</name> <description>xxpay4dubbo-web</description> <parent> <groupId>org.xxpay</groupId> <artifactId>xxpay4dubbo</artifactId> <version>1.0.0</version> </parent> <dependencies> <dependency> <groupId>org.xxpay</groupId> <artifactId>xxpay4dubbo-api</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.xxpay</groupId> <artifactId>xxpay-dal</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${springboot.version}</version> </plugin> </plugins> </build> </project>
其实在这里踩了一些坑,因为原框架作者的包结构跟现在的有所不同,导致我改结构的时候报了一些错,印象最深的就是,明明有包,但是找不到。原因有2:一可能是最外层的父pom没有声明子模块;二是子pom文件没有声明父级Pom(父Pom文件添加的依赖为公共依赖,父pom引入后,子pom不需要再次引入。
多模块项目有篇文章讲的可以:https://blog.csdn.net/jiangkai528/article/details/24798943)
接下来看一下我们要实现的接口的接口文档:
我们可以来分析下接口的请求数据,最外层是data和sign,那我们首先考虑应该是个Map<String,xx>去装,其中data里面,biz_content每个接口的数据格式不一样,也应该用一个Map<String,xx>去装数据,根据各个接口的不同,看定义Map<String,List>还是Map<String,String>,那我们确定了应该装数据的结构就是:
Map<String, Map<String, Map<String,xx>>>,我们考虑中间一层Map用对象代替,最里层Map声明为对象属性,那么我们看一下其中一个接口的业务参数
Pojo类应该是这样:
package com.yz.modular.system.model; import lombok.Getter; import lombok.Setter; import java.io.Serializable; import java.util.List; import java.util.Map; @Getter @Setter public class RequestTest1 implements Serializable { private String mchNo; private String outTrantNo; private String bizType; private String signType; private String timeStamp; private Map<String,List> bizContent; }
考虑到data中除开bizContent,其他都是公共的,可以提取出来作为接口基类,那么我们要定义装此接口数据的pojo类就成了
package com.yz.modular.system.model; import lombok.Getter; import lombok.Setter; import java.io.Serializable; import java.util.List; import java.util.Map; @Getter @Setter public class RequestTest1 extends RequestBaseInfo implements Serializable { private Map<String,List> bizContent; }
package com.yz.modular.system.model; import com.baomidou.mybatisplus.activerecord.Model; import lombok.Getter; import lombok.Setter; import java.io.Serializable; /** * <p> * 商户账户信息表 * </p> * * @author fjj123 * @since 2018-06-13 */ @Getter @Setter public class RequestBaseInfo extends Model<RequestBaseInfo> implements Serializable { private static final long serialVersionUID = 1L; private String mchNo; private String outTrantNo; private String bizType; private String signType; private String timeStamp; @Override protected Serializable pkVal() { return this.mchNo; } }
接下来就是调用接口:
package com.yz.system; import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONUtil; import com.yz.GunsApplication; import com.yz.core.util.DateUtil; import com.yz.modular.system.model.Accnt; import com.yz.modular.system.model.RequestTest1; import com.yz.modular.system.service.IHisAccntMchService; import com.yz.modular.system.service.IMchAccntService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.bind.annotation.ResponseBody; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = GunsApplication.class,webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @EnableAutoConfiguration public class ExceptionTest { @Autowired private IMchAccntService mch; @Autowired private IHisAccntMchService iHisAccntMchService; @Before public void before() throws Exception{ } @After public void after() throws Exception { } @ResponseBody @Test public void getAjaxJson(){ //调用spost方法时传入的外网接口地址 String url = "http://localhost:3020/api/pay/query_accnt.htm"; //调用spost方法时传入的map数据 //map放data,sign; data为对象(转json字符串)--- map.put("data",data),map.put("sign",sign) //data放mchNo,BizType....bizContent;bizContent为Map<String,List>---- data.setBizContent(bizContentmap),data.setMchNo(mchNo)... //bizeContent放split_accnt_detail; split_accnt_detail为list----- bizContentmap.put("split_accnt_detail",list) list.add(entity) //倒着比较好理解, 对象用list装,list用map装,map用对象装,对象再用map装 Map<String, Object> dataMap = new HashMap<>(); //具体接口定义的具体pojo RequestTest1 request001 = new RequestTest1(); //具体接口所需业务参数map Map<String,List> bizContentmap = new HashMap<>(); //具体接口所需业务参数主题 List<Accnt> accntList = new ArrayList<>(); Accnt accnt = null; for(int i =0;i<10;i++){ accnt = new Accnt(); accnt.setAmount(""); accnt.setDispatchEvent(""); accnt.setDispatchType(""); accnt.setMchAccntNo(""); accnt.setOrderNo(""); accntList.add(accnt); } bizContentmap.put("split_accnt_detail",accntList); request001.setBizContent(bizContentmap); request001.setMchNo(""); request001.setBizType(""); request001.setOutTrantNo(""); request001.setSignType(""); request001.setTimeStamp(DateUtil.getAllTime()); String data = JSONUtil.toJsonStr(request001); String token = "12e243a21f3y2w1h3s132"; String sign = SecureUtil.md5(data+"&"+request001.getTimeStamp()+token); dataMap.put("data",data); dataMap.put("sign",sign); String str = HttpUtil.post(url,dataMap); System.out.println(str); } }
模拟http请求的接口其实有很多工具类,可以网上找一找,然后自己写一下,这里用的是hutool工具包http://hutool.mydoc.io/?t=255570;调用方就完成了!