chenwen 3 years ago
commit
61cfad0cdd
37 changed files with 2945 additions and 0 deletions
  1. 8 0
      .classpath
  2. 1 0
      .gitignore
  3. 23 0
      .project
  4. 5 0
      .settings/org.eclipse.jdt.core.prefs
  5. 7 0
      .settings/org.maven.ide.eclipse.prefs
  6. 168 0
      pom.xml
  7. 56 0
      src/main/java/com/hb/proj/model/OilCurrentDTO.java
  8. 164 0
      src/main/java/com/hb/proj/model/QuotaConfig.java
  9. 69 0
      src/main/java/com/hb/proj/oil/controller/OutSettingController.java
  10. 133 0
      src/main/java/com/hb/proj/oil/service/OilService.java
  11. 34 0
      src/main/java/com/hb/proj/oil/service/OtherConfigService.java
  12. 57 0
      src/main/java/com/hb/proj/oil/service/ScheduledReportOil.java
  13. 115 0
      src/main/java/com/hb/proj/oil/service/ScheduledTaskOilQuery.java
  14. 345 0
      src/main/java/com/hb/proj/server/ByteUtil.java
  15. 82 0
      src/main/java/com/hb/proj/server/MeterBindBO.java
  16. 99 0
      src/main/java/com/hb/proj/server/OilBO.java
  17. 87 0
      src/main/java/com/hb/proj/server/OilBoxBO.java
  18. 164 0
      src/main/java/com/hb/proj/server/OilChangeBO.java
  19. 47 0
      src/main/java/com/hb/proj/server/OilCheckTask.java
  20. 182 0
      src/main/java/com/hb/proj/server/OilChecker.java
  21. 60 0
      src/main/java/com/hb/proj/server/OilDetecter.java
  22. 168 0
      src/main/java/com/hb/proj/server/OilMonitorServer.java
  23. 179 0
      src/main/java/com/hb/proj/server/OilParseTask.java
  24. 31 0
      src/main/java/com/hb/proj/server/ProcessWaveTask.java
  25. 20 0
      src/main/java/com/hb/proj/server/TaskExecutor.java
  26. 120 0
      src/main/java/com/hb/proj/server/VolumeCalibrater.java
  27. 8 0
      src/main/java/com/hb/proj/utils/CodeConstant.java
  28. 97 0
      src/main/java/com/hb/proj/utils/JsonOutUtils.java
  29. 96 0
      src/main/java/com/hb/proj/utils/OkhttpUtils.java
  30. 21 0
      src/main/java/com/hb/proj/utils/RequestUtils.java
  31. 47 0
      src/main/java/com/hb/proj/utils/WebAppListener.java
  32. 36 0
      src/main/java/logback.xml
  33. 4 0
      src/main/resources/config/sys_config.properties
  34. 92 0
      src/main/webapp/WEB-INF/config/applicationContext.xml
  35. 37 0
      src/main/webapp/WEB-INF/config/spring-servlet.xml
  36. 72 0
      src/main/webapp/WEB-INF/web.xml
  37. 11 0
      src/main/webapp/default.html

+ 8 - 0
.classpath

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+target

+ 23 - 0
.project

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>lhLoggingOilMonitor</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.maven.ide.eclipse.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.maven.ide.eclipse.maven2Nature</nature>
+	</natures>
+</projectDescription>

+ 5 - 0
.settings/org.eclipse.jdt.core.prefs

@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.7

+ 7 - 0
.settings/org.maven.ide.eclipse.prefs

@@ -0,0 +1,7 @@
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1

+ 168 - 0
pom.xml

@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>com.hb</groupId>
+  <artifactId>lhLoggingOilMonitor</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>war</packaging>
+
+  <name>lhLoggingOilMonitor Maven Webapp</name>
+  <!-- FIXME change it to the project's website -->
+  <url>http://www.example.com</url>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <maven.compiler.source>1.7</maven.compiler.source>
+    <maven.compiler.target>1.7</maven.compiler.target>
+  </properties>
+
+  <dependencies>
+      <dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>2.5</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>javax.servlet.jsp</groupId>
+			<artifactId>jsp-api</artifactId>
+			<version>2.1</version>
+			<scope>provided</scope>
+		</dependency>
+		
+       <dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-webmvc</artifactId>
+			<version>4.3.21.RELEASE</version>
+		</dependency>
+		
+			<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-tx</artifactId>
+			<version>4.3.21.RELEASE</version>
+		</dependency>
+
+		<dependency>
+	      <groupId>commons-dbcp</groupId>
+	      <artifactId>commons-dbcp</artifactId>
+	      <version>1.4</version>
+       </dependency>
+
+
+		<dependency>
+			<groupId>org.aspectj</groupId>
+			<artifactId>aspectjweaver</artifactId>
+			<version>1.7.1</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-jdbc</artifactId>
+			<version>4.3.21.RELEASE</version>
+		</dependency>
+		
+		<dependency>
+			<groupId>commons-beanutils</groupId>
+			<artifactId>commons-beanutils</artifactId>
+			<version>1.8.3</version>
+		</dependency>
+		
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+			<version>1.7.2</version>
+		</dependency>
+
+		<dependency>
+			<groupId>ch.qos.logback</groupId>
+			<artifactId>logback-core</artifactId>
+			<version>1.0.7</version>
+		</dependency>
+
+		<dependency>
+			<groupId>ch.qos.logback</groupId>
+			<artifactId>logback-classic</artifactId>
+			<version>1.0.7</version>
+		</dependency>
+		
+		<dependency>
+		    <groupId>com.fasterxml.jackson.core</groupId>
+		    <artifactId>jackson-databind</artifactId>
+		    <version>2.9.2</version>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-lang</groupId>
+			<artifactId>commons-lang</artifactId>
+			<version>2.6</version>
+		</dependency>
+		
+		<dependency>
+		    <groupId>com.alibaba</groupId>
+		    <artifactId>fastjson</artifactId>
+		    <version>1.2.45</version>
+		</dependency>
+		
+		<dependency>
+	         <groupId>com.hb</groupId>
+	         <artifactId>xframework</artifactId>
+	         <version>4.2</version>
+        </dependency>
+      
+      
+		<dependency>
+		    <groupId>mysql</groupId>
+		    <artifactId>mysql-connector-java</artifactId>
+		    <version>5.1.25</version>
+		</dependency>
+		
+		<dependency>
+		    <groupId>com.squareup.okhttp3</groupId>
+		    <artifactId>okhttp</artifactId>
+		    <version>3.10.0</version>
+	    </dependency>
+	  
+		<!--后期改用netty实现 -->
+		<!-- <dependency>
+		    <groupId>io.netty</groupId>
+		    <artifactId>netty-all</artifactId>
+		    <version>4.1.53.Final</version>
+		</dependency> -->
+  </dependencies>
+
+  <build>
+    <finalName>lhLoggingOilMonitor</finalName>
+    <plugins>
+	  		<plugin>
+				<groupId>org.apache.tomcat.maven</groupId>
+				<artifactId>tomcat7-maven-plugin</artifactId>
+				<version>2.2</version>
+				<configuration>
+					<url>http://localhost:8080/manager/text</url>
+					<path>/oil</path>
+					<uriEncoding>UTF-8</uriEncoding>
+					<server>tomcat</server>
+				</configuration>
+			</plugin>
+			<plugin>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3.2</version> 
+				<configuration>
+					<encoding>utf8</encoding>
+				</configuration>
+			</plugin>
+			<plugin>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.4</version>
+				<configuration>
+					<includeEmptyDirectories>true</includeEmptyDirectories>
+				</configuration>
+			</plugin>
+			
+		</plugins>
+  </build>
+</project>

+ 56 - 0
src/main/java/com/hb/proj/model/OilCurrentDTO.java

@@ -0,0 +1,56 @@
+package com.hb.proj.model;
+
+import java.util.Date;
+
+public class OilCurrentDTO {
+
+	private String termSn;
+	
+	private String vin;
+	
+	private Date reportTime;
+	
+	private Double curOil;
+	
+	private Double realValue;
+
+	public String getTermSn() {
+		return termSn;
+	}
+
+	public void setTermSn(String termSn) {
+		this.termSn = termSn;
+	}
+
+	public String getVin() {
+		return vin;
+	}
+
+	public void setVin(String vin) {
+		this.vin = vin;
+	}
+
+	public Date getReportTime() {
+		return reportTime;
+	}
+
+	public void setReportTime(Date reportTime) {
+		this.reportTime = reportTime;
+	}
+
+	public Double getCurOil() {
+		return curOil;
+	}
+
+	public void setCurOil(Double curOil) {
+		this.curOil = curOil;
+	}
+
+	public Double getRealValue() {
+		return realValue;
+	}
+
+	public void setRealValue(Double realValue) {
+		this.realValue = realValue;
+	}
+}

+ 164 - 0
src/main/java/com/hb/proj/model/QuotaConfig.java

@@ -0,0 +1,164 @@
+package com.hb.proj.model;
+/**
+ * 定额其他配置项(油品折算系数,取暖月份)
+ * @author hb
+ *
+ */
+public class QuotaConfig {
+
+	private double oilRatio=1;   //默认为92#汽油 升-公斤
+	
+	private double oilRatio95=1; //95#汽油折算系数 升-公斤
+	
+	private double coilRatio=1;	 //柴油折算系数 升-公斤
+	
+	private double oilCoalRatio=1;  //汽油折算标准煤系数  吨-吨
+	
+	private double coilCoalRatio=1;  //柴油折算标准煤系数  吨-吨
+	
+	private double powerCoalRatio=1;  //电能折算标准煤系数  万千瓦时-吨
+	
+	private double ygasCoalRatio=1;  //液化气折算标准煤系数  吨-吨
+	
+	private double ngasCoalRatio=1;  //天然气折算标准煤系数  万立方米-吨
+	
+	private Integer rptStart=null;  //数据上报期限本月几号开始(含),空表示不做限制
+	
+	private Integer rptEnd=null;   //数据上报期限下月几号截止(不含),空表示不做限制
+	
+	private String  quotaRiseMonths;   //百公里定额上浮月份,整数,半角英文分隔
+	
+	private double quotaRiseCount;    //百公里定额上浮量
+	
+	private String quotaRiseDeviceNames;  //百公里定额上浮 车型
+	
+	private int[]  warmMonths=null;
+	
+	private Integer monthSplitDay; //统计月份划分日
+
+	public double getOilRatio() {
+		return oilRatio;
+	}
+
+	public void setOilRatio(double oilRatio) {
+		this.oilRatio = oilRatio;
+	}
+
+	public double getCoilRatio() {
+		return coilRatio;
+	}
+
+	public void setCoilRatio(double coilRatio) {
+		this.coilRatio = coilRatio;
+	}
+
+	public int[] getWarmMonths() {
+		return warmMonths;
+	}
+
+	public void setWarmMonths(int[] warmMonths) {
+		this.warmMonths = warmMonths;
+	}
+
+	public double getOilCoalRatio() {
+		return oilCoalRatio;
+	}
+
+	public void setOilCoalRatio(double oilCoalRatio) {
+		this.oilCoalRatio = oilCoalRatio;
+	}
+
+	public double getCoilCoalRatio() {
+		return coilCoalRatio;
+	}
+
+	public void setCoilCoalRatio(double coilCoalRatio) {
+		this.coilCoalRatio = coilCoalRatio;
+	}
+
+	public double getPowerCoalRatio() {
+		return powerCoalRatio;
+	}
+
+	public void setPowerCoalRatio(double powerCoalRatio) {
+		this.powerCoalRatio = powerCoalRatio;
+	}
+
+	public double getYgasCoalRatio() {
+		return ygasCoalRatio;
+	}
+
+	public void setYgasCoalRatio(double ygasCoalRatio) {
+		this.ygasCoalRatio = ygasCoalRatio;
+	}
+
+	public double getNgasCoalRatio() {
+		return ngasCoalRatio;
+	}
+
+	public void setNgasCoalRatio(double ngasCoalRatio) {
+		this.ngasCoalRatio = ngasCoalRatio;
+	}
+
+	public double getOilRatio95() {
+		return oilRatio95;
+	}
+
+	public void setOilRatio95(double oilRatio95) {
+		this.oilRatio95 = oilRatio95;
+	}
+
+	public Integer getRptStart() {
+		return rptStart;
+	}
+
+	public void setRptStart(Integer rptStart) {
+		this.rptStart = rptStart;
+	}
+
+	public Integer getRptEnd() {
+		return rptEnd;
+	}
+
+	public void setRptEnd(Integer rptEnd) {
+		this.rptEnd = rptEnd;
+	}
+
+	
+
+	public double getQuotaRiseCount() {
+		return quotaRiseCount;
+	}
+
+	public void setQuotaRiseCount(double quotaRiseCount) {
+		this.quotaRiseCount = quotaRiseCount;
+	}
+
+	public String getQuotaRiseMonths() {
+		return quotaRiseMonths;
+	}
+
+	public void setQuotaRiseMonths(String quotaRiseMonths) {
+		this.quotaRiseMonths = quotaRiseMonths;
+	}
+
+	public String getQuotaRiseDeviceNames() {
+		return quotaRiseDeviceNames;
+	}
+
+	public void setQuotaRiseDeviceNames(String quotaRiseDeviceNames) {
+		this.quotaRiseDeviceNames = quotaRiseDeviceNames;
+	}
+
+	public Integer getMonthSplitDay() {
+		return monthSplitDay;
+	}
+
+	public void setMonthSplitDay(Integer monthSplitDay) {
+		this.monthSplitDay = monthSplitDay!=null?monthSplitDay:16;
+	}
+
+	
+
+	
+}

