Commit 3387d4db3de1adda54b2ed3bc5dd2ff718cc0a53

Authored by panzh
0 parents

update...

Showing 49 changed files with 4731 additions and 0 deletions

Too many changes to show.

To preserve performance only 49 of 148 files are displayed.

.gitignore 0 → 100644
  1 +++ a/.gitignore
  1 +.classpath
  2 +.project
  3 +.springBeans
  4 +.settings/*
  5 +/target/*
  6 +node_modules/
  7 +test_junitReport/
  8 +test_coverage/
  9 +.idea
  10 +.DS_Store
  11 +*.iml
  12 +tmp
  13 +
  14 +# git忽略空文件夹,按照惯例,空文件夹下放置.gitkeep文件避免文件夹被忽略不上传。
  15 +!.gitkeep
  16 +/target/
... ...
README.md 0 → 100644
  1 +++ a/README.md
  1 +
  2 +恩,,,我是信息发布
0 3 \ No newline at end of file
... ...
pom.xml 0 → 100644
  1 +++ a/pom.xml
  1 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3 +
  4 + <modelVersion>4.0.0</modelVersion>
  5 + <groupId>com.bsth</groupId>
  6 + <artifactId>info_publish</artifactId>
  7 + <version>0.0.1-SNAPSHOT</version>
  8 + <packaging>jar</packaging>
  9 +
  10 + <parent>
  11 + <groupId>org.springframework.boot</groupId>
  12 + <artifactId>spring-boot-starter-parent</artifactId>
  13 + <version>2.0.1.RELEASE</version>
  14 + </parent>
  15 +
  16 + <dependencies>
  17 + <dependency>
  18 + <groupId>org.springframework.boot</groupId>
  19 + <artifactId>spring-boot-starter-web</artifactId>
  20 + </dependency>
  21 +
  22 + <dependency>
  23 + <groupId>org.springframework.boot</groupId>
  24 + <artifactId>spring-boot-starter-tomcat</artifactId>
  25 + <scope>provided</scope>
  26 + </dependency>
  27 + <dependency>
  28 + <groupId>javax.servlet</groupId>
  29 + <artifactId>javax.servlet-api</artifactId>
  30 + <version>3.1.0</version>
  31 + <scope>provided</scope>
  32 + </dependency>
  33 + <dependency>
  34 + <groupId>org.springframework.boot</groupId>
  35 + <artifactId>spring-boot-starter-data-jpa</artifactId>
  36 + </dependency>
  37 + <dependency>
  38 + <groupId>org.springframework.boot</groupId>
  39 + <artifactId>spring-boot-starter-aop</artifactId>
  40 + </dependency>
  41 +
  42 + <dependency>
  43 + <groupId>org.springframework</groupId>
  44 + <artifactId>spring-context-support</artifactId>
  45 + </dependency>
  46 + <dependency>
  47 + <groupId>org.springframework.boot</groupId>
  48 + <artifactId>spring-boot-starter-websocket</artifactId>
  49 + </dependency>
  50 + <dependency>
  51 + <groupId>mysql</groupId>
  52 + <artifactId>mysql-connector-java</artifactId>
  53 + </dependency>
  54 +
  55 + <dependency>
  56 + <groupId>joda-time</groupId>
  57 + <artifactId>joda-time</artifactId>
  58 + </dependency>
  59 + <dependency>
  60 + <groupId>com.alibaba</groupId>
  61 + <artifactId>fastjson</artifactId>
  62 + <version>1.2.4</version>
  63 + </dependency>
  64 +
  65 + <dependency>
  66 + <groupId>org.apache.httpcomponents</groupId>
  67 + <artifactId>httpclient</artifactId>
  68 + </dependency>
  69 +
  70 +
  71 + <dependency>
  72 + <groupId>org.apache.commons</groupId>
  73 + <artifactId>commons-dbcp2</artifactId>
  74 + <version>2.1.1</version>
  75 + </dependency>
  76 + <dependency>
  77 + <groupId>commons-lang</groupId>
  78 + <artifactId>commons-lang</artifactId>
  79 + <version>2.6</version>
  80 + </dependency>
  81 + <dependency>
  82 + <groupId>org.apache.commons</groupId>
  83 + <artifactId>commons-lang3</artifactId>
  84 + <version>3.4</version>
  85 + </dependency>
  86 +
  87 + <dependency>
  88 + <groupId>org.springframework.boot</groupId>
  89 + <artifactId>spring-boot-starter-data-redis</artifactId>
  90 + </dependency>
  91 + <dependency>
  92 + <groupId>com.google.guava</groupId>
  93 + <artifactId>guava</artifactId>
  94 + <version>19.0</version>
  95 + </dependency>
  96 +
  97 + <dependency>
  98 + <groupId>org.apache.mina</groupId>
  99 + <artifactId>mina-core</artifactId>
  100 + <version>2.0.13</version>
  101 + </dependency>
  102 +
  103 + <dependency>
  104 + <groupId>com.mchange</groupId>
  105 + <artifactId>c3p0</artifactId>
  106 + <version>0.9.5.2</version>
  107 + </dependency>
  108 + <dependency>
  109 + <groupId>com.github.stuxuhai</groupId>
  110 + <artifactId>jpinyin</artifactId>
  111 + <version>1.1.8</version>
  112 + </dependency>
  113 +
  114 + <dependency>
  115 + <groupId>org.apache.commons</groupId>
  116 + <artifactId>commons-math3</artifactId>
  117 + <version>3.6.1</version>
  118 + </dependency>
  119 + </dependencies>
  120 +
  121 + <build>
  122 + <plugins>
  123 + <plugin>
  124 + <artifactId>maven-compiler-plugin</artifactId>
  125 + <version>3.5.1</version><!--$NO-MVN-MAN-VER$ -->
  126 + <configuration>
  127 + <source>1.8</source>
  128 + <target>1.8</target>
  129 + </configuration>
  130 + </plugin>
  131 + <plugin>
  132 + <artifactId>maven-war-plugin</artifactId>
  133 + <version>2.2</version><!--$NO-MVN-MAN-VER$ -->
  134 + <configuration>
  135 + <failOnMissingWebXml>false</failOnMissingWebXml>
  136 + </configuration>
  137 + </plugin>
  138 + <plugin>
  139 + <groupId>org.springframework.boot</groupId>
  140 + <artifactId>spring-boot-maven-plugin</artifactId>
  141 + </plugin>
  142 + </plugins>
  143 + <resources>
  144 + <resource>
  145 + <directory>src/main/resources</directory>
  146 + <filtering>false</filtering>
  147 + </resource>
  148 + </resources>
  149 + </build>
  150 + <repositories>
  151 + <repository>
  152 + <id>spring-snapshots</id>
  153 + <url>http://repo.spring.io/snapshot</url>
  154 + <snapshots>
  155 + <enabled>true</enabled>
  156 + </snapshots>
  157 + </repository>
  158 + <repository>
  159 + <id>spring-milestones</id>
  160 + <url>http://repo.spring.io/milestone</url>
  161 + </repository>
  162 + </repositories>
  163 + <pluginRepositories>
  164 + <pluginRepository>
  165 + <id>spring-snapshots</id>
  166 + <url>http://repo.spring.io/snapshot</url>
  167 + </pluginRepository>
  168 + <pluginRepository>
  169 + <id>spring-milestones</id>
  170 + <url>http://repo.spring.io/milestone</url>
  171 + </pluginRepository>
  172 + </pluginRepositories>
  173 +
  174 + <properties>
  175 + <start-class>com.bsth.Application</start-class>
  176 + </properties>
  177 +</project>
... ...
src/main/java/com/bsth/Application.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/Application.java
  1 +package com.bsth;
  2 +
  3 +import org.springframework.boot.SpringApplication;
  4 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  5 +
  6 +import java.util.concurrent.Executors;
  7 +import java.util.concurrent.ScheduledExecutorService;
  8 +
  9 +@SpringBootApplication
  10 +public class Application {
  11 +
  12 + public static ScheduledExecutorService mainServices = Executors.newScheduledThreadPool(6);
  13 +
  14 + public static void main(String[] args) {
  15 + SpringApplication.run(Application.class, args);
  16 + }
  17 +}
0 18 \ No newline at end of file
... ...
src/main/java/com/bsth/StartCommand.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/StartCommand.java
  1 +package com.bsth;
  2 +
  3 +import com.bsth.client.ClientApp;
  4 +import com.bsth.data.BasicCacheData;
  5 +import com.bsth.data.geo.loader.thread.DataLoadThread;
  6 +import com.bsth.data.gps.process.DataMainProcessor;
  7 +import com.bsth.data.history.HistoryConsumeTimeDataHandler;
  8 +import com.bsth.data.schedule.ScheduleCacheData;
  9 +import org.slf4j.Logger;
  10 +import org.slf4j.LoggerFactory;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +import org.springframework.boot.CommandLineRunner;
  13 +import org.springframework.stereotype.Component;
  14 +
  15 +import java.util.concurrent.ScheduledExecutorService;
  16 +import java.util.concurrent.TimeUnit;
  17 +
  18 +
  19 +/**
  20 + * 随应用启动运行
  21 + *
  22 + * @author PanZhao
  23 + */
  24 +@Component
  25 +public class StartCommand implements CommandLineRunner {
  26 +
  27 + @Autowired
  28 + DataLoadThread fixedLoadCacheThread;
  29 +
  30 + @Autowired
  31 + BasicCacheData.RefreshDataThead basicRefreshThead;
  32 +
  33 + @Autowired
  34 + ScheduleCacheData.RefreshScheduleCacheThread refreshScheduleCacheThread;
  35 +
  36 + @Autowired
  37 + DataMainProcessor dataMainProcessor;
  38 + @Autowired
  39 + ClientApp clientApp;
  40 + @Autowired
  41 + HistoryConsumeTimeDataHandler historyConsumeTimeDataHandler;
  42 +
  43 + Logger logger = LoggerFactory.getLogger(this.getClass());
  44 +
  45 + @Override
  46 + public void run(String... arg0) {
  47 +
  48 + try {
  49 + ScheduledExecutorService sexec = Application.mainServices;
  50 +
  51 + //加载基础对照信息
  52 + basicRefreshThead.run();
  53 + sexec.scheduleWithFixedDelay(basicRefreshThead, 60 * 60, 60 * 60, TimeUnit.SECONDS);
  54 + //加载 geo 数据(增量)
  55 + logger.info("load geo data start...");
  56 + fixedLoadCacheThread.run();
  57 + logger.info("load geo data end...");
  58 + sexec.scheduleWithFixedDelay(fixedLoadCacheThread, 60 * 300, 60 * 300, TimeUnit.SECONDS);
  59 +
  60 + //定时刷新班次信息
  61 + sexec.scheduleWithFixedDelay(refreshScheduleCacheThread, 60, 60 * 2, TimeUnit.SECONDS);
  62 +
  63 + //gps socket client
  64 + clientApp.init();
  65 + //gps 数据处理
  66 + dataMainProcessor.start();
  67 +
  68 + //历史站点耗时数据
  69 + historyConsumeTimeDataHandler.start();
  70 + } catch (Exception e) {
  71 + e.printStackTrace();
  72 + }
  73 + }
  74 +}
... ...
src/main/java/com/bsth/WebAppConfiguration.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/WebAppConfiguration.java
  1 +package com.bsth;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.context.annotation.Bean;
  6 +import org.springframework.context.annotation.ComponentScan;
  7 +import org.springframework.context.annotation.Configuration;
  8 +import org.springframework.web.filter.CharacterEncodingFilter;
  9 +import org.springframework.web.filter.HttpPutFormContentFilter;
  10 +import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
  11 +
  12 +import javax.servlet.Filter;
  13 +
  14 +@Configuration
  15 +@ComponentScan
  16 +public class WebAppConfiguration {
  17 +
  18 + Logger logger = LoggerFactory.getLogger(this.getClass());
  19 +
  20 + /**
  21 + * @Title: httpPutFormContentFilter
  22 + * @Description: TODO(弥补浏览器不支持PUT/DELETE,对携带 _method 参数的请求进行转换)
  23 + */
  24 + @Bean
  25 + public Filter httpPutFormContentFilter() {
  26 + return new HttpPutFormContentFilter();
  27 + }
  28 +
  29 + /**
  30 + * @Title: characterEncodingFilter
  31 + * @Description: TODO(编码过滤器)
  32 + */
  33 + @Bean
  34 + public Filter characterEncodingFilter(){
  35 + return new CharacterEncodingFilter("UTF-8");
  36 + }
  37 +
  38 +
  39 + /**
  40 + * 增加websocket的输出缓冲区
  41 + * @return
  42 + */
  43 + @Bean
  44 + public ServletServerContainerFactoryBean createServletServerContainerFactoryBean() {
  45 + ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
  46 + container.setMaxTextMessageBufferSize(52768);
  47 + container.setMaxBinaryMessageBufferSize(52768);
  48 + logger.info("Websocket factory returned");
  49 + return container;
  50 + }
  51 +}
... ...
src/main/java/com/bsth/client/ClientApp.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/ClientApp.java
  1 +package com.bsth.client;
  2 +
  3 +import com.bsth.client.pd.codec.PdMessageCodecFactory;
  4 +import com.bsth.client.pd.handler.PdClientHandler;
  5 +import com.bsth.client.pd.protocol.Pd_31_0;
  6 +import com.bsth.util.ConfigUtil;
  7 +import org.apache.mina.core.future.ConnectFuture;
  8 +import org.apache.mina.core.future.WriteFuture;
  9 +import org.apache.mina.core.session.IdleStatus;
  10 +import org.apache.mina.core.session.IoSession;
  11 +import org.apache.mina.core.session.IoSessionConfig;
  12 +import org.apache.mina.filter.codec.ProtocolCodecFilter;
  13 +import org.apache.mina.filter.logging.LogLevel;
  14 +import org.apache.mina.filter.logging.LoggingFilter;
  15 +import org.apache.mina.transport.socket.nio.NioSocketConnector;
  16 +import org.slf4j.Logger;
  17 +import org.slf4j.LoggerFactory;
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.stereotype.Component;
  20 +
  21 +import java.net.InetSocketAddress;
  22 +import java.util.concurrent.ExecutorService;
  23 +import java.util.concurrent.Executors;
  24 +import java.util.concurrent.ScheduledExecutorService;
  25 +import java.util.concurrent.TimeUnit;
  26 +
  27 +
  28 +@Component
  29 +public class ClientApp {
  30 +
  31 + private static NioSocketConnector pdDataConnector;
  32 +
  33 + @Autowired
  34 + private PdClientHandler pdClient;
  35 + @Autowired
  36 + GpsDataBuffer gpsBeforeBuffer;
  37 +
  38 + static Logger logger = LoggerFactory.getLogger(ClientApp.class);
  39 + private static ExecutorService exec;
  40 +
  41 + private ScheduledExecutorService sexec;
  42 +
  43 + public static boolean dconnect(String device) {
  44 + boolean flag = false;
  45 + try {
  46 + ConnectFuture con = pdDataConnector.connect(new InetSocketAddress(ConfigUtil.get("gps.server.pd"), Integer.parseInt(ConfigUtil.get("gps.port.pd"))));
  47 + con.awaitUninterruptibly();
  48 + IoSession session = con.getSession();
  49 + session.setAttribute("deviceId", device);
  50 + com.bsth.client.pd.protocol.PdMessage msg = new com.bsth.client.pd.protocol.PdMessage();
  51 + Pd_31_0 body = new Pd_31_0();
  52 + body.setFunCode((short)0x15);
  53 + body.setLineId(0);
  54 + body.setDeviceId(device);
  55 + msg.setMessageBody(body);
  56 + msg.setVersion((short)1);
  57 + msg.setSerialNo((short)1);
  58 + msg.setCommandType((short)0x31);
  59 + byte[] bytes = msg.write();
  60 + WriteFuture write = session.write(bytes);
  61 + write.awaitUninterruptibly();
  62 + flag = true;
  63 +
  64 + logger.info("dconnect...");
  65 + pdSession = session;
  66 + } catch (Exception e) {
  67 + e.printStackTrace();
  68 + }
  69 + return flag;
  70 + }
  71 +
  72 + public static void pdconnect(final String device) {
  73 + exec.submit(() -> {
  74 + // TODO Auto-generated method stub
  75 + long now = System.currentTimeMillis();
  76 + boolean flag = false;
  77 + while (!flag) {
  78 + flag = dconnect(device);
  79 + }
  80 + System.out.println("设备编号:" + device + "重连, cost time: " + (System.currentTimeMillis() - now));
  81 + });
  82 + }
  83 +
  84 + public static void pdreconn(){
  85 + pdconnect(ConfigUtil.get("forward.device.name"));
  86 + }
  87 +
  88 + public void destroy(){
  89 + try {
  90 + logger.warn("socket client destroy!!!");
  91 + exec.shutdownNow();
  92 + sexec.shutdownNow();
  93 +
  94 + pdDataConnector.dispose(true);
  95 + } catch (Exception e) {
  96 + logger.error("", e);
  97 + }
  98 + }
  99 +
  100 + public void init() {
  101 + logger.warn("socket client init...");
  102 + exec = Executors.newFixedThreadPool(3);
  103 + sexec = Executors.newSingleThreadScheduledExecutor(r -> {
  104 + // TODO Auto-generated method stub
  105 + Thread t = new Thread(r);
  106 + t.setName("SessionCheckExecutor");
  107 + return t;
  108 + });
  109 + sexec.scheduleAtFixedRate(new SessionChecker(), 20, 20, TimeUnit.SECONDS);
  110 + /*******************************浦东********************************/
  111 + pdDataConnector = new NioSocketConnector();
  112 +
  113 + LoggingFilter log = new LoggingFilter();
  114 + log.setMessageReceivedLogLevel(LogLevel.DEBUG);
  115 + pdDataConnector.getFilterChain().addLast("logger", log);
  116 +
  117 + pdDataConnector.getFilterChain().addLast("codec",
  118 + new ProtocolCodecFilter(new PdMessageCodecFactory()));
  119 +
  120 + IoSessionConfig config = pdDataConnector.getSessionConfig();
  121 +
  122 + config.setReadBufferSize(4096);
  123 + config.setWriteTimeout(10000);
  124 + config.setWriterIdleTime(60000);
  125 +
  126 + config.setIdleTime(IdleStatus.BOTH_IDLE, 60);
  127 +
  128 + pdDataConnector.setHandler(pdClient);
  129 +
  130 + pdconnect(ConfigUtil.get("forward.device.name"));
  131 + }
  132 +
  133 +
  134 + static IoSession pdSession;
  135 +
  136 + final class SessionChecker implements Runnable {
  137 +
  138 + @Override
  139 + public void run() {
  140 + try {
  141 +
  142 + if(!pdSession.isActive()){
  143 + logger.warn("浦东网关注销");
  144 + ClientApp.pdreconn();
  145 + }
  146 + } catch (Exception e) {
  147 + logger.error("SessionChecker异常", e);
  148 + }
  149 + }
  150 + }
  151 +}
0 152 \ No newline at end of file
... ...
src/main/java/com/bsth/client/GpsDataBuffer.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/GpsDataBuffer.java
  1 +package com.bsth.client;
  2 +
  3 +import com.bsth.Application;
  4 +import com.bsth.entity.GpsEntity;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +import org.springframework.beans.factory.annotation.Autowired;
  8 +import org.springframework.boot.CommandLineRunner;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import java.util.ArrayList;
  12 +import java.util.List;
  13 +import java.util.concurrent.ConcurrentLinkedQueue;
  14 +import java.util.concurrent.TimeUnit;
  15 +
  16 +/**
  17 + * 定时定距数据
  18 + */
  19 +@Component
  20 +public class GpsDataBuffer implements CommandLineRunner {
  21 +
  22 + static ConcurrentLinkedQueue<GpsEntity> linkedList = new ConcurrentLinkedQueue();
  23 + static final int MAX_SIZE = 4000 * 20;
  24 + static int size = 0;
  25 +
  26 + static Logger logger = LoggerFactory.getLogger(GpsDataBuffer.class);
  27 +
  28 + public void put(GpsEntity gps) {
  29 + try {
  30 + if(null == gps)
  31 + return;
  32 +
  33 + linkedList.add(gps);
  34 + size++;
  35 + } catch (Exception e) {
  36 + logger.error("", e);
  37 + }
  38 + }
  39 +
  40 + public static List<GpsEntity> pollAll() {
  41 + List<GpsEntity> rs = new ArrayList<>(300);
  42 + GpsEntity gps;
  43 +
  44 + while (true) {
  45 + gps = linkedList.poll();
  46 + if (gps == null) {
  47 + size = 0;
  48 + break;
  49 + }
  50 + rs.add(gps);
  51 + }
  52 +
  53 + //logger.info("poll size: " + rs.size() + " -current size: " + size);
  54 + return rs;
  55 + }
  56 +
  57 + /**
  58 + * 清理数据,保持最大 MAX_SIZE 个数的元素
  59 + */
  60 + public static void clear() {
  61 + if (size <= MAX_SIZE)
  62 + return;
  63 + int len = size - MAX_SIZE;
  64 + for (int j = 0; j < len; j++) {
  65 + linkedList.poll();
  66 + size--;
  67 + }
  68 + logger.info("clear size: " + len + " -current size: " + size);
  69 + }
  70 +
  71 + @Autowired
  72 + BufferSizeCheck bufferSizeCheck;
  73 +
  74 + @Override
  75 + public void run(String... args) {
  76 + Application.mainServices.scheduleWithFixedDelay(bufferSizeCheck, 60, 30, TimeUnit.SECONDS);
  77 + }
  78 +
  79 + @Component
  80 + public static class BufferSizeCheck extends Thread {
  81 +
  82 + @Override
  83 + public void run() {
  84 + GpsDataBuffer.clear();
  85 + }
  86 + }
  87 +}
0 88 \ No newline at end of file
... ...
src/main/java/com/bsth/client/common/ThreadLocalDateUtil.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/common/ThreadLocalDateUtil.java
  1 +package com.bsth.client.common;
  2 +
  3 +import java.text.DateFormat;
  4 +import java.text.ParseException;
  5 +import java.text.SimpleDateFormat;
  6 +import java.util.Date;
  7 +
  8 +public class ThreadLocalDateUtil {
  9 + private static final String date_format = "yyyyMMddHHmmss";
  10 + private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>();
  11 +
  12 + public static DateFormat getDateFormat()
  13 + {
  14 + DateFormat df = threadLocal.get();
  15 + if(df==null){
  16 + df = new SimpleDateFormat(date_format);
  17 + threadLocal.set(df);
  18 + }
  19 + return df;
  20 + }
  21 +
  22 + public static String formatDate(Date date) throws ParseException {
  23 + return getDateFormat().format(date);
  24 + }
  25 +
  26 + public static Date parse(String strDate) throws ParseException {
  27 + return getDateFormat().parse(strDate);
  28 + }
  29 +}
