@interface自定义注解的实际运用

来源:互联网 发布:8080端口怎么打开 编辑:程序博客网 时间:2024/06/07 05:47

1.什么是注解和为什么使用注解,优点

注解:可以看作是对一个类/方法的扩展模版;也就是一类规范;
使用注解:可以使得每个类/方法 按照注解类中的给定的规则,来为 类/方法注入不同的参数;
优点:注解反射器在获取类/方法中相关注解后,就可以得到不同的类/方法中注解的各种参数与值


2.自定义注解的编码格式

格式:public @interface 注解名 {定义体}

实现代码:

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)public @interface FunctionCode {//值String value();//描述String descript();//默认参数boolean onlySupportPost() default false;}

3.名词解释

  3.1  元注解:负责注解其他注解的注解

元注解分四种:
    1.@Target,
    2.@Retention,
    3.@Documented,
    4.@Inherited
   

@Target说明了Annotation所修饰的对象范围,用于描述注解的使用范围


代码中:ElementType.TYPE, ElementType.METHOD:表示可以使用在类,接口(包括注解类型) 或enum,以及方法中;
ElementType分为:
        1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明


@Retention定义了该Annotation被保留的时间有效范围,也就是定义了该注解的生命周期:
        RetentionPoicy分为:
                1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)


了解:@Documented,@Inherited
@Documented 标记注解,没有成员;
@Inherited  标记注解,@Inherited阐述了某个被标注的类型是被继承的;

3.2  @interface:用来声明一个注解,其中的每一个方法都是声明其中需要的一个配置参数。

方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。
可以通过default来声明参数的默认值
自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节

4.自定义实践

4.1 配置

