查询数据直接在job中实现,把提供接口和job合在一起
这种知识把提供接口的查询的数据放在一起,减少接口的开发,使用通用的方法查询数据并起导出。
重点说一下job的核心逻辑和代码实现
首先,简单的说明tk.mybatis 查询数据的方法主要有一下的几种:
1、直接使用系统定义好的方法(selectXXXX)。
可以使用 Mybatis Generator 直接生成,参数主要有两个参数,一个为查询条件等信息(Example 或 Condition),一个分页数据(RowBounds)
2、使用xml文件中写sql语句
mybatis 中的方法其实也是在xml文件中定义
3、使用注解(@Select 或者 @SelectProvider)
@Select("select max(id) from TABLE_NAME") public int getMaxId();
核心代码:
由于涉及的代码还是有点多的,所以只粘贴部分代码作为参考,主要看看原理,以后有时间整理出来再上传上来,里面的包可以 URLClassLoader 动态调用
1、获取实体
exampleJson 为Example序列化的值
Object example = JSON.parseObject(exampleJson, Object.class); // 数据库实体 Object entityPath = ((JSONObject) example).get("entityClass"); Class> entityClass = Class.forName(String.valueOf(entityPath));
2、获取mapper
tk中的example中有对应的实体对象,我们可以根据实体对象找到对应的mapper
/** * 获取mapper * * @param entityClass 实体类 * @return */ private Mapper getMapper(Class> entityClass) { // 获取所有的Mapper Map
mappers = applicationContext.getBeansOfType(Mapper.class); for (String key : mappers.keySet()) { mapper = mappers.get(key); Class>[] classes = mapper.getClass().getInterfaces(); for (Class> aClass : classes) { if (getMapper(entityClass, mapper, aClass)) { return mapper; } } } return mapper; } /** * 获取mapper * * @param entityClass 实体类 * @param mapper mapper * @param aClass aClass * @return */ private boolean getMapper(Class> entityClass, Mapper mapper, Class> aClass) { Type[] types = aClass.getGenericInterfaces(); for (Type type : types) { Type[] arguments = ((ParameterizedType) type).getActualTypeArguments(); for (Type argument : arguments) { String name = ((Class) argument).getName(); if (name.equals(entityClass.getName())) { // 假如获取到的实体类一致,则说明正确 return true; } } } return false; }
3、动态执行方法查询数据
动态查询数据的接口,现在支持的参数 Example(Condition),RowBounds和基本参数(基本参数现在直接从Example中提取获取)
private Object getMethodInvoke(Object example, RowBounds rowBounds, Mapper mapper, String methodName) throws InvalidException { // 查询总条数,没有则直接返回 Class extends Mapper> mapperClass = mapper.getClass(); // 获取需要执行的方法 Method[] methods = mapperClass.getDeclaredMethods(); Object rValue = null; for (Method method : methods) { if (!method.getName().equals(methodName)) { continue; } // 方法对应的值 List
4、导出svc用的组件
File file = new File(fileName); FileOutputStream fileOutputStream = new FileOutputStream(file); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "GB2312"); Writer writer = new BufferedWriter(outputStreamWriter); CSVPrinter printer = CSVFormat.EXCEL.print(writer); List
printer.printRecord(cells); printer.flush();
5、导出模板注解
public enum FormatTypeEnum { /** * 默认当前的值 */ DEFAULT("DEFAULT", "当前的值"), /** * 解析文本 */ TEXT("TEXT", "解析文本"), /** * 读取数据库 */ DATABASE("DATABASE", "读取数据库"), /** * 缓存 */ CACHE("CACHE","缓存"); /** * 编码 */ String code; /** * 提示信息 */ String message; /** * 构造函数 * * @param code 编码 * @param message 提示信息 */ FormatTypeEnum(String code, String message) { this.code = code; this.message = message; } /** * 获取编码 * * @return */ public String getCode() { return code; } /** * 获取提示信息 * * @return */ public String getMessage() { return message; } }
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface ExportField { /** * 表头 * * @return */ String tableHeader() default "未指定"; /** * 当前的值为数值要显示别名是读库还是字符串 * * @return */ FormatTypeEnum formatTypeEnum() default FormatTypeEnum.DEFAULT; /** * 当前类型为文本,则直接反序列化格式 * 字符串:[{"值":""显示的名称},{"值":""显示的名称}] * 数据库则直接用数据库语句:select cols from table where a = %s * * @return */ String formatContent() default "{}"; /** * 数据库表实体对应的属性名称,用于定义的导出模板和实体类的属性名称不一致时的转换 * 若是直接在提示中设置此注解或者名称和实体的名称一致,可以不指定 * * @return */ String fieldName() default ""; }