+ 69 - 0
src/main/java/com/hb/proj/oil/controller/OutSettingController.java

@@ -0,0 +1,69 @@
+package com.hb.proj.oil.controller;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import com.hb.proj.server.OilChecker;
+import com.hb.proj.server.VolumeCalibrater;
+import com.hb.proj.utils.JsonOutUtils;
+/**
+ * 提供外部设置接口
+ * @author hb
+ *
+ */
+@Controller
+@RequestMapping("/**/out")
+public class OutSettingController {
+
+	/**
+	 * 重新加载标定
+	 * @param response
+	 */
+	@RequestMapping("/reloadCalibrater")
+	public void reloadCalibrater(HttpServletResponse response){
+		try{
+			VolumeCalibrater.init();
+			JsonOutUtils.returnOk(response);
+		}
+		catch(Exception e){
+			e.printStackTrace();
+			JsonOutUtils.returnError(response, "重加载标定失败");
+		}
+	}
+	
+	@RequestMapping("/loadCalibrater")
+	public void loadCalibrater(HttpServletResponse response){
+		try{
+			Map<String,Object> map=new HashMap<String,Object>();
+			map.put("meters",VolumeCalibrater.getMeters());
+			//map.put("boxs",VolumeCalibrater.getBoxs());
+			JsonOutUtils.returnOkWithData(response, map);
+		}
+		catch(Exception e){
+			e.printStackTrace();
+			JsonOutUtils.returnError(response, "查询标定失败");
+		}
+	}
+	
+	/**
+	 * 重新加载其它设置
+	 * @param response
+	 */
+	@RequestMapping("/reloadOtherConfig")
+	public void reloadOtherConfig(HttpServletResponse response){
+		try{
+			OilChecker.initMonthSplitDay();
+			JsonOutUtils.returnOk(response);
+		}
+		catch(Exception e){
+			e.printStackTrace();
+			JsonOutUtils.returnError(response, "重新加载其它设置失败");
+		}
+	}
+
+}

+ 133 - 0
src/main/java/com/hb/proj/oil/service/OilService.java

@@ -0,0 +1,133 @@
+package com.hb.proj.oil.service;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import com.hb.proj.server.MeterBindBO;
+import com.hb.proj.server.OilBO;
+import com.hb.proj.server.OilBoxBO;
+import com.hb.proj.server.OilChangeBO;
+import com.hb.proj.server.OilChecker;
+import com.hb.xframework.dao.core.SpringJdbcDAO;
+
+@Service
+public class OilService {
+
+	@Autowired
+	private SpringJdbcDAO  dao;
+	
+	
+	/**
+	 * 删除已入库的杂波数据
+	 * @param dtuNum
+	 * @param startTime
+	 * @param endTime
+	 */
+	public void deleteWave(String dtuNum,Date startTime,Date endTime){
+		String sql="delete from t_oil_history_2 where dtu_num=? and data_time between ? and ?";
+		dao.getJdbcTemplate().update(sql,startTime,endTime);
+	}
+	
+	
+	public void saveCurrentData(OilBO oil){
+		if(oil==null){
+			return;
+		}
+		//当前库
+		String sql="update t_oil_current set liquid_str=?,liquidrt_str=?,oil_volume=?,data_time=? where dtu_num=?";
+		int num=dao.getJdbcTemplate().update(sql, oil.getLiquidStr(),oil.getLiquidrtStr(),oil.getOilVolume(),oil.getDataTime(),oil.getDtuNum());
+		if(num==0){
+			sql="insert into t_oil_current(dtu_num,liquid_str,liquidrt_str,oil_volume,data_time,car_id) values(?,?,?,?,?,?)";
+			dao.getJdbcTemplate().update(sql,oil.getDtuNum(),oil.getLiquidStr(),oil.getLiquidrtStr(),oil.getOilVolume(),oil.getDataTime(),oil.getCarId());
+		}
+		
+	}
+	
+	/**
+	 * 采集的油量数据入库,未直接存储车辆信息,要避免更换设备(设备编号)后,车辆历史油耗数据无法查找
+	 * @param oil
+	 */
+	public void saveOilData(OilBO oil){
+		if(oil==null){
+			return;
+		}
+		
+		
+		//历史库
+		String sql="insert into t_oil_history_2(dtu_num,liquid_height,oil_volume,data_time,mount_id,rt_height) values(?,?,?,?,?,?)";
+		dao.getJdbcTemplate().update(sql,oil.getDtuNum(),oil.getLiquidHeight(),oil.getOilVolume(),oil.getDataTime(),oil.getMountId(),oil.getRtHeight());
+		
+		//统计库
+		if(StringUtils.isEmpty(oil.getCarId())){  //采集数据已经收到但标定数据还未准备好,避免导致插入很多carId=null的记录。该情况概率小还是要处理
+			return;
+		}
+		Calendar ca=Calendar.getInstance();
+		ca.setTime(oil.getDataTime());
+		String rptMonth=null;
+		if(ca.get(Calendar.DAY_OF_MONTH)<OilChecker.MONTH_SPLIT_DAY){ //小于指定日期算当月,否则算下月
+			rptMonth=String.format("%s-%02d", ca.get(Calendar.YEAR),ca.get(Calendar.MONTH)+1);
+		}
+		else{
+			ca.add(Calendar.MONTH, 1);
+			rptMonth=String.format("%s-%02d", ca.get(Calendar.YEAR),ca.get(Calendar.MONTH)+1);
+		}
+		
+		sql="update t_oil_monitor_report set end_volume=?,modify_time=? where  rpt_month=? and mount_id=?";
+		int num2=dao.getJdbcTemplate().update(sql,oil.getOilVolume(),new Date(),rptMonth,oil.getMountId());
+		if(num2==0){//还没开始统计数据
+			sql="insert into t_oil_monitor_report(car_id,rpt_month,start_volume,mount_id,modify_time) values(?,?,?,?,?)";
+			dao.getJdbcTemplate().update(sql,oil.getCarId(),rptMonth,oil.getOilVolume(),oil.getMountId(),new Date());
+		}
+	}
+	
+	public List<OilBO> loadLastOilData(){
+		String sql="select * from t_oil_current";
+		return dao.queryForListPojo(sql, OilBO.class);
+	}
+	
+	/**
+	 * 油箱规格数据
+	 * @return
+	 */
+	public Map<String,OilBoxBO>  loadOilBox(){
+		String sql="select * from t_oil_box";
+		List<OilBoxBO>  datas=dao.queryForListPojo(sql, OilBoxBO.class);
+		if(datas==null||datas.size()==0){
+			return null;
+		}
+		Map<String,OilBoxBO> mapping=new HashMap<String,OilBoxBO>(datas.size());
+		for(OilBoxBO box : datas){
+			mapping.put(box.getRecordId(), box);
+		}
+		return mapping;
+	}
+	
+	/**
+	 * 油量计与油箱关联关系
+	 * @return
+	 */
+	public List<MeterBindBO> loadMeterBox(){
+		return dao.queryForListPojo("select record_id as mount_id,belong_car_id as car_id,meter_num,transfer_type,box_id,volume_ratio from t_oil_meter", MeterBindBO.class);
+	}
+	
+	/**
+	 * 保存油量变化数据:加油、异常消耗
+	 * @param changeBO
+	 */
+	public void saveOilChangeData(OilChangeBO changeBO){
+		String sql="insert into t_oil_change(car_id,dtu_num,diff_volume,diff_h,data_time,pre_data_time,change_type,mount_id) values(?,?,?,?,?,?,?,?)";
+		//String sql="insert into t_oil_change(car_id,dtu_num,diff_volume,data_time,pre_data_time,change_type) values(?,?,?,?,?,?)";
+		/*if(changeBO.isWaveFilter()){ //滤过波的数据
+			sql="insert into t_oil_change_filter(car_id,dtu_num,diff_volume,data_time,pre_data_time,change_type) values(?,?,?,?,?,?)";
+		}*/
+		dao.getJdbcTemplate().update(sql,changeBO.getCarId(),changeBO.getDtuNum(),changeBO.getDiffVolume(),changeBO.getDiffH(),changeBO.getDataTime(),changeBO.getPreDataTime(),changeBO.getChangeType(),changeBO.getMountId());
+	}
+
+}

+ 34 - 0
src/main/java/com/hb/proj/oil/service/OtherConfigService.java

@@ -0,0 +1,34 @@
+package com.hb.proj.oil.service;
+
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.alibaba.fastjson.JSON;
+import com.hb.proj.model.QuotaConfig;
+import com.hb.proj.utils.CodeConstant;
+import com.hb.xframework.dao.core.SpringJdbcDAO;
+
+/**
+ * 折算系数等其它设置
+ * @author cwen
+ *
+ */
+@Service
+public class OtherConfigService {
+
+	@Autowired
+	private SpringJdbcDAO  dao;
+	
+	public QuotaConfig load(){
+		Map<String,Object>  rst=dao.queryForSingleMap("select spare1 from t_sort_code where code_id=?", CodeConstant.SORT_OTHER_CONFIG);
+		if(rst==null||StringUtils.isBlank((String)rst.get("spare1"))){
+			return null;
+		}
+		return JSON.parseObject((String)rst.get("spare1"), QuotaConfig.class);
+	}
+	
+	
+}

+ 57 - 0
src/main/java/com/hb/proj/oil/service/ScheduledReportOil.java

