最近我们部门有个小项目,用来管理这个公司所有项目用到的代码表,例如国家代码、行政区划代码等。这个项目的功能其实很少,就是简单的修改、查询、新增和逻辑删除。但是为每张表都写一套增删改查的页面和一套service,工作量巨大,且维护很困难。我们发现各个表的业务其实都很类似,如果能写一套通用的service代码,在web层根据表名动态调用,在通用的jsp上生成想要的数据,那就只需要写一套代码就可以完成所有代码表的操作了。

  完成这个要求第一个想到的当然是用反射啊,通过表名反射生成相应的QO、DAO,通过调用相应的dao方法,来实现相关功能。但是当我通过反射实例出dao,再执行相应的方法时,方法内一直报错。通过查询资料,可以通过方法得到已经被Spring托管的bean( XX.getBean("xxx") ),于是我改成根据表名动态获取dao,通过反射找到相应方法,执行相应方法,问题就迎刃而解了。

  

  首先是获取被Spring托管类的工具类

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import org.springframework.beans.factory.DisposableBean;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.ApplicationContextAware;
  6. import org.springframework.stereotype.Service;
  7.  
  8. /**
  9. * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.
  10. */
  11. @Service
  12. public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
  13.  
  14. private static ApplicationContext applicationContext = null;
  15.  
  16. private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
  17.  
  18. /**
  19. * 实现ApplicationContextAware接口, 注入Context到静态变量中.
  20. */
  21. public void setApplicationContext(ApplicationContext applicationContext) {
  22. logger.debug("注入ApplicationContext到SpringContextHolder:" + applicationContext);
  23.  
  24. if (SpringContextHolder.applicationContext != null) {
  25. logger.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:"
  26. + SpringContextHolder.applicationContext);
  27. }
  28.  
  29. SpringContextHolder.applicationContext = applicationContext; //NOSONAR
  30. }
  31.  
  32. /**
  33. * 实现DisposableBean接口,在Context关闭时清理静态变量.
  34. */
  35. @Override
  36. public void destroy() throws Exception {
  37. SpringContextHolder.clear();
  38. }
  39.  
  40. /**
  41. * 取得存储在静态变量中的ApplicationContext.
  42. */
  43. public static ApplicationContext getApplicationContext() {
  44. assertContextInjected();
  45. return applicationContext;
  46. }
  47.  
  48. /**
  49. * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
  50. */
  51. @SuppressWarnings("unchecked")
  52. public static <T> T getBean(String name) {
  53. assertContextInjected();
  54. return (T) applicationContext.getBean(name);
  55. }
  56.  
  57. /**
  58. * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
  59. */
  60. public static <T> T getBean(Class<T> requiredType) {
  61. assertContextInjected();
  62. return applicationContext.getBean(requiredType);
  63. }
  64.  
  65. /**
  66. * 清除SpringContextHolder中的ApplicationContext为Null.
  67. */
  68. public static void clear() {
  69. logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
  70. applicationContext = null;
  71. }
  72.  
  73. /**
  74. * 检查ApplicationContext不为空.
  75. */
  76. private static void assertContextInjected() {
  77. if (applicationContext == null) {
  78. throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
  79. }
  80. }
  81. }

之后是service层代码

  1. public interface CommonService {
  2.  
  3. /**
  4. * 分页查询
  5. * @param object 表名
  6. * @return Page<> 列表
  7. */
  8. Object findPageList(String name);
  9. }
  1. /**
  2. *
  3. * 通用service
  4. */
  5. @Service("commonService")
  6. public class CommonServiceImpl implements CommonService {
  7. /**
  8. * 分页查询
  9. * @param object 表名
  10. * @return Page<> 列表
  11. */
  12. public Object findPageList(String name) {
  13. try {
  14. //获取QO
  15. Class clQO = Class.forName("org.xxx.domain.qo."+name+"QO");
  16. Object objectQO = clQO.newInstance();
  17. //设置未删除
  18. Field deltIndc = clQO.getDeclaredField("deltIndc");
  19. deltIndc.setAccessible(true);
  20. deltIndc.set(objectQO, "0");
  21. //首字母小写 拼成xxxxDao
  22. String nameDao =
  23. (new StringBuilder()).append(
  24. Character.toLowerCase(name.charAt(0))).append(name.substring(1)).toString()
  25. +"Dao";
  26. //获取被Spring托管的dao层实例
  27. Object objDao = SpringContextHolder.getBean(nameDao);
  28. Method[] ms = objDao.getClass().getMethods();
  29. for(Method m:ms){
  30. //找到find方法 执行
  31. if("find".equals(m.getName())){
  32. return m.invoke(objDao, new Object[]{objectQO});
  33. }
  34. }
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. }
  38. return null;
  39. }
  40. }

controller

  1. @Controller
  2. public class CommonAction {
  3.  
  4. @Autowired(required = false)
  5. private CommonService commonService;
  6.  
  7. @RequestMapping("getPage")
  8. public @ResponseBody Object getPage(String name) {
  9. //"PltmPubNews"
  10. return commonService.findPageList(name);
  11. }
  12.  
  13. }

  这样就可以根据表名动态查询了。

