API需要同时维护多个版本。如何优雅的设计?

在项目中经常遇到,相同的数据,对不同的客户以及不同的终端,需要输出不同的数据。

更有特殊的情况,需要对一个数据,在不同的终端表示形式不一样。综合多种考虑,需要一种支持扩展,并且灵活的的接口, 开发效率还需高效。

在网上找了一圈没有发现,决定自己实现一个,决定使用模板,在freeMark和Velocity之间择了Velocity 。

  1. 性能
  2. 够用

原理,

利用Velocity的功能,生成各种复杂的数据,再向通过接口统一输出

直接上代码截图

接口模板

package com.echo.api.velocity.inter;

import org.apache.velocity.VelocityContext;

/**
 * 适配器接口. <br>
 * 类详细说明.
 * <p>
 * Copyright: Copyright (c) 2015年9月9日 下午4:02:23
 * <p>
 * <p>
 * 
 * @version 1.0.0
 */
public interface IDataAdapter {

	String TYPE_JSON = "json";

	String TYPE_XML = "xml";

	/**
	 * @param type
	 *            报文类型,json,xml
	 * @param version
	 *            版本,1.0.0
	 * @param key
	 *            标示key可以是任意指定
	 * @param template
	 *            报文模板名称
	 * @return
	 */
	public String getResult(String type, String version, String key, String template, VelocityContext context);
}
package com.echo.api.velocity.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.StringWriter;
import java.util.Properties;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;

import com.echo.api.velocity.inter.IDataAdapter;

/**
 * 常见的数据
 * <p>
 * Copyright: Copyright (c) 2015年9月9日 下午4:13:42
 * <p>
 * 
 * @version 1.0.0
 */
public class GeneralDataAdapter implements IDataAdapter {

	/**
	 * 模板基础路径
	 */
	private String baseTemplatePath;

	private VelocityEngine velocityEngine;

	private String encoding = "utf-8";

	public GeneralDataAdapter() throws Exception {
		init();
	}

	private void init() throws Exception {
		try {

			Properties properties = new Properties();
			// 设置velocityp 配置
			properties.load(new FileInputStream(new File("./config/velocity.properties")));
			Velocity.init(properties);
			velocityEngine = new VelocityEngine();
		}
		catch (Exception ex) {
			throw ex;
		}
	}

	public String getResult(String type, String version, String key, String template, VelocityContext context) {
		// 添加通用的处理函数
		context.put("DateFormatUtils", DateFormatUtils.class);
		// 返回报文
		StringWriter sw = new StringWriter();
		String path = baseTemplatePath + "/" + type + "/" + version + "/" + key + "/" + template;
		velocityEngine.mergeTemplate(path, encoding, context, sw);
		return sw.toString();
	}

	public String getBaseTemplatePath() {
		return baseTemplatePath;
	}

	public void setBaseTemplatePath(String baseTemplatePath) {
		this.baseTemplatePath = baseTemplatePath;
	}

	public String getEncoding() {
		return encoding;
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	public GeneralDataAdapter(String baseTemplatePath, String encoding) throws Exception {
		super();
		this.baseTemplatePath = baseTemplatePath;
		this.encoding = encoding;
		init();
	}

	public GeneralDataAdapter(String baseTemplatePath, VelocityEngine velocityEngine, String encoding) throws Exception {
		super();
		this.baseTemplatePath = baseTemplatePath;
		this.velocityEngine = velocityEngine;
		this.encoding = encoding;
		init();
	}

}
package com.echo.api;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.velocity.VelocityContext;

import com.echo.api.velocity.impl.GeneralDataAdapter;
import com.echo.api.velocity.inter.IDataAdapter;

/**
 * 使用velocity设计复杂多变的报文接口,在bean相同情况下实现不同的输出
 * <p>
 * Copyright: Copyright (c) 2015年9月9日 下午3:27:47
 * <p>
 * Company: 北京宽连十方数字技术有限公司
 * <p>
 * 
 * @author [email protected]
 * @version 1.0.0
 */
public class TestAipVersion {