@@ -0,0 +1,57 @@
+package com.hb.proj.oil.service;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.hb.xframework.dao.core.SpringJdbcDAO;
+import com.hb.xframework.util.DateUtil;
+/**
+ * 定时根据油量监测数据统计加油量、耗油量.月份的开始,截止油量由采集程序写入
+ * @author hb
+ *
+ */
+@Service
+public class ScheduledReportOil {
+
+	public static Logger logger=LoggerFactory.getLogger(ScheduledReportOil.class);
+
+	@Autowired
+	private SpringJdbcDAO  dao;
+	
+	
+	public void createOilReport(){
+		logger.debug("开始统计月加油、耗油");
+		Calendar  ca=Calendar.getInstance(); //定时到每月16号零点
+		String rptMonth=DateUtil.format(ca.getTime(), "yyyy-MM");
+		String et=DateUtil.format(ca.getTime(), "yyyy-MM-dd HH:mm:ss");
+		ca.add(Calendar.MONTH, -1);
+		String st=DateUtil.format(ca.getTime(), "yyyy-MM-dd HH:mm:ss");
+		String sql="select car_id,sum(diff_volume) add_sum from t_oil_change c where change_type='add' and  DATE_FORMAT(data_time,'%Y-%m-%d %T') between ? and ? group by car_id";
+	    List<Map<String,Object>> rst=dao.queryForListMap(sql, st,et);
+	    if(rst==null||rst.size()==0){
+	    	logger.debug("统计月加油、耗油,未找到数据"+st+" "+et);
+	    	return ;
+	    }
+	    List<Object[]> batchParams = new ArrayList<Object[]>(rst.size());
+	    List<Object> params=null;
+		for(Map<String,Object> itm : rst){
+			params=new ArrayList<Object>();
+			params.add(itm.get("addSum"));
+			params.add(itm.get("addSum"));
+			params.add(itm.get("carId"));
+			params.add(rptMonth);
+			batchParams.add(params.toArray());
+		}
+		//入库油量监测统计
+		sql="update t_oil_monitor_report set add_volume=?,cost_volume=IFNULL(start_volume,0)-IFNULL(end_volume,0)+IFNULL(?,0) where car_id=? and  rpt_month=?";
+		int[] num=dao.getJdbcTemplate().batchUpdate(sql, batchParams);	
+		logger.debug("统计月加油、耗油,更新记录"+num);
+	}
+}

+ 115 - 0
src/main/java/com/hb/proj/oil/service/ScheduledTaskOilQuery.java

@@ -0,0 +1,115 @@
+package com.hb.proj.oil.service;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.hb.proj.model.OilCurrentDTO;
+import com.hb.proj.server.OilBO;
+import com.hb.proj.server.OilChecker;
+import com.hb.proj.server.VolumeCalibrater;
+import com.hb.proj.utils.OkhttpUtils;
+import com.hb.xframework.dao.core.SpringJdbcDAO;
+import com.hb.xframework.util.DateUtil;
+import com.hb.xframework.util.SysConfigUtil;
+
+/**
+ * 定时获取车辆油量数据---从宏电平台获取(3318设备)
+ * @author hb
+ *
+ */
+@Service
+public class ScheduledTaskOilQuery {
+	
+	public static Logger logger=LoggerFactory.getLogger(ScheduledTaskOilQuery.class);
+
+	@Autowired
+	private SpringJdbcDAO  dao;
+	
+	@Autowired
+	private OilService service;
+	
+	/**
+	 * 查询油位计数据
+	 */
+	public Set<String> queryMeterNums(){
+		String sql="select replace(meter_num,'_01','') meter_num,'1' tag from t_oil_meter where transfer_type='3318'";
+		Map<String,Object> map=dao.queryForMapping(sql, "meter_num", "tag");
+		return map!=null?map.keySet():null;
+	}
+	
+	public void addCollectCarOil(){
+		Set<String> meters=queryMeterNums();
+		if(meters==null||meters.size()==0){
+			logger.debug("未找到油位计设备信息,取消获取油量数据");
+			return;
+		}
+		logger.debug("开始定时获取车辆油量数据");
+		String meterNums=StringUtils.join(meters, ","); //设备识别码就是车牌号
+		//处理车辆基本信息中的车牌不规范字符
+		//carNums=carNums.replaceAll("[^京津冀晋蒙辽吉黑沪苏浙皖闽赣鲁豫鄂湘粤桂琼渝川黔滇藏陕甘青宁新台港澳0-9A-Z,]", "");
+		Map<String,String> reqArgs=new HashMap<String,String>();
+		reqArgs.put("vins", meterNums);
+		reqArgs.put("queryDate", DateUtil.format(new Date(), "yyyy-MM-dd"));
+		String resp=OkhttpUtils.post(SysConfigUtil.getConfig("hdOilAPI"), reqArgs);
+		if(StringUtils.isEmpty(resp)){
+			logger.info("未查询到油量数据:");
+		}
+		else{
+			//logger.debug(resp);
+			List<OilCurrentDTO> oilDats=JSON.parseObject(resp,new TypeReference<List<OilCurrentDTO>>() {});
+			saveCollectOilData(oilDats);
+			logger.debug("获取油量数据并入库,记录数:"+(oilDats!=null?oilDats.size():0));
+			
+		}
+		
+		
+		
+	}
+	
+	public void saveCollectOilData(List<OilCurrentDTO> oilDats){
+		if(oilDats==null||oilDats.size()==0){
+			return ;
+		}
+		Iterator<OilCurrentDTO> iterator=oilDats.iterator();
+		OilCurrentDTO temp=null;
+		OilBO tempBO=null;
+		while(iterator.hasNext()){
+			temp=iterator.next();
+			tempBO=getOilBOFromHDDTO(temp);
+			service.saveCurrentData(tempBO);
+			
+			VolumeCalibrater.fillCarId(tempBO);
+			
+			if(!OilChecker.validateData(tempBO)){ //油量变化量检测及有效性检测
+				iterator.remove();
+			}
+			else{
+				service.saveOilData(tempBO);
+			}
+		}
+		
+	
+	}
+	
+	//从宏电平台获取的油耗po转换为本系统内的po
+	private OilBO  getOilBOFromHDDTO(OilCurrentDTO oil){
+		OilBO oilPO=new OilBO();
+		oilPO.setDtuNum(oil.getVin()+"_01");
+		oilPO.setOilVolume(oil.getCurOil());
+		oilPO.setDataTime(oil.getReportTime());
+		//VolumeCalibrater.fillCarId(oilPO); //填入carID
+		return oilPO;
+	}
+}

+ 345 - 0
src/main/java/com/hb/proj/server/ByteUtil.java

@@ -0,0 +1,345 @@
+/**
+ * 
+ */
+package com.hb.proj.server;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+
+
+/**
+ * @author liyongjun
+ * 
+ */
+public class ByteUtil
+{
+    public static short getShort(short s)
+    {
+        ByteBuffer bb = ByteBuffer.allocate(2);
+        bb.order(ByteOrder.BIG_ENDIAN);
+        bb.asShortBuffer().put(s);
+        bb.order(ByteOrder.LITTLE_ENDIAN);
+        return bb.getShort();
+    }
+    
+    public static int getInt(int i){
+    	ByteBuffer bb = ByteBuffer.allocate(4);
+    	bb.order(ByteOrder.BIG_ENDIAN);
+    	bb.asIntBuffer().put(i);
+    	bb.order(ByteOrder.LITTLE_ENDIAN);
+    	return bb.getInt();
+    }
+    
+    /**
+     * 截取byte[]
+     */
+    public static byte[] subBytes(byte[] src, int begin, int count)
+    {
+        byte[] bs = new byte[count];
+        for (int i = begin; i < begin + count; i++)
+            bs[i - begin] = src[i];
+        return bs;
+    }
+    
+    /**
+     * 截取byte[]--> 小端转大端(适用 多字节的转换)
+     */
+    public static byte[] subBytes2Exchange(byte[] src, int begin, int count)
+    {
+        byte[] bs = new byte[count];
+        for (int i = begin; i < begin + count; i++)
+            bs[i - begin] = src[i];
+        return byteExchange(bs, count);
+    }
+    
+    /**
+     * 字节数组转换成整型
+     * 
+     * @param b
+     * @return
+     */
+    public static int byteArrayToInt(byte[] b)
+    {
+        int value = 0;
+        for (int i = 0; i < 4; i++)
+        {
+            int shift = (4 - 1 - i) * 8;
+            value += (b[i] & 0x000000FF) << shift;
+        }
+        return value;
+    }
+    
+    /**
+     * 截取byte[]--> 转成整形(适用于单字节转换)
+     * 
+     * @param b
+     * @return
+     */
+    public static int byteArrayToInt(byte[] b, int begin, int count)
+    {
+        return byteArrayToInt(subBytes(b, begin, count), count);
+    }
+    
+    /**
+     * 截取byte[]--> 小端转大端--> 转成整型(适用多字节转换)
+     * 
+     * @param b
+     * @param begin
+     * @param count
+     * @return
+     */
+    public static int byteArrayExchangeToInt(byte[] b, int begin, int count)
+    {
+        return byteArrayToInt(subBytes2Exchange(b, begin, count), count);
+    }
+    
+    /**
+     * 
+     * @param i
+     * @return
+     */
+    public static byte[] intToByteArray(int i)
+    {
+        byte[] result = new byte[4];
+        result[0] = (byte)((i >> 24) & 0xFF);
+        result[1] = (byte)((i >> 16) & 0xFF);
+        result[2] = (byte)((i >> 8) & 0xFF);
+        result[3] = (byte)(i & 0xFF);
+        return result;
+    }
+    
+    /**
+     * 字节数组转换成整型
+     * 
+     * @param b
+     * @return
+     */
+    public static int byteArrayToInt(byte[] b, int l)
+    {
+        int value = 0;
+        for (int i = 0; i < l; i++)
+        {
+            int shift = (l - 1 - i) * 8;
+            value += (b[i] & 0x000000FF) << shift;
+        }
+        return value;
+    }
+    
+    /**
+     * Convert byte[] to hex string.这里我们可以将byte转换成int,然后利用Integer.toHexString(int) 来转换成16进制字符串。
+     * 
+     * @param src byte[] data
+     * @return hex string
+     */
+    public static String bytesToHexString(byte[] src)
+    {
+        StringBuilder stringBuilder = new StringBuilder("");
+        if (src == null || src.length <= 0)
+        {
+            return null;
+        }
+        for (int i = 0; i < src.length; i++)
+        {
+            int v = src[i] & 0xFF;
+            String hv = Integer.toHexString(v);
+            if (hv.length() < 2)
+            {
+                stringBuilder.append(0);
+            }
+            stringBuilder.append(hv);
+            stringBuilder.append(" ");
+        }
+        return stringBuilder.toString();
+    }
+    
+    /**
+     * 4字节数组大小端转换
+     * 
+     * @param src
+     * @return
+     */
+    public static byte[] byteExchange(byte[] src)
+    {
+        if (src.length > 4)
+        {
+            return src;
+        }
+        else
+        {
+            byte temp[] = new byte[4];
+            for (int i = 0; i < 4; i++)
+            {
+                temp[i] = src[4 - i - 1];
+            }
+            return temp;
+        }
+    }
+    
+    /**
+     * 字节数组大小端转换
+     * 
+     * @param src
+     * @param l 字节长度
+     * @return
+     */
+    public static byte[] byteExchange(byte[] src, int l)
+    {
+        if (src.length > 4 || l > 4)
+        {
+            return src;
+        }
+        else
+        {
+            byte temp[] = new byte[l];
+            for (int i = 0; i < l; i++)
+            {
+                temp[i] = src[l - i - 1];
+            }
+            return temp;
+        }
+    }
+    
+    /**
+     * 字节数组大小端转换
+     * 
+     * @param src
+     * @param l 字节长度
+     * @return
+     */
+    public static byte[] subByteExchange(byte[] src, int begin, int count)
+    {
+        return byteExchange(subBytes(src, begin, count), count);
+    }
+    
+    /**
+     * 合并2个byte数组
+     * 
+     * @param byte_1
+     * @param byte_2
+     * @return
+     */
+    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2)
+    {
+        byte[] byte_3 = new byte[byte_1.length + byte_2.length];
+        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
+        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
+        return byte_3;
+    }
+    
+    /**
+     * 合并多个个byte数组
+     * 
+     * @param byte_1
+     * @param byte_2
+     * @return
+     */
+    public static byte[] byteMerger(List<byte[]> list)
+    {
+        int length = 0;
+        for (int i = 0; i < list.size(); i++)
+        {
+            length += list.get(i).length;
+        }
+        byte[] rs = new byte[length];
+        
+        int temp = 0;
+        for (int i = 0; i < list.size(); i++)
+        {
+            System.arraycopy(list.get(i), 0, rs, temp, list.get(i).length);
+            temp += list.get(i).length;
+        }
+        return rs;
+    }
+    
+    /**
+     * 将字节数组转成MAC地址
+     * 
+     * @param macBytes
+     * @return
+     */
+    public static String byteToMac(byte[] macBytes)
+    {
+        String mac = "";
+        for (int i = 0; i < macBytes.length; i++)
+        {
+            String sTemp = ByteUtil.byteArrayToInt(new byte[] {macBytes[i]}, 1) + "";
+            mac = mac + sTemp + ":";
+        }
+        
+        mac = mac.substring(0, mac.lastIndexOf(":"));
+        return mac;
+    }
+    
+    public static byte[] macToByte(String mac)
+    {
+        String[] macStr = mac.split(":");
+        byte[] macData = new byte[macStr.length];
+        for (int i = 0; i < macStr.length; i++)
+        {
+            macData[i] = (byte)Integer.parseInt(macStr[i]);
+        }
+        return macData;
+    }
+    
+    /**
+     * 将字节数组转成IP地址
+     * 
+     * @param ipBytes
+     * @return
+     */
+    public static String byteToIp(byte[] ipBytes)
+    {
+        String ip = "";
+        for (int i = 0; i < ipBytes.length; i++)
+        {
+            ip = ip + ByteUtil.byteArrayToInt(new byte[] {ipBytes[i]}, 1) + ".";
+        }
+        
+        ip = ip.substring(0, ip.lastIndexOf("."));
+        return ip;
+    }
+    
+    public static byte[] hexStringToBytes(String hexString)
+    {
+        if (hexString == null || hexString.equals(""))
+        {
+            return null;
+        }
+        hexString = hexString.toUpperCase();
+        int length = hexString.length() / 2;
+        char[] hexChars = hexString.toCharArray();
+        byte[] d = new byte[length];
+        for (int i = 0; i < length; i++)
+        {
+            int pos = i * 2;
+            d[i] = (byte)(charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
+        }
+        return d;
+    }
+    
+    private static byte charToByte(char c)
+    {
+        return (byte)"0123456789ABCDEF".indexOf(c);
+    }
+    
+    public static void main(String[] args)
+    {
+       /* byte[] b = hexStringToBytes("570D260000FFFF000000000003034350535A1200000000000000000009006800180500E50054");
+        
+        ZprotoTypeConfig config = new ZprotoTypeConfig();
+        try
+        {
+            JavaStruct.unpack(config, b, ByteOrder.BIG_ENDIAN);
+            
+            System.out.println(config.getFreq());
+        }
+        catch (StructException e)
+        {
+            e.printStackTrace();
+        }
+        */
+        //System.out.println(Arrays.toString(b));
+    }
+}