相关链接  :   http://blog.csdn.net/gaopeng0071/article/details/50511341

反射和动态加载bean 完成 通用servie的更多相关文章

  1. Java反射、动态加载(将java类名、方法、方法参数当做参数传递,执行方法)

    需求:将java类名.方法.方法参数当做参数传递,执行方法.可以用java的动态加载实现   反射的过程如下:     第一步:通过反射找到类并创建实例(classname为要实例化的类名,由pack ...

  2. C# 反射实现动态加载程序集

    原文:https://blog.csdn.net/pengdayong77/article/details/47622235 在.Net 中,程序集(Assembly)中保存了元数据(MetaData ...

  3. C#实现反射调用动态加载的DLL文件中的方法

    反射的作用:1. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型 2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射.3. ...

  4. Java动态加载类在功能模块开发中的作用

    Java中我们一般会使用new关键字实例化对象然后调用该对象所属类提供的方法来实现相应的功能,比如我们现在有个主类叫Web类这个类中能实现各种方法,比如用户注册.发送邮件等功能,代码如下: /* * ...

  5. c#实现动态加载Dll(转)

    c#实现动态加载Dll 分类: .net2009-12-28 13:54 3652人阅读 评论(1) 收藏 举报 dllc#assemblynullexceptionclass 原理如下: 1.利用反 ...

  6. c#实现动态加载Dll

    原文:c#实现动态加载Dll 原理如下: 1.利用反射进行动态加载和调用. Assembly assembly=Assembly.LoadFrom(DllPath); //利用dll的路径加载,同时将 ...

  7. C# 动态加载(转)

    原文链接地址:http://blog.csdn.net/lanruoshui/article/details/5090710 原理如下: 1.利用反射进行动态加载和调用. Assembly assem ...

  8. .Net Core利用反射动态加载类库的方法(解决类库不包含Nuget依赖包的问题)

    在.Net Framework时代,生成类库只需将类库项目编译好,然后拷贝到其他项目,即可引用或动态加载,相对来说,比较简单.但到了.Net Core时代,动态加载第三方类库,则稍微麻烦一些. 一.类 ...

  9. C# 利用反射动态加载dll

    笔者遇到的一个问题,dll文件在客户端可以加载成功,在web端引用程序报错.解决方法:利用反射动态加载dll 头部引用加: using System.Reflection; 主要代码: Assembl ...

随机推荐

  1. 在MySQL Workbench查看表,表结构,索引,函数,存储过程,触发器,重连

    表 表结构 索引 触发器 存储过程 函数 重新连接 出现Error Code: 2006 MySQL server has gone away时

  2. Linux下dmesg命令处理故障和收集系统信息的7种用法

    目录: <syslog之一:Linux syslog日志系统详解> <syslog之二:syslog协议及rsyslog服务全解析> <syslog之三:建立Window ...

  3. 单点登录--CAS认证--web.xml配置详解

    参考网址: https://blog.csdn.net/zhurhyme/article/details/29349543 https://blog.csdn.net/shzy1988/article ...

  4. 执行shell脚本的四种方式(转)

    原文网址:https://www.jb51.net/article/53924.htm 这篇文章主要介绍了Linux中执行shell脚本的4种方法,即总结在Linux中运行shell脚本的4种方法. ...

  5. 手把手教你整合最优雅SSM框架

    我们看招聘信息的时候,经常会看到这一点,需要具备 SSM 框架的技能, SpringMVC 可以完全替代 Struts,配合注解的方式,编程非常快捷,而且通过 restful 风格定义 url,让地址 ...

  6. 解决Maven工程install时[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources

    一.背景 最近的项目在用maven 进行install的时候,发现老师在控制台输出警告:[WARNING] Using platform encoding (UTF-8 actually) to co ...

  7. 浏览器对CSS小数点的解析——坑

    在写移动端项目时,为了将一个元素垂直居中,于是我将元素的高和行高设置成一样的,但是显示出来的结果,却让人不得其解,如下: 可以看到按钮的底部有一条缝隙,一开始以为是代码写错了,于是检查了一下,发现没啥 ...

  8. elk-nginx输出json格式的日志

    把Nginx日志的格式输出成JSON格式展示在Kibana面板,生产环境中基本都是这么使用. 1, 配置nginx 主要修改nginx的访问日志格式,这里定义成json格式,以便后面logstash更 ...

  9. Entity Framework 6.x 学习之 - 创建带连接表的实体模型 with Database First

    一.Modeling a Many-to-Many Relationship with No Payload 1. 创建数据库表 CREATE TABLE [Album] ( , ), ) COLLA ...

  10. Spring Actuator源码分析(转)

    转自:http://blog.csdn.net/wsscy2004/article/details/50166333 Actuator Endpoint Actuator模块通过Endpoint暴露一 ...