题外话:说好的要时不时的把自己在编程方面所学习的点点滴滴记录下来,但是却迟迟没有坚持下来。自己的编程技术的提升,一定要有知识沉淀的过程,希望自己能够把写技术博客这件事一直坚持下去,成为更好的自己,也希望大家都能够为了自己心中的目标坚持去做一件事!
项目背景:最近公司的项目中有这样一个需求,希望我完成一个每天定时向一个webservice接口推送数据库的一些数据的功能,推送的数据是xml格式的。
1.定时器Timer的编写
对于这个需求,第一个需要解决的就是如何完成定时执行任务?这里我用了java的定时器Timer来实现这个功能。这里我编写了两个类,DataListener类和DataTask类。前者是该定时器的监听类,用来设置定时任务执行的具体时间以及开启该定时任务;后者是执行定时任务的具体操作。
DataListener代码如下:
public class DataListener extends HttpServlet{
private static final long serialVersionUID = 1L;
private Timer timer = null;
private DataTask datatask = null;
public void init(){
datatask = new DataTask();
timer = new Timer(true);
//设定推送数据的时间,该定时任务在早上8:00执行(24小时格式)
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
timer.schedule(timetask, calendar.getTime());
}
}
该类继承了HttpServlet,主要是通过web项目启动时,启动该servlet定时任务。init()方法是HttpServlet启动时需要初始化的方法,所以定时器初始化的配置就写在该方法里。在web.xml文件中还需要配置该servlet启动信息,如下所示。
<servlet>
<servlet-name>DataListener</servlet-name>
<servlet-class>
com.xxx.xxx.xxx.DataListener
</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
接下来,需要编写执行具体任务的DataTask类,代码如下。
public class DataTask extends TimerTask {
private JxfpService jxfpService;
private XmlParser xmlParser= new XmlParser();
//定时执行部分,查找数据库所需要的数据
@Override
public void run() {
//通过ApplicationContext加载Spring配置文件完成service类的注入
ApplicationContext beanFactory= new ClassPathXmlApplicationContext("classpath:spring-*.xml");
jxfpService = (XxxxService) beanFactory.getBean("xxxxService");
String dataXml = "";
try {
List<xxxx> list =xxxService.xxxxQuery();
dataXml = xmlParser.pushDataToXml(list);
System.out.println("自动传输的数据为:"+dataXml);
} catch (Exception e) {
e.printStackTrace();
}
pushData(dataXml);
}
}
DataTask类继承了TimerTask,在run()方法中需要补充该定时任务的具体操作内容。我在该任务里边主要编写了访问数据库的service类,还有将数据格式转换成xml格式的类。最后,将转换成的xml格式的数据推送出去。
数据访问使用了springmvc+mybatis的访问方式,整个项目的数据访问都是注解的形式完成的类的注入,但是我使用这种方式service类总是加载不了,报NullPointException,所以就使用了ClassPathXmlApplicationContext来进行类的注入。
2.使用HttpClient完成xml格式数据推送
xml格式的数据推送,这里采用了HttpClient类进行soap协议的webservice请求,然后把数据传送过去,具体的代码如下。
该方法是编写在DataTask类中的。
// 向webservice发送请求,并推送数据库的数据
public void pushData(String data) {
String soapRequestData = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:jx=\"http://jx.xxxx.com\">"
+ "<soapenv:Header/>"
+ "<soapenv:Body>"
+ "<jx:pushData>"
+ "<param>"+data+"</param>"
+ "</jx:pushData>"
+ "</soapenv:Body>" + "</soapenv:Envelope>";
try {
PostMethod postMethod = new PostMethod(
"http://localhost:8080/xxxx/service/JxWebservice?wsdl");
// 然后把Soap请求数据添加到PostMethod中
byte[] b = soapRequestData.getBytes("utf-8");
InputStream is = new ByteArrayInputStream(b, 0, b.length);
RequestEntity re = new InputStreamRequestEntity(is, b.length,"application/soap+xml; charset=utf-8");
postMethod.setRequestEntity(re);
// 最后生成一个HttpClient对象,并发出postMethod请求
HttpClient httpClient = new HttpClient();
int statusCode;
statusCode = httpClient.executeMethod(postMethod);
if (statusCode == 200) {
System.out.println("数据推送成功!");
String soapResponseData = postMethod.getResponseBodyAsString();
System.out.println("返回的报文为:" + soapResponseData);
} else {
System.out.println("接口访问失败!错误代码:" + statusCode);
}
} catch (IOException e) {
e.printStackTrace();
}
}
这个功能做完以后,有几点疑问,希望和大家共享一下,如果我的博客有幸被你看到,如果能解决我的这些问题,我将不胜感激。
1.为什么我在定时任务中,使用@Resource注解或者@Autowired注解进行service类注入时,会报空指针的错误?
2.向接口推送xml数据的方式还有其他的方法吗?我在网上查的一种方式,是使用axis来传输,但是我试了没有成功。
最后,由于我的技术水平有限,博客中使用的术语或者代码有问题的,如果您看见了,可以给我提意见。