+ 82 - 0
src/main/java/com/hb/proj/server/MeterBindBO.java

@@ -0,0 +1,82 @@
+package com.hb.proj.server;
+/**
+ * 油量计业务对象
+ * @author hb
+ *
+ */
+public class MeterBindBO {
+	
+
+	private String carId;
+	
+	private String meterNum;
+	
+	private String boxId;
+	
+	private OilBoxBO  oilBox;
+	
+	private String transferType;
+	
+	private String mountId; //挂载参数编号  t_oil_Meter表主键
+	
+	private Double volumeRatio; //标定体积的线性系数,有值时优先使用,否则dtu用油箱规格计算,3318直接用采集值
+
+	public String getCarId() {
+		return carId;
+	}
+
+	public void setCarId(String carId) {
+		this.carId = carId;
+	}
+
+	public String getMeterNum() {
+		return meterNum;
+	}
+
+	public void setMeterNum(String meterNum) {
+		this.meterNum = meterNum;
+	}
+
+	public String getBoxId() {
+		return boxId;
+	}
+
+	public void setBoxId(String boxId) {
+		this.boxId = boxId;
+	}
+
+	public OilBoxBO getOilBox() {
+		return oilBox;
+	}
+
+	public void setOilBox(OilBoxBO oilBox) {
+		this.oilBox = oilBox;
+	}
+
+	public String getTransferType() {
+		return transferType;
+	}
+
+	public void setTransferType(String transferType) {
+		this.transferType = transferType;
+	}
+
+	public String getMountId() {
+		return mountId;
+	}
+
+	public void setMountId(String mountId) {
+		this.mountId = mountId;
+	}
+
+	public Double getVolumeRatio() {
+		return volumeRatio;
+	}
+
+	public void setVolumeRatio(Double volumeRatio) {
+		this.volumeRatio = volumeRatio;
+	}
+
+	
+
+}

+ 99 - 0
src/main/java/com/hb/proj/server/OilBO.java

@@ -0,0 +1,99 @@
+package com.hb.proj.server;
+
+import java.util.Date;
+
+public class OilBO {
+
+	private String dtuNum; //dtu身份识别码
+	
+	private Double liquidHeight; //液位高度 单位0.1mm
+	
+	private Date  dataTime; //数据采集时间
+	
+	private Double oilVolume ;  //油量容积毫升
+	
+	private String carId;
+	
+	private String mountId; //挂载参数编码(t_oil_meter表主键)
+	
+	private Double rtHeight; //实时液位高度 单位0.1mm
+	
+	private String liquidStr; //稳定液位高度 字符数据
+	
+	private String liquidrtStr; //实时液位高度 字符数据
+
+	public String getDtuNum() {
+		return dtuNum;
+	}
+
+	public void setDtuNum(String dtuNum) {
+		this.dtuNum = dtuNum;
+	}
+
+	
+
+	public Date getDataTime() {
+		return dataTime;
+	}
+
+	public void setDataTime(Date dataTime) {
+		this.dataTime = dataTime;
+	}
+
+	public Double getLiquidHeight() {
+		return liquidHeight;
+	}
+
+	public void setLiquidHeight(Double liquidHeight) {
+		this.liquidHeight = liquidHeight;
+	}
+
+	public Double getOilVolume() {
+		return oilVolume;
+	}
+
+	public void setOilVolume(Double oilVolume) {
+		this.oilVolume = oilVolume;
+	}
+
+	public String getCarId() {
+		return carId;
+	}
+
+	public void setCarId(String carId) {
+		this.carId = carId;
+	}
+
+	public String getMountId() {
+		return mountId;
+	}
+
+	public void setMountId(String mountId) {
+		this.mountId = mountId;
+	}
+
+	public Double getRtHeight() {
+		return rtHeight;
+	}
+
+	public void setRtHeight(Double rtHeight) {
+		this.rtHeight = rtHeight;
+	}
+
+	public String getLiquidStr() {
+		return liquidStr;
+	}
+
+	public void setLiquidStr(String liquidStr) {
+		this.liquidStr = liquidStr;
+	}
+
+	public String getLiquidrtStr() {
+		return liquidrtStr;
+	}
+
+	public void setLiquidrtStr(String liquidrtStr) {
+		this.liquidrtStr = liquidrtStr;
+	}
+
+}

+ 87 - 0
src/main/java/com/hb/proj/server/OilBoxBO.java

@@ -0,0 +1,87 @@
+package com.hb.proj.server;
+/**
+ * 油箱规格
+ * @author hb
+ *
+ */
+public class OilBoxBO {
+	
+	private String recordId;
+
+	private Double boxLen;  //长cm
+	
+	private Double boxWidth; //宽cm
+	
+	private Double boxHeight; //高cm
+	
+	private Double boxThick; //壁厚cm
+	
+	private Double btmHeight; //底部不规则高度 cm
+	
+	private Double btmDiffVolume; //底部不规则部分容积差
+	
+	public Double getInnerLen(){
+		return boxLen-2*boxThick;
+	}
+	
+	public Double getInnerWidth(){
+		return boxWidth-2*boxThick;
+	}
+
+	public Double getBoxLen() {
+		return boxLen;
+	}
+
+	public void setBoxLen(Double boxLen) {
+		this.boxLen = boxLen;
+	}
+
+	public Double getBoxWidth() {
+		return boxWidth;
+	}
+
+	public void setBoxWidth(Double boxWidth) {
+		this.boxWidth = boxWidth;
+	}
+
+	public Double getBoxHeight() {
+		return boxHeight;
+	}
+
+	public void setBoxHeight(Double boxHeight) {
+		this.boxHeight = boxHeight;
+	}
+
+	public Double getBoxThick() {
+		return boxThick;
+	}
+
+	public void setBoxThick(Double boxThick) {
+		this.boxThick = boxThick;
+	}
+
+	public Double getBtmHeight() {
+		return btmHeight;
+	}
+
+	public void setBtmHeight(Double btmHeight) {
+		this.btmHeight = btmHeight;
+	}
+
+	public Double getBtmDiffVolume() {
+		return btmDiffVolume;
+	}
+
+	public void setBtmDiffVolume(Double btmDiffVolume) {
+		this.btmDiffVolume = btmDiffVolume;
+	}
+
+	public String getRecordId() {
+		return recordId;
+	}
+
+	public void setRecordId(String recordId) {
+		this.recordId = recordId;
+	}
+
+}

+ 164 - 0
src/main/java/com/hb/proj/server/OilChangeBO.java

@@ -0,0 +1,164 @@
+package com.hb.proj.server;
+
+import java.util.Date;
+import java.util.Vector;
+
+/**
+ * 油量变化实体对象
+ * @author hb
+ *
+ */
+public class OilChangeBO {
+	
+	public static final String ADD_CHANGE="add";  //变化类型常量:加油
+	
+	public static final String EXCEPTION_CHANGE="exception"; //变化类型常量:异常消耗
+	
+	private String dtuNum;  //油量传感器编码
+	
+	private Double diffVolume; //变化体积,单位升
+	
+	private Double diffH; //前后液位差 0.1mm
+	
+	private Date dataTime; //变化时的数据的采集时间
+	
+	private Date preDataTime; //上一数据的采集时间
+	
+	private String carId;
+	
+	private String changeType;
+	
+	private Double changeRatio;
+	
+	private Vector<Double> diffVolumeList;
+	
+	private long diffTimes;
+	
+	private boolean waveFilter=false;
+	
+	private String mountId; //关联t_oil_meter表主键
+	
+	public OilChangeBO(){
+		
+	}
+	
+	public OilChangeBO(String carId,String dtuNum,Double diffVolume,Date dataTime,Date preDataTime){
+		this.carId=carId;
+		this.dtuNum=dtuNum;
+		this.diffVolume=diffVolume;
+		this.dataTime=dataTime;
+		this.preDataTime=preDataTime;
+		this.diffTimes=(dataTime.getTime()-preDataTime.getTime())/1000;
+		this.changeRatio=Math.abs(diffVolume)/this.diffTimes;
+	}
+	
+	public void update(Double diffVolume,Date dataTime,Date preDataTime){
+		this.diffVolume=diffVolume;
+		this.dataTime=dataTime;
+		this.preDataTime=preDataTime;
+		this.diffTimes=(dataTime.getTime()-preDataTime.getTime())/1000;
+		this.changeRatio=Math.abs(diffVolume)/this.diffTimes;
+	}
+
+	public String getDtuNum() {
+		return dtuNum;
+	}
+
+	public void setDtuNum(String dtuNum) {
+		this.dtuNum = dtuNum;
+	}
+
+	public Double getDiffVolume() {
+		return diffVolume;
+	}
+
+	public void setDiffVolume(Double diffVolume) {
+		this.diffVolume = diffVolume;
+	}
+
+	
+
+	public Date getDataTime() {
+		return dataTime;
+	}
+
+	public void setDataTime(Date dataTime) {
+		this.dataTime = dataTime;
+	}
+
+	public Date getPreDataTime() {
+		return preDataTime;
+	}
+
+	public void setPreDataTime(Date preDataTime) {
+		this.preDataTime = preDataTime;
+	}
+
+	public String getCarId() {
+		return carId;
+	}
+
+	public void setCarId(String carId) {
+		this.carId = carId;
+	}
+
+	public String getChangeType() {
+		return changeType;
+	}
+
+	public void setChangeType(String changeType) {
+		this.changeType = changeType;
+	}
+
+	public Double getChangeRatio() {
+		return changeRatio;
+	}
+
+	public void setChangeRatio(Double changeRatio) {
+		this.changeRatio = changeRatio;
+	}
+
+	public Vector<Double> getDiffVolumeList() {
+		return diffVolumeList;
+	}
+
+	public void setDiffVolumeList(Vector<Double> diffVolumeList) {
+		this.diffVolumeList = diffVolumeList;
+	}
+
+	public long getDiffTimes() {
+		return diffTimes;
+	}
+
+	public void setDiffTimes(long diffTimes) {
+		this.diffTimes = diffTimes;
+	}
+
+	public boolean isWaveFilter() {
+		return waveFilter;
+	}
+
+	public void setWaveFilter(boolean waveFilter) {
+		this.waveFilter = waveFilter;
+	}
+
+	public String getMountId() {
+		return mountId;
+	}
+
+	public void setMountId(String mountId) {
+		this.mountId = mountId;
+	}
+
+	public Double getDiffH() {
+		return diffH;
+	}
+
+	public void setDiffH(Double diffH) {
+		this.diffH = diffH;
+	}
+
+	
+
+	
+}