... ...
src/main/java/com/bsth/client/msg/IMessage.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/msg/IMessage.java
  1 +package com.bsth.client.msg;
  2 +
  3 +public interface IMessage extends IMessageIO {
  4 +
  5 + public IMessageBody getMessageBody();
  6 +}
... ...
src/main/java/com/bsth/client/msg/IMessageBody.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/msg/IMessageBody.java
  1 +package com.bsth.client.msg;
  2 +
  3 +public interface IMessageBody extends IMessageIO {
  4 +
  5 + public String getDeviceId();
  6 +
  7 + public long getTimestamp();
  8 +}
... ...
src/main/java/com/bsth/client/msg/IMessageIO.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/msg/IMessageIO.java
  1 +package com.bsth.client.msg;
  2 +
  3 +public interface IMessageIO {
  4 +
  5 + public void read(byte[] bytes);
  6 +
  7 + public byte[] write();
  8 +}
... ...
src/main/java/com/bsth/client/pd/codec/MessageDecoder.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/codec/MessageDecoder.java
  1 +package com.bsth.client.pd.codec;
  2 +
  3 +import com.bsth.client.pd.protocol.PdMessage;
  4 +import org.apache.mina.core.buffer.IoBuffer;
  5 +import org.apache.mina.core.session.IoSession;
  6 +import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
  7 +import org.apache.mina.filter.codec.ProtocolDecoderOutput;
  8 +import org.slf4j.Logger;
  9 +import org.slf4j.LoggerFactory;
  10 +
  11 +
  12 +public class MessageDecoder extends CumulativeProtocolDecoder {
  13 +
  14 + Logger log = LoggerFactory.getLogger(MessageDecoder.class);
  15 +
  16 + @Override
  17 + protected boolean doDecode(IoSession session, IoBuffer in,
  18 + ProtocolDecoderOutput out) throws Exception {
  19 + // TODO Auto-generated method stub
  20 + while (in.remaining() > 3) {
  21 + in.mark();
  22 + byte head1 = in.get(), head2 = in.get(), lenh = in.get(), lenl = in.get();
  23 + int len = ((lenh & 0xff) << 8) + (lenl & 0xff);
  24 + if ((head1 & 0xff) == 0xfa && (head2 & 0xff) == 0xf5) {
  25 + if (in.remaining() > len) {
  26 + try {
  27 + byte[] bytes = new byte[len + 1];
  28 + in.get(bytes);
  29 + PdMessage msg = new PdMessage();
  30 + msg.read(bytes);
  31 + out.write(msg);
  32 +
  33 + //日志纪录
  34 + //log.info("pd receive: " + ConvertUtil.bytesToHexString(bytes));
  35 + }catch (Exception e){
  36 + log.error("pd message decoder:", e);
  37 + }
  38 + } else {
  39 + in.reset();
  40 + return false;
  41 + }
  42 + }
  43 + }
  44 + return false;
  45 + }
  46 +
  47 + /*private static String toHexString(byte[] bytes) {
  48 + StringBuilder sb = new StringBuilder();
  49 + for (byte b : bytes) {
  50 + sb.append(Integer.toHexString(b & 0xff) + "|");
  51 + }
  52 + return sb.toString();
  53 + }*/
  54 +}
... ...
src/main/java/com/bsth/client/pd/codec/MessageEncoder.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/codec/MessageEncoder.java
  1 +package com.bsth.client.pd.codec;
  2 +
  3 +import org.apache.mina.core.buffer.IoBuffer;
  4 +import org.apache.mina.core.session.IoSession;
  5 +import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
  6 +import org.apache.mina.filter.codec.ProtocolEncoderOutput;
  7 +
  8 +
  9 +public class MessageEncoder extends ProtocolEncoderAdapter {
  10 +
  11 + @Override
  12 + public void encode(IoSession session, Object message,
  13 + ProtocolEncoderOutput out) throws Exception {
  14 + // TODO Auto-generated method stub
  15 + IoBuffer buf = IoBuffer.allocate(1024).setAutoExpand(true);
  16 + buf.put((byte[])message);
  17 + buf.flip();
  18 + out.write(buf);
  19 + /*if ("true".equals(ConfigUtil.getProperty("protocoldown", "true"))) {
  20 + DownProtocolDataService.getInstance().write((byte[])message);
  21 + }*/
  22 + }
  23 +
  24 +}
... ...
src/main/java/com/bsth/client/pd/codec/PdMessageCodecFactory.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/codec/PdMessageCodecFactory.java
  1 +package com.bsth.client.pd.codec;
  2 +
  3 +import org.apache.mina.core.session.IoSession;
  4 +import org.apache.mina.filter.codec.ProtocolCodecFactory;
  5 +import org.apache.mina.filter.codec.ProtocolDecoder;
  6 +import org.apache.mina.filter.codec.ProtocolEncoder;
  7 +
  8 +public class PdMessageCodecFactory implements ProtocolCodecFactory {
  9 +
  10 + private ProtocolEncoder encoder;
  11 + private ProtocolDecoder decoder;
  12 +
  13 + public PdMessageCodecFactory() {
  14 + encoder = new MessageEncoder();
  15 + decoder = new MessageDecoder();
  16 + }
  17 +
  18 + @Override
  19 + public ProtocolEncoder getEncoder(IoSession session) throws Exception {
  20 + // TODO Auto-generated method stub
  21 + return encoder;
  22 + }
  23 +
  24 + @Override
  25 + public ProtocolDecoder getDecoder(IoSession session) throws Exception {
  26 + // TODO Auto-generated method stub
  27 + return decoder;
  28 + }
  29 +
  30 +}
... ...
src/main/java/com/bsth/client/pd/common/ConvertUtil.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/common/ConvertUtil.java
  1 +package com.bsth.client.pd.common;
  2 +
  3 +import com.bsth.client.common.ThreadLocalDateUtil;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
  6 +
  7 +import java.text.ParseException;
  8 +import java.util.Arrays;
  9 +import java.util.Calendar;
  10 +import java.util.Date;
  11 +
  12 +
  13 +public class ConvertUtil {
  14 +
  15 + private final static Logger log = LoggerFactory.getLogger(ConvertUtil.class);
  16 +
  17 + public static int bcd2int(byte[] bytes, int start, int len) {
  18 + if (len > 4 || len == 0)
  19 + throw new IllegalArgumentException("bcd2int 字节数不符合要求");
  20 + String temp = "";
  21 + for (int i = 0;i < len;i++) {
  22 + int val = bytes[start + i] & 0xff;
  23 + if (val < 10) temp += 0;
  24 + temp += Integer.toHexString(val);
  25 + }
  26 + return Integer.parseInt(temp);
  27 + }
  28 +
  29 + public static byte[] int2bcd(int val, int len) {
  30 + if (len > 4 || len == 0)
  31 + throw new IllegalArgumentException("int2bcd 字节数不符合要求");
  32 + byte[] result = new byte[len];
  33 + for (int i = len - 1;i > -1;i--) {
  34 + result[i] = (byte)Integer.parseInt(val%100 + "", 16);
  35 + val = val/100;
  36 + }
  37 + return result;
  38 + }
  39 +
  40 + public static long bcd2long(byte[] bytes, int start, int len) {
  41 + if (len > 8 || len == 0)
  42 + throw new IllegalArgumentException("bcd2long 字节数不符合要求");
  43 + String temp = "";
  44 + for (int i = 0;i < len;i++) {
  45 + int val = bytes[start + i] & 0xff;
  46 + if (val < 10) temp += 0;
  47 + temp += Integer.toHexString(val);
  48 + }
  49 + return Long.parseLong(temp);
  50 + }
  51 +
  52 + public static byte[] long2bcd(long val, int len) {
  53 + if (len > 8 || len == 0)
  54 + throw new IllegalArgumentException("long2bcd 字节数不符合要求");
  55 + byte[] result = new byte[len];
  56 + for (int i = len - 1;i > -1;i--) {
  57 + result[i] = (byte)Integer.parseInt(val%100 + "", 16);
  58 + val = val/100;
  59 + }
  60 + return result;
  61 + }
  62 +
  63 + public static String ascii2string(byte[] bytes, int start, int len) {
  64 + return new String(Arrays.copyOfRange(bytes, start, start + len));
  65 + }
  66 +
  67 + public static byte[] string2ascii(String val, int len) {
  68 + byte[] result = new byte[len];
  69 + byte[] bytes = val.getBytes();
  70 + if (bytes.length > len && len != 0)
  71 + throw new IllegalArgumentException("string2ascii 参数不符合要求");
  72 + if (len != 0)
  73 + for (int i = 0, l = bytes.length;i < l;i++) result[i] = bytes[i];
  74 + else return bytes;
  75 + return result;
  76 + }
  77 +
  78 + public static long bcd2timestamp(byte[] bytes, int start) {
  79 + String temp = "20";
  80 + for (int i = 0;i < 6;i++) {
  81 + int val = bytes[start + i] & 0xff;
  82 + if (val < 10) temp += 0;
  83 + temp += Integer.toHexString(val);
  84 + }
  85 + Date date = null;
  86 + try {
  87 + date = ThreadLocalDateUtil.parse(temp);
  88 + } catch (ParseException e) {
  89 + log.error("协议中时间数据异常:" + temp);
  90 + }
  91 + if (date != null) return date.getTime();
  92 + return -1;
  93 + }
  94 +
  95 + public static byte[] timestamp2bcd(long val) {
  96 + byte[] result = new byte[6];
  97 + Calendar c = Calendar.getInstance();
  98 + c.setTime(new Date(val));
  99 + result[0] = (byte)(Integer.parseInt(c.get(Calendar.YEAR)%100 + "", 16));
  100 + result[1] = (byte)(Integer.parseInt(c.get(Calendar.MONTH) + 1 + "", 16));
  101 + result[2] = (byte)Integer.parseInt(c.get(Calendar.DAY_OF_MONTH) + "", 16);
  102 + result[3] = (byte)Integer.parseInt(c.get(Calendar.HOUR_OF_DAY) + "", 16);
  103 + result[4] = (byte)Integer.parseInt(c.get(Calendar.MINUTE) + "", 16);
  104 + result[5] = (byte)Integer.parseInt(c.get(Calendar.SECOND) + "", 16);
  105 + return result;
  106 + }
  107 +
  108 + public static byte[] int2hex(int val, int len) {
  109 + if (len < 1)
  110 + throw new IllegalArgumentException("int2hex len 参数不符合要求");
  111 + byte[] result = new byte[len];
  112 + for (int i = 0;i < len;i++) {
  113 + result[len - 1 - i] = (byte)(val%100);
  114 + val = val/100;
  115 + }
  116 +
  117 + return result;
  118 + }
  119 +
  120 + public static int bytes2int(byte[] bytes, int start, int len) {
  121 + int val = 0;
  122 + for (int i = 0; i < len; i++) {
  123 + int shift = (len - 1 - i) * 8;
  124 + val += (bytes[start + i] & 0x0000FF) << shift;
  125 + }
  126 +
  127 + return val;
  128 + }
  129 +
  130 + /* Convert byte[] to hex string.这里我们可以将byte转换成int,然后利用Integer.toHexString(int)来转换成16进制字符串。
  131 + * @param src byte[] data
  132 +* @return hex string
  133 +*/
  134 + public static String bytesToHexString(byte[] src){
  135 + StringBuilder stringBuilder = new StringBuilder("");
  136 + if (src == null || src.length <= 0) {
  137 + return null;
  138 + }
  139 + for (int i = 0; i < src.length; i++) {
  140 + int v = src[i] & 0xFF;
  141 + String hv = Integer.toHexString(v);
  142 + if (hv.length() < 2) {
  143 + stringBuilder.append(0);
  144 + }
  145 + stringBuilder.append(hv);
  146 + }
  147 + return stringBuilder.toString();
  148 + }
  149 +}
... ...
src/main/java/com/bsth/client/pd/handler/PdClientHandler.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/handler/PdClientHandler.java
  1 +package com.bsth.client.pd.handler;
  2 +
  3 +import com.bsth.client.ClientApp;
  4 +import com.bsth.client.GpsDataBuffer;
  5 +import com.bsth.client.msg.IMessageBody;
  6 +import com.bsth.client.pd.protocol.PdMessage;
  7 +import com.bsth.client.pd.protocol.Pd_41_0;
  8 +import com.bsth.client.pd.protocol.Pd_42_0;
  9 +import com.bsth.entity.GpsEntity;
  10 +import org.apache.mina.core.service.IoHandlerAdapter;
  11 +import org.apache.mina.core.session.IdleStatus;
  12 +import org.apache.mina.core.session.IoSession;
  13 +import org.apache.mina.transport.socket.SocketSessionConfig;
  14 +import org.slf4j.Logger;
  15 +import org.slf4j.LoggerFactory;
  16 +import org.springframework.beans.factory.annotation.Autowired;
  17 +import org.springframework.stereotype.Service;
  18 +
  19 +import java.io.IOException;
  20 +
  21 +
  22 +@Service
  23 +public class PdClientHandler extends IoHandlerAdapter{
  24 +
  25 + private final static Logger log = LoggerFactory.getLogger(PdClientHandler.class);
  26 +
  27 + @Autowired
  28 + GpsDataBuffer gpsBeforeBuffer;
  29 +
  30 + @Override
  31 + public void sessionCreated(IoSession session) {
  32 + SocketSessionConfig cfg = (SocketSessionConfig) session.getConfig();
  33 + cfg.setSoLinger(0);
  34 + }
  35 +
  36 + @Override
  37 + public void sessionOpened(IoSession session) {
  38 +
  39 + }
  40 +
  41 + @Override
  42 + public void sessionClosed(IoSession session) {
  43 + String deviceId = (String)session.getAttribute("deviceId");
  44 + if (deviceId != null) {
  45 + log.info("连网关设备编号:" + deviceId + "断开连接");
  46 + log.warn(deviceId + "网关设备注销");
  47 +
  48 + ClientApp.dconnect(deviceId);
  49 + } else {
  50 + log.info("连网关设备编号:" + deviceId + "断开连接");
  51 + }
  52 + }
  53 +
  54 + @Override
  55 + public void sessionIdle(IoSession session, IdleStatus status) {
  56 + log.warn("pd sessionIdle");
  57 + session.closeNow();
  58 + }
  59 +
  60 + @Override
  61 + public void exceptionCaught(IoSession session, Throwable cause) {
  62 + if (cause instanceof IOException) session.closeNow();
  63 + log.error("PdClientHandler异常:", cause);
  64 + }
  65 +
  66 + @Override
  67 + public void messageReceived(IoSession session, Object message) {
  68 + PdMessage msg = (PdMessage)message;
  69 + IMessageBody body = msg.getMessageBody();
  70 + if (body != null) {
  71 + if (0x31 == msg.getCommandType()) {
  72 + log.debug("设备编号:" + body.getDeviceId() + "建立连接");
  73 + }
  74 + else if(0x41 == msg.getCommandType()){
  75 + Pd_41_0 pd41 = (Pd_41_0)msg.getMessageBody();
  76 +
  77 + GpsEntity gps = GpsEntity.getInstance(pd41.getInfo(), msg.getVersion());
  78 + if(gps != null)
  79 + gpsBeforeBuffer.put(gps);
  80 + }
  81 + else if(0x42 == msg.getCommandType()){
  82 + Pd_42_0 pd42 = (Pd_42_0)msg.getMessageBody();
  83 +
  84 + GpsEntity gps = GpsEntity.getInstance(pd42.getInfo(), msg.getVersion());
  85 + if(gps != null)
  86 + gpsBeforeBuffer.put(gps);
  87 + }
  88 + }
  89 + }
  90 +
  91 + @Override
  92 + public void messageSent(IoSession session, Object message) {
  93 +
  94 + }
  95 +}
