精华内容
下载资源
问答
  • 而这些抽象方法就是多个类共同公共行为规范,需要类去遵守,这些行为是与外部交流通道,这就意味着接口通常定义的都是公共的用法,接口只关心这些类有没有遵守这些方法,而不去关心这些类内部数据,也不关心...

    接口是只是特殊的抽象类,它不包含普通方法,只包含抽象方法。而这些抽象方法就是多个类共同的公共行为规范,需要类去遵守,这些行为是与外部交流的通道,这就意味着接口通常定义的都是公共的用法,接口只关心这些类有没有遵守这些方法,而不去关心这些类的内部数据,也不关心这些类的方法实现细节。打个比方来说,接口就是一个公司的规章制度,部门就是类,那规章制度都是公开的要求大家遵守的,不可能把它私有起来不让别人看吧,那就没有意义了。

    那怎么证明呢,可以用反射。

    定义接口文件

    package com.zhangqi.jvm;
    
    import java.util.Date;
    
    public interface ITest {
    	
    	double PI = 3.14;
    	Date CREATE_TIME = new Date();
    	
    	void play();
    	String getName();
    }
    

    接下来,测试方法来反射获取静态变量和方法。

    package com.zhangqi.jvm;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class ReflectTest {
    
    	public static void main(String[] args) throws ClassNotFoundException {
    
    		// 加载com.zhangqi.jvm.ITest类文件
    		Class<?> clazz = Class.forName("com.zhangqi.jvm.ITest");
    		
    		// 获取类中所有方法
    		Method[]  methods = clazz.getDeclaredMethods();
    		
    		// 遍历每个方法,并输出该方法
    		for (Method method : methods) {
    			System.out.println(method.toString());
    		}
    		
    		System.out.println("~~~~~~~~~~~~~~~~~~~~~");
    		
    		// 获取类中所有静态变量
    		Field[] fields = clazz.getDeclaredFields();
    		
    		// 遍历所有常量
    		for (Field field : fields) {
    			System.out.println(field);
    		}
    	}
    }
    

    执行之后得到结果如下:

    public abstract java.lang.String com.zhangqi.jvm.ITest.getName()
    public abstract void com.zhangqi.jvm.ITest.play()
    ~~~~~~~~~~~~~~~~~~~~~
    public static final double com.zhangqi.jvm.ITest.PI
    public static final java.util.Date com.zhangqi.jvm.ITest.CREATE_TIME
    

      

    转载于:https://www.cnblogs.com/boucher/p/5682140.html

    展开全文
  • 现在系统有个需求所有列表 增加一个导出excel功能,为了不对现有业务带来倾入性 以及 对导出方法方便管理。设计为一个公共接口,前端列表 统一调用该接口,传参 有 要导出列,要导出数据(导出当前页...

    通过调用公共接口导出列表excel

    这篇文章不讲述如何使用easypoi导出excel,主要讲述的是如何通过公共接口调用其他接口拿数据。

    现在系统有个需求是 对所有列表 都增加一个导出excel功能,为了不对现有的业务带来倾入性 以及 对导出方法方便管理。设计为一个公共接口,前端列表 统一调用该接口,传参 有 要导出的列,要导出的数据(导出当前页数据,导出选中的数据,全部数据则传入数据接口的URL),导出excel集成的是easypoi,这个设置好表头List modelList = new ArrayList<>()和对应的数据List<Map<String, Object>> dataList = new ArrayList<>(),再调用ExcelExportUtil.exportExcel(exportParams, entities, list)就好了。codeSet 代码集是用于这个系统数据转换的。

    //表头
    List<ExcelExportEntity> modelList = new ArrayList<>();
    //数据行
    List<Map<String, Object>> dataList = new ArrayList<>();
    //代码集
    Map<String,Map<String,String>> codeSet = new HashMap<>();
    //设置表头
    setTableTitle( tableDefinition, modelList, codeSet, requestWrapper, response);
    //设置对应数据
    setTableData(rowList, tableDefinition, dataList, codeSet, requestWrapper, response);
    log.debug("=====>组装数据完成:"+(System.currentTimeMillis()-start));
    //组装下载excel文件
    ExcelUtils.exportExcel(modelList,dataList,"导出列表.xls",response);
    //testExcel(tableDefinition,rowList,response);
    log.debug("=====>导出全部数据完成:"+(System.currentTimeMillis()-start));
    

    以为很简单,但是遇到不少坑啊,现在就将遇到的问题做一个记录。

    主要问题是导出所有数据,如何通过前台传入的url调用指定的接口拿数据。我是通过在后台维护了一套url和方法对象的映射关系。通过下面的方法:

    @Slf4j
    @Configuration
    public class ActionManager {
    
    	public static Map<String, MethodEntity> actionMap = new HashMap();
    
    	/**
    	 * 扫描包
    	 */
    	@PostConstruct
    	private void scan() {
    		doAction();
    	}
    
    	public void doAction() {
    		// 包名且不可忘记,不然扫描全部项目包,包括引用的jar,填写所在的包名称!!!!
    		Reflections reflections = new Reflections("cn.***.***.app");
    		// 获取带Service注解的类
    		Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(RestController.class);
    		//遍历restcontroller类中的url映射方法方法
    		searchUrlMethod(typesAnnotatedWith);
    		Set<Class<?>> typesAnnotatedWith2 = reflections.getTypesAnnotatedWith(Controller.class);
    		//遍历controller类中的url映射方法方法
    		searchUrlMethod(typesAnnotatedWith2);
    	}
    
    	private void searchUrlMethod(Set<Class<?>> typesAnnotatedWith) {
    		for (Class clazz : typesAnnotatedWith) {
    			String[] clazzReq = null;
    			if(clazz.isAnnotationPresent(RequestMapping.class)){
    				clazzReq = ((RequestMapping) clazz.getAnnotation(RequestMapping.class)).value();
    			}
    			String clazzUrl = "";
    			if(clazzReq!=null&&clazzReq.length>0){
    				clazzUrl = clazzReq[0];
    			}
    			Map<String, MethodEntity> methodMap = new HashMap<>();
    			Method[] methods = clazz.getDeclaredMethods();
    			for (Method method : methods) {
    				String[] methUrl = null;
    				if (method.isAnnotationPresent(RequestMapping.class)) {
    					methUrl = ((RequestMapping) method.getAnnotation(RequestMapping.class)).value();
    				}else if(method.isAnnotationPresent(PostMapping.class)){
    					methUrl = ((PostMapping) method.getAnnotation(PostMapping.class)).value();
    				}else if(method.isAnnotationPresent(GetMapping.class)){
    					methUrl = ((GetMapping) method.getAnnotation(GetMapping.class)).value();
    				}else{
    					continue;
    				}
    				if (methUrl.length > 0) {
    					try {
    						//执行方法记录
    						MethodEntity methodEntity = MethodEntity.builder().annotation(methUrl[0]).classpath(clazz.getName()).classname(clazz.getSimpleName()).methodname(method.getName()).build();
    						actionMap.put(clazzUrl+methUrl[0], methodEntity);
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}
    	}
    }
    

    这个方法中 @PostConstruct 表示初始化bean时执行一次注解的方法,扫描指定的包 cn.*.*.app ,找到包含 @RestController@Controller 注解的类,然后遍历方法,将方法的信息封装到 MethodEntity 中,

    @Data
    @Builder
    public class MethodEntity {
    
    	/**
    	 * 类名称
    	 */
    	private String classname;
    
    	/**
    	 * 类路径
    	 */
    	private String classpath;
    	/**
    	 * 方法名称
    	 */
    	private String methodname;
    	/**
    	 * 注解写的value
    	 */
    	private String annotation;
    }
    

    最后将拼接的 url 和封装好的 MethodEntity 放入actionMap 中。
    然后就是通过前台传入 url 调用对应的接口了,直接上代码

    @Slf4j
    public class CallUrlUtil {
    	//前台没有传入类似json参数
    	public static Object getResultByAction(HttpServletRequest request, HttpServletResponse response) {
    		return getResultByAction(request,response,null);
    	}
    
    	//前台有传入类似json参数 通过JSONObject[]接收
    	public static Object getResultByAction(HttpServletRequest request, HttpServletResponse response, JSONObject[] requestbody) {
    		String actionName = RequestUtil.getString(request, "actionName");
    		if (StringUtils.isBlank(actionName)) {
    			actionName = (String) request.getAttribute("actionName");
    		}
    		if (StringUtils.isBlank(actionName)) {
    			throw new BusinessException("actionName is null!", BaseStatusCode.SYSTEM_ERROR);
    		}
    		String beanName = "";
    		String methodName = "";
    		Class<?> clazz = null;
    		try {
    			//通过指定url找到对应的方法
    			MethodEntity methodEntity = ActionManager.actionMap.getOrDefault(actionName, null);
    			if (methodEntity == null) {
    				return null;
    			}
    			//获取方法所在类的bean名称
    			beanName = LowerUpperCaseFirstLetter.lowerCaseFirstLetter(methodEntity.getClassname());
    			//方法名称
    			methodName = methodEntity.getMethodname();
    			//方法所在的类的字节码对象
    			//clazz = SpringContextUtil.getBean(beanName).getClass(); //此方法获取的字节码是代理过的 没含有编译保留的信息
    			clazz = Class.forName(methodEntity.getClasspath());
    			String finalMethodName = methodName;
    			//找到对应的方法对象
    			Method mathod = Arrays.stream(clazz.getMethods()).filter(method -> method.getName().equals(finalMethodName)).findAny().get();
    			//装配参数
    			//获取方法上的参数
    			Parameter[] parameters = mathod.getParameters();
    			if (parameters.length == 0) {
    				return mathod.invoke(SpringContextUtil.getBean(beanName));
    			} else {
    				List<Object> args = new ArrayList<>(parameters.length);
    				assembleParam(request, response, requestbody, parameters, args);
    				return mathod.invoke(SpringContextUtil.getBean(beanName), args.toArray());
    			}
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			e.printStackTrace();
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    		log.debug("============>call controller interface encounter error:" + actionName);
    		return null;
    	}
    
    	//装配参数
    	private static void assembleParam(HttpServletRequest request, HttpServletResponse response, JSONObject[] requestbody, Parameter[] parameters, List<Object> args) {
    		for (Parameter parameter : parameters) {
    			if (parameter.getType().getSimpleName().equals("HttpServletRequest")) {
    				args.add(request);
    			} else if (parameter.getType().getSimpleName().equals("HttpServletResponse")) {
    				args.add(response);
    			} else {
    				//string || 基本数据类型
    				if (parameter.getType().getSimpleName().equals("String") || parameter.getType().isPrimitive()) {
    					String value = "";
    					//优先尝试获取参数注解里的值
    					RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
    					if (requestParam != null && StringUtils.isNoneBlank(requestParam.value())) {
    						value = request.getParameter(requestParam.value());
    					}
    					if(StringUtils.isBlank(value)){
    						value = request.getParameter(parameter.getName());
    					}
    					args.add(value);
    				} else {
    					try {
    						//非基本数据类型尝试装配复杂数据类型
    						//判断是否是通过@RequestBody注解
    						if (parameter.isAnnotationPresent(RequestBody.class)) {
    							if (requestbody == null || requestbody.length == 0) {
    								//如果是简单的pojo则尝试通过requestParameter注入
    								if(!parameter.getType().getSimpleName().equals("List")){
    									args.add(PackObject.getObject(request, parameter.getType()));
    								}else{
    									args.add(null);
    								}
    								continue;
    							}
    							//list的复杂类型
    							if (parameter.getType().getSimpleName().equals("List")) {
    								List<Object> list = new ArrayList<>();
    								//获取list的泛型类型
    								ParameterizedType parameterizedType = (ParameterizedType) parameter.getParameterizedType();
    								Class<?> actualTypeArgument = (Class<?>) parameterizedType.getActualTypeArguments()[0];
    								//通过requestbody构造list
    								for (JSONObject jsonObject : requestbody) {
    									list.add(JSONObject.parseObject(jsonObject.toJSONString(), actualTypeArgument));
    								}
    								args.add(list);
    							} else {
    								//简单的pojo类型
    								args.add(JSONObject.parseObject(requestbody[0].toJSONString(), parameter.getType()));
    							}
    						} else {
    							args.add(PackObject.getObject(request, parameter.getType()));
    						}
    					} catch (Exception e) {
    						args.add(null);
    					}
    				}
    			}
    		}
    	}
    
    }
    

    这里面有个问题是 获取方法所在的类的字节码对象,使用 clazz = Class.forName(methodEntity.getClasspath()); 而不能用 clazz = SpringContextUtil.getBean(beanName).getClass(); 因为此方法获取的字节码是代理过的 没含有编译保留的信息,后面获取方法参数时 Parameter[] parameters = mathod.getParameters(); 则获取到的参数名是没有实际意义的 为arg0,arg1 这样就没办法绑定对应的参数数据了。

    最麻烦的就是绑定参数数据这一块了,情况太多肯定没考虑周全,后面再优化了……

    最后还有一个 PackObject.getObject(request, parameter.getType()) 这个方法是通过request 封装指定class的对象,代码如下:

    public class PackObject<T> {
        Class<T> c;
    
        public static <T> T getObject(HttpServletRequest request, Class<T> c) {
    
            T t = null;
            try {
                t = c.newInstance(); // 实例化参数对象
            } catch (InstantiationException e1) {
                e1.printStackTrace();
            } catch (IllegalAccessException e1) {
                e1.printStackTrace();
            }
    
            @SuppressWarnings("rawtypes")
            Enumeration e = request.getParameterNames(); // 所有请求参数
    
            Method[] methods = c.getDeclaredMethods(); // 参数对象的所有方法
    
            // 根据对象的set方法的参数类型去将请求的值做相应转换
            while (e.hasMoreElements()) {
                String paramName = e.nextElement().toString();
                String setParamName = reverseParamName(paramName); //将参数名字转换成set方法名字,如:id 转换成 setId
                
                for (Method method : methods) {
                    if (setParamName.equals(method.getName())) {
                        try {
                            Class<?> paramType = (method.getParameterTypes())[0]; //得到set方法参数类型
                            String value = request.getParameter(paramName); 
                            adapter(t, method, paramType, value); //通过适配器将值注入进POJO里面
                        } catch (IllegalArgumentException e1) {
                            e1.printStackTrace();
                        } catch (IllegalAccessException e1) {
                            e1.printStackTrace();
                        } catch (InvocationTargetException e1) {
                            e1.printStackTrace();
                        } catch (SecurityException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
            }
            return t;
        }
    
        private static String reverseParamName(String paramName) {
            char firstChar = paramName.charAt(0);
            char toUpper = Character.toUpperCase(firstChar);
            String setParamName = "set" + String.valueOf(toUpper)
                    + paramName.substring(1);
            return setParamName;
        }
    
        private static <T> void adapter(T t, Method method, Class<?> paramType,
                String value) throws IllegalAccessException,
                InvocationTargetException {
            if (paramType == String.class) {
                method.invoke(t, value);
            } else if (paramType == Integer.class || paramType == int.class) {
                method.invoke(t, Integer.parseInt(value));
            } else if (paramType == Long.class || paramType == long.class) {
                method.invoke(t, Long.parseLong(value));
            } else if (paramType == Boolean.class || paramType == boolean.class) {
                method.invoke(t, Boolean.parseBoolean(value));
            } else if (paramType == Short.class || paramType == short.class) {
                method.invoke(t, Short.parseShort(value));
            } else if (paramType == Float.class || paramType == float.class) {
                method.invoke(t, Float.parseFloat(value));
            } else if (paramType == Double.class || paramType == double.class) {
                method.invoke(t, Double.parseDouble(value));
            } else if (paramType == Character.class || paramType == char.class) {
                char[] cs = value.toCharArray();
                if (cs.length > 1) {
                    throw new IllegalArgumentException("参数长度太大");
                }
                method.invoke(t, value.toCharArray()[0]);
            }
        }
    
    展开全文
  • 在开发项目过程中几乎所有接口都需要知道它返回状态,比如失败或者成功,在移动端通常后台会返回结果,而我们只需要一个弹窗来弹出来结果就可以了。但是这个弹窗如果在整个项目里需要手动去每一个都定义,那非常...
  • 考虑到用户登录系统后,会受到权限规则限制,类似获取系统菜单、系统通知、即时消息等接口是所有用户具备功能,因此就将这部分通用功能接口抽离出来放在公共模块中,用户只需登录成功,即具备公共模块接口...

    1、公共模块的用途

    考虑到用户登录系统后,会受到权限规则的限制,类似获取系统菜单、系统通知、即时消息等接口,是所有用户都具备的功能,因此就将这部分的通用功能接口抽离出来放在公共模块中,用户只需登录成功,即具备公共模块接口的调用权限。

    2、公共模块控制器

    package cn.org.xcore.edusys.controller.common;
    
    import cn.org.xcore.edusys.db.ext.model.Menu;
    import cn.org.xcore.edusys.service.impl.MenuService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    /**
     * 公共接口
     *
     * @author 李海林 手机:13802780104|微信:lihailin9073|Email:767679879@qq.com
     * @copyright 个人开发者李海林版权所有,产品详情及技术服务请登录官网查询[http://www.x-core.org.cn]
     * @create 2019-08-28 08:34
     */
    @Api(tags = "02-公共模块")
    @RestController
    @RequestMapping("/common")
    public class CommonController {
        @Autowired
        MenuService menuService;
    
        /**
         * 获取登录用户菜单列表
         * @return
         */
        @ApiOperation(value = "获取用户菜单")
        @GetMapping("/get_user_menu")
        public List<Menu> getUserMenus() {
            return menuService.getMenusByUserId();
        }
    
    }
    

    3、公共模块服务层

    package cn.org.xcore.edusys.service.impl;
    
    import cn.org.xcore.edusys.db.ext.model.Menu;
    import cn.org.xcore.edusys.common.UserUtils;
    import cn.org.xcore.edusys.db.ext.mapper.ExtMenuMapper;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cache.annotation.CacheConfig;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.List;
    
    
    /**
     * 菜单服务类
     *
     * @author 李海林 手机:13802780104|微信:lihailin9073|Email:767679879@qq.com
     * @copyright 个人开发者李海林版权所有,产品详情及技术服务请登录官网查询[http://www.x-core.org.cn]
     * @create 2019-08-15 09:16
     */
    @Service
    @Transactional
    @CacheConfig(cacheNames = "menus_cache")
    public class MenuService {
        @Autowired
        private ExtMenuMapper extMenuMapper;
    
    //    @Cacheable(key = "#root.methodName")
        public List<Menu> getAllMenu(){
            return extMenuMapper.getAllMenu();
        }
    
        public List<Menu> getMenusByUserId() {
            return extMenuMapper.getMenusByHrId(UserUtils.getCurrentUser().getId());
        }
    
        public List<Menu> menuTree() {
            return extMenuMapper.menuTree();
        }
    
        public List<Long> getMenusByRid(Long rid) {
            return extMenuMapper.getMenusByRid(rid);
        }
    }
    

    4、公共模块数据层

    由于公共模块存在一定的定制化查询业务,仅靠MyBatis Generator自动生成的数据层代码无法实现需求,因此将这部分的数据层代码放在/db/ext模块下,如下图所示:

    5、基于Swagger测试接口

    展开全文
  • 接口的特性

    2020-08-12 10:50:51
    ** 什么是接口?** 接口就是一个特殊的抽象类...接口里面的方法都是抽象的,所有的方法在定义时默认加上public abstract void ccc(); 接口不能够实例化,它就是一个特殊的抽象类 抽象类是继承,接口是用来实现的 一个

    ** 什么是接口?**

    • 接口就是一个特殊的抽象类,里面的方法都是抽象方法,是多个类之间的公共规范
    • 接口解决了Java单继承的缺点
    • 定义接口:
    • public interface 接口名{
    • }
    • 接口的特点:
    • 接口里面的属性全是常量,所有的常量在定义时默认加上public static final int i = 10 ;
    • 接口里面的方法都是抽象的,所有的方法在定义时默认加上public abstract void ccc();
    • 接口不能够实例化,它就是一个特殊的抽象类
    • 抽象类是继承,接口是用来实现的
    • 一个类实现一个接口,这个类必须实现这个接口里所有的抽象方法(这个类不是抽象类)
    • 一个类可以实现多个接口,每个接口间使用“,”隔开
    • 接口里面不能定义普通方法,也没有构造方法
    • 实现类
    • (1).实现接口的类叫做实现类 class A implements B
    • (2).接口也可以继承接口,而且接口可以同时继承多个接口
    • (3).一个类可以同时继承抽象类和实现接口 public class A extends B implements C{}
    展开全文
  • 接口的理解

    2021-03-15 11:02:53
    个人理解:接口可以理解为一种特殊类,接口方法都是公共抽象方法和全局变量,是解决Java无法多重继承手段,接口在实际中更多是为了制定标准。 用interface定义一个接口,这个接口的所有方法只声明方法...
  • 这样每次都是去拿最新,保证了域名一变,所有接口都跟着变简单操作。 实际测试中,用例或接口经常因为切换环境导致域名变化,所以这里就完美解决来切换环境问题了。 首先打开views.py,先搞定接口库接口...
  • 接口

    2019-06-03 15:57:13
    所有方法都是公共抽象方法。 } 接口成员变量 默认都是public static final,必须显式初始化 接口方法 默认都是public abstract 接口没有构造方法,不能被实例化 一个接口不能实现另一个接口,但可以...
  • 接口的作用

    2019-02-12 14:17:34
    抽象类还提供某些具体实现,接口不提供任何实现,接口所有的方法都是抽象方法。接口是完全面向规范的,规定了一批类具有的公共方法规范。 从接口的“实现者角度”看,接口定义了可以向外部提供的服务。 从接口...
  • 实现接口的类必须包含该接口的所有成员实现代码,且都是公共的。实现接口成员有隐式实现和显式实现两种方法。 1. 隐式实现 如下图所示,类MyClass隐式地实现了接口IMyInterfaceDoSomething和DoSomethingElse两个...
  • 在开发项目过程中几乎所有接口都需要知道它返回状态,比如失败或者成功,在移动端通常后台会返回结果,而我们只需要一个弹窗来弹出来结果就可以了。但是这个弹窗如果在整个项目里需要手动去每一个都定义,那非常...
  • C#中的接口

    2018-09-10 20:44:19
    如果要使用多重继承,需要使用接口,因为C#语言只支持单继承,而接口支持多重继承。 当实现接口时,必须实现该接口...接口的成员必须保证是公共的(public),以供外界调用。实现接口的类必须实现所有接口方法。 ...
  • 1.接口是抽象类的延续,可以将它看作纯粹的抽象类,接口所有的方法没有方法体。由方法、属性、事件和索引器组成,但不包含字段。 2. 类要实现接口成员,类中的对应成员必须是公共的、非静态的,并且与接口成员...
  • 关于接口的一些笔记

    2021-04-04 11:00:00
    接口就是一种公共的规范标准,只要符合规范标准,大家可以通用。 Java中接口存在两个意义 用来定义规范 用来做功能拓展 接口的特点 接口用interface关键字来修饰 public interface 接口名{} 类实现接口用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,078
精华内容 431
关键字:

所有的接口都是公共接口