shjung 1 year ago
parent
commit
a64a30b424
31 changed files with 1123 additions and 77 deletions
  1. 2 0
      app-install/conf/application.yml
  2. 1 0
      conf/agip-comm-server.pid
  3. 2 0
      conf/application.yml
  4. 1 1
      conf/debug.properties
  5. 46 0
      src/main/java/com/its/app/utils/TimeUtils.java
  6. 5 3
      src/main/java/com/its/bis/AgipCommServerApplication.java
  7. 4 3
      src/main/java/com/its/bis/api/controller/AgipControlController.java
  8. 3 3
      src/main/java/com/its/bis/api/dto/AgipObeGnss.java
  9. 2 0
      src/main/java/com/its/bis/api/dto/AgipObeLoc.java
  10. 7 4
      src/main/java/com/its/bis/api/service/AgipControlService.java
  11. 3 0
      src/main/java/com/its/bis/config/ServerConfig.java
  12. 6 8
      src/main/java/com/its/bis/dto/BisObe.java
  13. 0 4
      src/main/java/com/its/bis/dto/Location.java
  14. 3 3
      src/main/java/com/its/bis/entity/TbBisVehLoc.java
  15. 40 0
      src/main/java/com/its/bis/process/Counter.java
  16. 6 6
      src/main/java/com/its/bis/service/AppRepositoryService.java
  17. 123 0
      src/main/java/com/its/bis/service/BisAgipService.java
  18. 277 0
      src/main/java/com/its/bis/service/BisAgipWorker.java
  19. 2 34
      src/main/java/com/its/bis/service/NodeLinkService.java
  20. 88 0
      src/main/java/com/its/bis/webapp/config/WebSecurityConfig.java
  21. 21 0
      src/main/java/com/its/bis/webapp/controller/WebAppCommonController.java
  22. 21 0
      src/main/java/com/its/bis/webapp/controller/WebAppController.java
  23. 27 0
      src/main/java/com/its/bis/webapp/security/SessionListener.java
  24. 38 0
      src/main/java/com/its/bis/webapp/security/UserAuthenticationProvider.java
  25. 198 0
      src/main/java/com/its/bis/webapp/service/FileService.java
  26. 40 0
      src/main/java/com/its/bis/webapp/service/UserService.java
  27. 19 0
      src/main/java/com/its/bis/webapp/vo/FileInfoVo.java
  28. 51 0
      src/main/java/com/its/bis/webapp/vo/UserVo.java
  29. 3 1
      src/main/resources/application.yml
  30. 1 0
      src/main/resources/mybatis/mapper/NodeLinkMapper.xml
  31. 83 7
      src/test/java/com/its/app/AgipCommServerApplicationTests.java

+ 2 - 0
app-install/conf/application.yml

@@ -6,6 +6,8 @@ server:
   history-min: 30
   min-speed: 3
   max-speed: 140
+  max-distance: 20
+  max-trvl-min: 60
 
 spring:
   datasource:

+ 1 - 0
conf/agip-comm-server.pid

@@ -0,0 +1 @@
+70372

+ 2 - 0
conf/application.yml

@@ -6,6 +6,8 @@ server:
   history-min: 30
   min-speed: 3
   max-speed: 140
+  max-distance: 20
+  max-trvl-min: 60
 
 spring:
   profiles:

+ 1 - 1
conf/debug.properties

@@ -1,5 +1,5 @@
 #system debug setting configuration...
-#Fri Nov 24 18:05:11 KST 2023
+#Mon Nov 27 16:51:26 KST 2023
 packet-info=x
 packet-dump=x
 system-debug=false

+ 46 - 0
src/main/java/com/its/app/utils/TimeUtils.java

