背景

目前各系统之间的数据交互越来越频繁,频繁的给项目增加接口不仅增加整个系统的负担,还给开发人员麻烦,开发效率低,日常维护起来更是嫌弃;最近几年Spring微服务非常火,基于Spring Boot的Spring Cloud已经成为一站式微服务框架;准备入手Spring Cloud;首先从Spring Boot下手,使用Spring Boot写了个通用型的第三方接口功能,目前主要用于查询数据抛给调用者;其实也比较简单,主要就是实现业务逻辑,对于访问数据层是直接使用以前项目访问的方式,打成jar包,直接依赖使用等等;然后就是定义一下接口的规范,过滤掉一部分URL,输入的URI必须包含指定访问哪个数据库,条件可选;输出必须让调用者知道调用接口后的结果,尽可能简单明了;至于调用者需要哪些数据则需要双方协调沟通,配置好sql语句;尽可能实现调用者的需求。

具体实现

一、前提条件
1.安装JDK8或以上(springBoot 2.X版本)
2.开发工具(Eclipse或IDEA等,本次使用的Eclipse)
3.Spring开发套件工具(springsource-tool-suite)
4.apache-maven

二、开发准备
1.eclipse中安装Spring开发套件工具(下载时注意查看eclipse版本对应的springSource-tool-suite版本)
使用SpringSource-tool-suite插件是为开发Spring应用程序而定制的,它提供一个随时可用的环境来实现调试、运行和部署Spring应用程式,插件(sts3版本)集成了Pivatal tc Server(企业级的轻量java应用服务器,拓展了Apache Tomcat;可以说是企业版本的Apache Tomcat)、Pivotal Cloud Foundry(PCF是一个统一的多云平台,可以运行你的企业应用程序)、Git(分布式版本控制系统)、Maven(项目管理工具)、AspectJ(面向切面的框架AOP,拓展了java语言)等等。

1.1离线安装springSource-tool-suite

(1)下载(地址:https://spring.io/tools3/sts/all)

spring boot调用adb指令 springboot调用api接口_java


(2)打开Eclipse–>help–>install New Software…

spring boot调用adb指令 springboot调用api接口_spring boot调用adb指令_02


(3)直接默认下一步Next,等待安装完成即可;安装完成之后就可以建Spring项目了。直接输入相关名称,然后默认下一步Next即可完成。

spring boot调用adb指令 springboot调用api接口_maven_03


三、开发过程(1)Spring Boot项目结构

主要用到几个目录和文件:

1)src/main/java目录:建java项目文件等等;其中包含主程序入口xxxxApplication.java文件,通过直接运行该类来启动Spring Boot应用

2)src/main/resources:配置目录,该目录用来存放应用的一些配置信息,比如应用名、服务端口、数据库配置等等,也可以存放一些静态资源,如一些图片、CSS文件、template模板文件等等;

3)src/test/java:单元测试目录,生成的xxxxApplicationTests通过JUnit4实现,可以直接运行Spring Boot进行测试。

4)application.properties:用于存放程序的各种依赖模块的配置信息,比如服务端口,数据库连接配置等等;目前

设置了第三使用方接口服务端口server.port=10101。

5)pom.xml:maven项目文件,主要用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的URL、项目的依赖关系。

spring boot调用adb指令 springboot调用api接口_java_04


(2)pom.xml文件基本解析

