最近在实现一个纯接口系统的需求,因为是支付类接口,所以考虑搭一套分布式的框架,跟后台系统隔离开来。

其实以前一直有疑问,接口是怎么调用与传输接收数据的呢?首先我们要了解:客户端与服务器常用数据交换格式xml、json、html;传输一般用http协议或者RPC协议

首先说xml

记得以前调过webService接口,就找了网上的例子当时好像是用的cxf框架,然后用xml配置暴露的接口,接口提供方可以用已实现序列化接口的对象来接收,当然,一般接口的数据结构没有那么简单,那我们也可以相对应的在我们要接收数据的对象里 加List或者对象属性来实现。cxf框架会自动把xml数据转化为我们所需的对象,底层传输的实际上是通过http协议传输xml数据(可以写一个拦截器获取发送的xml文件)。

然后是json

xml传输数据的话一般是webSerivce,偏银行多一些;而Json则偏互联网多一些。暴露接口的话,我们可以写一个controller,用@RequestMapping("xxxx")来指定接口的调用地址;底层传输的都是json字符串,我们可以用String来接收,也可以用对象来接收(实现序列化接口),一般用的框架有阿里的fastjson跟springMvc自带的jackson

了解了如何调用和传输数据后,我们直接开始

首先附上一张框架的结构图(框架为开源框架,fork下来自己做了点调整,地址:https://gitee.com/jmdhappy/xxpay-master.git)

java 向外暴露的接口怎么写 springboot对外暴露接口_http

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不需要再次引入。)

接下来看一下我们要实现的接口的接口文档:

java 向外暴露的接口怎么写 springboot对外暴露接口_Dubbo_02

java 向外暴露的接口怎么写 springboot对外暴露接口_http_03

我们可以来分析下接口的请求数据,最外层是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声明为对象属性,那么我们看一下其中一个接口的业务参数

java 向外暴露的接口怎么写 springboot对外暴露接口_json_04

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;调用方就完成了!