由于最近的一个项目需要定时抽取特定XML信息,然后保存到数据库,最后通过WebApi把手机端要使用的方法给暴露出来,所以去研究了一下Quartz.net。由于项目很小,我没用到Autofac,Repository模式,UOW这些东西,这个小项目中所涉及的知识点有:

1.Quartz.net配置

2.序列化XML信息到类对象中

3.AutoMapper做DomainModel和DTO之间的映射

4.WebApi允许多个Get方法的存在

下面我们一步一步的来进行说明。

让我们先来看看我们待处理的数据:http://price.agridoor.com.cn/nxt_price/uploads/2014/05/09/20140509_37.xml

从上图可以看到,这个xml数据有个根节点NXT_PRICE,并且根节点下面有很多个price子节点。那么如果我们想把这些xml数据反序列化到我们定义的类对象中,该怎么做呢?

其实很简单。

由于一个根节点NXT_PRICE下面有N个price子节点集合,所以我们创建如下的两个实体类来描述这种关系:

    [XmlRoot("NXT_PRICE")]
public class NxtPriceModel
{
public NxtPriceModel()
{
priceItems = new List<PriceItemModel>();
} [XmlElement("price")]
public List<PriceItemModel> priceItems { get; set; }
}

 

public class PriceItemModel
{
[XmlElement("seq")]
public int Seq { get; set; } [XmlElement("name")]
public string Name { get; set; } [XmlElement("type")]
public string Type { get; set; } [XmlElement("price")]
public decimal Price { get; set; } [XmlElement("unit")]
public string Unit { get; set; } [XmlElement("time")]
public string Time { get; set; } [XmlElement("first")]
public string First { get; set; } [XmlElement("second")]
public string Second { get; set; } [XmlElement("area")]
public string Area { get; set; }
}

这样两个实体类很简单,相信大家也看出了其中的包含关系。

然后如何反序列化到我们给定的实体类中呢? 这里使用XmlSerializer则是再合适不过的事情了。通过XmlSerializer对象,我们可以直接将对应的xml节点解释成实体类属性,并自动将数据保存到类中的集合对象中。

  WriteLog("=============================开始反序列化文件========================");
XmlSerializer ser = new XmlSerializer(typeof(NxtPriceModel));
ms.Position = 0;
var result = (NxtPriceModel)ser.Deserialize(ms);

通过上面的代码,我们就能成功的将路径中的xml信息下载并保存到类集合中,非常方便。这样,我们就完成了xml序列化成类对象的功能。

 

数据都已经保存到类对象中了,下一步就让我们来Consume它。