	/**
	 * main函数.
	 * 
	 * @param args
	 *            启动参数
	 * @throws Exception
	 *             Exception
	 */
	public static void main(String... args) throws Exception {

		VelocityContext context = new VelocityContext();
		// 同一数据源,输出不同报文以及不同的格式
		List<User> users = new ArrayList<User>();
		users.add(new User("张三", 23, "张家庄良民", new Date(), "shaoyishao"));
		// users.add(new User("李四", 25, "李家庄好人", new Date(), "shaoyishao"));
		// users.add(new User("王五", 39, "王庄刁民啊", new Date(), "shaoyishao"));

		context.put("userList", users);
		// json数据
		IDataAdapter generalDataAdapter = new GeneralDataAdapter("./templates", "utf-8");
		// json报文
		long stime = 0;
		stime = System.currentTimeMillis();
		System.out.println(generalDataAdapter.getResult(IDataAdapter.TYPE_JSON, "1.0.0", "android", "userlist.vm", context));
		System.out.println(generalDataAdapter.getResult(IDataAdapter.TYPE_JSON, "1.0.0", "android640", "userlist.vm", context));
		// xml报文
		stime = System.currentTimeMillis();
		System.out.println(generalDataAdapter.getResult(IDataAdapter.TYPE_XML, "1.0.0", "android", "userlist.vm", context));

	}
}

输出json,xml,以及不同屏幕

[{
"count:":  1,
"name":"张三",
"age":23,
"remark":"张家庄良民",
"regTime":"20150909170631",
"btn1":"扫一扫"
}
]
  
[{
"count:":  1,
"name":"张三",
"age":23,
"remark":"张家庄良民",
"regTime":"20150909170631",
"btn1":"扫一扫就知道"
}
]
  
<?xml version="1.0" encoding="utf-8" ?>
<data><users><user>
<count>1</count>
<name>张三</name>
<age>23</age>
<remark>张家庄良民</remark> 
<regTime>2015年09月09日 17:06:31</regTime> 
</user>
</users>
</data>
时间: 2024-10-11 04:49:08

API需要同时维护多个版本。如何优雅的设计?的相关文章

APP API如何维护多个版本的一些想法?

1.第一种形式:api版本号放在url路径中 https://api.example.com/v1/user/ID https://api.example.com/v2/user/ID https://api.example.com/v3/user/ID 2.第二种形式:api版本号放在url参数中 https://api.example.com/user/ID?version=v1&.. https://api.example.com/user/ID?version=v2&.. http

使用系统的某些block api(如UIView的block版本写动画时),是否也考虑循环引用问题?

系统的某些block api中,UIView的block版本写动画时不需要考虑,但也有一些api 需要考虑 以下这些使用方式不会引起循环引用的问题 [UIView animateWithDuration:duration animations:^ { [self.superview layoutIfNeeded]; }]; [[NSOperationQueue mainQueue] addOperationWithBlock:^ { self.someProperty = xyz; }]; [[

API不是从业务抽象出来的(1):设计思维

[back]  微课名称:     API不是从业务抽象出来的(1):设计思维 微课目标: 本微课举例说明这项初学者常常误解的软件编程思维许多人相信API是从业务需求所抽象出来的,真的吗? 本课程就来探讨这个议题.此议题是另一个是频课程(名称:"父类不是抽象出来的!")的姊妹作品. 微课介绍: 其实,API是分解出来的,是将<买主知识>分离开来而得的.本课程详细讲解业务领域知识(Domain Knowledge)与买主知识的切分方法与原则.让您轻易学会App框架的开发,及其

HDFS API详解-很老的版本

因近期要做一个网盘系统,所以搜集下. 关于文件操作类基本上全部是在"org.apache.hadoop.fs"包中,这些API能够支持的操作包含:打开文件,读写文件,删除文件等. Hadoop类库中最终面向用户提供的接口类是FileSystem,该类是个抽象类,只能通过来类的get方法得到具体类.get方法存在几个重载版本,常用的是这个: static FileSystem get(Configuration conf); 该类封装了几乎所有的文件操作,例如mkdir,delete等.

图灵机器人api的使用方法含微信版本和网页版

访问图灵机器人官网http://www.tuling123.com/ 注册一个新的机器人账号 注册成功后转到主页 点击我的机器人>创建机器人>微信机器人 填写基本信息 点击微信介入> 扫描二维码 创建网页版机器人 <html> <head> </head> <body> 问:<input type="text" id="robot" onkeypress="showHint(this.

Hadoop MapReduce编程 API入门系列之网页流量版本1(二十二)

不多说,直接上代码. 对流量原始日志进行流量统计,将不同省份的用户统计结果输出到不同文件. 代码 package zhouls.bigdata.myMapReduce.flowsum; import java.io.DataInput;import java.io.DataOutput;import java.io.IOException; import org.apache.hadoop.io.Writable;import org.apache.hadoop.io.WritableCompa

Hadoop HDFS编程 API入门系列之简单综合版本1(四)

不多说,直接上代码. 代码 package zhouls.bigdata.myWholeHadoop.HDFS.hdfs4; import java.io.IOException; import java.net.URISyntaxException;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.BlockLocation;import org.apache.hadoop.fs.FileStatus

Hadoop MapReduce编程 API入门系列之网页流量版本1(二十一)

不多说,直接上代码. 对流量原始日志进行流量统计,将不同省份的用户统计结果输出到不同文件. 代码 package zhouls.bigdata.myMapReduce.areapartition; import java.io.DataInput;import java.io.DataOutput;import java.io.IOException; import org.apache.hadoop.io.Writable;import org.apache.hadoop.io.Writabl

多语言版本网站建设数据库设计和考虑的因素

由于现在网站上动态应用日益增多,相当多的网站还会使用文件或者数据库来存储应用信息,因此如果文件或者数据库中存储的内容与语言相关时,还需要特别注意.对于存储在数据库中信息,可以采取以下几种方式支持多语言: 1,在数据库级别支持多语言:为每种语言建立独立的数据库,不同语言的用户操作不同的数据库. 2,在表级别支持多语言:为每种语言建立独立的表,不同语言的用户操作不同的表,但是它们在同一个数据库中. 3,在字段级别支持多语言:在同一个表中为每种语言建立独立的字段,不同语言的用户操作不同的字段,它们在同