首页 > 代码库 > 使用Spring自定义注解生产Http接口描述信息

使用Spring自定义注解生产Http接口描述信息

最近在做一个手机后台项目,使用的是SpringMVC,开发的接口是HTTP接口。在接口写完后需要在网页中吧接口的名称测试地址等信息添加到网页中,感觉这样很麻烦还容易漏。于是就写了一个自定义注解通过注解的方式将接口的描述信息加入到接口中,通过注解描述接口信息并且生产接口测试地址


先看使用方法及最终效果

	@ResponseBody
	@RequestMapping("/getBusWaiting")
	@AppInterface(value=http://www.mamicode.com/"获取候车信息",group="test",order=1,params={>
生成的效果

技术分享

下面是具体实现

接口描述类

/**  
 * <p>创建人:王成委  </p>
 * <p>创建时间:2014年12月8日 下午5:28:11  </p>
 * <p>类描述: 标记手机App接口,接口描述信息,用于生成接口信息及测试路径 </p>
 * <p>版权说明: © 2014 Tiamaes </p>
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AppInterface {

	/**
	 * <p>方法描述:接口名称</p>
	 * @return String
	 */
	String value();
	
	/**
	 * <p>方法描述:分组</p>
	 * @return String
	 */
	String group() default "";
	
	/**
	 * <p>方法描述:排序</p>
	 * @return int
	 */
	int order () default 0;
	
	/**
	 * <p>方法描述:参数列表</p>
	 * @return InterfaceParam[]
	 */
	InterfaceParam[] params() default {};
}
接口参数类
/**  
 * <p>创建人:王成委  </p>
 * <p>创建时间:2014年12月8日 下午5:29:34  </p>
 * <p>类描述: 手机App接口参数说明 </p>
 * <p>版权说明: © 2014 Tiamaes </p>
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InterfaceParam {
	
	/**
	 * <p>方法描述:参数名称</p>
	 * @return String
	 */
	String name();
	
	/**
	 * <p>方法描述:接口说明</p>
	 * @return String
	 */
	String desc();
	
	/**
	 * <p>方法描述:测试参数值</p>
	 * @return String
	 */
	String testValue() default "";
}
testValue支持自定义变量,在主类中有具体实现

package com.tiamaes.gjds.app.aop;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.tiamaes.gjds.app.annotation.AppInterface;
import com.tiamaes.gjds.app.annotation.InterfaceParam;
import com.tiamaes.gjds.app.base.RequestMethodMapping;
import com.tiamaes.gjds.app.base.RequestMethodParameter;
import com.tiamaes.gjds.app.base.Variable;
import com.tiamaes.gjds.util.SetUtils;

/**  
 * <p>类描述: 生成接口描述信息并放入Application中 </p>
 * <p>创建人:王成委  </p>
 * <p>创建时间:2015年1月19日 下午4:42:24  </p>
 * <p>版权说明: © 2015 Tiamaes </p>
 * @see com.tiamaes.gjds.app.annotation.AppInterface
 */

public class InterfaceAnnotationConfigProcesser implements ApplicationContextAware,InitializingBean{

	private Log logger = LogFactory.getLog(getClass());
	
	private Map<String,List<RequestMethodMapping>> mappers = 
			new HashMap<String,List<RequestMethodMapping>>();
	
	private WebApplicationContext applicationContext;
	
	/**
	 * <p>方法描述:加载带有{@link com.tiamaes.gjds.app.annotation.AppInterface}注解的接口</p>
	 * <p>首先需要获取所有接口,然后过滤方法中带有@AppInterface</p>
	 * <p>创建人: 王成委  </p>
	 * <p>创建时间: 2015年1月10日 上午10:50:06 </p>
	 */
	public void loadHandlerMapping(){
		this.logger.info("初始化配置");
		Map<String, HandlerMapping> handlers = BeanFactoryUtils.beansOfTypeIncludingAncestors(
				applicationContext, HandlerMapping.class, true, false);
		
		for(Entry<String, HandlerMapping> entry : handlers.entrySet()){
			HandlerMapping mapping = entry.getValue();
			if(mapping instanceof RequestMappingHandlerMapping){
				RequestMappingHandlerMapping requestHandler = (RequestMappingHandlerMapping)mapping;
				Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestHandler.getHandlerMethods();
				for(Entry<RequestMappingInfo, HandlerMethod> handlerMethod : handlerMethods.entrySet()){
					AppInterface annotation = handlerMethod.getValue().getMethodAnnotation(AppInterface.class);
					if(annotation== null)continue;
					PatternsRequestCondition patternsCondition = handlerMethod.getKey().getPatternsCondition();
					String requestUrl = SetUtils.first(patternsCondition.getPatterns());
					this.register(requestUrl, annotation,handlerMethod.getValue().getBeanType());
				}
			}
		}
	}
	
	/**
	 * <p>方法描述:注册方法</p>
	 * <p>创建人: 王成委  </p>
	 * <p>创建时间: 2015年1月10日 上午10:50:06 </p>
	 * @param requestUrl
	 * @param annotation
	 * @param beanType 
	 */
	private void register(String requestUrl, AppInterface annotation,
			Class<?> beanType) {
		String group = annotation.group();
		List<RequestMethodMapping> groupMappers = this.mappers.get(group);
		if(groupMappers == null)groupMappers = new ArrayList<RequestMethodMapping>();
		RequestMethodMapping mapper = new RequestMethodMapping();
		mapper.setGroup(group);
		mapper.setController(beanType.getName());
		mapper.setOrder(annotation.order());
		mapper.setName(annotation.value());
		mapper.setUrl(requestUrl);
		mapper.setParams(this.toParameters(annotation.params()));
		groupMappers.add(mapper);
		this.mappers.put(group, groupMappers);
	}
	
	/**
	 * <p>方法描述:读取参数</p>
	 * <p>创建人: 王成委  </p>
	 * <p>创建时间: 2015年1月10日 上午10:50:06 </p>
	 * @param params
	 * @return
	 */
	private List<RequestMethodParameter> toParameters(InterfaceParam[] params){
		List<RequestMethodParameter> parameters = new ArrayList<RequestMethodParameter>();
		
		for(InterfaceParam param : params){
			RequestMethodParameter bean = new RequestMethodParameter();
			bean.setName(param.name());
			bean.setDesc(param.desc());
			if(StringUtils.startsWithIgnoreCase(param.testValue(), "#")){
				String var = param.testValue();
				String value = http://www.mamicode.com/getByVariable(var.substring(var.indexOf("#")+1));>利用C标签生产接口描述信息

<div class="api-layout">
	<table class="api-table">
		<tr class="api-table-header">
       		<td width="300px;">接口地址</td>
       		<td width="200px;">接口名称</td>
       		<td>参数说明</td>
       	</tr>
		<c:forEach items="${api}" var="map">
        	<tr>
        		<td colspan="3" class="api-group">
					<c:out value=http://www.mamicode.com/"${map.key}" />>






使用Spring自定义注解生产Http接口描述信息