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

最近在做一个手机后台项目,使用的是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;
 }

生成的效果

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

下面是具体实现

接口描述类

/** 
 * <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 的下载地址: 

本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-01/112285.htm

使用Spring自定义注解生产Http接口描述信息
更多相关文章
  • SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
             首先我们为什么需要做日志管理,在现实的上线中我们经常会遇到系统出现异常或者问题.这个时候就马上打开CRT或者SSH连上服务器拿日子来分析.受网络的各种限制.于是我们就想为什么不能直接在管理后台查看报错的信息呢.于是日志管理就出现了.          其次个人觉得做日志管理最好的是 ...
  • Spring源码解析BeanFactory接口体系解读
    不知道为什么看着Spring的源码,感触最深的是Spring对概念的抽象,所以我就先学接口了,BeanFactory是Spring IOC实现的基础,这边定义了一系列的接口,我们通过这些接口的学习,可以大致了解BeanFactory体系各接口如何分工合作.为学习具体实现打下基础.毕竟这边逻辑复杂,涉 ...
  • A,首先说,如何配置:        1,在web.xml中添加代码:             <!-- log4j的配置相关 -->                   <context-param>                       <param-name ...
  • 一篇关于使用spring @Scheduled注解执行定时任务文章,希望对大家会有所帮助.javaapplicationContext.xml配置:添加命名空间: 代码如下 xmlns:task="http://www.springframework.org/schema/task&quo ...
  • Spring MVC 注解-让Spring跑起来
     (1) 导入包,包结构如下图所示:         (2) 配置web.xml,如下所示:<?xml version="1.0" encoding="UTF-8"?>  <web-app xmlns:xsi="http://www ...
  • Spring基于注解的缓存配置--EHCacheANDOSCache
    本文将构建一个普通工程来说明spring注解缓存的使用方式,关于如何在web应用中使用注解缓存,请参见: Spring基于注解的缓存配置--web应用实例 一.简介 在spring的modules包中提供对许多第三方缓存方案的支持,包括: EHCache OSCache(OpenSymphony) ...
  • 简析Geoserver中获取图层列表以及各图层描述信息的三种方法
    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 实际项目中需要获取到Geoserver中的图层组织以及各图层的描述信息:比如字段列表等.在AGS中,我们可以直接通过其提供的REST服务获取到图层组织情况以及图 ...
一周排行