Commit 3387d4db3de1adda54b2ed3bc5dd2ff718cc0a53
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
README.md
0 → 100644
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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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
src/main/java/com/bsth/client/msg/IMessageBody.java
0 → 100644
src/main/java/com/bsth/client/msg/IMessageIO.java
0 → 100644
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 | \ No newline at end of file | 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 | +} |