diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
new file mode 100644
index 0000000..c2e936d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
@@ -0,0 +1,46 @@
+package com.casic.missiles.modular.system.utils;
+
+import lombok.NonNull;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 网络请求工具
+ *
+ * @author a203
+ */
+public class HttpRequestHelper {
+
+ public static RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse(Constant.CONTENT_TYPE), value);
+ }
+
+ public static String doPost(Request request) {
+ return streamResponse(request);
+ }
+
+ public static String doGet(String url) {
+ return streamResponse(new Request.Builder()
+ .url(url)
+ .build());
+ }
+
+ private static String streamResponse(@NonNull Request request) {
+ OkHttpClient httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(20, TimeUnit.SECONDS)
+ .build();
+ Call call = httpClient.newCall(request);
+ try {
+ Response response = call.execute();
+ return response.body() != null ? Objects.requireNonNull(response.body()).string() : "";
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
new file mode 100644
index 0000000..c2e936d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
@@ -0,0 +1,46 @@
+package com.casic.missiles.modular.system.utils;
+
+import lombok.NonNull;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 网络请求工具
+ *
+ * @author a203
+ */
+public class HttpRequestHelper {
+
+ public static RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse(Constant.CONTENT_TYPE), value);
+ }
+
+ public static String doPost(Request request) {
+ return streamResponse(request);
+ }
+
+ public static String doGet(String url) {
+ return streamResponse(new Request.Builder()
+ .url(url)
+ .build());
+ }
+
+ private static String streamResponse(@NonNull Request request) {
+ OkHttpClient httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(20, TimeUnit.SECONDS)
+ .build();
+ Call call = httpClient.newCall(request);
+ try {
+ Response response = call.execute();
+ return response.body() != null ? Objects.requireNonNull(response.body()).string() : "";
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
new file mode 100644
index 0000000..aa56b23
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
@@ -0,0 +1,34 @@
+package com.casic.missiles.modular.system.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author a203
+ */
+public class TimeUtil {
+ static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
+
+ public static String getCurrentTime() {
+ synchronized (DATE_FORMAT) {
+ return DATE_FORMAT.format(new Date());
+ }
+ }
+
+ public static String timeToId(String time) {
+ synchronized (DATE_FORMAT) {
+ try {
+ Date date = DATE_FORMAT.parse(time);
+ synchronized (TIME_FORMAT) {
+ return TIME_FORMAT.format(date);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+}
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
new file mode 100644
index 0000000..c2e936d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
@@ -0,0 +1,46 @@
+package com.casic.missiles.modular.system.utils;
+
+import lombok.NonNull;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 网络请求工具
+ *
+ * @author a203
+ */
+public class HttpRequestHelper {
+
+ public static RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse(Constant.CONTENT_TYPE), value);
+ }
+
+ public static String doPost(Request request) {
+ return streamResponse(request);
+ }
+
+ public static String doGet(String url) {
+ return streamResponse(new Request.Builder()
+ .url(url)
+ .build());
+ }
+
+ private static String streamResponse(@NonNull Request request) {
+ OkHttpClient httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(20, TimeUnit.SECONDS)
+ .build();
+ Call call = httpClient.newCall(request);
+ try {
+ Response response = call.execute();
+ return response.body() != null ? Objects.requireNonNull(response.body()).string() : "";
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
new file mode 100644
index 0000000..aa56b23
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
@@ -0,0 +1,34 @@
+package com.casic.missiles.modular.system.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author a203
+ */
+public class TimeUtil {
+ static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
+
+ public static String getCurrentTime() {
+ synchronized (DATE_FORMAT) {
+ return DATE_FORMAT.format(new Date());
+ }
+ }
+
+ public static String timeToId(String time) {
+ synchronized (DATE_FORMAT) {
+ try {
+ Date date = DATE_FORMAT.parse(time);
+ synchronized (TIME_FORMAT) {
+ return TIME_FORMAT.format(date);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+}
diff --git a/casic-web/pom.xml b/casic-web/pom.xml
index 7d97900..a36cc14 100644
--- a/casic-web/pom.xml
+++ b/casic-web/pom.xml
@@ -100,6 +100,11 @@
casic-server
${pro.version}
+
+ com.casic
+ casic-ship
+ ${pro.version}
+
org.springframework.boot
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
new file mode 100644
index 0000000..c2e936d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
@@ -0,0 +1,46 @@
+package com.casic.missiles.modular.system.utils;
+
+import lombok.NonNull;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 网络请求工具
+ *
+ * @author a203
+ */
+public class HttpRequestHelper {
+
+ public static RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse(Constant.CONTENT_TYPE), value);
+ }
+
+ public static String doPost(Request request) {
+ return streamResponse(request);
+ }
+
+ public static String doGet(String url) {
+ return streamResponse(new Request.Builder()
+ .url(url)
+ .build());
+ }
+
+ private static String streamResponse(@NonNull Request request) {
+ OkHttpClient httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(20, TimeUnit.SECONDS)
+ .build();
+ Call call = httpClient.newCall(request);
+ try {
+ Response response = call.execute();
+ return response.body() != null ? Objects.requireNonNull(response.body()).string() : "";
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
new file mode 100644
index 0000000..aa56b23
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
@@ -0,0 +1,34 @@
+package com.casic.missiles.modular.system.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author a203
+ */
+public class TimeUtil {
+ static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
+
+ public static String getCurrentTime() {
+ synchronized (DATE_FORMAT) {
+ return DATE_FORMAT.format(new Date());
+ }
+ }
+
+ public static String timeToId(String time) {
+ synchronized (DATE_FORMAT) {
+ try {
+ Date date = DATE_FORMAT.parse(time);
+ synchronized (TIME_FORMAT) {
+ return TIME_FORMAT.format(date);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+}
diff --git a/casic-web/pom.xml b/casic-web/pom.xml
index 7d97900..a36cc14 100644
--- a/casic-web/pom.xml
+++ b/casic-web/pom.xml
@@ -100,6 +100,11 @@
casic-server
${pro.version}
+
+ com.casic
+ casic-ship
+ ${pro.version}
+
org.springframework.boot
diff --git a/casic-web/src/main/resources/config/application-dev.yml b/casic-web/src/main/resources/config/application-dev.yml
index 0f6d593..013057d 100644
--- a/casic-web/src/main/resources/config/application-dev.yml
+++ b/casic-web/src/main/resources/config/application-dev.yml
@@ -19,7 +19,7 @@
# redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
casic:
#kaptcha-open: false #是否开启登录时验证码 (true/false)
- no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**
+ no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**,/ais/**
#flowable数据源和多数据源配置
db:
init:
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
new file mode 100644
index 0000000..c2e936d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
@@ -0,0 +1,46 @@
+package com.casic.missiles.modular.system.utils;
+
+import lombok.NonNull;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 网络请求工具
+ *
+ * @author a203
+ */
+public class HttpRequestHelper {
+
+ public static RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse(Constant.CONTENT_TYPE), value);
+ }
+
+ public static String doPost(Request request) {
+ return streamResponse(request);
+ }
+
+ public static String doGet(String url) {
+ return streamResponse(new Request.Builder()
+ .url(url)
+ .build());
+ }
+
+ private static String streamResponse(@NonNull Request request) {
+ OkHttpClient httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(20, TimeUnit.SECONDS)
+ .build();
+ Call call = httpClient.newCall(request);
+ try {
+ Response response = call.execute();
+ return response.body() != null ? Objects.requireNonNull(response.body()).string() : "";
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
new file mode 100644
index 0000000..aa56b23
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
@@ -0,0 +1,34 @@
+package com.casic.missiles.modular.system.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author a203
+ */
+public class TimeUtil {
+ static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
+
+ public static String getCurrentTime() {
+ synchronized (DATE_FORMAT) {
+ return DATE_FORMAT.format(new Date());
+ }
+ }
+
+ public static String timeToId(String time) {
+ synchronized (DATE_FORMAT) {
+ try {
+ Date date = DATE_FORMAT.parse(time);
+ synchronized (TIME_FORMAT) {
+ return TIME_FORMAT.format(date);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+}
diff --git a/casic-web/pom.xml b/casic-web/pom.xml
index 7d97900..a36cc14 100644
--- a/casic-web/pom.xml
+++ b/casic-web/pom.xml
@@ -100,6 +100,11 @@
casic-server
${pro.version}
+
+ com.casic
+ casic-ship
+ ${pro.version}
+
org.springframework.boot
diff --git a/casic-web/src/main/resources/config/application-dev.yml b/casic-web/src/main/resources/config/application-dev.yml
index 0f6d593..013057d 100644
--- a/casic-web/src/main/resources/config/application-dev.yml
+++ b/casic-web/src/main/resources/config/application-dev.yml
@@ -19,7 +19,7 @@
# redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
casic:
#kaptcha-open: false #是否开启登录时验证码 (true/false)
- no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**
+ no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**,/ais/**
#flowable数据源和多数据源配置
db:
init:
diff --git a/casic-web/src/main/resources/config/application-prod.yml b/casic-web/src/main/resources/config/application-prod.yml
index e4dec71..259a389 100644
--- a/casic-web/src/main/resources/config/application-prod.yml
+++ b/casic-web/src/main/resources/config/application-prod.yml
@@ -21,7 +21,7 @@
#flowable数据源和多数据源配置
casic:
kaptcha-open: false #是否开启登录时验证码 (true/false)
- nologin-urls: /user/login,/user/appLogin,/kaptcha,/config/baseConfig,/route/mockToken,/environment/**
+ nologin-urls: /user/login,/user/appLogin,/kaptcha,/config/baseConfig,/route/mockToken,/environment/**,/ais/**
flowable:
datasource:
url: jdbc:mysql://10.18.0.20:3306/callcenter_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
new file mode 100644
index 0000000..c2e936d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
@@ -0,0 +1,46 @@
+package com.casic.missiles.modular.system.utils;
+
+import lombok.NonNull;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 网络请求工具
+ *
+ * @author a203
+ */
+public class HttpRequestHelper {
+
+ public static RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse(Constant.CONTENT_TYPE), value);
+ }
+
+ public static String doPost(Request request) {
+ return streamResponse(request);
+ }
+
+ public static String doGet(String url) {
+ return streamResponse(new Request.Builder()
+ .url(url)
+ .build());
+ }
+
+ private static String streamResponse(@NonNull Request request) {
+ OkHttpClient httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(20, TimeUnit.SECONDS)
+ .build();
+ Call call = httpClient.newCall(request);
+ try {
+ Response response = call.execute();
+ return response.body() != null ? Objects.requireNonNull(response.body()).string() : "";
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
new file mode 100644
index 0000000..aa56b23
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
@@ -0,0 +1,34 @@
+package com.casic.missiles.modular.system.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author a203
+ */
+public class TimeUtil {
+ static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
+
+ public static String getCurrentTime() {
+ synchronized (DATE_FORMAT) {
+ return DATE_FORMAT.format(new Date());
+ }
+ }
+
+ public static String timeToId(String time) {
+ synchronized (DATE_FORMAT) {
+ try {
+ Date date = DATE_FORMAT.parse(time);
+ synchronized (TIME_FORMAT) {
+ return TIME_FORMAT.format(date);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+}
diff --git a/casic-web/pom.xml b/casic-web/pom.xml
index 7d97900..a36cc14 100644
--- a/casic-web/pom.xml
+++ b/casic-web/pom.xml
@@ -100,6 +100,11 @@
casic-server
${pro.version}
+
+ com.casic
+ casic-ship
+ ${pro.version}
+
org.springframework.boot
diff --git a/casic-web/src/main/resources/config/application-dev.yml b/casic-web/src/main/resources/config/application-dev.yml
index 0f6d593..013057d 100644
--- a/casic-web/src/main/resources/config/application-dev.yml
+++ b/casic-web/src/main/resources/config/application-dev.yml
@@ -19,7 +19,7 @@
# redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
casic:
#kaptcha-open: false #是否开启登录时验证码 (true/false)
- no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**
+ no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**,/ais/**
#flowable数据源和多数据源配置
db:
init:
diff --git a/casic-web/src/main/resources/config/application-prod.yml b/casic-web/src/main/resources/config/application-prod.yml
index e4dec71..259a389 100644
--- a/casic-web/src/main/resources/config/application-prod.yml
+++ b/casic-web/src/main/resources/config/application-prod.yml
@@ -21,7 +21,7 @@
#flowable数据源和多数据源配置
casic:
kaptcha-open: false #是否开启登录时验证码 (true/false)
- nologin-urls: /user/login,/user/appLogin,/kaptcha,/config/baseConfig,/route/mockToken,/environment/**
+ nologin-urls: /user/login,/user/appLogin,/kaptcha,/config/baseConfig,/route/mockToken,/environment/**,/ais/**
flowable:
datasource:
url: jdbc:mysql://10.18.0.20:3306/callcenter_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
diff --git a/casic-web/src/main/resources/config/application-test.yml b/casic-web/src/main/resources/config/application-test.yml
index d59fd10..acea2d6 100644
--- a/casic-web/src/main/resources/config/application-test.yml
+++ b/casic-web/src/main/resources/config/application-test.yml
@@ -14,7 +14,7 @@
# store-type: redis
casic:
# kaptcha-open: false #是否开启登录时验证码 (true/false)
- nologin-urls: /user/login,/user/appLogin,/kaptcha/base64,/config/baseConfig,/route/mockToken,/workflow/**,/environment/**
+ nologin-urls: /user/login,/user/appLogin,/kaptcha/base64,/config/baseConfig,/route/mockToken,/workflow/**,/environment/**,/ais/**
#flowable数据源和多数据源配置
flowable:
datasource:
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
new file mode 100644
index 0000000..c2e936d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
@@ -0,0 +1,46 @@
+package com.casic.missiles.modular.system.utils;
+
+import lombok.NonNull;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 网络请求工具
+ *
+ * @author a203
+ */
+public class HttpRequestHelper {
+
+ public static RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse(Constant.CONTENT_TYPE), value);
+ }
+
+ public static String doPost(Request request) {
+ return streamResponse(request);
+ }
+
+ public static String doGet(String url) {
+ return streamResponse(new Request.Builder()
+ .url(url)
+ .build());
+ }
+
+ private static String streamResponse(@NonNull Request request) {
+ OkHttpClient httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(20, TimeUnit.SECONDS)
+ .build();
+ Call call = httpClient.newCall(request);
+ try {
+ Response response = call.execute();
+ return response.body() != null ? Objects.requireNonNull(response.body()).string() : "";
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
new file mode 100644
index 0000000..aa56b23
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
@@ -0,0 +1,34 @@
+package com.casic.missiles.modular.system.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author a203
+ */
+public class TimeUtil {
+ static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
+
+ public static String getCurrentTime() {
+ synchronized (DATE_FORMAT) {
+ return DATE_FORMAT.format(new Date());
+ }
+ }
+
+ public static String timeToId(String time) {
+ synchronized (DATE_FORMAT) {
+ try {
+ Date date = DATE_FORMAT.parse(time);
+ synchronized (TIME_FORMAT) {
+ return TIME_FORMAT.format(date);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+}
diff --git a/casic-web/pom.xml b/casic-web/pom.xml
index 7d97900..a36cc14 100644
--- a/casic-web/pom.xml
+++ b/casic-web/pom.xml
@@ -100,6 +100,11 @@
casic-server
${pro.version}
+
+ com.casic
+ casic-ship
+ ${pro.version}
+
org.springframework.boot
diff --git a/casic-web/src/main/resources/config/application-dev.yml b/casic-web/src/main/resources/config/application-dev.yml
index 0f6d593..013057d 100644
--- a/casic-web/src/main/resources/config/application-dev.yml
+++ b/casic-web/src/main/resources/config/application-dev.yml
@@ -19,7 +19,7 @@
# redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
casic:
#kaptcha-open: false #是否开启登录时验证码 (true/false)
- no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**
+ no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**,/ais/**
#flowable数据源和多数据源配置
db:
init:
diff --git a/casic-web/src/main/resources/config/application-prod.yml b/casic-web/src/main/resources/config/application-prod.yml
index e4dec71..259a389 100644
--- a/casic-web/src/main/resources/config/application-prod.yml
+++ b/casic-web/src/main/resources/config/application-prod.yml
@@ -21,7 +21,7 @@
#flowable数据源和多数据源配置
casic:
kaptcha-open: false #是否开启登录时验证码 (true/false)
- nologin-urls: /user/login,/user/appLogin,/kaptcha,/config/baseConfig,/route/mockToken,/environment/**
+ nologin-urls: /user/login,/user/appLogin,/kaptcha,/config/baseConfig,/route/mockToken,/environment/**,/ais/**
flowable:
datasource:
url: jdbc:mysql://10.18.0.20:3306/callcenter_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
diff --git a/casic-web/src/main/resources/config/application-test.yml b/casic-web/src/main/resources/config/application-test.yml
index d59fd10..acea2d6 100644
--- a/casic-web/src/main/resources/config/application-test.yml
+++ b/casic-web/src/main/resources/config/application-test.yml
@@ -14,7 +14,7 @@
# store-type: redis
casic:
# kaptcha-open: false #是否开启登录时验证码 (true/false)
- nologin-urls: /user/login,/user/appLogin,/kaptcha/base64,/config/baseConfig,/route/mockToken,/workflow/**,/environment/**
+ nologin-urls: /user/login,/user/appLogin,/kaptcha/base64,/config/baseConfig,/route/mockToken,/workflow/**,/environment/**,/ais/**
#flowable数据源和多数据源配置
flowable:
datasource:
diff --git a/casic-web/src/main/resources/config/application.yml b/casic-web/src/main/resources/config/application.yml
index 4a5f1f4..6fed21e 100644
--- a/casic-web/src/main/resources/config/application.yml
+++ b/casic-web/src/main/resources/config/application.yml
@@ -19,7 +19,7 @@
spring-session-open: false #是否开启spring session,如果是多机环境需要开启(true/false)
session-invalidate-time: 86400 #session失效时间(只在单机环境下生效,,多机环境在SpringSessionConfig类中配置) 单位:秒
session-validation-interval: 900 #多久检测一次失效的session(只在单机环境下生效) 单位:秒
- no-login-urls: /user/login,/kaptcha,/config/baseConfig,/environment/**
+ no-login-urls: /user/login,/kaptcha,/config/baseConfig,/environment/**,/ais/**
config:
export-path: D:\java\boot\guns-web-1.0.0-SNAPSHOT\export\
diff --git a/casic-ship/pom.xml b/casic-ship/pom.xml
new file mode 100644
index 0000000..b7bab3c
--- /dev/null
+++ b/casic-ship/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+ com.casic
+ casic-template
+ ../pom.xml
+ 2.0.0
+
+
+ casic-ship
+ 2.0.0
+ jar
+ casic-ship
+ casic 的spring boot版本
+
+
+
+
+ com.casic
+ casic-core
+ ${core.version}
+ provided
+
+
+ com.casic
+ casic-admin-support
+ ${admin.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${boot.version}
+ provided
+
+
+ com.casic
+ casic-server
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.1
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ org.locationtech.spatial4j
+ spatial4j
+ 0.8
+
+
+
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
new file mode 100644
index 0000000..b311d5c
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/controller/ShipController.java
@@ -0,0 +1,50 @@
+package com.casic.missiles.modular.system.controller;
+
+import com.casic.missiles.core.base.controller.BaseController;
+import com.casic.missiles.model.response.ResponseData;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+/**
+ * 最新船舶信息控制器
+ *
+ * @author a203
+ */
+@Controller
+@RequestMapping("/ais")
+public class ShipController extends BaseController {
+
+ private final IShipService shipService;
+ private final IAisLogService logService;
+
+ public ShipController(IShipService shipService, IAisLogService logService) {
+ this.shipService = shipService;
+ this.logService = logService;
+ }
+
+ /**
+ * 圆形区域最新船舶信息
+ */
+ @GetMapping(value = "/shipsInCircle")
+ @ResponseBody
+ public Object list(String rgn, int age) {
+ List ships = shipService.shipsInCircle(rgn, age);
+ return ResponseData.success(ships);
+ }
+
+ /**
+ * AIS调用记录
+ */
+ @GetMapping(value = "/log")
+ @ResponseBody
+ public Object log() {
+ return ResponseData.success(logService.count());
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
new file mode 100644
index 0000000..d4103fd
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dao/AisLogMapper.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用次数 Mapper 接口
+ *
+ * @author a203
+ */
+public interface AisLogMapper extends BaseMapper {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
new file mode 100644
index 0000000..c4d9cbf
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/dto/ShipDTO.java
@@ -0,0 +1,106 @@
+package com.casic.missiles.modular.system.dto;
+
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import lombok.Data;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * @author a203
+ */
+@Data
+public class ShipDTO {
+ private String shipId;
+ /**
+ * 定位时间
+ */
+ private String positionTime;
+ /**
+ * 经度
+ */
+ private Double lng;
+ /**
+ * 纬度
+ */
+ private Double lat;
+ /**
+ * 航向(单位:度)
+ */
+ private Float course;
+ /**
+ * 航艏向
+ */
+ private Integer heading;
+ /**
+ * 航速(单位:节)
+ */
+ private Float speed;
+ /**
+ * ais 航行状态
+ */
+ private String aisStatus;
+ private String mmsi;
+ /**
+ * 英文船名
+ */
+ private String engName;
+ /**
+ * Imo 号
+ */
+ private String imoNum;
+ /**
+ * 船舶呼号
+ */
+ private String shipCallNum;
+ private String shipType;
+ private Integer shipLength;
+ private Integer shipWidth;
+ /**
+ * 预到时间
+ */
+ private String expectTime;
+ /**
+ * 目的港
+ */
+ private String destination;
+ /**
+ * 吃水(单位:m)
+ */
+ private Float depth;
+ /**
+ * 国籍 3 字母
+ */
+ private String nationality;
+
+ public ShipDTO(ShipModel.DataBean data) {
+ this.shipId = data.getI();
+ this.positionTime = formatUTC(data.getT());
+ this.lng = (double) data.getN() / 600000;
+ this.lat = (double) data.getA() / 600000;
+ this.course = (float) data.getC() / 10;
+ this.heading = data.getH();
+ this.speed = (float) data.getS() / 10;
+ this.aisStatus = data.getV();
+ this.mmsi = data.getM();
+ this.engName = data.getE();
+ this.imoNum = data.getO();
+ this.shipCallNum = data.getG();
+ this.shipType = data.getY();
+ this.shipLength = data.getL();
+ this.shipWidth = data.getB();
+ this.expectTime = data.getR();
+ this.destination = data.getP();
+ this.depth = (float) data.getD() / 10;
+ this.nationality = data.getF();
+ }
+
+ private String formatUTC(int seconds) {
+ long utc = seconds * 1000L;
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ format.setTimeZone(TimeZone.getTimeZone("GMT+08"));
+ return format.format(new Date(utc));
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
new file mode 100644
index 0000000..69ab8b5
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/remote/ShipModel.java
@@ -0,0 +1,251 @@
+package com.casic.missiles.modular.system.model.remote;
+
+import java.util.List;
+
+/**
+ * 第三方AIS数据模型
+ *
+ * @author a203
+ */
+public class ShipModel {
+
+ /**
+ * code : 0
+ * count : 7
+ * message : 成功
+ * data : [{"g":"3EQK6","y":"70","a":10884867,"n":68125760,"i":"2030707","t":1632903145,"e":"HMM ROTTERDAM","m":"351246000","o":"9868338","f":"PAN","l":400,"c":1872,"s":163,"h":189,"v":"0","b":62,"r":"10-15 19:00","p":"EGSUE","d":154}]
+ */
+
+ private String code;
+ private int count;
+ private String message;
+ private List data;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ public static class DataBean {
+ /**
+ * g : 3EQK6
+ * y : 70
+ * a : 10884867
+ * n : 68125760
+ * i : 2030707
+ * t : 1632903145
+ * e : HMM ROTTERDAM
+ * m : 351246000
+ * o : 9868338
+ * f : PAN
+ * l : 400
+ * c : 1872
+ * s : 163
+ * h : 189
+ * v : 0
+ * b : 62
+ * r : 10-15 19:00
+ * p : EGSUE
+ * d : 154
+ */
+
+ private String g;
+ private String y;
+ private int a;
+ private int n;
+ private String i;
+ private int t;
+ private String e;
+ private String m;
+ private String o;
+ private String f;
+ private int l;
+ private int c;
+ private int s;
+ private int h;
+ private String v;
+ private int b;
+ private String r;
+ private String p;
+ private int d;
+
+ public String getG() {
+ return g;
+ }
+
+ public void setG(String g) {
+ this.g = g;
+ }
+
+ public String getY() {
+ return y;
+ }
+
+ public void setY(String y) {
+ this.y = y;
+ }
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int a) {
+ this.a = a;
+ }
+
+ public int getN() {
+ return n;
+ }
+
+ public void setN(int n) {
+ this.n = n;
+ }
+
+ public String getI() {
+ return i;
+ }
+
+ public void setI(String i) {
+ this.i = i;
+ }
+
+ public int getT() {
+ return t;
+ }
+
+ public void setT(int t) {
+ this.t = t;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ public String getM() {
+ return m;
+ }
+
+ public void setM(String m) {
+ this.m = m;
+ }
+
+ public String getO() {
+ return o;
+ }
+
+ public void setO(String o) {
+ this.o = o;
+ }
+
+ public String getF() {
+ return f;
+ }
+
+ public void setF(String f) {
+ this.f = f;
+ }
+
+ public int getL() {
+ return l;
+ }
+
+ public void setL(int l) {
+ this.l = l;
+ }
+
+ public int getC() {
+ return c;
+ }
+
+ public void setC(int c) {
+ this.c = c;
+ }
+
+ public int getS() {
+ return s;
+ }
+
+ public void setS(int s) {
+ this.s = s;
+ }
+
+ public int getH() {
+ return h;
+ }
+
+ public void setH(int h) {
+ this.h = h;
+ }
+
+ public String getV() {
+ return v;
+ }
+
+ public void setV(String v) {
+ this.v = v;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public void setB(int b) {
+ this.b = b;
+ }
+
+ public String getR() {
+ return r;
+ }
+
+ public void setR(String r) {
+ this.r = r;
+ }
+
+ public String getP() {
+ return p;
+ }
+
+ public void setP(String p) {
+ this.p = p;
+ }
+
+ public int getD() {
+ return d;
+ }
+
+ public void setD(int d) {
+ this.d = d;
+ }
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
new file mode 100644
index 0000000..bac67bc
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/model/sql/AisLog.java
@@ -0,0 +1,38 @@
+package com.casic.missiles.modular.system.model.sql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+ * @author a203
+ */
+@Data
+@TableName("ais_request_log")
+public class AisLog extends Model {
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "ID", type = IdType.ASSIGN_ID)
+ private Long id;
+
+ /**
+ * ais请求参数
+ */
+ @TableField("REQUEST_PARAM")
+ private String requestParam;
+
+ /**
+ * ais返回数据
+ */
+ @TableField("RESPONSE")
+ private String response;
+
+ /**
+ * 调用第三方ais接口时间
+ */
+ @TableField("REQUEST_TIME")
+ private String requestTime;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
new file mode 100644
index 0000000..cd1298d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IAisLogService.java
@@ -0,0 +1,13 @@
+package com.casic.missiles.modular.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+
+/**
+ * AIS调用记录 服务类
+ *
+ * @author a203
+ */
+public interface IAisLogService extends IService {
+
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
new file mode 100644
index 0000000..94dbe25
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/IShipService.java
@@ -0,0 +1,22 @@
+package com.casic.missiles.modular.system.service;
+
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.Ship;
+
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务类
+ *
+ * @author a203
+ */
+public interface IShipService {
+ /**
+ * 查询圆形区域最新船舶信息
+ *
+ * @param rgn 包含圆形区域信息,格式:圆心纬度,圆心经度,半径;经纬 度单位为 1/10000 分,半径单位海里。每次调用的半径不 能超过 80 海里
+ * @param age 船位时间在此范围内的数据;最小 1 分 钟(默认),最大 240 分钟
+ * @return {@link List}
+ */
+ List shipsInCircle(String rgn, int age);
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
new file mode 100644
index 0000000..9505b18
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/AisLogServiceImpl.java
@@ -0,0 +1,21 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.casic.missiles.modular.system.dao.AisLogMapper;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * AIS调用记录 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class AisLogServiceImpl extends ServiceImpl implements IAisLogService {
+
+ public AisLogServiceImpl() {
+
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
new file mode 100644
index 0000000..e6dcdd9
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/service/impl/ShipServiceImpl.java
@@ -0,0 +1,94 @@
+package com.casic.missiles.modular.system.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.casic.missiles.modular.system.dto.ShipDTO;
+import com.casic.missiles.modular.system.model.remote.ShipModel;
+import com.casic.missiles.modular.system.model.sql.AisLog;
+import com.casic.missiles.modular.system.service.IAisLogService;
+import com.casic.missiles.modular.system.service.IShipService;
+import com.casic.missiles.modular.system.utils.Constant;
+import com.casic.missiles.modular.system.utils.HttpRequestHelper;
+import com.casic.missiles.modular.system.utils.TimeUtil;
+import okhttp3.Request;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 船舶数据信息 服务实现类
+ *
+ * @author a203
+ */
+
+@Service
+public class ShipServiceImpl implements IShipService {
+
+ private static final String SUCCESS_CODE = "0";
+ private final IAisLogService logService;
+
+ public ShipServiceImpl(IAisLogService logService) {
+ this.logService = logService;
+ }
+
+ @Override
+ public List shipsInCircle(String rgn, int age) {
+ if (rgn == null || rgn.isEmpty()) {
+ throw new NullPointerException("搜索区域不能为空");
+ }
+ if (age < Constant.MIN_AGE || age > Constant.MAX_AGE) {
+ throw new IllegalArgumentException("时间范围错误");
+ }
+ /**
+ * 封装请求参数
+ * */
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("rgn", rgn);
+ jsonObject.put("age", age);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ List shipDTOList = new ArrayList<>();
+ /**
+ * 获取AIS接口数据
+ * */
+ String requestBody = jsonObject.toJSONString();
+ Request request = new Request.Builder()
+ .addHeader(Constant.AIS_HEADER_NAME, Constant.AIS_KEY_VALUE)
+ .url(Constant.SHIPS_IN_CIRCLE)
+ .post(HttpRequestHelper.createRequestBody(requestBody))
+ .build();
+ String res = HttpRequestHelper.doPost(request);
+ //先解析出code,根据code判断
+ if (SUCCESS_CODE.equals(getResponseCode(res))) {
+ //请求成功才保存ais访问记录
+ AisLog aisLog = new AisLog();
+ aisLog.setRequestParam(requestBody);
+ aisLog.setResponse(res);
+ aisLog.setRequestTime(TimeUtil.getCurrentTime());
+ logService.save(aisLog);
+
+ ShipModel remoteData = JSON.parseObject(res, new TypeReference() {
+ });
+ for (ShipModel.DataBean data : remoteData.getData()) {
+ shipDTOList.add(new ShipDTO(data));
+ }
+ }
+ return shipDTOList;
+ }
+
+ /**
+ * {"code":"101", "message":"权限失效"}
+ */
+ public String getResponseCode(String value) {
+ if ("".equals(value)) {
+ return value;
+ }
+ JSONObject jsonObject = JSON.parseObject(value);
+ return jsonObject.getString("code");
+ }
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
new file mode 100644
index 0000000..8edaeff
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/Constant.java
@@ -0,0 +1,18 @@
+package com.casic.missiles.modular.system.utils;
+
+/**
+ * 船舶相关常量
+ *
+ * @author a203
+ */
+public class Constant {
+ private static final String AIS_BASE_URL = "https://api3.myships.com";
+ public static final String AIS_HEADER_NAME = "appKey";
+ public static final String AIS_KEY_VALUE = "de26d070af5f42fabb13a02f7c0ec065";
+ public static final String CONTENT_TYPE = "application/json; charset=utf-8";
+
+ public static final String SHIPS_IN_CIRCLE = AIS_BASE_URL + "/sp/region/latest/shipinfoCircle";
+
+ public static final int MIN_AGE = 1;
+ public static final int MAX_AGE = 240;
+}
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
new file mode 100644
index 0000000..c2e936d
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/HttpRequestHelper.java
@@ -0,0 +1,46 @@
+package com.casic.missiles.modular.system.utils;
+
+import lombok.NonNull;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 网络请求工具
+ *
+ * @author a203
+ */
+public class HttpRequestHelper {
+
+ public static RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse(Constant.CONTENT_TYPE), value);
+ }
+
+ public static String doPost(Request request) {
+ return streamResponse(request);
+ }
+
+ public static String doGet(String url) {
+ return streamResponse(new Request.Builder()
+ .url(url)
+ .build());
+ }
+
+ private static String streamResponse(@NonNull Request request) {
+ OkHttpClient httpClient = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(20, TimeUnit.SECONDS)
+ .build();
+ Call call = httpClient.newCall(request);
+ try {
+ Response response = call.execute();
+ return response.body() != null ? Objects.requireNonNull(response.body()).string() : "";
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
new file mode 100644
index 0000000..aa56b23
--- /dev/null
+++ b/casic-ship/src/main/java/com/casic/missiles/modular/system/utils/TimeUtil.java
@@ -0,0 +1,34 @@
+package com.casic.missiles.modular.system.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * @author a203
+ */
+public class TimeUtil {
+ static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+ static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
+
+ public static String getCurrentTime() {
+ synchronized (DATE_FORMAT) {
+ return DATE_FORMAT.format(new Date());
+ }
+ }
+
+ public static String timeToId(String time) {
+ synchronized (DATE_FORMAT) {
+ try {
+ Date date = DATE_FORMAT.parse(time);
+ synchronized (TIME_FORMAT) {
+ return TIME_FORMAT.format(date);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+}
diff --git a/casic-web/pom.xml b/casic-web/pom.xml
index 7d97900..a36cc14 100644
--- a/casic-web/pom.xml
+++ b/casic-web/pom.xml
@@ -100,6 +100,11 @@
casic-server
${pro.version}
+
+ com.casic
+ casic-ship
+ ${pro.version}
+
org.springframework.boot
diff --git a/casic-web/src/main/resources/config/application-dev.yml b/casic-web/src/main/resources/config/application-dev.yml
index 0f6d593..013057d 100644
--- a/casic-web/src/main/resources/config/application-dev.yml
+++ b/casic-web/src/main/resources/config/application-dev.yml
@@ -19,7 +19,7 @@
# redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
casic:
#kaptcha-open: false #是否开启登录时验证码 (true/false)
- no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**
+ no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken,/environment/**,/ais/**
#flowable数据源和多数据源配置
db:
init:
diff --git a/casic-web/src/main/resources/config/application-prod.yml b/casic-web/src/main/resources/config/application-prod.yml
index e4dec71..259a389 100644
--- a/casic-web/src/main/resources/config/application-prod.yml
+++ b/casic-web/src/main/resources/config/application-prod.yml
@@ -21,7 +21,7 @@
#flowable数据源和多数据源配置
casic:
kaptcha-open: false #是否开启登录时验证码 (true/false)
- nologin-urls: /user/login,/user/appLogin,/kaptcha,/config/baseConfig,/route/mockToken,/environment/**
+ nologin-urls: /user/login,/user/appLogin,/kaptcha,/config/baseConfig,/route/mockToken,/environment/**,/ais/**
flowable:
datasource:
url: jdbc:mysql://10.18.0.20:3306/callcenter_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
diff --git a/casic-web/src/main/resources/config/application-test.yml b/casic-web/src/main/resources/config/application-test.yml
index d59fd10..acea2d6 100644
--- a/casic-web/src/main/resources/config/application-test.yml
+++ b/casic-web/src/main/resources/config/application-test.yml
@@ -14,7 +14,7 @@
# store-type: redis
casic:
# kaptcha-open: false #是否开启登录时验证码 (true/false)
- nologin-urls: /user/login,/user/appLogin,/kaptcha/base64,/config/baseConfig,/route/mockToken,/workflow/**,/environment/**
+ nologin-urls: /user/login,/user/appLogin,/kaptcha/base64,/config/baseConfig,/route/mockToken,/workflow/**,/environment/**,/ais/**
#flowable数据源和多数据源配置
flowable:
datasource:
diff --git a/casic-web/src/main/resources/config/application.yml b/casic-web/src/main/resources/config/application.yml
index 4a5f1f4..6fed21e 100644
--- a/casic-web/src/main/resources/config/application.yml
+++ b/casic-web/src/main/resources/config/application.yml
@@ -19,7 +19,7 @@
spring-session-open: false #是否开启spring session,如果是多机环境需要开启(true/false)
session-invalidate-time: 86400 #session失效时间(只在单机环境下生效,,多机环境在SpringSessionConfig类中配置) 单位:秒
session-validation-interval: 900 #多久检测一次失效的session(只在单机环境下生效) 单位:秒
- no-login-urls: /user/login,/kaptcha,/config/baseConfig,/environment/**
+ no-login-urls: /user/login,/kaptcha,/config/baseConfig,/environment/**,/ais/**
config:
export-path: D:\java\boot\guns-web-1.0.0-SNAPSHOT\export\
diff --git a/pom.xml b/pom.xml
index 5a8edaf..80d830f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,6 +9,7 @@
casic-web
casic-server
+ casic-ship
com.casic