我们创建一个Asp.net MVC4项目,并利用Install-package quartz命令将其添加到项目中。然后在项目中添加一个MyJob类,继承自IJob对象:

 public class MyJob : IJob
{
private object obj = new object(); public void Execute(IJobExecutionContext context)
{
if (ShouldRun())
Run();
} private bool ShouldRun()
{
CommandPengEntities cpEntities = new CommandPengEntities();
try
{
string strStart = DateTime.Now.ToString("yyyy-MM-dd") + " 00:00:00";
string strEnd = DateTime.Now.ToString("yyyy-MM-dd") + " 23:59:59"; DateTime? dtStart = DateTime.Parse(strStart);
DateTime? dtEnd = DateTime.Parse(strEnd); var result = (from p in cpEntities.NxtPrice where p.Time >= dtStart && p.Time <= dtEnd select p).FirstOrDefault();
if (result == null)
{
WriteLog("当天数据不存在,准许插入新数据");
return true; //当天数据未被插入
}
WriteLog("当天数据存在,禁止插入新数据");
return false; //当天数据已经插入
}
catch (Exception ex)
{
WriteLog(ex.InnerException.Message);
return false;
}
finally
{
DisposeContext(cpEntities);
}
} private void Run()
{
string uri = "http://price.agridoor.com.cn/nxt_price/uploads/2014/05/09/20140509_37.xml";
WriteLog("=============================开始进行文件获取========================");
var request = HttpWebRequest.Create(uri);
IAsyncResult iasync = request.BeginGetResponse((iar) =>
{
var requestCallBack = (HttpWebRequest)iar.AsyncState;
var response = requestCallBack.EndGetResponse(iar);
WriteLog("=============================获取文件内容结束========================"); var stream = response.GetResponseStream(); byte[] buffer = null; //将stream保存到MemoryStream中
WriteLog("=============================保存内容到内存流========================");
using (MemoryStream ms = new MemoryStream())
{
int count = 0;
do
{
byte[] buf = new byte[1024];
count = stream.Read(buf, 0, 1024);
ms.Write(buf, 0, count);
}
while (stream.CanRead && count > 0);
buffer = ms.ToArray(); //string txt = Encoding.UTF8.GetString(buffer); //开始反序列化
WriteLog("=============================开始反序列化文件========================");
XmlSerializer ser = new XmlSerializer(typeof(NxtPriceModel));
ms.Position = 0;
var result = (NxtPriceModel)ser.Deserialize(ms); //检测是否为空
WriteLog("=============================检测文件是否为空========================");
if (result == null) return;
if (result.priceItems == null) return;
if (result.priceItems.Count == 0) return; var allItems = result.priceItems;
var totalRecords = result.priceItems.Count;
int batch = 200; //每200条批量提交一次
int totalExecuteCount = (totalRecords % batch == 0) ? (totalRecords / batch) : (totalRecords / batch + 1); //写入数据库
lock (obj)
{
PerformLogicInsert(totalRecords, totalExecuteCount, batch, allItems);
}
}
}, request);
} private void AddEntity(PriceItemModel pModel,CommandPengEntities cpEntities)
{
var itemShouldInsert = AutoMapper.Mapper.Map<NxtPrice>(pModel);
cpEntities.NxtPrice.AddObject(itemShouldInsert);
} private bool CommitEntity(CommandPengEntities cpEntities)
{
int rowAffected = cpEntities.SaveChanges();
if (rowAffected > 0)
return true;
return false;
} private void DisposeContext(CommandPengEntities cpEntities)
{
if (cpEntities != null)
cpEntities.Dispose();
} private void PerformLogicInsert(int totalRecords
, int totalExecuteCount
, int batch
, List<PriceItemModel> allItems)
{
WriteLog("=============================启用事务控制========================"); CommandPengEntities cpEntities = null;
try
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 3, 0)))
{
cpEntities = new CommandPengEntities(); for (int i = 0; i < totalExecuteCount; i++)
{
int remainRecords = totalRecords - i * batch;
int isLastBatch = remainRecords / batch;
int loopCounter = 0;
if (isLastBatch > 0) //不是最后一批数据
loopCounter = batch;
else //最后一批数据
loopCounter = remainRecords; for (int j = 0; j < loopCounter; j++)
{
var item = allItems[i * batch + j];
AddEntity(item, cpEntities);
} try
{
bool flag = CommitEntity(cpEntities);
if (flag) WriteLog(string.Format("第{0}批数据插入完毕,共计{1}条", i, loopCounter));
else WriteLog(string.Format("第{0}批数据插入失败", i));
}
catch (Exception ex)
{
WriteLog(ex.Message);
WriteLog(ex.InnerException.Message);
}
}
scope.Complete();
WriteLog("=============================事务提交成功========================");
}
}
finally
{
DisposeContext(cpEntities);
}
} private void WriteLog(string content)
{
string logFile = AppDomain.CurrentDomain.BaseDirectory + "\\log" + DateTime.Now.ToString("yyyyMMdd") + ".txt";
using (FileStream stream = new FileStream(logFile, FileMode.Append))
{
byte[] buffer = Encoding.UTF8.GetBytes(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + " " + content + Environment.NewLine);
stream.Write(buffer, 0, buffer.Length);
stream.Flush();
}
}
}

上面的代码主要是抽取数据,然后将数据写入到数据库中的操作行为.其中需要说到一点的就是Automapper的使用.

由于数据访问层,我直接使用的NxtPrice.edmx,所以会自动生成一个NxtPrice模型出来,这样当我们提交数据的时候,需要将对象进行转换:

  private void AddEntity(PriceItemModel pModel,CommandPengEntities cpEntities)
{
var itemShouldInsert = AutoMapper.Mapper.Map<NxtPrice>(pModel);
cpEntities.NxtPrice.AddObject(itemShouldInsert);
}