... ...
src/main/java/com/bsth/client/pd/protocol/BasicInfo.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/protocol/BasicInfo.java
  1 +package com.bsth.client.pd.protocol;
  2 +
  3 +
  4 +import com.bsth.client.pd.common.ConvertUtil;
  5 +
  6 +import java.nio.ByteBuffer;
  7 +import java.util.Date;
  8 +
  9 +
  10 +public class BasicInfo {
  11 +
  12 + private int cityCode;
  13 + private short industryCode;
  14 + private short companyCode;
  15 + private String deviceId;
  16 + private int lineId;
  17 + private int driverEmpNo;
  18 + private short carparkSerialNo;
  19 + private String carparkNo;
  20 + private short stopSerialNo;
  21 + private String stopNo;
  22 + // 经度 bcd 5 0121245333表示经度为121度24.5333分
  23 + private long carLon;
  24 + // 维度
  25 + private int carLat;
  26 + private long timestamp;
  27 + // 速度(传感器)bcd 2 保留一位小数 km/h
  28 + private short speedSensor;
  29 + // 速度(gps)bcd 2 保留一位小数 km/h
  30 + private short speedGps;
  31 + // 方向 bcd 2 0-359.5 保留一位小数
  32 + private short direction;
  33 + // 车内温度 bcd 2 第一字节为符号 00为正 01为负 后一字节为温度
  34 + private short inTemp;
  35 + // 营运状态 hex 4高位在前
  36 + // 第一字节位 7 GPS有/无效|6 场外/内|5 起终点站外/内|4 上/下行|3 已知/未知|2站外/站内|1 营运/非营运|0 在线路上/不在
  37 + // 7=1时其它位无效|0=1时3,4,5无效 第二字节6,7无效|3=1时2,4无效 第二字节6,7无效
  38 + // 第二字节位 7 非/标杆点|6 非/中途校时点|5 点/熄火|4 实时/缓存数据|3 门开/关|2 预留|1 非/包车|0预留
  39 + // 1=1时 第一字节0-6无效 6,7无效
  40 + // 后两个字节保留
  41 + private long serviceState;
  42 + // 调控状态
  43 + private long controlState;
  44 + // 累计里程 km 保留两位小数
  45 + private int totalMiles;
  46 + // 水温
  47 + private byte waterTemp;
  48 + // 油耗 (第一个字节 + 第二个字节/10)升/百公里
  49 + private int oilConsumption;
  50 + // 发动机转速 100转/秒
  51 + private int engineSpeed;
  52 + private float lon;
  53 + private float lat;
  54 +
  55 + private boolean inOutStopFlag = false;
  56 +
  57 + public void read(byte[] bytes, int idx) {
  58 + // TODO Auto-generated method stub
  59 + ByteBuffer buf = ByteBuffer.wrap(bytes);
  60 + cityCode = ConvertUtil.bcd2int(bytes, idx, 3); idx += 3;
  61 + industryCode = (short)(bytes[idx] & 0xff); idx++;
  62 + companyCode = (short)(bytes[idx] & 0xff); idx++;
  63 + deviceId = ConvertUtil.ascii2string(bytes, idx, 8); idx += 8;
  64 + lineId = ConvertUtil.bcd2int(bytes, idx, 3); idx += 3;
  65 + driverEmpNo = ConvertUtil.bcd2int(bytes, idx, 4); idx +=4;
  66 + carparkSerialNo = (short)(bytes[idx] & 0xff); idx++;
  67 + carparkNo = ConvertUtil.ascii2string(bytes, idx, 8); idx += 8;
  68 + stopSerialNo = (short)(bytes[idx] & 0xff); idx++;
  69 + stopNo = ConvertUtil.ascii2string(bytes, idx, 8).trim(); idx += 8;
  70 + carLon = ConvertUtil.bcd2long(bytes, idx, 5); lon = (int)(carLon/1000000) + carLon%1000000/600000f; idx += 5;
  71 + carLat = ConvertUtil.bcd2int(bytes, idx, 4); lat = carLat/1000000 + carLat%1000000/600000f; idx += 4;
  72 + timestamp = ConvertUtil.bcd2timestamp(bytes, idx); idx += 6;
  73 + speedSensor = (short)ConvertUtil.bcd2int(bytes, idx, 2); idx += 2;
  74 + speedGps = (short)ConvertUtil.bcd2int(bytes, idx, 2); idx += 2;
  75 + direction = (short)(ConvertUtil.bcd2int(bytes, idx, 2)); idx += 2;
  76 + inTemp = (short)ConvertUtil.bcd2int(bytes, idx, 2); idx += 2;
  77 + serviceState = buf.getInt(idx) & 0xffffffff; idx += 4;
  78 + controlState = buf.getInt(idx) & 0xffffffff; idx += 4;
  79 + totalMiles = ConvertUtil.bcd2int(bytes, idx, 4); idx += 4;
  80 + waterTemp = bytes[idx]; idx++;
  81 + oilConsumption = ConvertUtil.bcd2int(bytes, idx, 4); idx += 4;
  82 + engineSpeed = buf.getShort(idx) & 0xffff; idx += 2;
  83 + }
  84 +
  85 + public byte[] write() {
  86 + ByteBuffer buf = ByteBuffer.allocate(80);
  87 + buf.put(ConvertUtil.int2bcd(cityCode, 3));
  88 + buf.put((byte)industryCode);
  89 + buf.put((byte)companyCode);
  90 + buf.put(ConvertUtil.string2ascii(deviceId, 8));
  91 + buf.put(ConvertUtil.int2bcd(lineId, 3));
  92 + buf.put(ConvertUtil.int2bcd(driverEmpNo, 4));
  93 + buf.put((byte)carparkSerialNo);
  94 + buf.put(ConvertUtil.string2ascii(carparkNo, 8));
  95 + buf.put((byte)stopSerialNo);
  96 + buf.put(ConvertUtil.string2ascii(stopNo, 8));
  97 + buf.put(ConvertUtil.long2bcd(carLon, 5));
  98 + buf.put(ConvertUtil.long2bcd(carLat, 4));
  99 + buf.put(ConvertUtil.timestamp2bcd(timestamp));
  100 + buf.put(ConvertUtil.int2bcd(speedSensor, 2));
  101 + buf.put(ConvertUtil.int2bcd(speedGps, 2));
  102 + buf.put(ConvertUtil.int2bcd(direction, 2));
  103 + buf.put(ConvertUtil.int2bcd(inTemp, 2));
  104 + buf.putInt((int)serviceState);
  105 + buf.putInt((int)controlState);
  106 + buf.put(ConvertUtil.int2bcd(totalMiles, 4));
  107 + buf.put(waterTemp);
  108 + buf.put(ConvertUtil.int2bcd(oilConsumption, 2));
  109 + buf.putShort((short)engineSpeed);
  110 +
  111 + return buf.array();
  112 + }
  113 +
  114 + public String getDeviceId() {
  115 + // TODO Auto-generated method stub
  116 + return deviceId;
  117 + }
  118 +
  119 + public int getCityCode() {
  120 + return cityCode;
  121 + }
  122 +
  123 + public short getIndustryCode() {
  124 + return industryCode;
  125 + }
  126 +
  127 + public short getCompanyCode() {
  128 + return companyCode;
  129 + }
  130 +
  131 + public int getLineId() {
  132 + return lineId;
  133 + }
  134 +
  135 + public int getDriverEmpNo() {
  136 + return driverEmpNo;
  137 + }
  138 +
  139 + public short getCarparkSerialNo() {
  140 + return carparkSerialNo;
  141 + }
  142 +
  143 + public String getCarparkNo() {
  144 + return carparkNo;
  145 + }
  146 +
  147 + public short getStopSerialNo() {
  148 + return stopSerialNo;
  149 + }
  150 +
  151 + public String getStopNo() {
  152 + return stopNo;
  153 + }
  154 +
  155 + public long getCarLon() {
  156 + return carLon;
  157 + }
  158 +
  159 + public int getCarLat() {
  160 + return carLat;
  161 + }
  162 +
  163 + public long getTimestamp() {
  164 + return timestamp;
  165 + }
  166 +
  167 + public short getSpeedSensor() {
  168 + return speedSensor;
  169 + }
  170 +
  171 + public short getSpeedGps() {
  172 + return speedGps;
  173 + }
  174 +
  175 + public short getDirection() {
  176 + return direction;
  177 + }
  178 +
  179 + public short getInTemp() {
  180 + return inTemp;
  181 + }
  182 +
  183 + public long getServiceState() {
  184 + return serviceState;
  185 + }
  186 +
  187 + public long getControlState() {
  188 + return controlState;
  189 + }
  190 +
  191 + public int getTotalMiles() {
  192 + return totalMiles;
  193 + }
  194 +
  195 + public byte getWaterTemp() {
  196 + return waterTemp;
  197 + }
  198 +
  199 + public int getOilConsumption() {
  200 + return oilConsumption;
  201 + }
  202 +
  203 + public int getEngineSpeed() {
  204 + return engineSpeed;
  205 + }
  206 +
  207 + public float getLon() {
  208 + return lon;
  209 + }
  210 +
  211 + public void setLon(float lon) {
  212 + this.lon = lon;
  213 + }
  214 +
  215 + public float getLat() {
  216 + return lat;
  217 + }
  218 +
  219 + public void setLat(float lat) {
  220 + this.lat = lat;
  221 + }
  222 +
  223 + public void setStopNo(String stopNo) {
  224 + this.stopNo = stopNo;
  225 + }
  226 +
  227 + public byte getGpsValid() {
  228 + return (byte)(((serviceState & 0x80000000) == 0x80000000) ? 1 : 0);
  229 + }
  230 +
  231 + /**
  232 + * 获取车辆在场外/内
  233 + * @return -1无效 0场外1场内
  234 + */
  235 + public byte getInOrOutCarpark() {
  236 + if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000
  237 + || (serviceState & 0x01000000) == 0x01000000) return -1;
  238 + return (byte)(((serviceState & 0x40000000) == 0x40000000) ? 1 : 0);
  239 + }
  240 +
  241 + public void setInOrOutCarpark(boolean inOutFlag) {
  242 + if (inOutFlag) serviceState |= 0x40000000;
  243 + else serviceState &= 0xbfffffff;
  244 + }
  245 +
  246 + /**
  247 + * 获取车辆在起终点站外/内
  248 + * @return -1无效 0起终点站外1起终点站内
  249 + */
  250 + public byte getInOrOutStartEnd() {
  251 + if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000
  252 + || (serviceState & 0x01000000) == 0x01000000) return -1;
  253 + return (byte)(((serviceState & 0x20000000) == 0x20000000) ? 1 : 0);
  254 + }
  255 +
  256 + /**
  257 + * 获取车辆线路上下行
  258 + * @return -1无效 0上行 1下行
  259 + */
  260 + public byte getUpOrDown() {
  261 + /*if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000
  262 + || (serviceState & 0x01000000) == 0x01000000
  263 + || (serviceState & 0x08000000) == 0x08000000) return -1;*/
  264 + return (byte)(((serviceState & 0x10000000) == 0x10000000) ? 1 : 0);
  265 + }
  266 +
  267 + public void setUpOrDown(boolean upOrDown) {
  268 + if (!upOrDown) serviceState |= 0x10000000;
  269 + else serviceState &= 0xefffffff;
  270 + }
  271 +
  272 + /**
  273 + * 获取车辆在站外/内
  274 + * @return -1无效 0站外 1站内
  275 + */
  276 + public byte getInOrOutStop() {
  277 + if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000
  278 + || (serviceState & 0x01000000) == 0x01000000
  279 + || (serviceState & 0x08000000) == 0x08000000) return -1;
  280 + return (byte)(((serviceState & 0x04000000) == 0x04000000) ? 1 : 0);
  281 + }
  282 +
  283 + public void setInOrOutStop(boolean isInOrOutStop) {
  284 + inOutStopFlag = true;
  285 + if (isInOrOutStop) serviceState |= 0x04000000;
  286 + else serviceState &= 0xfbffffff;
  287 + }
  288 +
  289 + /**
  290 + * 获取运营状态
  291 + * @return -1无效 0运营 1未运营
  292 + */
  293 + public byte getService() {
  294 + //if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000) return -1;
  295 + return (byte)(((serviceState & 0x02000000) == 0x02000000) ? 1 : 0);
  296 + }
  297 +
  298 + public void setService(boolean service) {
  299 + if (!service) serviceState |= 0x02000000;
  300 + else serviceState &= 0xfdffffff;
  301 + }
  302 +
  303 + /**
  304 + * 获得车辆状态
  305 + * @return 0点火 1熄火
  306 + */
  307 + public byte getVehicleState() {
  308 + return (byte)(((serviceState & 0x00200000) == 0x00200000) ? 1 : 0);
  309 + }
  310 +
  311 + public void setInOutStopFlag(boolean inOutStopFlag) {
  312 + this.inOutStopFlag = inOutStopFlag;
  313 + }
  314 +
  315 + public boolean getInOutStopFlag() {
  316 + return inOutStopFlag;
  317 + }
  318 +
  319 + public String toString() {
  320 + Date d = new Date();d.setTime(timestamp);
  321 + StringBuilder sb = new StringBuilder();
  322 + sb.append("城市代码:").append(cityCode)
  323 + .append("行业代码:").append(industryCode)
  324 + .append("公司代码:").append(companyCode)
  325 + .append("设备号:").append(deviceId)
  326 + .append("线路编号:").append(lineId)
  327 + .append("驾驶员工号:").append(driverEmpNo)
  328 + .append("停车场序列号:").append(carparkSerialNo)
  329 + .append("停车场编号:").append(carparkNo)
  330 + .append("站点序列号").append(stopSerialNo)
  331 + .append("站点编号:").append(stopNo)
  332 + .append("经度:").append(carLon)
  333 + .append("维度:").append(carLat)
  334 + .append("时间戳:").append(d)
  335 + .append("速度(传感器):").append(speedSensor)
  336 + .append("速度(gps)").append(speedGps)
  337 + .append("方向:").append(direction)
  338 + .append("车内温度:").append(inTemp)
  339 + .append("营运状态:").append(serviceState)
  340 + .append("调控状态:").append(controlState)
  341 + .append("总里程:").append(totalMiles)
  342 + .append("水温:").append(waterTemp)
  343 + .append("油耗:").append(oilConsumption)
  344 + .append("发动机速度:").append(engineSpeed);
  345 +
  346 + return sb.toString();
  347 + }
  348 + /* ----------------------------------------------------- */
  349 +
  350 + public void setCityCode(int cityCode) {
  351 + this.cityCode = cityCode;
  352 + }
  353 +
  354 + public void setIndustryCode(short industryCode) {
  355 + this.industryCode = industryCode;
  356 + }
  357 +
  358 + public void setCompanyCode(short companyCode) {
  359 + this.companyCode = companyCode;
  360 + }
  361 +
  362 + public void setDeviceId(String deviceId) {
  363 + this.deviceId = deviceId;
  364 + }
  365 +
  366 + public void setLineId(int lineId) {
  367 + this.lineId = lineId;
  368 + }
  369 +
  370 + public void setDriverEmpNo(int driverEmpNo) {
  371 + this.driverEmpNo = driverEmpNo;
  372 + }
  373 +
  374 + public void setCarparkSerialNo(short carparkSerialNo) {
  375 + this.carparkSerialNo = carparkSerialNo;
  376 + }
  377 +
  378 + public void setCarparkNo(String carparkNo) {
  379 + this.carparkNo = carparkNo;
  380 + }
  381 +
  382 + public void setStopSerialNo(short stopSerialNo) {
  383 + this.stopSerialNo = stopSerialNo;
  384 + }
  385 +
  386 + public void setCarLon(long carLon) {
  387 + this.carLon = carLon;
  388 + }
  389 +
  390 + public void setCarLat(int carLat) {
  391 + this.carLat = carLat;
  392 + }
  393 +
  394 + public void setTimestamp(long timestamp) {
  395 + this.timestamp = timestamp;
  396 + }
  397 +
  398 + public void setSpeedSensor(short speedSensor) {
  399 + this.speedSensor = speedSensor;
  400 + }
  401 +
  402 + public void setSpeedGps(short speedGps) {
  403 + this.speedGps = speedGps;
  404 + }
  405 +
  406 + public void setDirection(short direction) {
  407 + this.direction = direction;
  408 + }
  409 +
  410 + public void setInTemp(short inTemp) {
  411 + this.inTemp = inTemp;
  412 + }
  413 +
  414 + public void setServiceState(long serviceState) {
  415 + this.serviceState = serviceState;
  416 + }
  417 +
  418 + public void setControlState(long controlState) {
  419 + this.controlState = controlState;
  420 + }
  421 +
  422 + public void setTotalMiles(int totalMiles) {
  423 + this.totalMiles = totalMiles;
  424 + }
  425 +
  426 + public void setWaterTemp(byte waterTemp) {
  427 + this.waterTemp = waterTemp;
  428 + }
  429 +
  430 + public void setOilConsumption(int oilConsumption) {
  431 + this.oilConsumption = oilConsumption;
  432 + }
  433 +
  434 + public void setEngineSpeed(int engineSpeed) {
  435 + this.engineSpeed = engineSpeed;
  436 + }
  437 +}
... ...
src/main/java/com/bsth/client/pd/protocol/PdFactory.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/protocol/PdFactory.java
  1 +package com.bsth.client.pd.protocol;
  2 +
  3 +import com.bsth.client.msg.IMessageBody;
  4 +
  5 +public class PdFactory {
  6 +
  7 + public static IMessageBody create(int commandType, byte[] data) {
  8 + String pkgName = PdFactory.class.getPackage().getName();
  9 + IMessageBody body = null;
  10 + try {
  11 + Class<?> cls = Class.forName(pkgName + ".Pd_" + Integer.toHexString(commandType).toUpperCase() + "_0");
  12 + body = (IMessageBody)cls.newInstance();
  13 + body.read(data);
  14 + } catch (ClassNotFoundException e) {
  15 + // TODO Auto-generated catch block
  16 + //e.printStackTrace();
  17 + } catch (InstantiationException e) {
  18 + // TODO Auto-generated catch block
  19 + e.printStackTrace();
  20 + } catch (IllegalAccessException e) {
  21 + // TODO Auto-generated catch block
  22 + e.printStackTrace();
  23 + }
  24 + return body;
  25 + }
  26 +}
... ...
src/main/java/com/bsth/client/pd/protocol/PdMessage.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/protocol/PdMessage.java
  1 +package com.bsth.client.pd.protocol;
  2 +
  3 +import com.bsth.client.msg.IMessage;
  4 +import com.bsth.client.msg.IMessageBody;
  5 +
  6 +import java.nio.ByteBuffer;
  7 +import java.util.Arrays;
  8 +
  9 +public class PdMessage implements IMessage {
  10 +
  11 + private short version;
  12 + private short serialNo;
  13 + private short commandType;
  14 + private IMessageBody messageBody;
  15 + private byte checkSum;
  16 +
  17 + public short getVersion() {
  18 + return version;
  19 + }
  20 +
  21 + public void setVersion(short version) {
  22 + this.version = version;
  23 + }
  24 +
  25 + public short getSerialNo() {
  26 + return serialNo;
  27 + }
  28 +
  29 + public void setSerialNo(short serialNo) {
  30 + this.serialNo = serialNo;
  31 + }
  32 +
  33 + public short getCommandType() {
  34 + return commandType;
  35 + }
  36 +
  37 + public void setCommandType(short commandType) {
  38 + this.commandType = commandType;
  39 + }
  40 +
  41 + public IMessageBody getMessageBody() {
  42 + return messageBody;
  43 + }
  44 +
  45 + public void setMessageBody(IMessageBody messageBody) {
  46 + this.messageBody = messageBody;
  47 + }
  48 +
  49 + public byte getCheckSum() {
  50 + return checkSum;
  51 + }
  52 +
  53 + public void setCheckSum(byte checkSum) {
  54 + this.checkSum = checkSum;
  55 + }
  56 +
  57 + public void read(byte[] data) {
  58 + int idx = 0, len = data.length;
  59 + version = (short)(data[idx] & 0xff); idx++;
  60 + serialNo = (short)(data[idx] & 0xff); idx++;
  61 + commandType = (short)(data[idx] & 0xff); idx++;
  62 + byte[] temp = Arrays.copyOfRange(data, idx, len - 1);
  63 + checkSum = data[len - 1];
  64 + byte sum = 0;
  65 + for (int i = 0;i < len - 1;i++) {
  66 + sum += data[i];
  67 + }
  68 + if (sum == checkSum) {
  69 + messageBody = PdFactory.create(commandType, temp);
  70 + }
  71 + }
  72 +
  73 + public byte[] write() {
  74 + byte[] bytes = messageBody.write();
  75 + ByteBuffer buf = ByteBuffer.allocate(bytes.length + 8);
  76 + buf.put(new byte[] { (byte)0xfa, (byte)0xf5 });
  77 + buf.putShort((short)(bytes.length + 3));
  78 + buf.put((byte)version);
  79 + buf.put((byte)serialNo);
  80 + buf.put((byte)commandType);
  81 + buf.put(bytes);
  82 + checkSum = 0;
  83 + checkSum += (byte)version;
  84 + checkSum += (byte)serialNo;
  85 + checkSum += (byte)commandType;
  86 + for (byte b : bytes) {
  87 + checkSum += b;
  88 + }
  89 + buf.put(checkSum);
  90 + return buf.array();
  91 + }
  92 +
  93 + public String toString() {
  94 + StringBuilder sb = new StringBuilder();
  95 + sb.append("报文版本号:").append(version)
  96 + .append("报文序列号:").append(serialNo)
  97 + .append("报文命令字:0x").append(Integer.toHexString(commandType))
  98 + .append("报文主体:(").append(messageBody).append(")")
  99 + .append("报文校验和:").append(checkSum);
  100 +
  101 + return sb.toString();
  102 + }
  103 +}
... ...
src/main/java/com/bsth/client/pd/protocol/Pd_31_0.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/protocol/Pd_31_0.java
  1 +package com.bsth.client.pd.protocol;
  2 +
  3 +import com.bsth.client.msg.IMessageBody;
  4 +import com.bsth.client.pd.common.ConvertUtil;
  5 +
  6 +import java.nio.ByteBuffer;
  7 +import java.util.Date;
  8 +
  9 +
  10 +public class Pd_31_0 implements IMessageBody {
  11 +
  12 + // bcd 1
  13 + private short funCode;
  14 + // bcd 3
  15 + private int lineId;
  16 + // ascii 8
  17 + private String deviceId;
  18 + // bcd 6 yyMMddhhmmss
  19 + private long timestamp;
  20 + // hex 8
  21 + private String reserved;
  22 +
  23 + @Override
  24 + public void read(byte[] bytes) {
  25 + // TODO Auto-generated method stub
  26 + int idx = 0;
  27 + funCode = (short)(bytes[idx] & 0xff);idx++;
  28 + lineId = ConvertUtil.bcd2int(bytes, idx, 3);idx += 3;
  29 + deviceId = ConvertUtil.ascii2string(bytes, idx, 8);idx += 8;
  30 + timestamp = ConvertUtil.bcd2timestamp(bytes, idx);idx += 6;
  31 + reserved = ConvertUtil.ascii2string(bytes, idx, 8);idx += 8;
  32 + }
  33 +
  34 + @Override
  35 + public byte[] write() {
  36 + // TODO Auto-generated method stub
  37 + ByteBuffer buf = ByteBuffer.allocate(26);
  38 + buf.put((byte)funCode);
  39 + buf.put(ConvertUtil.int2bcd(lineId, 3));
  40 + buf.put(deviceId.getBytes());
  41 + buf.put(ConvertUtil.timestamp2bcd(timestamp));
  42 + buf.put(new byte[]{0,0,0,0,0,0,0,0});
  43 + return buf.array();
  44 + }
  45 +
  46 + public short getFunCode() {
  47 + return funCode;
  48 + }
  49 +
  50 + public int getLineId() {
  51 + return lineId;
  52 + }
  53 +
  54 + public String getDeviceId() {
  55 + return deviceId;
  56 + }
  57 +
  58 + public long getTimestamp() {
  59 + return timestamp;
  60 + }
  61 +
  62 + public String getReserved() {
  63 + return reserved;
  64 + }
  65 +
  66 + public void setFunCode(short funCode) {
  67 + this.funCode = funCode;
  68 + }
  69 +
  70 + public void setLineId(int lineId) {
  71 + this.lineId = lineId;
  72 + }
  73 +
  74 + public void setDeviceId(String deviceId) {
  75 + this.deviceId = deviceId;
  76 + }
  77 +
  78 + public void setTimeStamp(long timestamp) {
  79 + this.timestamp = timestamp;
  80 + }
  81 +
  82 + public void setReserved(String reserved) {
  83 + this.reserved = reserved;
  84 + }
  85 +
  86 + public String toString() {
  87 + Date d = new Date();
  88 + d.setTime(timestamp);
  89 + StringBuilder sb = new StringBuilder();
  90 + sb.append("功能号:").append(Integer.toHexString(funCode))
  91 + .append("线路编号:").append(lineId)
  92 + .append("设备编号:").append(deviceId)
  93 + .append("时间戳:").append(d);
  94 + return sb.toString();
  95 + }
  96 +}
... ...
src/main/java/com/bsth/client/pd/protocol/Pd_41_0.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/protocol/Pd_41_0.java
  1 +package com.bsth.client.pd.protocol;
  2 +
  3 +
  4 +import com.bsth.client.msg.IMessageBody;
  5 +import com.bsth.client.pd.common.ConvertUtil;
  6 +
  7 +import java.nio.ByteBuffer;
  8 +
  9 +
  10 +public class Pd_41_0 implements IMessageBody {
  11 +
  12 + private BasicInfo info;
  13 + private short leaveStopDis;
  14 +
  15 + public BasicInfo getInfo() {
  16 + return info;
  17 + }
  18 +
  19 + public void setInfo(BasicInfo info) {
  20 + this.info = info;
  21 + }
  22 +
  23 + public short getLeaveStopDis() {
  24 + return leaveStopDis;
  25 + }
  26 +
  27 + public void setLeaveStopDis(short leaveStopDis) {
  28 + this.leaveStopDis = leaveStopDis;
  29 + }
  30 +
  31 + @Override
  32 + public void read(byte[] bytes) {
  33 + // TODO Auto-generated method stub
  34 + int idx = 0;
  35 + info = new BasicInfo();
  36 + info.read(bytes, idx); idx += 80;
  37 + leaveStopDis = (short) ConvertUtil.bcd2int(bytes, idx, 2); idx += 2;
  38 + }
  39 +
  40 + @Override
  41 + public byte[] write() {
  42 + // TODO Auto-generated method stub
  43 + ByteBuffer buf = ByteBuffer.allocate(82);
  44 + buf.put(info.write());
  45 + buf.put(ConvertUtil.int2bcd(leaveStopDis, 2));
  46 +
  47 + return buf.array();
  48 + }
  49 +
  50 + @Override
  51 + public String getDeviceId() {
  52 + // TODO Auto-generated method stub
  53 + return info.getDeviceId();
  54 + }
  55 +
  56 + public String toString() {
  57 + StringBuilder sb = new StringBuilder();
  58 + sb.append("基本数据:").append(info.toString())
  59 + .append("离站距离:").append(leaveStopDis);
  60 +
  61 + return sb.toString();
  62 + }
  63 +
  64 + @Override
  65 + public long getTimestamp() {
  66 + // TODO Auto-generated method stub
  67 + return info.getTimestamp();
  68 + }
  69 +}
