@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); } }}
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:商品价格
- @interface自定义注解的实际运用
- Android中注解的实际运用
- 注解:@interface 自定义注解的语法
- Java 自定义注解@interface
- 关于@interface 自定义注解
- @interface 自定义注解
- 使用@interface 自定义注解
- java @interface 自定义注解
- java自定义注解 @interface
- 自定义注解 @interface
- @interface 自定义注解
- fusioncharts的实际运用
- AcionBar的实际运用
- java之@interface-自定义注解
- (自定义注解)Java注释@interface的用法【转】
- hash算法的实际运用
- spring注解的运用
- java注解,反射实现抽象代码工作中实际运用
- 批量免密登录
- vmware tools第一次安装失败后再次安装时出现的错误及解决
- 谷歌面试题(5)
- Faster R-CNN改进篇-ION/HyperNet/MS CNN
- Dynamic Time Warping(DTW) Algorithm
- @interface自定义注解的实际运用
- 谷歌面试题(6)
- Linux Shell脚本详细教程
- 有关USES_CONVERSION
- PID控制算法的C语言实现
- es5新增数组方法
- 搭建及使用K8s集群 <k8s 集群部署springcloud 多应用>
- R_地图上的热力气泡图
- 掌握Angular2的NgModule(模块系统)