由于数据库插入对象时NxtPrice,而我们的数据集合对象是NxtPriceModel,所以这里需要将NxtPriceModel中的字段逐一赋值给NxtPrice对象,由于automapper能够提供类似的行为,所以我们采用automapper自动来进行.automapper会对比两个model的异同,只要是字段相同的话,都会自动进行映射.这样就省去了很多的操作步骤.

AutoMapper进行映射前,我们需要在Global.asax中配置一下,方可使用:

 private void ModelMapper()
{
//Model and DTO conversion
AutoMapper.Mapper.CreateMap<PriceItemModel, NxtPrice>();
AutoMapper.Mapper.CreateMap<NxtPrice,PriceItemModel>(); }

这样就达到我们的自动映射的要求了.

最后需要说明的是,我们的Job写完之后,需要定时运行,这个该如何做呢?

由于Quartz.net中,工作分为创建计划任务->创建工作内容->创建触发条件->启动 四个步骤,所以这里我们就按照这四个步骤来进行:

private void StartSchedular()
{
IScheduler scheduler = null;
// start up scheduler
// construct a factory
ISchedulerFactory factory = new StdSchedulerFactory();
// get a scheduler
scheduler = factory.GetScheduler();
// start the scheduler
scheduler.Start(); // create job
IJobDetail job = JobBuilder.Create<MyJob>()
.WithIdentity("MyJob", "MyJobs")
.Build(); // create trigger
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("MyJobTrigger", "MyJobs")
// start at 7:30 every day
.StartAt(DateBuilder.DateOf(7,30,0))
.WithSimpleSchedule(x => x.WithInterval(TimeSpan.FromMilliseconds(1)).WithRepeatCount(0))
.Build(); // Schedule the job using the job and trigger
scheduler.ScheduleJob(job, trigger);
}

注释说的很明白了, 其中scheduler对象就是创建的计划任务.

job对象则是我们刚刚新建的MyJob类及其要执行的内容.

trigger对象则是设置触发条件,这里我们设置为每天7:30开始,运行一次即可.

最后一句则是将工作内容和触发器连接起来,以便进行控制.

这样运行之后,我们运行程序,就能够看到系统正常运行了.

数据库的数据都填充以后,我们开始编写我们的webapi代码了.这里由于不是讲解的重点,我就不多说了,但是需要注意一点的是,webapi中可以通过设置路由来允许多个Get方法并存:

   config.Routes.MapHttpRoute(
name: "ApiByName",
routeTemplate: "api/{controller}/{action}/{name}",
defaults: null,
constraints: new { name = @"^[a-z]+$" }
);

这样当我们访问多个get方法的时候,就可以通过如下的方式访问了:

http://192.168.0.119/api/PriceItems/GetProductType/?cityName=新乡市

http://192.168.0.119/api/PriceItems/GetProvince/

最后需要说明的是,由于WebApi默认返回JSON格式,所以如果你想接受XML格式的内容,服务端是不需要做任何设置的。你只需要在客户端加上Accept:application/xml即可请求到xml的数据,非常方便。

百度网盘

腾讯网盘