... ...
src/main/java/com/bsth/client/pd/protocol/Pd_42_0.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/client/pd/protocol/Pd_42_0.java
  1 +package com.bsth.client.pd.protocol;
  2 +
  3 +import com.bsth.client.msg.IMessageBody;
  4 +import com.bsth.client.pd.common.ConvertUtil;
  5 +
  6 +import java.nio.ByteBuffer;
  7 +
  8 +public class Pd_42_0 implements IMessageBody {
  9 +
  10 + private BasicInfo info;
  11 + // 站间里程 保留两位小数 km
  12 + private short stopBetMiles;
  13 + private short frontDoorUp;
  14 + private short frontDoorDown;
  15 + private short backDoorUp;
  16 + private short backDoorDown;
  17 + // 本站留车人数
  18 + private int stay;
  19 + // 本站刷卡次数
  20 + private short cardCount;
  21 + // 本站刷卡金额
  22 + private int cardMoney;
  23 + // 免费刷卡次数
  24 + private short freeCardCount;
  25 + // 免费刷卡金额
  26 + private int freeCardMoney;
  27 + // 总刷卡次数
  28 + private int totalCardCount;
  29 + // 总数卡金额
  30 + private long totalCardMoney;
  31 + // 总免费刷卡次数
  32 + private int totalFreeCardCount;
  33 + // 总免费刷卡金额
  34 + private long totalFreeCardMoney;
  35 + // 客流站号
  36 + private short passengerStopNo;
  37 +
  38 + @Override
  39 + public void read(byte[] bytes) {
  40 + // TODO Auto-generated method stub
  41 + ByteBuffer buf = ByteBuffer.wrap(bytes);
  42 + int idx = 0;
  43 + info = new BasicInfo();
  44 + info.read(bytes, idx); idx += 80;
  45 + stopBetMiles = (short) ConvertUtil.bcd2int(bytes, idx, 2); idx += 2;
  46 + frontDoorUp = (short)(buf.get(idx) & 0xff); idx++;
  47 + frontDoorDown = (short)(buf.get(idx) & 0xff); idx++;
  48 + backDoorUp = (short)(buf.get(idx) & 0xff); idx++;
  49 + backDoorDown = (short)(buf.get(idx) & 0xff); idx++;
  50 + stay = buf.getShort(idx) & 0xffff; idx += 2;
  51 + cardCount = (short)(buf.get(idx) & 0xff); idx++;
  52 + cardMoney = buf.getShort(idx) & 0xffff; idx += 2;
  53 + freeCardCount = (short)(buf.get(idx) & 0xff); idx++;
  54 + freeCardMoney = buf.getShort(idx) & 0xffff; idx += 2;
  55 + totalCardCount = buf.getShort(idx) & 0xffff; idx += 2;
  56 + totalCardMoney = buf.getInt(idx) & 0xffffffffl; idx += 4;
  57 + totalFreeCardCount = buf.getShort(idx) & 0xffff; idx += 2;
  58 + totalFreeCardMoney = buf.getInt(idx) & 0xffffffffl; idx += 4;
  59 + passengerStopNo = (short)(buf.get(idx) & 0xff); idx++;
  60 + }
  61 +
  62 + @Override
  63 + public byte[] write() {
  64 + // TODO Auto-generated method stub
  65 + ByteBuffer buf = ByteBuffer.allocate(107);
  66 + buf.put(info.write());
  67 + buf.put(ConvertUtil.int2bcd(stopBetMiles, 2));
  68 + buf.put((byte)frontDoorUp);
  69 + buf.put((byte)frontDoorDown);
  70 + buf.put((byte)backDoorUp);
  71 + buf.put((byte)backDoorDown);
  72 + buf.putShort((short)stay);
  73 + buf.put((byte)cardCount);
  74 + buf.putShort((short)cardMoney);
  75 + buf.put((byte)freeCardCount);
  76 + buf.putShort((short)freeCardMoney);
  77 + buf.putShort((short)totalCardCount);
  78 + buf.putInt((int)totalCardMoney);
  79 + buf.putShort((short)totalFreeCardCount);
  80 + buf.putInt((int)totalFreeCardMoney);
  81 + buf.put((byte)passengerStopNo);
  82 +
  83 + return buf.array();
  84 + }
  85 +
  86 + @Override
  87 + public String getDeviceId() {
  88 + // TODO Auto-generated method stub
  89 + return info.getDeviceId();
  90 + }
  91 +
  92 + public BasicInfo getInfo() {
  93 + return info;
  94 + }
  95 +
  96 + public short getStopBetMiles() {
  97 + return stopBetMiles;
  98 + }
  99 +
  100 + public short getFrontDoorUp() {
  101 + return frontDoorUp;
  102 + }
  103 +
  104 + public short getFrontDoorDown() {
  105 + return frontDoorDown;
  106 + }
  107 +
  108 + public short getBackDoorUp() {
  109 + return backDoorUp;
  110 + }
  111 +
  112 + public short getBackDoorDown() {
  113 + return backDoorDown;
  114 + }
  115 +
  116 + public int getStay() {
  117 + return stay;
  118 + }
  119 +
  120 + public short getCardCount() {
  121 + return cardCount;
  122 + }
  123 +
  124 + public int getCardMoney() {
  125 + return cardMoney;
  126 + }
  127 +
  128 + public short getFreeCardCount() {
  129 + return freeCardCount;
  130 + }
  131 +
  132 + public int getFreeCardMoney() {
  133 + return freeCardMoney;
  134 + }
  135 +
  136 + public int getTotalCardCount() {
  137 + return totalCardCount;
  138 + }
  139 +
  140 + public long getTotalCardMoney() {
  141 + return totalCardMoney;
  142 + }
  143 +
  144 + public int getTotalFreeCardCount() {
  145 + return totalFreeCardCount;
  146 + }
  147 +
  148 + public long getTotalFreeCardMoney() {
  149 + return totalFreeCardMoney;
  150 + }
  151 +
  152 + public short getPassengerStopNo() {
  153 + return passengerStopNo;
  154 + }
  155 +
  156 + public String toString() {
  157 + StringBuilder sb = new StringBuilder();
  158 + sb.append("基本数据:").append(info.toString())
  159 + .append("站间距离:").append(stopBetMiles)
  160 + .append("前门上客:").append(frontDoorUp)
  161 + .append("前门下客:").append(frontDoorDown)
  162 + .append("后门上客:").append(backDoorUp)
  163 + .append("后门下客:").append(backDoorDown)
  164 + .append("本站留车人数:").append(stay)
  165 + .append("本站刷卡次数:").append(cardCount)
  166 + .append("本站刷卡金额:").append(cardMoney)
  167 + .append("免费刷卡次数:").append(freeCardCount)
  168 + .append("免费刷卡金额:").append(freeCardMoney)
  169 + .append("总刷卡次数:").append(totalCardCount)
  170 + .append("总数卡金额:").append(totalCardMoney)
  171 + .append("总免费刷卡次数:").append(totalFreeCardCount)
  172 + .append("总免费刷卡金额:").append(totalFreeCardMoney)
  173 + .append("客流站号:").append(passengerStopNo);
  174 +
  175 + return sb.toString();
  176 + }
  177 +
  178 + @Override
  179 + public long getTimestamp() {
  180 + // TODO Auto-generated method stub
  181 + return info.getTimestamp();
  182 + }
  183 +}
... ...
src/main/java/com/bsth/common/Constants.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/common/Constants.java
  1 +package com.bsth.common;
  2 +
  3 +/**
  4 + *
  5 + * @ClassName: Constants
  6 + * @Description: TODO(常量类)
  7 + * @author PanZhao
  8 + * @date 2016年3月18日 下午11:06:53
  9 + *
  10 + */
  11 +public class Constants {
  12 +
  13 + /**
  14 + * 不需要拦截的资源
  15 + */
  16 + public static final String FAVICON_URL = "/favicon.ico";
  17 + public static final String SESSION_USERNAME = "sessionUserName";
  18 +
  19 +}
... ...
src/main/java/com/bsth/common/ResponseCode.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/common/ResponseCode.java
  1 +package com.bsth.common;
  2 +
  3 +/**
  4 + *
  5 + * @ClassName: ResponseCode
  6 + * @Description: TODO(响应状态码)
  7 + * @author PanZhao
  8 + * @date 2016年3月18日 下午11:12:08
  9 + *
  10 + */
  11 +public enum ResponseCode {
  12 +
  13 + SUCCESS("操作成功", 200),
  14 + NO_PERMISSION("无资源访问权限", 403),
  15 + NO_AUTHENTICATION("客户端未授权", 407),
  16 + ERROR("服务器异常", 500);
  17 +
  18 + private String text;
  19 + private int code;
  20 +
  21 + ResponseCode(String text, int code) {
  22 + this.text = text;
  23 + this.code = code;
  24 + }
  25 +
  26 + @Override
  27 + public String toString() {
  28 + return this.code + "";
  29 + }
  30 +
  31 + public String getText() {
  32 + return this.text;
  33 + }
  34 +}
... ...
src/main/java/com/bsth/controller/BaseController.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/controller/BaseController.java
  1 +package com.bsth.controller;
  2 +
  3 +import com.bsth.service.BaseService;
  4 +import org.springframework.beans.factory.annotation.Autowired;
  5 +import org.springframework.data.domain.Page;
  6 +import org.springframework.data.domain.PageRequest;
  7 +import org.springframework.data.domain.Sort;
  8 +import org.springframework.data.domain.Sort.Direction;
  9 +import org.springframework.web.bind.annotation.PathVariable;
  10 +import org.springframework.web.bind.annotation.RequestMapping;
  11 +import org.springframework.web.bind.annotation.RequestMethod;
  12 +import org.springframework.web.bind.annotation.RequestParam;
  13 +
  14 +import java.io.Serializable;
  15 +import java.util.Map;
  16 +
  17 +/**
  18 + * @param <T>
  19 + * @param <ID> 主键类型
  20 + * @author PanZhao
  21 + * @ClassName: BaseController
  22 + * @Description: TODO(基础的Controller实现)
  23 + * @date 2016年3月17日 下午12:44:06
  24 + */
  25 +public class BaseController<T, ID extends Serializable> {
  26 +
  27 + @Autowired
  28 + protected BaseService<T, ID> baseService;
  29 +
  30 + /**
  31 + * @param @param map 查询条件
  32 + * @param @param page 页码
  33 + * @param @param size 每页显示数量
  34 + * @throws
  35 + * @Title: list
  36 + * @Description: TODO(多条件分页查询)
  37 + */
  38 + @RequestMapping(method = RequestMethod.GET)
  39 + public Page<T> list(@RequestParam Map<String, Object> map,
  40 + @RequestParam(defaultValue = "0") int page,
  41 + @RequestParam(defaultValue = "10") int size,
  42 + @RequestParam(defaultValue = "id") String order,
  43 + @RequestParam(defaultValue = "DESC") String direction) {
  44 +
  45 + Direction d;
  46 + if(null != direction && direction.equals("ASC"))
  47 + d = Direction.ASC;
  48 + else
  49 + d = Direction.DESC;
  50 +
  51 + return baseService.list(map, PageRequest.of(page, size, new Sort(d, order)));
  52 + }
  53 +
  54 + /**
  55 + * @param @param map
  56 + * @throws
  57 + * @Title: list
  58 + * @Description: TODO(多条件查询)
  59 + */
  60 + @RequestMapping(value = "/all", method = RequestMethod.GET)
  61 + public Iterable<T> list(@RequestParam Map<String, Object> map) {
  62 + return baseService.list(map);
  63 + }
  64 +
  65 + /**
  66 + * @param @param t
  67 + * @param @return 设定文件
  68 + * @return Map<String,Object> {status: 1(成功),-1(失败)}
  69 + * @throws
  70 + * @Title: save
  71 + * @Description: TODO(持久化对象)
  72 + */
  73 + @RequestMapping(method = RequestMethod.POST)
  74 + public Map<String, Object> save(T t) {
  75 + return baseService.save(t);
  76 + }
  77 +
  78 + /**
  79 + * @param @param id
  80 + * @throws
  81 + * @Title: findById
  82 + * @Description: TODO(根据主键获取单个对象)
  83 + */
  84 + @RequestMapping(value = "/{id}", method = RequestMethod.GET)
  85 + public T findById(@PathVariable("id") ID id) {
  86 + return baseService.findById(id);
  87 + }
  88 +
  89 + /**
  90 + * @param @param id
  91 + * @throws
  92 + * @Title: delete
  93 + * @Description: TODO(根据主键删除对象)
  94 + */
  95 + @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
  96 + public Map<String, Object> delete(@PathVariable("id") ID id) {
  97 + return baseService.delete(id);
  98 + }
  99 +
  100 +}
... ...
src/main/java/com/bsth/controller/BasicDataController.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/controller/BasicDataController.java
  1 +package com.bsth.controller;
  2 +
  3 +import com.bsth.data.BasicCacheData;
  4 +import com.bsth.entity.Line;
  5 +import org.springframework.web.bind.annotation.RequestMapping;
  6 +import org.springframework.web.bind.annotation.RestController;
  7 +
  8 +import java.util.Collection;
  9 +
  10 +@RestController
  11 +@RequestMapping("basic")
  12 +public class BasicDataController {
  13 +
  14 + @RequestMapping("lines")
  15 + public Collection<Line> findLines() {
  16 + return BasicCacheData.code2LineMap.values();
  17 + }
  18 +}
... ...
src/main/java/com/bsth/controller/ConsumeDataController.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/controller/ConsumeDataController.java
  1 +package com.bsth.controller;
  2 +
  3 +import com.bsth.data.history.entity.StationConsumeTime;
  4 +import com.bsth.service.ConsumeDataService;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.web.bind.annotation.RequestMapping;
  7 +import org.springframework.web.bind.annotation.RequestParam;
  8 +import org.springframework.web.bind.annotation.RestController;
  9 +
  10 +import java.util.List;
  11 +
  12 +@RestController
  13 +@RequestMapping("consume_data")
  14 +public class ConsumeDataController {
  15 +
  16 + @Autowired
  17 + ConsumeDataService consumeDataService;
  18 +
  19 + @RequestMapping("search")
  20 + public List<StationConsumeTime> search(@RequestParam String rq
  21 + , @RequestParam String lineCode
  22 + , @RequestParam String st
  23 + , @RequestParam String et, String nbbm) {
  24 +
  25 + return consumeDataService.search(rq, lineCode, st, et, nbbm);
  26 + }
  27 +}
... ...
src/main/java/com/bsth/controller/GeoDataController.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/controller/GeoDataController.java
  1 +package com.bsth.controller;
  2 +
  3 +import com.bsth.data.geo.GeoCacheData;
  4 +import com.bsth.entity.SectionRoute;
  5 +import com.bsth.entity.StationRoute;
  6 +import org.springframework.web.bind.annotation.PathVariable;
  7 +import org.springframework.web.bind.annotation.RequestMapping;
  8 +import org.springframework.web.bind.annotation.RestController;
  9 +
  10 +import java.util.HashMap;
  11 +import java.util.List;
  12 +import java.util.Map;
  13 +
  14 +@RestController
  15 +@RequestMapping("geo_data")
  16 +public class GeoDataController {
  17 +
  18 + @RequestMapping("{lineCode}")
  19 + public Map<String, Object> find(@PathVariable("lineCode") String lineCode) {
  20 + List<StationRoute>[] stationLists = GeoCacheData.find(lineCode);
  21 + List<SectionRoute>[] sectionLists = GeoCacheData.findSections(lineCode);
  22 +
  23 + Map<String, Object> rs = new HashMap<>();
  24 + rs.put("stations", stationLists);
  25 + rs.put("section", sectionLists);
  26 + return rs;
  27 + }
  28 +
  29 + @RequestMapping("/stations/{lineCode}")
  30 + public Map<String, Object> findStations(@PathVariable("lineCode") String lineCode) {
  31 + List<StationRoute>[] stationLists = GeoCacheData.find(lineCode);
  32 +
  33 + Map<String, Object> rs = new HashMap<>();
  34 + rs.put("stations", stationLists);
  35 + return rs;
  36 + }
  37 +}
... ...
src/main/java/com/bsth/controller/GpsDataController.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/controller/GpsDataController.java
  1 +package com.bsth.controller;
  2 +
  3 +import com.bsth.data.gps.GpsCacheData;
  4 +import com.bsth.entity.GpsEntity;
  5 +import org.springframework.web.bind.annotation.RequestMapping;
  6 +import org.springframework.web.bind.annotation.RequestParam;
  7 +import org.springframework.web.bind.annotation.RestController;
  8 +
  9 +import java.util.List;
  10 +import java.util.Map;
  11 +
  12 +@RestController
  13 +@RequestMapping("gps")
  14 +public class GpsDataController {
  15 +
  16 + @RequestMapping("findByStation")
  17 + public List<GpsEntity> findByStation(@RequestParam String lineCode
  18 + , @RequestParam String upDown
  19 + , @RequestParam String name) {
  20 +
  21 +
  22 + return null;
  23 + }
  24 +
  25 + @RequestMapping("findByLineAndUpDown")
  26 + public Map<String, Object> findByLineAndUpDown(@RequestParam String lineCode, @RequestParam int upDown) {
  27 + return GpsCacheData.find(lineCode, upDown);
  28 + }
  29 +}
... ...
src/main/java/com/bsth/data/BasicCacheData.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/BasicCacheData.java
  1 +package com.bsth.data;
  2 +
  3 +import com.bsth.entity.Line;
  4 +import com.github.stuxuhai.jpinyin.PinyinException;
  5 +import com.github.stuxuhai.jpinyin.PinyinFormat;
  6 +import com.github.stuxuhai.jpinyin.PinyinHelper;
  7 +import com.google.common.collect.BiMap;
  8 +import com.google.common.collect.HashBiMap;
  9 +import org.slf4j.Logger;
  10 +import org.slf4j.LoggerFactory;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +import org.springframework.jdbc.core.BeanPropertyRowMapper;
  13 +import org.springframework.jdbc.core.JdbcTemplate;
  14 +import org.springframework.stereotype.Component;
  15 +
  16 +import java.util.HashMap;
  17 +import java.util.List;
  18 +import java.util.Map;
  19 +
  20 +/**
  21 + * 基础数据缓存 by panzhao
  22 + */
  23 +@Component
  24 +public class BasicCacheData {
  25 +
  26 + /**
  27 + * K: lineCode
  28 + */
  29 + public static Map<String, Line> code2LineMap;
  30 +
  31 + public static BiMap<String, String> device2nbbmMap;
  32 +
  33 + Logger logger = LoggerFactory.getLogger(this.getClass());
  34 +
  35 + @Autowired
  36 + JdbcTemplate jdbcTemplate;
  37 +
  38 + public void reLoad() {
  39 + loadCode2LineMap();
  40 + loadDevice2nbbmMap();
  41 + }
  42 +
  43 + private void loadDevice2nbbmMap() {
  44 + List<Map<String, Object>> list = jdbcTemplate.queryForList("select INSIDE_CODE,EQUIPMENT_CODE from bsth_c_cars where inside_code is not null and equipment_code is not null");
  45 +
  46 + BiMap<String, String> biMap = HashBiMap.create();
  47 +
  48 + for (Map<String, Object> map : list) {
  49 + biMap.put(map.get("EQUIPMENT_CODE").toString(), map.get("INSIDE_CODE").toString());
  50 + }
  51 +
  52 + device2nbbmMap = biMap;
  53 + }
  54 +
  55 + private void loadCode2LineMap() {
  56 + String sql = "select line_code,`name`,start_station_name,end_station_name from bsth_c_line WHERE destroy=0 and `remove`!=1";
  57 + List<Line> list = jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(Line.class));
  58 +
  59 + Map<String, Line> map = new HashMap<>();
  60 + for (Line line : list) {
  61 + try {
  62 + line.setFullChars(PinyinHelper.convertToPinyinString(line.getName(), "", PinyinFormat.WITHOUT_TONE));
  63 + line.setCamelChars(PinyinHelper.getShortPinyin(line.getName()));
  64 + } catch (PinyinException e) {
  65 + logger.error("", e);
  66 + }
  67 + map.put(line.getLineCode(), line);
  68 + }
  69 +
  70 + if (map.size() > 0)
  71 + code2LineMap = map;
  72 + }
  73 +
  74 + @Component
  75 + public class RefreshDataThead extends Thread {
  76 + @Override
  77 + public void run() {
  78 + reLoad();
  79 + }
  80 + }
  81 +}
