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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jaune161/article/details/43058295

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


先看使用方法及最终效果

@ResponseBody
	@RequestMapping("/getBusWaiting")
	@AppInterface(value="获取候车信息",group="test",order=1,params={
			@InterfaceParam(name="lineName",desc="线路名称",testValue="B2"),
			@InterfaceParam(name="isUpDown",desc="上下行标识",testValue="1"),
			@InterfaceParam(name="stationNum",desc="站序",testValue="0"),
			@InterfaceParam(name="len",desc="长度",testValue="700")
	})
	public AppResponse getBusWaitingInfo(String lineName,Integer isUpDown,Integer stationNum,Integer len){
		AppResponse result = new AppResponse();
		return result;
	}

生成的效果


下面是具体实现

接口描述类

/**  
 * <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 = getByVariable(var.substring(var.indexOf("#")+1));
				bean.setTestValue(value);
			}else{
				bean.setTestValue(param.testValue());
			}
			parameters.add(bean);
		}
		return parameters;
	}
	
	/**
	 * <p>方法描述:获取变量的值</p>
	 * <p>创建人: 王成委  </p>
	 * <p>创建时间: 2015年1月10日 上午10:50:06 </p>
	 * @param var
	 * @return
	 */
	private String getByVariable(String var){
		Variable variable = Variable.valueOf(var);
		return variable.getValue();
	}

	/**
	 * <p>方法描述:对接口方法根据分组排序</p>
	 * <p>创建人: 王成委  </p>
	 * <p>创建时间: 2015年1月20日 下午16:00:06 </p>
	 */
	private void orderMappers(){
		for(Entry<String,List<RequestMethodMapping>> entry : this.mappers.entrySet() ){
			Collections.sort(entry.getValue(), new Comparator<RequestMethodMapping>() {
						
				@Override
				public int compare(RequestMethodMapping o1, RequestMethodMapping o2) {
					Integer one = o1.getOrder();
					Integer two = o2.getOrder();
					if(one != null && two != null) return one.intValue()-two.intValue();
					return 0;
				}
			});
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = (WebApplicationContext)applicationContext;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.loadHandlerMapping();
		this.orderMappers();
		this.applicationContext.getServletContext().setAttribute("api", this.mappers);
	}
	
	/**
	 * <p>方法描述:刷新接口信息</p>
	 * <p>创建人: 王成委  </p>
	 * <p>创建时间: 2015年1月10日 上午10:50:06 </p>
	 * @throws Exception
	 */
	public void refresh() throws Exception{
		this.mappers = new HashMap<String,List<RequestMethodMapping>>();
		this.afterPropertiesSet();
	}
}
利用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="${map.key}" />
				</td>
			</tr>
			<c:forEach items="${map.value}" var="list">
	            
	            <tr>
	        		<td width="300px;">
	        			<a href="<%=baseUrl%>${list.url}${list.testUrl}" target="_blank">${list.url}</a>
	        		</td>
	        		<td width="200px;">${list.name}</td>
	        		<td>
					<c:forEach items="${list.params}" var="params">
						${params.name}:${params.desc}<br/>
					</c:forEach>
					</td>
	        	</tr>
	        </c:forEach>
		</c:forEach>
	</table>
</div>







转载于:https://my.oschina.net/jaune161/blog/3015855

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值