+ 47 - 0
src/main/java/com/hb/proj/server/OilCheckTask.java

@@ -0,0 +1,47 @@
+package com.hb.proj.server;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.hb.proj.oil.service.OilService;
+import com.hb.xframework.util.ApplicationContextUtils;
+
+public class OilCheckTask implements Runnable {
+
+	public static Logger logger=LoggerFactory.getLogger(OilCheckTask.class);
+	
+	private OilChangeBO changeBO;
+	
+	private OilService  oilService;
+	
+	/**
+	 * 采用对象属性复制,避免入参changeBO 的线程不安全性
+	 * @param changeBO
+	 */
+	public OilCheckTask(OilChangeBO changeBO){
+		this.changeBO=changeBO;
+		this.oilService=ApplicationContextUtils.getBean("oilService", OilService.class);
+	}
+	
+	/**
+	 * 2021.2.19
+	 * this.changeBO不是线程安全的,在写入数据库前可能this.changeBO已经改变。导致偶尔出现不满足上一步限制的也写入了数据库
+	 * 已做处理传入的changeBO,是快照数据
+	 */
+	@Override
+	public void run() {
+		Double diffVolume=this.changeBO.getDiffVolume();
+		if(diffVolume>50){ //油量增加  认为是加油了
+			this.changeBO.setChangeType(OilChangeBO.ADD_CHANGE);
+		}
+		else if(diffVolume<-20){//油量减少 认为消耗异常
+			this.changeBO.setChangeType(OilChangeBO.EXCEPTION_CHANGE);
+		}
+		if(this.changeBO.getChangeType()!=null){
+			this.oilService.saveOilChangeData(this.changeBO);
+		}
+		
+	}
+
+	
+}

+ 182 - 0
src/main/java/com/hb/proj/server/OilChecker.java

@@ -0,0 +1,182 @@
+package com.hb.proj.server;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+
+import com.hb.proj.oil.service.OilService;
+import com.hb.proj.oil.service.OtherConfigService;
+import com.hb.xframework.util.ApplicationContextUtils;
+
+/**
+ * 油量采集数据检验器
+ * @author hb
+ *
+ */
+public class OilChecker {
+
+	public static Logger logger=LoggerFactory.getLogger(OilChecker.class);
+	
+	/**
+	 * 初始容量按目前最大车辆数,实际每天动用车辆30辆左右,只要车辆动用过,数据就会存在(除非应用重启),
+	 * 以后可以加优化,一定时间没有上传数据的车辆,清理掉,减少不必要内存消耗
+	 * 需要考虑多线程
+	 */
+	private static final Map<String,OilBO> oilDatas=new HashMap<String,OilBO>(300);
+	
+	private static final Map<String,OilChangeBO> chanageDatas=new HashMap<String,OilChangeBO>(300);
+	
+	/**
+	 * 升/秒   假设最大加油速率  10s-20升  3318采样间隔是1分钟,dtu是2秒
+	 */
+	private static final double maxAddRatio=2;  //  升/s
+	
+	/**
+	 * 升/秒   假设最大正常耗油速率  10升/min  3318采样间隔是1分钟,dtu是2秒
+	 */
+	private static final double maxCostRatio=0.17;  //  升/s
+	
+	public static int MONTH_SPLIT_DAY=16;  //月份划分日,默认是16号,实际从数据库中获取配置;
+	
+	public static void initMonthSplitDay(){
+		OtherConfigService otherConfig=ApplicationContextUtils.getBean("otherConfigService", OtherConfigService.class);
+		Integer splitDay=otherConfig.load().getMonthSplitDay();
+		MONTH_SPLIT_DAY=splitDay!=null?splitDay:16;
+	}
+	
+	public static void init(){
+		initMonthSplitDay();
+		
+		OilService service=ApplicationContextUtils.getBean("oilService",OilService.class);
+		List<OilBO> datas=service.loadLastOilData();
+		for(OilBO oil : datas){
+			oilDatas.put(oil.getDtuNum(), oil);
+		}
+	}
+	
+	public static void addData(OilBO oil){
+		oilDatas.put(oil.getDtuNum(), oil);
+	}
+	
+	public static OilBO getData(String dtuNum){
+		return oilDatas.get(dtuNum);
+	}
+	
+	public static boolean validateData(OilBO newData){
+		if(newData==null){
+			return false;
+		}
+		OilBO oldData=oilDatas.get(newData.getDtuNum());
+		
+		//首次启用,将第一个采集数据作为基准
+		if(oldData==null){
+			oilDatas.put(newData.getDtuNum(),newData);
+			return true;
+		}
+		
+		//每次检测下最后的跳变
+		OilChangeBO  lastJump=chanageDatas.get(newData.getDtuNum());
+		if(lastJump!=null&&OilDetecter.detectChangeTimeout(lastJump)){ //最后的跳变已经超过修复时间,需要记录跳变事件,并清空该事件
+			lastJump.setWaveFilter(true);
+			TaskExecutor.execute(new OilCheckTask(lastJump));
+			chanageDatas.put(newData.getDtuNum(), null);
+		}
+		
+		//数据未更新重复数据 主要针对3318模式
+		if(oldData.getDataTime().getTime()==newData.getDataTime().getTime()){
+			return false;
+		}
+		//未采集到有效数据,使用最后的数据
+		if(newData.getOilVolume()==null||newData.getOilVolume().doubleValue()==0){
+			newData.setLiquidHeight(oldData.getLiquidHeight());
+			newData.setOilVolume(oldData.getOilVolume());
+			oilDatas.put(newData.getDtuNum(),newData);
+			
+		}
+		else if(oldData.getOilVolume()==null){
+			oilDatas.put(newData.getDtuNum(),newData);
+		}
+		else{
+			/*double diff=newData.getLiquidHeight()-oldData.getLiquidHeight();
+			if(Math.abs(diff)>=100){ 
+				//只考虑绝对量的变化,未考虑时间,计算变化率
+				//单位0.1mm,液位波动1+cm  就需要进行关注
+				//波动原因:路面颠簸、急刹车等驾驶原因导致,但一段时间后液位会回复;异常耗油(重点检测)
+				//开机状态下通过斜率判断,但需要先提供标准斜率(标准斜率的确定分不同的车、路况、驾驶习惯、作业状态而不同)
+				Double diffVolume=newData.getOilVolume()!=null&&oldData.getOilVolume()!=null?(newData.getOilVolume()-oldData.getOilVolume()):null;
+				TaskExecutor.execute(new OilCheckTask(newData.getCarId(),newData.getDtuNum(),diff,diffVolume,(newData.getDataTime().getTime()-oldData.getDataTime().getTime()),newData.getDataTime()));
+			}
+			
+			oilDatas.put(newData.getDtuNum(),newData);*/
+			
+			
+			double diff=newData.getOilVolume()-oldData.getOilVolume();
+			Double diffH=null;
+			if(newData.getLiquidHeight()!=null&&oldData.getLiquidHeight()!=null){
+				diffH=newData.getLiquidHeight().doubleValue()-oldData.getLiquidHeight().doubleValue();
+			}
+			
+			if(Math.abs(diff)>=5){
+				if(lastJump==null){ //第一个跳变
+					lastJump=new OilChangeBO(newData.getCarId(),newData.getDtuNum(),diff,newData.getDataTime(),oldData.getDataTime());
+					lastJump.setMountId(newData.getMountId());
+					lastJump.setDiffH(diffH);
+					chanageDatas.put(newData.getDtuNum(),lastJump);
+				}
+				else{
+					OilChangeBO oldChange=new OilChangeBO();
+					BeanUtils.copyProperties(lastJump,oldChange);
+					lastJump.update(diff,newData.getDataTime(),oldData.getDataTime()); //更新为新跳变
+					int rst=OilDetecter.detectChangeWave(oldChange, lastJump);
+					if(rst==OilDetecter.JUMP_EVENT){ //需要记录前一跳变事件
+						oldChange.setWaveFilter(true);
+						TaskExecutor.execute(new OilCheckTask(oldChange));
+					}
+					else if(rst==OilDetecter.WAVE){ //波动过滤
+						chanageDatas.put(newData.getDtuNum(),null);
+						TaskExecutor.execute(new ProcessWaveTask(newData.getDtuNum(),lastJump.getDataTime(),oldChange.getDataTime()));
+					}
+					
+				}
+				//只要有跳变就记录,用于对比后期会去掉
+				//TaskExecutor.execute(new OilCheckTask(new OilChangeBO(newData.getCarId(),newData.getDtuNum(),diff,newData.getDataTime(),oldData.getDataTime())));
+			}
+			
+			/*
+			 * 有些车加油时还在传数据,且上传的是30s内的稳定值,一直加油一直不稳定直到加完后,所以有些车在一个采集周期内(2s)数据就跳变,实际应该是一直上升持续多个采集周期
+			 * 所以判断是否加油,异常耗油,还是波动,需要观察一段时间内的数据,有紧跟的上下跳变就是波动,否则上跳是加油,下跳是异常。
+			 * 上下跳变紧跟时间规定为多少?肯定小于:异常消耗至加油,否则会掩盖这次异常。且如果是波动,上下跳动幅度应该差不多(相差正常耗油的差距)
+			 */
+			
+			
+			
+			
+			/**
+			 * 先判断间隔时间,超过采集周期的(3318采样间隔是1分钟,dtu是2秒)
+			 * 间隔超过90秒,油耗有10升变化幅度,可能中途无信号、设备故障或停机后再开机;
+			 * 先不考虑设备故障,不在周期内的异常变化就认为异常;可以过滤部分周期内的波动
+			 * 基本1cm液位对应3-5升
+			 */
+			/*if(preChange.getDiffTimes()>30&&Math.abs(preChange.getDiffVolume())>=10){
+				TaskExecutor.execute(new OilCheckTask(preChange));
+			}*/
+			
+			/*if(Math.abs(diff)>=10){
+				OilChangeBO changeData=new OilChangeBO();
+				BeanUtils.copyProperties(preChange,changeData); //避免多线程接收数据时,入库时的数据是另一个数据(可能是不需要报警的数据)
+				TaskExecutor.execute(new OilCheckTask(changeData));
+				//logger.info(newData.getDtuNum()+":diff:"+diff+" to save:"+preChange.getDiffVolume()+"--"+changeData.getDiffVolume());
+			}*/
+			
+			oilDatas.put(newData.getDtuNum(),newData);
+			
+		}
+		return true;
+	}
+	
+	
+}