<?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/maven-v4_0_0.xsd">
    <!--
    	POM的版本
    -->
    <modelVersion>4.0.0</modelVersion>
    <!-- 
        含义:组织标识,定义了项目属于哪个组
        用途:此名称则是本地仓库中的路径
        命名规范:项目名称,模块,子模块
    -->
    <groupId>com.demo</groupId>
    <!-- 
        含义:项目名称也可以说你所模块名称,定义当面Maven项目在组中唯一的ID
        用途:例如:filter,在M2_REPO目录下,将是:com/demo/filter对应下的目录
        命名规范:唯一就好
    -->
    <artifactId>filter</artifactId>
    <!-- 
        含义:项目当前的版本号
        用途:例如:0.0.1-SNAPSHOT,在M2_REPO目录下,将是:com/demo/filter/0.0.1-SNAPSHOT目录
    -->
    <version>0.0.1-SNAPSHOT</version>
    <!-- 打包的格式,可以为:pom , jar , maven-plugin , ejb , war , ear , rar , par -->
    <packaging>war</packaging>
    <!-- 元素声明了一个对用户更为友好的项目名称 -->
    <name>Spring-Boot-Demo</name>
    <!-- 依赖继承的父类的jars -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.3.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<!--
	相关属性配置,如改变版本号、统一编码方式等等  
	-->
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<springfox.version>2.2.2</springfox.version>
		<maven.compiler.source>1.8</maven.compiler.source>
    	<maven.compiler.target>1.8</maven.compiler.target>
    	<skipTests>true</skipTests>
	</properties>
	<!-- 
	依赖的额外jar包 ,根据自己实际需要去依赖,如果maven的中央库有就直接去取;
	本地仓库需要自己指定或直接导到项目目录,依赖指定位置即可,groupId、artifacId和version名字随便取
	-->
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
		    <groupId>org.apache.commons</groupId>
		    <artifactId>commons-text</artifactId>
		    <version>1.6</version>
		</dependency>
		<dependency>
		    <groupId>io.springfox</groupId>
		    <artifactId>springfox-swagger2</artifactId>
		    <version>${springfox.version}</version>
		 </dependency>
		 <dependency>
		    <groupId>io.springfox</groupId>
		    <artifactId>springfox-swagger-ui</artifactId>
		    <version>${springfox.version}</version>
		 </dependency>    
	    <dependency>
		   <groupId>org.springframework.boot</groupId>
		   <artifactId>spring-boot-starter-tomcat</artifactId>
		   <scope>provided</scope>
		</dependency>
	</dependencies>
	<!-- 使用spring boot Maven插件将依赖的jar包生成可执行jar包 -->	
	<build>
	     <plugins>
            <plugin>
                 <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                       <mainclass>com.myselft.ThirdPartyInterfaceApplication</mainclass>
                    </configuration>
                </plugin>
      		 <plugin>
                 <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                       <includeSystemScope>true</includeSystemScope>
                    </configuration>
                </plugin>
        </plugins>
	</build>
</project>

(3)程序设计

1)基本设计流程

如下:

spring boot调用adb指令 springboot调用api接口_java_05

2)程序设计

One: 最主要的Application.java文件;

/*
1.导入java基本依赖包
2.导入spring boot基本依赖包
3.导入自己的需求包;如操作IO流的工具包,自定义的过滤器、还有一些基本封装工具包
*/
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import com.myself.filter.ThirdPartyCommonFilter;
import com.myself.util.IOUtil;
/*
使用的注解:
1.@EnableSwagger2: 启动Swagger;使用Swagger生成API,可以得到交互式文档,自动生成代码的SDK以及API的发现特性等等;
					其实Swagger就是一个简单、功能强大的API表达工具;在springboot中的主要功能:
					方便进行测试后台的restful形式的接口,实现动态的更新,当我们在后台的接口修改了以后。swagger
					可以实现自动的更新,而不需要单独使用一些工具(如postman)来测试后台修改的接口。目前没有使用到,
					先启动再说;依赖的jar包在
					pom.xml文件引入:
							<dependency>
							    <groupId>io.springfox</groupId>
							    <artifactId>springfox-swagger2</artifactId>
							    <version>2.2.2</version>
							 </dependency>
							 <dependency>
							    <groupId>io.springfox</groupId>
							    <artifactId>springfox-swagger-ui</artifactId>
							    <version>2.2.2</version>
							 </dependency>

2.@Bean:注解会将方法中的返回对象在SpringBoot启动的时候放入IOC容器中,加载时自动实现实例化
*/
@EnableSwagger2
public class ThirdPartyInterfaceApplication extends SpringBootServletInitializer {
	//注册Filter
	@Bean
	public FilterRegistrationBean<Filter> filterRegistrationBean(){
	/*
	1.创建并注册filter;
	ThirdPartyCommonFilter类为自定义的过滤器
	*/
		FilterRegistrationBean<Filter> regFilter=new FilterRegistrationBean<>();
		regFilter.setFilter(new ThirdPartyCommonFilter());
		List<String> urlHeader=new ArrayList<String>();
		//读取配置文件设置的需要过滤的url参数;自己封装的io工具类;方法可以自行
		String url=IOUtil.getPropertyByName("com.myself.url.header", "ConfigFile/myself.properties").trim();
		urlHeader.add(url);
		/*
		2.设置filter的相关属性
		*/
		regFilter.setUrlPatterns(urlHeader);//url过滤
		regFilter.setName("ThirdPartyCommon");//过滤器名称
		regFilter.setOrder(1);//过滤优先顺序
		regFilter.setEnabled(true);//设置过滤器是否有效
		return regFilter;//返回直接加载到IOC容器
		
	}
	public static void main(String[] args) {
		//主程序入口,加载启动xxxxApplication类文件
		SpringApplication.run(ThirdPartyInterfaceApplication.class, args);
	}