... ...
src/main/java/com/bsth/data/geo/GeoCacheData.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/geo/GeoCacheData.java
  1 +package com.bsth.data.geo;
  2 +
  3 +import com.bsth.entity.CarPark;
  4 +import com.bsth.entity.GpsEntity;
  5 +import com.bsth.entity.SectionRoute;
  6 +import com.bsth.entity.StationRoute;
  7 +import com.bsth.util.geo.Point;
  8 +import com.google.common.collect.ArrayListMultimap;
  9 +import com.google.common.collect.ListMultimap;
  10 +import com.google.common.collect.Multimaps;
  11 +
  12 +import java.util.Collection;
  13 +import java.util.List;
  14 +import java.util.Set;
  15 +import java.util.concurrent.ConcurrentHashMap;
  16 +import java.util.concurrent.ConcurrentMap;
  17 +
  18 +/**
  19 + * 站点和路段空间数据缓存
  20 + */
  21 +public class GeoCacheData {
  22 +
  23 + /**
  24 + * K: lineCode_upDown V: 完整的路段
  25 + */
  26 + private static ListMultimap<String, Point> fullSectionMaps;
  27 +
  28 + /**
  29 + * K: lineCode_upDown
  30 + */
  31 + private static ListMultimap<String, StationRoute> srsListMultiMap;
  32 +
  33 + /**
  34 + * K: lineCode_upDown_stationCode
  35 + */
  36 + private static ConcurrentMap<String, StationRoute> codeMap;
  37 +
  38 + /**
  39 + * K: lineCode_upDown_stationName
  40 + */
  41 + private static ConcurrentMap<String, StationRoute> nameMap;
  42 +
  43 + /**
  44 + * K: lineCode_upDown 原始路段信息
  45 + */
  46 + private static ListMultimap<String, SectionRoute> sectionMultiMap;
  47 +
  48 + /**
  49 + * 停车场
  50 + */
  51 + public static ConcurrentMap<String, CarPark> tccMap;
  52 +
  53 + /**
  54 + * K: lineCode_upDown V: 0:有效的路段数据
  55 + */
  56 + public static ConcurrentMap<String, Integer> lineValidMap;
  57 +
  58 + static {
  59 + srsListMultiMap = Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
  60 + fullSectionMaps = Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
  61 + sectionMultiMap = ArrayListMultimap.create();
  62 + codeMap = new ConcurrentHashMap<>();
  63 + nameMap = new ConcurrentHashMap<>();
  64 + tccMap = new ConcurrentHashMap<>();
  65 + lineValidMap = new ConcurrentHashMap<>();
  66 + }
  67 +
  68 + public static boolean isValidSection(String lineCode, int upDown) {
  69 + String k = lineCode + "_" + upDown;
  70 + if (!lineValidMap.containsKey(k))
  71 + return false;
  72 +
  73 + return lineValidMap.get(k) != 1;
  74 + }
  75 +
  76 + public static void put(ListMultimap<String, StationRoute> mMap,
  77 + ListMultimap<String, SectionRoute> sectionMaps,
  78 + ListMultimap<String, Point> fSectionMap) {
  79 +
  80 + List<StationRoute> srs;
  81 + //put station
  82 + Set<String> ks = mMap.keySet();
  83 + for (String k : ks) {
  84 + srs = mMap.get(k);
  85 + srsListMultiMap.removeAll(k);
  86 + srsListMultiMap.putAll(k, srs);
  87 +
  88 + //标记线路的路段数据是否有效
  89 + lineValidMap.put(k, 0);
  90 + for (StationRoute s : srs) {
  91 + if (null == s.getPaths() && !"E".equals(s.getMark())) {
  92 + lineValidMap.put(k, 1);//无效的路段数据
  93 + break;
  94 + }
  95 + }
  96 + }
  97 +
  98 + Collection<StationRoute> vs = mMap.values();
  99 + String prefix;
  100 + for (StationRoute s : vs) {
  101 + prefix = s.getLineCode() + "_" + s.getUpDown() + "_";
  102 + codeMap.put(prefix + s.getStationCode(), s);
  103 + nameMap.put(prefix + s.getName(), s);
  104 + }
  105 +
  106 + //put section
  107 + ks = sectionMaps.keySet();
  108 + for (String k : ks) {
  109 + sectionMultiMap.removeAll(k);
  110 + sectionMultiMap.putAll(k, sectionMaps.get(k));
  111 + }
  112 +
  113 + //put full section
  114 + ks = fSectionMap.keySet();
  115 + for (String k : ks) {
  116 + fullSectionMaps.removeAll(k);
  117 + fullSectionMaps.putAll(k, fSectionMap.get(k));
  118 + }
  119 + }
  120 +
  121 + public static List<Point> getFullSection(String lineCode, int upDown) {
  122 + return fullSectionMaps.get(lineCode + "_" + upDown);
  123 + }
  124 +
  125 + public static void setTccMap(List<CarPark> list) {
  126 + ConcurrentMap<String, CarPark> map = new ConcurrentHashMap<>();
  127 +
  128 + for (CarPark cp : list) {
  129 + map.put(cp.getCode(), cp);
  130 + }
  131 +
  132 + tccMap = map;
  133 + }
  134 +
  135 + public static CarPark getCarPark(String code) {
  136 + return tccMap.get(code);
  137 + }
  138 +
  139 + public static Collection<CarPark> carPacks() {
  140 + return tccMap.values();
  141 + }
  142 +
  143 + public static StationRoute findByName(String lineCode, int upDown, String name) {
  144 + return nameMap.get(lineCode + "_" + upDown + "_" + name);
  145 + }
  146 +
  147 + public static StationRoute findByCode(String lineCode, int upDown, String code) {
  148 + return codeMap.get(lineCode + "_" + upDown + "_" + code);
  149 + }
  150 +
  151 + public static StationRoute findByCode(GpsEntity gps) {
  152 + return codeMap.get(gps.getLineId() + "_" + gps.getUpDown() + "_" + gps.getStationCode());
  153 + }
  154 +
  155 + public static List<StationRoute> find(String lineCode, int upDown) {
  156 + return srsListMultiMap.get(lineCode + "_" + upDown);
  157 + }
  158 +
  159 + public static List<StationRoute>[] find(String lineCode) {
  160 + List<StationRoute>[] lists = new List[2];
  161 + lists[0] = find(lineCode, 0);
  162 + lists[1] = find(lineCode, 1);
  163 + return lists;
  164 + }
  165 +
  166 + public static List<SectionRoute> findSections(String lineCode, int upDown) {
  167 + return sectionMultiMap.get(lineCode + "_" + upDown);
  168 + }
  169 +
  170 + public static List<SectionRoute>[] findSections(String lineCode) {
  171 + List<SectionRoute>[] lists = new List[2];
  172 + lists[0] = findSections(lineCode, 0);
  173 + lists[1] = findSections(lineCode, 1);
  174 + return lists;
  175 + }
  176 +}
... ...
src/main/java/com/bsth/data/geo/loader/DataLoader.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/geo/loader/DataLoader.java
  1 +package com.bsth.data.geo.loader;
  2 +
  3 +import com.bsth.data.geo.GeoCacheData;
  4 +import com.bsth.data.geo.loader.util.GeoCalculator;
  5 +import com.bsth.entity.CarPark;
  6 +import com.bsth.entity.SectionRoute;
  7 +import com.bsth.entity.StationRoute;
  8 +import com.bsth.util.geo.GeoUtils;
  9 +import com.bsth.util.geo.Point;
  10 +import com.bsth.util.geo.Polygon;
  11 +import com.google.common.collect.ArrayListMultimap;
  12 +import com.google.common.collect.ListMultimap;
  13 +import org.slf4j.Logger;
  14 +import org.slf4j.LoggerFactory;
  15 +import org.springframework.beans.factory.annotation.Autowired;
  16 +import org.springframework.jdbc.core.BeanPropertyRowMapper;
  17 +import org.springframework.jdbc.core.JdbcTemplate;
  18 +import org.springframework.stereotype.Component;
  19 +
  20 +import java.util.List;
  21 +import java.util.Set;
  22 +
  23 +/**
  24 + * 加载 geo 数据
  25 + */
  26 +@Component
  27 +public class DataLoader {
  28 +
  29 + @Autowired
  30 + JdbcTemplate jdbcTemplate;
  31 +
  32 + Logger logger = LoggerFactory.getLogger(this.getClass());
  33 +
  34 + public void load(List<String> codes) {
  35 + try {
  36 + String inCond = null;
  37 + if (null != codes && codes.size() > 0) {
  38 + StringBuilder sb = new StringBuilder();
  39 + for (String code : codes) {
  40 + sb.append("'" + code + "',");
  41 + }
  42 + sb.deleteCharAt(sb.length() - 1);
  43 + inCond = sb.toString();
  44 + }
  45 +
  46 + //站点路由
  47 + ListMultimap<String, StationRoute> stationMaps = loadStationRoutes(inCond);
  48 + //路段路由
  49 + ListMultimap<String, SectionRoute> sectionMaps = loadRoadRoutes(inCond);
  50 + //拼接好的完整路段
  51 + ListMultimap<String, Point> fullSectionMaps = ArrayListMultimap.create();
  52 + List<Point> fullSections;
  53 +
  54 + Set<String> ks = stationMaps.keySet();
  55 + for (String k : ks) {
  56 + //计算空间属性
  57 + fullSections = GeoCalculator.calc(stationMaps.get(k), sectionMaps.get(k));
  58 +
  59 + if(null != fullSections)
  60 + fullSectionMaps.putAll(k, fullSections);
  61 + }
  62 +
  63 + GeoCacheData.put(stationMaps, sectionMaps, fullSectionMaps);
  64 +
  65 +
  66 + //加载停车场信息
  67 + GeoCacheData.setTccMap(loadAllTccInfo());
  68 + } catch (Exception e) {
  69 + logger.error("", e);
  70 + }
  71 + }
  72 +
  73 + private List<CarPark> loadAllTccInfo() {
  74 + String sql = "select PARK_CODE as code,park_name as name, ST_AsText(G_PARK_POINT) as polygon_str from bsth_c_car_park where park_code is not null and b_park_point is not null and destroy=0";
  75 +
  76 + List<CarPark> cps = jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(CarPark.class));
  77 + Polygon polygon;
  78 + for(CarPark cp : cps){
  79 + polygon = GeoUtils.parsePolygon(cp.getPolygonStr());
  80 + cp.setPolygon(polygon);
  81 + }
  82 + return cps;
  83 + }
  84 +
  85 +
  86 + private ListMultimap<String, StationRoute> loadStationRoutes(String inCont) {
  87 + ListMultimap<String, StationRoute> multimap = ArrayListMultimap.create();
  88 +
  89 + String sql = " SELECT " +
  90 + " a.*," +
  91 + " b.g_lonx AS lon," +
  92 + " b.g_laty AS lat," +
  93 + " b.shapes_type," +
  94 + " b.radius," +
  95 + " ST_AsText ( b.g_polygon_grid ) AS polygonStr " +
  96 + " FROM" +
  97 + " ( SELECT line_code, station_code, station_name AS NAME, station_route_code AS serial_no, directions AS up_down FROM bsth_c_stationroute WHERE destroy = 0 ) a" +
  98 + " LEFT JOIN bsth_c_station b ON a.station_code = b.station_cod"
  99 + + (inCont == null ? "" : " where a.line_code in (" + inCont + ")");
  100 +
  101 + List<StationRoute> srs = jdbcTemplate.query(sql
  102 + , BeanPropertyRowMapper.newInstance(StationRoute.class));
  103 +
  104 + //按线路_走向分组数据
  105 + for (StationRoute sr : srs) {
  106 + if (sr.getShapesType() == 'r' && null == sr.getRadius())
  107 + sr.setRadius(80f);
  108 + multimap.put(sr.getLineCode() + "_" + sr.getUpDown(), sr);
  109 + }
  110 +
  111 + return multimap;
  112 + }
  113 +
  114 + private ListMultimap<String, SectionRoute> loadRoadRoutes(String inCont) {
  115 + ListMultimap<String, SectionRoute> mMap = ArrayListMultimap.create();
  116 +
  117 + String sql = "SELECT" +
  118 + " a.line_code," +
  119 + " a.directions AS up_down," +
  120 + " a.i," +
  121 + " b.section_name AS NAME," +
  122 + " ST_AsText ( b.gsection_vector ) AS roads " +
  123 + " FROM " +
  124 + " ( SELECT line_code, directions, sectionroute_code AS i, section_code FROM bsth_c_sectionroute WHERE destroy = 0 ) a " +
  125 + " LEFT JOIN bsth_c_section b ON a.section_code = b.section_code "
  126 + + (inCont == null ? "" : " where a.line_code in (" + inCont + ")");
  127 +
  128 + List<SectionRoute> srs = jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(SectionRoute.class));
  129 +
  130 + //按线路_走向分组数据
  131 + for (SectionRoute rr : srs) {
  132 + mMap.put(rr.getLineCode() + "_" + rr.getUpDown(), rr);
  133 + }
  134 +
  135 + return mMap;
  136 + }
  137 +}
... ...
src/main/java/com/bsth/data/geo/loader/comps/SectionRouteComp.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/geo/loader/comps/SectionRouteComp.java
  1 +package com.bsth.data.geo.loader.comps;
  2 +
  3 +import com.bsth.entity.SectionRoute;
  4 +
  5 +import java.util.Comparator;
  6 +
  7 +/**
  8 + * 路段路由排序器
  9 + */
  10 +public class SectionRouteComp implements Comparator<SectionRoute> {
  11 +
  12 + @Override
  13 + public int compare(SectionRoute s1, SectionRoute s2) {
  14 + return s1.getI() - s2.getI();
  15 + }
  16 +}
... ...
src/main/java/com/bsth/data/geo/loader/comps/StationRouteComp.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/geo/loader/comps/StationRouteComp.java
  1 +package com.bsth.data.geo.loader.comps;
  2 +
  3 +import com.bsth.entity.StationRoute;
  4 +
  5 +import java.util.Comparator;
  6 +
  7 +/**
  8 + * 站点路由排序器
  9 + */
  10 +public class StationRouteComp implements Comparator<StationRoute> {
  11 +
  12 + @Override
  13 + public int compare(StationRoute s1, StationRoute s2) {
  14 + return s1.getSerialNo() - s2.getSerialNo();
  15 + }
  16 +}
... ...
src/main/java/com/bsth/data/geo/loader/thread/DataLoadThread.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/geo/loader/thread/DataLoadThread.java
  1 +package com.bsth.data.geo.loader.thread;
  2 +
  3 +
  4 +import com.bsth.data.geo.loader.DataLoader;
  5 +import org.joda.time.format.DateTimeFormat;
  6 +import org.joda.time.format.DateTimeFormatter;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.jdbc.core.JdbcTemplate;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +import java.util.List;
  14 +
  15 +@Component
  16 +public class DataLoadThread extends Thread {
  17 +
  18 + private static boolean firstLoadFlag = true;
  19 +
  20 + Logger logger = LoggerFactory.getLogger(this.getClass());
  21 +
  22 + @Autowired
  23 + DataLoader cacheLoader;
  24 +
  25 + @Autowired
  26 + JdbcTemplate jdbcTemplate;
  27 +
  28 + /**
  29 + * 上次更新缓存时间
  30 + */
  31 + private static long t;
  32 +
  33 + private static DateTimeFormatter fmtyyyyMMddHHmm = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm");
  34 +
  35 + @Override
  36 + public void run() {
  37 +
  38 + try {
  39 + t = System.currentTimeMillis();
  40 + if (firstLoadFlag) {
  41 + cacheLoader.load(null);
  42 + firstLoadFlag = false;
  43 + } else {
  44 +
  45 + String timeStr = fmtyyyyMMddHHmm.print(t),
  46 + sql = "select DISTINCT line_code from bsth_c_sectionroute where section_code in (select section_code from bsth_c_section where update_date>='" + timeStr + "') " +
  47 + " UNION" +
  48 + " select DISTINCT line_code from bsth_c_stationroute where station_code in ( select station_cod from bsth_c_station where update_date>='" + timeStr + "') " +
  49 + " UNION" +
  50 + " select DISTINCT line_code from bsth_c_stationroute where update_date>='" + timeStr + "' " +
  51 + " UNION" +
  52 + " select DISTINCT line_code from bsth_c_sectionroute where update_date>='" + timeStr + "'";
  53 +
  54 +
  55 + List<String> codes = jdbcTemplate.queryForList(sql, String.class);
  56 +
  57 + if (codes.size() > 0)
  58 + cacheLoader.load(codes);
  59 + }
  60 + } catch (Exception e) {
  61 + logger.error("", e);
  62 + }
  63 + }
  64 +}
... ...
src/main/java/com/bsth/data/geo/loader/util/GeoCalculator.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/geo/loader/util/GeoCalculator.java
  1 +package com.bsth.data.geo.loader.util;
  2 +
  3 +import com.bsth.data.geo.loader.comps.SectionRouteComp;
  4 +import com.bsth.data.geo.loader.comps.StationRouteComp;
  5 +import com.bsth.entity.SectionRoute;
  6 +import com.bsth.entity.StationRoute;
  7 +import com.bsth.util.geo.GeoUtils;
  8 +import com.bsth.util.geo.Point;
  9 +import org.apache.commons.lang3.StringUtils;
  10 +
  11 +import java.util.ArrayList;
  12 +import java.util.Collections;
  13 +import java.util.List;
  14 +import java.util.concurrent.CopyOnWriteArrayList;
  15 +
  16 +/**
  17 + * 计算空间属性
  18 + */
  19 +public class GeoCalculator {
  20 +
  21 + private static StationRouteComp stationComp;
  22 + private static SectionRouteComp sectionComp;
  23 +
  24 + static {
  25 + stationComp = new StationRouteComp();
  26 + sectionComp = new SectionRouteComp();
  27 + }
  28 +
  29 + public static List<Point> calc(List<StationRoute> stations, List<SectionRoute> sections) {
  30 + //init station
  31 + initStationGeoField(stations);
  32 +
  33 + int size = stations.size();
  34 + if (size < 2 || null == sections || sections.size() == 0)
  35 + return null;
  36 +
  37 + if (isLoop(stations) && stations.get(0).getUpDown() == 1)
  38 + return null;//单环线下行
  39 +
  40 + /*if(stations.get(0).getLineCode().equals("10507") && stations.get(0).getUpDown()==1)
  41 + System.out.println("aaa");*/
  42 +
  43 + //sort
  44 + Collections.sort(stations, stationComp);
  45 + Collections.sort(sections, sectionComp);
  46 +
  47 + //station mark
  48 + stations.get(0).setMark("B");
  49 + stations.get(size - 1).setMark("E");
  50 +
  51 + //join section
  52 + List<Point> seCds = joinSections(sections);
  53 +
  54 + //根据第二站 的 索引位置,判断路段是否整体反向
  55 + Intersection si = searchIndex(stations.get(1), seCds);
  56 + if (si.getIndex() > seCds.size() * 0.8)
  57 + Collections.reverse(seCds);
  58 +
  59 + //split section by station
  60 + List<Intersection> siList = new ArrayList<>();
  61 + for (int i = 0, len = size; i < len; i++) {
  62 + si = searchIndex(stations.get(i), seCds);
  63 +
  64 + seCds.add(si.getIndex(), si.getP());
  65 + siList.add(si);
  66 + }
  67 +
  68 + //按交叉点截断
  69 + int pi = siList.get(0).getIndex(), ci;
  70 + StationRoute s;
  71 + for (int i = 1, len = siList.size(); i < len; i++) {
  72 + ci = siList.get(i).getIndex();
  73 + s = siList.get(i - 1).getS();
  74 +
  75 + if (pi > ci)
  76 + continue;
  77 +
  78 + /*if(s.getStationCode().equals("32270"))
  79 + System.out.println("bbb");*/
  80 + s.setPaths(new CopyOnWriteArrayList(subList(seCds, pi, ci + 1)));
  81 + pi = ci;
  82 + }
  83 +
  84 + return seCds;
  85 + }
  86 +
  87 + private static Intersection searchIndex(StationRoute station, List<Point> ps) {
  88 + Intersection rs = new Intersection();
  89 + rs.setS(station);
  90 + Point s, e,
  91 + p = station.getPoint(), p2;
  92 + double d1, d2, d3, alpha, beta, distance, min = -1;
  93 + for (int i = 1, len = ps.size(); i < len; i++) {
  94 + s = ps.get(i - 1);
  95 + e = ps.get(i);
  96 +
  97 + if (GeoUtils.isPointInLine(p, s, e)) {
  98 + rs.setP(p);
  99 + rs.setIndex(i);
  100 + return rs;
  101 + }
  102 +
  103 + d1 = GeoUtils.getDistance(s, p);
  104 + d2 = GeoUtils.getDistance(p, e);
  105 + d3 = GeoUtils.getDistance(s, e);
  106 + alpha = Math.acos((d1 * d1 + d3 * d3 - d2 * d2) / (2 * d1 * d3));
  107 + beta = Math.acos((d2 * d2 + d3 * d3 - d1 * d1) / (2 * d2 * d3));
  108 +
  109 + if (d3 < 0.5 || Double.isNaN(alpha) || Double.isNaN(beta))
  110 + continue;
  111 +
  112 + if (alpha > Math.PI / 2) {
  113 + distance = d1;
  114 + p2 = s;
  115 + } else if (beta > Math.PI / 2) {
  116 + distance = d2;
  117 + p2 = e;
  118 + } else {
  119 + distance = Math.sin(alpha) * d1;
  120 + p2 = GeoUtils.perpendularPoint(s, e, p);
  121 + }
  122 +
  123 + if (-1 == min || min > distance) {
  124 + min = distance;
  125 + rs.setIndex(i);
  126 + rs.setP(p2);
  127 + }
  128 + }
  129 + rs.setDistance(min);
  130 + return rs;
  131 + }
  132 +
  133 + /**
  134 + * 将路段连接
  135 + *
  136 + * @param sections
  137 + * @return
  138 + */
  139 + private static List<Point> joinSections(List<SectionRoute> sections) {
  140 + List<Point> all = new ArrayList<>();
  141 +
  142 + String str;
  143 + String[] arr;
  144 + for (SectionRoute section : sections) {
  145 + str = section.getRoads();
  146 + arr = str.substring(11, str.length() - 1).split(",");
  147 +
  148 + section.setPs(cdsToPoints(arr));
  149 +
  150 + joinSections(all, new ArrayList(section.getPs()));
  151 + }
  152 + return all;
  153 + }
  154 +
  155 + private static void joinSections(List<Point> all, List<Point> sections) {
  156 + int size = all.size(), size2 = sections.size();
  157 +
  158 + if (size == 0) {
  159 + all.addAll(sections);
  160 + return;
  161 + }
  162 +
  163 + //路段倒着画
  164 + double d1 = GeoUtils.getDistance(all.get(0), sections.get(0));
  165 + double d2 = GeoUtils.getDistance(all.get(0), sections.get(size2 - 1));
  166 + double d3 = GeoUtils.getDistance(all.get(size - 1), sections.get(0));
  167 + double d4 = GeoUtils.getDistance(all.get(size - 1), sections.get(size2 - 1));
  168 +
  169 + int dt = 10;
  170 + if (d1 < dt && d1 < d2)
  171 + Collections.reverse(all);
  172 + if (d4 < dt && d4 < d3)
  173 + Collections.reverse(sections);
  174 + if (d2 < dt && d2 < d3) {
  175 + Collections.reverse(all);
  176 + Collections.reverse(sections);
  177 + }
  178 +
  179 + //线路交叉点
  180 + Point p = GeoUtils.getLineToLineIntersection(all.get(size - 2), all.get(size - 1)
  181 + , sections.get(0), sections.get(1), 3);
  182 +
  183 + if (null != p) {
  184 + all.set(size - 1, p);
  185 + }
  186 +
  187 + int index = 0;
  188 + boolean bk = false;
  189 + for (int j = 0; j < size2; j++) {
  190 + p = sections.get(j);
  191 + for (int i = size - 1; i > 0; i--) {
  192 + if (!GeoUtils.isPointInLine(p, all.get(i), all.get(i - 1)))
  193 + index = j;
  194 + else {
  195 + bk = true;
  196 + break;
  197 + }
  198 + }
  199 + if (bk) break;
  200 + }
  201 +
  202 + if (index == sections.size() - 1)
  203 + index = 0;
  204 +
  205 + //join
  206 + for (int i = index; i < size2; i++)
  207 + all.add(sections.get(i));
  208 + }
  209 +
  210 + /**
  211 + * 坐标字符串转 List<Point>
  212 + *
  213 + * @param array
  214 + * @return
  215 + */
  216 + private static List<Point> cdsToPoints(String[] array) {
  217 + List<Point> ps = new ArrayList<>(array.length);
  218 + String[] cs;
  219 + Point p;
  220 + for (int i = 0, len = array.length; i < len; i++) {
  221 + cs = array[i].split(" ");
  222 + p = new Point(Double.parseDouble(cs[0]), Double.parseDouble(cs[1]));
  223 + ps.add(p);
  224 + }
  225 + return ps;
  226 + }
  227 +
  228 + private static void initStationGeoField(List<StationRoute> srs) {
  229 + for (StationRoute sr : srs) {
  230 + sr.setPoint(new Point(sr.getLon(), sr.getLat()));
  231 +
  232 + if (sr.getShapesType() == 'd'
  233 + && StringUtils.isNotEmpty(sr.getPolygonStr())
  234 + && sr.getPolygonStr().length() > 9) {
  235 +
  236 + sr.setPolygon(GeoUtils.parsePolygon(sr.getPolygonStr()));
  237 + }
  238 + }
  239 + }
  240 +
  241 + private static boolean isLoop(List<StationRoute> list) {
  242 + int size = list.size();
  243 + if (size != 2)
  244 + return false;
  245 +
  246 + if (list.get(0).getStationCode()
  247 + .equals(list.get(1).getStationCode()))
  248 + return true;
  249 +
  250 + String n1 = list.get(0).getName();
  251 + String n2 = list.get(1).getName();
  252 + if (n1.indexOf(n2) != -1
  253 + || n2.indexOf(n1) != -1)
  254 + return true;
  255 +
  256 + try {
  257 + if (GeoUtils.getDistance(list.get(0).getPoint(), list.get(1).getPoint()) < 50)
  258 + return true;
  259 + } catch (Exception e) {
  260 + return false;
  261 + }
  262 +
  263 + return false;
  264 + }
  265 +
  266 + private static List<Point> subList(List<Point> all, int f, int t) {
  267 + List<Point> sub = new ArrayList<>(t - f);
  268 +
  269 + for (int i = f; i < t; i++) {
  270 + sub.add(all.get(i));
  271 + }
  272 + return sub;
  273 + }
  274 +
  275 + private static class Intersection {
  276 + int index;
  277 + Point p;
  278 + StationRoute s;
  279 + double distance;
  280 +
  281 + public int getIndex() {
  282 + return index;
  283 + }
  284 +
  285 + public void setIndex(int index) {
  286 + this.index = index;
  287 + }
  288 +
  289 + public Point getP() {
  290 + return p;
  291 + }
  292 +
  293 + public void setP(Point p) {
  294 + this.p = p;
  295 + }
  296 +
  297 + public StationRoute getS() {
  298 + return s;
  299 + }
  300 +
  301 + public void setS(StationRoute s) {
  302 + this.s = s;
  303 + }
  304 +
  305 + public double getDistance() {
  306 + return distance;
  307 + }
  308 +
  309 + public void setDistance(double distance) {
  310 + this.distance = distance;
  311 + }
  312 + }
  313 +}
