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