	/*
	override重写 configure方法;可以修改启动类
	*/
	@Override	
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
		return builder.sources(ThirdPartyInterfaceApplication.class);
		
	}
}

Two: 过滤器Filter文件

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.myself.thirdpartyinterface.controller.ThirdPartyCommonController;

/*
创建自己的过滤器并实现Filter接口,以及重写Filter接口的方法,init()、doFilter()、destroy()
*/
public class ThirdPartyCommonFilter implements Filter {

	//Filter过滤器初始化
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}
	//过滤器所需要做的事情;即从接收到请求request之后所做的一系列动作,最后response响应返回
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// TODO Auto-generated method stub
		//1.满足条件之后就会去该控制器执行自己设计的业务逻辑
		ThirdPartyCommonController commonController=new ThirdPartyCommonController();
		//2.设置request和response
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		//3.设置访问权限属性,设置无限制		
		resp.setHeader("Access-Control-Allow-Origin", "*");
		resp.setHeader("Access-Control-Allow-Methods", "*");
		resp.setHeader("Access-Control-Allow-Headers", "*");
		//4.请求方法为OPTIONS时不做任何处理
		if(req.getMethod().equals("OPTIONS")) {
			resp.setStatus(HttpServletResponse.SC_OK);
			return;
		}
		//5.设置响应的编码方式和响应返回的数据格式为json格式
		resp.setCharacterEncoding(request.getCharacterEncoding());
		resp.setContentType("application/json");		
		//6.开始过滤部分接收到的url,符合要求就继续往下执行业务;并返回结果
		if(!req.getParameterMap().containsKey("TokenId")) {
			//7.请求参数没有包含TokenId
			resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);//400
			resp.getWriter().write("The Request param: TokenId can not null!");
		}else {
			resp.setStatus(HttpServletResponse.SC_OK);//200
			//8.进入controller执行业务,并将返回结果响应给调用者
			resp.getWriter().write(commonController.dealRequest(req));
		}

	}
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}

Three: controller业务逻辑控制层

import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.myselft.action.Constants;
import com.myself.thirdpartyinterface.service.ThirdPartyCommonService;
import com.myself.util.IOUtil;
import net.sf.json.JSONObject;

public class ThirdPartyCommonController {

	private static Logger log=LoggerFactory.getLogger(ThirdPartyCommonController.class);
	private ThirdPartyCommonService commonService=new ThirdPartyCommonService(log);	
	/*
	 * 处理request请求
	 * @param HttpServletRequest
	 * @return String
	 * */
	public String dealRequest(HttpServletRequest request)  {
		JSONObject jsonObj_res=new JSONObject();//返回响应的结果信息
		jsonObj_res.put("Result", "Fail");
		jsonObj_res.put("Message", "response fail");
		String url_match=IOUtil.getPropertyByName("com.myself.url.header", "ConfigFile/myself.properties").trim();
		/*
		 * 1.获取请求url的信息,包括:url、api_path_name、参数key-value值
		 * 
		 * */
		String url=request.getRequestURI();	//获取url
		String api_path_name=url.substring(url_match.length()-2);//获取api_path_name
		JSONObject jsonObj=new JSONObject();//用来保存请求传过来的所有参数
		Map<String, String[]> maps=request.getParameterMap();//获取参数的key-value值
		for(String key:maps.keySet()) {//遍历请求的参数值
			String value=maps.get(key)[0].toString();
			if(!value.equals("")) {
				jsonObj.put(key.toUpperCase(), value);
			}
		}
		/*
		 * 2.根据api_path_name获取需要查询的信息
		 * 包括:
		 * 1).所做的动作action,如query,add,update,delete
		 * 2).api_path_name,获取执行的环境schema和执行的sql
		 * 3).将sql的参数使用请求保存的jsonObj来代替
		 * */
		String selectInfo=commonService.getInfoToUri(api_path_name);
		if(selectInfo.startsWith("Exception")) {//异常
			jsonObj_res.put("Result", "Exception");
			jsonObj_res.put("Message", selectInfo.substring(10));
		}else if(selectInfo.equals("[]")){
			jsonObj_res.put("Message", "URL address Error,please Checked");
		}else{
			/*
			 * 3.根据jsonObj参数匹配并替换掉selectInfo的sql参数,并执行sql,返回json格式参数
			 * */
			String query_res=commonService.selectSQLjsonArr(jsonObj, selectInfo);
			if(query_res.startsWith("Exception")) {
				jsonObj_res.put("Result", "Exception");
				jsonObj_res.put("Message", query_res.substring(10));
			}else if(query_res.equals("Null")) {
				jsonObj_res.put("Message", "execute select sql not successed");
			}else {
				jsonObj_res.put("Result", "OK");
				jsonObj_res.put("Message", query_res);
			}
			
		}
		return jsonObj_res.toString();
	}
}

