diff --git a/jtt808-server/src/main/java/org/yzh/commons/mybatis/Page.java b/jtt808-server/src/main/java/org/yzh/commons/mybatis/Page.java new file mode 100644 index 0000000000000000000000000000000000000000..ec818bdaaef6c1951a835df5cc4bd5369ccf9ba2 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/commons/mybatis/Page.java @@ -0,0 +1,31 @@ +package org.yzh.commons.mybatis; + +import java.util.List; +import java.util.function.Supplier; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class Page { + + private static final ThreadLocal LOCAL_PAGE = new ThreadLocal<>(); + + public static Pagination start(Supplier> select, int page, int limit) { + return start(select, new PageInfo(page, limit)); + } + + public static Pagination start(Supplier> select, PageInfo pageInfo) { + try { + LOCAL_PAGE.set(pageInfo); + List list = select.get(); + return new Pagination<>(pageInfo, list); + } finally { + LOCAL_PAGE.remove(); + } + } + + protected static PageInfo get() { + return LOCAL_PAGE.get(); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/commons/mybatis/PageInfo.java b/jtt808-server/src/main/java/org/yzh/commons/mybatis/PageInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..1aac8cd7de745698473c1fff72b8bdf2013b18fa --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/commons/mybatis/PageInfo.java @@ -0,0 +1,108 @@ +package org.yzh.commons.mybatis; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class PageInfo { + + @Schema(description = "当前页码", maxProperties = 111) + private int page; + @Schema(description = "每页显示行数", maxProperties = 112) + private int limit; + @Schema(description = "是否显示总页数", maxProperties = 113) + private boolean showPages; + @Schema(description = "是否有下一页", hidden = true) + private boolean hasNext; + @Schema(description = "总行数", hidden = true) + private int count; + + public PageInfo() { + this(1); + } + + public PageInfo(int page) { + this(page, 5); + } + + public PageInfo(int page, int limit) { + this(page, limit, true); + } + + public PageInfo(int page, int limit, boolean showPages) { + setPage(page); + setLimit(limit); + this.showPages = showPages; + } + + public int getPage() { + return page; + } + + public void setPage(int page) { + if (page > 0) + this.page = page; + } + + public int getLimit() { + return limit; + } + + public void setLimit(int limit) { + if (limit > 0) + this.limit = limit; + } + + public boolean isShowPages() { + return showPages; + } + + public void setShowPages(boolean showPages) { + this.showPages = showPages; + } + + public boolean isHasNext() { + return hasNext; + } + + public void setHasNext(boolean hasNext) { + this.hasNext = hasNext; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + int pages = pages(); + this.setHasNext(page < pages); + if (count != 0 && page > pages) + this.setPage(pages); + } + + /** @return 总页数 */ + public int pages() { + return (count - 1) / limit + 1; + } + + /** @return 当前页偏移量 */ + public int offset() { + return (page - 1) * limit; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(54); + sb.append('{'); + sb.append("page:").append(page); + sb.append(",pages:").append(pages()); + sb.append(",limit:").append(limit); + sb.append(",offset:").append(offset()); + sb.append(",count:").append(count); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/commons/mybatis/PageInterceptor.java b/jtt808-server/src/main/java/org/yzh/commons/mybatis/PageInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..914a878781f2621de52b0786bb840b0a81c0e8eb --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/commons/mybatis/PageInterceptor.java @@ -0,0 +1,111 @@ +package org.yzh.commons.mybatis; + +import org.apache.ibatis.executor.parameter.ParameterHandler; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.*; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yzh.commons.util.IOUtils; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; +import java.util.Properties; + +/** + * MyBatis分页拦截器 + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})) +public class PageInterceptor implements Interceptor { + + private static final Logger log = LoggerFactory.getLogger(PageInterceptor.class); + + public Object intercept(Invocation invocation) throws Throwable { + StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); + MetaObject metaObject = SystemMetaObject.forObject(statementHandler); + + if (SqlCommandType.SELECT == metaObject.getValue("delegate.mappedStatement.sqlCommandType")) { + BoundSql boundSql = statementHandler.getBoundSql(); + Object parameterObject = boundSql.getParameterObject(); + + PageInfo pageInfo = getPageInfo(parameterObject); + + if (pageInfo != null) { + String sql = boundSql.getSql(); + if (pageInfo.isShowPages()) { + int totalRows = getTotalRows(sql, (Connection) invocation.getArgs()[0], statementHandler.getParameterHandler()); + pageInfo.setCount(totalRows); + } + String pageSql = buildPageSql(sql, pageInfo); + metaObject.setValue("delegate.boundSql.sql", pageSql); + } + } + return invocation.proceed(); + } + + public static PageInfo getPageInfo(Object parameterObject) { + PageInfo pageInfo = Page.get(); + if (pageInfo == null) + if (parameterObject instanceof Map) { + Map parameterMap = (Map) parameterObject; + if (parameterMap.containsKey("pageInfo")) + pageInfo = (PageInfo) parameterMap.get("pageInfo"); + } + return pageInfo; + } + + /** + * 获取总行数 + */ + private static int getTotalRows(String sql, Connection connection, ParameterHandler handler) { + String countSql = new StringBuilder(sql.length() + 32) + .append("select count(*) from (").append(sql).append(") as total").toString(); + + int totalCount = 0; + PreparedStatement statement = null; + ResultSet rs = null; + try { + statement = connection.prepareStatement(countSql); + handler.setParameters(statement); + rs = statement.executeQuery(); + if (rs.next()) + totalCount = rs.getInt(1); + } catch (SQLException e) { + log.error("SELECT COUNT(1) ERROR", e); + } finally { + IOUtils.close(rs, statement); + } + return totalCount; + } + + /** + * 构建分页SQL + * 若无需展示总页数,则PageInfo中的hasNext 以大于limit一条记录的存在与否来决定 + */ + private static String buildPageSql(String sql, PageInfo page) { + int limit = page.isShowPages() ? page.getLimit() : page.getLimit() + 1; + return new StringBuilder(sql.length() + 14) + .append(sql).append(" limit ") + .append(page.offset()).append(',') + .append(limit).toString(); + } + + @Override + public void setProperties(Properties properties) { + } + + @Override + public Object plugin(Object target) { + if (target instanceof StatementHandler) + return Plugin.wrap(target, this); + return target; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/commons/mybatis/Pagination.java b/jtt808-server/src/main/java/org/yzh/commons/mybatis/Pagination.java new file mode 100644 index 0000000000000000000000000000000000000000..7602c619964791c5143b94defecd56d7130013cd --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/commons/mybatis/Pagination.java @@ -0,0 +1,88 @@ +package org.yzh.commons.mybatis; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.yzh.commons.model.APIResult; + +import java.io.Serializable; +import java.util.List; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class Pagination extends APIResult> implements Serializable { + + @Schema(description = "当前页码") + private int page; + @Schema(description = "总页数") + private int pages; + @Schema(description = "总行数") + private int count; + @Schema(description = "是否有下一页") + private boolean hasNext; + + public Pagination(PageInfo pageInfo, List list) { + if (pageInfo != null) { + if (pageInfo.isShowPages()) { + this.hasNext = pageInfo.isHasNext(); + } else { + //若无需展示总页数,则PageInfo中的hasNext 以大于limit一条记录的存在与否来决定 + this.hasNext = list.size() > pageInfo.getLimit(); + if (hasNext) { + list.remove(list.size() - 1); + } + } + + this.page = pageInfo.getPage(); + this.pages = pageInfo.pages(); + this.count = pageInfo.getCount(); + } + this.data = list; + } + + public int getPage() { + return page; + } + + public void setPage(int page) { + this.page = page; + } + + public int getPages() { + return pages; + } + + public void setPages(int pages) { + this.pages = pages; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public boolean isHasNext() { + return hasNext; + } + + public void setHasNext(boolean hasNext) { + this.hasNext = hasNext; + } + + @Override + public String toString() { + int size = data == null ? 0 : data.size(); + StringBuilder sb = new StringBuilder(); + sb.append('{'); + sb.append("page:").append(page); + sb.append(",pages:").append(pages); + sb.append(",count:").append(count); + sb.append(",hasNext:").append(hasNext); + sb.append(",listSize:").append(size); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/AreaConfiguration.java b/jtt808-server/src/main/java/org/yzh/component/area/AreaConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..cf6bb2499a768facd9fe61e736dcbfcfa9feddce --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/AreaConfiguration.java @@ -0,0 +1,15 @@ +package org.yzh.component.area; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +@ComponentScan({"org.yzh.component.area.controller", "org.yzh.component.area.service"}) +@MapperScan("org.yzh.component.area.mapper") +@Configuration +public class AreaConfiguration { +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/AreaFilter.java b/jtt808-server/src/main/java/org/yzh/component/area/AreaFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..45a8d39971e70342a22f3dee831e3e1134d2aaec --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/AreaFilter.java @@ -0,0 +1,84 @@ +package org.yzh.component.area; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yzh.component.area.model.Area; +import org.yzh.component.area.model.VehicleArea; +import org.yzh.protocol.basics.JTMessageFilter; +import org.yzh.protocol.commons.DateUtils; +import org.yzh.protocol.t808.T0200; + +import java.time.LocalDateTime; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class AreaFilter implements JTMessageFilter { + + private static final Logger log = LoggerFactory.getLogger(AreaFilter.class); + + private VehicleArea[] areas; + + public VehicleArea[] getAreas() { + return areas; + } + + public AreaFilter updateAreas(VehicleArea[] areas) { + this.areas = areas; + return this; + } + + @Override + public boolean doFilter(T0200 data) { + final VehicleArea[] areas = this.areas; + if (areas == null) + return true; + + LocalDateTime deviceTime = data.getDeviceTime(); + float speed = data.getSpeedKph(); + double lng = data.getLng(); + double lat = data.getLat(); + int vehicleId = data.getVehicleId(); + + for (int i = 0; i < areas.length; i++) { + + final VehicleArea vehicleArea = areas[i]; + final Area area = vehicleArea.getArea(); + + if (!area.contains(deviceTime)) { + vehicleArea.setEntryTime(0); + continue; + } + + if (area.contains(lng, lat)) { + if (area.limitInOut == 1) { + log.info("车辆[{}]状态[{},{},{}]{}:{}", vehicleId, lng, lat, speed, "进区域报警", area.name); + } + if (data.getSpeed() >= area.limitSpeed) { + log.info("车辆[{}]状态[{},{},{}]{}:{}", vehicleId, lng, lat, speed, "区域内超速", area.name + ",当前速度:" + speed + "km/h," + "区域限速:" + area.limitSpeed / 10d + "km/h"); + } + + long currentTime = deviceTime.toEpochSecond(DateUtils.GMT8); + long beforeTime = vehicleArea.getEntryTime(); + + if (beforeTime == 0) { + vehicleArea.setEntryTime(currentTime); + } else { + int time = (int) (currentTime - beforeTime); + if (time > area.limitTime) { + log.info("车辆[{}]状态[{},{},{}]{}:{}", vehicleId, lng, lat, speed, "区域内停车超时", area.name + ",停车:" + time + "秒,限时:" + area.limitTime + "秒"); + } + } + } else { + if (vehicleArea.getEntryTime() != 0) { + vehicleArea.setEntryTime(0); + if (area.limitInOut == 2) { + log.info("车辆[{}]状态[{},{},{}]{}:{}", vehicleId, lng, lat, speed, "出区域报警", area.name); + } + } + } + } + return true; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/EnableArea.java b/jtt808-server/src/main/java/org/yzh/component/area/EnableArea.java new file mode 100644 index 0000000000000000000000000000000000000000..bcfd786481adf9c2a91bd87a99d66a07390eb479 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/EnableArea.java @@ -0,0 +1,19 @@ +package org.yzh.component.area; + +import org.springframework.context.annotation.Import; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * 启用区域模块 + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@Target(value = {java.lang.annotation.ElementType.TYPE}) +@Import(AreaConfiguration.class) +@Documented +public @interface EnableArea { +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/GeometryFactory.java b/jtt808-server/src/main/java/org/yzh/component/area/GeometryFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..26206eff25dd6c4eecc9cda07dc9a13823b6a780 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/GeometryFactory.java @@ -0,0 +1,43 @@ +package org.yzh.component.area; + +import org.yzh.commons.util.Converter; +import org.yzh.commons.util.StrUtils; +import org.yzh.component.area.model.domain.*; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public abstract class GeometryFactory { + + public static Geometry build(int type, String text) { + return build(null, type, text); + } + + public static Geometry build(Converter converter, int type, String text) { + return build(converter, type, StrUtils.toDoubles(text, ",")); + } + + public static Geometry build(Converter converter, int type, double... points) { + if (converter != null) { + int length = points.length - (points.length % 2); + for (int i = 0; i < length; ) { + double[] xy = converter.convert(points[i], points[i + 1]); + points[i++] = xy[0]; + points[i++] = xy[1]; + } + } + switch (type) { + case Geometry.Circle: + return new Circle(points); + case Geometry.Rectangle: + return new Rectangle(points); + case Geometry.Polygon: + return new Polygon(points); + case Geometry.Lines: + return new Lines(points); + default: + throw new IllegalArgumentException("不支持的几何图形type=" + type); + } + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/controller/AreaController.java b/jtt808-server/src/main/java/org/yzh/component/area/controller/AreaController.java new file mode 100644 index 0000000000000000000000000000000000000000..e8cf19012fb72ee88b2a9ce1b63dc8e37d8ed399 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/controller/AreaController.java @@ -0,0 +1,65 @@ +package org.yzh.component.area.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.yzh.commons.model.APIResult; +import org.yzh.commons.mybatis.Page; +import org.yzh.commons.mybatis.PageInfo; +import org.yzh.commons.mybatis.Pagination; +import org.yzh.component.area.mapper.AreaMapper; +import org.yzh.component.area.model.entity.AreaDO; +import org.yzh.component.area.model.vo.AreaQuery; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +@RestController +@RequestMapping("area") +public class AreaController { + + @Autowired + private AreaMapper areaMapper; + + @Operation(summary = "查询区域") + @GetMapping + public Pagination find(AreaQuery query, PageInfo pageInfo) { + Pagination result = Page.start(() -> areaMapper.find(query), pageInfo); + return result; + } + + @Operation(summary = "新增|更新区域") + @PostMapping + public APIResult save(AreaDO record) { + if (record.getId() != null) { + int row = areaMapper.update(record.updatedBy("system")); + return APIResult.ok(row); + } else { + areaMapper.insert(record.createdBy("system")); + return APIResult.ok(record.getId()); + } + } + + @Operation(summary = "启用|禁用区域") + @PutMapping("enable") + public APIResult enable(@Parameter(description = "区域ID") @RequestParam Integer id, + @Parameter(description = "0.禁用 1.启用") @RequestParam int enable) { + int row = areaMapper.update(new AreaDO(id).deleted(enable == 0).updatedBy("system")); + return APIResult.ok(row); + } + + @Operation(summary = "绑定|解绑区域") + @PutMapping("vehicle") + public APIResult addVehicle(@Parameter(description = "车辆ID") @RequestParam Integer vehicleId, + @Parameter(description = "区域ID") @RequestParam Integer areaId, + @Parameter(description = "0.解绑 1.绑定") @RequestParam int bind) { + int row; + if (bind == 0) + row = areaMapper.removeVehicle(vehicleId, areaId); + else + row = areaMapper.addVehicle(vehicleId, areaId, "system"); + return APIResult.ok(row); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/mapper/AreaMapper.java b/jtt808-server/src/main/java/org/yzh/component/area/mapper/AreaMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..288eb33bfe1a7e1ef0ca128fd7cabf55ddf3cb4e --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/mapper/AreaMapper.java @@ -0,0 +1,31 @@ +package org.yzh.component.area.mapper; + +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; +import org.yzh.component.area.model.entity.AreaDO; +import org.yzh.component.area.model.vo.AreaQuery; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +@Repository +public interface AreaMapper { + + int[] findVehicleId(LocalDateTime updateTime); + + int[] findAreaId(int vehicleId); + + List find(AreaQuery query); + + int update(AreaDO record); + + int insert(AreaDO record); + + int removeVehicle(@Param("vehicleId") int vehicleId, @Param("areaId") Integer areaId); + + int addVehicle(@Param("vehicleId") int vehicleId, @Param("areaId") int areaId, @Param("createdBy") String createdBy); +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/Area.java b/jtt808-server/src/main/java/org/yzh/component/area/model/Area.java new file mode 100644 index 0000000000000000000000000000000000000000..8d36e5e662490f24d7147eb9c472c4e859d01ae0 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/Area.java @@ -0,0 +1,87 @@ +package org.yzh.component.area.model; + +import org.yzh.component.area.GeometryFactory; +import org.yzh.component.area.model.domain.DateTimeRange; +import org.yzh.component.area.model.domain.Geometry; +import org.yzh.component.area.model.entity.AreaDO; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class Area extends DateTimeRange implements Geometry { + + public final int id; // 区域id + public final int agencyId; // 机构id + public final String name; // 名称 + public final String areaDesc; // 描述 + public final int geomType; // 几何类型: 1.圆形 2.矩形 3.多边形 4.路线 + public final int markType; // 标记类型: 1.作业区 2.停车场 3.禁行区 + public final int limitInOut; // 限制出入: 0.无 1.进区域 2.出区域 + public final int limitSpeed; // 限速(1/10公里每小时) + public final int limitTime; // 限停(秒) + public final Geometry geometry; // 区域几何图形 + + private Area(AreaDO record, Geometry geometry) { + super(record.getStartTime(), record.getEndTime(), record.getStartDate(), record.getEndDate(), record.getWeeks()); + this.id = record.getId(); + this.agencyId = record.getAgencyId(); + this.name = record.getName(); + this.areaDesc = record.getAreaDesc(); + this.geomType = record.getGeomType(); + this.markType = record.getMarkType(); + this.limitInOut = record.getLimitInOut(); + this.limitSpeed = record.getLimitSpeed() <= 0 ? Integer.MAX_VALUE : record.getLimitSpeed() * 10; + this.limitTime = record.getLimitTime() * 60; + this.geometry = geometry; + } + + public static Area build(AreaDO record) { + return new Area(record, GeometryFactory.build(record.getGeomType(), record.getGeomText())); + } + + @Override + public boolean contains(double x, double y) { + return geometry.contains(x, y); + } + + public int getId() { + return id; + } + + public int getAgencyId() { + return agencyId; + } + + public String getName() { + return name; + } + + public String getAreaDesc() { + return areaDesc; + } + + public int getGeomType() { + return geomType; + } + + public int getMarkType() { + return markType; + } + + public int getLimitInOut() { + return limitInOut; + } + + public int getLimitSpeed() { + return limitSpeed; + } + + public int getLimitTime() { + return limitTime; + } + + public Geometry getGeometry() { + return geometry; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/TArea.java b/jtt808-server/src/main/java/org/yzh/component/area/model/TArea.java new file mode 100644 index 0000000000000000000000000000000000000000..7a0e18c38e01b587230d7865fef2684310c545d1 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/TArea.java @@ -0,0 +1,19 @@ +package org.yzh.component.area.model; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class TArea { + + private Area value; + + public TArea set(Area value) { + this.value = value; + return this; + } + + public Area get() { + return value; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/VehicleArea.java b/jtt808-server/src/main/java/org/yzh/component/area/model/VehicleArea.java new file mode 100644 index 0000000000000000000000000000000000000000..0af0f58916bc29cfe1f194510810a21cf0fec220 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/VehicleArea.java @@ -0,0 +1,27 @@ +package org.yzh.component.area.model; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class VehicleArea { + + private final TArea area; + private long entryTime; + + public VehicleArea(TArea area) { + this.area = area; + } + + public Area getArea() { + return area.get(); + } + + public long getEntryTime() { + return entryTime; + } + + public void setEntryTime(long entryTime) { + this.entryTime = entryTime; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Circle.java b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Circle.java new file mode 100644 index 0000000000000000000000000000000000000000..58343acd4afb58acae3ccb0d8693b31512bb1982 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Circle.java @@ -0,0 +1,31 @@ +package org.yzh.component.area.model.domain; + +import org.yzh.commons.util.GeomUtils; + +/** + * 圆形 + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class Circle implements Geometry { + + private final double x; + private final double y; + private final double radius; + + public Circle(double... values) { + this(values[0], values[1], values[2]); + } + + public Circle(double x, double y, double radius) { + this.x = x; + this.y = y; + this.radius = Math.abs(radius); + } + + @Override + public boolean contains(double x, double y) { + double distance = GeomUtils.distance(this.x, this.y, x, y); + return distance <= radius; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/domain/DateTimeRange.java b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/DateTimeRange.java new file mode 100644 index 0000000000000000000000000000000000000000..39d83ad9b06106031e4e61295ab3739c2964ee13 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/DateTimeRange.java @@ -0,0 +1,69 @@ +package org.yzh.component.area.model.domain; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class DateTimeRange { + + private final LocalTime startTime;// 开始时间 + private final LocalTime endTime; // 结束时间 + private final LocalDate startDate;// 开始日期 + private final LocalDate endDate; // 结束日期 + private final int weeks; // 生效日(按位,周一至周日) + + public DateTimeRange(LocalTime startTime, LocalTime endTime, LocalDate startDate, LocalDate endDate, int weeks) { + this.startTime = startTime; + this.endTime = endTime; + this.startDate = startDate; + this.endDate = endDate; + this.weeks = weeks; + } + + public boolean contains(LocalDateTime dateTime) { + if (containsTime(dateTime.toLocalTime())) + if (containsWeek(dateTime.getDayOfWeek())) + if (containsDate(dateTime.toLocalDate())) + return true; + return false; + } + + public boolean containsTime(LocalTime time) { + return (endTime == null || endTime.compareTo(time) > 0) && + (startTime == null || startTime.compareTo(time) <= 0); + } + + public boolean containsDate(LocalDate date) { + return (endDate == null || endDate.compareTo(date) >= 0) && + (startDate == null || startDate.compareTo(date) <= 0); + } + + public boolean containsWeek(DayOfWeek dayOfWeek) { + return (weeks & (1 << dayOfWeek.ordinal())) > 0; + } + + public LocalDate getStartDate() { + return startDate; + } + + public LocalDate getEndDate() { + return endDate; + } + + public LocalTime getStartTime() { + return startTime; + } + + public LocalTime getEndTime() { + return endTime; + } + + public int getWeeks() { + return weeks; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Geometry.java b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Geometry.java new file mode 100644 index 0000000000000000000000000000000000000000..fca2eb7aee6823ff4cf88f7f98c2bc016af3c4e8 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Geometry.java @@ -0,0 +1,25 @@ +package org.yzh.component.area.model.domain; + +/** + * 几何图形 + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public interface Geometry { + + int Circle = 1; + int Rectangle = 2; + int Polygon = 3; + int Lines = 4; + + /** + * @param x 经度 + * @param y 纬度 + * @return + */ + boolean contains(double x, double y); + + default boolean contains(double... xy) { + return this.contains(xy[0], xy[1]); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Lines.java b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Lines.java new file mode 100644 index 0000000000000000000000000000000000000000..2900c5366058c17635b1e7e3dec1f0a2e77385b5 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Lines.java @@ -0,0 +1,46 @@ +package org.yzh.component.area.model.domain; + +import org.yzh.commons.util.GeomUtils; + +import java.util.Arrays; + +/** + * 线段 + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class Lines implements Geometry { + + private final double[] points; + private final double width; + private final int size; + + public Lines(double... points) { + this(Arrays.copyOfRange(points, 0, points.length - 1), points[points.length - 1]); + } + + public Lines(double[] points, double width) { + if (points.length % 2 != 0) + throw new IllegalArgumentException("数组长度不是偶数"); + if (points.length < 4) + throw new IllegalArgumentException("至少两个坐标点"); + + this.points = points.clone(); + this.width = Math.abs(width); + this.size = points.length - 2; + } + + @Override + public boolean contains(double x, double y) { + for (int i = 0; i < size; ) { + double distance = GeomUtils.distancePointToLine( + points[i++], points[i++], + points[i], points[i + 1], + x, y + ); + if (distance <= width) + return true; + } + return false; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Polygon.java b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Polygon.java new file mode 100644 index 0000000000000000000000000000000000000000..33a86f54bfca55657c13c8fd7a3c9e2fad3d0e7b --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Polygon.java @@ -0,0 +1,26 @@ +package org.yzh.component.area.model.domain; + +import org.yzh.commons.util.GeomUtils; + +/** + * 多边形 + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class Polygon implements Geometry { + + private final double[] points; + + public Polygon(double... points) { + if (points.length % 2 != 0) + throw new IllegalArgumentException("数组长度不是偶数"); + if (points.length < 6) + throw new IllegalArgumentException("至少三个坐标点"); + this.points = points.clone(); + } + + @Override + public boolean contains(double x, double y) { + return GeomUtils.inside(x, y, points); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Rectangle.java b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Rectangle.java new file mode 100644 index 0000000000000000000000000000000000000000..8ad90acf6a1e9a921cf886291ee51697fa7d81de --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/domain/Rectangle.java @@ -0,0 +1,32 @@ +package org.yzh.component.area.model.domain; + +import org.yzh.commons.util.GeomUtils; + +/** + * 矩形 + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class Rectangle implements Geometry { + + private final double minX; + private final double minY; + private final double maxX; + private final double maxY; + + public Rectangle(double... values) { + this(values[0], values[1], values[2], values[3]); + } + + public Rectangle(double x1, double y1, double x2, double y2) { + this.minX = Math.min(x1, x2); + this.minY = Math.min(y1, y2); + this.maxX = Math.max(x1, x2); + this.maxY = Math.max(y1, y2); + } + + @Override + public boolean contains(double x, double y) { + return GeomUtils.inside(x, y, minX, minY, maxX, maxY); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/entity/AreaDO.java b/jtt808-server/src/main/java/org/yzh/component/area/model/entity/AreaDO.java new file mode 100644 index 0000000000000000000000000000000000000000..59c375e2ae6e2dd115bc6b4d84b9385433409c3e --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/entity/AreaDO.java @@ -0,0 +1,376 @@ +package org.yzh.component.area.model.entity; + + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * 区域实体类 + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class AreaDO { + + @Schema(description = "区域id") + private Integer id; + @Schema(description = "机构id") + private Integer agencyId; + @Schema(description = "名称") + private String name; + @Schema(description = "描述") + private String areaDesc; + @Schema(description = "几何类型: 1.圆形 2.矩形 3.多边形 4.路线") + private Integer geomType; + @Schema(description = "几何数据: 圆形[x,y,r] 矩形[x,y,x,y] 多边形[x,y,x,y,x,y] 路线[x,y,x,y,w]") + private String geomText; + @Schema(description = "标记类型: 1.作业区 2.停车场 3.禁行区") + private Integer markType; + @Schema(description = "限制出入: 0.无 1.进区域 2.出区域") + private Integer limitInOut; + @Schema(description = "限速(公里每小时)") + private Integer limitSpeed; + @Schema(description = "限停(分钟)") + private Integer limitTime; + @Schema(description = "生效日(按位,周一至周日)") + private Integer weeks; + @Schema(description = "开始日期") + private LocalDate startDate; + @Schema(description = "结束日期") + private LocalDate endDate; + @Schema(description = "开始时间") + private LocalTime startTime; + @Schema(description = "结束时间") + private LocalTime endTime; + @Schema(description = "删除标志") + private Boolean deleted; + @Schema(description = "更新者") + private String updatedBy; + @Schema(description = "创建者") + private String createdBy; + @Schema(description = "更新时间") + private LocalDateTime updatedAt; + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + public AreaDO() { + } + + public AreaDO(int id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getAgencyId() { + return agencyId; + } + + public void setAgencyId(Integer agencyId) { + this.agencyId = agencyId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAreaDesc() { + return areaDesc; + } + + public void setAreaDesc(String areaDesc) { + this.areaDesc = areaDesc; + } + + public Integer getGeomType() { + return geomType; + } + + public void setGeomType(Integer geomType) { + this.geomType = geomType; + } + + public String getGeomText() { + return geomText; + } + + public void setGeomText(String geomText) { + this.geomText = geomText; + } + + public Integer getMarkType() { + return markType; + } + + public void setMarkType(Integer markType) { + this.markType = markType; + } + + public Integer getLimitInOut() { + return limitInOut; + } + + public void setLimitInOut(Integer limitInOut) { + this.limitInOut = limitInOut; + } + + public Integer getLimitSpeed() { + return limitSpeed; + } + + public void setLimitSpeed(Integer limitSpeed) { + this.limitSpeed = limitSpeed; + } + + public Integer getLimitTime() { + return limitTime; + } + + public void setLimitTime(Integer limitTime) { + this.limitTime = limitTime; + } + + public Integer getWeeks() { + return weeks; + } + + public void setWeeks(Integer weeks) { + this.weeks = weeks; + } + + public LocalDate getStartDate() { + return startDate; + } + + public void setStartDate(LocalDate startDate) { + this.startDate = startDate; + } + + public LocalDate getEndDate() { + return endDate; + } + + public void setEndDate(LocalDate endDate) { + this.endDate = endDate; + } + + public LocalTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalTime startTime) { + this.startTime = startTime; + } + + public LocalTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalTime endTime) { + this.endTime = endTime; + } + + public Boolean isDeleted() { + return deleted; + } + + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public AreaDO id(Integer id) { + this.id = id; + return this; + } + + public AreaDO agencyId(Integer agencyId) { + this.agencyId = agencyId; + return this; + } + + public AreaDO name(String name) { + this.name = name; + return this; + } + + public AreaDO areaDesc(String areaDesc) { + this.areaDesc = areaDesc; + return this; + } + + public AreaDO geomType(Integer geomType) { + this.geomType = geomType; + return this; + } + + public AreaDO geomText(String geomText) { + this.geomText = geomText; + return this; + } + + public AreaDO markType(Integer markType) { + this.markType = markType; + return this; + } + + public AreaDO limitInOut(Integer limitInOut) { + this.limitInOut = limitInOut; + return this; + } + + public AreaDO limitSpeed(Integer limitSpeed) { + this.limitSpeed = limitSpeed; + return this; + } + + public AreaDO limitTime(Integer limitTime) { + this.limitTime = limitTime; + return this; + } + + public AreaDO weeks(Integer weeks) { + this.weeks = weeks; + return this; + } + + public AreaDO startDate(LocalDate startDate) { + this.startDate = startDate; + return this; + } + + public AreaDO endDate(LocalDate endDate) { + this.endDate = endDate; + return this; + } + + public AreaDO startTime(LocalTime startTime) { + this.startTime = startTime; + return this; + } + + public AreaDO endTime(LocalTime endTime) { + this.endTime = endTime; + return this; + } + + public AreaDO deleted(Boolean deleted) { + this.deleted = deleted; + return this; + } + + public AreaDO updatedBy(String updatedBy) { + this.updatedBy = updatedBy; + return this; + } + + public AreaDO createdBy(String createdBy) { + this.createdBy = createdBy; + return this; + } + + public AreaDO updatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + public AreaDO createdAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + return this; + } + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + AreaDO other = (AreaDO) that; + return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) + && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())); + } + + @Override + public int hashCode() { + final Integer prime = 31; + Integer result = 1; + result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); + result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode()); + return result; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("AreaDO{"); + sb.append("id=").append(id); + sb.append(", agencyId=").append(agencyId); + sb.append(", name='").append(name).append('\''); + sb.append(", geomType=").append(geomType); + sb.append(", markType=").append(markType); + sb.append(", limitInOut=").append(limitInOut); + sb.append(", limitSpeed=").append(limitSpeed); + sb.append(", limitTime=").append(limitTime); + sb.append(", weeks=[").append(weeks).append(']'); + sb.append(", startDate=").append(startDate); + sb.append(", endDate=").append(endDate); + sb.append(", startTime=").append(startTime); + sb.append(", endTime=").append(endTime); + sb.append(", deleted=").append(deleted); + sb.append(", areaDesc='").append(areaDesc).append('\''); + sb.append(", geomText='").append(geomText).append('\''); + sb.append(", updatedBy='").append(updatedBy).append('\''); + sb.append(", createdBy='").append(createdBy).append('\''); + sb.append(", updatedAt=").append(updatedAt); + sb.append(", createdAt=").append(createdAt); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/model/vo/AreaQuery.java b/jtt808-server/src/main/java/org/yzh/component/area/model/vo/AreaQuery.java new file mode 100644 index 0000000000000000000000000000000000000000..b35b62752173607cc5c159de5b25acb119d5e955 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/model/vo/AreaQuery.java @@ -0,0 +1,195 @@ +package org.yzh.component.area.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class AreaQuery { + + @Schema(description = "区域id") + private Integer id; + @Schema(description = "机构id") + private Integer agencyId; + @Schema(description = "名称") + private String name; + @Schema(description = "几何类型: 1.圆形 2.矩形 3.多边形 4.路线") + private Integer geomType; + @Schema(description = "标记类型: 1.作业区 2.停车场 3.禁行区") + private Integer markType; + @Schema(description = "限制出入: 0.无 1.进区域 2.出区域") + private Integer limitInOut; + @Schema(description = "开始日期") + private LocalDate startDate; + @Schema(description = "结束日期") + private LocalDate endDate; + @Schema(description = "开始时间") + private LocalTime startTime; + @Schema(description = "结束时间") + private LocalTime endTime; + @Schema(description = "删除标志") + private Boolean deleted; + @Schema(description = "更新时间") + private LocalDateTime updatedAt; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getAgencyId() { + return agencyId; + } + + public void setAgencyId(Integer agencyId) { + this.agencyId = agencyId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getGeomType() { + return geomType; + } + + public void setGeomType(Integer geomType) { + this.geomType = geomType; + } + + public Integer getMarkType() { + return markType; + } + + public void setMarkType(Integer markType) { + this.markType = markType; + } + + public Integer getLimitInOut() { + return limitInOut; + } + + public void setLimitInOut(Integer limitInOut) { + this.limitInOut = limitInOut; + } + + public LocalDate getStartDate() { + return startDate; + } + + public void setStartDate(LocalDate startDate) { + this.startDate = startDate; + } + + public LocalDate getEndDate() { + return endDate; + } + + public void setEndDate(LocalDate endDate) { + this.endDate = endDate; + } + + public LocalTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalTime startTime) { + this.startTime = startTime; + } + + public LocalTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalTime endTime) { + this.endTime = endTime; + } + + public Boolean isDeleted() { + return deleted; + } + + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public AreaQuery id(Integer id) { + this.id = id; + return this; + } + + public AreaQuery agencyId(Integer agencyId) { + this.agencyId = agencyId; + return this; + } + + public AreaQuery name(String name) { + this.name = name; + return this; + } + + public AreaQuery geomType(Integer geomType) { + this.geomType = geomType; + return this; + } + + public AreaQuery markType(Integer markType) { + this.markType = markType; + return this; + } + + public AreaQuery limitInOut(Integer limitInOut) { + this.limitInOut = limitInOut; + return this; + } + + public AreaQuery startDate(LocalDate startDate) { + this.startDate = startDate; + return this; + } + + public AreaQuery endDate(LocalDate endDate) { + this.endDate = endDate; + return this; + } + + public AreaQuery startTime(LocalTime startTime) { + this.startTime = startTime; + return this; + } + + public AreaQuery endTime(LocalTime endTime) { + this.endTime = endTime; + return this; + } + + public AreaQuery deleted(Boolean deleted) { + this.deleted = deleted; + return this; + } + + public AreaQuery updatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + return this; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/component/area/service/AreaService.java b/jtt808-server/src/main/java/org/yzh/component/area/service/AreaService.java new file mode 100644 index 0000000000000000000000000000000000000000..d7678dcc8a13890346da6f43d9f6d03af2162b93 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/component/area/service/AreaService.java @@ -0,0 +1,142 @@ +package org.yzh.component.area.service; + +import io.github.yezhihao.netmc.session.Session; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.yzh.component.area.AreaFilter; +import org.yzh.component.area.mapper.AreaMapper; +import org.yzh.component.area.model.Area; +import org.yzh.component.area.model.TArea; +import org.yzh.component.area.model.VehicleArea; +import org.yzh.component.area.model.entity.AreaDO; +import org.yzh.component.area.model.vo.AreaQuery; +import org.yzh.web.model.enums.SessionKey; +import org.yzh.web.model.vo.DeviceInfo; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +@Service +public class AreaService { + + private static final Logger log = LoggerFactory.getLogger(AreaService.class); + + private final Map vehicleAreaMap = new ConcurrentHashMap<>(); + + private final Map areaMap = new HashMap<>(); + + @Autowired + private AreaMapper areaMapper; + + public void register(Session session) { + DeviceInfo deviceInfo = SessionKey.getDeviceInfo(session); + int vehicleId = deviceInfo.getVehicleId(); + + VehicleArea[] areas = getVehicleAreas(vehicleId); + AreaFilter areaFilter = new AreaFilter().updateAreas(areas); + log.info("车辆区域绑定,车辆[{}],区域{}", vehicleId, areas == null ? "[]" : Arrays.toString(Arrays.stream(areas).mapToInt(v -> v.getArea().getId()).toArray())); + + session.setAttribute(SessionKey.AreaFilter, areaFilter); + vehicleAreaMap.put(vehicleId, areaFilter); + } + + public void cancellation(Session session) { + DeviceInfo deviceInfo = SessionKey.getDeviceInfo(session); + AreaFilter areaFilter = vehicleAreaMap.remove(deviceInfo.getVehicleId()); + VehicleArea[] areas = areaFilter.getAreas(); + log.info("车辆区域解绑,车辆[{}],区域{}", deviceInfo.getVehicleId(), areas == null ? "[]" : Arrays.toString(Arrays.stream(areas).mapToInt(v -> v.getArea().getId()).toArray())); + } + + private LocalDateTime lastUpdateTime; + + @Scheduled(fixedDelay = 10000L) + public void update() { + final LocalDateTime temp = lastUpdateTime; + this.lastUpdateTime = LocalDateTime.now(); + updateAreas(temp); + updateVehicleAreas(temp); + } + + private synchronized void updateAreas(LocalDateTime updateTime) { + List areas = areaMapper.find(new AreaQuery().updatedAt(updateTime)); + if (areas.isEmpty()) + return; + + LocalDate now = LocalDate.now(); + List dels = new LinkedList<>(); + List adds = new LinkedList<>(); + + for (AreaDO area : areas) { + if (area.isDeleted() || area.getWeeks() == 0 || (area.getEndDate() != null && now.isAfter(area.getEndDate()))) { + dels.add(area.getId()); + } else { + try { + adds.add(Area.build(area)); + } catch (Exception e) { + log.error("加载区域出错[{}],{}", area, e.getMessage()); + } + } + } + + for (Integer id : dels) { + areaMap.remove(id); + } + for (Area area : adds) { + TArea tArea = areaMap.get(area.getId()); + if (tArea == null) { + areaMap.put(area.getId(), new TArea().set(area)); + } else { + tArea.set(area); + } + } + + log.info("区域更新\n移除区域{}\n加载区域{}\n当前区域{}", + Arrays.toString(dels.stream().mapToInt(e -> e).toArray()), + Arrays.toString(adds.stream().mapToInt(Area::getId).toArray()), + Arrays.toString(areaMap.keySet().stream().mapToInt(k -> k).toArray()) + ); + } + + private synchronized void updateVehicleAreas(LocalDateTime updateTime) { + int[] vehicleIds = areaMapper.findVehicleId(updateTime); + for (int vehicleId : vehicleIds) { + + AreaFilter areaFilter = vehicleAreaMap.get(vehicleId); + if (areaFilter != null) { + + VehicleArea[] areas = getVehicleAreas(vehicleId); + areaFilter.updateAreas(areas); + log.info("车辆区域绑定,车辆[{}],区域{}", vehicleId, areas == null ? "[]" : Arrays.toString(Arrays.stream(areas).mapToInt(v -> v.getArea().getId()).toArray())); + } + } + } + + private VehicleArea[] getVehicleAreas(int vehicleId) { + int[] areaIds = areaMapper.findAreaId(vehicleId); + log.info("车辆区域查询,车辆[{}],区域{}", vehicleId, Arrays.toString(areaIds)); + if (areaIds.length == 0) + return null; + + List temp = new ArrayList<>(areaIds.length); + + for (int areaId : areaIds) { + TArea area = areaMap.get(areaId); + if (area != null) { + temp.add(new VehicleArea(area)); + } + } + if (temp.isEmpty()) + return null; + + return temp.toArray(new VehicleArea[temp.size()]); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/protocol/t808/T0200.java b/jtt808-server/src/main/java/org/yzh/protocol/t808/T0200.java new file mode 100644 index 0000000000000000000000000000000000000000..679cf274aa035fd0fe402d7ed0f0f49235e3b1ae --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/protocol/t808/T0200.java @@ -0,0 +1,192 @@ +package org.yzh.protocol.t808; + +import io.github.yezhihao.protostar.annotation.Field; +import io.github.yezhihao.protostar.annotation.Message; +import org.yzh.protocol.basics.JTMessage; +import org.yzh.protocol.commons.DateUtils; +import org.yzh.protocol.commons.JT808; +import org.yzh.protocol.commons.transform.AttributeConverter; +import org.yzh.protocol.commons.transform.AttributeConverterYue; +import org.yzh.web.model.enums.SessionKey; +import org.yzh.web.model.vo.DeviceInfo; + +import java.time.LocalDateTime; +import java.util.Map; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +@Message(JT808.位置信息汇报) +public class T0200 extends JTMessage { + + @Field(length = 4, desc = "报警标志") + private int warnBit; + @Field(length = 4, desc = "状态") + private int statusBit; + @Field(length = 4, desc = "纬度") + private int latitude; + @Field(length = 4, desc = "经度") + private int longitude; + @Field(length = 2, desc = "高程(米)") + private int altitude; + @Field(length = 2, desc = "速度(1/10公里每小时)") + private int speed; + @Field(length = 2, desc = "方向") + private int direction; + @Field(length = 6, charset = "BCD", desc = "时间(YYMMDDHHMMSS)") + private String dateTime; + @Field(desc = "位置附加信息", converter = AttributeConverter.class, version = {-1, 0}) + @Field(desc = "位置附加信息(粤标)", converter = AttributeConverterYue.class, version = 1) + private Map attributes; + + public int getWarnBit() { + return warnBit; + } + + public void setWarnBit(int warnBit) { + this.warnBit = warnBit; + } + + public int getStatusBit() { + return statusBit; + } + + public void setStatusBit(int statusBit) { + this.statusBit = statusBit; + } + + public int getLatitude() { + return latitude; + } + + public void setLatitude(int latitude) { + this.latitude = latitude; + } + + public int getLongitude() { + return longitude; + } + + public void setLongitude(int longitude) { + this.longitude = longitude; + } + + public int getAltitude() { + return altitude; + } + + public void setAltitude(int altitude) { + this.altitude = altitude; + } + + public int getSpeed() { + return speed; + } + + public void setSpeed(int speed) { + this.speed = speed; + } + + public int getDirection() { + return direction; + } + + public void setDirection(int direction) { + this.direction = direction; + } + + public String getDateTime() { + return dateTime; + } + + public void setDateTime(String dateTime) { + this.dateTime = dateTime; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + private boolean updated; + private String deviceId; + private String plateNo; + private int vehicleId; + private double lng; + private double lat; + private float speedKph; + private LocalDateTime deviceTime; + + @Override + public boolean transform() { + lng = getLongitude() / 1000000d; + lat = getLatitude() / 1000000d; + speedKph = getSpeed() / 10f; + if (getDateTime() != null) + deviceTime = DateUtils.parse(getDateTime()); + + DeviceInfo device = SessionKey.getDeviceInfo(session); + if (device != null) { + deviceId = device.getDeviceId(); + plateNo = device.getPlateNo(); + vehicleId = device.getVehicleId(); + } else { + deviceId = clientId; + plateNo = ""; + } + return deviceTime != null; + } + + + public boolean updated() { + return updated ? true : !(updated = true); + } + + public String getDeviceId() { + return deviceId; + } + + public String getPlateNo() { + return plateNo; + } + + public int getVehicleId() { + return vehicleId; + } + + public double getLng() { + return lng; + } + + public double getLat() { + return lat; + } + + public float getSpeedKph() { + return speedKph; + } + + public LocalDateTime getDeviceTime() { + return deviceTime; + } + + @Override + public String toString() { + StringBuilder sb = toStringHead(); + sb.append("T0200{dateTime=").append(dateTime); + sb.append(",longitude=").append(longitude); + sb.append(",latitude=").append(latitude); + sb.append(",altitude=").append(altitude); + sb.append(",speed=").append(speed); + sb.append(",direction=").append(direction); + sb.append(",warnBit=").append(Integer.toBinaryString(warnBit)); + sb.append(",statusBit=").append(Integer.toBinaryString(statusBit)); + sb.append(",attributes=").append(attributes); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/Application.java b/jtt808-server/src/main/java/org/yzh/web/Application.java index a8e7dbaca6b4be17a3064e186c12facf9de3dfc3..8516a07d5fe78ad17612c8bd901f4bcb06468aef 100644 --- a/jtt808-server/src/main/java/org/yzh/web/Application.java +++ b/jtt808-server/src/main/java/org/yzh/web/Application.java @@ -8,8 +8,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.yzh.component.area.EnableArea; import springfox.documentation.swagger2.annotations.EnableSwagger2; +@EnableArea @EnableCaching @EnableScheduling @EnableSwagger2 diff --git a/jtt808-server/src/main/java/org/yzh/web/config/BeanConfig.java b/jtt808-server/src/main/java/org/yzh/web/config/BeanConfig.java index 94ae978d4ba3737cdc7f8ec7a2abdffa6390a6a0..9c38541f7cfb2f2d288f128fc3f1d23974b8ec04 100644 --- a/jtt808-server/src/main/java/org/yzh/web/config/BeanConfig.java +++ b/jtt808-server/src/main/java/org/yzh/web/config/BeanConfig.java @@ -15,6 +15,7 @@ import org.springframework.cache.caffeine.CaffeineCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.Converter; +import org.yzh.commons.mybatis.PageInterceptor; import org.yzh.protocol.commons.DateUtils; import java.time.LocalDate; @@ -35,6 +36,11 @@ public class BeanConfig { return manager; } + @Bean + public PageInterceptor pageInterceptor() { + return new PageInterceptor(); + } + @Bean public Jackson2ObjectMapperBuilderCustomizer customizeJackson2ObjectMapper() { return builder -> { diff --git a/jtt808-server/src/main/java/org/yzh/web/config/JTBeanConfig.java b/jtt808-server/src/main/java/org/yzh/web/config/JTBeanConfig.java index 579e8e8bc2fd2ad91e813870e80ff7a1674f93c3..a2b19c78349bef6668975e274dd4f190081c808d 100644 --- a/jtt808-server/src/main/java/org/yzh/web/config/JTBeanConfig.java +++ b/jtt808-server/src/main/java/org/yzh/web/config/JTBeanConfig.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.yzh.component.area.service.AreaService; import org.yzh.protocol.codec.DataFrameMessageDecoder; import org.yzh.protocol.codec.JTMessageAdapter; import org.yzh.protocol.codec.JTMessageEncoder; @@ -16,6 +17,7 @@ import org.yzh.protocol.codec.MultiPacketDecoder; import org.yzh.web.endpoint.JTHandlerInterceptor; import org.yzh.web.endpoint.JTMultiPacketListener; import org.yzh.web.endpoint.JTSessionListener; +import org.yzh.web.mapper.DeviceStatusMapper; import org.yzh.web.model.enums.SessionKey; @Configuration @@ -38,8 +40,8 @@ public class JTBeanConfig { } @Bean - public SessionListener sessionListener() { - return new JTSessionListener(); + public SessionListener sessionListener(DeviceStatusMapper deviceStatusMapper, @Autowired(required = false) AreaService areaService) { + return new JTSessionListener(deviceStatusMapper, areaService); } @Bean diff --git a/jtt808-server/src/main/java/org/yzh/web/controller/OtherController.java b/jtt808-server/src/main/java/org/yzh/web/controller/OtherController.java index 82aea6b3ac5e275da04ada6cfac8f1008d69d792..84c917d2d892491a64b3586eb5a7580772b98445 100644 --- a/jtt808-server/src/main/java/org/yzh/web/controller/OtherController.java +++ b/jtt808-server/src/main/java/org/yzh/web/controller/OtherController.java @@ -12,28 +12,38 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import org.springframework.web.bind.annotation.*; import org.yzh.commons.model.APIResult; +import org.yzh.commons.mybatis.Page; +import org.yzh.commons.mybatis.Pagination; import org.yzh.commons.util.LogUtils; import org.yzh.protocol.codec.JTMessageDecoder; import org.yzh.protocol.codec.MultiPacketDecoder; import org.yzh.web.config.WebLogAdapter; +import org.yzh.web.model.enums.SessionKey; import org.yzh.web.model.vo.DeviceInfo; +import org.yzh.web.model.vo.DeviceQuery; +import org.yzh.web.model.vo.Location; +import org.yzh.web.model.vo.LocationQuery; +import org.yzh.web.service.LocationService; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; @RestController @RequestMapping public class OtherController { + private final LocationService locationService; + private final SessionManager sessionManager; private final JTMessageDecoder decoder; - public OtherController(SessionManager sessionManager, SchemaManager schemaManager) { + public OtherController(LocationService locationService, SessionManager sessionManager, SchemaManager schemaManager) { + this.locationService = locationService; this.sessionManager = sessionManager; this.decoder = new MultiPacketDecoder(schemaManager); } @@ -47,9 +57,22 @@ public class OtherController { @Operation(summary = "终端实时信息查询") @GetMapping("terminal/all") - public APIResult> all() { + public Pagination all(DeviceQuery query) { Collection all = sessionManager.all(); - return new APIResult<>(all); + Stream stream = all.stream(); + + if (!query.isEmpty()) { + all = all.stream().filter(query).collect(Collectors.toList()); + stream = all.stream(); + } + + List page = stream + .skip(query.offset()) + .limit(query.getLimit()) + .collect(Collectors.toList()); + + query.setCount(all.size()); + return new Pagination<>(query, page); } @Operation(summary = "获得当前所有在线设备信息") @@ -67,7 +90,7 @@ public class OtherController { Session session = sessionManager.get(clientId); if (session != null) { WebLogAdapter.addClient(session.getClientId()); - return new APIResult(Collections.singletonMap("clientId", session.getClientId())); + return new APIResult(session.getAttribute(SessionKey.DeviceInfo)); } } else { WebLogAdapter.removeClient(clientId); @@ -104,6 +127,13 @@ public class OtherController { return "fail"; } + @Operation(summary = "位置信息查询") + @GetMapping("location") + public Pagination find(LocationQuery query) { + Pagination result = Page.start(() -> locationService.find(query), query); + return result; + } + @Operation(summary = "修改日志级别") @GetMapping("logger") public String logger(@RequestParam LogUtils.Lv level) { diff --git a/jtt808-server/src/main/java/org/yzh/web/endpoint/JT808Endpoint.java b/jtt808-server/src/main/java/org/yzh/web/endpoint/JT808Endpoint.java index ddf0e5fc539b5ea75232e6a7af11b9aa8ab84ad2..dcafaaef6c064a883c54ca8641e819d099d6eebb 100644 --- a/jtt808-server/src/main/java/org/yzh/web/endpoint/JT808Endpoint.java +++ b/jtt808-server/src/main/java/org/yzh/web/endpoint/JT808Endpoint.java @@ -5,19 +5,25 @@ import io.github.yezhihao.netmc.core.annotation.AsyncBatch; import io.github.yezhihao.netmc.core.annotation.Endpoint; import io.github.yezhihao.netmc.core.annotation.Mapping; import io.github.yezhihao.netmc.session.Session; +import io.github.yezhihao.netmc.util.AdapterList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.yzh.commons.model.Result; +import org.yzh.commons.util.EncryptUtils; import org.yzh.protocol.basics.JTMessage; import org.yzh.protocol.commons.JT808; import org.yzh.protocol.t808.*; import org.yzh.web.model.enums.SessionKey; import org.yzh.web.model.vo.DeviceInfo; +import org.yzh.web.service.DeviceService; import org.yzh.web.service.FileService; +import org.yzh.web.service.LocationService; import java.time.LocalDateTime; import java.time.ZoneOffset; +import java.util.Base64; import java.util.List; import static org.yzh.protocol.commons.JT808.*; @@ -28,6 +34,12 @@ public class JT808Endpoint { private static final Logger log = LoggerFactory.getLogger(JT808Endpoint.class.getSimpleName()); + @Autowired + private LocationService locationService; + + @Autowired + private DeviceService deviceService; + @Autowired private FileService fileService; @@ -58,29 +70,41 @@ public class JT808Endpoint { @Mapping(types = 终端注册, desc = "终端注册") public T8100 register(T0100 message, Session session) { - session.register(message); - DeviceInfo deviceInfo = new DeviceInfo(); - deviceInfo.setDeviceId(message.getDeviceId()); - session.setAttribute(SessionKey.DeviceInfo, deviceInfo); - T8100 result = new T8100(); result.setResponseSerialNo(message.getSerialNo()); - result.setToken(message.getDeviceId()); - result.setResultCode(T8100.Success); + + Result device = deviceService.register(message); + if (device.isSuccess()) { + session.setAttribute(SessionKey.DeviceInfo, device.get()); + session.register(message); + + byte[] bytes = DeviceInfo.toBytes(device.get()); + bytes = EncryptUtils.encrypt(bytes); + String token = Base64.getEncoder().encodeToString(bytes); + + result.setToken(token); + result.setResultCode(T8100.Success); + } else { + result.setResultCode(device.state()); + } return result; } @Mapping(types = 终端鉴权, desc = "终端鉴权") public T0001 authentication(T0102 message, Session session) { - session.register(message); - DeviceInfo deviceInfo = new DeviceInfo(); - deviceInfo.setDeviceId(message.getToken()); - session.setAttribute(SessionKey.DeviceInfo, deviceInfo); - T0001 result = new T0001(); result.setResponseSerialNo(message.getSerialNo()); result.setResponseMessageId(message.getMessageId()); - result.setResultCode(T0001.Success); + + DeviceInfo device = deviceService.authentication(message); + if (device != null) { + session.setAttribute(SessionKey.DeviceInfo, device); + session.register(message); + result.setResultCode(T0001.Success); + return result; + } + log.warn("终端鉴权失败,{}{}", session, message); + result.setResultCode(T0001.Failure); return result; } @@ -107,10 +131,19 @@ public class JT808Endpoint { @AsyncBatch(poolSize = 2, maxElements = 4000, maxWait = 1000) @Mapping(types = 位置信息汇报, desc = "位置信息汇报") public void locationReport(List list) { + locationService.batchInsert(list); } @Mapping(types = 定位数据批量上传, desc = "定位数据批量上传") public void locationBatchReport(T0704 message) { + Session session = message.getSession(); + List list = new AdapterList<>(message.getItems(), location -> { + location.copyBy(message); + location.setSession(session); + location.transform(); + return location; + }); + locationService.batchInsert(list); } @Mapping(types = {位置信息查询应答, 车辆控制应答}, desc = "位置信息查询应答/车辆控制应答") diff --git a/jtt808-server/src/main/java/org/yzh/web/endpoint/JTHandlerInterceptor.java b/jtt808-server/src/main/java/org/yzh/web/endpoint/JTHandlerInterceptor.java index 0fccf1f1b2da611add7874b787cd00ee8c8a49dd..fad3ac1a4ed987352d0af905c2976e0b8db3488f 100644 --- a/jtt808-server/src/main/java/org/yzh/web/endpoint/JTHandlerInterceptor.java +++ b/jtt808-server/src/main/java/org/yzh/web/endpoint/JTHandlerInterceptor.java @@ -5,6 +5,7 @@ import io.github.yezhihao.netmc.session.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yzh.protocol.basics.JTMessage; +import org.yzh.protocol.basics.JTMessageFilter; import org.yzh.protocol.commons.JT808; import org.yzh.protocol.t808.T0001; import org.yzh.web.model.enums.SessionKey; @@ -71,6 +72,9 @@ public class JTHandlerInterceptor implements HandlerInterceptor { if (messageId == JT808.位置信息汇报) { request.transform(); session.setAttribute(SessionKey.Snapshot, request); + JTMessageFilter areaFilter = SessionKey.getAreaFilter(session); + if (areaFilter != null) + areaFilter.doFilter(request); } if (!session.isRegistered()) { log.info("{}未注册的设备<<<<-{}", session, request); diff --git a/jtt808-server/src/main/java/org/yzh/web/endpoint/JTSessionListener.java b/jtt808-server/src/main/java/org/yzh/web/endpoint/JTSessionListener.java index c3880c39b12cedcbe93aa207803dee106033575b..2f421b0857c46fcac5d48ad78f6d3b71878018bb 100644 --- a/jtt808-server/src/main/java/org/yzh/web/endpoint/JTSessionListener.java +++ b/jtt808-server/src/main/java/org/yzh/web/endpoint/JTSessionListener.java @@ -2,18 +2,59 @@ package org.yzh.web.endpoint; import io.github.yezhihao.netmc.session.Session; import io.github.yezhihao.netmc.session.SessionListener; +import org.yzh.component.area.service.AreaService; +import org.yzh.web.mapper.DeviceStatusMapper; +import org.yzh.web.model.entity.DeviceStatusDO; +import org.yzh.web.model.enums.SessionKey; +import org.yzh.web.model.vo.DeviceInfo; + +import java.util.Date; public class JTSessionListener implements SessionListener { + private final DeviceStatusMapper deviceStatusMapper; + + private final AreaService areaService; + + public JTSessionListener(DeviceStatusMapper deviceStatusMapper, AreaService areaService) { + this.deviceStatusMapper = deviceStatusMapper; + this.areaService = areaService; + } + @Override public void sessionCreated(Session session) { } @Override public void sessionRegistered(Session session) { + DeviceInfo device = SessionKey.getDeviceInfo(session); + if (device != null) { + + DeviceStatusDO status = new DeviceStatusDO(); + status.setDeviceId(device.getDeviceId()); + status.setOnline(true); + status.setAgencyId(device.getAgencyId()); + status.setPlateNo(device.getPlateNo()); + status.setMobileNo(device.getClientId()); + status.setVehicleId(device.getVehicleId()); + + if (deviceStatusMapper.update(status) < 1) + deviceStatusMapper.insert(status); + if (areaService != null) + areaService.register(session); + } } @Override public void sessionDestroyed(Session session) { + DeviceInfo device = SessionKey.getDeviceInfo(session); + if (device != null) { + deviceStatusMapper.update(new DeviceStatusDO().deviceId(device.getDeviceId()).online(false)); + long onlineTime = session.getCreationTime(); + int onlineDuration = (int) (System.currentTimeMillis() - onlineTime) / 1000; + deviceStatusMapper.insertOnlineRecord(device, new Date(onlineTime), onlineDuration); + if (areaService != null) + areaService.cancellation(session); + } } } \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/mapper/DeviceMapper.java b/jtt808-server/src/main/java/org/yzh/web/mapper/DeviceMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4e9f747c04448cfec647afdf8969ef0d33c7dec0 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/mapper/DeviceMapper.java @@ -0,0 +1,26 @@ +package org.yzh.web.mapper; + +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Repository; +import org.yzh.web.model.entity.DeviceDO; + +import java.util.List; + +@Repository +public interface DeviceMapper { + + List find(DeviceDO query); + + DeviceDO getByMobileNo(String mobileNo); + + @Cacheable(cacheNames = "DeviceDO.deviceId") + DeviceDO get(String deviceId); + + @CacheEvict(cacheNames = "DeviceDO.deviceId", key = "#record.deviceId") + int insert(DeviceDO record); + + int update(DeviceDO record); + + int delete(String deviceId); +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/mapper/DeviceStatusMapper.java b/jtt808-server/src/main/java/org/yzh/web/mapper/DeviceStatusMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..a0bd61ee4723d7293986f3d8748c91e7c52882a1 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/mapper/DeviceStatusMapper.java @@ -0,0 +1,21 @@ +package org.yzh.web.mapper; + +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; +import org.yzh.web.model.entity.DeviceStatusDO; +import org.yzh.web.model.vo.DeviceInfo; + +import java.util.Date; +import java.util.List; + +@Repository +public interface DeviceStatusMapper { + + List find(DeviceStatusDO query); + + int update(DeviceStatusDO record); + + int insert(DeviceStatusDO record); + + int insertOnlineRecord(@Param("d") DeviceInfo record, @Param("onlineTime") Date onlineTime, @Param("onlineDuration") int onlineDuration); +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/mapper/LocationMapper.java b/jtt808-server/src/main/java/org/yzh/web/mapper/LocationMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..1805ec5d7c4d2113964e246db9ffa5cbac6f9e3d --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/mapper/LocationMapper.java @@ -0,0 +1,14 @@ +package org.yzh.web.mapper; + +import org.springframework.stereotype.Repository; +import org.yzh.web.model.vo.Location; +import org.yzh.web.model.vo.LocationQuery; + +import java.util.List; + +@Repository +public interface LocationMapper { + + List find(LocationQuery query); + +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/mapper/VehicleMapper.java b/jtt808-server/src/main/java/org/yzh/web/mapper/VehicleMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..cb8cff249cb0bf9b13d461b4ce764029f05753ce --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/mapper/VehicleMapper.java @@ -0,0 +1,26 @@ +package org.yzh.web.mapper; + +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Repository; +import org.yzh.web.model.entity.VehicleDO; + +import java.util.List; + +@Repository +public interface VehicleMapper { + + List find(VehicleDO query); + + @Cacheable(cacheNames = "VehicleDO.plateNo") + VehicleDO getByPlateNo(String plateNo); + + VehicleDO get(int id); + + int update(VehicleDO record); + + @CacheEvict(cacheNames = "VehicleDO.plateNo", key = "#record.plateNo") + int insert(VehicleDO record); + + int delete(int id); +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/model/entity/DeviceDO.java b/jtt808-server/src/main/java/org/yzh/web/model/entity/DeviceDO.java new file mode 100644 index 0000000000000000000000000000000000000000..51559cc0ea527730472235f52429b17f60c0e579 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/model/entity/DeviceDO.java @@ -0,0 +1,312 @@ +package org.yzh.web.model.entity; + +import java.time.LocalDateTime; + +public class DeviceDO { + + private String deviceId; + private Integer agencyId; + private Integer vehicleId; + private String mobileNo; + private String iccid; + private String imei; + private LocalDateTime registerTime; + private LocalDateTime installTime; + private Integer protocolVersion; + private String softwareVersion; + private String firmwareVersion; + private String hardwareVersion; + private String deviceModel; + private String makerId; + private Boolean deleted; + private String updatedBy; + private String createdBy; + private LocalDateTime updatedAt; + private LocalDateTime createdAt; + + private String plateNo; + private byte plateColor; + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public Integer getAgencyId() { + return agencyId; + } + + public void setAgencyId(Integer agencyId) { + this.agencyId = agencyId; + } + + public Integer getVehicleId() { + return vehicleId; + } + + public void setVehicleId(Integer vehicleId) { + this.vehicleId = vehicleId; + } + + public String getMobileNo() { + return mobileNo; + } + + public void setMobileNo(String mobileNo) { + this.mobileNo = mobileNo; + } + + public String getIccid() { + return iccid; + } + + public void setIccid(String iccid) { + this.iccid = iccid; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public LocalDateTime getRegisterTime() { + return registerTime; + } + + public void setRegisterTime(LocalDateTime registerTime) { + this.registerTime = registerTime; + } + + public LocalDateTime getInstallTime() { + return installTime; + } + + public void setInstallTime(LocalDateTime installTime) { + this.installTime = installTime; + } + + public Integer getProtocolVersion() { + return protocolVersion; + } + + public void setProtocolVersion(Integer protocolVersion) { + this.protocolVersion = protocolVersion; + } + + public String getSoftwareVersion() { + return softwareVersion; + } + + public void setSoftwareVersion(String softwareVersion) { + this.softwareVersion = softwareVersion; + } + + public String getFirmwareVersion() { + return firmwareVersion; + } + + public void setFirmwareVersion(String firmwareVersion) { + this.firmwareVersion = firmwareVersion; + } + + public String getHardwareVersion() { + return hardwareVersion; + } + + public void setHardwareVersion(String hardwareVersion) { + this.hardwareVersion = hardwareVersion; + } + + public String getDeviceModel() { + return deviceModel; + } + + public void setDeviceModel(String deviceModel) { + this.deviceModel = deviceModel; + } + + public String getMakerId() { + return makerId; + } + + public void setMakerId(String makerId) { + this.makerId = makerId; + } + + public Boolean getDeleted() { + return deleted; + } + + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public String getPlateNo() { + return plateNo; + } + + public void setPlateNo(String plateNo) { + this.plateNo = plateNo; + } + + public byte getPlateColor() { + return plateColor; + } + + public void setPlateColor(byte plateColor) { + this.plateColor = plateColor; + } + + public DeviceDO deviceId(String deviceId) { + this.deviceId = deviceId; + return this; + } + + public DeviceDO agencyId(Integer agencyId) { + this.agencyId = agencyId; + return this; + } + + public DeviceDO vehicleId(Integer vehicleId) { + this.vehicleId = vehicleId; + return this; + } + + public DeviceDO mobileNo(String mobileNo) { + this.mobileNo = mobileNo; + return this; + } + + public DeviceDO iccid(String iccid) { + this.iccid = iccid; + return this; + } + + public DeviceDO imei(String imei) { + this.imei = imei; + return this; + } + + public DeviceDO registerTime(LocalDateTime registerTime) { + this.registerTime = registerTime; + return this; + } + + public DeviceDO installTime(LocalDateTime installTime) { + this.installTime = installTime; + return this; + } + + public DeviceDO protocolVersion(Integer protocolVersion) { + this.protocolVersion = protocolVersion; + return this; + } + + public DeviceDO softwareVersion(String softwareVersion) { + this.softwareVersion = softwareVersion; + return this; + } + + public DeviceDO firmwareVersion(String firmwareVersion) { + this.firmwareVersion = firmwareVersion; + return this; + } + + public DeviceDO hardwareVersion(String hardwareVersion) { + this.hardwareVersion = hardwareVersion; + return this; + } + + public DeviceDO deviceModel(String deviceModel) { + this.deviceModel = deviceModel; + return this; + } + + public DeviceDO makerId(String makerId) { + this.makerId = makerId; + return this; + } + + public DeviceDO deleted(Boolean deleted) { + this.deleted = deleted; + return this; + } + + public DeviceDO updatedBy(String updatedBy) { + this.updatedBy = updatedBy; + return this; + } + + public DeviceDO createdBy(String createdBy) { + this.createdBy = createdBy; + return this; + } + + public DeviceDO updatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + public DeviceDO createdAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + return this; + } + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + DeviceDO other = (DeviceDO) that; + return (this.getDeviceId() == null ? other.getDeviceId() == null : this.getDeviceId().equals(other.getDeviceId())); + } + + @Override + public int hashCode() { + return ((getDeviceId() == null) ? 0 : getDeviceId().hashCode()); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/model/entity/DeviceStatusDO.java b/jtt808-server/src/main/java/org/yzh/web/model/entity/DeviceStatusDO.java new file mode 100644 index 0000000000000000000000000000000000000000..f0a3af3d2130398d2a67f63dadff7b47eea677e2 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/model/entity/DeviceStatusDO.java @@ -0,0 +1,325 @@ +package org.yzh.web.model.entity; + +import java.time.LocalDateTime; + +public class DeviceStatusDO { + + private String deviceId; + private Boolean online; + private Integer agencyId; + private String plateNo; + private LocalDateTime deviceTime; + private String mobileNo; + private Integer vehicleId; + private Integer warnBit; + private Integer statusBit; + private Integer longitude; + private Integer latitude; + private Integer altitude; + private Integer speed; + private Integer direction; + private String address; + private LocalDateTime updatedAt; + private LocalDateTime createdAt; + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public Boolean getOnline() { + return online; + } + + public void setOnline(Boolean online) { + this.online = online; + } + + public Integer getAgencyId() { + return agencyId; + } + + public void setAgencyId(Integer agencyId) { + this.agencyId = agencyId; + } + + public String getPlateNo() { + return plateNo; + } + + public void setPlateNo(String plateNo) { + this.plateNo = plateNo; + } + + public LocalDateTime getDeviceTime() { + return deviceTime; + } + + public void setDeviceTime(LocalDateTime deviceTime) { + this.deviceTime = deviceTime; + } + + public String getMobileNo() { + return mobileNo; + } + + public void setMobileNo(String mobileNo) { + this.mobileNo = mobileNo; + } + + public Integer getVehicleId() { + return vehicleId; + } + + public void setVehicleId(Integer vehicleId) { + this.vehicleId = vehicleId; + } + + public Integer getWarnBit() { + return warnBit; + } + + public void setWarnBit(Integer warnBit) { + this.warnBit = warnBit; + } + + public Integer getStatusBit() { + return statusBit; + } + + public void setStatusBit(Integer statusBit) { + this.statusBit = statusBit; + } + + public Integer getLongitude() { + return longitude; + } + + public void setLongitude(Integer longitude) { + this.longitude = longitude; + } + + public Integer getLatitude() { + return latitude; + } + + public void setLatitude(Integer latitude) { + this.latitude = latitude; + } + + public Integer getAltitude() { + return altitude; + } + + public void setAltitude(Integer altitude) { + this.altitude = altitude; + } + + public Integer getSpeed() { + return speed; + } + + public void setSpeed(Integer speed) { + this.speed = speed; + } + + public Integer getDirection() { + return direction; + } + + public void setDirection(Integer direction) { + this.direction = direction; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public DeviceStatusDO deviceId(String deviceId) { + this.deviceId = deviceId; + return this; + } + + public DeviceStatusDO online(Boolean online) { + this.online = online; + return this; + } + + public DeviceStatusDO agencyId(Integer agencyId) { + this.agencyId = agencyId; + return this; + } + + public DeviceStatusDO plateNo(String plateNo) { + this.plateNo = plateNo; + return this; + } + + public DeviceStatusDO deviceTime(LocalDateTime deviceTime) { + this.deviceTime = deviceTime; + return this; + } + + public DeviceStatusDO mobileNo(String mobileNo) { + this.mobileNo = mobileNo; + return this; + } + + public DeviceStatusDO vehicleId(Integer vehicleId) { + this.vehicleId = vehicleId; + return this; + } + + public DeviceStatusDO warnBit(Integer warnBit) { + this.warnBit = warnBit; + return this; + } + + public DeviceStatusDO statusBit(Integer statusBit) { + this.statusBit = statusBit; + return this; + } + + public DeviceStatusDO longitude(Integer longitude) { + this.longitude = longitude; + return this; + } + + public DeviceStatusDO latitude(Integer latitude) { + this.latitude = latitude; + return this; + } + + public DeviceStatusDO altitude(Integer altitude) { + this.altitude = altitude; + return this; + } + + public DeviceStatusDO speed(Integer speed) { + this.speed = speed; + return this; + } + + public DeviceStatusDO direction(Integer direction) { + this.direction = direction; + return this; + } + + public DeviceStatusDO address(String address) { + this.address = address; + return this; + } + + public DeviceStatusDO updatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + public DeviceStatusDO createdAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + return this; + } + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + DeviceStatusDO other = (DeviceStatusDO) that; + return (this.getDeviceId() == null ? other.getDeviceId() == null : this.getDeviceId().equals(other.getDeviceId())) + && (this.getOnline() == null ? other.getOnline() == null : this.getOnline().equals(other.getOnline())) + && (this.getAgencyId() == null ? other.getAgencyId() == null : this.getAgencyId().equals(other.getAgencyId())) + && (this.getPlateNo() == null ? other.getPlateNo() == null : this.getPlateNo().equals(other.getPlateNo())) + && (this.getDeviceTime() == null ? other.getDeviceTime() == null : this.getDeviceTime().equals(other.getDeviceTime())) + && (this.getMobileNo() == null ? other.getMobileNo() == null : this.getMobileNo().equals(other.getMobileNo())) + && (this.getVehicleId() == null ? other.getVehicleId() == null : this.getVehicleId().equals(other.getVehicleId())) + && (this.getWarnBit() == null ? other.getWarnBit() == null : this.getWarnBit().equals(other.getWarnBit())) + && (this.getStatusBit() == null ? other.getStatusBit() == null : this.getStatusBit().equals(other.getStatusBit())) + && (this.getLongitude() == null ? other.getLongitude() == null : this.getLongitude().equals(other.getLongitude())) + && (this.getLatitude() == null ? other.getLatitude() == null : this.getLatitude().equals(other.getLatitude())) + && (this.getAltitude() == null ? other.getAltitude() == null : this.getAltitude().equals(other.getAltitude())) + && (this.getSpeed() == null ? other.getSpeed() == null : this.getSpeed().equals(other.getSpeed())) + && (this.getDirection() == null ? other.getDirection() == null : this.getDirection().equals(other.getDirection())) + && (this.getAddress() == null ? other.getAddress() == null : this.getAddress().equals(other.getAddress())) + && (this.getUpdatedAt() == null ? other.getUpdatedAt() == null : this.getUpdatedAt().equals(other.getUpdatedAt())) + && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getDeviceId() == null) ? 0 : getDeviceId().hashCode()); + result = prime * result + ((getOnline() == null) ? 0 : getOnline().hashCode()); + result = prime * result + ((getAgencyId() == null) ? 0 : getAgencyId().hashCode()); + result = prime * result + ((getPlateNo() == null) ? 0 : getPlateNo().hashCode()); + result = prime * result + ((getDeviceTime() == null) ? 0 : getDeviceTime().hashCode()); + result = prime * result + ((getMobileNo() == null) ? 0 : getMobileNo().hashCode()); + result = prime * result + ((getVehicleId() == null) ? 0 : getVehicleId().hashCode()); + result = prime * result + ((getWarnBit() == null) ? 0 : getWarnBit().hashCode()); + result = prime * result + ((getStatusBit() == null) ? 0 : getStatusBit().hashCode()); + result = prime * result + ((getLongitude() == null) ? 0 : getLongitude().hashCode()); + result = prime * result + ((getLatitude() == null) ? 0 : getLatitude().hashCode()); + result = prime * result + ((getAltitude() == null) ? 0 : getAltitude().hashCode()); + result = prime * result + ((getSpeed() == null) ? 0 : getSpeed().hashCode()); + result = prime * result + ((getDirection() == null) ? 0 : getDirection().hashCode()); + result = prime * result + ((getAddress() == null) ? 0 : getAddress().hashCode()); + result = prime * result + ((getUpdatedAt() == null) ? 0 : getUpdatedAt().hashCode()); + result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode()); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("DeviceStatus["); + sb.append("deviceId=").append(deviceId); + sb.append(", online=").append(online); + sb.append(", agencyId=").append(agencyId); + sb.append(", plateNo=").append(plateNo); + sb.append(", deviceTime=").append(deviceTime); + sb.append(", mobileNo=").append(mobileNo); + sb.append(", vehicleId=").append(vehicleId); + sb.append(", warnBit=").append(warnBit); + sb.append(", statusBit=").append(statusBit); + sb.append(", longitude=").append(longitude); + sb.append(", latitude=").append(latitude); + sb.append(", altitude=").append(altitude); + sb.append(", speed=").append(speed); + sb.append(", direction=").append(direction); + sb.append(", address=").append(address); + sb.append(", updatedAt=").append(updatedAt); + sb.append(", createdAt=").append(createdAt); + sb.append(']'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/model/entity/LocationDO.java b/jtt808-server/src/main/java/org/yzh/web/model/entity/LocationDO.java new file mode 100644 index 0000000000000000000000000000000000000000..bf79f7bb9bfe18ff18f3ab031bfe9881c23f7fd4 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/model/entity/LocationDO.java @@ -0,0 +1,168 @@ +package org.yzh.web.model.entity; + +import org.yzh.protocol.commons.DateUtils; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class LocationDO { + + private String deviceId; + private String mobileNo; + private String plateNo; + private Integer warnBit; + private Integer statusBit; + private Integer longitude; + private Integer latitude; + private Integer altitude; + private Integer speed; + private Integer direction; + private Integer alarmType; + private LocalDate deviceDate; + private LocalDateTime deviceTime; + private LocalDateTime createdAt; + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getMobileNo() { + return mobileNo; + } + + public void setMobileNo(String mobileNo) { + this.mobileNo = mobileNo; + } + + public String getPlateNo() { + return plateNo; + } + + public void setPlateNo(String plateNo) { + this.plateNo = plateNo; + } + + public Integer getWarnBit() { + return warnBit; + } + + public void setWarnBit(Integer warnBit) { + this.warnBit = warnBit; + } + + public Integer getStatusBit() { + return statusBit; + } + + public void setStatusBit(Integer statusBit) { + this.statusBit = statusBit; + } + + public Integer getLongitude() { + return longitude; + } + + public void setLongitude(Integer longitude) { + this.longitude = longitude; + } + + public Integer getLatitude() { + return latitude; + } + + public void setLatitude(Integer latitude) { + this.latitude = latitude; + } + + public Integer getAltitude() { + return altitude; + } + + public void setAltitude(Integer altitude) { + this.altitude = altitude; + } + + public Integer getSpeed() { + return speed; + } + + public void setSpeed(Integer speed) { + this.speed = speed; + } + + public Integer getDirection() { + return direction; + } + + public void setDirection(Integer direction) { + this.direction = direction; + } + + public Integer getAlarmType() { + return alarmType; + } + + public void setAlarmType(Integer alarmType) { + this.alarmType = alarmType; + } + + public LocalDate getDeviceDate() { + return deviceDate; + } + + public void setDeviceDate(LocalDate deviceDate) { + this.deviceDate = deviceDate; + } + + public LocalDateTime getDeviceTime() { + return deviceTime; + } + + public void setDeviceTime(LocalDateTime deviceTime) { + this.deviceTime = deviceTime; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + LocationDO other = (LocationDO) that; + return (this.getDeviceTime() == null ? other.getDeviceTime() == null : this.getDeviceTime().equals(other.getDeviceTime())) + && (this.getDeviceId() == null ? other.getDeviceId() == null : this.getDeviceId().equals(other.getDeviceId())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getDeviceTime() == null) ? 0 : getDeviceTime().hashCode()); + result = prime * result + ((getDeviceId() == null) ? 0 : getDeviceId().hashCode()); + return result; + } + + @Override + public String toString() { + return new StringBuilder(32) + .append('[').append(deviceId).append(',') + .append(DateUtils.yyMMddHHmmss.format(deviceTime)).append(']').toString(); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/model/entity/VehicleDO.java b/jtt808-server/src/main/java/org/yzh/web/model/entity/VehicleDO.java new file mode 100644 index 0000000000000000000000000000000000000000..3208b6241a11e8e0b39918041eae1723fbe053c0 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/model/entity/VehicleDO.java @@ -0,0 +1,254 @@ +package org.yzh.web.model.entity; + +import java.time.LocalDateTime; + +public class VehicleDO { + + private Integer id; + private Integer agencyId; + private String deviceId; + private String plateNo; + private String vinNo; + private String engineNo; + private Integer plateColor; + private Integer cityId; + private Integer provinceId; + private Integer vehicleType; + private String remark; + private String updatedBy; + private String createdBy; + private LocalDateTime updatedAt; + private LocalDateTime createdAt; + private LocalDateTime areaUpdatedAt; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getAgencyId() { + return agencyId; + } + + public void setAgencyId(Integer agencyId) { + this.agencyId = agencyId; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getPlateNo() { + return plateNo; + } + + public void setPlateNo(String plateNo) { + this.plateNo = plateNo; + } + + public String getVinNo() { + return vinNo; + } + + public void setVinNo(String vinNo) { + this.vinNo = vinNo; + } + + public String getEngineNo() { + return engineNo; + } + + public void setEngineNo(String engineNo) { + this.engineNo = engineNo; + } + + public Integer getPlateColor() { + return plateColor; + } + + public void setPlateColor(Integer plateColor) { + this.plateColor = plateColor; + } + + public Integer getCityId() { + return cityId; + } + + public void setCityId(Integer cityId) { + this.cityId = cityId; + } + + public Integer getProvinceId() { + return provinceId; + } + + public void setProvinceId(Integer provinceId) { + this.provinceId = provinceId; + } + + public Integer getVehicleType() { + return vehicleType; + } + + public void setVehicleType(Integer vehicleType) { + this.vehicleType = vehicleType; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public LocalDateTime getAreaUpdatedAt() { + return areaUpdatedAt; + } + + public void setAreaUpdatedAt(LocalDateTime areaUpdatedAt) { + this.areaUpdatedAt = areaUpdatedAt; + } + + public VehicleDO id(Integer id) { + this.id = id; + return this; + } + + public VehicleDO agencyId(Integer agencyId) { + this.agencyId = agencyId; + return this; + } + + public VehicleDO deviceId(String deviceId) { + this.deviceId = deviceId; + return this; + } + + public VehicleDO plateNo(String plateNo) { + this.plateNo = plateNo; + return this; + } + + public VehicleDO vinNo(String vinNo) { + this.vinNo = vinNo; + return this; + } + + public VehicleDO engineNo(String engineNo) { + this.engineNo = engineNo; + return this; + } + + public VehicleDO plateColor(Integer plateColor) { + this.plateColor = plateColor; + return this; + } + + public VehicleDO cityId(Integer cityId) { + this.cityId = cityId; + return this; + } + + public VehicleDO provinceId(Integer provinceId) { + this.provinceId = provinceId; + return this; + } + + public VehicleDO vehicleType(Integer vehicleType) { + this.vehicleType = vehicleType; + return this; + } + + public VehicleDO remark(String remark) { + this.remark = remark; + return this; + } + + public VehicleDO updatedBy(String updatedBy) { + this.updatedBy = updatedBy; + return this; + } + + public VehicleDO createdBy(String createdBy) { + this.createdBy = createdBy; + return this; + } + + public VehicleDO updatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + public VehicleDO createdAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + return this; + } + + public VehicleDO areaUpdatedAt(LocalDateTime areaUpdatedAt) { + this.areaUpdatedAt = areaUpdatedAt; + return this; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("VehicleDO{"); + sb.append("id=").append(id); + sb.append(", agencyId=").append(agencyId); + sb.append(", deviceId='").append(deviceId).append('\''); + sb.append(", plateNo='").append(plateNo).append('\''); + sb.append(", vinNo='").append(vinNo).append('\''); + sb.append(", engineNo='").append(engineNo).append('\''); + sb.append(", plateColor=").append(plateColor); + sb.append(", cityId=").append(cityId); + sb.append(", provinceId=").append(provinceId); + sb.append(", vehicleType=").append(vehicleType); + sb.append(", remark='").append(remark).append('\''); + sb.append(", updatedBy='").append(updatedBy).append('\''); + sb.append(", createdBy='").append(createdBy).append('\''); + sb.append(", updatedAt=").append(updatedAt); + sb.append(", createdAt=").append(createdAt); + sb.append(", areaUpdatedAt=").append(areaUpdatedAt); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/model/enums/SessionKey.java b/jtt808-server/src/main/java/org/yzh/web/model/enums/SessionKey.java index e0bc478f13a226c4a6a997866c3f38776950bf75..b9738ecf785bd3249e79eb5dd9c3ca18b4ae0b67 100644 --- a/jtt808-server/src/main/java/org/yzh/web/model/enums/SessionKey.java +++ b/jtt808-server/src/main/java/org/yzh/web/model/enums/SessionKey.java @@ -1,6 +1,7 @@ package org.yzh.web.model.enums; import io.github.yezhihao.netmc.session.Session; +import org.yzh.protocol.basics.JTMessageFilter; import org.yzh.protocol.t808.T0200; /** @@ -10,7 +11,8 @@ import org.yzh.protocol.t808.T0200; public enum SessionKey { DeviceInfo, - Snapshot; + Snapshot, + AreaFilter; public static org.yzh.web.model.vo.DeviceInfo getDeviceInfo(Session session) { return (org.yzh.web.model.vo.DeviceInfo) session.getAttribute(DeviceInfo); @@ -20,4 +22,7 @@ public enum SessionKey { return (T0200) session.getAttribute(Snapshot); } + public static JTMessageFilter getAreaFilter(Session session) { + return (JTMessageFilter) session.getAttribute(AreaFilter); + } } \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/model/vo/DeviceQuery.java b/jtt808-server/src/main/java/org/yzh/web/model/vo/DeviceQuery.java new file mode 100644 index 0000000000000000000000000000000000000000..9ff8410e6d79a9fbb9595171ea03d7e1980849c5 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/model/vo/DeviceQuery.java @@ -0,0 +1,154 @@ +package org.yzh.web.model.vo; + +import io.github.yezhihao.netmc.session.Session; +import io.swagger.v3.oas.annotations.media.Schema; +import org.yzh.commons.mybatis.PageInfo; +import org.yzh.commons.util.CoordType; +import org.yzh.commons.util.StrUtils; +import org.yzh.component.area.GeometryFactory; +import org.yzh.component.area.model.domain.Geometry; +import org.yzh.web.model.enums.SessionKey; +import org.yzh.protocol.t808.T0200; + +import java.util.function.Predicate; + +/** + * @author yezhihao + * https://gitee.com/yezhihao/jt808-server + */ +public class DeviceQuery extends PageInfo implements Predicate { + + @Schema(description = "机构ID") + protected Integer agencyId; + @Schema(description = "车辆ID") + protected Integer vehicleId; + + @Schema(description = "设备ID") + protected String deviceId; + @Schema(description = "终端ID") + protected String clientId; + @Schema(description = "车牌号") + protected String plateNo; + + @Schema(description = "几何数据: 圆形[x,y,r] 矩形[x,y,x,y] 多边形[x,y,x,y,x,y] 路线[x,y,x,y,w]") + protected String areaRaw; + @Schema(description = "几何类型: 1.圆形 2.矩形 3.多边形 4.路线") + protected int areaType = 1; + @Schema(description = "坐标类型: wgs84 、gcj02、bd09") + protected CoordType coordType = CoordType.wgs84; + + @Schema(hidden = true) + private Geometry geometry; + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public Integer getAgencyId() { + return agencyId; + } + + public void setAgencyId(Integer agencyId) { + this.agencyId = agencyId; + } + + public Integer getVehicleId() { + return vehicleId; + } + + public void setVehicleId(Integer vehicleId) { + this.vehicleId = vehicleId; + } + + public String getPlateNo() { + return plateNo; + } + + public void setPlateNo(String plateNo) { + this.plateNo = plateNo; + } + + public CoordType getCoordType() { + return coordType; + } + + public void setCoordType(CoordType coordType) { + this.coordType = coordType; + } + + public int getAreaType() { + return areaType; + } + + public void setAreaType(int areaType) { + this.areaType = areaType; + } + + public String getAreaRaw() { + return areaRaw; + } + + public void setAreaRaw(String areaRaw) { + this.areaRaw = areaRaw; + } + + public boolean isEmpty() { + if (agencyId != null) + return false; + if (vehicleId != null) + return false; + + if (StrUtils.isNotBlank(deviceId)) + return false; + if (StrUtils.isNotBlank(clientId)) + return false; + if (StrUtils.isNotBlank(plateNo)) + return false; + + if (StrUtils.isNotBlank(areaRaw)) { + if (geometry == null) + geometry = GeometryFactory.build(coordType.WGS84, areaType, areaRaw); + return false; + } + return true; + } + + @Override + public boolean test(Session session) { + DeviceInfo that = SessionKey.getDeviceInfo(session); + T0200 snapshot = SessionKey.getSnapshot(session); + + boolean result = true; + + if (snapshot != null) { + if (geometry != null) + result &= geometry.contains(snapshot.getLng(), snapshot.getLat()); + } + + if (that != null) { + if (this.agencyId != null) + result &= that.agencyId == this.agencyId; + if (this.vehicleId != null) + result &= that.vehicleId == this.vehicleId; + if (this.plateNo != null && that.plateNo != null) + result &= that.plateNo.startsWith(this.plateNo); + if (this.deviceId != null && that.deviceId != null) + result &= that.deviceId.startsWith(this.deviceId); + if (this.clientId != null && that.clientId != null) + result &= that.clientId.startsWith(this.clientId); + } + return result; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/model/vo/Location.java b/jtt808-server/src/main/java/org/yzh/web/model/vo/Location.java new file mode 100644 index 0000000000000000000000000000000000000000..31982c1f942dec5a55bf13596b225a49cdee5db7 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/model/vo/Location.java @@ -0,0 +1,7 @@ +package org.yzh.web.model.vo; + +import org.yzh.web.model.entity.LocationDO; + +public class Location extends LocationDO { + +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/model/vo/LocationQuery.java b/jtt808-server/src/main/java/org/yzh/web/model/vo/LocationQuery.java new file mode 100644 index 0000000000000000000000000000000000000000..b2f5e29fbd3103b2ef3d7df334cbfb6bd5a68fe7 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/model/vo/LocationQuery.java @@ -0,0 +1,55 @@ +package org.yzh.web.model.vo; + +import org.yzh.commons.mybatis.PageInfo; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class LocationQuery extends PageInfo { + + private String deviceId; + private String plateNo; + private LocalDate day; + private LocalDateTime startTime; + private LocalDateTime endTime; + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getPlateNo() { + return plateNo; + } + + public void setPlateNo(String plateNo) { + this.plateNo = plateNo; + } + + public LocalDate getDay() { + return day; + } + + public void setDay(LocalDate day) { + this.day = day; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/service/DeviceService.java b/jtt808-server/src/main/java/org/yzh/web/service/DeviceService.java new file mode 100644 index 0000000000000000000000000000000000000000..776fdba95c47bf12ddc2ccb733314160ca20bbf9 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/service/DeviceService.java @@ -0,0 +1,14 @@ +package org.yzh.web.service; + +import org.yzh.protocol.t808.T0100; +import org.yzh.protocol.t808.T0102; +import org.yzh.commons.model.Result; +import org.yzh.web.model.vo.DeviceInfo; + +public interface DeviceService { + + Result register(T0100 request); + + DeviceInfo authentication(T0102 request); + +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/service/LocationService.java b/jtt808-server/src/main/java/org/yzh/web/service/LocationService.java new file mode 100644 index 0000000000000000000000000000000000000000..ec132e58fa1eff659f4555d0f215766a5ddcf1b9 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/service/LocationService.java @@ -0,0 +1,14 @@ +package org.yzh.web.service; + +import org.yzh.protocol.t808.T0200; +import org.yzh.web.model.vo.Location; +import org.yzh.web.model.vo.LocationQuery; + +import java.util.List; + +public interface LocationService { + + List find(LocationQuery query); + + void batchInsert(List list); +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/service/impl/DeviceServiceImpl.java b/jtt808-server/src/main/java/org/yzh/web/service/impl/DeviceServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..dedfc5fd0bd0c2741a4c9884b08a2d5d2e85a1b6 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/service/impl/DeviceServiceImpl.java @@ -0,0 +1,219 @@ +package org.yzh.web.service.impl; + +import io.github.yezhihao.netmc.session.Session; +import io.github.yezhihao.netmc.session.SessionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.yzh.commons.model.Result; +import org.yzh.commons.util.EncryptUtils; +import org.yzh.commons.util.IOUtils; +import org.yzh.commons.util.StrUtils; +import org.yzh.protocol.commons.DateUtils; +import org.yzh.protocol.t808.T0100; +import org.yzh.protocol.t808.T0102; +import org.yzh.protocol.t808.T8100; +import org.yzh.web.mapper.DeviceMapper; +import org.yzh.web.mapper.VehicleMapper; +import org.yzh.web.model.entity.DeviceDO; +import org.yzh.web.model.entity.VehicleDO; +import org.yzh.web.model.enums.SessionKey; +import org.yzh.protocol.t808.T0200; +import org.yzh.web.model.vo.DeviceInfo; +import org.yzh.web.service.DeviceService; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.Statement; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Base64; +import java.util.Collection; + +@Service +public class DeviceServiceImpl implements DeviceService { + + private static final Logger log = LoggerFactory.getLogger(DeviceServiceImpl.class.getSimpleName()); + + private static final Result AlreadyRegisteredTerminal = Result.of(T8100.AlreadyRegisteredTerminal); + private static final Result NotFoundTerminal = Result.of(T8100.NotFoundTerminal); + private static final Result AlreadyRegisteredVehicle = Result.of(T8100.AlreadyRegisteredVehicle); + private static final Result NotFoundVehicle = Result.of(T8100.NotFoundVehicle); + + private static final boolean vehicleCheck = false;//是否校验车牌号 + private static final boolean deviceCheck = false;//是否校验设备ID + + @Autowired + private DeviceMapper deviceMapper; + + @Autowired + private VehicleMapper vehicleMapper; + + @Qualifier("dataSource") + @Autowired + private DataSource dataSource; + + @Autowired + private SessionManager sessionManager; + + @Override + public Result register(T0100 request) { + String clientId = request.getClientId(); + String deviceId = request.getDeviceId(); + String plateNo = request.getPlateNo(); + + if (StrUtils.isBlank(clientId) || StrUtils.isBlank(deviceId) || StrUtils.isBlank(plateNo)) + return NotFoundTerminal; + + VehicleDO vehicle = vehicleMapper.getByPlateNo(plateNo); + if (vehicle != null) { + if (!(StrUtils.isBlank(vehicle.getDeviceId()) || deviceId.equals(vehicle.getDeviceId()))) + return AlreadyRegisteredVehicle; + } else { + if (vehicleCheck) + return NotFoundVehicle; + vehicle = new VehicleDO(); + } + + DeviceDO device = deviceMapper.get(deviceId); + if (device != null) { + if (!(device.getVehicleId() == null || device.getVehicleId().equals(vehicle.getId()))) + return AlreadyRegisteredTerminal; + } else { + if (deviceCheck) + return NotFoundTerminal; + device = new DeviceDO(); + } + + vehicle.setDeviceId(deviceId); + vehicle.setPlateNo(plateNo); + vehicle.setPlateColor(request.getPlateColor()); + vehicle.setCityId(request.getCityId()); + vehicle.setProvinceId(request.getProvinceId()); + + if (vehicle.getId() != null) { + vehicleMapper.update(vehicle.updatedBy("device")); + } else { + vehicleMapper.insert(vehicle.createdBy("device")); + } + + + device.setVehicleId(vehicle.getId()); + device.setAgencyId(vehicle.getAgencyId()); + device.setMobileNo(clientId); + device.setDeviceModel(request.getDeviceModel()); + device.setProtocolVersion(request.getProtocolVersion()); + device.setMakerId(request.getMakerId()); + device.setRegisterTime(LocalDateTime.now()); + + if (device.getDeviceId() != null) { + deviceMapper.update(device.updatedBy("device")); + } else { + if (device.getInstallTime() == null) + device.setInstallTime(LocalDateTime.now()); + deviceMapper.insert(device.createdBy("device").deviceId(deviceId)); + } + + + DeviceInfo deviceInfo = new DeviceInfo(); + deviceInfo.setIssuedAt(LocalDate.now()); + deviceInfo.setDeviceId(deviceId); + deviceInfo.setVehicleId(vehicle.getId()); + deviceInfo.setClientId(clientId); + deviceInfo.setProtocolVersion(request.getProtocolVersion()); + + deviceInfo.setReserved((byte) 0); + deviceInfo.setPlateColor((byte) request.getPlateColor()); + deviceInfo.setPlateNo(plateNo); + return Result.of(deviceInfo); + } + + @Override + public DeviceInfo authentication(T0102 request) { + try { + byte[] bytes = Base64.getDecoder().decode(request.getToken()); + bytes = EncryptUtils.decrypt(bytes); + DeviceInfo deviceInfo = DeviceInfo.formBytes(bytes); + + DeviceDO record = deviceMapper.get(deviceInfo.getDeviceId()); + if (record == null) { + log.warn("鉴权失败:不存在的设备ID[{}]", deviceInfo.getDeviceId()); + return null; + } + + if (request.getImei() != null && !request.getImei().equals(record.getImei())) { + deviceMapper.update(new DeviceDO() + .deviceId(deviceInfo.getDeviceId()) + .imei(request.getImei()) + .softwareVersion(request.getSoftwareVersion())); + } + + deviceInfo.setAgencyId(record.getAgencyId()); + deviceInfo.setVehicleId(record.getVehicleId()); + deviceInfo.setPlateNo(record.getPlateNo()); + deviceInfo.setPlateColor(record.getPlateColor()); + deviceInfo.setClientId(request.getClientId()); + deviceInfo.setProtocolVersion(request.getProtocolVersion()); + return deviceInfo; + } catch (Exception e) { + log.warn("鉴权失败:错误的token[{}],{}", request.getToken(), e.getMessage()); + return null; + } + } + + private static final String SQL_HEAD = "insert into device_status (device_time,device_id,mobile_no,warn_bit,status_bit,longitude,latitude,altitude,speed,direction,updated_at) values "; + private static final String SQL_TAIL = "on duplicate key update device_time=values(device_time),mobile_no=values(mobile_no),warn_bit=values(warn_bit),status_bit=values(status_bit),longitude=values(longitude),latitude=values(latitude),altitude=values(altitude),speed=values(speed),direction=values(direction),updated_at=values(updated_at)"; + + @Scheduled(fixedDelay = 1000) + public void updateDeviceStatus() { + Collection all = sessionManager.all(); + if (all.isEmpty()) + return; + + String now = DateUtils.DATE_TIME_FORMATTER.format(LocalDateTime.now()); + + StringBuilder builder = new StringBuilder(1024); + builder.append(SQL_HEAD); + + for (Session session : all) { + T0200 request = SessionKey.getSnapshot(session); + if (request == null || request.updated()) + continue; + + builder.append('('); + builder.append('\'').append(DateUtils.DATE_TIME_FORMATTER.format(request.getDeviceTime())).append('\'').append(','); + builder.append('\'').append(request.getDeviceId()).append('\'').append(','); + builder.append(request.getClientId()).append(','); + builder.append(request.getWarnBit()).append(','); + builder.append(request.getStatusBit()).append(','); + builder.append(request.getLongitude()).append(','); + builder.append(request.getLatitude()).append(','); + builder.append(request.getAltitude()).append(','); + builder.append(request.getSpeed()).append(','); + builder.append(request.getDirection()).append(','); + builder.append('\'').append(now).append('\''); + builder.append(')'); + builder.append(','); + } + if (builder.length() == SQL_HEAD.length()) + return; + builder.setCharAt(builder.length() - 1, ' '); + builder.append(SQL_TAIL); + String sql = builder.toString(); + + Connection connection = null; + Statement statement = null; + try { + connection = dataSource.getConnection(); + statement = connection.createStatement(); + statement.executeUpdate(sql); + } catch (Exception e) { + log.error("批量更新失败", e); + } finally { + IOUtils.close(statement, connection); + } + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/java/org/yzh/web/service/impl/LocationServiceImpl.java b/jtt808-server/src/main/java/org/yzh/web/service/impl/LocationServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..9107479571399bf5fe1bf25668036019faf07f98 --- /dev/null +++ b/jtt808-server/src/main/java/org/yzh/web/service/impl/LocationServiceImpl.java @@ -0,0 +1,130 @@ +package org.yzh.web.service.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.yzh.protocol.t808.T0200; +import org.yzh.protocol.commons.DateUtils; +import org.yzh.commons.util.IOUtils; +import org.yzh.web.mapper.LocationMapper; +import org.yzh.web.model.vo.Location; +import org.yzh.web.model.vo.LocationQuery; +import org.yzh.web.service.LocationService; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.time.LocalDateTime; +import java.util.List; + +@Service +public class LocationServiceImpl implements LocationService { + + private static final Logger log = LoggerFactory.getLogger(LocationServiceImpl.class.getSimpleName()); + + @Autowired + private LocationMapper locationMapper; + + @Qualifier("dataSource") + @Autowired + private DataSource dataSource; + + @Override + public List find(LocationQuery query) { + List result = locationMapper.find(query); + return result; + } + + @Override + public void batchInsert(List list) { + //MySQL预编译语句不支持批量写入,改用SQL拼接方式 +// jdbcBatchInsert(list); + jdbcSQLInsert(list); + } + + private static final String SQL_HEAD = "insert ignore into location (device_time,device_id,mobile_no,vehicle_id,warn_bit,status_bit,longitude,latitude,altitude,speed,direction,created_at) values "; + private static final String SQL = SQL_HEAD + "(?,?,?,?,?,?,?,?,?,?,?,?,?)"; + + public void jdbcBatchInsert(List list) { + LocalDateTime now = LocalDateTime.now(); + int size = list.size(); + + Connection connection = null; + PreparedStatement statement = null; + try { + connection = dataSource.getConnection(); + statement = connection.prepareStatement(SQL); + for (int i = 0; i < size; i++) { + T0200 request = list.get(i); + int j = 1; + + statement.setObject(j++, request.getDeviceTime()); + statement.setString(j++, request.getDeviceId()); + statement.setString(j++, request.getClientId()); + statement.setInt(j++, request.getVehicleId()); + statement.setInt(j++, request.getWarnBit()); + statement.setInt(j++, request.getStatusBit()); + statement.setInt(j++, request.getLongitude()); + statement.setInt(j++, request.getLatitude()); + statement.setInt(j++, request.getAltitude()); + statement.setInt(j++, request.getSpeed()); + statement.setInt(j++, request.getDirection()); + statement.setObject(j, now); + + statement.addBatch(); + } + statement.executeLargeBatch(); + } catch (Exception e) { + log.error("批量写入失败", e); + } finally { + IOUtils.close(statement, connection); + } + } + + public void jdbcSQLInsert(List list) { + String now = DateUtils.DATE_TIME_FORMATTER.format(LocalDateTime.now()); + int size = list.size(); + + StringBuilder builder = new StringBuilder(size * 132 + 174); + builder.append(SQL_HEAD); + + for (int i = 0; i < size; i++) { + T0200 request = list.get(i); + + builder.append('('); + builder.append('\'').append(DateUtils.DATE_TIME_FORMATTER.format(request.getDeviceTime())).append('\'').append(','); + builder.append('\'').append(request.getDeviceId()).append('\'').append(','); + builder.append(request.getClientId()).append(','); + builder.append(request.getVehicleId()).append(','); + builder.append(request.getWarnBit()).append(','); + builder.append(request.getStatusBit()).append(','); + builder.append(request.getLongitude()).append(','); + builder.append(request.getLatitude()).append(','); + builder.append(request.getAltitude()).append(','); + builder.append(request.getSpeed()).append(','); + builder.append(request.getDirection()).append(','); + builder.append('\'').append(now).append('\''); + builder.append(')'); + builder.append(','); + } + String sql = builder.substring(0, builder.length() - 1); + + Connection connection = null; + Statement statement = null; + try { + connection = dataSource.getConnection(); + statement = connection.createStatement(); + int row = statement.executeUpdate(sql); + if (row < size) + log.warn("批量写入存在重复的主键或唯一键,新增:{},忽略:{}", row, size - row); + } catch (Exception e) { + log.error(sql); + log.error("批量写入失败", e); + } finally { + IOUtils.close(statement, connection); + } + } +} \ No newline at end of file diff --git a/jtt808-server/src/main/resources/application-test.yml b/jtt808-server/src/main/resources/application-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..6a0587a3e00de95c840f670982d3045f83c712b3 --- /dev/null +++ b/jtt808-server/src/main/resources/application-test.yml @@ -0,0 +1,7 @@ +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/jt + username: root + password: 123@abc + driver-class-name: com.mysql.cj.jdbc.Driver + initialization-mode: never diff --git a/jtt808-server/src/main/resources/application.yml b/jtt808-server/src/main/resources/application.yml index 7d040797e2f5e03f241964605878983e1fb7cb48..420e17971eb6450da75464d26bcee2e9200fb7e6 100644 --- a/jtt808-server/src/main/resources/application.yml +++ b/jtt808-server/src/main/resources/application.yml @@ -6,6 +6,8 @@ spring: driver-class-name: org.h2.Driver type: com.zaxxer.hikari.HikariDataSource initialization-mode: always + schema: classpath:sql/schema_mysql.sql + data: classpath:sql/initial.sql hikari: minimum-idle: 8 maximum-pool-size: 8 diff --git a/jtt808-server/src/main/resources/generatorConfig.xml b/jtt808-server/src/main/resources/generatorConfig.xml new file mode 100644 index 0000000000000000000000000000000000000000..8d1a5c28bd6683c949959130d003f0b2d29ad5fa --- /dev/null +++ b/jtt808-server/src/main/resources/generatorConfig.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jtt808-server/src/main/resources/mapper/AreaMapper.xml b/jtt808-server/src/main/resources/mapper/AreaMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..b730c7e8ab568f80331e939341d213bcd8b9be54 --- /dev/null +++ b/jtt808-server/src/main/resources/mapper/AreaMapper.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + update area + + agency_id = #{agencyId,jdbcType=SMALLINT}, + name = #{name,jdbcType=VARCHAR}, + area_desc = #{areaDesc,jdbcType=VARCHAR}, + geom_type = #{geomType,jdbcType=TINYINT}, + mark_type = #{markType,jdbcType=TINYINT}, + limit_in_out = #{limitInOut,jdbcType=TINYINT}, + limit_speed = #{limitSpeed,jdbcType=TINYINT}, + limit_time = #{limitTime,jdbcType=TINYINT}, + weeks = #{weeks,jdbcType=TINYINT}, + start_date = #{startDate,jdbcType=DATE}, + end_date = #{endDate,jdbcType=DATE}, + start_time = #{startTime,jdbcType=TIME}, + end_time = #{endTime,jdbcType=TIME}, + geom_text = #{geomText,jdbcType=LONGVARCHAR}, + updated_by = #{updatedBy,jdbcType=VARCHAR}, updated_at = now() + + where id = #{id,jdbcType=SMALLINT}; + + update vehicle + set area_updated_at = now() + where id in ( + select vehicle_id + from area_vehicle + where area_id = #{id,jdbcType=SMALLINT} + ) + + + + + insert into area + + agency_id, + name, + area_desc, + geom_type, + mark_type, + limit_in_out, + limit_speed, + limit_time, + weeks, + start_date, + end_date, + start_time, + end_time, + deleted, + geom_text, + updated_by,created_by,updated_at,created_at + + + #{agencyId,jdbcType=SMALLINT}, + #{name,jdbcType=VARCHAR}, + #{areaDesc,jdbcType=VARCHAR}, + #{geomType,jdbcType=TINYINT}, + #{markType,jdbcType=TINYINT}, + #{limitInOut,jdbcType=TINYINT}, + #{limitSpeed,jdbcType=TINYINT}, + #{limitTime,jdbcType=TINYINT}, + #{weeks,jdbcType=TINYINT}, + #{startDate,jdbcType=DATE}, + #{endDate,jdbcType=DATE}, + #{startTime,jdbcType=TIME}, + #{endTime,jdbcType=TIME}, + #{deleted,jdbcType=BIT}, + #{geomText,jdbcType=LONGVARCHAR}, + #{createdBy,jdbcType=VARCHAR},#{createdBy,jdbcType=VARCHAR},now(),now() + + + + + update vehicle + set area_updated_at = now() + where id = #{vehicleId,jdbcType=INTEGER} + + + + insert ignore into area_vehicle (vehicle_id, area_id, created_by, created_at) values + (#{vehicleId,jdbcType=INTEGER}, #{areaId,jdbcType=SMALLINT}, #{createdBy,jdbcType=VARCHAR}, now()); + + + + + delete from area_vehicle + where vehicle_id = #{vehicleId,jdbcType=INTEGER} + and area_id = #{areaId,jdbcType=SMALLINT}; + + + \ No newline at end of file diff --git a/jtt808-server/src/main/resources/mapper/DeviceMapper.xml b/jtt808-server/src/main/resources/mapper/DeviceMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..f9efb20d43a0f741095ffc77d9ee4a42481e184e --- /dev/null +++ b/jtt808-server/src/main/resources/mapper/DeviceMapper.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + update device + + agency_id = #{agencyId,jdbcType=SMALLINT}, + vehicle_id = #{vehicleId,jdbcType=INTEGER}, + mobile_no = #{mobileNo,jdbcType=BIGINT}, + iccid = #{iccid,jdbcType=CHAR}, + imei = #{imei,jdbcType=VARCHAR}, + register_time = #{registerTime,jdbcType=TIMESTAMP}, + install_time = #{installTime,jdbcType=TIMESTAMP}, + protocol_version = #{protocolVersion,jdbcType=TINYINT}, + software_version = #{softwareVersion,jdbcType=VARCHAR}, + firmware_version = #{firmwareVersion,jdbcType=VARCHAR}, + hardware_version = #{hardwareVersion,jdbcType=VARCHAR}, + device_model = #{deviceModel,jdbcType=VARCHAR}, + maker_id = #{makerId,jdbcType=VARCHAR}, + deleted = #{deleted,jdbcType=BOOLEAN}, + updated_by = #{updatedBy,jdbcType=VARCHAR}, + updated_at = #{updatedAt,jdbcType=TIMESTAMP}, + + where device_id = #{deviceId,jdbcType=VARCHAR} + + + + insert ignore into device + + agency_id, + vehicle_id, + mobile_no, + iccid, + imei, + register_time, + install_time, + protocol_version, + software_version, + firmware_version, + hardware_version, + device_model, + maker_id, + deleted, + updated_by,created_by,updated_at,created_at,device_id + + + #{agencyId,jdbcType=SMALLINT}, + #{vehicleId,jdbcType=INTEGER}, + #{mobileNo,jdbcType=BIGINT}, + #{iccid,jdbcType=CHAR}, + #{imei,jdbcType=VARCHAR}, + #{registerTime,jdbcType=TIMESTAMP}, + #{installTime,jdbcType=TIMESTAMP}, + #{protocolVersion,jdbcType=TINYINT}, + #{softwareVersion,jdbcType=VARCHAR}, + #{firmwareVersion,jdbcType=VARCHAR}, + #{hardwareVersion,jdbcType=VARCHAR}, + #{deviceModel,jdbcType=VARCHAR}, + #{makerId,jdbcType=VARCHAR}, + #{deleted,jdbcType=BOOLEAN}, + #{createdBy,jdbcType=VARCHAR},#{createdBy,jdbcType=VARCHAR},now(),now(),#{deviceId,jdbcType=VARCHAR} + + + + + delete + from device + where device_id = #{deviceId,jdbcType=VARCHAR} + + \ No newline at end of file diff --git a/jtt808-server/src/main/resources/mapper/DeviceStatusMapper.xml b/jtt808-server/src/main/resources/mapper/DeviceStatusMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..3d6b61ab915b670ca31abef8e0580050d90b36e9 --- /dev/null +++ b/jtt808-server/src/main/resources/mapper/DeviceStatusMapper.xml @@ -0,0 +1,45 @@ + + + + + + + + update device_status + + online = #{online,jdbcType=BIT}, + agency_id = #{agencyId,jdbcType=SMALLINT}, + plate_no = #{plateNo,jdbcType=CHAR}, + mobile_no = #{mobileNo,jdbcType=BIGINT}, + vehicle_id = #{vehicleId,jdbcType=INTEGER}, + updated_at = now() + + where device_id = #{deviceId,jdbcType=VARCHAR} + + + + insert into device_status (device_id, online, agency_id, plate_no, mobile_no, vehicle_id, device_time, updated_at, created_at) + values (#{deviceId,jdbcType=VARCHAR}, #{online,jdbcType=BIT}, #{agencyId,jdbcType=SMALLINT}, + #{plateNo,jdbcType=CHAR}, #{mobileNo,jdbcType=BIGINT}, #{vehicleId,jdbcType=INTEGER}, now(), now(), now()) + + + + insert ignore into online_record (agency_id, vehicle_id, mobile_no, device_id, online_time, online_duration) + values (#{d.agencyId,jdbcType=SMALLINT}, #{d.vehicleId,jdbcType=INTEGER}, #{d.clientId,jdbcType=VARCHAR}, + #{d.deviceId,jdbcType=VARCHAR}, #{onlineTime,jdbcType=TIMESTAMP}, #{onlineDuration,jdbcType=INTEGER}) + + \ No newline at end of file diff --git a/jtt808-server/src/main/resources/mapper/LocationMapper.xml b/jtt808-server/src/main/resources/mapper/LocationMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..5e604376f6cdb9cbac4a6ef02576faf05f31a279 --- /dev/null +++ b/jtt808-server/src/main/resources/mapper/LocationMapper.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/jtt808-server/src/main/resources/mapper/VehicleMapper.xml b/jtt808-server/src/main/resources/mapper/VehicleMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..a43128f1cae9f341b4402c1671041575c98c0d9c --- /dev/null +++ b/jtt808-server/src/main/resources/mapper/VehicleMapper.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + update vehicle + + device_id = #{deviceId,jdbcType=VARCHAR}, + agency_id = #{agencyId,jdbcType=SMALLINT}, + plate_no = #{plateNo,jdbcType=CHAR}, + vin_no = #{vinNo,jdbcType=CHAR}, + engine_no = #{engineNo,jdbcType=VARCHAR}, + plate_color = #{plateColor,jdbcType=TINYINT}, + city_id = #{cityId,jdbcType=SMALLINT}, + province_id = #{provinceId,jdbcType=TINYINT}, + vehicle_type = #{vehicleType,jdbcType=TINYINT}, + remark = #{remark,jdbcType=VARCHAR}, + updated_by=#{updatedBy,jdbcType=VARCHAR},updated_at=now() + + where id = #{id,jdbcType=INTEGER} + + + + insert into vehicle + + device_id, + agency_id, + plate_no, + vin_no, + engine_no, + plate_color, + city_id, + province_id, + vehicle_type, + remark, + updated_by,created_by,updated_at,created_at,area_updated_at + + + #{deviceId,jdbcType=VARCHAR}, + #{agencyId,jdbcType=SMALLINT}, + #{plateNo,jdbcType=CHAR}, + #{vinNo,jdbcType=CHAR}, + #{engineNo,jdbcType=VARCHAR}, + #{plateColor,jdbcType=TINYINT}, + #{cityId,jdbcType=SMALLINT}, + #{provinceId,jdbcType=TINYINT}, + #{vehicleType,jdbcType=TINYINT}, + #{remark,jdbcType=VARCHAR}, + #{createdBy,jdbcType=VARCHAR},#{createdBy,jdbcType=VARCHAR},now(),now(),now() + + + + + delete + from vehicle + where id = #{id,jdbcType=INTEGER} + + \ No newline at end of file diff --git a/jtt808-server/src/main/resources/sql/initial.sql b/jtt808-server/src/main/resources/sql/initial.sql new file mode 100644 index 0000000000000000000000000000000000000000..0777127164750d7a1944cd35bd30fb6695808402 --- /dev/null +++ b/jtt808-server/src/main/resources/sql/initial.sql @@ -0,0 +1,1009 @@ +insert ignore into area(id, limit_in_out, limit_speed, limit_time, name, agency_id, mark_type, geom_type, geom_text) values + (1, 1, 0, 1, '圆形1', 0, 1, 1, '121.740204,30.886695,100'), + (2, 2, 10, 1, '矩形4', 0, 1, 2, '121.746942,30.881797,121.750547,30.879329'), + (3, 1, 10, 1, '多边形2', 0, 1, 3, '121.739603,30.882754,121.740548,30.882644,121.740140,30.880784,121.742629,30.880692,121.742307,30.879789,121.739110,30.880047'), + (4, 2, 5, 1, '路线3', 0, 1, 4, '121.740140,30.882183,121.739582,30.880158,121.735376,30.880416,30') +; + +insert ignore into area_vehicle(vehicle_id, area_id) values + (1,1),(1,2),(1,3),(1,4), + (2,1),(2,2),(2,3),(2,4), + (3,1),(3,2),(3,3),(3,4), + (4,1),(4,2),(4,3),(4,4), + (5,1),(5,2),(5,3),(5,4), + (6,1),(6,2),(6,3),(6,4), + (7,1),(7,2),(7,3),(7,4), + (8,1),(8,2),(8,3),(8,4), + (9,1),(9,2),(9,3),(9,4), + (10,1),(10,2),(10,3),(10,4), + (11,1),(11,2),(11,3),(11,4), + (12,1),(12,2),(12,3),(12,4), + (13,1),(13,2),(13,3),(13,4), + (14,1),(14,2),(14,3),(14,4), + (15,1),(15,2),(15,3),(15,4), + (16,1),(16,2),(16,3),(16,4), + (17,1),(17,2),(17,3),(17,4), + (18,1),(18,2),(18,3),(18,4), + (19,1),(19,2),(19,3),(19,4), + (20,1),(20,2),(20,3),(20,4), + (21,1),(21,2),(21,3),(21,4), + (22,1),(22,2),(22,3),(22,4), + (23,1),(23,2),(23,3),(23,4), + (24,1),(24,2),(24,3),(24,4), + (25,1),(25,2),(25,3),(25,4), + (26,1),(26,2),(26,3),(26,4), + (27,1),(27,2),(27,3),(27,4), + (28,1),(28,2),(28,3),(28,4), + (29,1),(29,2),(29,3),(29,4), + (30,1),(30,2),(30,3),(30,4), + (31,1),(31,2),(31,3),(31,4), + (32,1),(32,2),(32,3),(32,4), + (33,1),(33,2),(33,3),(33,4), + (34,1),(34,2),(34,3),(34,4), + (35,1),(35,2),(35,3),(35,4), + (36,1),(36,2),(36,3),(36,4), + (37,1),(37,2),(37,3),(37,4), + (38,1),(38,2),(38,3),(38,4), + (39,1),(39,2),(39,3),(39,4), + (40,1),(40,2),(40,3),(40,4), + (41,1),(41,2),(41,3),(41,4), + (42,1),(42,2),(42,3),(42,4), + (43,1),(43,2),(43,3),(43,4), + (44,1),(44,2),(44,3),(44,4), + (45,1),(45,2),(45,3),(45,4), + (46,1),(46,2),(46,3),(46,4), + (47,1),(47,2),(47,3),(47,4), + (48,1),(48,2),(48,3),(48,4), + (49,1),(49,2),(49,3),(49,4), + (50,1),(50,2),(50,3),(50,4), + (51,1),(51,2),(51,3),(51,4), + (52,1),(52,2),(52,3),(52,4), + (53,1),(53,2),(53,3),(53,4), + (54,1),(54,2),(54,3),(54,4), + (55,1),(55,2),(55,3),(55,4), + (56,1),(56,2),(56,3),(56,4), + (57,1),(57,2),(57,3),(57,4), + (58,1),(58,2),(58,3),(58,4), + (59,1),(59,2),(59,3),(59,4), + (60,1),(60,2),(60,3),(60,4), + (61,1),(61,2),(61,3),(61,4), + (62,1),(62,2),(62,3),(62,4), + (63,1),(63,2),(63,3),(63,4), + (64,1),(64,2),(64,3),(64,4), + (65,1),(65,2),(65,3),(65,4), + (66,1),(66,2),(66,3),(66,4), + (67,1),(67,2),(67,3),(67,4), + (68,1),(68,2),(68,3),(68,4), + (69,1),(69,2),(69,3),(69,4), + (70,1),(70,2),(70,3),(70,4), + (71,1),(71,2),(71,3),(71,4), + (72,1),(72,2),(72,3),(72,4), + (73,1),(73,2),(73,3),(73,4), + (74,1),(74,2),(74,3),(74,4), + (75,1),(75,2),(75,3),(75,4), + (76,1),(76,2),(76,3),(76,4), + (77,1),(77,2),(77,3),(77,4), + (78,1),(78,2),(78,3),(78,4), + (79,1),(79,2),(79,3),(79,4), + (80,1),(80,2),(80,3),(80,4), + (81,1),(81,2),(81,3),(81,4), + (82,1),(82,2),(82,3),(82,4), + (83,1),(83,2),(83,3),(83,4), + (84,1),(84,2),(84,3),(84,4), + (85,1),(85,2),(85,3),(85,4), + (86,1),(86,2),(86,3),(86,4), + (87,1),(87,2),(87,3),(87,4), + (88,1),(88,2),(88,3),(88,4), + (89,1),(89,2),(89,3),(89,4), + (90,1),(90,2),(90,3),(90,4), + (91,1),(91,2),(91,3),(91,4), + (92,1),(92,2),(92,3),(92,4), + (93,1),(93,2),(93,3),(93,4), + (94,1),(94,2),(94,3),(94,4), + (95,1),(95,2),(95,3),(95,4), + (96,1),(96,2),(96,3),(96,4), + (97,1),(97,2),(97,3),(97,4), + (98,1),(98,2),(98,3),(98,4), + (99,1),(99,2),(99,3),(99,4), + (100,1),(100,2),(100,3),(100,4), + (101,1),(101,2),(101,3),(101,4), + (102,1),(102,2),(102,3),(102,4), + (103,1),(103,2),(103,3),(103,4), + (104,1),(104,2),(104,3),(104,4), + (105,1),(105,2),(105,3),(105,4), + (106,1),(106,2),(106,3),(106,4), + (107,1),(107,2),(107,3),(107,4), + (108,1),(108,2),(108,3),(108,4), + (109,1),(109,2),(109,3),(109,4), + (110,1),(110,2),(110,3),(110,4), + (111,1),(111,2),(111,3),(111,4), + (112,1),(112,2),(112,3),(112,4), + (113,1),(113,2),(113,3),(113,4), + (114,1),(114,2),(114,3),(114,4), + (115,1),(115,2),(115,3),(115,4), + (116,1),(116,2),(116,3),(116,4), + (117,1),(117,2),(117,3),(117,4), + (118,1),(118,2),(118,3),(118,4), + (119,1),(119,2),(119,3),(119,4), + (120,1),(120,2),(120,3),(120,4), + (121,1),(121,2),(121,3),(121,4), + (122,1),(122,2),(122,3),(122,4), + (123,1),(123,2),(123,3),(123,4), + (124,1),(124,2),(124,3),(124,4), + (125,1),(125,2),(125,3),(125,4), + (126,1),(126,2),(126,3),(126,4), + (127,1),(127,2),(127,3),(127,4), + (128,1),(128,2),(128,3),(128,4), + (129,1),(129,2),(129,3),(129,4), + (130,1),(130,2),(130,3),(130,4), + (131,1),(131,2),(131,3),(131,4), + (132,1),(132,2),(132,3),(132,4), + (133,1),(133,2),(133,3),(133,4), + (134,1),(134,2),(134,3),(134,4), + (135,1),(135,2),(135,3),(135,4), + (136,1),(136,2),(136,3),(136,4), + (137,1),(137,2),(137,3),(137,4), + (138,1),(138,2),(138,3),(138,4), + (139,1),(139,2),(139,3),(139,4), + (140,1),(140,2),(140,3),(140,4), + (141,1),(141,2),(141,3),(141,4), + (142,1),(142,2),(142,3),(142,4), + (143,1),(143,2),(143,3),(143,4), + (144,1),(144,2),(144,3),(144,4), + (145,1),(145,2),(145,3),(145,4), + (146,1),(146,2),(146,3),(146,4), + (147,1),(147,2),(147,3),(147,4), + (148,1),(148,2),(148,3),(148,4), + (149,1),(149,2),(149,3),(149,4), + (150,1),(150,2),(150,3),(150,4), + (151,1),(151,2),(151,3),(151,4), + (152,1),(152,2),(152,3),(152,4), + (153,1),(153,2),(153,3),(153,4), + (154,1),(154,2),(154,3),(154,4), + (155,1),(155,2),(155,3),(155,4), + (156,1),(156,2),(156,3),(156,4), + (157,1),(157,2),(157,3),(157,4), + (158,1),(158,2),(158,3),(158,4), + (159,1),(159,2),(159,3),(159,4), + (160,1),(160,2),(160,3),(160,4), + (161,1),(161,2),(161,3),(161,4), + (162,1),(162,2),(162,3),(162,4), + (163,1),(163,2),(163,3),(163,4), + (164,1),(164,2),(164,3),(164,4), + (165,1),(165,2),(165,3),(165,4), + (166,1),(166,2),(166,3),(166,4), + (167,1),(167,2),(167,3),(167,4), + (168,1),(168,2),(168,3),(168,4), + (169,1),(169,2),(169,3),(169,4), + (170,1),(170,2),(170,3),(170,4), + (171,1),(171,2),(171,3),(171,4), + (172,1),(172,2),(172,3),(172,4), + (173,1),(173,2),(173,3),(173,4), + (174,1),(174,2),(174,3),(174,4), + (175,1),(175,2),(175,3),(175,4), + (176,1),(176,2),(176,3),(176,4), + (177,1),(177,2),(177,3),(177,4), + (178,1),(178,2),(178,3),(178,4), + (179,1),(179,2),(179,3),(179,4), + (180,1),(180,2),(180,3),(180,4), + (181,1),(181,2),(181,3),(181,4), + (182,1),(182,2),(182,3),(182,4), + (183,1),(183,2),(183,3),(183,4), + (184,1),(184,2),(184,3),(184,4), + (185,1),(185,2),(185,3),(185,4), + (186,1),(186,2),(186,3),(186,4), + (187,1),(187,2),(187,3),(187,4), + (188,1),(188,2),(188,3),(188,4), + (189,1),(189,2),(189,3),(189,4), + (190,1),(190,2),(190,3),(190,4), + (191,1),(191,2),(191,3),(191,4), + (192,1),(192,2),(192,3),(192,4), + (193,1),(193,2),(193,3),(193,4), + (194,1),(194,2),(194,3),(194,4), + (195,1),(195,2),(195,3),(195,4), + (196,1),(196,2),(196,3),(196,4), + (197,1),(197,2),(197,3),(197,4), + (198,1),(198,2),(198,3),(198,4), + (199,1),(199,2),(199,3),(199,4), + (200,1),(200,2),(200,3),(200,4), + (201,1),(201,2),(201,3),(201,4), + (202,1),(202,2),(202,3),(202,4), + (203,1),(203,2),(203,3),(203,4), + (204,1),(204,2),(204,3),(204,4), + (205,1),(205,2),(205,3),(205,4), + (206,1),(206,2),(206,3),(206,4), + (207,1),(207,2),(207,3),(207,4), + (208,1),(208,2),(208,3),(208,4), + (209,1),(209,2),(209,3),(209,4), + (210,1),(210,2),(210,3),(210,4), + (211,1),(211,2),(211,3),(211,4), + (212,1),(212,2),(212,3),(212,4), + (213,1),(213,2),(213,3),(213,4), + (214,1),(214,2),(214,3),(214,4), + (215,1),(215,2),(215,3),(215,4), + (216,1),(216,2),(216,3),(216,4), + (217,1),(217,2),(217,3),(217,4), + (218,1),(218,2),(218,3),(218,4), + (219,1),(219,2),(219,3),(219,4), + (220,1),(220,2),(220,3),(220,4), + (221,1),(221,2),(221,3),(221,4), + (222,1),(222,2),(222,3),(222,4), + (223,1),(223,2),(223,3),(223,4), + (224,1),(224,2),(224,3),(224,4), + (225,1),(225,2),(225,3),(225,4), + (226,1),(226,2),(226,3),(226,4), + (227,1),(227,2),(227,3),(227,4), + (228,1),(228,2),(228,3),(228,4), + (229,1),(229,2),(229,3),(229,4), + (230,1),(230,2),(230,3),(230,4), + (231,1),(231,2),(231,3),(231,4), + (232,1),(232,2),(232,3),(232,4), + (233,1),(233,2),(233,3),(233,4), + (234,1),(234,2),(234,3),(234,4), + (235,1),(235,2),(235,3),(235,4), + (236,1),(236,2),(236,3),(236,4), + (237,1),(237,2),(237,3),(237,4), + (238,1),(238,2),(238,3),(238,4), + (239,1),(239,2),(239,3),(239,4), + (240,1),(240,2),(240,3),(240,4), + (241,1),(241,2),(241,3),(241,4), + (242,1),(242,2),(242,3),(242,4), + (243,1),(243,2),(243,3),(243,4), + (244,1),(244,2),(244,3),(244,4), + (245,1),(245,2),(245,3),(245,4), + (246,1),(246,2),(246,3),(246,4), + (247,1),(247,2),(247,3),(247,4), + (248,1),(248,2),(248,3),(248,4), + (249,1),(249,2),(249,3),(249,4), + (250,1),(250,2),(250,3),(250,4), + (251,1),(251,2),(251,3),(251,4), + (252,1),(252,2),(252,3),(252,4), + (253,1),(253,2),(253,3),(253,4), + (254,1),(254,2),(254,3),(254,4), + (255,1),(255,2),(255,3),(255,4), + (256,1),(256,2),(256,3),(256,4), + (257,1),(257,2),(257,3),(257,4), + (258,1),(258,2),(258,3),(258,4), + (259,1),(259,2),(259,3),(259,4), + (260,1),(260,2),(260,3),(260,4), + (261,1),(261,2),(261,3),(261,4), + (262,1),(262,2),(262,3),(262,4), + (263,1),(263,2),(263,3),(263,4), + (264,1),(264,2),(264,3),(264,4), + (265,1),(265,2),(265,3),(265,4), + (266,1),(266,2),(266,3),(266,4), + (267,1),(267,2),(267,3),(267,4), + (268,1),(268,2),(268,3),(268,4), + (269,1),(269,2),(269,3),(269,4), + (270,1),(270,2),(270,3),(270,4), + (271,1),(271,2),(271,3),(271,4), + (272,1),(272,2),(272,3),(272,4), + (273,1),(273,2),(273,3),(273,4), + (274,1),(274,2),(274,3),(274,4), + (275,1),(275,2),(275,3),(275,4), + (276,1),(276,2),(276,3),(276,4), + (277,1),(277,2),(277,3),(277,4), + (278,1),(278,2),(278,3),(278,4), + (279,1),(279,2),(279,3),(279,4), + (280,1),(280,2),(280,3),(280,4), + (281,1),(281,2),(281,3),(281,4), + (282,1),(282,2),(282,3),(282,4), + (283,1),(283,2),(283,3),(283,4), + (284,1),(284,2),(284,3),(284,4), + (285,1),(285,2),(285,3),(285,4), + (286,1),(286,2),(286,3),(286,4), + (287,1),(287,2),(287,3),(287,4), + (288,1),(288,2),(288,3),(288,4), + (289,1),(289,2),(289,3),(289,4), + (290,1),(290,2),(290,3),(290,4), + (291,1),(291,2),(291,3),(291,4), + (292,1),(292,2),(292,3),(292,4), + (293,1),(293,2),(293,3),(293,4), + (294,1),(294,2),(294,3),(294,4), + (295,1),(295,2),(295,3),(295,4), + (296,1),(296,2),(296,3),(296,4), + (297,1),(297,2),(297,3),(297,4), + (298,1),(298,2),(298,3),(298,4), + (299,1),(299,2),(299,3),(299,4), + (300,1),(300,2),(300,3),(300,4), + (301,1),(301,2),(301,3),(301,4), + (302,1),(302,2),(302,3),(302,4), + (303,1),(303,2),(303,3),(303,4), + (304,1),(304,2),(304,3),(304,4), + (305,1),(305,2),(305,3),(305,4), + (306,1),(306,2),(306,3),(306,4), + (307,1),(307,2),(307,3),(307,4), + (308,1),(308,2),(308,3),(308,4), + (309,1),(309,2),(309,3),(309,4), + (310,1),(310,2),(310,3),(310,4), + (311,1),(311,2),(311,3),(311,4), + (312,1),(312,2),(312,3),(312,4), + (313,1),(313,2),(313,3),(313,4), + (314,1),(314,2),(314,3),(314,4), + (315,1),(315,2),(315,3),(315,4), + (316,1),(316,2),(316,3),(316,4), + (317,1),(317,2),(317,3),(317,4), + (318,1),(318,2),(318,3),(318,4), + (319,1),(319,2),(319,3),(319,4), + (320,1),(320,2),(320,3),(320,4), + (321,1),(321,2),(321,3),(321,4), + (322,1),(322,2),(322,3),(322,4), + (323,1),(323,2),(323,3),(323,4), + (324,1),(324,2),(324,3),(324,4), + (325,1),(325,2),(325,3),(325,4), + (326,1),(326,2),(326,3),(326,4), + (327,1),(327,2),(327,3),(327,4), + (328,1),(328,2),(328,3),(328,4), + (329,1),(329,2),(329,3),(329,4), + (330,1),(330,2),(330,3),(330,4), + (331,1),(331,2),(331,3),(331,4), + (332,1),(332,2),(332,3),(332,4), + (333,1),(333,2),(333,3),(333,4), + (334,1),(334,2),(334,3),(334,4), + (335,1),(335,2),(335,3),(335,4), + (336,1),(336,2),(336,3),(336,4), + (337,1),(337,2),(337,3),(337,4), + (338,1),(338,2),(338,3),(338,4), + (339,1),(339,2),(339,3),(339,4), + (340,1),(340,2),(340,3),(340,4), + (341,1),(341,2),(341,3),(341,4), + (342,1),(342,2),(342,3),(342,4), + (343,1),(343,2),(343,3),(343,4), + (344,1),(344,2),(344,3),(344,4), + (345,1),(345,2),(345,3),(345,4), + (346,1),(346,2),(346,3),(346,4), + (347,1),(347,2),(347,3),(347,4), + (348,1),(348,2),(348,3),(348,4), + (349,1),(349,2),(349,3),(349,4), + (350,1),(350,2),(350,3),(350,4), + (351,1),(351,2),(351,3),(351,4), + (352,1),(352,2),(352,3),(352,4), + (353,1),(353,2),(353,3),(353,4), + (354,1),(354,2),(354,3),(354,4), + (355,1),(355,2),(355,3),(355,4), + (356,1),(356,2),(356,3),(356,4), + (357,1),(357,2),(357,3),(357,4), + (358,1),(358,2),(358,3),(358,4), + (359,1),(359,2),(359,3),(359,4), + (360,1),(360,2),(360,3),(360,4), + (361,1),(361,2),(361,3),(361,4), + (362,1),(362,2),(362,3),(362,4), + (363,1),(363,2),(363,3),(363,4), + (364,1),(364,2),(364,3),(364,4), + (365,1),(365,2),(365,3),(365,4), + (366,1),(366,2),(366,3),(366,4), + (367,1),(367,2),(367,3),(367,4), + (368,1),(368,2),(368,3),(368,4), + (369,1),(369,2),(369,3),(369,4), + (370,1),(370,2),(370,3),(370,4), + (371,1),(371,2),(371,3),(371,4), + (372,1),(372,2),(372,3),(372,4), + (373,1),(373,2),(373,3),(373,4), + (374,1),(374,2),(374,3),(374,4), + (375,1),(375,2),(375,3),(375,4), + (376,1),(376,2),(376,3),(376,4), + (377,1),(377,2),(377,3),(377,4), + (378,1),(378,2),(378,3),(378,4), + (379,1),(379,2),(379,3),(379,4), + (380,1),(380,2),(380,3),(380,4), + (381,1),(381,2),(381,3),(381,4), + (382,1),(382,2),(382,3),(382,4), + (383,1),(383,2),(383,3),(383,4), + (384,1),(384,2),(384,3),(384,4), + (385,1),(385,2),(385,3),(385,4), + (386,1),(386,2),(386,3),(386,4), + (387,1),(387,2),(387,3),(387,4), + (388,1),(388,2),(388,3),(388,4), + (389,1),(389,2),(389,3),(389,4), + (390,1),(390,2),(390,3),(390,4), + (391,1),(391,2),(391,3),(391,4), + (392,1),(392,2),(392,3),(392,4), + (393,1),(393,2),(393,3),(393,4), + (394,1),(394,2),(394,3),(394,4), + (395,1),(395,2),(395,3),(395,4), + (396,1),(396,2),(396,3),(396,4), + (397,1),(397,2),(397,3),(397,4), + (398,1),(398,2),(398,3),(398,4), + (399,1),(399,2),(399,3),(399,4), + (400,1),(400,2),(400,3),(400,4), + (401,1),(401,2),(401,3),(401,4), + (402,1),(402,2),(402,3),(402,4), + (403,1),(403,2),(403,3),(403,4), + (404,1),(404,2),(404,3),(404,4), + (405,1),(405,2),(405,3),(405,4), + (406,1),(406,2),(406,3),(406,4), + (407,1),(407,2),(407,3),(407,4), + (408,1),(408,2),(408,3),(408,4), + (409,1),(409,2),(409,3),(409,4), + (410,1),(410,2),(410,3),(410,4), + (411,1),(411,2),(411,3),(411,4), + (412,1),(412,2),(412,3),(412,4), + (413,1),(413,2),(413,3),(413,4), + (414,1),(414,2),(414,3),(414,4), + (415,1),(415,2),(415,3),(415,4), + (416,1),(416,2),(416,3),(416,4), + (417,1),(417,2),(417,3),(417,4), + (418,1),(418,2),(418,3),(418,4), + (419,1),(419,2),(419,3),(419,4), + (420,1),(420,2),(420,3),(420,4), + (421,1),(421,2),(421,3),(421,4), + (422,1),(422,2),(422,3),(422,4), + (423,1),(423,2),(423,3),(423,4), + (424,1),(424,2),(424,3),(424,4), + (425,1),(425,2),(425,3),(425,4), + (426,1),(426,2),(426,3),(426,4), + (427,1),(427,2),(427,3),(427,4), + (428,1),(428,2),(428,3),(428,4), + (429,1),(429,2),(429,3),(429,4), + (430,1),(430,2),(430,3),(430,4), + (431,1),(431,2),(431,3),(431,4), + (432,1),(432,2),(432,3),(432,4), + (433,1),(433,2),(433,3),(433,4), + (434,1),(434,2),(434,3),(434,4), + (435,1),(435,2),(435,3),(435,4), + (436,1),(436,2),(436,3),(436,4), + (437,1),(437,2),(437,3),(437,4), + (438,1),(438,2),(438,3),(438,4), + (439,1),(439,2),(439,3),(439,4), + (440,1),(440,2),(440,3),(440,4), + (441,1),(441,2),(441,3),(441,4), + (442,1),(442,2),(442,3),(442,4), + (443,1),(443,2),(443,3),(443,4), + (444,1),(444,2),(444,3),(444,4), + (445,1),(445,2),(445,3),(445,4), + (446,1),(446,2),(446,3),(446,4), + (447,1),(447,2),(447,3),(447,4), + (448,1),(448,2),(448,3),(448,4), + (449,1),(449,2),(449,3),(449,4), + (450,1),(450,2),(450,3),(450,4), + (451,1),(451,2),(451,3),(451,4), + (452,1),(452,2),(452,3),(452,4), + (453,1),(453,2),(453,3),(453,4), + (454,1),(454,2),(454,3),(454,4), + (455,1),(455,2),(455,3),(455,4), + (456,1),(456,2),(456,3),(456,4), + (457,1),(457,2),(457,3),(457,4), + (458,1),(458,2),(458,3),(458,4), + (459,1),(459,2),(459,3),(459,4), + (460,1),(460,2),(460,3),(460,4), + (461,1),(461,2),(461,3),(461,4), + (462,1),(462,2),(462,3),(462,4), + (463,1),(463,2),(463,3),(463,4), + (464,1),(464,2),(464,3),(464,4), + (465,1),(465,2),(465,3),(465,4), + (466,1),(466,2),(466,3),(466,4), + (467,1),(467,2),(467,3),(467,4), + (468,1),(468,2),(468,3),(468,4), + (469,1),(469,2),(469,3),(469,4), + (470,1),(470,2),(470,3),(470,4), + (471,1),(471,2),(471,3),(471,4), + (472,1),(472,2),(472,3),(472,4), + (473,1),(473,2),(473,3),(473,4), + (474,1),(474,2),(474,3),(474,4), + (475,1),(475,2),(475,3),(475,4), + (476,1),(476,2),(476,3),(476,4), + (477,1),(477,2),(477,3),(477,4), + (478,1),(478,2),(478,3),(478,4), + (479,1),(479,2),(479,3),(479,4), + (480,1),(480,2),(480,3),(480,4), + (481,1),(481,2),(481,3),(481,4), + (482,1),(482,2),(482,3),(482,4), + (483,1),(483,2),(483,3),(483,4), + (484,1),(484,2),(484,3),(484,4), + (485,1),(485,2),(485,3),(485,4), + (486,1),(486,2),(486,3),(486,4), + (487,1),(487,2),(487,3),(487,4), + (488,1),(488,2),(488,3),(488,4), + (489,1),(489,2),(489,3),(489,4), + (490,1),(490,2),(490,3),(490,4), + (491,1),(491,2),(491,3),(491,4), + (492,1),(492,2),(492,3),(492,4), + (493,1),(493,2),(493,3),(493,4), + (494,1),(494,2),(494,3),(494,4), + (495,1),(495,2),(495,3),(495,4), + (496,1),(496,2),(496,3),(496,4), + (497,1),(497,2),(497,3),(497,4), + (498,1),(498,2),(498,3),(498,4), + (499,1),(499,2),(499,3),(499,4), + (500,1),(500,2),(500,3),(500,4), + (501,1),(501,2),(501,3),(501,4), + (502,1),(502,2),(502,3),(502,4), + (503,1),(503,2),(503,3),(503,4), + (504,1),(504,2),(504,3),(504,4), + (505,1),(505,2),(505,3),(505,4), + (506,1),(506,2),(506,3),(506,4), + (507,1),(507,2),(507,3),(507,4), + (508,1),(508,2),(508,3),(508,4), + (509,1),(509,2),(509,3),(509,4), + (510,1),(510,2),(510,3),(510,4), + (511,1),(511,2),(511,3),(511,4), + (512,1),(512,2),(512,3),(512,4), + (513,1),(513,2),(513,3),(513,4), + (514,1),(514,2),(514,3),(514,4), + (515,1),(515,2),(515,3),(515,4), + (516,1),(516,2),(516,3),(516,4), + (517,1),(517,2),(517,3),(517,4), + (518,1),(518,2),(518,3),(518,4), + (519,1),(519,2),(519,3),(519,4), + (520,1),(520,2),(520,3),(520,4), + (521,1),(521,2),(521,3),(521,4), + (522,1),(522,2),(522,3),(522,4), + (523,1),(523,2),(523,3),(523,4), + (524,1),(524,2),(524,3),(524,4), + (525,1),(525,2),(525,3),(525,4), + (526,1),(526,2),(526,3),(526,4), + (527,1),(527,2),(527,3),(527,4), + (528,1),(528,2),(528,3),(528,4), + (529,1),(529,2),(529,3),(529,4), + (530,1),(530,2),(530,3),(530,4), + (531,1),(531,2),(531,3),(531,4), + (532,1),(532,2),(532,3),(532,4), + (533,1),(533,2),(533,3),(533,4), + (534,1),(534,2),(534,3),(534,4), + (535,1),(535,2),(535,3),(535,4), + (536,1),(536,2),(536,3),(536,4), + (537,1),(537,2),(537,3),(537,4), + (538,1),(538,2),(538,3),(538,4), + (539,1),(539,2),(539,3),(539,4), + (540,1),(540,2),(540,3),(540,4), + (541,1),(541,2),(541,3),(541,4), + (542,1),(542,2),(542,3),(542,4), + (543,1),(543,2),(543,3),(543,4), + (544,1),(544,2),(544,3),(544,4), + (545,1),(545,2),(545,3),(545,4), + (546,1),(546,2),(546,3),(546,4), + (547,1),(547,2),(547,3),(547,4), + (548,1),(548,2),(548,3),(548,4), + (549,1),(549,2),(549,3),(549,4), + (550,1),(550,2),(550,3),(550,4), + (551,1),(551,2),(551,3),(551,4), + (552,1),(552,2),(552,3),(552,4), + (553,1),(553,2),(553,3),(553,4), + (554,1),(554,2),(554,3),(554,4), + (555,1),(555,2),(555,3),(555,4), + (556,1),(556,2),(556,3),(556,4), + (557,1),(557,2),(557,3),(557,4), + (558,1),(558,2),(558,3),(558,4), + (559,1),(559,2),(559,3),(559,4), + (560,1),(560,2),(560,3),(560,4), + (561,1),(561,2),(561,3),(561,4), + (562,1),(562,2),(562,3),(562,4), + (563,1),(563,2),(563,3),(563,4), + (564,1),(564,2),(564,3),(564,4), + (565,1),(565,2),(565,3),(565,4), + (566,1),(566,2),(566,3),(566,4), + (567,1),(567,2),(567,3),(567,4), + (568,1),(568,2),(568,3),(568,4), + (569,1),(569,2),(569,3),(569,4), + (570,1),(570,2),(570,3),(570,4), + (571,1),(571,2),(571,3),(571,4), + (572,1),(572,2),(572,3),(572,4), + (573,1),(573,2),(573,3),(573,4), + (574,1),(574,2),(574,3),(574,4), + (575,1),(575,2),(575,3),(575,4), + (576,1),(576,2),(576,3),(576,4), + (577,1),(577,2),(577,3),(577,4), + (578,1),(578,2),(578,3),(578,4), + (579,1),(579,2),(579,3),(579,4), + (580,1),(580,2),(580,3),(580,4), + (581,1),(581,2),(581,3),(581,4), + (582,1),(582,2),(582,3),(582,4), + (583,1),(583,2),(583,3),(583,4), + (584,1),(584,2),(584,3),(584,4), + (585,1),(585,2),(585,3),(585,4), + (586,1),(586,2),(586,3),(586,4), + (587,1),(587,2),(587,3),(587,4), + (588,1),(588,2),(588,3),(588,4), + (589,1),(589,2),(589,3),(589,4), + (590,1),(590,2),(590,3),(590,4), + (591,1),(591,2),(591,3),(591,4), + (592,1),(592,2),(592,3),(592,4), + (593,1),(593,2),(593,3),(593,4), + (594,1),(594,2),(594,3),(594,4), + (595,1),(595,2),(595,3),(595,4), + (596,1),(596,2),(596,3),(596,4), + (597,1),(597,2),(597,3),(597,4), + (598,1),(598,2),(598,3),(598,4), + (599,1),(599,2),(599,3),(599,4), + (600,1),(600,2),(600,3),(600,4), + (601,1),(601,2),(601,3),(601,4), + (602,1),(602,2),(602,3),(602,4), + (603,1),(603,2),(603,3),(603,4), + (604,1),(604,2),(604,3),(604,4), + (605,1),(605,2),(605,3),(605,4), + (606,1),(606,2),(606,3),(606,4), + (607,1),(607,2),(607,3),(607,4), + (608,1),(608,2),(608,3),(608,4), + (609,1),(609,2),(609,3),(609,4), + (610,1),(610,2),(610,3),(610,4), + (611,1),(611,2),(611,3),(611,4), + (612,1),(612,2),(612,3),(612,4), + (613,1),(613,2),(613,3),(613,4), + (614,1),(614,2),(614,3),(614,4), + (615,1),(615,2),(615,3),(615,4), + (616,1),(616,2),(616,3),(616,4), + (617,1),(617,2),(617,3),(617,4), + (618,1),(618,2),(618,3),(618,4), + (619,1),(619,2),(619,3),(619,4), + (620,1),(620,2),(620,3),(620,4), + (621,1),(621,2),(621,3),(621,4), + (622,1),(622,2),(622,3),(622,4), + (623,1),(623,2),(623,3),(623,4), + (624,1),(624,2),(624,3),(624,4), + (625,1),(625,2),(625,3),(625,4), + (626,1),(626,2),(626,3),(626,4), + (627,1),(627,2),(627,3),(627,4), + (628,1),(628,2),(628,3),(628,4), + (629,1),(629,2),(629,3),(629,4), + (630,1),(630,2),(630,3),(630,4), + (631,1),(631,2),(631,3),(631,4), + (632,1),(632,2),(632,3),(632,4), + (633,1),(633,2),(633,3),(633,4), + (634,1),(634,2),(634,3),(634,4), + (635,1),(635,2),(635,3),(635,4), + (636,1),(636,2),(636,3),(636,4), + (637,1),(637,2),(637,3),(637,4), + (638,1),(638,2),(638,3),(638,4), + (639,1),(639,2),(639,3),(639,4), + (640,1),(640,2),(640,3),(640,4), + (641,1),(641,2),(641,3),(641,4), + (642,1),(642,2),(642,3),(642,4), + (643,1),(643,2),(643,3),(643,4), + (644,1),(644,2),(644,3),(644,4), + (645,1),(645,2),(645,3),(645,4), + (646,1),(646,2),(646,3),(646,4), + (647,1),(647,2),(647,3),(647,4), + (648,1),(648,2),(648,3),(648,4), + (649,1),(649,2),(649,3),(649,4), + (650,1),(650,2),(650,3),(650,4), + (651,1),(651,2),(651,3),(651,4), + (652,1),(652,2),(652,3),(652,4), + (653,1),(653,2),(653,3),(653,4), + (654,1),(654,2),(654,3),(654,4), + (655,1),(655,2),(655,3),(655,4), + (656,1),(656,2),(656,3),(656,4), + (657,1),(657,2),(657,3),(657,4), + (658,1),(658,2),(658,3),(658,4), + (659,1),(659,2),(659,3),(659,4), + (660,1),(660,2),(660,3),(660,4), + (661,1),(661,2),(661,3),(661,4), + (662,1),(662,2),(662,3),(662,4), + (663,1),(663,2),(663,3),(663,4), + (664,1),(664,2),(664,3),(664,4), + (665,1),(665,2),(665,3),(665,4), + (666,1),(666,2),(666,3),(666,4), + (667,1),(667,2),(667,3),(667,4), + (668,1),(668,2),(668,3),(668,4), + (669,1),(669,2),(669,3),(669,4), + (670,1),(670,2),(670,3),(670,4), + (671,1),(671,2),(671,3),(671,4), + (672,1),(672,2),(672,3),(672,4), + (673,1),(673,2),(673,3),(673,4), + (674,1),(674,2),(674,3),(674,4), + (675,1),(675,2),(675,3),(675,4), + (676,1),(676,2),(676,3),(676,4), + (677,1),(677,2),(677,3),(677,4), + (678,1),(678,2),(678,3),(678,4), + (679,1),(679,2),(679,3),(679,4), + (680,1),(680,2),(680,3),(680,4), + (681,1),(681,2),(681,3),(681,4), + (682,1),(682,2),(682,3),(682,4), + (683,1),(683,2),(683,3),(683,4), + (684,1),(684,2),(684,3),(684,4), + (685,1),(685,2),(685,3),(685,4), + (686,1),(686,2),(686,3),(686,4), + (687,1),(687,2),(687,3),(687,4), + (688,1),(688,2),(688,3),(688,4), + (689,1),(689,2),(689,3),(689,4), + (690,1),(690,2),(690,3),(690,4), + (691,1),(691,2),(691,3),(691,4), + (692,1),(692,2),(692,3),(692,4), + (693,1),(693,2),(693,3),(693,4), + (694,1),(694,2),(694,3),(694,4), + (695,1),(695,2),(695,3),(695,4), + (696,1),(696,2),(696,3),(696,4), + (697,1),(697,2),(697,3),(697,4), + (698,1),(698,2),(698,3),(698,4), + (699,1),(699,2),(699,3),(699,4), + (700,1),(700,2),(700,3),(700,4), + (701,1),(701,2),(701,3),(701,4), + (702,1),(702,2),(702,3),(702,4), + (703,1),(703,2),(703,3),(703,4), + (704,1),(704,2),(704,3),(704,4), + (705,1),(705,2),(705,3),(705,4), + (706,1),(706,2),(706,3),(706,4), + (707,1),(707,2),(707,3),(707,4), + (708,1),(708,2),(708,3),(708,4), + (709,1),(709,2),(709,3),(709,4), + (710,1),(710,2),(710,3),(710,4), + (711,1),(711,2),(711,3),(711,4), + (712,1),(712,2),(712,3),(712,4), + (713,1),(713,2),(713,3),(713,4), + (714,1),(714,2),(714,3),(714,4), + (715,1),(715,2),(715,3),(715,4), + (716,1),(716,2),(716,3),(716,4), + (717,1),(717,2),(717,3),(717,4), + (718,1),(718,2),(718,3),(718,4), + (719,1),(719,2),(719,3),(719,4), + (720,1),(720,2),(720,3),(720,4), + (721,1),(721,2),(721,3),(721,4), + (722,1),(722,2),(722,3),(722,4), + (723,1),(723,2),(723,3),(723,4), + (724,1),(724,2),(724,3),(724,4), + (725,1),(725,2),(725,3),(725,4), + (726,1),(726,2),(726,3),(726,4), + (727,1),(727,2),(727,3),(727,4), + (728,1),(728,2),(728,3),(728,4), + (729,1),(729,2),(729,3),(729,4), + (730,1),(730,2),(730,3),(730,4), + (731,1),(731,2),(731,3),(731,4), + (732,1),(732,2),(732,3),(732,4), + (733,1),(733,2),(733,3),(733,4), + (734,1),(734,2),(734,3),(734,4), + (735,1),(735,2),(735,3),(735,4), + (736,1),(736,2),(736,3),(736,4), + (737,1),(737,2),(737,3),(737,4), + (738,1),(738,2),(738,3),(738,4), + (739,1),(739,2),(739,3),(739,4), + (740,1),(740,2),(740,3),(740,4), + (741,1),(741,2),(741,3),(741,4), + (742,1),(742,2),(742,3),(742,4), + (743,1),(743,2),(743,3),(743,4), + (744,1),(744,2),(744,3),(744,4), + (745,1),(745,2),(745,3),(745,4), + (746,1),(746,2),(746,3),(746,4), + (747,1),(747,2),(747,3),(747,4), + (748,1),(748,2),(748,3),(748,4), + (749,1),(749,2),(749,3),(749,4), + (750,1),(750,2),(750,3),(750,4), + (751,1),(751,2),(751,3),(751,4), + (752,1),(752,2),(752,3),(752,4), + (753,1),(753,2),(753,3),(753,4), + (754,1),(754,2),(754,3),(754,4), + (755,1),(755,2),(755,3),(755,4), + (756,1),(756,2),(756,3),(756,4), + (757,1),(757,2),(757,3),(757,4), + (758,1),(758,2),(758,3),(758,4), + (759,1),(759,2),(759,3),(759,4), + (760,1),(760,2),(760,3),(760,4), + (761,1),(761,2),(761,3),(761,4), + (762,1),(762,2),(762,3),(762,4), + (763,1),(763,2),(763,3),(763,4), + (764,1),(764,2),(764,3),(764,4), + (765,1),(765,2),(765,3),(765,4), + (766,1),(766,2),(766,3),(766,4), + (767,1),(767,2),(767,3),(767,4), + (768,1),(768,2),(768,3),(768,4), + (769,1),(769,2),(769,3),(769,4), + (770,1),(770,2),(770,3),(770,4), + (771,1),(771,2),(771,3),(771,4), + (772,1),(772,2),(772,3),(772,4), + (773,1),(773,2),(773,3),(773,4), + (774,1),(774,2),(774,3),(774,4), + (775,1),(775,2),(775,3),(775,4), + (776,1),(776,2),(776,3),(776,4), + (777,1),(777,2),(777,3),(777,4), + (778,1),(778,2),(778,3),(778,4), + (779,1),(779,2),(779,3),(779,4), + (780,1),(780,2),(780,3),(780,4), + (781,1),(781,2),(781,3),(781,4), + (782,1),(782,2),(782,3),(782,4), + (783,1),(783,2),(783,3),(783,4), + (784,1),(784,2),(784,3),(784,4), + (785,1),(785,2),(785,3),(785,4), + (786,1),(786,2),(786,3),(786,4), + (787,1),(787,2),(787,3),(787,4), + (788,1),(788,2),(788,3),(788,4), + (789,1),(789,2),(789,3),(789,4), + (790,1),(790,2),(790,3),(790,4), + (791,1),(791,2),(791,3),(791,4), + (792,1),(792,2),(792,3),(792,4), + (793,1),(793,2),(793,3),(793,4), + (794,1),(794,2),(794,3),(794,4), + (795,1),(795,2),(795,3),(795,4), + (796,1),(796,2),(796,3),(796,4), + (797,1),(797,2),(797,3),(797,4), + (798,1),(798,2),(798,3),(798,4), + (799,1),(799,2),(799,3),(799,4), + (800,1),(800,2),(800,3),(800,4), + (801,1),(801,2),(801,3),(801,4), + (802,1),(802,2),(802,3),(802,4), + (803,1),(803,2),(803,3),(803,4), + (804,1),(804,2),(804,3),(804,4), + (805,1),(805,2),(805,3),(805,4), + (806,1),(806,2),(806,3),(806,4), + (807,1),(807,2),(807,3),(807,4), + (808,1),(808,2),(808,3),(808,4), + (809,1),(809,2),(809,3),(809,4), + (810,1),(810,2),(810,3),(810,4), + (811,1),(811,2),(811,3),(811,4), + (812,1),(812,2),(812,3),(812,4), + (813,1),(813,2),(813,3),(813,4), + (814,1),(814,2),(814,3),(814,4), + (815,1),(815,2),(815,3),(815,4), + (816,1),(816,2),(816,3),(816,4), + (817,1),(817,2),(817,3),(817,4), + (818,1),(818,2),(818,3),(818,4), + (819,1),(819,2),(819,3),(819,4), + (820,1),(820,2),(820,3),(820,4), + (821,1),(821,2),(821,3),(821,4), + (822,1),(822,2),(822,3),(822,4), + (823,1),(823,2),(823,3),(823,4), + (824,1),(824,2),(824,3),(824,4), + (825,1),(825,2),(825,3),(825,4), + (826,1),(826,2),(826,3),(826,4), + (827,1),(827,2),(827,3),(827,4), + (828,1),(828,2),(828,3),(828,4), + (829,1),(829,2),(829,3),(829,4), + (830,1),(830,2),(830,3),(830,4), + (831,1),(831,2),(831,3),(831,4), + (832,1),(832,2),(832,3),(832,4), + (833,1),(833,2),(833,3),(833,4), + (834,1),(834,2),(834,3),(834,4), + (835,1),(835,2),(835,3),(835,4), + (836,1),(836,2),(836,3),(836,4), + (837,1),(837,2),(837,3),(837,4), + (838,1),(838,2),(838,3),(838,4), + (839,1),(839,2),(839,3),(839,4), + (840,1),(840,2),(840,3),(840,4), + (841,1),(841,2),(841,3),(841,4), + (842,1),(842,2),(842,3),(842,4), + (843,1),(843,2),(843,3),(843,4), + (844,1),(844,2),(844,3),(844,4), + (845,1),(845,2),(845,3),(845,4), + (846,1),(846,2),(846,3),(846,4), + (847,1),(847,2),(847,3),(847,4), + (848,1),(848,2),(848,3),(848,4), + (849,1),(849,2),(849,3),(849,4), + (850,1),(850,2),(850,3),(850,4), + (851,1),(851,2),(851,3),(851,4), + (852,1),(852,2),(852,3),(852,4), + (853,1),(853,2),(853,3),(853,4), + (854,1),(854,2),(854,3),(854,4), + (855,1),(855,2),(855,3),(855,4), + (856,1),(856,2),(856,3),(856,4), + (857,1),(857,2),(857,3),(857,4), + (858,1),(858,2),(858,3),(858,4), + (859,1),(859,2),(859,3),(859,4), + (860,1),(860,2),(860,3),(860,4), + (861,1),(861,2),(861,3),(861,4), + (862,1),(862,2),(862,3),(862,4), + (863,1),(863,2),(863,3),(863,4), + (864,1),(864,2),(864,3),(864,4), + (865,1),(865,2),(865,3),(865,4), + (866,1),(866,2),(866,3),(866,4), + (867,1),(867,2),(867,3),(867,4), + (868,1),(868,2),(868,3),(868,4), + (869,1),(869,2),(869,3),(869,4), + (870,1),(870,2),(870,3),(870,4), + (871,1),(871,2),(871,3),(871,4), + (872,1),(872,2),(872,3),(872,4), + (873,1),(873,2),(873,3),(873,4), + (874,1),(874,2),(874,3),(874,4), + (875,1),(875,2),(875,3),(875,4), + (876,1),(876,2),(876,3),(876,4), + (877,1),(877,2),(877,3),(877,4), + (878,1),(878,2),(878,3),(878,4), + (879,1),(879,2),(879,3),(879,4), + (880,1),(880,2),(880,3),(880,4), + (881,1),(881,2),(881,3),(881,4), + (882,1),(882,2),(882,3),(882,4), + (883,1),(883,2),(883,3),(883,4), + (884,1),(884,2),(884,3),(884,4), + (885,1),(885,2),(885,3),(885,4), + (886,1),(886,2),(886,3),(886,4), + (887,1),(887,2),(887,3),(887,4), + (888,1),(888,2),(888,3),(888,4), + (889,1),(889,2),(889,3),(889,4), + (890,1),(890,2),(890,3),(890,4), + (891,1),(891,2),(891,3),(891,4), + (892,1),(892,2),(892,3),(892,4), + (893,1),(893,2),(893,3),(893,4), + (894,1),(894,2),(894,3),(894,4), + (895,1),(895,2),(895,3),(895,4), + (896,1),(896,2),(896,3),(896,4), + (897,1),(897,2),(897,3),(897,4), + (898,1),(898,2),(898,3),(898,4), + (899,1),(899,2),(899,3),(899,4), + (900,1),(900,2),(900,3),(900,4), + (901,1),(901,2),(901,3),(901,4), + (902,1),(902,2),(902,3),(902,4), + (903,1),(903,2),(903,3),(903,4), + (904,1),(904,2),(904,3),(904,4), + (905,1),(905,2),(905,3),(905,4), + (906,1),(906,2),(906,3),(906,4), + (907,1),(907,2),(907,3),(907,4), + (908,1),(908,2),(908,3),(908,4), + (909,1),(909,2),(909,3),(909,4), + (910,1),(910,2),(910,3),(910,4), + (911,1),(911,2),(911,3),(911,4), + (912,1),(912,2),(912,3),(912,4), + (913,1),(913,2),(913,3),(913,4), + (914,1),(914,2),(914,3),(914,4), + (915,1),(915,2),(915,3),(915,4), + (916,1),(916,2),(916,3),(916,4), + (917,1),(917,2),(917,3),(917,4), + (918,1),(918,2),(918,3),(918,4), + (919,1),(919,2),(919,3),(919,4), + (920,1),(920,2),(920,3),(920,4), + (921,1),(921,2),(921,3),(921,4), + (922,1),(922,2),(922,3),(922,4), + (923,1),(923,2),(923,3),(923,4), + (924,1),(924,2),(924,3),(924,4), + (925,1),(925,2),(925,3),(925,4), + (926,1),(926,2),(926,3),(926,4), + (927,1),(927,2),(927,3),(927,4), + (928,1),(928,2),(928,3),(928,4), + (929,1),(929,2),(929,3),(929,4), + (930,1),(930,2),(930,3),(930,4), + (931,1),(931,2),(931,3),(931,4), + (932,1),(932,2),(932,3),(932,4), + (933,1),(933,2),(933,3),(933,4), + (934,1),(934,2),(934,3),(934,4), + (935,1),(935,2),(935,3),(935,4), + (936,1),(936,2),(936,3),(936,4), + (937,1),(937,2),(937,3),(937,4), + (938,1),(938,2),(938,3),(938,4), + (939,1),(939,2),(939,3),(939,4), + (940,1),(940,2),(940,3),(940,4), + (941,1),(941,2),(941,3),(941,4), + (942,1),(942,2),(942,3),(942,4), + (943,1),(943,2),(943,3),(943,4), + (944,1),(944,2),(944,3),(944,4), + (945,1),(945,2),(945,3),(945,4), + (946,1),(946,2),(946,3),(946,4), + (947,1),(947,2),(947,3),(947,4), + (948,1),(948,2),(948,3),(948,4), + (949,1),(949,2),(949,3),(949,4), + (950,1),(950,2),(950,3),(950,4), + (951,1),(951,2),(951,3),(951,4), + (952,1),(952,2),(952,3),(952,4), + (953,1),(953,2),(953,3),(953,4), + (954,1),(954,2),(954,3),(954,4), + (955,1),(955,2),(955,3),(955,4), + (956,1),(956,2),(956,3),(956,4), + (957,1),(957,2),(957,3),(957,4), + (958,1),(958,2),(958,3),(958,4), + (959,1),(959,2),(959,3),(959,4), + (960,1),(960,2),(960,3),(960,4), + (961,1),(961,2),(961,3),(961,4), + (962,1),(962,2),(962,3),(962,4), + (963,1),(963,2),(963,3),(963,4), + (964,1),(964,2),(964,3),(964,4), + (965,1),(965,2),(965,3),(965,4), + (966,1),(966,2),(966,3),(966,4), + (967,1),(967,2),(967,3),(967,4), + (968,1),(968,2),(968,3),(968,4), + (969,1),(969,2),(969,3),(969,4), + (970,1),(970,2),(970,3),(970,4), + (971,1),(971,2),(971,3),(971,4), + (972,1),(972,2),(972,3),(972,4), + (973,1),(973,2),(973,3),(973,4), + (974,1),(974,2),(974,3),(974,4), + (975,1),(975,2),(975,3),(975,4), + (976,1),(976,2),(976,3),(976,4), + (977,1),(977,2),(977,3),(977,4), + (978,1),(978,2),(978,3),(978,4), + (979,1),(979,2),(979,3),(979,4), + (980,1),(980,2),(980,3),(980,4), + (981,1),(981,2),(981,3),(981,4), + (982,1),(982,2),(982,3),(982,4), + (983,1),(983,2),(983,3),(983,4), + (984,1),(984,2),(984,3),(984,4), + (985,1),(985,2),(985,3),(985,4), + (986,1),(986,2),(986,3),(986,4), + (987,1),(987,2),(987,3),(987,4), + (988,1),(988,2),(988,3),(988,4), + (989,1),(989,2),(989,3),(989,4), + (990,1),(990,2),(990,3),(990,4), + (991,1),(991,2),(991,3),(991,4), + (992,1),(992,2),(992,3),(992,4), + (993,1),(993,2),(993,3),(993,4), + (994,1),(994,2),(994,3),(994,4), + (995,1),(995,2),(995,3),(995,4), + (996,1),(996,2),(996,3),(996,4), + (997,1),(997,2),(997,3),(997,4), + (998,1),(998,2),(998,3),(998,4), + (999,1),(999,2),(999,3),(999,4), + (1000,1),(1000,2),(1000,3),(1000,4) +; \ No newline at end of file diff --git a/jtt808-server/src/main/resources/sql/schema_mysql.sql b/jtt808-server/src/main/resources/sql/schema_mysql.sql new file mode 100644 index 0000000000000000000000000000000000000000..5656c57df55e31d1de599e7135308b25b576bf85 --- /dev/null +++ b/jtt808-server/src/main/resources/sql/schema_mysql.sql @@ -0,0 +1,157 @@ +CREATE TABLE IF NOT EXISTS `location` +( + `vehicle_id` MEDIUMINT UNSIGNED NOT NULL COMMENT '车辆ID', + `device_time` DATETIME NOT NULL COMMENT '设备时间', + `mobile_no` BIGINT UNSIGNED NOT NULL COMMENT '手机号', + `device_id` VARCHAR(30) NOT NULL COMMENT '设备ID', + `warn_bit` INT NOT NULL COMMENT '报警标志', + `status_bit` INT NOT NULL COMMENT '状态', + `longitude` INT NOT NULL COMMENT 'GPS经度', + `latitude` INT NOT NULL COMMENT 'GPS纬度', + `altitude` SMALLINT NOT NULL COMMENT '海拔(米)', + `speed` SMALLINT UNSIGNED NOT NULL COMMENT '速度(1/10公里每小时)', + `direction` SMALLINT NOT NULL COMMENT '方向', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + INDEX idx_device_time (`device_time`), + PRIMARY KEY (`vehicle_id`, `device_time`) +) ENGINE = InnoDB COMMENT '位置数据'; + + +CREATE TABLE IF NOT EXISTS `device_status` +( + `online` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '0.离线 1.在线', + `plate_no` CHAR(8) NOT NULL DEFAULT '' COMMENT '车牌号', + `agency_id` SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '机构ID', + `vehicle_id` MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '车辆ID', + `device_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '设备时间', + `mobile_no` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '手机号', + `device_id` VARCHAR(30) NOT NULL DEFAULT '' COMMENT '设备ID', + `warn_bit` INT NOT NULL DEFAULT 0 COMMENT '报警标志', + `status_bit` INT NOT NULL DEFAULT 0 COMMENT '状态', + `longitude` INT NOT NULL DEFAULT 0 COMMENT 'GPS经度', + `latitude` INT NOT NULL DEFAULT 0 COMMENT 'GPS纬度', + `altitude` SMALLINT NOT NULL DEFAULT 0 COMMENT '海拔(米)', + `speed` SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '速度(1/10公里每小时)', + `direction` SMALLINT NOT NULL DEFAULT 0 COMMENT '方向', + `address` VARCHAR(255) NULL COMMENT '当前位置', + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + INDEX idx_plate_no (`plate_no`), + INDEX idx_mobile_no (`mobile_no`), + INDEX idx_vehicle_id (`vehicle_id`), + PRIMARY KEY (`device_id`) +) ENGINE = InnoDB COMMENT '设备状态'; + + +CREATE TABLE IF NOT EXISTS `device` +( + `device_id` VARCHAR(30) NOT NULL COMMENT '设备ID', + `agency_id` SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '机构ID', + `vehicle_id` MEDIUMINT UNSIGNED NOT NULL COMMENT '车辆ID', + `mobile_no` BIGINT UNSIGNED NULL COMMENT '手机号', + `iccid` CHAR(20) NULL COMMENT '集成电路卡识别码', + `imei` CHAR(15) NULL COMMENT '国际移动设备识别码', + `register_time` DATETIME NULL COMMENT '注册时间(最近注册时间)', + `install_time` DATETIME NULL COMMENT '安装时间(首次注册时间)', + `protocol_version` TINYINT NULL COMMENT '协议版本号', + `software_version` VARCHAR(20) NULL COMMENT '软件版本号', + `firmware_version` VARCHAR(255) NULL COMMENT '固件版本号', + `hardware_version` VARCHAR(255) NULL COMMENT '硬件版本号', + `device_model` VARCHAR(30) NULL COMMENT '设备型号', + `maker_id` VARCHAR(11) NULL COMMENT '制造商', + `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标志', + `updated_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '更新者', + `created_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '创建者', + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + INDEX d_idx_vehicle_id (`vehicle_id`), + UNIQUE d_uni_mobile_no (`mobile_no`), + PRIMARY KEY (`device_id`) +) ENGINE = InnoDB COMMENT '设备表'; + + +CREATE TABLE IF NOT EXISTS `vehicle` +( + `id` MEDIUMINT UNSIGNED AUTO_INCREMENT COMMENT '车辆ID', + `agency_id` SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '机构ID', + `device_id` VARCHAR(30) NULL COMMENT '设备ID', + `plate_no` CHAR(8) NOT NULL COMMENT '车牌号', + `vin_no` CHAR(17) NULL COMMENT '车架号', + `engine_no` VARCHAR(17) NULL COMMENT '引擎号', + `plate_color` TINYINT UNSIGNED NULL COMMENT '车牌颜色: 1.蓝色 2.黄色 3.黑色 4.白色 9.其他', + `vehicle_type` TINYINT UNSIGNED NULL COMMENT '车辆类型', + `city_id` SMALLINT UNSIGNED NULL COMMENT '市县域ID', + `province_id` TINYINT UNSIGNED NULL COMMENT '省域ID', + `remark` VARCHAR(255) NULL COMMENT '备注', + `updated_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '更新者', + `created_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '创建者', + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `area_updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '区域更新时间', + INDEX idx_area_updated_at (`area_updated_at`), + UNIQUE v_uni_plate_no (`plate_no`), + UNIQUE v_uni_device_id (`device_id`), + PRIMARY KEY (`id`) +) ENGINE = InnoDB COMMENT '车辆表'; + + +CREATE TABLE IF NOT EXISTS `agency` +( + `id` SMALLINT UNSIGNED AUTO_INCREMENT COMMENT '机构ID', + `name` VARCHAR(20) NOT NULL COMMENT '机构简称', + `full_name` VARCHAR(40) NOT NULL COMMENT '机构全称', + `remark` VARCHAR(255) NULL COMMENT '备注', + `updated_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '更新者', + `created_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '创建者', + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE = InnoDB COMMENT '机构表'; + + +CREATE TABLE IF NOT EXISTS `area_vehicle` +( + `vehicle_id` MEDIUMINT UNSIGNED NOT NULL COMMENT '车辆ID', + `area_id` SMALLINT UNSIGNED NOT NULL COMMENT '区域ID', + `created_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '创建者', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`vehicle_id`, `area_id`) +) ENGINE = InnoDB COMMENT '区域车辆绑定'; + + +CREATE TABLE IF NOT EXISTS `area` +( + `id` SMALLINT UNSIGNED AUTO_INCREMENT COMMENT '区域ID', + `agency_id` SMALLINT UNSIGNED NOT NULL COMMENT '机构ID', + `name` VARCHAR(30) NOT NULL COMMENT '名称', + `area_desc` VARCHAR(255) NULL COMMENT '描述', + `geom_type` TINYINT UNSIGNED NOT NULL COMMENT '几何类型: 1.圆形 2.矩形 3.多边形 4.路线', + `geom_text` TEXT NOT NULL COMMENT '几何数据: 圆形[x,y,r] 矩形[x,y,x,y] 多边形[x,y,x,y,x,y] 路线[x,y,x,y,w]', + `mark_type` TINYINT UNSIGNED NOT NULL COMMENT '标记类型: 1.作业区 2.停车场 3.禁行区', + `limit_in_out` TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '限制出入: 0.无 1.进区域 2.出区域', + `limit_speed` TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '限速(公里每小时) 0不限制', + `limit_time` TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '限停(分钟) 0不限制', + `weeks` TINYINT UNSIGNED NOT NULL DEFAULT 127 COMMENT '生效日(按位,周一至周日)', + `start_date` DATE NULL COMMENT '开始日期', + `end_date` DATE NULL COMMENT '结束日期', + `start_time` TIME NULL COMMENT '开始时间', + `end_time` TIME NULL COMMENT '结束时间', + `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标志', + `updated_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '更新者', + `created_by` VARCHAR(32) NOT NULL DEFAULT 'db' COMMENT '创建者', + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE = InnoDB COMMENT '区域表'; + +CREATE TABLE IF NOT EXISTS `online_record` +( + `agency_id` SMALLINT UNSIGNED NOT NULL COMMENT '机构ID', + `vehicle_id` MEDIUMINT UNSIGNED NOT NULL COMMENT '车辆ID', + `mobile_no` BIGINT UNSIGNED NOT NULL COMMENT '手机号', + `device_id` VARCHAR(30) NOT NULL COMMENT '设备ID', + `online_time` DATETIME NOT NULL COMMENT '上线时间', + `online_duration` MEDIUMINT UNSIGNED NOT NULL COMMENT '在线时长', + INDEX idx_online_time (`online_time`), + PRIMARY KEY (`vehicle_id`, `online_time`) +) ENGINE = InnoDB COMMENT '在线记录'; \ No newline at end of file diff --git a/jtt808-server/src/main/resources/sql/schema_mysql_pro.sql b/jtt808-server/src/main/resources/sql/schema_mysql_pro.sql new file mode 100644 index 0000000000000000000000000000000000000000..03bb032c780b46fabad54a0db6c78ea3932b4d90 --- /dev/null +++ b/jtt808-server/src/main/resources/sql/schema_mysql_pro.sql @@ -0,0 +1,22 @@ +CREATE TABLE IF NOT EXISTS `location` +( + `vehicle_id` MEDIUMINT UNSIGNED NOT NULL COMMENT '车辆ID', + `device_time` DATETIME NOT NULL COMMENT '设备时间', + `mobile_no` VARCHAR(20) NOT NULL COMMENT '手机号', + `device_id` VARCHAR(30) NOT NULL COMMENT '设备ID', + `warn_bit` INT NOT NULL COMMENT '报警标志', + `status_bit` INT NOT NULL COMMENT '状态', + `longitude` INT NOT NULL COMMENT 'GPS经度', + `latitude` INT NOT NULL COMMENT 'GPS纬度', + `altitude` SMALLINT NOT NULL COMMENT '海拔(米)', + `speed` SMALLINT UNSIGNED NOT NULL COMMENT '速度(1/10公里每小时)', + `direction` SMALLINT NOT NULL COMMENT '方向', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `device_date` DATE GENERATED ALWAYS AS (DATE(`device_time`)) VIRTUAL NOT NULL COMMENT '设备日期', + INDEX idx_date_vehicleid (`device_date`, `vehicle_id`), + INDEX idx_devicetime (`device_time`), + PRIMARY KEY (`vehicle_id`, `device_time`) +) ENGINE = InnoDB COMMENT '位置数据' PARTITION BY RANGE COLUMNS (device_time)( + PARTITION 2021_01_01 VALUES LESS THAN ('2021-01-01'), + PARTITION 2021_01_02 VALUES LESS THAN ('2021-01-02') +); \ No newline at end of file diff --git "a/jtt808-server/src/main/resources/sql/\345\210\206\345\214\272\346\223\215\344\275\234.sql" "b/jtt808-server/src/main/resources/sql/\345\210\206\345\214\272\346\223\215\344\275\234.sql" new file mode 100644 index 0000000000000000000000000000000000000000..c46c33def5e6eaf878e21cc1096a8d1453eaf482 --- /dev/null +++ "b/jtt808-server/src/main/resources/sql/\345\210\206\345\214\272\346\223\215\344\275\234.sql" @@ -0,0 +1,14 @@ +-- 添加表分区 +alter table location add partition ( + partition 2021_01_03 values less than ('2021-01-03'), + partition 2021_01_04 values less than ('2021-01-04') +); + +-- 删除表分区 +alter table location drop partition 2021_01_04; + +-- 查看分区 +select * +from information_schema.partitions +where table_schema = schema() and table_name = 'location' +order by partition_ordinal_position desc; \ No newline at end of file diff --git "a/jtt808-server/src/main/resources/sql/\345\274\200\345\220\257MySQL\347\232\204\345\256\232\346\227\266\344\273\273\345\212\241.sql" "b/jtt808-server/src/main/resources/sql/\345\274\200\345\220\257MySQL\347\232\204\345\256\232\346\227\266\344\273\273\345\212\241.sql" new file mode 100644 index 0000000000000000000000000000000000000000..52b4be46d4b8e3fd302159cb0b120729038434e6 --- /dev/null +++ "b/jtt808-server/src/main/resources/sql/\345\274\200\345\220\257MySQL\347\232\204\345\256\232\346\227\266\344\273\273\345\212\241.sql" @@ -0,0 +1,15 @@ +-- 开启定时任务 +-- 方法1 修改mysql配置文件 +-- my.ini 文件中添加 event_scheduler=1 +-- 方法2 执行语句,MySQL重启后需要再次执行 +set global event_scheduler = 1; +-- 方法3 执行语句,MySQL8.0 +set persist event_scheduler = 1; +show variables like 'event_scheduler'; + +-- 查看定时任务 +show events; + +-- 创建定时任务 每天23点,执行存储过程 proc_add_partition('location', null) +drop event if exists `event_add_partition_location`; +create event `event_add_partition_location` on schedule every 1 day starts '1970-01-01 23:00:00' on completion preserve enable do call proc_add_partition('location', null); \ No newline at end of file diff --git "a/jtt808-server/src/main/resources/sql/\350\207\252\345\212\250\345\210\233\345\273\272\345\210\206\345\214\272\347\232\204\345\255\230\345\202\250\350\277\207\347\250\213.sql" "b/jtt808-server/src/main/resources/sql/\350\207\252\345\212\250\345\210\233\345\273\272\345\210\206\345\214\272\347\232\204\345\255\230\345\202\250\350\277\207\347\250\213.sql" new file mode 100644 index 0000000000000000000000000000000000000000..d4fe9f9a485077c8ec2be4b73996ae4f477852e9 --- /dev/null +++ "b/jtt808-server/src/main/resources/sql/\350\207\252\345\212\250\345\210\233\345\273\272\345\210\206\345\214\272\347\232\204\345\255\230\345\202\250\350\277\207\347\250\213.sql" @@ -0,0 +1,28 @@ +-- 调用存储过程 +call proc_add_partition('location', null); +call proc_add_partition('location', '2020-01-07'); + +-- 删除存储过程 +drop procedure if exists `proc_add_partition`; + +-- 创建分区的存储过程 +-- table_name 分区表的表名 +-- p_date 分区的日期 yyyy-MM-dd +CREATE PROCEDURE `proc_add_partition`(IN table_name VARCHAR(30), IN p_date DATE) +BEGIN + IF p_date IS NULL THEN + -- 如果 p_date为空,找到当前表的最大分区,并且加一天 + select DATE_ADD(REPLACE(p.partition_description, '\'', ''), interval 1 day) into p_date + from information_schema.partitions p + where p.table_schema = schema() and p.table_name = table_name + order by p.partition_ordinal_position desc limit 1; + END IF; + + -- 创建分区 + set @cmd = concat('alter table ', table_name, ' add partition (partition ', DATE_FORMAT(p_date, '%Y_%m_%d'), ' values less than (''', p_date, '''))'); + select @cmd; + + prepare stmt from @cmd; + execute stmt; + deallocate prepare stmt; +END \ No newline at end of file