Quartz.net打造信息抽取器的更多相关文章

  1. trie树信息抽取之中文数字抽取

    这一章讲一下利用trie树对中文数字抽取的算法.trie树是一个非常有用的数据结构,可以应用于大部分文本信息抽取/转换之中,后续会开一个系列,对我在实践中摸索出来的各种抽取算法讲开来.比如中文时间抽取 ...

  2. 【开源】C#信息抽取系统【招募C#队友】

    FDDC2018金融算法挑战赛02-A股上市公司公告信息抽取 更新时间 2018年7月11日 By 带着兔子去旅行 信息抽取是NLP里的一个实用内容.该工具的目标是打造一个泛用的自动信息抽取工具.使得 ...

  3. 新闻网页通用抽取器GNEv0.04版更新,支持提取正文图片与源代码

    GeneralNewsExtractor以下简称GNE是一个新闻网页通用抽取器,能够在不指定任何抽取规则的情况下,把新闻网站的正文提取出来. 我们来看一下它的基本使用方法. 安装 GNE 使用 pip ...

  4. Atitit.Atiposter 发帖机 信息发布器 v7 q516

    Atitit.Atiposter 发帖机 信息发布器 v7 q516 V7 jetty 版本 基本访问改为web版. 这样发布调试 V1  初步实现sina csdn cnblogs V2  实现qz ...

  5. Scala正则和抽取器:解析方法参数

    在<正则表达式基础知识>中概括了正则表达式的基础知识, 本文讲解如何使用正则表达式解析方法参数,从而可以根据 DAO 自动生成 Service. 在做 Java 项目时,常常要根据 DAO ...

  6. Java中正则表达式、模式匹配与信息抽取

    引言 记得几年前在做网页爬虫后的信息抽取时,针对网页源码中隐藏的要提取的信息,比如评论.用户信息等属性信息,直接利用HtmlParser得到.如此做倒是简单,不过利用的是网页的规范的tag标记.其实j ...

  7. Mp3tag(MP3文件信息修改器) V2.79a 多语绿色版

    软件名称: Mp3tag(MP3文件信息修改器) 软件语言: 多国语言 授权方式: 免费软件 运行环境: Win 32位/64位 软件大小: 3.0MB 图片预览: 软件简介: Mp3Tag 是一款m ...

  8. 窗口信息获取器 Spy4Win v0.20b 中文绿色版

    软件名称:窗口信息获取器 Spy4Win v0.20b 中文绿色版软件类别:国产软件运行环境:Windows XP软件语言:简体中文授权方式:免费版软件大小:1.67 MB软件等级:整理时间:2012 ...

  9. ACL2016信息抽取与知识图谱相关论文掠影

    实体关系推理与知识图谱补全 Unsupervised Person Slot Filling based on Graph Mining 作者:Dian Yu, Heng Ji 机构:Computer ...

随机推荐

  1. OC正则表达式的使用

    OC中一般正则表达式的使用方法为2步 1.创建一个正则表达式对象 2.利用正则表达式来测试对应的字符串 例如 NSString *checkString = @"a34sd231" ...

  2. iOS 使用SDwebImage缓存图片并在断网时候显示

     [_loadImageView setShowActivityIndicatorView:YES];    [_loadImageView setIndicatorStyle:UIActivityI ...

  3. 基于AFNetWorking 3.0封装网络请求数据的类

    对于使用 AFNetworking 的朋友来说,很多朋友都是直接调用 AFNetworking的 API ,这样不太好,无法做到全工程统一配置. 最好的方式就是对网络层再封装一层,全工程不允许直接使用 ...

  4. MySQL 强制操作以及order by 使用

    我们以MySQL中常用的hint来进行详细的解析,如果你是经常使用Oracle的朋友可能知道,Oracle的hincvt功能种类很多,对于优化sql语句提供了很多方法. 同样,在MySQL里,也有类似 ...

  5. Windows Server 2012 R2下通过80端口访问Odoo ERP

    背景 Odoo 9.0系统,安装于Windows Server 2012R2,同时与IIS并存.Odoo自带web服务器,使用端口8069.因客户需要用80端口访问,因此需要进一步设置,且8069端口 ...

  6. OSX下VirtualBox安装CentOS

    1.OSX上下载安装VirtualBox 2.新建虚拟机(所有选项默认即可) 3.启动虚拟机,选择CentOS安装镜像 CentOS-6.7-x86_64-minimal.iso 此处下载的是最小镜像 ...

  7. radclient安装记录

    下载地址: http://freeradius.org/getting.html 选择:1.1.5版本 wget -c ftp://ftp.freeradius.org/pub/freeradius/ ...

  8. NSThread基础使用

    1.创建和启动线程   一个NSThread对象就代表一条线程;   创建,启动线程 NSThread *thread = [[NSThread alloc] initWithTarget:self ...

  9. [转]Google Cloud Messaging: Overview

    本文转自:https://developers.google.com/cloud-messaging/gcm

  10. zookeeper适用场景:如何竞选Master及代码实现

    问题导读:1.如何利用zookeeper保证集群Master可用性和唯一性?2.zookeeper竞选Master包含哪些过程?3.zookeeper竞选Master机制利用了zk哪些特性? 在zoo ...