... ...
src/main/java/com/bsth/data/gps/GpsCacheData.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/gps/GpsCacheData.java
  1 +package com.bsth.data.gps;
  2 +
  3 +import com.bsth.data.geo.GeoCacheData;
  4 +import com.bsth.data.gps.util.CircleQueue;
  5 +import com.bsth.data.history.HistoryConsumeTimeDataHandler;
  6 +import com.bsth.entity.GpsEntity;
  7 +import com.bsth.entity.StationRoute;
  8 +import com.google.common.collect.ArrayListMultimap;
  9 +import com.google.common.collect.ListMultimap;
  10 +import com.google.common.collect.Multimaps;
  11 +
  12 +import java.util.ArrayList;
  13 +import java.util.HashMap;
  14 +import java.util.List;
  15 +import java.util.Map;
  16 +import java.util.concurrent.ConcurrentHashMap;
  17 +import java.util.concurrent.ConcurrentMap;
  18 +
  19 +/**
  20 + * GPS 历史缓存 和 实时对照缓存
  21 + */
  22 +public class GpsCacheData {
  23 +
  24 + /**
  25 + * 每个设备缓存最后 200 个 GPS 点位
  26 + */
  27 + private static final int MAX_CACHE_SIZE = 200;
  28 + private static ConcurrentMap<String, CircleQueue> prevMap;
  29 +
  30 + /**
  31 + * 实时gps对照 K: 设备号
  32 + */
  33 + private static ConcurrentMap<String, GpsEntity> realMap;
  34 +
  35 + /**
  36 + * 线路索引的设备号K:lineCode_upDown
  37 + */
  38 + private static ListMultimap<String, String> lineRealMap;
  39 +
  40 + static {
  41 + prevMap = new ConcurrentHashMap<>();
  42 + realMap = new ConcurrentHashMap<>();
  43 + lineRealMap = Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
  44 + }
  45 +
  46 + public static void put(GpsEntity gps) {
  47 + String device = gps.getDeviceId();
  48 + GpsEntity prev = realMap.get(device);
  49 +
  50 + if (null != prev) {
  51 + if (!prev.getCode().equals(gps.getCode())){
  52 + lineRealMap.remove(prev.getCode(), prev.getDeviceId());
  53 + lineRealMap.put(gps.getCode(), gps.getDeviceId());
  54 + }
  55 + putPrev(prev);
  56 + }
  57 + else
  58 + lineRealMap.put(gps.getCode(), gps.getDeviceId());
  59 +
  60 +
  61 + realMap.put(device, gps);
  62 + }
  63 +
  64 + private static void putPrev(GpsEntity prev) {
  65 + String device = prev.getDeviceId();
  66 + CircleQueue queue = prevMap.get(device);
  67 +
  68 + if (null == queue) {
  69 + queue = new CircleQueue(MAX_CACHE_SIZE);
  70 + prevMap.put(device, queue);
  71 + }
  72 +
  73 + queue.add(prev);
  74 + }
  75 +
  76 + /**
  77 + * 获取指定时间之前的轨迹数据
  78 + *
  79 + * @param device
  80 + * @param maxSecond
  81 + * @param minSecond
  82 + * @return 如果数据不满足 < minSecond ,则返回空list
  83 + */
  84 + public static List<GpsEntity> prev(String device, long maxSecond, long minSecond) {
  85 + List<GpsEntity> rs = new ArrayList<>();
  86 + CircleQueue queue = prevMap.get(device);
  87 +
  88 + if (null == queue)
  89 + return rs;
  90 +
  91 + long t = System.currentTimeMillis();
  92 + minSecond = t - (minSecond * 1000);
  93 + maxSecond = t - (maxSecond * 1000);
  94 +
  95 + GpsEntity[] array = queue.getQueue();
  96 +
  97 + if (t - array[0].getTimestamp() < minSecond)
  98 + return rs;
  99 +
  100 + for (int i = array.length - 1; i > 0; i--) {
  101 + if (t - array[i].getTimestamp() > maxSecond)
  102 + break;
  103 + rs.add(array[i]);
  104 + }
  105 + return rs;
  106 + }
  107 +
  108 + public static GpsEntity findOne(String device) {
  109 + return realMap.get(device);
  110 + }
  111 +
  112 + public static Map<String, Object> find(String lineCode, int upDown) {
  113 + List<String> ds = lineRealMap.get(lineCode + "_" + upDown);
  114 +
  115 + List<GpsEntity> list = new ArrayList<>(ds.size());
  116 + for(String d : ds){
  117 + list.add(findOne(d));
  118 + }
  119 +
  120 + Map<String, Object> rs = new HashMap<>();
  121 + rs.put("list", list);
  122 + rs.put("forecast", HistoryConsumeTimeDataHandler.forecastEnd(list));
  123 + return rs;
  124 + }
  125 +
  126 + /**
  127 + * 上一个进出的站点
  128 + *
  129 + * @param gps
  130 + * @return
  131 + */
  132 + public static StationRoute prevInStation(GpsEntity gps) {
  133 + CircleQueue queue = prevMap.get(gps.getDeviceId());
  134 +
  135 + if (null == queue || queue.size() == 0)
  136 + return null;
  137 +
  138 + GpsEntity[] array = queue.getQueue();
  139 +
  140 + GpsEntity prev;
  141 + for (int i = array.length - 1; i > 0; i--) {
  142 + prev = array[i];
  143 +
  144 + if (prev.getInOut() > 0
  145 + && !prev.getStationCode().equals(gps.getStationCode())) {
  146 + return GeoCacheData.findByCode(prev);
  147 + }
  148 + }
  149 + return null;
  150 + }
  151 +
  152 + public static void clear(String deviceId) {
  153 + CircleQueue queue = prevMap.get(deviceId);
  154 + if (null != queue) {
  155 + queue = null;
  156 + prevMap.remove(deviceId);
  157 + }
  158 + }
  159 +}
... ...
src/main/java/com/bsth/data/gps/process/DataMainProcessor.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/gps/process/DataMainProcessor.java
  1 +package com.bsth.data.gps.process;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.bsth.Application;
  5 +import com.bsth.client.GpsDataBuffer;
  6 +import com.bsth.data.BasicCacheData;
  7 +import com.bsth.data.gps.GpsCacheData;
  8 +import com.bsth.data.gps.process.chains.BusinessInfoProcess;
  9 +import com.bsth.data.gps.process.chains.ForecastProcess;
  10 +import com.bsth.data.gps.process.chains.InOutStationProcess;
  11 +import com.bsth.data.gps.process.chains.SectionProcess;
  12 +import com.bsth.data.gps.util.GpsDataUtils;
  13 +import com.bsth.entity.GpsEntity;
  14 +import com.google.common.collect.ArrayListMultimap;
  15 +import org.slf4j.Logger;
  16 +import org.slf4j.LoggerFactory;
  17 +import org.springframework.beans.factory.annotation.Autowired;
  18 +import org.springframework.stereotype.Component;
  19 +
  20 +import java.util.ArrayList;
  21 +import java.util.Collection;
  22 +import java.util.List;
  23 +import java.util.Set;
  24 +import java.util.concurrent.CountDownLatch;
  25 +import java.util.concurrent.ExecutorService;
  26 +import java.util.concurrent.Executors;
  27 +import java.util.concurrent.TimeUnit;
  28 +
  29 +/**
  30 + * 处理gps数据
  31 + */
  32 +@Component
  33 +public class DataMainProcessor {
  34 +
  35 + @Autowired
  36 + DataLoaderThread dataLoaderThread;
  37 +
  38 + @Autowired
  39 + InOutStationProcess inOutStationProcess;
  40 + @Autowired
  41 + SectionProcess sectionProcess;
  42 + @Autowired
  43 + BusinessInfoProcess businessInfoProcess;
  44 + @Autowired
  45 + ForecastProcess forecastProcess;
  46 +
  47 + Logger logger = LoggerFactory.getLogger(this.getClass());
  48 +
  49 + final static int POOL_SIZE = 20;
  50 + static ExecutorService threadPool = Executors.newFixedThreadPool(POOL_SIZE + 1);
  51 + public static CountDownLatch count;
  52 +
  53 + public void start() {
  54 + Application.mainServices.scheduleWithFixedDelay(dataLoaderThread
  55 + , 40, 10, TimeUnit.SECONDS);
  56 + }
  57 +
  58 + public void process(ArrayListMultimap<String, GpsEntity> data) {
  59 + try {
  60 + long t = System.currentTimeMillis();
  61 + List<String> deviceList = new ArrayList(data.keySet());
  62 + //数据均分给线程
  63 + ArrayListMultimap dataListMap = ArrayListMultimap.create();
  64 + int size = deviceList.size(), threadIndex = 0, threadSize = size / POOL_SIZE;
  65 + if (threadSize == 0)
  66 + threadSize = size;
  67 + for (int i = 0; i < size; i++) {
  68 + if (i % threadSize == 0)
  69 + threadIndex++;
  70 + dataListMap.putAll(threadIndex, data.get(deviceList.get(i)));
  71 + }
  72 +
  73 + Set<Integer> ks = dataListMap.keySet();
  74 + logger.info("analyse gps size: " + data.size() + ", ks: " + ks.size());
  75 + count = new CountDownLatch(ks.size());
  76 +
  77 + logger.info(JSON.toJSONString(ks));
  78 + for (Integer index : ks) {
  79 + threadPool.execute(new NewSignalHandleThread(dataListMap.get(index), count));
  80 + //new NewSignalHandleThread(dataListMap.get(index), count).run();
  81 + }
  82 +
  83 +
  84 + //等待子线程结束
  85 + count.await();
  86 +
  87 + //加入实时gps对照
  88 + Collection<GpsEntity> vs = data.values();
  89 + for (GpsEntity gps : vs)
  90 + GpsCacheData.put(gps);
  91 + logger.info("time , " + (System.currentTimeMillis() - t));
  92 + } catch (Exception e) {
  93 + logger.error("", e);
  94 + }
  95 + }
  96 +
  97 + @Component
  98 + public class DataLoaderThread implements Runnable {
  99 +
  100 + @Override
  101 + public void run() {
  102 + try {
  103 + List<GpsEntity> list = GpsDataUtils.clearInvalid(GpsDataBuffer.pollAll());
  104 + ArrayListMultimap<String, GpsEntity> data = ArrayListMultimap.create();
  105 +
  106 + for (GpsEntity gps : list) {
  107 + gps.setNbbm(BasicCacheData.device2nbbmMap.get(gps.getDeviceId()));
  108 + data.put(gps.getDeviceId(), gps);
  109 + }
  110 +
  111 + process(data);
  112 + } catch (Exception e) {
  113 + logger.error("", e);
  114 + }
  115 + }
  116 + }
  117 +
  118 + public class NewSignalHandleThread implements Runnable {
  119 +
  120 + List<GpsEntity> list;
  121 + CountDownLatch count;
  122 +
  123 + NewSignalHandleThread(List<GpsEntity> list, CountDownLatch count) {
  124 + this.list = list;
  125 + this.count = count;
  126 + }
  127 +
  128 + Logger logger2 = LoggerFactory.getLogger(this.getClass());
  129 +
  130 + @Override
  131 + public void run() {
  132 + try {
  133 + for (GpsEntity gps : list) {
  134 + try {
  135 + inOutStationProcess.process(gps);//进出站处理
  136 + businessInfoProcess.process(gps);//业务信息
  137 + sectionProcess.process(gps);//路段相关处理,越界、越站、到下站距离
  138 + forecastProcess.process(gps);//计算均速,时间预测
  139 + } catch (Exception e) {
  140 + logger2.error("", e);
  141 + }
  142 + }
  143 + } finally {
  144 + count.countDown();
  145 + }
  146 + }
  147 + }
  148 +}
... ...
src/main/java/com/bsth/data/gps/process/chains/BusinessInfoProcess.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/gps/process/chains/BusinessInfoProcess.java
  1 +package com.bsth.data.gps.process.chains;
  2 +
  3 +import com.bsth.data.schedule.ScheduleCacheData;
  4 +import com.bsth.data.schedule.entity.ScheduleRealInfo;
  5 +import com.bsth.entity.GpsEntity;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +/**
  9 + * 班次、业务信息
  10 + */
  11 +@Component
  12 +public class BusinessInfoProcess {
  13 +
  14 + public void process(GpsEntity gps) {
  15 +
  16 + ScheduleRealInfo sch = ScheduleCacheData.get(gps.getNbbm());
  17 +
  18 + if (null == sch
  19 + || !sch.getXlBm().equals(gps.getLineId())
  20 + || sch.getXlDir() != gps.getUpDown().intValue()) {
  21 +
  22 + return;
  23 + }
  24 +
  25 + gps.setSch(sch);
  26 + }
  27 +}
... ...
src/main/java/com/bsth/data/gps/process/chains/ForecastProcess.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/gps/process/chains/ForecastProcess.java
  1 +package com.bsth.data.gps.process.chains;
  2 +
  3 +import com.bsth.data.geo.GeoCacheData;
  4 +import com.bsth.data.gps.GpsCacheData;
  5 +import com.bsth.data.history.HistoryConsumeTimeDataHandler;
  6 +import com.bsth.entity.GpsEntity;
  7 +import com.bsth.entity.StationRoute;
  8 +import com.bsth.util.geo.GeoUtils;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * 来来 我是一个菠菜 菜菜菜菜菜菜
  15 + */
  16 +@Component
  17 +public class ForecastProcess {
  18 +
  19 + private final static int OFFLINE_TIME = 1000 * 60 * 3;
  20 + private final static int OUT_BOUNDS = 80;
  21 +
  22 + public void process(GpsEntity gps) {
  23 + //获取10分钟内的点位,如果不够,5分钟也行
  24 + List<GpsEntity> list = GpsCacheData.prev(gps.getDeviceId(), 60 * 10, 60 * 5);
  25 + list.add(gps);
  26 +
  27 + //有效的,健康的轨迹
  28 + if (isValidSignal(list)) {
  29 + GpsEntity first = list.get(0);
  30 + double sumDist = GeoUtils.getDistance(first, gps);//行驶距离
  31 + double seconds = (gps.getTimestamp() - first.getTimestamp()) / 1000;//耗时
  32 + double avgSpeed = sumDist / seconds;//均速
  33 + gps.setSeconds((int) (gps.getDistance() / avgSpeed));//到下一站的时间
  34 + } else {
  35 +
  36 + //用行驶距离 的比例 取计划时间
  37 + StationRoute s = GeoCacheData.findByCode(gps);
  38 + if (null != s && null != gps.getDistance()) {
  39 + double scale = gps.getDistance() / s.getLength();
  40 + Integer time = HistoryConsumeTimeDataHandler.findConsume(gps);
  41 +
  42 + if (null != time)
  43 + gps.setSeconds((int) (time * scale));
  44 + }
  45 + }
  46 + }
  47 +
  48 +/* private Integer[] getJHTimeArray(GpsEntity gps) {
  49 + List<StationRoute> srs = GeoCacheData.find(gps.getLineId(), gps.getUpDown());
  50 + String sCode = gps.getStationCode()
  51 + , eCode = srs.get(srs.size() - 1).getStationCode();
  52 +
  53 + ScheduleRealInfo sch = gps.getSch();
  54 + if (null != sch
  55 + && null != sch.getQdzCode()
  56 + && null != sch.getZdzCode()) {
  57 +
  58 + eCode = sch.getZdzCode();
  59 + }
  60 +
  61 + return HistoryConsumeTimeDataHandler.findConsumeArray(gps.getLineId(), gps.getUpDown(), sCode, eCode);
  62 + }*/
  63 +
  64 + private boolean isValidSignal(List<GpsEntity> list) {
  65 + if (list.size() <= 1)
  66 + return false;
  67 +
  68 + if (isChangeUpDown(list))
  69 + return false;
  70 +
  71 + if (isOfflineSignal(list))
  72 + return false;
  73 +
  74 + return !isOutOfBounds(list);
  75 + }
  76 +
  77 + /**
  78 + * 是否是同一个走向的轨迹
  79 + *
  80 + * @param list
  81 + * @return
  82 + */
  83 + private boolean isChangeUpDown(List<GpsEntity> list) {
  84 + int size = list.size(), upDown = list.get(size - 1).getUpDown();
  85 +
  86 + for (int i = size - 2; i > 0; i--) {
  87 + if (list.get(i).getUpDown().intValue() != upDown)
  88 + return true;
  89 + }
  90 + return false;
  91 + }
  92 +
  93 + /**
  94 + * 是否有大幅度越界
  95 + *
  96 + * @param list
  97 + * @return
  98 + */
  99 + private boolean isOutOfBounds(List<GpsEntity> list) {
  100 + for (int i = 0, size = list.size(); i < size; i++) {
  101 + if (list.get(i).getOverstepDistance() >= OUT_BOUNDS)
  102 + return true;
  103 + }
  104 +
  105 + return false;
  106 + }
  107 +
  108 + /**
  109 + * 是否有掉线
  110 + *
  111 + * @param list
  112 + * @return
  113 + */
  114 + private boolean isOfflineSignal(List<GpsEntity> list) {
  115 +
  116 + for (int i = 0, size = list.size() - 1; i < size; i++) {
  117 + if (list.get(i + 1).getTimestamp() - list.get(i).getTimestamp() >= OFFLINE_TIME)
  118 + return true;
  119 + }
  120 + return false;
  121 + }
  122 +}
