万万没想到,本渣居然也有用javassist的一天。真是只要胆子大,啥技术都敢用啊。
先说需求
很简单,就是下载excel,好嘛,找了个阿里的easyExcel,用的美滋滋,结果需求进一步了,要能随意的查哪个表,不用每次都改代码新建Entity类,好嘛,我傻了,但是呢,我又不想换别的excel工具,心里想着怎么在原有的代码上改一下就好。
展示一下原有的工具类
public static void download(HttpServletResponse response, String name, Class type, List<?> data) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode(name, "UTF-8");
// String fileName = URLEncoder.encode(name, "ISO-8859-1");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), type)
.sheet("sheet1").doWrite(data);
}
问题
问题不就是没有数据库对应的entity类嘛,既然没有那就造一个!!!
说起新的类第一反应就是动态代理,然而动态代理是为了改变行为,咱们只是要几个field,几个get、set方法而已,动态代理不适合,也干不了这个。
这个时候我脑袋灵光一闪,学dubbo的时候不是看到有javassist这种东西吗?根本不在乎什么代理不代理,就跟拿记事本写java文件一样。
这个大胆的想法一出来,我的第一反应就是摇头,动态生成类这么高大上的东西,框架里才能用到的东西,我这种小菜鸡也敢用,怕不是对方还没用力我就倒下了。然而,那位大人说过所谓「活着」就是要克服恐惧,而站在世界顶点的,便是那没有一丝恐惧的人!
说干就干
说干就干,百度起来,我们不过要的是一个简单的类,包名+类名+field+get/set方法足以。
类名
ClassPool pool = ClassPool.getDefault();
CtClass cclz = pool.makeClass("com.example.javass." + beanName);
field
//这里需要获取field的类型的权限定名,这个好说,例如Integer.class.getName()。
CtField f2 = new CtField(pool.get(fieldTypeAllName), key, cclz);
//设置修饰符
f2.setModifiers(Modifier.PRIVATE);
cclz.addField(f2);
getter/setter
//如果是某个属性的get和set方法还可以通过CtNewMethod类来创建
String s = key.substring(0, 1).toUpperCase() + key.substring(1);
CtMethod m3 = CtNewMethod.getter("get" + s, f2);
CtMethod m4 = CtNewMethod.setter("set" + s, f2);
cclz.addMethod(m3);
cclz.addMethod(m4);
构造方法
CtConstructor constructor2 = CtNewConstructor.make("public " + beanName +"(){}", cclz);
cclz.addConstructor(constructor2);
类加载器
CtConstructor constructor2 = CtNewConstructor.make("public " + beanName +"(){}", cclz);
cclz.addConstructor(constructor2);
生成Class
Class clz = cclz.toClass(SS.class.getClassLoader());
好像缺了包名,不过看来javassist已经给我们做了
剩下的问题
原有的工具类,不止需要entity的类,还需要List的数据,那么怎么把List转换成List呢,难道要自己一个一个从map里get,然后再set到实体类里吗?这个对应关系我又怎么保证呢?
正当我头疼Get/Set方法和field的对应关系时,想起一般的网页项目,后端接口返回类型有时是List,也就是数据在field里,但是前端接收的json,是通过对象里的field对应的get方法拿到的;在接收对象时也是同理,json给我们发送json串,后端接口的接收类型也是对象,但这不是简单的field到field的关系,而是fastJson等工具帮我们把json里的数据拿出来set到实例里的。
也就是说,FastJson就有把数据放到实例里的能力。(这种工具甚至会根据get方法给你莫名其妙多出字段,这里不细说了)
那么就用FastJson来做吧
String s = JSON.toJSONString(map);
Object o = JSON.parseObject(s, type);
JSON解析需要类,我们前面已经生成了类,在这里用上了。
结语
我估计我这个需求肯定有更好的办法解决,但是呢,没那么忙,也有功夫去自己搞个小东西,所以花一点时间尝试一下,美滋滋。当然啦,所谓的鲁棒性什么的,基本是没有的,但是,数字和字符类型是没有问题的,就先这样吧。
总之,尝试了下javassist,感觉这些技术离我们并不远,隐隐约约感觉自己又提升了一点点呢。
再次中二一下:
所谓「活着」就是要克服恐惧,而站在世界顶点的,便是那没有一丝恐惧的人!