+ 60 - 0
src/main/java/com/hb/proj/server/OilDetecter.java

@@ -0,0 +1,60 @@
+package com.hb.proj.server;
+
+import java.util.Date;
+
+
+/**
+ * 对采集数据进行预判:异常消耗、加油等事件判断
+ * @author hb
+ *
+ */
+public class OilDetecter {
+
+	
+	public static long repairWait=600000; //修复最大等待时间毫秒 ,3分钟,2022.3.22调整为10分钟
+	
+	public static final int WAVE=0;
+	
+	public static final int JUMP_EVENT=2;
+	
+	public static final int IGNORE=3;
+	
+	/**
+	 * 检测前后两次跳变是否为波动
+	 * @param preJumpBO
+	 * @param jumpBO
+	 * @return false 不需要记录前一事件  true 需要记录
+	 */
+	public static int detectChangeWave(OilChangeBO preJumpBO,OilChangeBO jumpBO){
+		long diffTimes=jumpBO.getDataTime().getTime()-preJumpBO.getDataTime().getTime();
+		Double preJump=preJumpBO.getDiffVolume(),newJump=jumpBO.getDiffVolume();
+		if(preJump*newJump<0){ //得到反向补偿
+			if(diffTimes>repairWait){//超过补偿最大等待时间,3分钟内,
+				return JUMP_EVENT;
+			}
+			preJump=preJump.doubleValue()+newJump.doubleValue();
+			if(Math.abs(preJump.doubleValue())<10){ //且补偿后前后差值不超过10升就认为是杂波,过滤
+				return WAVE;  //是波动
+			}
+			else{ //补偿后差值过大不认为是杂波,需要记录事件(针对加油前后的跳变,避免把加油前的异常消耗过滤掉,避免加油后的下跳而把加油事件滤掉,不可完全避免)
+				return JUMP_EVENT;
+			}
+		}
+		else{  //同向加强,逐步加强,但还不支持逐步恢复,不能一次恢复的就会认为是:补偿后差值过大不认为是杂波,需要记录事件
+			jumpBO.setDiffVolume(preJump.doubleValue()+newJump.doubleValue());
+			return IGNORE;
+		}
+		
+	}
+	
+	/**
+	 * 检测最后的跳变是否超过补偿时间
+	 * @param jumpBO
+	 * @return
+	 */
+	public static boolean detectChangeTimeout(OilChangeBO jumpBO){
+		long diffTimes=(new Date()).getTime()-jumpBO.getDataTime().getTime();
+		return diffTimes>repairWait;
+	}
+
+}

+ 168 - 0
src/main/java/com/hb/proj/server/OilMonitorServer.java

@@ -0,0 +1,168 @@
+package com.hb.proj.server;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class OilMonitorServer extends Thread {
+
+	public static Logger logger=LoggerFactory.getLogger(OilMonitorServer.class);
+	
+	 //通道管理器
+    private Selector selector;
+    
+    private boolean stop=false;
+    
+    private int port;
+    
+    public void setPort(int port){
+    	this.port=port;
+    }
+    public OilMonitorServer(int port){
+    	this.port=port;
+    }
+    
+    @Override
+	public void run() {
+    	if(!this.init()){
+    		return ;
+    	}
+    	this.listen();
+    }
+    
+    public boolean init(){
+        try{
+      	//获取一个ServerSocket通道
+          ServerSocketChannel serverChannel = ServerSocketChannel.open();
+          serverChannel.configureBlocking(false);
+          serverChannel.socket().bind(new InetSocketAddress(port));
+          //获取通道管理器
+          selector=Selector.open();
+          //将通道管理器与通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,
+          //只有当该事件到达时,Selector.select()会返回,否则一直阻塞。
+          serverChannel.register(selector, SelectionKey.OP_ACCEPT);
+          
+          return true;
+        }
+        catch(Exception e){
+          logger.error("接收服务器启动失败",e);
+      	  return false;
+        }
+      }
+    
+    public void listen(){
+    	logger.debug("接收服务器启动成功,开始监听...");
+      try{
+        //使用轮询访问selector
+        while(!stop){
+        	//当有注册的事件到达时,方法返回,否则阻塞。
+            int num=selector.select();
+            if(num==0){  //select()为阻塞方法,一般情况下,能返回的num肯定就大于0;特殊情况下,其他线程调用了selector.wakeup使得select()立即返回
+            	continue;
+            }
+            logger.debug("找到准备就绪通道");
+            //获取selector中的迭代器,选中项为注册的事件
+            Iterator<SelectionKey> ite=selector.selectedKeys().iterator();
+            
+            while(ite.hasNext()){
+                SelectionKey key = ite.next();
+                //删除已选key,防止重复处理
+                ite.remove();
+                //客户端请求连接事件
+                if(key.isAcceptable()){
+                    ServerSocketChannel server = (ServerSocketChannel)key.channel();
+                    //获得客户端连接通道
+                    SocketChannel channel = server.accept();
+                    channel.configureBlocking(false);
+                    logger.debug("终端"+channel.getRemoteAddress()+"已登录服务器");
+                    //向客户端发消息
+                    //channel.write(ByteBuffer.wrap(new String("send message to client").getBytes()));
+                    //在与客户端连接成功后,为客户端通道注册SelectionKey.OP_READ事件。
+                    channel.register(selector, SelectionKey.OP_READ);
+                    
+                    
+                }else if(key.isReadable()){//有可读数据事件
+                	//获取客户端传输数据可读取消息通道。
+                    SocketChannel channel = (SocketChannel)key.channel();
+                    //创建读取数据缓冲器
+                    ByteBuffer buffer = ByteBuffer.allocate(4096);
+                    byte[] realReceive=null;
+                    int readedNum=-1;
+                	
+	                    try{
+	                    	 buffer.clear();
+	                    	 readedNum = channel.read(buffer);
+	                         if(readedNum==-1){
+	                        	logger.debug("终端"+channel.getRemoteAddress()+"已断开连接");
+	                         	channel.close();
+	                         	//key.selector().selectNow(); 外层循环有select()方法,会最终关闭
+	                         	continue;
+	                         }
+	                         if(readedNum==0){
+	                        	 logger.debug("未读到数据");
+	                        	 continue;
+	                         }
+	                         
+	                         realReceive =new byte[readedNum]; //buffer.array();
+	                         System.arraycopy(buffer.array(), 0, realReceive,0,readedNum);
+	                         logger.debug("接收数据:"+ByteUtil.bytesToHexString(realReceive));
+	                         /*byte[] rst=process(realReceive);
+	                         if(rst!=null){
+	                        	 channel.write(ByteBuffer.wrap(rst));
+	                         }*/
+	                         TaskExecutor.execute(new OilParseTask(channel,realReceive));
+	                    	
+	                    } 
+	                    catch(IOException e){
+	                    	 e.printStackTrace();
+	                    	 logger.debug("终端"+channel.getRemoteAddress()+"异常关闭");
+	                    	 channel.close();
+	                      	 //key.selector().selectNow();
+	                    	 break;
+	                    }
+                	
+                    
+                }
+            }
+        }
+        logger.debug("接收服务器关闭");
+        selector.close();
+      }
+      catch(Exception e){
+    	  e.printStackTrace();
+    	  logger.debug("接收服务器监听出现异常");
+      }
+    }
+    
+    
+    public void  stopServer(){
+    	this.stop=true;
+    	TaskExecutor.shutdown();
+    }
+    
+   
+    
+    
+   
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		/*byte[] bs={0x00,0x1b};
+		int num=OilMonitorServer.bytesToInt(bs);
+		System.out.println(num);*/
+		OilMonitorServer  server=new OilMonitorServer(51663);
+		server.init();
+		server.listen();
+	}
+
+}

+ 179 - 0
src/main/java/com/hb/proj/server/OilParseTask.java

@@ -0,0 +1,179 @@
+package com.hb.proj.server;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.Date;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.hb.proj.oil.service.OilService;
+import com.hb.xframework.util.ApplicationContextUtils;
+
+public class OilParseTask implements Runnable {
+	
+	public static Logger logger=LoggerFactory.getLogger(OilParseTask.class);
+	
+	private byte[]  datas;
+	
+	private SocketChannel channel;
+	
+	private OilService  oilService;
+	
+	public OilParseTask(SocketChannel channel,byte[]  datas){
+		this.channel=channel;
+		this.datas=datas;
+		this.oilService=ApplicationContextUtils.getBean("oilService", OilService.class);
+	}
+
+	@Override
+	public void run() {
+		int i=0,len=datas.length;
+    	int packageLen=0;
+    	byte[]  packagebox=null;
+    	while(i<len){
+    		if(datas[i]!=0x7B){ //包头不对,继续向后找
+    			i++;
+    			continue;
+    		}
+    		packageLen=ByteUtil.byteArrayToInt(new byte[]{datas[i+2],datas[i+3]}, 2);
+    		if((i+packageLen-1)>=len||datas[i+packageLen-1]!=0x7B){ //数据长度不够或者包尾不对 0x7b
+    			i++;
+    			continue;
+    		}
+    		packagebox=new byte[packageLen];
+    		System.arraycopy(datas, i, packagebox, 0, packageLen); //提取指令内容
+    		processPacket(packagebox);
+    		i+=packageLen;
+    	}
+    	
+    	
+    	
+
+	}
+	
+	/**
+	 * 处理提前的完整的消息
+	 * dtu wrap数据
+	 * 油量采集数据 *XD,0000,01, 1786,1796,0000,0320,1371#
+	 * @param packet
+	 */
+	private void processPacket(byte[] packet){
+		if(packet!=null&&packet[1]==0x01){  //注册请求
+			try {
+				channel.write(ByteBuffer.wrap(buildRegRespMsg(packet)));
+			} catch (IOException e) {
+				e.printStackTrace();
+				logger.error("注册应答出错"+e.getMessage());
+			}
+    	}
+    	else if(packet!=null&&packet[1]==0x09){ //dtu发送业务数据到dsc
+    		OilBO oilData=buildOilBO(packet);
+    		if(oilData==null){
+    			return;
+    		}
+    		
+    		oilService.saveCurrentData(oilData);  //存于当前数据表
+    		if(oilData.getLiquidHeight()==null){  //未采集到有效的稳定液位值,不进行后面的处理及入库
+    			return;
+    		}
+    		VolumeCalibrater.fillVolume(oilData);
+    		if(OilChecker.validateData(oilData)){
+    			oilService.saveOilData(oilData);
+    		}	
+    		
+    		
+    		
+    	}
+    	else{
+    		logger.info("DTU发送的未知请求");
+    	}
+	}
+	
+	
+	/**
+	 * 提取油量数据
+	 * @param packet
+	 * @return
+	 */
+	private OilBO  buildOilBO(byte[] packet){
+		//DTU身份识别码 11bytes
+		byte[] slice=new byte[11];
+		System.arraycopy(packet,4,slice,0,11);
+		String dtuNum=(new String(slice)).trim();
+		//油量 数据包
+		slice=new byte[packet.length-16];
+		System.arraycopy(packet,15,slice,0,slice.length);
+		
+		logger.debug(dtuNum+":"+new String(slice));
+		
+		
+		if(!checkOilPacket(slice)){
+			return null;
+		}
+		String[] oilMsgs=(new String(slice)).split(",");
+		
+		OilBO oilPO=new OilBO();
+		
+		oilPO.setDtuNum(dtuNum+"_"+oilMsgs[2]);
+		
+		oilPO.setDataTime(new Date());
+		
+		oilPO.setLiquidStr(oilMsgs[3]);  //存储原始稳定值
+		
+		oilPO.setLiquidrtStr(oilMsgs[4]);  //存储原始瞬时值
+		
+		if(StringUtils.isNumeric(oilMsgs[3])){ //采集到稳定液位值
+			oilPO.setLiquidHeight(Double.parseDouble(oilMsgs[3]));
+		}
+		
+		if(StringUtils.isNumeric(oilMsgs[4])){
+			oilPO.setRtHeight(Double.parseDouble(oilMsgs[4]));
+		}
+		
+		
+		return oilPO;
+	}
+	
+	/**
+	 * 油量数据包校验(头尾校验,校验和暂不处理)
+	 * @param oilPacket
+	 * @return
+	 */
+	private boolean checkOilPacket(byte[] oilPacket){
+		String msg=new String(oilPacket);
+		//logger.debug("油量数据:"+msg);
+		if(msg.startsWith("*XD")&&msg.endsWith("#")){
+			return true;
+		}
+		/*byte[] slice=new byte[3];
+		System.arraycopy(oilPacket,0,slice,0,3);
+		String head=new String(slice);
+		boolean rst=true;
+		rst="*XD".equals(head)&&((char)oilPacket[oilPacket.length-1])=='#';
+		int verifySum=0;
+		for(int i=4,len=oilPacket.length-5;i<len;i++){
+			
+		}*/
+		return false;
+	}
+
+	/**
+	 * 构建注册请求回应消息
+	 * @param regRequest
+	 * @return
+	 */
+	private byte[] buildRegRespMsg(byte[] regRequest){
+		byte[] respPackage=new byte[16];
+		System.arraycopy(regRequest, 0, respPackage, 0, 15);
+		respPackage[1]=(byte)(0x81&0xFF);
+		respPackage[2]=(byte)(0x0&0xFF);
+		respPackage[3]=(byte)(0x10&0xFF);
+		respPackage[15]=(byte)(0x7B&0xFF);
+		logger.debug("注册请求应答:"+ByteUtil.bytesToHexString(respPackage));
+		return respPackage;
+	}
+
+}