Four: service层,主要与数据库交道;目前此使用的是oracle数据库;真正抛送给用户数据的执行sql保存在数据表里面,需要自行配置

//导入操作一些自己操作数据库的基本包
import java.sql.SQLException;
import org.slf4j.Logger;
import com.myself.function.dao.BaseDao;
import com.myself.function.service.BaseServices;
import com.myself.util.JsonUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class ThirdPartyCommonService extends BaseServices<BaseDao>{
	public ThirdPartyCommonService(Logger log) {
		super(log);
		// TODO Auto-generated constructor stub
	}

	/*
	 * 1.根据uri获取所有配置的相关信息
	 * @param String api_path_name
	 * @return String
	 * */	
		public String getInfoToUri(String api_path_name) {
			String query_sql="自己需要配置的额sql语句,用来查询相关信息;比如根据api_path_name来获取需要执行的sql语句";				
			try {
			/*
			1.1自己的工具包,将查询出来的结果集转化成jsonArray格式
				参数(sql语句,schema名称,条件参数)
			*/
				return JsonUtil.setToJsonArr(super.getResultSet(query_sql, "schema", new Object[]{api_path_name}));
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return "Exception: "+e.getMessage();
			}	
		}
		
		/*
		 * 2.根据jsonObj参数匹配并替换掉selectInfo的sql参数,并执行sql,返回json格式参数
		 * @param JSONObject
		 * @param Sting 
		 * @return String 
		 * */
		public String  selectSQLjsonArr(JSONObject jsonObj,String selectInfo ) {
			String jsonArr_str="Null";
			JSONArray jsonArr=JSONArray.fromObject(selectInfo);
			ThirdPartyCommonService service=new ThirdPartyCommonService(log);
			if(jsonArr.size()>0) {
				for(int i=0;i<jsonArr.size();i++) {
					try {
					System.out.println(jsonArr.size());
					JSONObject jsonObj_param=jsonArr.getJSONObject(i);
					String schema=service.getSchemaToFactory(jsonObj.getString("TokenId"));
					String query_sql=jsonObj_param.getString("SQL");
					for(Object key:jsonObj.keySet()) {
						query_sql=query_sql.replaceAll("@"+key.toString().toUpperCase()+"@", jsonObj.get(key).toString());
					}			
					jsonArr_str=JsonUtil.setToJsonArr(super.getResultSet(query_sql, schema, new Object[] {}));
					} catch (SQLException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
						System.out.println(e.getMessage());
						jsonArr_str="Exception:"+e.getMessage();
						
					}				
				}
			}			
			return jsonArr_str;

		}
		/*
		 * 3.根据TokenId获取对应的数据库schema名称
		 * @param String
		 * @return String
		 * */
		public String getSchemaToFactory(String factory) throws SQLException {
			String query_sql=
					"根据TokenId来筛选获取对应去哪个数据库环境抓数据";
			String schema_qry=(String) super.getResultColumn("schema", query_sql, new Object[] {TokenId});
			return schema_qry;
			
		}
}

四、运行程序以及服务器简单jar部署

1)涉及到Maven相关配置的,如pom.xml文件,运行之前先Update Project…

spring boot调用adb指令 springboot调用api接口_spring boot调用adb指令_06


2)然后直接RunAs–>Spring Boot App

spring boot调用adb指令 springboot调用api接口_spring_07

3)生成jar包(war也是可以的;目前程式是前后端分离,所以jar包部署比较方便)

(1)RunAs–>Maven clean;清除之前生成的jar等相关文件。

(2)RunAs–>Maven install;生成可执行的jar包;

(3)之后会在项目下的target文件夹生成两个东西:xxx.jar和xxx.jar.original

PS:打包生成jar时Maven install会经常出现一个报错:

No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

spring boot调用adb指令 springboot调用api接口_spring_08


解决办法:

点击项目右键,选中Build Path–>Configure Build Path;

将JRE运行环境改为JDK即可。

spring boot调用adb指令 springboot调用api接口_spring boot_09


4)将生成的在target的两个文件上传到服务器(目前使用的是linux服务器,需要有jdk8以上的运行环境);

然后指定目录;直接后台一直运行: java -jar xxxx.jar & ;即可启动成功:

spring boot调用adb指令 springboot调用api接口_spring boot_10

spring boot调用adb指令 springboot调用api接口_spring boot_11

总结

此处省略三千行…;放手去盘spring boot吧