@@ -4,6 +4,7 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.concurrent.TimeUnit;
 
 public class TimeUtils {
 
@@ -16,6 +17,51 @@ public class TimeUtils {
 	public static final int TYPE_PRCS_MONTH = 6;
 	public static final int TYPE_PRCS_YEAR  = 7;
 
+	public static String elapsedTime(long startTime, long endTime) {
+		return elapsedTimeStr(endTime - startTime);
+	}
+
+	public static String elapsedTime(long startTime) {
+		return elapsedTimeStr(System.nanoTime() - startTime);
+	}
+
+	public static String elapsedTimeStr(long elapsed) {
+		long seconds = TimeUnit.SECONDS.convert(elapsed, TimeUnit.NANOSECONDS);
+		long miliSeconds = TimeUnit.MILLISECONDS.convert(elapsed, TimeUnit.NANOSECONDS) % 1000L;
+		long microSeconds = TimeUnit.MICROSECONDS.convert(elapsed, TimeUnit.NANOSECONDS) % 1000L;
+		long nanoSeconds = TimeUnit.NANOSECONDS.convert(elapsed, TimeUnit.NANOSECONDS) % 1000L;
+		if (seconds > 0L) {
+			return String.format("Elapsed: %,d sec. %3d ms. %d us. %3d ns.", seconds, miliSeconds, microSeconds, nanoSeconds);
+		} else if (miliSeconds > 0L) {
+			return String.format("Elapsed: %3d ms. %3d us. %3d ns.", miliSeconds, microSeconds, nanoSeconds);
+		} else {
+			return microSeconds > 0L ? String.format("Elapsed: --- ms. %3d us. %3d ns.", microSeconds, nanoSeconds) : String.format("Elapsed: --- ms. --- us. %3d ns.", nanoSeconds);
+		}
+	}
+
+	public static long currentElapsedTime() {
+		return System.nanoTime() / 1000000L;
+	}
+
+	public static long currentTimeMillis() {
+		return System.currentTimeMillis();
+	}
+
+	public static long currentTimeSeconds() {
+		return TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+	}
+
+	public static Date elapsedTimeToDate(long elapsedTime) {
+		long wallTime = currentTimeMillis() + elapsedTime - currentElapsedTime();
+		return new Date(wallTime);
+	}
+
+	public static String millisToString(long millis) {
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		return transFormat.format(millis);
+	}
+
+
 	/* 현재 시각을 문자열로 리턴 */
 	public static String getCurrentTimeString() {
 		Calendar cal = Calendar.getInstance();

+ 5 - 3
src/main/java/com/its/bis/AgipCommServerApplication.java

@@ -10,6 +10,7 @@ import com.its.bis.dto.NearNodeDto;
 import com.its.bis.dto.TbLinkDto;
 import com.its.bis.entity.TbUnitSyst;
 import com.its.bis.process.DbmsDataProcess;
+import com.its.bis.service.BisAgipService;
 import com.its.bis.service.NodeLinkService;
 import com.its.bis.service.UnitSystService;
 import com.its.bis.ui.JTextAreaOutputStream;
@@ -152,21 +153,22 @@ public class AgipCommServerApplication implements CommandLineRunner, Application
         NodeLinkService nodeLinkService = (NodeLinkService)AppUtils.getBean(NodeLinkService.class);
         nodeLinkService.loadDb();
 
+        BisAgipService bisAgipService = (BisAgipService)AppUtils.getBean(BisAgipService.class);
         Location from = Location.builder()
                 .mLatitude(128.74352336)
                 .mLongitude(36.56392018)
                 .build();
-        NearNodeDto fNode = nodeLinkService.getNearNode(from);
+        NearNodeDto fNode = bisAgipService.getNearNode(from);
         log.info("From NearNode: {}", fNode);
 
         Location to = Location.builder()
                 .mLatitude(128.73881251)
                 .mLongitude(36.56128759)
                 .build();
-        NearNodeDto tNode = nodeLinkService.getNearNode(to);
+        NearNodeDto tNode = bisAgipService.getNearNode(to);
         log.info("  To NearNode: {}", tNode);
 
-        TbLinkDto link = nodeLinkService.getSectInfo(fNode.getNodeId(), tNode.getNodeId());
+        TbLinkDto link = bisAgipService.getSectInfo(fNode.getNodeId(), tNode.getNodeId());
         log.info("Matching Link: {}", link);
 
         DebugConfig debugConfig = (DebugConfig)AppUtils.getBean(DebugConfig.class);

+ 4 - 3
src/main/java/com/its/bis/api/controller/AgipControlController.java

@@ -27,15 +27,16 @@ public class AgipControlController {
     private final AgipControlService service;
 
     @ApiOperation(value = "AGIP 실시간 OBE 위치정보 수집")
-    @PostMapping(value = "/location", produces = {"application/json; charset=utf8"})
+    @PostMapping(value = "/location2", produces = {"application/json; charset=utf8"})
     public void receiveWebhooksFromAGIP2(@RequestBody List<Map<String, Object>> payload) {
         log.error("{}", payload);
     }
 
     @ApiOperation(value = "AGIP 실시간 OBE 위치정보 수집")
-    @PostMapping(value = "/location2", produces = {"application/json; charset=utf8"})
+    @PostMapping(value = "/location", produces = {"application/json; charset=utf8"})
     public void receiveWebhooksFromAGIP(@RequestBody AgipObeLoc payload) {
-        log.error("{}", payload);
+        log.info("{}", payload);
+        this.service.add(payload);
     }
 
     @ApiOperation(value = "AGIP 테스트 URL", response = String.class)

+ 3 - 3
src/main/java/com/its/bis/api/dto/AgipObeGnss.java

@@ -19,9 +19,9 @@ public class AgipObeGnss implements Serializable {
     private Integer hertz;      // 전송주기, 0
     private Double latitude;    // 위도, 37.48543554333333
     private Double longitude;   // 경도, 126.89448518666667
-    private Double height;      // 높이(m), 19.203
-    private Double speed;       // 속도(km/h), 2.48
-    private Double angle;       // 방위각, 250.29
+    private Float height;      // 높이(m), 19.203
+    private Float speed;       // 속도(km/h), 2.48
+    private Float angle;       // 방위각, 250.29
     private Integer pdop;       // 0
     private String fixStatus;   // "NORMAL"
     private String baseStation; // 기준국, "UNKNOWN"

+ 2 - 0
src/main/java/com/its/bis/api/dto/AgipObeLoc.java

@@ -36,4 +36,6 @@ public class AgipObeLoc implements Serializable {
     private String routeId;                 // 운행중인 노선 아이디, null
     private String runStatus;               // 운행 상태 NORMAL(일반운행), FIRST(첫차운행), LAST(막차운행), EMPTY(공차운행), null
 
+    private long rcvNanoSeconds;
+
 }

+ 7 - 4
src/main/java/com/its/bis/api/service/AgipControlService.java

@@ -1,7 +1,7 @@
 package com.its.bis.api.service;
 
-import com.its.bis.config.ApplicationConfig;
-import com.its.bis.service.AppRepositoryService;
+import com.its.bis.api.dto.AgipObeLoc;
+import com.its.bis.service.BisAgipService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -11,7 +11,10 @@ import org.springframework.stereotype.Service;
 @Service
 public class AgipControlService {
 
-    private final ApplicationConfig config;
-    private final AppRepositoryService repoService;
+    private final BisAgipService service;
 
+    public void add(AgipObeLoc bisLoc) {
+        bisLoc.setRcvNanoSeconds(System.nanoTime());
+        this.service.add(bisLoc);
+    }
 }

+ 3 - 0
src/main/java/com/its/bis/config/ServerConfig.java

@@ -20,5 +20,8 @@ public class ServerConfig {
     private int historyMin = 30;
     private int minSpeed = 3;
     private int maxSpeed = 140;
+    private int maxDistance = 20;   // 노드와의 최대 거리(반지름)
+    private int maxTrvlMin = 60;    // 지점간 최대 여행시간
 
 }
+

+ 6 - 8
src/main/java/com/its/bis/dto/BisObe.java

@@ -18,14 +18,9 @@ public class BisObe  implements Serializable {
     private String carNumber;               // 차량 번호, null
 
     private Location location;
-//    private Double xCrdn;
-//    private Double yCrdn;
-    //private Double longitude;   // 경도, 126.89448518666667
-    //private Double latitude;    // 위도, 37.48543554333333
-
-    private Double height;      // 높이(m), 19.203
-    private Double speed;       // 속도(km/h), 2.48
-    private Double angle;       // 방위각, 250.29
+    private Float height;      // 높이(m), 19.203
+    private Float speed;       // 속도(km/h), 2.48
+    private Float angle;       // 방위각, 250.29
 
     private float moveDist;
 
@@ -33,4 +28,7 @@ public class BisObe  implements Serializable {
     private Long edNodeId = 0L;
     private int  trvlHh = 0;    // stNodeId ~ edNodeId travel time(seconds)
 
+    private long stNodeTm;
+    private long edNodeTm;
+
 }

+ 0 - 4
src/main/java/com/its/bis/dto/Location.java

@@ -7,10 +7,6 @@ import lombok.Data;
 @Builder
 public class Location {
 
-//    private double mLat1 = 0.0;
-//    private double mLon1 = 0.0;
-//    private double mLat2 = 0.0;
-//    private double mLon2 = 0.0;
     private float mDistance = 0.0f;
     private float mInitialBearing = 0.0f;
     private float mFinalBearing = 0.0f;

+ 3 - 3
src/main/java/com/its/bis/entity/TbBisVehLoc.java

@@ -30,13 +30,13 @@ public class TbBisVehLoc implements Serializable {
     private String LOC_TYPE;
 
     @ApiModelProperty("속도(km/h)")  // Y NUMBER(5,2)
-    private Double SPEED;
+    private Float SPEED;
 
     @ApiModelProperty("높이(m)")  // Y NUMBER(5,2)
-    private Double HEGT;
+    private Float HEGT;
 
     @ApiModelProperty("방위각")  // Y NUMBER(5,2)
-    private Double ANGLE;
+    private Float ANGLE;
 
     @ApiModelProperty("경도(126.89448518666667)")  // Y NUMBER(11,8)
     private Double LNG;

+ 40 - 0
src/main/java/com/its/bis/process/Counter.java

@@ -0,0 +1,40 @@
+package com.its.bis.process;
+
+import com.its.app.utils.Converter;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class Counter {
+    private AtomicLong counter = new AtomicLong(0L);
+
+    public Counter() {
+    }
+
+    public long reset() {
+        return this.counter.getAndSet(0L);
+    }
+
+    public long reset(long value) {
+        return this.counter.getAndSet(0L);
+    }
+
+    public long increment() {
+        return this.counter.incrementAndGet();
+    }
+
+    public long add(long value) {
+        return this.counter.addAndGet(value);
+    }
+
+    public long decrement() {
+        return this.counter.decrementAndGet();
+    }
+
+    public long get() {
+        return this.counter.get();
+    }
+
+    public String toString() {
+        return Converter.getSize(this.counter.doubleValue());
+    }
+}

+ 6 - 6
src/main/java/com/its/bis/service/AppRepositoryService.java

@@ -47,11 +47,11 @@ public class AppRepositoryService {
         return this.sectMap.get(fNodeId + ":" + tNodeId);
     }
 
-//    public BisObe putObeMap(BisObe obj) {
-//        return this.obeMap.put(obj.getDeviceId(), obj);
-//    }
-//    public BisObe getObeMap(String deviceId) {
-//        return this.obeMap.get(deviceId);
-//    }
+    public BisObe putObeMap(BisObe obj) {
+        return this.obeMap.put(obj.getDeviceId(), obj);
+    }
+    public BisObe getObeMap(String deviceId) {
+        return this.obeMap.get(deviceId);
+    }
 
 }

+ 123 - 0
src/main/java/com/its/bis/service/BisAgipService.java

@@ -0,0 +1,123 @@
+package com.its.bis.service;
+
+import com.its.app.utils.Elapsed;
+import com.its.bis.api.dto.AgipObeLoc;
+import com.its.bis.config.ServerConfig;
+import com.its.bis.config.ThreadPoolInitializer;
+import com.its.bis.dto.Location;
+import com.its.bis.dto.NearNodeDto;
+import com.its.bis.dto.TbLinkDto;
+import com.its.bis.dto.TbNodeDto;
+import com.its.bis.process.DbmsDataProcess;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@Transactional(rollbackFor = {Exception.class})
+public class BisAgipService {
+
+    private final AppRepositoryService repoService;
+    private final ServerConfig config;
+    private final DbmsDataProcess dbmsDataProcess;
+    private final ThreadPoolInitializer threadPoolInitializer;
+
+    private final List<Thread> threadList = new ArrayList<Thread>();
+    private final List<BisAgipWorker> workerList = new ArrayList<BisAgipWorker>();
+    private final ThreadGroup workerGroup = new ThreadGroup("BisAgipService");
+    private int workers;
+
+    @PostConstruct
+    private void init() {
+        log.info("BisAgipService.init: Start.");
+
+        this.workers = this.threadPoolInitializer.getDbms();
+        if (this.workers <= 0) this.workers = 10;
+        int qSize = 100;
+        for (int ii = 0; ii < this.workers; ii++) {
+            BisAgipWorker packetWorker = new BisAgipWorker(ii, qSize, this.config, this.repoService, this.dbmsDataProcess);
+            this.workerList.add(packetWorker);
+            Thread worker = new Thread(workerGroup, packetWorker);
+            worker.setName(String.format("BisAgipService-%02d.%02d", this.workers, ii+1));
+            worker.setDaemon(true);
+            this.threadList.add(worker);
+        }
+        for (Thread worker : this.threadList) {
+            worker.start();
+        }
+        log.info("BisAgipService.init: ..End.");
+    }
+
+    /**
+     * REST API 로 수신한 위치정보를 작업큐에 입력
+     * @param obeLoc
+     * @return
+     */
+    public boolean add(AgipObeLoc obeLoc) {
+        boolean offer = false;
+        String deviceId = obeLoc.getDeviceId();
+        if (deviceId == null || deviceId.equals("")) {
+            deviceId = "xxx";
+            obeLoc.setDeviceId(deviceId);
+        }
+        try {
+            int idx = Math.abs(deviceId.hashCode() % this.workers);
+            offer = this.workerList.get(idx).add(obeLoc);
+        }
+        catch (Exception e) {
+            MDC.put("id", deviceId);
+            log.error("QUEUE_DATA.add: Exception: {}, {}, {}", deviceId, obeLoc, e.getMessage());
+            MDC.clear();
+        }
+        return offer;
+    }
+
+    public void report() {
+        for (BisAgipWorker worker : this.workerList) {
+            worker.report();
+        }
+    }
+
+    public double getDistance(double lat1, double lon1, double lat2, double lon2) {
+        double EARTH_RADIUS = 6371.0;
+        double dLat = Math.toRadians(lat2 - lat1);
+        double dLon = Math.toRadians(lon2 - lon1);
+
+        double a = Math.sin(dLat/2)* Math.sin(dLat/2)+ Math.cos(Math.toRadians(lat1))* Math.cos(Math.toRadians(lat2))* Math.sin(dLon/2)* Math.sin(dLon/2);
+        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
+        return (EARTH_RADIUS * c * 1000);    // Distance in m
+    }
+
+    public NearNodeDto getNearNode(Location loc) {
+        Elapsed elapsed = new Elapsed();
+        log.info("getNearNode: {}", loc);
+        //Location(mDistance=0.0, mInitialBearing=0.0, mFinalBearing=0.0, mLatitude=128.73881251, mLongitude=36.56128759)
+        double maxDistance = 40;
+        NearNodeDto node = NearNodeDto.builder().nodeId(0L).distance(maxDistance).build();
+        for (Map.Entry<Long, TbNodeDto> e : this.repoService.getEntrySetNode()) {
+            TbNodeDto obj = e.getValue();
+            double fDistance = (float) getDistance(loc.getMLatitude(), loc.getMLongitude(), obj.getXCrdn(), obj.getYCrdn());
+            if (fDistance < maxDistance) {
+                maxDistance = fDistance;
+                node.setNodeId(obj.getNodeId());
+                node.setDistance(fDistance);
+            }
+        }
+        log.info("getNearNode: {} ms. {} m, {}", elapsed.milliSeconds(), maxDistance, node);
+        return node;
+    }
+
+    public TbLinkDto getSectInfo(Long fNodeId, Long tNodeId) {
+        return this.repoService.getSectMap(fNodeId, tNodeId);
+    }
+
+}

+ 277 - 0
src/main/java/com/its/bis/service/BisAgipWorker.java

@@ -0,0 +1,277 @@
+package com.its.bis.service;
+
+import com.its.app.utils.Elapsed;
+import com.its.app.utils.SysUtils;
+import com.its.app.utils.TimeUtils;
+import com.its.bis.api.dto.AgipObeLoc;
+import com.its.bis.config.ServerConfig;
+import com.its.bis.dto.*;
+import com.its.bis.entity.TbBisLinkTrafClct;
+import com.its.bis.entity.TbBisVehLoc;
+import com.its.bis.process.DbmsData;
+import com.its.bis.process.DbmsDataProcess;
+import com.its.bis.process.DbmsDataType;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+
+@Slf4j
+public class BisAgipWorker implements Runnable {
+
+    private long avgTime = 0;
+    private int idx;
+    private int qSize;
+
+    private final ServerConfig config;
+    private final AppRepositoryService repoService;
+    private final DbmsDataProcess dbmsDataProcess;
+    private final LinkedBlockingQueue<AgipObeLoc> DATA_QUEUE;
+
+    public BisAgipWorker(int idx, int qSize, ServerConfig config, AppRepositoryService repoService, DbmsDataProcess dbmsDataProcess) {
+        this.idx = idx;
+        this.qSize = qSize;
+        this.config = config;
+        this.repoService = repoService;
+        this.dbmsDataProcess = dbmsDataProcess;
+        this.DATA_QUEUE = new LinkedBlockingQueue<>(qSize);
+    }
+
+    protected long calcProcessTime(long recvTime) {
+        long jobTime = System.nanoTime() - recvTime;
+        if (this.avgTime == 0) {
+            this.avgTime = jobTime;
+        }
+        else {
+            this.avgTime = (this.avgTime + jobTime) / 2L;
+        }
+        return this.avgTime;
+    }
+
+    /*
+     *  작업큐에 데이터 추가
+     */
+    public boolean add(AgipObeLoc obeLoc) {
+        boolean offer = false;
+        try {
+            //offer => full -> return
+            //add   => full -> wait
+            offer = this.DATA_QUEUE.offer(obeLoc);
+            if (!offer) {
+                MDC.put("id", obeLoc.getDeviceId());
+                log.error("Packet Queue.offer: {}/{}, Queue Full: {} EA, {}, {}",
+                        obeLoc.getDeviceId(), this.DATA_QUEUE.size(), this.qSize, TimeUtils.elapsedTime(obeLoc.getRcvNanoSeconds()), Thread.currentThread().getName());
+                MDC.clear();
+            }
+        } catch (Exception e) {
+            MDC.put("id", obeLoc.getDeviceId());
+            log.error("Packet Queue.offer: Exception: {}, {}, {}", obeLoc.getDeviceId(), Thread.currentThread().getName(), e.getMessage());
+            MDC.clear();
+        }
+        return offer;
+    }
+
+    public void process(AgipObeLoc obeLoc) {
+//        long curr = System.nanoTime();
+        // 샘플데이터: latitude=36.56392018, longitude=128.74352336
+        Location currLocation = Location.builder()
+                .mDistance(0)
+                .mInitialBearing(0)
+                .mFinalBearing(0)
+                .mLatitude(obeLoc.getGnssInfo().getLongitude())
+                .mLongitude(obeLoc.getGnssInfo().getLatitude())
+//                .mLatitude(obeLoc.getGnssInfo().getLatitude())
+//                .mLongitude(obeLoc.getGnssInfo().getLongitude())
+                .build();
+
+        BisObe bisObe = this.repoService.getObeMap(obeLoc.getDeviceId());
+        if (bisObe == null) {
+            bisObe = BisObe.builder()
+                    .deviceId(obeLoc.getDeviceId())
+                    .carId(obeLoc.getCarId())
+                    .carNumber(obeLoc.getCarNumber())
+                    .location(currLocation)
+                    .moveDist(0)
+                    .stNodeId(0L)
+                    .edNodeId(0L)
+                    .trvlHh(0)
+                    .stNodeTm(0)
+                    .edNodeTm(0)
+                    .build();
+            this.repoService.putObeMap(bisObe);
+        }
+        else {
+            bisObe.setLocation(currLocation);
+        }
+
+        bisObe.setHeight(obeLoc.getGnssInfo().getHeight());
+        bisObe.setSpeed(obeLoc.getGnssInfo().getSpeed());
+        bisObe.setAngle(obeLoc.getGnssInfo().getAngle());
+
+        /**
+         * 최근접 통과노드정보를 구한다.
+         */
+        NearNodeDto passNode = getNearNode(currLocation);
+        Long stNodeId = bisObe.getStNodeId();
+        Long edNodeId = bisObe.getEdNodeId();
+        Long passNodeId = passNode.getNodeId();
+        if (passNodeId != 0L) {
+            log.info("DEVICE ID: {}, 현재노드 통과: {}", bisObe.getDeviceId(), passNodeId);
+            if (stNodeId == 0L) {
+                // 시작노드가 없으면 시작노드 설정
+                bisObe.setStNodeId(passNodeId);
+                bisObe.setStNodeTm(System.currentTimeMillis());
+                log.info("DEVICE ID: {}, 시작노드 통과: {}", bisObe.getDeviceId(), passNodeId);
+            }
+            else {
+                if (!stNodeId.equals(passNodeId) && !edNodeId.equals(passNodeId)) {
+                    // 시작노드 값이 존재하면서 통과노드가 시작노드 및 종료노드와 같지 않으면 종료노드로 설정
+                    log.info("DEVICE ID: {}, 종료노드 통과: {}", bisObe.getDeviceId(), passNodeId);
+                    // 종료노드와 같지 않은 경우 종료노드에 도착한 것이므로 구간 소통정보를 생성하자....
+                    bisObe.setEdNodeId(passNodeId);
+                    bisObe.setEdNodeTm(System.currentTimeMillis());
+                    int travelSec = (int) ((bisObe.getEdNodeTm() - bisObe.getStNodeTm()) / 1000);
+                    if (travelSec > (this.config.getMaxTrvlMin() * 60)) {
+                        // 구간 통과 시간이 설정한 값보다 크기 때문에 통행시간을 계산하지 않는다.
+                        // 현재 통과 노드를 시작노드로 설정한다.
+                        log.warn("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 여행시간 오류: {} sec.", bisObe.getDeviceId(), bisObe.getStNodeId(), bisObe.getEdNodeId(), travelSec);
+                        bisObe.setStNodeId(bisObe.getEdNodeId());
+                        bisObe.setStNodeTm(bisObe.getEdNodeTm());
+                        bisObe.setEdNodeId(0L);
+                        bisObe.setEdNodeTm(0);
+                    }
+                    else {
+                        TbLinkDto link = this.repoService.getSectMap(bisObe.getStNodeId(), bisObe.getEdNodeId());
+                        if (link == null) {
+                            // 구간을 찾지 못하였음... 종료노드를 시작노드로 설정
+                            log.warn("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 구간 맷칭 오류...", bisObe.getDeviceId(), bisObe.getStNodeId(), bisObe.getEdNodeId());
+                            bisObe.setStNodeId(bisObe.getEdNodeId());
+                            bisObe.setStNodeTm(bisObe.getEdNodeTm());
+                            bisObe.setEdNodeId(0L);
+                            bisObe.setEdNodeTm(0);
+                        }
+                        else {
+                            // 구간을 통과하였으므로 구간교통정보를 생성한다.
+                            int speed = calcSpeed(link.getLinkLeng(), travelSec);
+                            log.warn("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 구간통과: {}, {} m, {} km/h, {} seconds.",
+                                    bisObe.getDeviceId(), bisObe.getStNodeId(), bisObe.getEdNodeId(), link.getLinkId(), link.getLinkLeng(), speed, travelSec);
+                            TbBisLinkTrafClct bisLinkTrafClct = TbBisLinkTrafClct.builder()
+                                    .CLCT_DT(SysUtils.getSysTime())
+                                    .LINK_ID(link.getLinkId())
+                                    .DEVICE_ID(bisObe.getDeviceId())
+                                    .SPED(speed)
+                                    .TRVL_HH(travelSec)
+                                    .ST_NODE_ARR_DT(TimeUtils.millisToString(bisObe.getStNodeTm()))
+                                    .ED_NODE_ARR_DT(TimeUtils.millisToString(bisObe.getEdNodeTm()))
+                                    .build();
+
+                            this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_CRT_BIS_LINK_TRAF_CLCT, false, bisLinkTrafClct));
+
+                            bisObe.setStNodeId(bisObe.getEdNodeId());
+                            bisObe.setStNodeTm(bisObe.getEdNodeTm());
+                            bisObe.setEdNodeId(0L);
+                            bisObe.setEdNodeTm(0);
+                        }
+                    }
+                }
+                else {
+                    log.info("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 통과노드: {}", bisObe.getDeviceId(), stNodeId, edNodeId, passNodeId);
+                }
+            }
+        }
+        else {
+            if (stNodeId != 0 && edNodeId != 0) {
+                // 시작노드와 종료노드가 설정된 상태에서 이번에 아무런 노드정보가 없으므로 노드를 빠져 나온것이므로
+                // 종료노드를 시작노드로 설정하고 종료노드는 0으로 설정한다.
+                log.info("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 통과노드: {}", bisObe.getDeviceId(), stNodeId, edNodeId, passNodeId);
+                bisObe.setStNodeId(edNodeId);
+                bisObe.setStNodeTm(System.currentTimeMillis());
+                // 종료노드 초기화
+                bisObe.setEdNodeId(0L);
+                bisObe.setEdNodeTm(0);
+            }
+            else {
+                log.info("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 통과노드: {}, 구간 운행 중...", bisObe.getDeviceId(), stNodeId, edNodeId, passNodeId);
+            }
+        }
+
+        /**
+         * 버스 현재위치 정보를 업데이트 한다.
+         */
+        TbBisVehLoc bisVehLoc = TbBisVehLoc.builder()
+                .DEVICE_ID(bisObe.getDeviceId())
+                .CLCT_DT(SysUtils.getSysTime())
+                .LOC_TYPE(obeLoc.getGnssInfo().getType())
+                .SPEED(obeLoc.getGnssInfo().getSpeed())
+                .HEGT(obeLoc.getGnssInfo().getHeight())
+                .ANGLE(obeLoc.getGnssInfo().getAngle())
+                .LNG(obeLoc.getGnssInfo().getLongitude())
+                .LAT(obeLoc.getGnssInfo().getLatitude())
+                .PASS_NODE_ID(passNodeId)
+                .build();
+        this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_UPD_BIS_VEH_LOC, false, bisVehLoc));
+    }
+
+    public void report() {
+        long avgTime = 0;
+        log.info("Packet: Remain Q: {}, Average: {}, {}", this.DATA_QUEUE.size(), TimeUtils.elapsedTimeStr(avgTime), Thread.currentThread().getName());
+    }
+
+    public int calcSpeed(int distance, int seconds) {
+        int speed;
+        if (distance <= 0 || seconds <= 0) {
+            return 2;
+        }
+        speed = (int)(((distance * 3.6) / (float)seconds) + 0.5);
+        return speed;
+    }
+
+    public NearNodeDto getNearNode(Location loc) {
+        Elapsed elapsed = new Elapsed();
+        //Location(mDistance=0.0, mInitialBearing=0.0, mFinalBearing=0.0, mLatitude=128.73881251, mLongitude=36.56128759)
+        double maxDistance = this.config.getMaxDistance();
+        NearNodeDto nearNode = NearNodeDto.builder().nodeId(0L).distance(maxDistance).build();
+        for (Map.Entry<Long, TbNodeDto> e : this.repoService.getEntrySetNode()) {
+            TbNodeDto node = e.getValue();
+            double fDistance = (float) getDistance(loc.getMLatitude(), loc.getMLongitude(), node.getXCrdn(), node.getYCrdn());
+            if (fDistance < maxDistance) {
+                maxDistance = fDistance;
+                nearNode.setNodeId(node.getNodeId());
+                nearNode.setDistance(fDistance);
+                //log.info("{}", nearNode);
+            }
+        }
+        log.info("getNearNode: {} ms. {} m, {}", elapsed.milliSeconds(), maxDistance, nearNode);
+        return nearNode;
+    }
+
+    public double getDistance(double lat1, double lon1, double lat2, double lon2) {
+        double EARTH_RADIUS = 6371.0;
+        double dLat = Math.toRadians(lat2 - lat1);
+        double dLon = Math.toRadians(lon2 - lon1);
+
+        double a = Math.sin(dLat/2)* Math.sin(dLat/2)+ Math.cos(Math.toRadians(lat1))* Math.cos(Math.toRadians(lat2))* Math.sin(dLon/2)* Math.sin(dLon/2);
+        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
+        return (EARTH_RADIUS * c * 1000);    // Distance in m
+    }
+
+    @Override
+    public void run() {
+        log.info("{} Start. Q_SIZE: {}", Thread.currentThread().getName(), this.qSize);
+        while (true) {
+            try {
+                AgipObeLoc obeLoc = this.DATA_QUEUE.take();
+                if (obeLoc != null) {
+                    process(obeLoc);
+                }
+                else {
+                    Thread.yield();
+                }
+            }
+            catch (Exception e) {
+                log.error("Exception: {}", e.getMessage());
+            }
+        }
+    }
+}

+ 2 - 34
src/main/java/com/its/bis/service/NodeLinkService.java

@@ -4,7 +4,8 @@ import com.its.app.utils.Elapsed;
 import com.its.app.utils.SysUtils;
 import com.its.bis.config.ServerConfig;
 import com.its.bis.dao.mapper.NodeLinkMapper;
-import com.its.bis.dto.*;
+import com.its.bis.dto.TbLinkDto;
+import com.its.bis.dto.TbNodeDto;
 import com.its.bis.entity.MakeTrafParam;
 import com.its.bis.entity.TbLink;
 import com.its.bis.entity.TbNode;
@@ -18,7 +19,6 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.PostConstruct;
 import java.util.List;
-import java.util.Map;
 
 @Slf4j
 @Service
@@ -86,38 +86,6 @@ public class NodeLinkService {
         log.info("NodeService.loadLinkInfo: {} EA, {} ms.", this.repoService.getNodeMap().size(), elapsed.milliSeconds());
     }
 
-    public double getDistance(double lat1, double lon1, double lat2, double lon2) {
-        int EARTH_RADIUS = 6371;
-        double dLat = Math.toRadians(lat2 - lat1);
-        double dLon = Math.toRadians(lon2 - lon1);
-
-        double a = Math.sin(dLat/2)* Math.sin(dLat/2)+ Math.cos(Math.toRadians(lat1))* Math.cos(Math.toRadians(lat2))* Math.sin(dLon/2)* Math.sin(dLon/2);
-        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
-        double d = EARTH_RADIUS* c * 1000;    // Distance in m
-        return d;
-    }
-
-    public NearNodeDto getNearNode(Location loc) {
-        Elapsed elapsed = new Elapsed();
-        double maxDistance = 40;
-        NearNodeDto node = NearNodeDto.builder().nodeId(0L).distance(maxDistance).build();
-        for (Map.Entry<Long, TbNodeDto> e : this.repoService.getEntrySetNode()) {
-            TbNodeDto obj = e.getValue();
-            double fDistance = (float) getDistance(loc.getMLatitude(), loc.getMLongitude(), obj.getXCrdn(), obj.getYCrdn());
-            if (fDistance < maxDistance) {
-                maxDistance = fDistance;
-                node.setNodeId(obj.getNodeId());
-                node.setDistance(fDistance);
-            }
-        }
-        log.info("getNearNode: {} ms. {} m, {}", elapsed.milliSeconds(), maxDistance, node);
-        return node;
-    }
-
-    public TbLinkDto getSectInfo(Long fNodeId, Long tNodeId) {
-        return this.repoService.getSectMap(fNodeId, tNodeId);
-    }
-
     /**
      * BIS 구간 소통정보 생성
      */

+ 88 - 0
src/main/java/com/its/bis/webapp/config/WebSecurityConfig.java

@@ -0,0 +1,88 @@
+package com.its.bis.webapp.config;
+
+import com.its.bis.webapp.security.SessionListener;
+import com.its.bis.webapp.service.UserService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+
+import javax.servlet.http.HttpSessionListener;
+
+@EnableWebSecurity
+@Configuration
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    private final UserService userService;
+
+    public WebSecurityConfig(UserService userService) {
+        this.userService = userService;
+    }
+
+    @Override
+    public void configure(WebSecurity web) throws Exception {
+        web.ignoring().antMatchers("/favicon.ico");
+        web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**");
+
+        web.ignoring().antMatchers(HttpMethod.GET, "/api/**");  // GET Method 는 모두 통과
+        web.ignoring().antMatchers(HttpMethod.POST, "/api/**");  // GET Method 는 모두 통과
+        web.ignoring().antMatchers(HttpMethod.PUT, "/api/**");  // GET Method 는 모두 통과
+        web.ignoring().antMatchers(HttpMethod.DELETE, "/api/**");  // GET Method 는 모두 통과
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+
+        http
+                .httpBasic().disable()
+                .cors().configurationSource(corsConfigurationSource())
+                .and()
+                .csrf().disable()
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+                .and()
+                .authorizeRequests()
+                // SWAGGER 권한 설정
+                .antMatchers("/swagger-ui.html", "/swagger/**", "/swagger-resources/**", "/webjars/**", "/v2/api-docs").permitAll()
+                // 웹소켓 권한 설정하지
+                .antMatchers("/ws/**").permitAll()
+                .antMatchers("/api/**").permitAll()
+                .anyRequest().permitAll()
+        ;
+    }
+
+    // CORS 허용 적용
+    @Bean
+    public CorsConfigurationSource corsConfigurationSource() {
+        CorsConfiguration corsConfig = new CorsConfiguration();
+
+        corsConfig.setAllowCredentials(true);       // cross origin 으로부터 인증을 위한 쿠키 정보를 받을지 여부
+        corsConfig.addAllowedOriginPattern("*");    // addAllowedOrigin("*") 대신 사용, 허용할 origin 정보, Arrays.asList("http://localhost:8080")
+        corsConfig.addAllowedHeader("*");
+        corsConfig.addAllowedMethod("*");           // 허용할 http methods. Arrays.asList("GET", "POST")
+
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", corsConfig);
+
+        return source;
+    }
+
+    @Bean
+    public SessionRegistry sessionRegistry() {
+        return new SessionRegistryImpl();
+    }
+
+    @Bean
+    public HttpSessionListener httpSessionListener() {
+        return new SessionListener();
+    }
+
+}
+

+ 21 - 0
src/main/java/com/its/bis/webapp/controller/WebAppCommonController.java

@@ -0,0 +1,21 @@
+package com.its.bis.webapp.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Slf4j
+@RequiredArgsConstructor
+@Controller
+public class WebAppCommonController {
+
+    @RequestMapping({"/", "/index"})
+    public String index(Model model, HttpServletRequest request) {
+        String result = "system";
+        return result;
+    }
+}

+ 21 - 0
src/main/java/com/its/bis/webapp/controller/WebAppController.java

@@ -0,0 +1,21 @@
+package com.its.bis.webapp.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Slf4j
+@RequiredArgsConstructor
+@Controller
+public class WebAppController {
+
+    @RequestMapping(value = {"/controller"})
+    public String controller(Model model, HttpServletRequest request) {
+        return "";
+    }
+
+}

+ 27 - 0
src/main/java/com/its/bis/webapp/security/SessionListener.java

@@ -0,0 +1,27 @@
+package com.its.bis.webapp.security;
+
+import org.springframework.security.web.session.HttpSessionEventPublisher;
+
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionEvent;
+
+public class SessionListener extends HttpSessionEventPublisher {
+
+	public void sessionCreated(HttpSessionEvent se) {
+		HttpSession session = se.getSession();
+		if (session != null) {
+			session.setMaxInactiveInterval(300);
+		}
+
+		super.sessionCreated(se);
+	}
+
+	public void sessionDestroyed(HttpSessionEvent se) {
+		HttpSession session = se.getSession();
+		if (session != null) {
+			
+		}
+
+		super.sessionDestroyed(se);
+	}
+}

+ 38 - 0
src/main/java/com/its/bis/webapp/security/UserAuthenticationProvider.java

@@ -0,0 +1,38 @@
+package com.its.bis.webapp.security;
+
+import com.its.bis.webapp.service.UserService;
+import com.its.bis.webapp.vo.UserVo;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserAuthenticationProvider implements AuthenticationProvider {
+	private final UserService userService;
+
+	public UserAuthenticationProvider(UserService userService) {
+		this.userService = userService;
+	}
+
+	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+		String id = authentication.getName();
+		String password = (String) authentication.getCredentials();
+		UserVo user = this.userService.loadUserByUsername(id);
+		if (user == null) {
+			throw new BadCredentialsException("Login Error !!");
+		} else {
+			UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(id, password,
+					user.getAuthorities());
+			result.setDetails(user);
+			return result;
+		}
+	}
+
+	@Override
+	public boolean supports(Class<?> authentication) {
+		return authentication.equals(UsernamePasswordAuthenticationToken.class);
+	}
+}

+ 198 - 0
src/main/java/com/its/bis/webapp/service/FileService.java

@@ -0,0 +1,198 @@
+package com.its.bis.webapp.service;
+
+import com.its.app.utils.OS;
+import com.its.bis.webapp.vo.FileInfoVo;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.json.JSONObject;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.core.io.Resource;
+import org.springframework.http.ContentDisposition;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@Service
+public class FileService {
+    private final String logDir= "/logs/";
+    private final String sysDir= System.getProperty("user.dir");
+    private final String[] exceptDir ={"backup"};
+    private int id = 1;
+
+    public String getView(HttpServletRequest request, String fileName, String filePath) {
+        long preEndPoint = request.getParameter("preEndPoint") == null ? 0 : Long.parseLong(request.getParameter("preEndPoint") + "");
+        StringBuilder sb = new StringBuilder();
+        long startPoint, endPoint;
+        RandomAccessFile file = null;
+        String errMsg = "";
+
+        try {
+            file = new RandomAccessFile(System.getProperty("user.dir") + filePath + fileName, "r");
+            endPoint = file.length();
+            startPoint = preEndPoint > 0 ? preEndPoint : endPoint < 2000 ? 0 : endPoint - 2000;
+            file.seek(startPoint);
+
+            String str;
+            while ((str = file.readLine()) != null) {
+                byte[] b = str.getBytes("iso-8859-1");
+                str = new String(b, "UTF-8");
+                sb.append(str);
+                sb.append("<br>");
+                endPoint = file.getFilePointer();
+                file.seek(endPoint);
+            }
+
+            JSONObject json = new JSONObject();
+            json.put("endPoint", endPoint);
+            json.put("log", sb.toString());
+            return json.toString();
+        }
+        catch(FileNotFoundException fnf) {
+            log.error("FileService.getView: Exception: {}", fnf.toString());
+            errMsg += fnf.toString();
+        }
+        catch (IOException e) {
+            log.error(e.getMessage());
+            errMsg += e.toString();
+        }
+        finally {
+            try {
+                if (file != null) file.close();
+            }
+            catch (Exception e) {
+                log.error("FileService.getView: Exception: {}", e.toString());
+                errMsg += e.toString();
+            }
+        }
+
+        if (!errMsg.equals("")) {
+            sb.append(errMsg);
+            sb.append("<br>");
+            JSONObject json = new JSONObject();
+            json.put("endPoint", 0);
+            json.put("log", sb.toString());
+            return json.toString();
+        }
+        return null;
+    }
+
+    public ResponseEntity<Resource> fileDownload(String fileName, String filePath){
+        try {
+            Path path = Paths.get(System.getProperty("user.dir")+filePath+ fileName);
+            String contentType = "application/download";
+            HttpHeaders headers = new HttpHeaders();
+            headers.add(HttpHeaders.CONTENT_TYPE, contentType);
+            headers.setContentDisposition(ContentDisposition.parse("attachment;" + " filename=\"" + fileName + "\";"));
+            Resource resource = new InputStreamResource(Files.newInputStream(path));
+
+            return new ResponseEntity<>(resource, headers, HttpStatus.OK);
+        }
+        catch (IOException e) {
+            log.error("FileService.fileDownload: Exception: {}", e.toString());
+        }
+        return null;
+    }
+
+    public void fileDelete(String fileName,String filePath) {
+        File file = new File(this.sysDir+filePath+fileName);
+        if (file.exists()) {
+            if (file.delete()) {
+                log.info("FileService.fileDelete: Delete Success: {}", filePath+fileName);
+            }
+            else {
+                log.error("FileService.fileDelete: Delete Fail: {}", filePath+fileName);
+            }
+        }
+        else {
+            log.warn("FileService.fileDelete: Not exists: {}", filePath+fileName);
+        }
+    }
+
+    public List<FileInfoVo> getLogFiles() {
+        this.id = 1;
+        FileInfoVo rootFile = new FileInfoVo();
+        rootFile.setId(id);
+        rootFile.setType("dir");
+        this.id++;
+        rootFile.setFileName("logs");
+        rootFile.setFileInfos(getFiles(this.sysDir, this.logDir));
+        List<FileInfoVo> fileInfos = new ArrayList<>();
+        fileInfos.add(rootFile);
+        return fileInfos;
+    }
+
+    private List<FileInfoVo> getFiles(String sysDir, String logDir) {
+        int rootId = id - 1;
+        //log.debug("FileService.getFiles: id: {}, sysDir: {}, logDir: {}", id, sysDir, logDir);
+        List<FileInfoVo> subArr = new ArrayList<>();
+        File dirFile = new File(sysDir, logDir);
+        File[] fileList = dirFile.listFiles();
+
+        for (File file: fileList) {
+            FileInfoVo info = new FileInfoVo();
+            //log.debug("FileService.getFiles: getName: {}, isDir: {}, getPath: {}", file.getName(), file.isDirectory(), file.getPath());
+
+            if (file.isDirectory()) {
+                for (String dir : exceptDir) {
+                    if (dir.equals(file.getName())) {
+                        break;
+                    }
+                    else {
+                        String subDir = file.getPath().substring(file.getPath().indexOf(logDir.replaceAll("/", "")), file.getPath().length());
+                        info.setId(id);
+                        id++;
+                        String sFileSeparator = "/";
+                        info.setFilePath(sFileSeparator + subDir);
+                        info.setFileName(file.getName());
+                        info.setFileSize(file.length());
+                        info.setType("dir");
+
+                        info.setFileInfos(getFiles(sysDir,  subDir));
+                        info.setParentId(rootId);
+                        //log.info(info.toString());
+                        subArr.add(info);
+                    }
+                }
+            }
+        }
+
+        //log.debug("x: {}", fileList.toString());
+        for (File file: fileList) {
+            FileInfoVo info = new FileInfoVo();
+            if (file.isFile() && file.getName().contains(".log")) {
+                info.setId(id);
+                id++;
+                info.setFileName(file.getName());
+                info.setFileSize(file.length());
+                String subDir;
+                if (OS.isWindows()) {
+                    subDir = file.getPath().substring(file.getPath().indexOf(logDir.replaceAll("/","")), file.getPath().length() - file.getName().length()).replaceAll("\\\\", "/");
+                } else {
+                    subDir = file.getPath().substring(file.getPath().indexOf(logDir), file.getPath().length() - file.getName().length()).replaceAll("\\\\", "/");
+                }
+
+                String sFileSeparator = "/";
+                info.setFilePath(sFileSeparator + subDir);
+                info.setType("log");
+                info.setParentId(rootId);
+                //log.info(info.toString());
+                subArr.add(info);
+            }
+        }
+        //log.debug("y: {}", subArr.toString());
+        return subArr;
+    }
+
+}

+ 40 - 0
src/main/java/com/its/bis/webapp/service/UserService.java

@@ -0,0 +1,40 @@
+package com.its.bis.webapp.service;
+
+import com.its.bis.webapp.vo.UserVo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@Service
+public class UserService implements UserDetailsService {
+
+    @Value("${server.user.id:admin}")
+    private String userId;
+    @Value("${server.user.pswd:1234}")
+    private String userPswd;
+
+    @Override
+    public UserVo loadUserByUsername(String username) throws UsernameNotFoundException {
+
+        String userId = this.userId;
+        String userPswd = this.userPswd;
+        UserVo user = new UserVo(userId,"{noop}"+userPswd);
+        if (user == null) {
+            throw new UsernameNotFoundException("No user found with "+username + user.getUsername());
+        }
+
+        //디비에서 권한 가져와야하는데 고정으로 넣어줌
+        List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>();
+        roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
+        user.setAuthorities(roles);
+        return user;
+    }
+}

+ 19 - 0
src/main/java/com/its/bis/webapp/vo/FileInfoVo.java

@@ -0,0 +1,19 @@
+package com.its.bis.webapp.vo;
+
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@ToString
+public class FileInfoVo {
+    private List<FileInfoVo> fileInfos = new ArrayList<>();
+    private int    id;
+    private int    parentId;
+    private String type;
+    private String fileName;
+    private long   fileSize;
+    private String filePath;
+}

+ 51 - 0
src/main/java/com/its/bis/webapp/vo/UserVo.java

@@ -0,0 +1,51 @@
+package com.its.bis.webapp.vo;
+
+import lombok.Data;
+import lombok.ToString;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@ToString
+public class UserVo implements UserDetails {
+    private String id;
+    private String password;
+    private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+
+    public UserVo(String id, String password){
+        this.id = id;
+        this.password = password;
+    }
+
+    public UserVo() {
+
+    }
+
+    @Override
+    public String getUsername() {
+        return id;
+    }
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return true;
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+}

+ 3 - 1
src/main/resources/application.yml

@@ -2,7 +2,7 @@ spring:
   application:
     name: agip-comm-server
   main:
-    #web-application-type: none
+#    web-application-type: none
     log-startup-info: true
     banner-mode: off
   mvc:
@@ -46,6 +46,8 @@ server:
   servlet:
     session:
       timeout: 300
+  max-distance: 20
+  max-trvl-min: 60
 
 application:
   id: BIS01

+ 1 - 0
src/main/resources/mybatis/mapper/NodeLinkMapper.xml

@@ -30,6 +30,7 @@
                A.LINK_LENG,
                A.DEL_YN
         FROM TB_LINK A
+       WHERE A.LINK_LENG > 1
         ]]>
     </select>
 