... ...
src/main/java/com/bsth/data/gps/process/chains/InOutStationProcess.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/gps/process/chains/InOutStationProcess.java
  1 +package com.bsth.data.gps.process.chains;
  2 +
  3 +import com.bsth.data.geo.GeoCacheData;
  4 +import com.bsth.data.gps.GpsCacheData;
  5 +import com.bsth.data.history.HistoryConsumeTimeDataHandler;
  6 +import com.bsth.data.schedule.entity.ScheduleRealInfo;
  7 +import com.bsth.entity.ArriveStationDetail;
  8 +import com.bsth.entity.CarPark;
  9 +import com.bsth.entity.GpsEntity;
  10 +import com.bsth.entity.StationRoute;
  11 +import com.bsth.util.geo.GeoUtils;
  12 +import org.slf4j.Logger;
  13 +import org.slf4j.LoggerFactory;
  14 +import org.springframework.beans.factory.annotation.Autowired;
  15 +import org.springframework.stereotype.Component;
  16 +
  17 +import java.util.List;
  18 +
  19 +/**
  20 + * 车辆进出站处理
  21 + */
  22 +@Component
  23 +public class InOutStationProcess {
  24 +
  25 + @Autowired
  26 + HistoryConsumeTimeDataHandler historyConsumeTimeData;
  27 +
  28 + Logger logger = LoggerFactory.getLogger(this.getClass());
  29 +
  30 + public void process(GpsEntity gps) {
  31 +
  32 + GpsEntity prev = GpsCacheData.findOne(gps.getDeviceId());
  33 +
  34 + //是否在场内
  35 + String parkCode = GeoUtils.gpsInCarpark(gps);
  36 + if (null != parkCode) {
  37 + gps.setParkCode(parkCode);
  38 + gps.setStationCode(parkCode);
  39 + gps.setInOut(2);
  40 +
  41 + CarPark cp = GeoCacheData.getCarPark(parkCode);
  42 + if (null != cp)
  43 + gps.setStationName(cp.getName());
  44 +
  45 + gps.setRelease(false);
  46 + }
  47 +
  48 + //是否在站内
  49 + List<StationRoute> srs = GeoCacheData.find(gps.getLineId(), gps.getUpDown());
  50 + ArriveStationDetail sDetail = GeoUtils.gpsInStation(gps, srs);
  51 + StationRoute s = null;
  52 +
  53 + if (null != sDetail) {
  54 + s = sDetail.getSr();
  55 + gps.setInOut(1);
  56 + gps.setStationCode(s.getStationCode());
  57 + gps.setInStationDistance(sDetail.getDistance());
  58 + gps.setStationName(s.getName());
  59 + gps.setStationNo(s.getSerialNo());
  60 +
  61 + //起点站站内的信号,不发布
  62 + if ("B".equals(s.getMark()))
  63 + gps.setRelease(false);
  64 +
  65 + } else if (null != prev && gps.getInOut() == 0) {
  66 + gps.setStationCode(prev.getStationCode());
  67 + gps.setStationName(prev.getStationName());
  68 + gps.setStationNo(prev.getStationNo());
  69 + }
  70 +
  71 + if (null == prev || null == prev.getStationCode())
  72 + return;
  73 +
  74 + //进站1 从站外到站内
  75 + if (prev.getInOut() == 0 && gps.getInOut() > 0)
  76 + inStation(gps, prev);
  77 +
  78 + //进站2 从站内到另一个站内
  79 + if (prev.getInOut() == 1 && gps.getInOut() == 1
  80 + && !prev.getStationCode().equals(gps.getStationCode()))
  81 + inStation(gps, prev);
  82 +
  83 + //进站3 从场内到站内
  84 + if (prev.getInOut() == 2 && gps.getInOut() == 1)
  85 + inStation(gps, prev);
  86 +
  87 +
  88 + //出站1 从站内到站外
  89 + if (prev.getInOut() > 0 && gps.getInOut() == 0)
  90 + outStation(gps);
  91 +
  92 + //出站2 从站内到另一个站内
  93 + if (prev.getInOut() > 0 && gps.getInOut() > 0
  94 + && !prev.getStationCode().equals(gps.getStationCode()))
  95 + outStation(gps);
  96 + }
  97 +
  98 + private void inStation(GpsEntity gps, GpsEntity prev) {
  99 + StationRoute s;
  100 + /**
  101 + * 网关每次在车辆进线路终点的时候
  102 + * 会切换走向,把 “终点的进站信号” 变成下一个走向的 “起点站内信号”
  103 + * 在这里恢复一下信号,不然会缺少终点站的到站数据,而且会又走向抖动
  104 + *
  105 + * PS:调度系统是信任班次走向的,但是也仍然处理了这个问题,减少走向同步指令的下发
  106 + * PS:信息发布是信任设备网关走向的,所以必须处理这个问题
  107 + * by panzhao 2018-06-13
  108 + *
  109 + * 说不定网关哪天把代码改了,这段代码就可以删掉
  110 + */
  111 + StationRoute prevStation = GeoCacheData.findByCode(prev);
  112 + s = GeoCacheData.findByCode(gps);
  113 + if (gps.getUpDown().intValue() != prev.getUpDown().intValue()
  114 + && null != s
  115 + && null != prevStation
  116 + && "B".equals(s.getMark())
  117 + && !"E".equals(prevStation.getMark())) {
  118 +
  119 + gps.setUpDown(prev.getUpDown());
  120 + gps.setStationCode(null);
  121 + gps.setInStationDistance(null);
  122 + //重新判定到离站
  123 + process(gps);
  124 + logger.info("纠正网关的终点进站信号,,-" + gps.getDeviceId() + " station: " + s.getStationCode() + " -time: " + gps.getTimestamp());
  125 + return;
  126 + }
  127 +
  128 + s = GeoCacheData.findByCode(gps);
  129 + if (null == s)
  130 + return;
  131 +
  132 + //存一份站点间耗时数据
  133 + historyConsumeTimeData.in(gps, prev);
  134 +
  135 + if ("B".equals(s.getMark())
  136 + || "E".equals(s.getMark()))
  137 + GpsCacheData.clear(gps.getDeviceId());
  138 +
  139 + ScheduleRealInfo sch = gps.getSch();
  140 + if (null != sch && sch.getZdzName().equals(s.getName()))
  141 + GpsCacheData.clear(gps.getDeviceId());
  142 + }
  143 +
  144 + private void outStation(GpsEntity gps) {
  145 + StationRoute s = GeoCacheData.findByCode(gps);
  146 +
  147 + if (null == s)
  148 + return;
  149 +
  150 + //出站距离
  151 + gps.setOutStationDistance(GeoUtils.getDistance(gps.getPoint(), s.getPoint()));
  152 +
  153 + if ("B".equals(s.getMark()))
  154 + GpsCacheData.clear(gps.getDeviceId());
  155 +
  156 + ScheduleRealInfo sch = gps.getSch();
  157 + if (null != sch && sch.getQdzName().equals(s.getName()))
  158 + GpsCacheData.clear(gps.getDeviceId());
  159 + }
  160 +}
... ...
src/main/java/com/bsth/data/gps/process/chains/SectionProcess.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/gps/process/chains/SectionProcess.java
  1 +package com.bsth.data.gps.process.chains;
  2 +
  3 +import com.bsth.data.geo.GeoCacheData;
  4 +import com.bsth.data.schedule.entity.ScheduleRealInfo;
  5 +import com.bsth.entity.GpsEntity;
  6 +import com.bsth.entity.IntersePoint;
  7 +import com.bsth.entity.StationRoute;
  8 +import com.bsth.util.geo.GeoUtils;
  9 +import com.bsth.util.geo.Point;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +import org.springframework.stereotype.Component;
  13 +
  14 +import java.text.DecimalFormat;
  15 +import java.util.ArrayList;
  16 +import java.util.List;
  17 +
  18 +/**
  19 + * 路段相关处理,越界、越站、到下站距离
  20 + */
  21 +@Component
  22 +public class SectionProcess {
  23 +
  24 + Logger logger = LoggerFactory.getLogger(this.getClass());
  25 + static DecimalFormat df = new DecimalFormat("#.00");
  26 +
  27 + public void process(GpsEntity gps) {
  28 + /*if (gps.getDeviceId().equals("226L4179"))
  29 + System.out.println("aaa");*/
  30 +
  31 + ScheduleRealInfo sch = gps.getSch();
  32 + if (null != sch && sch.isInOut())
  33 + return; //执行进出场班次
  34 +
  35 + //计算越界和越站
  36 + if (gps.getInOut() == 0)
  37 + calcOverstep(gps);
  38 +
  39 + List<Point> ps;
  40 + //计算到下一站的距离
  41 + StationRoute s = GeoCacheData.findByCode(gps);
  42 + if (null != s && !"E".equals(s.getMark())) {
  43 + List<Point> paths = s.getPaths();
  44 + if (null == paths)
  45 + return;
  46 +
  47 + IntersePoint intersePoint = GeoUtils.pointToLineNearPoint(gps.getPoint(), paths);
  48 +
  49 + if (null != intersePoint
  50 + && intersePoint.getIndex() < paths.size()) {
  51 +
  52 + ps = subList(paths, intersePoint.getIndex() + 1, paths.size());
  53 + gps.setDistance(GeoUtils.getDistance(ps));
  54 + }
  55 + }
  56 + }
  57 +
  58 + private List<Point> subList(List<Point> all, int f, int t) {
  59 + List<Point> sub = new ArrayList<>(t - f);
  60 +
  61 + for (int i = f; i < t; i++) {
  62 + sub.add(all.get(i));
  63 + }
  64 + return sub;
  65 + }
  66 +
  67 + /**
  68 + * 越界和越站
  69 + *
  70 + * @param gps
  71 + */
  72 + private void calcOverstep(GpsEntity gps) {
  73 + Point p = gps.getPoint();
  74 + List<Point> ps;
  75 + StationRoute near = null;
  76 + double distance, min = -1;
  77 +
  78 + /**
  79 + * 如果切割的路段数据无效,直接用原始路段计算一下越界距离就好了
  80 + */
  81 + if (!GeoCacheData.isValidSection(gps.getLineId(), gps.getUpDown())) {
  82 + List<Point> all = GeoCacheData.getFullSection(gps.getLineId(), gps.getUpDown());
  83 + for (int i = 0, size = all.size() - 1; i < size; i++) {
  84 + distance = GeoUtils.getDistanceFromLine(all.get(i), all.get(i + 1), p);
  85 +
  86 + if (Double.isNaN(distance))
  87 + continue;
  88 +
  89 + if (min == -1 || distance < min)
  90 + min = distance;
  91 + }
  92 +
  93 + gps.setOverstepDistance(Double.parseDouble(df.format(min)));
  94 + return;
  95 + }
  96 +
  97 + //越界距离
  98 + List<StationRoute> srs = GeoCacheData.find(gps.getLineId(), gps.getUpDown());
  99 + for (StationRoute sr : srs) {
  100 + ps = sr.getPaths();
  101 + if (null == ps)
  102 + continue;
  103 + for (int i = 0, len = ps.size() - 1; i < len; i++) {
  104 + distance = GeoUtils.getDistanceFromLine(ps.get(i), ps.get(i + 1), p);
  105 +
  106 + if (Double.isNaN(distance))
  107 + continue;
  108 +
  109 + if (min == -1 || distance < min) {
  110 + min = distance;
  111 + near = sr;
  112 + }
  113 + }
  114 + }
  115 + gps.setOverstepDistance(Double.parseDouble(df.format(min)));
  116 +
  117 + //越站
  118 + if (null != near
  119 + && null != gps.getStationCode()
  120 + && min < 20
  121 + && gps.getInOut() == 0
  122 + && !near.getStationCode().equals(gps.getStationCode())) {
  123 + logger.info("本宝宝说你越站就是越站, nbbm: " + gps.getNbbm() + " -t: " + gps.getTimestamp());
  124 +
  125 + gps.setStationCode(near.getStationCode());
  126 + gps.setInStationDistance(null);
  127 + }
  128 + }
  129 +}
... ...
src/main/java/com/bsth/data/gps/util/CircleQueue.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/gps/util/CircleQueue.java
  1 +package com.bsth.data.gps.util;
  2 +
  3 +import com.bsth.entity.GpsEntity;
  4 +
  5 +import java.util.Arrays;
  6 +
  7 +/**
  8 + * GPS 循环队列缓存
  9 + * Created by panzhao on 2016/12/23.
  10 + */
  11 +public class CircleQueue {
  12 +
  13 + /**
  14 + * (循环队列)数组的容量
  15 + */
  16 + public int capacity;
  17 +
  18 + /**
  19 + * 数组:保存循环队列的元素
  20 + */
  21 + public GpsEntity[] elementData;
  22 +
  23 + /**
  24 + * 头
  25 + */
  26 + public int head = 0;
  27 +
  28 + /**
  29 + * 尾
  30 + */
  31 + public int tail = 0;
  32 +
  33 + /**
  34 + * 以指定长度的数组来创建循环队列
  35 + *
  36 + * @param initSize
  37 + */
  38 + public CircleQueue(final int initSize) {
  39 + capacity = initSize;
  40 + elementData = new GpsEntity[capacity];
  41 + }
  42 +
  43 + /**
  44 + * 获取循环队列的大小
  45 + */
  46 + public int size() {
  47 + if (isEmpty()) {
  48 + return 0;
  49 + } else if (isFull()) {
  50 + return capacity;
  51 + } else {
  52 + return tail + 1;
  53 + }
  54 + }
  55 +
  56 + /**
  57 + * 插入队尾一个元素
  58 + */
  59 + public void add(final GpsEntity element) {
  60 + if (isEmpty()) {
  61 + elementData[0] = element;
  62 + } else if (isFull()) {
  63 + elementData[head] = element;
  64 + head++;
  65 + tail++;
  66 + head = head == capacity ? 0 : head;
  67 + tail = tail == capacity ? 0 : tail;
  68 + } else {
  69 + elementData[tail + 1] = element;
  70 + tail++;
  71 + }
  72 + }
  73 +
  74 + public boolean isEmpty() {
  75 + return tail == head && tail == 0 && elementData[tail] == null;
  76 + }
  77 +
  78 + public boolean isFull() {
  79 + return head != 0 && head - tail == 1 || head == 0 && tail == capacity - 1;
  80 + }
  81 +
  82 + public void clear() {
  83 + Arrays.fill(elementData, null);
  84 + head = 0;
  85 + tail = 0;
  86 + }
  87 +
  88 + /**
  89 + * @return 取 循环队列里的值(先进的index=0)
  90 + */
  91 + public GpsEntity[] getQueue() {
  92 + final GpsEntity[] elementDataSort;
  93 + final GpsEntity[] elementDataCopy = elementData.clone();
  94 +
  95 + if (isEmpty()) {
  96 + elementDataSort = new GpsEntity[0];
  97 + } else if (isFull()) {
  98 + elementDataSort = new GpsEntity[capacity];
  99 + int indexMax = capacity;
  100 + int indexSort = 0;
  101 + for (int i = head; i < indexMax; ) {
  102 + elementDataSort[indexSort] = elementDataCopy[i];
  103 + indexSort++;
  104 + i++;
  105 + if (i == capacity) {
  106 + i = 0;
  107 + indexMax = head;
  108 + }
  109 + }
  110 + } else {
  111 + elementDataSort = new GpsEntity[tail + 1];
  112 + for (int i = 0; i <= tail; i++) {
  113 + elementDataSort[i] = elementDataCopy[i];
  114 + }
  115 + }
  116 + return elementDataSort;
  117 + }
  118 +
  119 + public GpsEntity[] getQueue(int len) {
  120 + GpsEntity[] all = getQueue();
  121 + if (all.length < len)
  122 + len = all.length;
  123 +
  124 + GpsEntity[] array = new GpsEntity[len];
  125 +
  126 + for (int i = all.length - 1, c = 0; i >= 0; i--, c++) {
  127 + if (c >= len)
  128 + break;
  129 + array[c] = all[i];
  130 + }
  131 + return array;
  132 + }
  133 +
  134 + /**
  135 + * 取最后一个值
  136 + *
  137 + * @return
  138 + */
  139 + public GpsEntity getTail() {
  140 + return elementData[tail] == null ? null : elementData[tail];
  141 + }
  142 +}
0 143 \ No newline at end of file
... ...
src/main/java/com/bsth/data/gps/util/GpsDataUtils.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/gps/util/GpsDataUtils.java
  1 +package com.bsth.data.gps.util;
  2 +
  3 +import com.bsth.data.gps.GpsCacheData;
  4 +import com.bsth.entity.GpsEntity;
  5 +import org.apache.commons.lang3.StringUtils;
  6 +import org.slf4j.Logger;
  7 +import org.slf4j.LoggerFactory;
  8 +
  9 +import java.util.ArrayList;
  10 +import java.util.List;
  11 +
  12 +public class GpsDataUtils {
  13 +
  14 + static Logger logger = LoggerFactory.getLogger(GpsDataUtils.class);
  15 +
  16 + private final static long MAX_DIFF = 1000 * 60 * 60 * 24;
  17 +
  18 + public static List<GpsEntity> clearInvalid(List<GpsEntity> list) {
  19 +
  20 + List<GpsEntity> rs = new ArrayList<>();
  21 + long t = System.currentTimeMillis();
  22 +
  23 + try {
  24 + GpsEntity prev;
  25 + for (GpsEntity gps : list) {
  26 +
  27 + if (StringUtils.isBlank(gps.getDeviceId()))
  28 + continue;
  29 +
  30 + if (gps.getValid() == 1)
  31 + continue;
  32 +
  33 + if (null == gps.getLineId())
  34 + continue;
  35 +
  36 + if (Math.abs(gps.getTimestamp() - t) > MAX_DIFF)
  37 + gps.setTimestamp(t + 1);//尝试校准GPS时间
  38 +
  39 + prev = GpsCacheData.findOne(gps.getDeviceId());
  40 +
  41 + //不接收过期数据
  42 + if (prev != null) {
  43 +
  44 + if (gps.getTimestamp().longValue() < prev.getTimestamp().longValue())
  45 + continue;
  46 +
  47 + if (prev.getTimestamp().equals(gps.getTimestamp()) &&
  48 + prev.getLat().equals(gps.getLat()) &&
  49 + prev.getLon().equals(gps.getLon()))
  50 + continue;
  51 + }
  52 +
  53 + if (Math.abs(gps.getTimestamp() - gps.getServerTimestamp()) < 1000 * 60 * 20)
  54 + rs.add(gps);
  55 + }
  56 + } catch (Exception e) {
  57 + logger.error("", e);
  58 + }
  59 + return rs;
  60 + }
  61 +}