+ 31 - 0
src/main/java/com/hb/proj/server/ProcessWaveTask.java

@@ -0,0 +1,31 @@
+package com.hb.proj.server;
+
+import java.util.Date;
+
+import com.hb.proj.oil.service.OilService;
+import com.hb.xframework.util.ApplicationContextUtils;
+
+public class ProcessWaveTask implements Runnable {
+
+	private String dtuNum;
+	
+    private Date dataTime; //变化时的数据的采集时间
+	
+	private Date preDataTime; //上一数据的采集时间
+	
+	private OilService  oilService;
+	
+	public ProcessWaveTask(String dtuNum,Date dataTime,Date preDataTime){
+		this.dtuNum=dtuNum;
+		this.dataTime=dataTime;
+		this.preDataTime=preDataTime;
+		this.oilService=ApplicationContextUtils.getBean("oilService", OilService.class);
+	}
+	
+	@Override
+	public void run() {
+		
+		this.oilService.deleteWave(dtuNum, preDataTime, dataTime);
+	}
+
+}

+ 20 - 0
src/main/java/com/hb/proj/server/TaskExecutor.java

@@ -0,0 +1,20 @@
+package com.hb.proj.server;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+//解析任务执行器
+public class TaskExecutor {
+
+	private static final ExecutorService  executor=Executors.newCachedThreadPool(); //所有新任务直接创建线程处理,线程数量受系统限制
+	
+
+	
+	public static void execute(Runnable task){
+		executor.execute(task);
+	}
+	
+	public static void shutdown(){
+		executor.shutdown();
+	}
+}

+ 120 - 0
src/main/java/com/hb/proj/server/VolumeCalibrater.java

@@ -0,0 +1,120 @@
+package com.hb.proj.server;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.hb.proj.oil.service.OilService;
+import com.hb.xframework.util.ApplicationContextUtils;
+
+/**
+ * 由液位标定为容量
+ * @author hb
+ *
+ */
+public class VolumeCalibrater {
+
+	public static Logger logger=LoggerFactory.getLogger(VolumeCalibrater.class);
+	
+	private static Map<String,MeterBindBO> meters=new HashMap<String,MeterBindBO>(200); //总共约200个油量设备,key:meterNum(dtuNum),val:油箱规格主键、carId等关联数据
+	
+	public static Map<String,MeterBindBO> getMeters(){
+		return meters;
+	}
+	
+	
+	/**
+	 * 加载新设备到标定对象
+	 */
+	public synchronized  static void init(){
+		logger.info("init volume calibrater");
+		OilService service=ApplicationContextUtils.getBean("oilService",OilService.class);
+		
+		List<MeterBindBO> carMeters=service.loadMeterBox();
+		if(carMeters==null){
+			return;
+		}
+		Map<String,OilBoxBO>  boxRst=service.loadOilBox();
+		if(boxRst==null){
+			boxRst=new HashMap<String,OilBoxBO>();
+		}
+		for(MeterBindBO meter : carMeters){
+			meter.setOilBox(boxRst.get(meter.getBoxId()));
+			meters.put(meter.getMeterNum(), meter);
+		}
+		
+	}
+	
+	/**
+	 * 对从3318采集的数据进行入库前的处理(填充关联数据、体积换算)
+	 * @param oilData
+	 */
+	public static void fillCarId(OilBO  oilData){
+		MeterBindBO meter=meters.get(oilData.getDtuNum());
+		if(meter!=null){
+			oilData.setCarId(meter.getCarId());
+			oilData.setMountId(meter.getMountId());
+			if(meter.getVolumeRatio()!=null&&meter.getVolumeRatio().doubleValue()>0&&oilData.getOilVolume()!=null){
+				oilData.setOilVolume(oilData.getOilVolume().doubleValue()*meter.getVolumeRatio().doubleValue());
+			}
+		}
+		
+	}
+	
+	/**
+	 * 对从DTU采集的数据进行入库前的处理(填充关联数据、体积换算)
+	 * @param oilData
+	 */
+	public static void fillVolume(OilBO  oilData){
+		if(oilData==null){
+			return ;
+		}
+		MeterBindBO meter=meters.get(oilData.getDtuNum());
+		if(meter!=null){
+			oilData.setCarId(meter.getCarId());
+			oilData.setMountId(meter.getMountId());
+		}
+		oilData.setOilVolume(getVolume(meter,oilData.getLiquidHeight()));
+		
+	}
+	
+	/**
+	 * 根据液位高度计算容量
+	 * @param meterNum
+	 * @param liquidHeight
+	 * @return
+	 */
+	public static Double getVolume(MeterBindBO meter,Double liquidHeight){
+		if(liquidHeight==null||liquidHeight.isNaN()||meter==null||meter.getOilBox()==null){
+			return null;
+		}
+		
+		OilBoxBO box=meter.getOilBox();
+		double liquidh=liquidHeight.doubleValue()/100.0; //0.1mm转为cm
+		
+		/*if(meter.getVolumeRatio()!=null&&meter.getVolumeRatio().doubleValue()>0){  //配置有体积线性标定系数(相当于是截面积dm^2),则优先使用
+			return meter.getVolumeRatio().doubleValue()*liquidh/10;  //液位进一步转换为分米,计算结果就直接是升
+		}*/
+		
+		double volume=box.getInnerLen()*box.getInnerWidth()*liquidh;
+		double diff=box.getBtmDiffVolume().doubleValue();
+		if(liquidh>=box.getBtmHeight().doubleValue()){
+			volume=(volume-diff)/1000.0;  //毫升转升
+		}
+		else{ //近似为椎体计算容积比例
+			double h=box.getBtmHeight(),th=h-liquidh;
+			diff=diff*(1-Math.pow(th/h, 3));
+			volume=(volume-diff)/1000.0;
+		}
+		//二次标定
+		if(meter.getVolumeRatio()!=null&&meter.getVolumeRatio().doubleValue()>0){
+			volume=volume*meter.getVolumeRatio().doubleValue();
+		}
+		
+		return volume;
+		
+	}
+}

+ 8 - 0
src/main/java/com/hb/proj/utils/CodeConstant.java

@@ -0,0 +1,8 @@
+package com.hb.proj.utils;
+
+public class CodeConstant {
+
+	public static final  String SORT_WORK_AREA="4028cde37c0b409f017c0b4245730002";
+	
+	public static final  String SORT_OTHER_CONFIG="4028cde37ffc8c59017ffc8c59eb0000";
+}

+ 97 - 0
src/main/java/com/hb/proj/utils/JsonOutUtils.java

@@ -0,0 +1,97 @@
+package com.hb.proj.utils;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+
+
+public class JsonOutUtils {
+
+	public static void preprocessTreeNodes(List<Map<String,Object>> nodes,String depth){
+		preprocessTreeNodes(nodes,depth,depth);
+	}
+	
+	public static void preprocessTreeNodes(List<Map<String,Object>> nodes,String depth,String defLeafSkin){
+		for(Map<String,Object> itm : nodes){
+			if(((Number)itm.get("childCount")).intValue()>0){
+				itm.put("isParent", true);
+				itm.put("typeEnd", false);
+				itm.put("iconSkin",null);
+			}
+			else if(StringUtils.isNotEmpty(depth)&&!depth.equals(itm.get("nodeType"))){
+				itm.put("isParent", true);
+				itm.put("typeEnd", true);
+				itm.put("iconSkin",null);
+			}
+			else{
+				itm.put("isParent", false);
+				itm.put("typeEnd", true);
+				itm.put("iconSkin", itm.get("iconSkin")!=null?itm.get("iconSkin"):defLeafSkin);
+			}
+			
+		}
+	}
+
+	
+	public static void writeToResponse(HttpServletResponse response,String message){
+		writeToResponse(response,message,null);
+	}
+	
+	public static void writeToResponse(HttpServletResponse response,String message,String contentType){
+		PrintWriter out=null;
+		try {
+			response.setContentType(contentType!=null?contentType:"text/text;charset=UTF-8");
+			out = response.getWriter();
+			out.write(message);
+			
+		} catch (Exception ex) {
+			ex.printStackTrace();
+		}finally{
+			if (out != null) {
+				out.flush();
+				out.close();
+			}
+		}
+	}
+	
+	public static void returnData(HttpServletResponse response,Object data){
+		writeToResponse(response,JSON.toJSONString(data));
+	}
+	
+	public static void returnOkWithData(HttpServletResponse response,Object data){
+		  returnJsonResult(response,true,data,null);
+	}
+	
+	public static void returnError(HttpServletResponse response,String exception){
+		  returnJsonResult(response,false,null,exception);
+	}
+	 
+	 public static void returnJsonResult(HttpServletResponse response,boolean success,Object data,String exception){
+		 StringBuilder json=new StringBuilder("{\"success\":");
+		 json.append(success?"true":"false");
+		 if(data!=null){
+			 
+			 json.append(",\"data\":"+JSONObject.toJSONString(data,SerializerFeature.WriteMapNullValue));  
+		 }
+		 if(exception!=null){
+			 json.append(",\"exception\":\""+exception+"\"");
+		 }
+		 json.append("}");
+		 writeToResponse(response,json.toString());
+	 }
+	 
+	 public static void returnOk(HttpServletResponse response){
+		 writeToResponse(response,"{\"success\":true}");
+	 }
+	
+	
+	
+}

+ 96 - 0
src/main/java/com/hb/proj/utils/OkhttpUtils.java

