最近在做一個手機後台項目,使用的是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>
Spring中如何配置Hibernate事務 http://www.linuxidc.com/Linux/2013-12/93681.htm
Struts2整合Spring方法及原理 http://www.linuxidc.com/Linux/2013-12/93692.htm
基於 Spring 設計並實現 RESTful Web Services http://www.linuxidc.com/Linux/2013-10/91974.htm
Spring-3.2.4 + Quartz-2.2.0集成實例 http://www.linuxidc.com/Linux/2013-10/91524.htm
使用 Spring 進行單元測試 http://www.linuxidc.com/Linux/2013-09/89913.htm
運用Spring注解實現Netty服務器端UDP應用程序 http://www.linuxidc.com/Linux/2013-09/89780.htm
Spring 3.x 企業應用開發實戰 PDF完整高清掃描版+源代碼 http://www.linuxidc.com/Linux/2013-10/91357.htm
Spring 的詳細介紹:請點這裡
Spring 的下載地址:請點這裡