... ...
src/main/java/com/bsth/data/history/HistoryConsumeTimeDataHandler.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/history/HistoryConsumeTimeDataHandler.java
  1 +package com.bsth.data.history;
  2 +
  3 +import com.bsth.Application;
  4 +import com.bsth.data.geo.GeoCacheData;
  5 +import com.bsth.data.history.entity.LineConsumeTime;
  6 +import com.bsth.data.history.entity.StationConsumeTime;
  7 +import com.bsth.entity.GpsEntity;
  8 +import com.bsth.entity.StationRoute;
  9 +import com.bsth.util.DateUtils;
  10 +import com.bsth.util.db_utils.DBUtils_InfoPublish;
  11 +import com.google.common.collect.ArrayListMultimap;
  12 +import com.google.common.collect.BiMap;
  13 +import com.google.common.collect.HashBiMap;
  14 +import org.joda.time.DateTime;
  15 +import org.joda.time.format.DateTimeFormat;
  16 +import org.joda.time.format.DateTimeFormatter;
  17 +import org.slf4j.Logger;
  18 +import org.slf4j.LoggerFactory;
  19 +import org.springframework.beans.factory.annotation.Autowired;
  20 +import org.springframework.jdbc.core.BatchPreparedStatementSetter;
  21 +import org.springframework.jdbc.core.BeanPropertyRowMapper;
  22 +import org.springframework.jdbc.core.JdbcTemplate;
  23 +import org.springframework.stereotype.Component;
  24 +
  25 +import java.sql.PreparedStatement;
  26 +import java.sql.SQLException;
  27 +import java.util.*;
  28 +import java.util.concurrent.ConcurrentHashMap;
  29 +import java.util.concurrent.ConcurrentLinkedQueue;
  30 +import java.util.concurrent.ConcurrentMap;
  31 +import java.util.concurrent.TimeUnit;
  32 +
  33 +/**
  34 + * 历史的站点间耗时数据
  35 + */
  36 +@Component
  37 +public class HistoryConsumeTimeDataHandler {
  38 +
  39 + /**
  40 + * K: 设备号 V:最后一个进站信号(实时)
  41 + */
  42 + private static ConcurrentMap<String, GpsEntity> lastInStationMap;
  43 +
  44 + /**
  45 + * 等待持久化入库的站点间 耗时 数据
  46 + * 070000 ~ 090000 早高峰 0
  47 + * 173000 ~ 190000 晚高峰 2
  48 + * 其他都算平峰 1
  49 + */
  50 + private static ConcurrentLinkedQueue<StationConsumeTime> pstQueue;
  51 + private final static int MORNING_PEAK_S = 70000;
  52 + private final static int MORNING_PEAK_E = 94000;
  53 + private final static int EVENIGN_PEAK_S = 173000;
  54 + private final static int EVENIGN_PEAK_E = 190000;
  55 +
  56 +
  57 + /**
  58 + * K : lineCode_upDown
  59 + */
  60 + private static ConcurrentMap<String, LineConsumeTime> lctMaps;
  61 +
  62 + Logger logger = LoggerFactory.getLogger(this.getClass());
  63 +
  64 + static {
  65 + lastInStationMap = new ConcurrentHashMap();
  66 + pstQueue = new ConcurrentLinkedQueue<>();
  67 + lctMaps = new ConcurrentHashMap();
  68 + }
  69 +
  70 +
  71 + @Autowired
  72 + ConsumeTimePstThread consumeTimePstThread;
  73 +
  74 + @Autowired
  75 + ConsumeTimeLoadThread consumeTimeLoadThread;
  76 +
  77 + private static DateTimeFormatter fmtHHmmss = DateTimeFormat.forPattern("HHmmss");
  78 +
  79 + public static Map<String, Integer> forecastEnd(List<GpsEntity> list) {
  80 +
  81 + int v = Integer.parseInt(fmtHHmmss.print(System.currentTimeMillis()));
  82 + int peakVal = 1;
  83 + if (v > MORNING_PEAK_S && v < MORNING_PEAK_E)
  84 + peakVal = 0;
  85 + else if (v > EVENIGN_PEAK_S && v < EVENIGN_PEAK_E)
  86 + peakVal = 2;
  87 +
  88 + Map<String, Integer> rs = new HashMap<>();
  89 +
  90 + for (GpsEntity gps : list) {
  91 + rs.put(gps.getDeviceId(), forecastEnd(gps, peakVal));
  92 + }
  93 +
  94 + return rs;
  95 + }
  96 +
  97 + private static Integer forecastEnd(GpsEntity gps, int peakVal) {
  98 + int sum = 0;
  99 + Integer[] ns = findConsumeArray(gps, peakVal);
  100 +
  101 + if (null == ns)
  102 + return 0;
  103 + for (int i = 1, len = ns.length; i < len; i++) {
  104 + sum += ns[i];
  105 + }
  106 +
  107 + return sum + gps.getSeconds();
  108 + }
  109 +
  110 + public void start() {
  111 + //将到离站数据入库
  112 + //Application.mainServices.scheduleWithFixedDelay(consumeTimePstThread
  113 + // , 60, 30, TimeUnit.SECONDS);
  114 +
  115 +
  116 + //凌晨一点
  117 + long timeDiff = (DateUtils.getTimestamp() + 1000 * 60 * 60) - System.currentTimeMillis();
  118 + if (timeDiff < 0)
  119 + timeDiff += (1000 * 60 * 60 * 24);
  120 + //从数据库加载上周的数据,做当天的预测用
  121 + Application.mainServices.scheduleAtFixedRate(consumeTimeLoadThread
  122 + , timeDiff, 60 * 60 * 24, TimeUnit.SECONDS);
  123 +
  124 + if (timeDiff > 1000 * 60 * 30)
  125 + consumeTimeLoadThread.run();
  126 + }
  127 +
  128 + public static LineConsumeTime getLct(String lineCode, int upDown) {
  129 + return lctMaps.get(lineCode + "_" + upDown);
  130 + }
  131 +
  132 + public static Integer[] findConsumeArray(GpsEntity gps, int peakVal) {
  133 + String sCode = gps.getStationCode()
  134 + , eCode = null;
  135 + if (null != gps.getSch())
  136 + eCode = gps.getSch().getZdzCode();
  137 + else {
  138 + List<StationRoute> srs = GeoCacheData.find(gps.getLineId(), gps.getUpDown());
  139 + eCode = srs.get(srs.size() - 1).getStationCode();
  140 + }
  141 + return findConsumeArray(gps.getLineId(), gps.getUpDown(), sCode, eCode, peakVal);
  142 + }
  143 +
  144 + public static Integer[] findConsumeArray(String lineCode, int upDown, String sCode, String eCode, int peakVal) {
  145 + LineConsumeTime lct = lctMaps.get(lineCode + "_" + upDown + "_" + peakVal);
  146 + if (null != lct) {
  147 + Map<String, Integer> code2iMap = lct.getCode2iMap();
  148 + Integer[] array = lct.getTimes();
  149 + Integer s = code2iMap.get(sCode), e = code2iMap.get(eCode);
  150 +
  151 + if (null == s)
  152 + s = 0;
  153 + if (null == e)
  154 + e = array.length - 1;
  155 +
  156 + Integer[] ns = new Integer[e - s];
  157 +
  158 + for (int i = 0; s < e; s++, i++)
  159 + ns[i] = array[s];
  160 +
  161 + return ns;
  162 + }
  163 + return null;
  164 + }
  165 +
  166 + public static Integer findConsume(GpsEntity gps) {
  167 + int peakVal = 1;
  168 + int v = Integer.parseInt(fmtHHmmss.print(gps.getTimestamp()));
  169 + if (v > MORNING_PEAK_S && v < MORNING_PEAK_E)
  170 + peakVal = 0;
  171 + else if (v > EVENIGN_PEAK_S && v < EVENIGN_PEAK_E)
  172 + peakVal = 2;
  173 +
  174 + String key = gps.getLineId() + "_" + gps.getUpDown() + "_" + peakVal;
  175 + String code = gps.getStationCode();
  176 +
  177 + LineConsumeTime lct = lctMaps.get(key);
  178 + if (null != lct) {
  179 + Map<String, Integer> code2iMap = lct.getCode2iMap();
  180 + Integer index = code2iMap.get(code);
  181 + if (null == index)
  182 + return null;
  183 +
  184 + return lct.getTimes()[index];
  185 + }
  186 + return null;
  187 + }
  188 +
  189 + public void in(GpsEntity gps, GpsEntity prev) {
  190 + if (gps.getInOut() != 1
  191 + || gps.getStationCode().equals(prev.getStationCode()))
  192 + return;
  193 +
  194 + GpsEntity lastInGps = lastInStationMap.get(gps.getDeviceId());
  195 + if (null == lastInGps)
  196 + lastInStationMap.put(gps.getDeviceId(), gps);
  197 +
  198 + if (gps.getUpDown().intValue() != prev.getUpDown().intValue()
  199 + || null == lastInGps
  200 + || !lastInGps.getStationCode().equals(prev.getStationCode())
  201 + || prev.getTimestamp() - lastInGps.getTimestamp() > 1000 * 60 * 60)
  202 + return;
  203 +
  204 + StationConsumeTime sct = StationConsumeTime.getInstance(lastInGps, gps);
  205 + pstQueue.add(sct);
  206 + lastInStationMap.put(gps.getDeviceId(), gps);
  207 + }
  208 +
  209 + @Component
  210 + public class ConsumeTimeLoadThread implements Runnable {
  211 +
  212 + @Override
  213 + public void run() {
  214 + try {
  215 +
  216 + logger.info("Load ConsumeTime start");
  217 + DateTime dt = new DateTime();
  218 + dt.minusDays(7);//减7天
  219 + String rq = dt.toString("yyyyMMdd ");
  220 +
  221 + rq = "20180620";
  222 + String sql = "select * from bsth_h_consume_time where rq=" + rq;
  223 + JdbcTemplate jdbcTemplate = new JdbcTemplate(DBUtils_InfoPublish.getDataSource());
  224 + List<StationConsumeTime> list =
  225 + jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(StationConsumeTime.class));
  226 +
  227 + logger.info("select end,, " + list.size());
  228 + //按线路、走向、早晚高峰分组
  229 + ArrayListMultimap<String, StationConsumeTime> multimap = ArrayListMultimap.create();
  230 + int peakVal, v;
  231 + for (StationConsumeTime sct : list) {
  232 + peakVal = 1;
  233 + v = Integer.parseInt(sct.getTimeStr());
  234 + if (v > MORNING_PEAK_S && v < MORNING_PEAK_E)
  235 + peakVal = 0;
  236 + else if (v > EVENIGN_PEAK_S && v < EVENIGN_PEAK_E)
  237 + peakVal = 2;
  238 + multimap.put(sct.getLineCode() + "_" + sct.getUpDown() + "_" + peakVal, sct);
  239 + }
  240 +
  241 + //汇总数据,生成一份线路上 站点间的耗时数据
  242 + ConcurrentMap<String, LineConsumeTime> map = new ConcurrentHashMap<>();
  243 + LineConsumeTime lct;
  244 + Set<String> ks = multimap.keySet();
  245 + for (String k : ks) {
  246 + lct = buildLineConsumeData(multimap.get(k));
  247 + map.put(k, lct);
  248 + }
  249 +
  250 + if (map.size() > 0)
  251 + lctMaps = map;
  252 + logger.info("calc end...");
  253 + } catch (Exception e) {
  254 + logger.error("", e);
  255 + }
  256 + }
  257 +
  258 + private LineConsumeTime buildLineConsumeData(List<StationConsumeTime> list) {
  259 + String lineCode = list.get(0).getLineCode();
  260 + int upDown = list.get(0).getUpDown();
  261 +
  262 + LineConsumeTime lct = new LineConsumeTime();
  263 + lct.setLineCode(lineCode);
  264 + lct.setUpDown(upDown);
  265 +
  266 + List<StationRoute> srs = GeoCacheData.find(lineCode, upDown);
  267 + Integer[] times = new Integer[srs.size()];
  268 + BiMap<String, Integer> code2iMap = HashBiMap.create();
  269 +
  270 + lct.setTimes(times);
  271 + lct.setCode2iMap(code2iMap);
  272 +
  273 + //按 key 分组数据
  274 + ArrayListMultimap<String, StationConsumeTime> multimap = ArrayListMultimap.create();
  275 + for (StationConsumeTime sct : list) {
  276 + multimap.put(sct.getKey1(), sct);
  277 + }
  278 +
  279 + StationRoute s;
  280 + for (int i = 0, size = srs.size() - 1; i < size; i++) {
  281 + s = srs.get(i);
  282 + code2iMap.put(s.getStationCode(), i);
  283 + times[i] = standardValue(multimap.get(s.getStationCode() + "_" + srs.get(i + 1).getStationCode()));
  284 + }
  285 +
  286 + Map<Integer, String> i2codeMap = code2iMap.inverse();
  287 + String code;
  288 + //缺少历史耗时,有空缺的,用实时距离换算一个时间
  289 + for (int i = 0, len = times.length; i < len; i++) {
  290 + if (null != times[i])
  291 + continue;
  292 +
  293 + code = i2codeMap.get(i);
  294 + s = GeoCacheData.findByCode(lineCode, upDown, code);
  295 +
  296 + if (null != s)
  297 + times[i] = (int) s.getLength() / 12;
  298 + else
  299 + times[i] = 55;
  300 + }
  301 + return lct;
  302 + }
  303 +
  304 +
  305 + /**
  306 + * 求一个标准值
  307 + *
  308 + * @param list
  309 + * @return
  310 + */
  311 + private Integer standardValue(List<StationConsumeTime> list) {
  312 + if (list.size() == 0)
  313 + return null;
  314 + List<Integer> ns = new ArrayList<>(list.size());
  315 + //把进站距离部分 均算成耗时
  316 + double inD;
  317 + int normal = 40;
  318 + for (StationConsumeTime sct : list) {
  319 + inD = sct.getInD1() + sct.getInD2();
  320 + if (inD > normal)
  321 + sct.setSeconds((int) (sct.getSeconds() + ((inD - normal) / 10)));
  322 +
  323 + ns.add(sct.getSeconds());
  324 + }
  325 +
  326 + int min = _min(ns);
  327 + int max = _max(ns);
  328 + int step = 20;
  329 + return _scale(ns, min, max, step);
  330 + }
  331 +
  332 + private Integer _scale(List<Integer> ns, int min, int max, int step) {
  333 + ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create();
  334 +
  335 + for (Integer n : ns) {
  336 + multimap.put(((n - min) / step) + "", n);
  337 + }
  338 +
  339 + List<Integer> vs, maxVs = null;
  340 + Set<String> ks = multimap.keySet();
  341 + for (String k : ks) {
  342 + vs = multimap.get(k);
  343 + if (null == maxVs || vs.size() > maxVs.size())
  344 + maxVs = vs;
  345 + }
  346 + return _avg(maxVs);
  347 + }
  348 +
  349 + private int _min(List<Integer> ns) {
  350 + int min = -1;
  351 + for (Integer n : ns) {
  352 + if (min == -1 || n < min)
  353 + min = n;
  354 + }
  355 + return min;
  356 + }
  357 +
  358 + private int _max(List<Integer> ns) {
  359 + int max = -1;
  360 + for (Integer n : ns) {
  361 + if (max == -1 || n > max)
  362 + max = n;
  363 + }
  364 + return max;
  365 + }
  366 +
  367 + private int _avg(List<Integer> ns) {
  368 + int sum = 0;
  369 +
  370 + for (Integer n : ns) {
  371 + sum += n;
  372 + }
  373 + return sum / ns.size();
  374 + }
  375 +
  376 + private List<Integer> exclude(List<Integer> ns, int v, float scale) {
  377 + List<Integer> rs = new ArrayList<>();
  378 +
  379 + float s = scale / 100;
  380 + int diff = (int) (v * s);
  381 + for (Integer n : ns) {
  382 + if (Math.abs(n - v) < diff)
  383 + rs.add(n);
  384 + }
  385 +
  386 + if (rs.size() == 0) {
  387 + return ns;
  388 + }
  389 + return rs;
  390 + }
  391 + }
  392 +
  393 + @Component
  394 + public class ConsumeTimePstThread implements Runnable {
  395 +
  396 + @Override
  397 + public void run() {
  398 + List<StationConsumeTime> list = new ArrayList<>();
  399 + try {
  400 + StationConsumeTime sct;
  401 + for (int i = 0; i < 1000; i++) {
  402 + sct = pstQueue.poll();
  403 + if (null == sct)
  404 + break;
  405 +
  406 + list.add(sct);
  407 + }
  408 +
  409 + if (list.size() > 0) {
  410 + //入库
  411 + batchSaveConsumeData(list);
  412 + logger.info("入库站点耗时数据, " + list.size());
  413 + }
  414 + } catch (Exception e) {
  415 + logger.error("", e);
  416 + }
  417 + }
  418 + }
  419 +
  420 + /**
  421 + * 批量入库站点间耗时数据
  422 + *
  423 + * @param list
  424 + */
  425 + public static void batchSaveConsumeData(List<StationConsumeTime> list) {
  426 + //写入数据
  427 + JdbcTemplate jdbcTemplate = new JdbcTemplate(DBUtils_InfoPublish.getDataSource());
  428 + jdbcTemplate.batchUpdate("insert into bsth_h_consume_time(rq,line_code,up_down,key1,key2,in_d1,in_d2,distance,seconds,time_str,nbbm) " +
  429 + " values (?,?,?,?,?,?,?,?,?,?,?)", new BatchPreparedStatementSetter() {
  430 +
  431 + @Override
  432 + public void setValues(PreparedStatement ps, int i) throws SQLException {
  433 + StationConsumeTime sct = list.get(i);
  434 + ps.setInt(1, sct.getRq());
  435 + ps.setString(2, sct.getLineCode());
  436 + ps.setInt(3, sct.getUpDown());
  437 + ps.setString(4, sct.getKey1());
  438 + ps.setString(5, sct.getKey2());
  439 + ps.setDouble(6, sct.getInD1());
  440 + ps.setDouble(7, sct.getInD2());
  441 + ps.setDouble(8, sct.getDistance());
  442 + ps.setInt(9, sct.getSeconds());
  443 + ps.setString(10, sct.getTimeStr());
  444 + ps.setString(11, sct.getNbbm());
  445 + }
  446 +
  447 + @Override
  448 + public int getBatchSize() {
  449 + return list.size();
  450 + }
  451 + });
  452 + }
  453 +}
... ...
src/main/java/com/bsth/data/history/entity/LineConsumeTime.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/history/entity/LineConsumeTime.java
  1 +package com.bsth.data.history.entity;
  2 +
  3 +import com.google.common.collect.BiMap;
  4 +
  5 +/**
  6 + * 线路上 站点间 耗时样本
  7 + */
  8 +public class LineConsumeTime {
  9 +
  10 + private String lineCode;
  11 +
  12 + private int upDown;
  13 +
  14 + /**
  15 + * 站点编号 和 站序索引对照
  16 + */
  17 + private BiMap<String, Integer> code2iMap;
  18 +
  19 + /**
  20 + * 按站序排列的 耗时数据(秒)
  21 + */
  22 + private Integer[] times;
  23 +
  24 + public String getLineCode() {
  25 + return lineCode;
  26 + }
  27 +
  28 + public void setLineCode(String lineCode) {
  29 + this.lineCode = lineCode;
  30 + }
  31 +
  32 + public int getUpDown() {
  33 + return upDown;
  34 + }
  35 +
  36 + public void setUpDown(int upDown) {
  37 + this.upDown = upDown;
  38 + }
  39 +
  40 + public Integer[] getTimes() {
  41 + return times;
  42 + }
  43 +
  44 + public void setTimes(Integer[] times) {
  45 + this.times = times;
  46 + }
  47 +
  48 + public BiMap<String, Integer> getCode2iMap() {
  49 + return code2iMap;
  50 + }
  51 +
  52 + public void setCode2iMap(BiMap<String, Integer> code2iMap) {
  53 + this.code2iMap = code2iMap;
  54 + }
  55 +}
... ...
src/main/java/com/bsth/data/history/entity/StationConsumeTime.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/history/entity/StationConsumeTime.java
  1 +package com.bsth.data.history.entity;
  2 +
  3 +import com.bsth.data.geo.GeoCacheData;
  4 +import com.bsth.entity.GpsEntity;
  5 +import com.bsth.entity.StationRoute;
  6 +import org.joda.time.format.DateTimeFormat;
  7 +import org.joda.time.format.DateTimeFormatter;
  8 +
  9 +/**
  10 + * 站点间耗时数据
  11 + */
  12 +public class StationConsumeTime {
  13 +
  14 + /**
  15 + * 日期 20180614
  16 + */
  17 + private int rq;
  18 +
  19 + /**
  20 + * 线路编码
  21 + */
  22 + private String lineCode;
  23 +
  24 + private String nbbm;
  25 +
  26 + /**
  27 + * 上下行
  28 + */
  29 + private int upDown;
  30 +
  31 + /**
  32 + * code1_code2
  33 + */
  34 + private String key1;
  35 +
  36 + /**
  37 + * name1_name2
  38 + */
  39 + private String key2;
  40 +
  41 + /**
  42 + * 站点1 进站距离
  43 + */
  44 + private double inD1;
  45 +
  46 + /**
  47 + * 站点2 进站距离
  48 + */
  49 + private double inD2;
  50 +
  51 + /**
  52 + * 距离
  53 + */
  54 + private double distance;
  55 +
  56 + /**
  57 + * 耗时(秒)
  58 + */
  59 + private int seconds;
  60 +
  61 + /**
  62 + * 时间 0830
  63 + */
  64 + private String timeStr;
  65 +
  66 + private static DateTimeFormatter fmtyyyyMMdd = DateTimeFormat.forPattern("yyyyMMdd");
  67 + private static DateTimeFormatter fmtHHmmss = DateTimeFormat.forPattern("HHmmss");
  68 +
  69 + public static StationConsumeTime getInstance(GpsEntity ig1, GpsEntity ig2) {
  70 + StationConsumeTime sct = new StationConsumeTime();
  71 + sct.setRq(Integer.parseInt(fmtyyyyMMdd.print(ig2.getTimestamp())));
  72 + sct.setTimeStr(fmtHHmmss.print(ig2.getTimestamp()));
  73 +
  74 + sct.setLineCode(ig2.getLineId());
  75 + sct.setUpDown(ig2.getUpDown());
  76 +
  77 + StationRoute s1 = GeoCacheData.findByCode(ig1)
  78 + , s2 = GeoCacheData.findByCode(ig2);
  79 +
  80 + sct.setKey1(s1.getStationCode() + "_" + s2.getStationCode());
  81 + sct.setKey2(s1.getName() + "_" + s2.getName());
  82 + sct.setDistance(s1.getLength());
  83 +
  84 + sct.setInD1(ig1.getInStationDistance());
  85 + sct.setInD2(ig2.getInStationDistance());
  86 + sct.setSeconds((int) ((ig2.getTimestamp() - ig1.getTimestamp()) / 1000));
  87 + sct.setNbbm(ig2.getNbbm());
  88 + return sct;
  89 + }
  90 +
  91 + public String getLineCode() {
  92 + return lineCode;
  93 + }
  94 +
  95 + public void setLineCode(String lineCode) {
  96 + this.lineCode = lineCode;
  97 + }
  98 +
  99 + public int getUpDown() {
  100 + return upDown;
  101 + }
  102 +
  103 + public void setUpDown(int upDown) {
  104 + this.upDown = upDown;
  105 + }
  106 +
  107 + public String getKey1() {
  108 + return key1;
  109 + }
  110 +
  111 + public void setKey1(String key1) {
  112 + this.key1 = key1;
  113 + }
  114 +
  115 + public String getKey2() {
  116 + return key2;
  117 + }
  118 +
  119 + public void setKey2(String key2) {
  120 + this.key2 = key2;
  121 + }
  122 +
  123 + public double getDistance() {
  124 + return distance;
  125 + }
  126 +
  127 + public void setDistance(double distance) {
  128 + this.distance = distance;
  129 + }
  130 +
  131 + public int getSeconds() {
  132 + return seconds;
  133 + }
  134 +
  135 + public void setSeconds(int seconds) {
  136 + this.seconds = seconds;
  137 + }
  138 +
  139 + public String getTimeStr() {
  140 + return timeStr;
  141 + }
  142 +
  143 + public void setTimeStr(String timeStr) {
  144 + this.timeStr = timeStr;
  145 + }
  146 +
  147 + public int getRq() {
  148 + return rq;
  149 + }
  150 +
  151 + public void setRq(int rq) {
  152 + this.rq = rq;
  153 + }
  154 +
  155 + public String getNbbm() {
  156 + return nbbm;
  157 + }
  158 +
  159 + public void setNbbm(String nbbm) {
  160 + this.nbbm = nbbm;
  161 + }
  162 +
  163 + public Double getInD1() {
  164 + return inD1;
  165 + }
  166 +
  167 + public void setInD1(Double inD1) {
  168 + this.inD1 = inD1;
  169 + }
  170 +
  171 + public Double getInD2() {
  172 + return inD2;
  173 + }
  174 +
  175 + public void setInD2(Double inD2) {
  176 + this.inD2 = inD2;
  177 + }
  178 +}
... ...
src/main/java/com/bsth/data/schedule/ScheduleCacheData.java 0 → 100644
  1 +++ a/src/main/java/com/bsth/data/schedule/ScheduleCacheData.java
  1 +package com.bsth.data.schedule;
  2 +
  3 +import com.alibaba.fastjson.JSONArray;
  4 +import com.bsth.data.geo.GeoCacheData;
  5 +import com.bsth.data.schedule.entity.ScheduleRealInfo;
  6 +import com.bsth.entity.StationRoute;
  7 +import com.bsth.util.ConfigUtil;
  8 +import com.bsth.util.HttpClientUtils;
  9 +import com.bsth.util.RsRequestUtils;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +import org.springframework.stereotype.Component;
  13 +
  14 +import java.util.HashMap;
  15 +import java.util.List;
  16 +import java.util.Map;
  17 +
  18 +/**
  19 + * 班次数据缓存
  20 + */
  21 +@Component
  22 +public class ScheduleCacheData {
  23 +
  24 + /**
  25 + * K: 车辆自编号
  26 + */
  27 + private static Map<String, ScheduleRealInfo> schMap;
  28 + private static String dataUrl;
  29 +
  30 +
  31 + static {
  32 + dataUrl = ConfigUtil.get("control.data.server.url") + "/rest/schedule_real/execs";
  33 + schMap = new HashMap<>();
  34 + }
  35 +
  36 + static Logger logger = LoggerFactory.getLogger(ScheduleCacheData.class);
  37 +
  38 + public static ScheduleRealInfo get(String nbbm) {
  39 + return schMap.get(nbbm);
  40 + }
  41 +
  42 + @Component
  43 + public class RefreshScheduleCacheThread implements Runnable {
  44 +
  45 + @Override
  46 + public void run() {
  47 + try {
  48 + StringBuilder sb = HttpClientUtils.get(dataUrl + RsRequestUtils.getParams());
  49 + List<ScheduleRealInfo> list = JSONArray.parseArray(sb.toString(), ScheduleRealInfo.class);
  50 +
  51 + Map<String, ScheduleRealInfo> map = new HashMap<>(list.size());
  52 +
  53 + StationRoute s1, s2, s3;
  54 + for (ScheduleRealInfo sch : list) {
  55 +
  56 + s1 = GeoCacheData.findByName(sch.getXlBm(), sch.getXlDir(), sch.getQdzName());
  57 + s2 = GeoCacheData.findByName(sch.getXlBm(), sch.getXlDir(), sch.getZdzName());
  58 +
  59 + if (null != s1){
  60 + sch.setQdzCode(s1.getStationCode());
  61 + sch.setQdzNo(s1.getSerialNo());
  62 + }
  63 +
  64 + if (null != s2){
  65 + sch.setZdzCode(s2.getStationCode());
  66 + sch.setZdzNo(s2.getSerialNo());
  67 + }
  68 +
  69 + if ("major".equals(sch.getBcType())) {
  70 + s3 = GeoCacheData.findByName(sch.getXlBm(), sch.getXlDir(), sch.getMajorStationName());
  71 +
  72 + if(null != s3){
  73 + sch.setQdzCode(s3.getStationCode());
  74 + sch.setQdzNo(s3.getSerialNo());
  75 + }
  76 +
  77 + }
  78 +
  79 + map.put(sch.getClZbh(), sch);
  80 + }
  81 +
  82 + if (map.size() > 0)
  83 + schMap = map;
  84 + } catch (Exception e) {
  85 + logger.error("", e);
  86 + }
  87 + }
  88 + }
  89 +}
... ...