@@ -0,0 +1,96 @@
+package com.hb.proj.utils;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.Call;
+import okhttp3.FormBody;
+import okhttp3.FormBody.Builder;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class OkhttpUtils {
+
+	private static OkHttpClient singleton;
+	
+	
+	private OkhttpUtils(){
+
+    }
+	
+	public static OkHttpClient getInstance() {
+        if (singleton == null)
+        {
+            synchronized (OkhttpUtils.class)
+            {
+                if (singleton == null)
+                {
+                    singleton = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).build();
+                }
+            }
+        }
+        return singleton;
+    }
+	
+	
+	public static String get(String url){
+		try{
+			OkHttpClient client=OkhttpUtils.getInstance();
+			Request req=new Request.Builder()
+			.url(url)
+			.get()
+			.build();
+			Response response = client.newCall(req).execute();
+		    if (response.isSuccessful()) {
+		        return response.body().string();
+		    } else {
+		        return null;
+		    }
+
+	
+		}
+		catch (Exception e) {
+		      e.printStackTrace();
+		      return null;
+	     }
+		
+	}
+	
+	public static String post(String url,Map<String,String> args){
+		return post(url,args,null);
+	}
+	
+	
+	public static String post(String url,Map<String,String> args,Map<String,String> headers){
+	  try {
+		
+		OkHttpClient client=OkhttpUtils.getInstance();
+		Builder b=new FormBody.Builder();
+		for(String key : args.keySet()){
+			b.add(key, args.get(key));
+		}
+		
+		okhttp3.Request.Builder rb=new Request.Builder();
+		if(headers!=null&&headers.size()>0){
+			for(String h : headers.keySet()){
+				rb.addHeader(h, headers.get(h));
+			}
+		}
+		
+		Request req=rb.url(url)
+        .post(b.build())
+        .build();
+        final Call call = client.newCall(req);
+        Response rmtResp=call.execute();
+        return rmtResp.isSuccessful()?rmtResp.body().string():null;
+	    } catch (Exception e) {
+	      e.printStackTrace();
+	      return null;
+        }
+       
+	}
+	
+	
+
+}

+ 21 - 0
src/main/java/com/hb/proj/utils/RequestUtils.java

@@ -0,0 +1,21 @@
+package com.hb.proj.utils;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class RequestUtils {
+
+	public static Map<String, Object> getParams(HttpServletRequest request){
+		 Map<String, Object> requestMap = new HashMap<String, Object>();
+		 Enumeration<?> enum_term = request.getParameterNames();
+		 String paramName=null;
+		 while (enum_term.hasMoreElements()) {
+		   paramName = (String) enum_term.nextElement();
+		   requestMap.put(paramName, request.getParameter(paramName));
+		}
+		 return requestMap;
+	}
+}

+ 47 - 0
src/main/java/com/hb/proj/utils/WebAppListener.java

@@ -0,0 +1,47 @@
+package com.hb.proj.utils;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.hb.proj.server.OilChecker;
+import com.hb.proj.server.OilMonitorServer;
+import com.hb.proj.server.VolumeCalibrater;
+
+public class WebAppListener implements ServletContextListener {
+
+	public static Logger logger=LoggerFactory.getLogger(WebAppListener.class);
+	
+	private OilMonitorServer oilMonitorServer;
+			
+	@Override
+	public void contextInitialized(ServletContextEvent sce) {
+		logger.info("开始启动油量采集服务");
+		VolumeCalibrater.init();
+		OilChecker.init();
+		
+		String port=sce.getServletContext().getInitParameter("port");
+		int nioPort=StringUtils.isNotEmpty(port)?Integer.parseInt(port):51663;
+		oilMonitorServer=new OilMonitorServer(nioPort);
+		oilMonitorServer.start();
+		
+		
+		
+		
+	}
+
+	@Override
+	public void contextDestroyed(ServletContextEvent sce) {
+		logger.info("关闭油量采集服务");
+		if(oilMonitorServer!=null){
+			oilMonitorServer.stopServer();
+		}
+
+	}
+	
+	
+
+}

+ 36 - 0
src/main/java/logback.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>  
+<configuration>  
+<property name="LOG_HOME" value="F:/lhloggingcar/apache-tomcat-7.0.106/weblog"></property>
+<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">  
+    <encoder>  
+      <pattern>[%thread] %d{yyyy-MM-dd HH:mm:ss.SSS} %-8level %logger{36} - %msg%n</pattern>  
+    </encoder>  
+</appender>  
+
+<appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">   
+        <Encoding>UTF-8</Encoding>   
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            日志文件输出的文件名
+            <FileNamePattern>${LOG_HOME}/fsy.log.%d{yyyy-MM-dd}.log</FileNamePattern>   
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>   
+        <layout class="ch.qos.logback.classic.PatternLayout">  
+            格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-8level %logger{50} - %msg%n   
+            </pattern>   
+       </layout> 
+        日志文件最大的大小
+       <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+         <MaxFileSize>5MB</MaxFileSize>
+       </triggeringPolicy>
+</appender>
+
+ 
+  <logger name="com.hb.proj.server" level="INFO">
+    <appender-ref ref="FILE" />
+  </logger>
+  
+  <root level="INFO">
+    <appender-ref ref="STDOUT" />
+  </root>  
+</configuration> 

+ 4 - 0
src/main/resources/config/sys_config.properties

@@ -0,0 +1,4 @@
+# the system administrator
+hdOilAPI=http://223.75.76.159:52467/iVehicleGPS/oilthird/loadLastOilData.hd
+
+

+ 92 - 0
src/main/webapp/WEB-INF/config/applicationContext.xml

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xmlns:aop="http://www.springframework.org/schema/aop"    
+     xmlns:tx="http://www.springframework.org/schema/tx"
+     xmlns:context="http://www.springframework.org/schema/context"
+	 xsi:schemaLocation="http://www.springframework.org/schema/beans
+		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+		http://www.springframework.org/schema/tx     
+        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd    
+		http://www.springframework.org/schema/aop     
+        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
+		http://www.springframework.org/schema/context
+		http://www.springframework.org/schema/context/spring-context-3.0.xsd"  default-autowire="byName">
+ 
+ 
+	
+	<bean id="dataSource" class="com.hb.xframework.util.HotBasicDataSource" destroy-method="close">
+		<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
+		<property name="url" value="jdbc:mysql://localhost:3306/lh_logging_car?useOldAliasMetadataBehavior=true"/>
+		<property name="username" value="root"/>
+		<property name="password" value=""/>
+		<property name="maxWait" value="3000"/>
+		<property name="maxIdle" value="1"/>
+		<property name="maxActive" value="2"/>
+		<property name="testOnBorrow" value="true"/>
+		<property name="validationQuery" value="select 1 from DUAL"/>
+		
+	</bean>
+	
+	<!-- <bean id="dataSource" class="com.hb.xframework.util.HotBasicDataSource" destroy-method="close">
+		<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
+		<property name="url" value="jdbc:mysql://10.242.168.251:3306/lh_logging_car"/>
+		<property name="username" value="root"/>
+		<property name="password" value="lh_logging_car"/>
+		<property name="maxWait" value="3000"/>
+		<property name="maxIdle" value="1"/>
+		<property name="maxActive" value="2"/>
+		<property name="testOnBorrow" value="true"/>
+		<property name="validationQuery" value="select 1 from DUAL"/>
+		
+	</bean> -->
+	
+	
+	
+  
+   
+  
+   
+	
+	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
+        <property name="dataSource" ref="dataSource"></property>  
+   </bean>  
+       
+   
+    
+   <tx:advice id="txAdvice" transaction-manager="txManager">  
+       <tx:attributes>  
+           <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>  
+           <tx:method name="create*" propagation="REQUIRED" rollback-for="Exception"/>  
+           <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>  
+           <tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/> 
+           <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>  
+           <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>  <!-- rollback-for="Exception" -->
+           <tx:method name="*" read-only="true"/>
+      </tx:attributes>  
+    </tx:advice>  
+    
+      <!-- 声明式事务管理 -->  
+    <aop:config>  
+       <aop:advisor pointcut="(execution(* com.hb.proj.*.service.*.*(..)))" advice-ref="txAdvice" /> 
+       
+    </aop:config>  
+    
+	
+	<context:component-scan base-package="com.hb.proj.*.dao,com.hb.proj.*.service"/>
+	
+    
+	  
+	
+	
+	<bean id="SpringJdbcDAO" class="com.hb.xframework.dao.core.SpringJdbcDAO">
+	  <property name="dialect" value="MySQL"></property>
+	</bean>
+	
+	
+   
+    <bean  class="com.hb.xframework.util.ApplicationContextUtils"/>  
+    
+    
+    
+</beans>

+ 37 - 0
src/main/webapp/WEB-INF/config/spring-servlet.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:mvc="http://www.springframework.org/schema/mvc"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:p="http://www.springframework.org/schema/p"
+	xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:task="http://www.springframework.org/schema/task"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+		http://www.springframework.org/schema/mvc
+        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
+		http://www.springframework.org/schema/context
+		http://www.springframework.org/schema/context/spring-context-3.0.xsd
+		http://www.springframework.org/schema/task 
+		http://www.springframework.org/schema/task/spring-task-3.0.xsd">
+
+	<context:component-scan
+		base-package="com.hb.proj.*.controller"/>
+		
+     <!--   <mvc:annotation-driven/> 不配置时,由spring的Dispather.properties配置文件指定默认组件,两者配置的组件一致-->
+    <mvc:annotation-driven/> 
+    
+	<bean id="viewResolver"
+		class="org.springframework.web.servlet.view.UrlBasedViewResolver">
+		<property name="viewClass"
+			value="org.springframework.web.servlet.view.JstlView" />
+		<property name="prefix" value="/" />
+		<property name="suffix" value=".jsp" />
+	</bean>
+	
+	<!--<task:scheduler id="scheduler" pool-size="2"/>
+	<task:scheduled-tasks scheduler="scheduler"> 
+	  <task:scheduled ref="scheduledTaskOilQuery" method="addCollectCarOil" cron="0 */1 * * * ?"/> 
+	  <task:scheduled ref="scheduledReportOil" method="createOilReport" cron="0 0 0 16 * ?"/> 
+	</task:scheduled-tasks>-->
+
+</beans>

+ 72 - 0
src/main/webapp/WEB-INF/web.xml

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app id="WebApp_ID" version="2.4"
+	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+	<display-name>lhLoggingOilMonitor</display-name>
+	<context-param>
+	  <param-name>contextConfigLocation</param-name>
+	  <param-value>/WEB-INF/config/applicationContext.xml</param-value>
+	</context-param>
+	
+	 <listener>  
+      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
+     </listener>
+     
+     <listener>  
+      <listener-class>com.hb.proj.utils.WebAppListener</listener-class>  
+     </listener>
+     
+	<servlet>
+	<servlet-name>dispatcherServlet</servlet-name>
+	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+	<init-param>
+		<param-name>contextConfigLocation</param-name>
+		<param-value>
+				/WEB-INF/config/spring-servlet.xml
+		</param-value>
+	</init-param>
+	<load-on-startup>1</load-on-startup>
+    </servlet>
+
+	<servlet-mapping>
+		<servlet-name>dispatcherServlet</servlet-name>
+		<url-pattern>*.do</url-pattern>
+	</servlet-mapping>
+	
+	
+	<welcome-file-list>
+	 <welcome-file>/default.html</welcome-file>
+	</welcome-file-list>
+
+    
+	
+	<filter>
+		<filter-name>Set Character Encoding</filter-name>
+		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
+		<init-param>
+			<param-name>encoding</param-name>
+			<param-value>UTF-8</param-value>
+		</init-param>
+		
+	</filter>
+	<filter-mapping>
+		<filter-name>Set Character Encoding</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+	
+	
+ 
+	
+	
+	
+	
+
+   
+	
+	
+	
+	
+	
+	
+	
+</web-app>

+ 11 - 0
src/main/webapp/default.html

@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+		<title>油量采集</title>
+	</head>
+	<body>
+	   油量采集程序
+	</body>
+</html>