论java中的.xml到底有多坑?!
感觉自己都快哭了,再一次被.xml给坑了一下,这次坑的太狠了,一下子导致自己浪费了昨天一下午,一晚上,今天一上午和半个下午呀,中间的过程真的是乏善可陈呀,各种转折,各种离奇的错误,自己都崩溃了好多次,让我一一来诉说吧。
1、在springmvc分层结构中(分为mybatis层、service层、controller层)自己定义了一个定时器,定时器是定义在service的配置文件中的,文件如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:mvc="http://www.springframework.org/schema/mvc" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xmlns:p="http://www.springframework.org/schema/p" 7 xmlns:tx="http://www.springframework.org/schema/tx" 8 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 9 10 xmlns:task="http://www.springframework.org/schema/task" 11 12 xsi:schemaLocation=" 13 http://www.springframework.org/schema/mvc 14 http://www.springframework.org/schema/mvc/spring-mvc.xsd 15 http://www.springframework.org/schema/beans 16 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 17 http://www.springframework.org/schema/context 18 http://www.springframework.org/schema/context/spring-context-3.2.xsd 19 http://www.springframework.org/schema/aop 20 http://www.springframework.org/schema/aop/spring-aop-3.2.xsd 21 http://www.springframework.org/schema/tx 22 http://www.springframework.org/schema/tx/spring-tx-3.2.xsd 23 24 http://www.springframework.org/schema/task 25 http://www.springframework.org/schema/task/spring-task-3.2.xsd" > 26 27 28 <!-- 定义service --> 29 <!-- 扫描controller交给前段控制器,service包中的注解交给此配置扫描 --> 30 <context:component-scan base-package="service" > </context:component-scan> 31 <!-- 第二个扫描项bean包 --> 32 <context:component-scan base-package="bean" > </context:component-scan> 33 34 35 <task:annotation-driven/> 36 37 </beans>
代码中加粗的部分是定时器的关键,注意这里一定要配置在service层,如果配置到了spring-mvc.xml层,就没有反应,这也是我以前犯的一个愚蠢的错误,究其原因,这和springmvc运行的机理有关,如果没有得到合理的初始化,没有被扫描到都是执行不了的。
之后就可以在service层写定时器的代码了,其实也简单,但是写完之后一定要注意配置扫描,这个地方,因为整个service层都被扫描了,所以无论放在哪里都可以,也不用在.xml中配置了。
定时器的代码如下:
@Component public class StatisticsTimer { private static Logger logger = Logger.getLogger(StatisticsTimer.class); //定时器测试 @Scheduled(cron="0/20 * * * * ? ") public void statisticsTimerCycle(){ System.out.println("============begining==============="); //一些代码 System.out.println("============end==============="); } }
这里要注意加入的部分,之后运行程序,就可以看到每隔一段时间就打印出来一些东西了。
可是在大型项目中,定时器都是用来处理SQL语句的,也就是要进行数据库操作,这个时候,因为我是用的mybatis这个框架,其中配置之后就可以自动扫描来生成代码了,根本就不用我来配置,我就理所当然的使用依赖注入想要的语句,之后来查询数据库,可是一直报错,意思是说mybatis不能找到我要调用的查找方法,在这里我要说明一点,那些mapper以及相应的.xml都是我自己写的,因为自动生成的可能满足不了的我的要求,也正是因为这个原因我就悲剧了,还记得当时写这个东西是在我电脑出了点问题的时候,我没有在工程里面写,而是在一个文本编辑器中写的,这就造成了一些东西是我手打出来的,而不是复制的,这样就很容易错过一个或者两个字母,而这次我竟然真的是犯了这个错,就是因为我在.xml中少写了一个字母‘s’,而我当时不知道呀,再加上对自己的编码能力太自信了吧,想哭。。。
1 17-12-06-14-55-40-001-ERROR-[pool-1-thread-1]-Unexpected error occurred in scheduled task. 2 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): mapper.part.OrderStatisticsPartMapper.selectOrdersInfoByToday 3 at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:189) 4 at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:43) 5 at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:58) 6 at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:51) 7 at com.sun.proxy.$Proxy44.selectOrdersInfoByToday(Unknown Source) 8 at service.statistics.OrderStatisticsOperator.selectOrdersInfoByToday(OrderStatisticsOperator.java:25) 9 at service.timer.StatisticsTimer.statisticsTimerCycle(StatisticsTimer.java:55) 10 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 11 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 12 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 13 at java.lang.reflect.Method.invoke(Method.java:497) 14 at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64) 15 at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53) 16 at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) 17 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) 18 at java.util.concurrent.FutureTask.run(FutureTask.java:266) 19 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) 20 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) 21 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 22 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 23 at java.lang.Thread.run(Thread.java:745)
1 @Autowired 2 private OrderStatisticsOperator orderStatisticsOperator;
首先我给大家看一下我的这些相关文件吧:
1.罪恶之源:OrderStatisticsPartMapper.xml,看到了吗,这就是我标出的那个我错的地方,其实是Orders而不是Order!!!!!!
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 <mapper namespace="mapper.part.OrderStatisticsPartMapper"> 4 5 <resultMap id="order_statistics_part" type="pojo.part.OrderStatisticsPart"> 6 <result column="order_id" jdbcType="VARCHAR" property="orderId" /> 7 <result column="shop_account_id" jdbcType="INTEGER" property="shopAccountId" /> 8 <result column="wating_start_time" jdbcType="VARCHAR" property="watingStartTime" /> 9 <result column="waiting_end_time" jdbcType="VARCHAR" property="waitingEndTime" /> 10 <result column="pay_total_price" jdbcType="DECIMAL" property="payTotalPrice" /> 11 </resultMap> 12 13 <select id="selectOrderInfoByToday" resultMap="order_statistics_part"> 14 select order_id ,shop_account_id , wating_start_time , waiting_end_time , pay_total_price 15 from orders 16 17 </select> 18 19 </mapper>
2.对应的接口类:OrderStatisticsPartMapper
1 package service.statistics; 2 import java.util.List; 3 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Service; 6 7 import pojo.part.OrderStatisticsPart; 8 import mapper.part.OrderStatisticsPartMapper; 9 10 /** 11 * @author zyr 12 * 按日期查询当天商城消费订单信息 13 */ 14 public interface OrderStatisticsInterface { 15 16 public List<OrderStatisticsPart> selectOrdersInfoByToday(String today_date); 17 }
3.OrderStatisticsOperator类,service层,对上面的方法进行封装
1 package service.statistics; 2 import java.util.List; 3 4 import javax.transaction.Transactional; 5 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.stereotype.Service; 8 9 import pojo.part.OrderStatisticsPart; 10 import mapper.part.OrderStatisticsPartMapper; 11 12 /** 13 * @author zyr 14 * 按日期查询当天商城消费订单信息 15 */ 16 @Service("orderStatisticsOperator") 17 //@Service("orderStatisticsInterface") 18 @Transactional 19 //public class OrderStatisticsOperator implements OrderStatisticsInterface{ 20 public class OrderStatisticsOperator{ 21 @Autowired 22 private OrderStatisticsPartMapper orderStatisticsPartMapper; 23 // @Override 24 public List<OrderStatisticsPart> selectOrdersInfoByToday(String today_date) { 25 return orderStatisticsPartMapper.selectOrdersInfoByToday(today_date); 26 } 27 }
4.ApplicationContextUtil类,要注意在以前博客上的代码中是没有@Component的!!!!!!
1 package service.timer; 2 3 import org.apache.log4j.Logger; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.ApplicationContextAware; 6 import org.springframework.stereotype.Component; 7 import org.springframework.stereotype.Controller; 8 9 /** 10 * @author zyr 11 * 由于定时器的执行优先于注入,因此我们不能通过@Resource注入service 12 * 因此需要创建一个类ApplicationContextUtil,用来获取service 13 */ 14 @Component 15 public class ApplicationContextUtil implements ApplicationContextAware{ 16 private static ApplicationContext applicationContext; 17 private static Logger logger = Logger.getLogger(ApplicationContextUtil.class); 18 19 20 public static ApplicationContext getApplicationContext() { 21 return applicationContext; 22 } 23 24 public void setApplicationContext(ApplicationContext applicationContext) { 25 logger.debug("------SpringContextUtil setApplicationContext-------"); 26 ApplicationContextUtil.applicationContext = applicationContext; 27 } 28 public static Object getBean(String beanName) 29 { 30 return applicationContext.getBean(beanName); 31 } 32 }
如果我之前看到该多好呀,可惜是一天之后了,下面我来给大家说一下我看到这个错误做了什么事情!!!
首先我在网上搜索了这个问题,还真的让我给找到了一个同样的问题,就是这篇“该死的博客”让我一直苦逼不堪!!!!!!
http://blog.csdn.net/u011277123/article/details/54285896
根据这篇博客上说的,我发现这就是我的翻版呀,哈哈,然后我开开心心的起了个大早就来搞这个东西了,结果这个博客上有一点不清楚的地方,那就是@Service("一些名称"),括号中的东西到底应该是什么,当然可以是任意字符串,那意思呢,因为我当时直接在OrderStatisticsOperator中直接写了@Service("orderStatisticsOperator")这样的东西,并且在定时器中,使用:
1 OrderStatisticsOperator orderStatisticsOperator=(OrderStatisticsOperator)ApplicationContextUtil.getBean("orderStatisticsOperator");
来直接运行,结果就错了,错了,当然了,在以前的博客上是没有@Component的,因此报的错一直是空指针错误,让我们看一下这个语句,一直报错,这浪费我三个多小时,我一直搞不懂这个东西为什么会报错,而且是空指针错误,因为程序一直卡在ApplicationContextUtil.getBean("orderStatisticsOperator");这个语句上面,提示这个语句空指针错误,我在想是不是beanName中传进的参数orderStatisticsOperator的错,可是也没错呀,如果是全称的话也可以的,但是我已经在@Service中表明了这个名字,应该没错的,那是怎么回事呢,想呀想,改不成是applicationContext的错吧,因为applicationContext.getBean(beanName);,如果applicationContext为空,那么将会是null..getBean(beanName);那么肯定会是空指针异常了,这让我绝望,因为我们的这个类是继承自ApplicationContextAware的,这个东西里面我们重载了 getBean(String beanName)方法和setApplicationContext(ApplicationContext applicationContext) 方法,也就是说在程序运行的时候,加载的过程中就会调用setApplicationContext对我们的applicationContext赋值了,这个意思是应用上下文,当然是在这个时候就给我们的了,可是还是出错,到底是怎么回事呢,我把这个文件放到了controller层还是不行,因为我在另一篇博客上看到,这个定时任务是Spring的,而不是Springmvc上面的应该,而前者比后者先初始化,也就是说前者是后者的父亲,Springmvc是Spring的孩子,应该现在父亲那边初始化才能因为继承的关系在Springmvc中有效,可是放到了controller中还是没用呀,真的坑。。。于是我又进行了一些细微的修改还是不行
1 public static Object getBean(String beanName) 2 { 3 return applicationContext.getBean(beanName); 4 }
就在我快要绝望的时候,突然想起来,我们把这个自己定义的类当做bean,却没有能够让框架扫描到这个东西,因为没有暴露任何东西,所以我在这个类的前面加了个@Component,也就是在这个时候奇迹出现了,程序总算不在报空指针错误了,原来自己之前的所有操作都是因为没有加这个东西,不能让框架扫描到,当然是不能调用里面重载的setApplicationContext方法,从而applicationContext就是空null的,按理说这样总算是解决了问题了,我又运行一下程序,谁知道还是在报以前的错误,mybatis解析不了,我的天呀,当时我的心态真的是爆炸了,想的是原来这个东西,我搞了这么长时间,总算把bean注入到了我需要的地方了,却没有任何效果,就在我痛定思痛的时候,我想到了是不是因为我的那个mapper.xml真的有问题呢,因为以前就有这样的问题,后来我仔细一看还真是有问题,就是少了一个‘s’,我的天,我的世界电闪雷鸣了,赶紧改过来再运行一下,结果正常了,正常了,正常了!!!!!!后来我在想既然用了这个新的类我的程序正常了,并且这个时候我还实现了一个operator的接口,这是我从其他博客中学到的,接口如下:
1 package service.statistics; 2 import java.util.List; 3 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Service; 6 7 import pojo.part.OrderStatisticsPart; 8 import mapper.part.OrderStatisticsPartMapper; 9 10 /** 11 * @author zyr 12 * 按日期查询当天商城消费订单信息 13 */ 14 public interface OrderStatisticsInterface { 15 16 public List<OrderStatisticsPart> selectOrdersInfoByToday(String today_date); 17 }
调用的方法如下:
1 OrderStatisticsInterface orderStatisticsInterface=(OrderStatisticsInterface)ApplicationContextUtil.getBean("orderStatisticsInterface");
这样是正常的,那么我不用接口呢?也就是:
1 OrderStatisticsOperator orderStatisticsOperator=(OrderStatisticsOperator)ApplicationContextUtil.getBean("orderStatisticsOperator");
我试了一下,把一些相应的地方改了一下,竟然也正常了,我哭。。。。
后来想了一下干脆不用这个类,我试一下怎么样,我当时想的是肯定是不行的,谁知道呀,竟然可以了,可以了。。。
也就是这样做,竟然成功了,和我以前编程的方法一模一样,真的是让人难以接受呀!!!!!!原来自己搞了一天的时间就是因为一个字母,只是一个字符呀,都不是字符串,哇哇~~~
1 @Component 2 public class StatisticsTimer { 3 @Autowired 4 private OrderStatisticsOperator orderStatisticsOperator; 5 private static Logger logger = Logger.getLogger(StatisticsTimer.class); 6 //一次性查询所有的订单相关信息 7 private List<OrderStatisticsPart> orderStatisticsList = new ArrayList<OrderStatisticsPart>(); 8 //定时器测试 9 @Scheduled(cron="0/20 * * * * ? ") 10 // @Scheduled(cron="0 59 23 ? * *") 11 public void statisticsTimerCycle(){ 12 System.out.println("============begining==============="); 13 //按时间查询该天商城的所用订单,返回订单的中需要用到的字段,实现统计功能 14 // OrderStatisticsOperator orderStatisticsOperator=(OrderStatisticsOperator)ApplicationContextUtil.getBean("orderStatisticsOperator"); 15 // ApplicationContext appCtx = ApplicationContextUtil.getApplicationContext(); 16 // logger.debug(appCtx); 17 // if(appCtx==null) 18 // { 19 // logger.debug("ApplicationContext 为空"); 20 // } 21 // OrderStatisticsOperator orderStatisticsOperator=(OrderStatisticsOperator)ApplicationContextUtil.getBean("orderStatisticsOperator"); 22 // 23 // OrderStatisticsInterface orderStatisticsInterface=(OrderStatisticsInterface)ApplicationContextUtil.getBean("orderStatisticsInterface"); 24 System.out.println(orderStatisticsOperator); 25 System.out.println("===========暂无问题==============="); 26 orderStatisticsList= orderStatisticsOperator.selectOrdersInfoByToday(DateTimeTool.get_now_date()); 27 System.out.println("============end==============="); 28 // //当前销售菜品统计 29 // dishStatisticsTask(); 30 // //当前商家销售情况统计 31 // shopStatisticsTask(); 32 // //当前商家等位时间统计 33 // waitingTimeStatisticsTask(); 34 }
到了这一步,我可以看到,首先是在网上找的那个程序有问题,没有在类的前面加上@Component,加上了之后使用这个方法也是可以的;
其次,就是无论实现不实现接口和类,其实都是可以的,不一定非要用接口;
最后就是我的程序最本质的错误是在mapper.xml上,这个东西真的坑,以后一定要加倍小心,特别是刚才那种错误,真的是难以发现呀!!!!!!
因此我觉得.xml真的是一个让程序员又爱又恨的东西,爱的原因是这种文件为程序员节约了大量的时间,想要什么功能只要简单的配置就好了,甚至可以灵活地改变自己需要的东西,实现不同的功能,剩下的就交给web容器去解决了,这点来说真的是神器,可是与之相对应的就是对于一些出错信息缺少智能提示的问题,要知道一个好的开发环境是能够让程序员快速而准确地定位自己的错误,并且找到相应的解决办法的,而这个.xml文件对于“”里面的东西是没有解析能力的,只能够处理最基本的语法,比如结构不对称等,这显示是低级的,从可能性的角度来说,.xml在以后还是可能走向越来越智能的道路的,只不过框架这样做的话效率会下降吧,就如我之前说的这个错误,有的时候是在所难免的,人非圣贤,孰能无过,只不过错了却不一定会往这方面想呀,再加上myeclipse报的错误往往有误导的作用,特别是.xml文件出错的情况下,基本上都是没有参考价值的,正如我上一次在.xml中对于一个参数类型的描述,本来是jdbcType=VARCHAR的,而我写成了,jdbcType=String,结果给我报的错误,那是真的让人绝望呀,最后找了好久才找到,大大的浪费了开发的时间,就像这个错误浪费了我一天的时间一样,那个错误也整整浪费了我的大半天,与其他开发工具相比,我还是觉得java需要在这个方面改进一下,让.xml更加的智能起来,这样才能成为大家更喜爱的开发软件。当然了在我的这个错误中,使用网上说的那个方法也是可以的,但是一定要注意一些细节。下面,我对这几种方法进行梳理:
方法一:使用原生的方法,直接依赖注入。
1.1、OrderStatisticsPartMapper.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 <mapper namespace="mapper.part.OrderStatisticsPartMapper"> 4 5 <resultMap id="order_statistics_part" type="pojo.part.OrderStatisticsPart"> 6 <result column="order_id" jdbcType="VARCHAR" property="orderId" /> 7 <result column="shop_account_id" jdbcType="INTEGER" property="shopAccountId" /> 8 <result column="wating_start_time" jdbcType="VARCHAR" property="watingStartTime" /> 9 <result column="waiting_end_time" jdbcType="VARCHAR" property="waitingEndTime" /> 10 <result column="pay_total_price" jdbcType="DECIMAL" property="payTotalPrice" /> 11 </resultMap> 12 13 <select id="selectOrdersInfoByToday" resultMap="order_statistics_part"> 14 select order_id ,shop_account_id , wating_start_time , waiting_end_time , pay_total_price 15 from orders 16 17 </select> 18 19 </mapper>
1.2、OrderStatisticsPartMapper接口
1 package mapper.part; 2 3 import java.util.List; 4 5 import org.apache.ibatis.annotations.Param; 6 import org.mybatis.spring.annotation.MapperScan; 7 8 import pojo.part.OrderStatisticsPart; 9 10 /** 11 * @author zyr 12 * 查询当天该商城产生的所有订单信息 13 * 并返回信息需要的字段 14 */ 15 public interface OrderStatisticsPartMapper { 16 List<OrderStatisticsPart> selectOrdersInfoByToday(@Param("today_date")String today_date); 17 }
1.3.OrderStatisticsOperator:service层,其实也可以不用,直接在定时器中调用mapper
1 package service.statistics; 2 import java.util.List; 3 4 import javax.transaction.Transactional; 5 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.stereotype.Service; 8 9 import pojo.part.OrderStatisticsPart; 10 import mapper.part.OrderStatisticsPartMapper; 11 12 /** 13 * @author zyr 14 * 按日期查询当天商城消费订单信息 15 */ 16 @Service 17 18 public class OrderStatisticsOperator{ 19 @Autowired 20 private OrderStatisticsPartMapper orderStatisticsPartMapper; 21 22 public List<OrderStatisticsPart> selectOrdersInfoByToday(String today_date) { 23 return orderStatisticsPartMapper.selectOrdersInfoByToday(today_date); 24 } 25 }
1.4.定时器任务类:StatisticsTimer
1 package service.timer; 2 import java.util.ArrayList; 3 import java.util.List; 4 5 import mapper.DishSaleStatisticsMapper; 6 import mapper.part.OrderStatisticsPartMapper; 7 8 import org.apache.log4j.Logger; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.context.ApplicationContext; 11 import org.springframework.context.annotation.Configuration; 12 import org.springframework.scheduling.annotation.Scheduled; 13 import org.springframework.stereotype.Component; 14 import org.springframework.stereotype.Service; 15 16 import pojo.part.OrderDetailStatisticsPart; 17 import pojo.part.OrderStatisticsPart; 18 import service.statistics.DishSaleStatisticsOperator; 19 import service.statistics.OrderDetailStatisticsOperator; 20 import service.statistics.OrderStatisticsInterface; 21 import service.statistics.OrderStatisticsOperator; 22 import service.statistics.ShopSaleStatisticsOperator; 23 import service.statistics.WaitingTimeStatisticsOperator; 24 import tools.time.DateTimeTool; 25 26 /** 27 * @author zyr 28 * 系统定时器,每一天定时运行一次,进行统计工作 29 */ 30 @Component 31 public class StatisticsTimer { 32 @Autowired 33 private OrderStatisticsOperator orderStatisticsOperator; 34 private static Logger logger = Logger.getLogger(StatisticsTimer.class); 35 //一次性查询所有的订单相关信息 36 private List<OrderStatisticsPart> orderStatisticsList = new ArrayList<OrderStatisticsPart>(); 37 //定时器测试 38 @Scheduled(cron="0/20 * * * * ? ") 39 public void statisticsTimerCycle(){ 40 System.out.println("============begining==============="); 41 //按时间查询该天商城的所用订单,返回订单的中需要用到的字段,实现统计功能 42 43 System.out.println(orderStatisticsOperator); 44 System.out.println("===========暂无问题==============="); 45 orderStatisticsList= orderStatisticsOperator.selectOrdersInfoByToday(DateTimeTool.get_now_date()); 46 System.out.println("============end==============="); 47 } 48 }
就这样一个程序就可以正常工作了,当然定时器要有之前的配置,这里不再赘述。
方法二:使用ApplicationContextUtil,继承ApplicationContextAware,并且不创建新的服务层接口
首先,方法一中的OrderStatisticsPartMapper.xml和OrderStatisticsPartMapper接口都没变。
其次在以前的服务中作如下修改:
1 package service.statistics; 2 import java.util.List; 3 4 import javax.transaction.Transactional; 5 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.stereotype.Service; 8 9 import pojo.part.OrderStatisticsPart; 10 import mapper.part.OrderStatisticsPartMapper; 11 12 /** 13 * @author zyr 14 * 按日期查询当天商城消费订单信息 15 */ 16 @Service("orderStatisticsOperator") 17 public class OrderStatisticsOperator{ 18 @Autowired 19 private OrderStatisticsPartMapper orderStatisticsPartMapper; 20 public List<OrderStatisticsPart> selectOrdersInfoByToday(String today_date) { 21 return orderStatisticsPartMapper.selectOrdersInfoByToday(today_date); 22 } 23 }
并且增加一个新的类:ApplicationContextUtil,注意红色的部分!!!!!!
1 package service.timer; 2 3 import org.apache.log4j.Logger; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.ApplicationContextAware; 6 import org.springframework.stereotype.Component; 7 import org.springframework.stereotype.Controller; 8 9 /** 10 * @author zyr 11 * 由于定时器的执行优先于注入,因此我们不能通过@Resource注入service 12 * 因此需要创建一个类ApplicationContextUtil,用来获取service 13 * 但是经过测试,事实并非如此,与版本有关 14 */ 15 @Component 16 public class ApplicationContextUtil implements ApplicationContextAware{ 17 private static ApplicationContext applicationContext; 18 private static Logger logger = Logger.getLogger(ApplicationContextUtil.class); 19 20 21 public static ApplicationContext getApplicationContext() { 22 return applicationContext; 23 } 24 25 public void setApplicationContext(ApplicationContext applicationContext) { 26 logger.debug("------SpringContextUtil setApplicationContext-------"); 27 ApplicationContextUtil.applicationContext = applicationContext; 28 } 29 public static Object getBean(String beanName) 30 { 31 return applicationContext.getBean(beanName); 32 } 33 }
然后在定时器中:其中注释的部分也可以打开,看看对象是否为空,肯定不空!一定要注意@Component!!!!!!
1 /** 2 * @author zyr 3 * 系统定时器,每一天定时运行一次,进行统计工作 4 */ 5 @Component 6 public class StatisticsTimer { 7 private static Logger logger = Logger.getLogger(StatisticsTimer.class); 8 //一次性查询所有的订单相关信息 9 private List<OrderStatisticsPart> orderStatisticsList = new ArrayList<OrderStatisticsPart>(); 10 //定时器测试 11 @Scheduled(cron="0/20 * * * * ? ") 12 public void statisticsTimerCycle(){ 13 System.out.println("============begining==============="); 14 //按时间查询该天商城的所用订单,返回订单的中需要用到的字段,实现统计功能 15 OrderStatisticsOperator orderStatisticsOperator=(OrderStatisticsOperator)ApplicationContextUtil.getBean("orderStatisticsOperator"); 16 // ApplicationContext appCtx = ApplicationContextUtil.getApplicationContext(); 17 // logger.debug(appCtx); 18 // if(appCtx==null) 19 // { 20 // logger.debug("ApplicationContext 为空"); 21 // } 22 23 System.out.println(orderStatisticsOperator); 24 System.out.println("===========暂无问题==============="); 25 orderStatisticsList= orderStatisticsOperator.selectOrdersInfoByToday(DateTimeTool.get_now_date()); 26 System.out.println("============end==============="); 27 }
之后运行:
方法三:使用ApplicationContextUtil,继承ApplicationContextAware,并且创建新的服务层接口
这个时候,需要再创建一个新的接口:OrderStatisticsInterface
1 package service.statistics; 2 import java.util.List; 3 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Service; 6 7 import pojo.part.OrderStatisticsPart; 8 import mapper.part.OrderStatisticsPartMapper; 9 10 /** 11 * @author zyr 12 * 按日期查询当天商城消费订单信息 13 */ 14 public interface OrderStatisticsInterface { 15 16 public List<OrderStatisticsPart> selectOrdersInfoByToday(String today_date); 17 }
然后在刚刚的service中继承该接口:
1 package service.timer; 2 import java.util.ArrayList; 3 import java.util.List; 4 5 import mapper.DishSaleStatisticsMapper; 6 import mapper.part.OrderStatisticsPartMapper; 7 8 import org.apache.log4j.Logger; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.context.ApplicationContext; 11 import org.springframework.context.annotation.Configuration; 12 import org.springframework.scheduling.annotation.Scheduled; 13 import org.springframework.stereotype.Component; 14 import org.springframework.stereotype.Service; 15 16 import pojo.part.OrderDetailStatisticsPart; 17 import pojo.part.OrderStatisticsPart; 18 import service.statistics.DishSaleStatisticsOperator; 19 import service.statistics.OrderDetailStatisticsOperator; 20 import service.statistics.OrderStatisticsInterface; 21 import service.statistics.OrderStatisticsOperator; 22 import service.statistics.ShopSaleStatisticsOperator; 23 import service.statistics.WaitingTimeStatisticsOperator; 24 import tools.time.DateTimeTool; 25 26 package service.statistics; 27 import java.util.List; 28 29 import javax.transaction.Transactional; 30 31 import org.springframework.beans.factory.annotation.Autowired; 32 import org.springframework.stereotype.Service; 33 34 import pojo.part.OrderStatisticsPart; 35 import mapper.part.OrderStatisticsPartMapper; 36 37 /** 38 * @author zyr 39 * 按日期查询当天商城消费订单信息 40 */ 41 @Service("orderStatisticsInterface") 42 public class OrderStatisticsOperator implements OrderStatisticsInterface{ 43 @Autowired 44 private OrderStatisticsPartMapper orderStatisticsPartMapper; 45 @Override 46 public List<OrderStatisticsPart> selectOrdersInfoByToday(String today_date) { 47 return orderStatisticsPartMapper.selectOrdersInfoByToday(today_date); 48 } 49 }
最后在timer中:
1 where pay_time like ‘#{today_date,jdbcType = VARCHAR}%‘ 2 3 4 package service.timer; 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import mapper.DishSaleStatisticsMapper; 9 import mapper.part.OrderStatisticsPartMapper; 10 11 import org.apache.log4j.Logger; 12 import org.springframework.beans.factory.annotation.Autowired; 13 import org.springframework.context.ApplicationContext; 14 import org.springframework.context.annotation.Configuration; 15 import org.springframework.scheduling.annotation.Scheduled; 16 import org.springframework.stereotype.Component; 17 import org.springframework.stereotype.Service; 18 19 import pojo.part.OrderDetailStatisticsPart; 20 import pojo.part.OrderStatisticsPart; 21 import service.statistics.DishSaleStatisticsOperator; 22 import service.statistics.OrderDetailStatisticsOperator; 23 import service.statistics.OrderStatisticsInterface; 24 import service.statistics.OrderStatisticsOperator; 25 import service.statistics.ShopSaleStatisticsOperator; 26 import service.statistics.WaitingTimeStatisticsOperator; 27 import tools.time.DateTimeTool; 28 29 /** 30 * @author zyr 31 * 系统定时器,每一天定时运行一次,进行统计工作 32 */ 33 @Component 34 public class StatisticsTimer { 35 private static Logger logger = Logger.getLogger(StatisticsTimer.class); 36 //一次性查询所有的订单相关信息 37 private List<OrderStatisticsPart> orderStatisticsList = new ArrayList<OrderStatisticsPart>(); 38 //定时器测试 39 @Scheduled(cron="0/20 * * * * ? ") 40 public void statisticsTimerCycle(){ 41 System.out.println("============begining==============="); 42 //按时间查询该天商城的所用订单,返回订单的中需要用到的字段,实现统计功能 43 ApplicationContext appCtx = ApplicationContextUtil.getApplicationContext(); 44 logger.debug(appCtx); 45 if(appCtx==null) 46 { 47 logger.debug("ApplicationContext 为空"); 48 } 49 OrderStatisticsInterface orderStatisticsInterface=(OrderStatisticsInterface)ApplicationContextUtil.getBean("orderStatisticsInterface"); 50 System.out.println(orderStatisticsInterface); 51 System.out.println("===========暂无问题==============="); 52 orderStatisticsList= orderStatisticsInterface.selectOrdersInfoByToday(DateTimeTool.get_now_date()); 53 System.out.println("============end==============="); 54 }
结果为:
综上所述,这就是我这一天多完成的任务了,虽然遇到了困难,并且放大了困难,也确实学到了一些好的方法,算是为自己对springmvc和Spring的理解创造了条件,奠定了坚实的基础,对于组件扫描,以及定时器的操作有了更深刻的认识,希望能对读者有意义,帮助大家解决一定的问题,可以看到我陈述解决问题的时候,非常的细腻,不漏过任何的东西,这也是很多博客做不到的,只专注于一件事情,并且做到最好,让大家可以照着做一遍,而不是一知半解!