+ 83 - 7
src/test/java/com/its/app/AgipCommServerApplicationTests.java

@@ -4,7 +4,6 @@ import com.its.app.utils.ItsUtils;
 import com.its.app.utils.SysUtils;
 import com.its.bis.AgipCommServerApplication;
 import com.its.bis.dto.Location;
-import com.its.bis.service.NodeLinkService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
@@ -32,12 +31,12 @@ public class AgipCommServerApplicationTests {
 
     @Test
     void getNearNode() {
-        NodeLinkService nodeLinkService = (NodeLinkService)AppUtils.getBean(NodeLinkService.class);
-        Location from = Location.builder()
-                .mLatitude(128.74352336)
-                .mLongitude(36.56392018)
-                .build();
-        log.error("{}", nodeLinkService.getNearNode(from));
+//        NodeLinkService nodeLinkService = (NodeLinkService)AppUtils.getBean(NodeLinkService.class);
+//        Location from = Location.builder()
+//                .mLatitude(128.74352336)
+//                .mLongitude(36.56392018)
+//                .build();
+//        log.error("{}", nodeLinkService.getNearNode(from));
     }
 
     @Test
@@ -250,4 +249,81 @@ public class AgipCommServerApplicationTests {
 //        log.info("{}", crc);
     }
 
+//[
+//    {
+//        "tenant": {
+//        "entityStatus": null,
+//                "regUser": null,
+//                "regDate": null,
+//                "modUser": null,
+//                "modDate": null,
+//                "entityId": null,
+//                "name": "test2",
+//                "alias": "test2",
+//                "description": null,
+//                "logoType": null,
+//                "logo1Token": null,
+//                "logo1ImageUrl": null,
+//                "logo2Token": null,
+//                "logo2ImageUrl": null
+//    },
+//        "deviceName": "LOADER-VOD-36687",
+//            "productName": null,
+//            "modelName": null,
+//            "deviceIdType": null,
+//            "deviceId": "6D-45-C4-08-AA-B6",
+//            "deviceToken": "a738fcf994e14d8cbb99e4db244a687c",
+//            "deviceStatus": "ACTIVE",
+//            "deviceType": "ROVER",
+//            "deviceClassification": "A05_ETC",
+//            "lastConnectionStatus": "CONNECTED",
+//            "lastConnectionDatetime": 1619505455498,
+//            "gnssInfo": {
+//        "deviceId": "6D-45-C4-08-AA-B6",
+//                "deviceTime": 1619505737630,
+//                "type": "nmea",
+//                "raw": "$GPGGA,064217.63,3729.1261326,N,12653.6691112,E,1,00,1.0,19.203,M,0.000,M,0.0,*4C\r\n$GNRMC,064217.63,A,3729.1261326,N,12653.6691112,E,1.34,250.29,270421,0.0,E,A,V*5F\r\n$GNVTG,250.29,T,,M,1.339,N,2.480,K,D*2C\r\n$GNGST,064217.63,10,1.000,1.000,1.000,0.700,5.960,8.770*61\r",
+//                "hertz": 0,
+//                "latitude": 37.48543554333333,
+//                "longitude": 126.89448518666667,
+//                "height": 19.203,
+//                "speed": 2.48,
+//                "angle": 250.29,
+//                "pdop": 0,
+//                "fixStatus": "NORMAL",
+//                "baseStation": "UNKNOWN",
+//                "rmsX": 5.96,
+//                "rmsY": 0.7,
+//                "rmsZ": 8.77,
+//                "ecefX": -3042181.7143300786,
+//                "ecefY": 4052617.9642652427,
+//                "ecefZ": 3860293.232899369,
+//                "satellites": []
+//    },
+//        "healthInfo": {
+//        "deviceId": "6D-45-C4-08-AA-B6",
+//                "osFamily": "Raspbian GNU/Linux",
+//                "osVersion": "10",
+//                "cpuUsage": 14.85,
+//                "freeMemory": 697125639,
+//                "totalMemory": 970825728,
+//                "freeStorage": {
+//            "/": 61164593113
+//        },
+//        "totalStorage": {
+//            "/": 62738714624
+//        },
+//        "temperature": 50.7,
+//                "bettery": 72,
+//                "networkType": "ETHERNET",
+//                "collectedDate": null
+//    },
+//        "satelliteCount": 0,
+//            "carId": null,
+//            "carNumber": null,
+//            "routeId": null,
+//            "runStatus": null
+//    }
+//]
+
 }