/** * 订单判断 */@FunctionCode(value = "order", descript = "订单相关API")@Servicepublic class OrderServiceImpl implements OrderService {    @Autowired    private CommonService commonService;    @Autowired    ShoppingOrderMapper shoppingOrderMapper;    @FunctionCode(value = "order.placeOrder", descript = "支付成功后的订单处理接口")    @Override    public ApiResponse<HashMap<String, Object>> placeOrder(ApiRequest apiRequest) throws Exception {        Object orderObj = apiRequest.get("orderStr");        String orderStr = orderObj.toString();        if (StringUtils.isEmpty(orderStr)) {            return new ApiResponse<HashMap<String, Object>>(RestResultEnum.MissParameterException);        }        ApiResponse<HashMap<String, Object>> apiResponse = null;        try {            //如果支付成功则调用此接口,并将订单的数据拆解存储对应的数据表            HashMap<String, Object> hashMap = commonService.saveAnalyzeJson(orderStr);            if (hashMap.size() == 1) {                apiResponse = new ApiResponse<HashMap<String, Object>>(RestResultEnum.CreateOrderFail, 0, hashMap);            } else {                apiResponse = new ApiResponse<HashMap<String, Object>>(RestResultEnum.SUCCESS, 1, hashMap);            }        } catch (Exception ex) {            apiResponse = new ApiResponse<HashMap<String, Object>>(RestResultEnum.UNKNOW_ERROR);        }        return apiResponse;    }}

其中类和方法都标记了自定义注解

4.2 读取

读取的方式和方法很多,这里说一种;

配置web.xml添加监听器:

<listener><listener-class>com.peit.api.web.SpringContextLoaderListener</listener-class></listener>
SpringContextLoaderListener类:
import org.springframework.web.context.ContextLoaderListener;import org.springframework.web.context.WebApplicationContext;import javax.servlet.ServletContextEvent;public class SpringContextLoaderListener extends ContextLoaderListener {    @Override    public void contextInitialized(ServletContextEvent event) {        super.contextInitialized(event);        WebApplicationContext context = (WebApplicationContext) event.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);        SpringBeanProxy.setApplicationContext(context);    }}

加载:SpringBeanProxy.setApplicationContext(context);

import com.epeit.api.annotations.FunctionCode;import org.springframework.context.ApplicationContext;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;public class SpringBeanProxy {private static ApplicationContext applicationContext;private static Map<String, Object> functionCodeBeanMap = new HashMap<String, Object>();private static Map<String, Method> functionCodeMethodMap = new HashMap<String, Method>();private static Map<String, String> functionCodeCatalogMap = new HashMap<String, String>();private static Map<String, Map<String, String>> functionCodeListMap = new HashMap<String, Map<String, String>>();public synchronized static void setApplicationContext(ApplicationContext arg0) {applicationContext = arg0;//加载bean的MapMap<String, Object> tempMap = applicationContext.getBeansWithAnnotation(FunctionCode.class);if (tempMap != null && tempMap.size() > 0) {for (Map.Entry<String, Object> entry : tempMap.entrySet()) {Object bean = entry.getValue();FunctionCode beanFc = bean.getClass().getAnnotation(FunctionCode.class);if (beanFc != null) {//值String beanFunctionCode = beanFc.value();//值和BeanfunctionCodeBeanMap.put(beanFunctionCode, bean);//值和描述functionCodeCatalogMap.put(beanFunctionCode, beanFc.descript());//方法集合Method[] methodArr = bean.getClass().getDeclaredMethods();if (methodArr != null && methodArr.length > 0) {Map<String, String> methodFunctionCodeMap = new HashMap<String, String>();for (Method method : methodArr) {FunctionCode methodFc = method.getAnnotation(FunctionCode.class);if (methodFc != null) {//code和方法绑定String methodFunctionCode = methodFc.value();functionCodeMethodMap.put(methodFunctionCode, method);methodFunctionCodeMap.put(methodFunctionCode, methodFc.descript());}}functionCodeListMap.put(beanFunctionCode, methodFunctionCodeMap);}}}}}public static Object getBean(String beanName) {return applicationContext.getBean(beanName);}public static Object getBeanByFunctionCode(String functionCode) {return functionCodeBeanMap.get(functionCode);}public static Method getMethodByFunctionCode(String functionCode) {return functionCodeMethodMap.get(functionCode);}public static Map<String, String> getFunctionCodeCatalogMap() {return functionCodeCatalogMap;}public static Map<String, Map<String, String>> getFunctionCodeListMap() {return functionCodeListMap;}}

4.3 调用

import com.alibaba.fastjson.JSON;import com.epeit.api.dto.ApiFinalResponse;import com.epeit.api.dto.ApiRequest;import com.epeit.api.dto.ApiResponse;import com.epeit.api.enums.RestResultEnum;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.lang.reflect.Method;import java.util.Date;import java.util.Enumeration;/** * API分发处理器<br> * <p> * 1.首先定义一个注解,如FunctionCode,value  约定;<br> * 2.将这个注解应用于相应业务的service以及service方法上; <br> * 3.当请求进入时,拦截请求,封装请求参数至ApiRequest,并分发到相应的service上;<br> * 4.业务处理完成后,由总控制的地方,统一输出响应数据,如ApiResponse。<br> */@Controllerpublic class ApiDispatchController {    private final Log loger = LogFactory.getLog(ApiDispatchController.class);    private static final String API_ID = "apiId";    private static final String ACCESS_TOKEN = "token";    private static final String FUNCTION_CODE = "functioncode";    @Value("${api.version}")    private String apiVersion;    @Value("${epeit.api.secert}")    private String apiSecert;    @Value("${cookie.domain}")    private String cookieDomain;    @SuppressWarnings({"rawtypes"})    @RequestMapping(value = "/apicenter")    public String apiDispatch(HttpServletRequest req, HttpServletResponse rsp) {        ApiResponse apiRsp = null;        try {            ApiRequest apiReq = new ApiRequest();            ApiRequest sysReq = new ApiRequest();            //请求转换            Enumeration em = req.getParameterNames();            while (em.hasMoreElements()) {                String name = (String) em.nextElement();                if (API_ID.equals(name) || FUNCTION_CODE.equals(name) || ACCESS_TOKEN.equals(name)) {                    sysReq.put(name, req.getParameter(name));                }                String value = req.getParameter(name);                apiReq.put(name, value);            }            //参数验证            apiRsp = this.checkParam(sysReq);            if (apiRsp != null) {                return this.outputApiResponse(req, rsp, apiRsp);            }            // 把调用接口的IP,时间记录下来            apiReq.setApiId(req.getParameter(API_ID));            apiReq.setAccessToken(req.getParameter(ACCESS_TOKEN));            apiReq.setFunctionCode(req.getParameter(FUNCTION_CODE));            apiReq.setRequestIp(WebHelper.getRequestIp(req));            apiReq.setRequestTime(new Date());            apiReq.setCookies(req.getCookies());            apiReq.setSession(req.getSession());            apiReq.setRequest(req);            apiReq.setResponse(rsp);            loger.info("apiReq======" + apiReq.toString());            //对传入的fuctionCode做处理            String functioncode = req.getParameter(FUNCTION_CODE);            // 目录,暂时以这种方法反射            String[] tempArr = functioncode.split("\\.");            if (tempArr != null && tempArr.length > 0) {                //获取服务类的FunctionCode                String serviceFunctionCode = tempArr[0];                //获取到类                Object bean = SpringBeanProxy.getBeanByFunctionCode(serviceFunctionCode);                //获取到方法                Method method = SpringBeanProxy.getMethodByFunctionCode(functioncode);                try {                    //请求类中的方法中                    Object rspObj = method.invoke(bean, new Object[]{apiReq});                    //类判定                    if (rspObj instanceof ApiResponse) {                        apiRsp = (ApiResponse) rspObj;                    }                } catch (Exception e) {                    e.printStackTrace();                    apiRsp = new ApiResponse(RestResultEnum.INVOKE_ERROR);                }            }        } catch (Exception e) {            e.printStackTrace();        }        if (apiRsp == null) {            apiRsp = new ApiResponse(RestResultEnum.UNKNOW_ERROR);        }        // 统一输出响应JSON        return this.outputApiResponse(req, rsp, apiRsp);    }    /**     * 验证参数     */    @SuppressWarnings("rawtypes")    private ApiResponse checkParam(ApiRequest apiReq) {        loger.info("入参: " + apiReq.toString());        ApiResponse apiRsp = null;        if (!StringUtils.isEmpty(apiReq.get(API_ID)) && !StringUtils.isEmpty(apiReq.get(ACCESS_TOKEN)) && !StringUtils.isEmpty(apiReq.get(FUNCTION_CODE))) {            String apiId = apiReq.get(API_ID).toString();            String inputToken = apiReq.get(ACCESS_TOKEN).toString();            String functionCode = apiReq.get(FUNCTION_CODE).toString();            //Token验证            String rightToken = SimpleTokenUtil.buildToken(apiReq, apiSecert);            loger.info("inputToken===" + inputToken + "rightToken=" + rightToken);            if (!inputToken.equals(rightToken)) {                apiRsp = new ApiResponse(RestResultEnum.TOKEN_ERROR);            }        } else {            apiRsp = new ApiResponse(RestResultEnum.MissParameterException);        }        return apiRsp;    }    @SuppressWarnings({"rawtypes", "unchecked"})    private String outputApiResponse(HttpServletRequest req, HttpServletResponse rsp, ApiResponse apiRsp) {        // 统一输出响应JSON        ApiFinalResponse finalRsp = new ApiFinalResponse();        finalRsp.setVersion(apiVersion);        finalRsp.setFunctioncode(req.getParameter(FUNCTION_CODE));        finalRsp.setIsSuccess(apiRsp.getReturnEnum().getIsSuccess());        finalRsp.setCode(apiRsp.getReturnEnum().getCode());        finalRsp.setMsg(apiRsp.getReturnEnum().getMsg());        finalRsp.setTotal(apiRsp.getTotal());        finalRsp.setRecord(apiRsp.getRecord());        String jsonString = JSON.toJSONString(finalRsp, true);        loger.info("jsonString===" + jsonString);        String jsonpCallback = req.getParameter("jsonpCallback");        if (jsonpCallback != null && !"".equals(jsonpCallback.trim())) {            return WebHelper.outputForJsonp(jsonpCallback, jsonString, rsp);        } else {            return WebHelper.outputJson(jsonString, rsp);        }    }}


5.优势

1.统一调用,无需暴露大量的接口,降低开发成本;同时也降低了前端接口调用地址的维护的复杂度;

2.代码结构明晰,方便拓展


6.请求和返回

请求参数:


{apiId=1234567890876542345678, functioncode=order.placeOrder, token=c664788ac23ac2c839cd1649601382de, orderStr={"userId":1,"totalPrice":1.38,"deviceInfo":"866184023611242","userIp":"105.31.168.192","orderAddress":"上海田林路288号田林大厦123号","linkman":"","linkTel":"15601751301","record":[{"id":"60","proId":"23","proName":"产品","productPic":"/epeit/20150717/default/2ae8eef72eff47fb8c650bf438618bd2.png","proPrice":"1","proNum":"1","emerLever":"0","emerName":"不加急","emerPrice":"0","orderPrice":"1.0","freight":"0"}]}}



返回值:
{"code":"0000","functioncode":"order.placeOrder","isSuccess":true,"msg":"成功","record":{"orderAddress":"上海田林路288号田林大厦123号","orderCode":"DD514375267736684","totalPrice":1.38,"userId":"1"},"total":1,"version":"1.0"}


部分字段解释
orderCode:订单编号
totalPrice:商品价格



原创粉丝点击