From 6e4576934f143f18214c2d0e1821440d42d49e8e Mon Sep 17 00:00:00 2001 From: mjkhan21 Date: Wed, 30 Aug 2023 15:03:55 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B5=9C=EC=B4=88=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/libgpkiapi_jni_1.5.jar | Bin 0 -> 58217 bytes pom.xml | 154 +++++++ .../service/DisabledParkingService.java | 22 + .../service/bean/DisabledParkingBean.java | 278 ++++++++++++ .../bean/DisabledParkingServiceBean.java | 30 ++ .../disabledparking/service/bean/GPKI.java | 419 ++++++++++++++++++ .../web/DisabledParkingController.java | 47 ++ src/main/resources/.gitignore | 3 + .../resources/intf-conf/disabled-parking.conf | 16 + src/main/resources/intf-conf/gpki.conf | 24 + .../template/disabled-parking-request.xml | 20 + .../service/DisabledParkingServiceTest.java | 57 +++ 12 files changed, 1070 insertions(+) create mode 100644 lib/libgpkiapi_jni_1.5.jar create mode 100644 pom.xml create mode 100644 src/main/java/cokr/xit/interfaces/disabledparking/service/DisabledParkingService.java create mode 100644 src/main/java/cokr/xit/interfaces/disabledparking/service/bean/DisabledParkingBean.java create mode 100644 src/main/java/cokr/xit/interfaces/disabledparking/service/bean/DisabledParkingServiceBean.java create mode 100644 src/main/java/cokr/xit/interfaces/disabledparking/service/bean/GPKI.java create mode 100644 src/main/java/cokr/xit/interfaces/disabledparking/web/DisabledParkingController.java create mode 100644 src/main/resources/.gitignore create mode 100644 src/main/resources/intf-conf/disabled-parking.conf create mode 100644 src/main/resources/intf-conf/gpki.conf create mode 100644 src/main/resources/template/disabled-parking-request.xml create mode 100644 src/test/java/cokr/xit/interfaces/disabledparking/service/DisabledParkingServiceTest.java diff --git a/lib/libgpkiapi_jni_1.5.jar b/lib/libgpkiapi_jni_1.5.jar new file mode 100644 index 0000000000000000000000000000000000000000..5e3bdea4ffc1799cf3273f71b86a406c176d8eb3 GIT binary patch literal 58217 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 literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..17ddf1a --- /dev/null +++ b/pom.xml @@ -0,0 +1,154 @@ + + 4.0.0 + + cokr.xit.interfaces + xit-disabled-parking + 23.04.01-SNAPSHOT + jar + + xit-disabled-parking + http://maven.apache.org + + + UTF-8 + + 17 + ${java.version} + ${java.version} + + + + + mvn2s + https://repo1.maven.org/maven2/ + + true + + + true + + + + egovframe + https://maven.egovframe.go.kr/maven/ + + true + + + false + + + + maven-public + https://nas.xit.co.kr:8888/repository/maven-public/ + + + + + + + cokr.xit.base + xit-foundation + 23.04.01-SNAPSHOT + + + + libgpkiapi_jni_1.5 + libgpkiapi_jni_1.5 + 1.0 + system + ${project.basedir}/lib/libgpkiapi_jni_1.5.jar + + + + org.mariadb.jdbc + mariadb-java-client + 2.7.2 + + + + + install + ${basedir}/target + ${artifactId}-${version} + + + ${basedir}/src/main/resources + + + ${basedir}/src/test/resources + ${basedir}/src/main/resources + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + **/*.class + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0 + + true + xml + + **/Abstract*.java + **/*Suite.java + + + **/*Test.java + + + + + org.codehaus.mojo + emma-maven-plugin + true + + + org.apache.maven.plugins + maven-source-plugin + 2.2 + + + attach-sources + + jar + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + + + + + + + maven-snapshot + https://nas.xit.co.kr:8888/repository/maven-snapshots/ + + + + maven-release + https://nas.xit.co.kr:8888/repository/maven-releases/ + + + + + diff --git a/src/main/java/cokr/xit/interfaces/disabledparking/service/DisabledParkingService.java b/src/main/java/cokr/xit/interfaces/disabledparking/service/DisabledParkingService.java new file mode 100644 index 0000000..33b622e --- /dev/null +++ b/src/main/java/cokr/xit/interfaces/disabledparking/service/DisabledParkingService.java @@ -0,0 +1,22 @@ +package cokr.xit.interfaces.disabledparking.service; + +import java.util.List; + +import cokr.xit.foundation.data.DataObject; + +/**장애인 표지 조회 서비스 인터페이스 + * @author mjkhan + */ +public interface DisabledParkingService { + /**지정한 차량번호의 장애인 표지 여부를 조회한다. + * @param vehicleNo 차량번호 + * @return 지정한 차량번호의 장애인 표지 여부 + */ + DataObject getParkingInfo(String vehicleNo); + + /**지정한 차량번호들의 장애인 표지 여부를 조회한다. + * @param vehicleNos 차량번호 + * @return 지정한 차량번호의 장애인 표지 여부 + */ + List getParkingList(String... vehicleNos); +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/DisabledParkingBean.java b/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/DisabledParkingBean.java new file mode 100644 index 0000000..c5aa5a1 --- /dev/null +++ b/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/DisabledParkingBean.java @@ -0,0 +1,278 @@ +package cokr.xit.interfaces.disabledparking.service.bean; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.http.HttpResponse; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Stream; + +import javax.xml.parsers.DocumentBuilderFactory; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; +import org.springframework.util.FileCopyUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import cokr.xit.foundation.AbstractComponent; +import cokr.xit.foundation.data.DataObject; +import cokr.xit.foundation.data.JSON; +import cokr.xit.foundation.web.WebClient; + +/**장애인 표지 조회 Bean. 올바로 동작하려면 + *

+ * 을 설정해야 한다. + * @author mjkhan + */ +@Component("disabledParkingBean") +public class DisabledParkingBean extends AbstractComponent { + private static final String template; + private static final Config conf = Config.get(); + + static { + ClassPathResource resource = new ClassPathResource(conf.template); + try ( + InputStream input = resource.getInputStream(); + InputStreamReader reader = new InputStreamReader(input); + ) { + template = FileCopyUtils.copyToString(reader); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private GPKI gpki = new GPKI(); + + /**지정한 차량번호의 장애인 표지 여부를 조회한다. + * @param vehicleNo 차량번호 + * @return 지정한 차량번호의 장애인 표지 여부 + */ + public DataObject getParkingInfo(String vehicleNo) { + String xml = template + .replace("{carsNo}", vehicleNo) + .replace("{transactionID}", getTransactionID()); + + String params = parse(xml, conf.getRequest()), + encrypted = gpki.encrypt(conf.getTargetServer(), params); + log().debug("params:\n{}", params); + + xml = xml.replace(params, encrypted); + + String + hresp = request(xml), + parsed = parse(hresp, conf.getResponse()), + decrypted = gpki.decrypt(parsed); + hresp = hresp.replace(parsed, decrypted); + log().debug("response:\n{}", hresp.replace("><", ">\n<")); + + return toMap(hresp); + } + + /**지정한 차량번호들의 장애인 표지 여부를 조회한다. + * @param vehicleNos 차량번호 + * @return 지정한 차량번호의 장애인 표지 여부 + */ + public List getParkingList(String... vehicleNos) { + if (isEmpty(vehicleNos)) + return Collections.emptyList(); + + return Stream.of(vehicleNos) + .distinct() + .map(this::getParkingInfo) + .toList(); + } + + private String request(String xml) { + HttpResponse hresp = new WebClient().post(req -> + req.uri(conf.serviceUrl) + .contentType(WebClient.Request.ContentType.XML) + .header("Connection", "close") + .bodyData(xml) + + ); + return hresp.body(); + } + + private static String getTransactionID() { + return new SimpleDateFormat("yyyyMMddHHmmssSSS", Locale.KOREA).format(new Date()) + + Double.toString(Math.random()).substring(2, 6) + + Double.toString(Math.random()).substring(2, 6); + } + + private static String parse(String str, Map range) { + return str + .split(range.get("start"))[1] + .split(range.get("end"))[0]; + } + + private static DataObject toMap(String xml) { + try ( + StringReader reader = new StringReader(xml); + ) { + Document doc = DocumentBuilderFactory + .newInstance() + .newDocumentBuilder() + .parse(new InputSource(reader)); + + DataObject result = new DataObject(); + + NodeList nodes = doc.getElementsByTagName("getDisabledParkingYnResponse"); + for (int i = 0, length = nodes.getLength(); i < length; ++i) { + Node node = nodes.item(i); + if (node.getNodeType() != Node.ELEMENT_NODE) continue; + + NodeList children = node.getChildNodes(); + for (int j = 0, count = children.getLength(); j < count; ++j) { + Node child = children.item(j); + if (child.getNodeType() != Node.ELEMENT_NODE) continue; + + Element element = (Element)child; + result.set(element.getTagName(), element.getTextContent()); + } + } + + return result; + } catch (Exception e) { + throw runtimeException(e); + } + } + + /**장애인 표지 조회 설정. + * 설정 항목은 intf-conf/disabled-parking.conf 파일의 JSON 포맷으로 된 다음 내용을 적재한다. + *
 {
+	 *     "template": "장애인 표지 조회를 위한 요청 xml 템플릿의 클래스패스 상의 경로",
+	 *     "serviceUrl": "장애인 표지 조회 서비스 url",
+	 *     "targetServer": "장애인 표지 조회 서버 아이디(인증키)",
+	 *     "request": {
+	 *         "start": "요청 xml의 파라미터 시작 태그",
+	 *         "end": "요청 xml의 파라미터 끝 태그"
+	 *     },
+	 *     "response": {
+	 *         "start": "응답 xml의 데이터 시작 태그",
+	 *         "end": "응답 xml의 데이터 끝 태그"
+	 *     }
+	 * }
+ * 요청 xml 템플릿(template/disabled-parking-request.xml)으로는 다음 내용을 설정한다. + *
  • commonHeader + *
    • serviceName - 서비스 이름
    • + *
    • useSystemCode - 이용 시스템 코드
    • + *
    • certServerId - 이용기관 GPKI 서버인증서 아이디
    • + *
    • transactionUniqueId - {transactionID}, 프로그램이 생성하는 트랜잭션 아이디, 수정금지
    • + *
    • userDeptCode - 이용자 부서코드
    • + *
    • userName - 이용자 이름
    • + *
    + *
  • + *
  • Body / getDisabledParkingYn + *
    • ReqOrgCd - 요청기관 코드
    • + *
    • ReqBizCd - 요청업무 코드
    • + *
    • CARS_NO - {carsNo}, 이용자가 프로그램으로 전달하는 차량번호, 수정금지
    • + *
    + *
  • + *
+ * @author mjkhan + */ + public static class Config extends AbstractComponent { + private static Config conf; + + public static Config get() { + if (conf == null) + try { + ClassPathResource res = new ClassPathResource("intf-conf/disabled-parking.conf"); + conf = new JSON().parse(res.getInputStream(), Config.class); + } catch (Exception e) { + throw runtimeException(e); + } + return conf; + } + + private String + template, + serviceUrl, + targetServer; + private Map + request, + response; + + /**요청 xml의 클래스패스 상의 경로를 반환한다. + * @return 요청 xml의 클래스패스 상의 경로 + */ + public String getTemplate() { + return template; + } + + /**요청 xml의 클래스패스 상의 경로를 설정한다. + * @param template 요청 xml의 클래스패스 상의 경로 + */ + public void setTemplate(String template) { + this.template = template; + } + + /**장애인 표지 조회 서비스 url을 반환한다. + * @return 장애인 표지 조회 서비스 url + */ + public String getServiceUrl() { + return serviceUrl; + } + + /**장애인 표지 조회 서비스 url을 설정한다. + * @param serviceUrl 장애인 표지 조회 서비스 url + */ + public void setServiceUrl(String serviceUrl) { + this.serviceUrl = serviceUrl; + } + + /**장애인 조회 서버 아이디(키)를 반환한다. + * @return 장애인 조회 서버 아이디(키) + */ + public String getTargetServer() { + return targetServer; + } + + /**장애인 조회 서버 아이디(키)를 설정한다. + * @param targetServer 장애인 조회 서버 아이디(키) + */ + public void setTargetServer(String targetServer) { + this.targetServer = targetServer; + } + + /**요청 xml의 파라미터의 시작과 끝 태그를 반환한다. + * @return 요청 xml의 파라미터의 시작과 끝 태그 + */ + public Map getRequest() { + return request; + } + + /**요청 xml의 파라미터의 시작과 끝 태그를 설정한다. + * @param request 요청 xml의 파라미터의 시작과 끝 태그 + */ + public void setRequest(Map request) { + this.request = request; + } + + /**요청 xml의 결과값의 시작과 끝 태그를 반환한다. + * @return 요청 xml의 결과값의 시작과 끝 태그 + */ + public Map getResponse() { + return response; + } + + /**요청 xml의 결과값의 시작과 끝 태그를 설정한다. + * @param response 요청 xml의 결과값의 시작과 끝 태그 + */ + public void setResponse(Map response) { + this.response = response; + } + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/DisabledParkingServiceBean.java b/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/DisabledParkingServiceBean.java new file mode 100644 index 0000000..72cd5a0 --- /dev/null +++ b/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/DisabledParkingServiceBean.java @@ -0,0 +1,30 @@ +package cokr.xit.interfaces.disabledparking.service.bean; + +import java.util.List; + +import javax.annotation.Resource; + +import org.springframework.stereotype.Service; + +import cokr.xit.foundation.component.AbstractServiceBean; +import cokr.xit.foundation.data.DataObject; +import cokr.xit.interfaces.disabledparking.service.DisabledParkingService; + +/**장애인 표지 조회 서비스 구현체 + * @author mjkhan + */ +@Service("disabledParkingService") +public class DisabledParkingServiceBean extends AbstractServiceBean implements DisabledParkingService { + @Resource(name = "disabledParkingBean") + private DisabledParkingBean bean; + + @Override + public DataObject getParkingInfo(String vehicleNo) { + return bean.getParkingInfo(vehicleNo); + } + + @Override + public List getParkingList(String... vehicleNos) { + return bean.getParkingList(vehicleNos); + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/GPKI.java b/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/GPKI.java new file mode 100644 index 0000000..3674357 --- /dev/null +++ b/src/main/java/cokr/xit/interfaces/disabledparking/service/bean/GPKI.java @@ -0,0 +1,419 @@ +package cokr.xit.interfaces.disabledparking.service.bean; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.IntSupplier; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.springframework.core.io.ClassPathResource; + +import com.gpki.gpkiapi_jni; +import com.gpki.gpkiapi.GpkiApi; +import com.gpki.gpkiapi.cert.X509Certificate; +import com.gpki.gpkiapi.exception.GpkiApiException; +import com.gpki.gpkiapi.storage.Disk; + +import cokr.xit.foundation.AbstractComponent; +import cokr.xit.foundation.data.JSON; + +/**GPKI(행정전자서명) API 유틸리티. 올바로 동작하려면 {@link Config intf-conf/gpki.conf}를 설정해야 한다. + * @author mjkhan + */ +public class GPKI extends AbstractComponent { + private static final Config conf = Config.get(); + private static final HashMap serverCerts = new HashMap<>(); + private static byte[] + envCert, + envKey, + sigCert, + sigKey; + + private gpkiapi_jni gpki; + + static { + init(); + } + + /**주어진 문자열을 지정한 아이디의 서버인증서로 암호화하여 반환한다. + * @param serverID 서버인증서 아이디 + * @param data 문자열 + * @return 지정한 아이디의 서버인증서로 암호화한 문자열 + */ + public String encrypt(String serverID, String data) { + if (isEmpty(data)) return ""; + + try { + start(); + + byte[] encrypted = encrypt(serverID, data.getBytes(conf.getCharset())); + return encode(sign(encrypted)); + } catch (Exception e) { + throw runtimeException(e); + } finally { + finish(); + } + } + + /**주어진 암호화된 문자열을 복호화하여 반환한다. + * @param encrypted 암호화된 문자열 + * @return 복호화한 문자열 + */ + public String decrypt(String encrypted) { + if (isEmpty(encrypted)) return ""; + + try { + start(); + + byte[] validated = validate(decode(encrypted)); + return new String(decrypt(validated), conf.getCharset()); + } catch (Exception e) { + throw runtimeException(e); + } finally { + finish(); + } + } + + private static void call(gpkiapi_jni gpki, IntSupplier task, String msg) throws Exception { + int result = task.getAsInt(); + if (result == 0) return; + + String message = isEmpty(msg) ? "" : msg + ": "; + message += gpki != null ? gpki.sDetailErrorString : "errorCode = " + result; + + throw new Exception(message); + } + + private static void init() { + try { + GpkiApi.init(conf.license); + gpkiapi_jni gpki = getGpki(); + call(gpki, () -> gpki.API_GetInfo(), null); + + for (String serverID: conf.getTargetServers()) + load(gpki, serverID); + + envCert = Disk.readCert(conf.getCertFile("env")).getCert(); + envKey = Disk.readPriKey(conf.getPrivateKeyFile("env"), conf.getPrivateKeyPassword("env")).getKey(); + + sigCert = Disk.readCert(conf.getCertFile("sig")).getCert(); + sigKey = Disk.readPriKey(conf.getPrivateKeyFile("sig"), conf.getPrivateKeyPassword("sig")).getKey(); + + finish(gpki); + } catch (Exception e) { + throw runtimeException(e); + } + } + + private static gpkiapi_jni getGpki() throws Exception{ + gpkiapi_jni gpki = new gpkiapi_jni(); + call(gpki, () -> gpki.API_Init(conf.license), null); + return gpki; + } + + private static void finish(gpkiapi_jni gpki) { + if (gpki == null) return; + + try { + call(gpki, () -> gpki.API_Finish(), null); + } catch (Exception e) { + throw runtimeException(e); + } + } + + private static void load(gpkiapi_jni gpki, String serverID) throws Exception { + X509Certificate cert = null; + String certFile = conf.certDir + File.separator + serverID + ".cer"; + try { + cert = Disk.readCert(certFile); + } catch (GpkiApiException e) { + cert = null; + } + + if (cert == null && !isEmpty(conf.ldapUrl)) { + String uri = serverID.charAt(3) > '9' ? + ",ou=Group of Server,o=Public of Korea,c=KR" : + ",ou=Group of Server,o=Government of Korea,c=KR"; + + call(gpki, + () -> gpki.LDAP_GetAnyDataByURL("userCertificate;binary", conf.ldapUrl + serverID + uri), + null + ); + + cert = new X509Certificate(gpki.baReturnArray); + Disk.writeCert(certFile, cert); + } + + if (cert != null) + serverCerts.put(serverID, cert); + } + + private static X509Certificate getCert(String serverID) { + X509Certificate cert = serverCerts.get(serverID); + if (cert == null) + throw new RuntimeException(String.format("%s not found for %s", X509Certificate.class.getSimpleName(), serverID)); + return cert; + } + + private T call(IntSupplier work, Supplier result, String message) { + boolean finish = start(); + + try { + call(gpki, work, message); + return result.get(); + } catch (Exception e) { + throw runtimeException(e); + } finally { + if (finish) + finish(); + } + } + + private byte[] encrypt(String serverID, byte[] data) { + return call( + () -> { + X509Certificate cert = getCert(serverID); + return gpki.CMS_MakeEnvelopedData(cert.getCert(), data, gpkiapi_jni.SYM_ALG_NEAT_CBC); + }, + () -> gpki.baReturnArray, + "Encryption failed" + ); + } + + private byte[] decrypt(byte[] encrypted) { + return call( + () -> gpki.CMS_ProcessEnvelopedData(envCert, envKey, encrypted), + () -> gpki.baReturnArray, + "Decryption failed" + ); + } + + private byte[] sign(byte[] data) { + return call( + () -> gpki.CMS_MakeSignedData(sigCert, sigKey, data, null), + () -> gpki.baReturnArray, + "Fail to sign message" + ); + } + + private byte[] validate(byte[] signed) { + return call( + () -> gpki.CMS_ProcessSignedData(signed), + () -> gpki.baData, + "Validation failed" + ); + } + + private String encode(byte[] data) { + return call( + () -> gpki.BASE64_Encode(data), + () -> gpki.sReturnString, + "Encoding failed" + ); + } + + private byte[] decode(String encoded) { + return call( + () -> gpki.BASE64_Decode(encoded), + () -> gpki.baReturnArray, + "Decoding failed" + ); + } + + private boolean start() { + if (gpki != null) return false; + + try { + gpki = getGpki(); + return true; + } catch (Exception e) { + throw runtimeException(e); + } + } + + private void finish() { + if (gpki == null) return; + + finish(gpki); + gpki = null; + } + + /**GPKI 설정파일(intf-conf/gpki.conf)을 로드한다. + * 설정 항목은 JSON 포맷으로 된 다음 내용을 적재한다. + *
 {
+	 *     "license": "이용기관 GPKI API 라이센스 디렉토리",
+	 *     "charset": "문자셋",
+	 *     "server": {
+	 *         "local": "이용기관 서버 CN",
+	 *         "targets": "대상기관 서버인증서 아이디, 여러 개일 경우 컴마(,)로 구분"
+	 *     },
+	 *     "ldapUrl": "대상기관 인증서 다운로드를 위한 LDAP URL",
+	 *     "certDir": "서버 인증서, 키 저장 디렉토리",
+	 *     "env": {
+	 *         "certFile": "이용기관 서버 인증서 파일",
+	 *         "privateKeyFile": "이용기관 서버 인증서 키 파일",
+	 *         "privateKeyPassword": "이용기관 서버 인증서 비밀번호"
+	 *     },
+	 *     "sig": {
+	 *         "certFile": "이용기관 서버 전자서명 파일",
+	 *         "privateKeyFile": "이용기관 서버 전자서명 키 파일",
+	 *         "privateKeyPassword": "이용기관 서버 전자서명 비밀번호"
+	 *     }
+	 * }
+ * @author mjkhan + */ + public static class Config extends AbstractComponent { + private static Config conf; + + public static Config get() { + if (conf == null) + try { + ClassPathResource res = new ClassPathResource("intf-conf/gpki.conf"); + conf = new JSON().parse(res.getInputStream(), Config.class); + } catch (Exception e) { + throw runtimeException(e); + } + return conf; + } + + private String + charset, + license, + ldapUrl, + certDir; + private Map + server, + env, + sig; + + /**charset을(를) 반환한다. + * @return charset + */ + public String getCharset() { + return charset; + } + + /**charset을(를) 설정한다. + * @param charset charset + */ + public void setCharset(String charset) { + this.charset = charset; + } + + /**license을(를) 반환한다. + * @return license + */ + public String getLicense() { + return license; + } + + /**license을(를) 설정한다. + * @param license license + */ + public void setLicense(String license) { + this.license = license; + } + + /**ldapUrl을(를) 반환한다. + * @return ldapUrl + */ + public String getLdapUrl() { + return ldapUrl; + } + + /**ldapUrl을(를) 설정한다. + * @param ldapUrl ldapUrl + */ + public void setLdapUrl(String ldapUrl) { + this.ldapUrl = ldapUrl; + } + + /**certDir을(를) 반환한다. + * @return certDir + */ + public String getCertDir() { + return certDir; + } + + /**certDir을(를) 설정한다. + * @param certDir certDir + */ + public void setCertDir(String certDir) { + this.certDir = certDir; + } + + /**server을(를) 반환한다. + * @return server + */ + public Map getServer() { + return ifEmpty(server, Collections::emptyMap); + } + + public String getLocalServer() { + return getServer().get("local"); + } + + public List getTargetServers() { + String targets = ifEmpty(getServer().get("targets"), ""); + return Stream.of(targets.split(",")).map(String::trim).toList(); + } + + /**server을(를) 설정한다. + * @param server server + */ + public void setServer(Map server) { + this.server = server; + } + + /**env을(를) 반환한다. + * @return env + */ + public Map getEnv() { + return ifEmpty(env, Collections::emptyMap); + } + + /**env을(를) 설정한다. + * @param env env + */ + public void setEnv(Map env) { + this.env = env; + } + + /**sig을(를) 반환한다. + * @return sig + */ + public Map getSig() { + return ifEmpty(sig, Collections::emptyMap); + } + + /**sig을(를) 설정한다. + * @param sig sig + */ + public void setSig(Map sig) { + this.sig = sig; + } + + private Map getCredentials(String type) { + switch (type) { + case "env": return getEnv(); + case "sig": return getSig(); + default: throw new IllegalArgumentException(type); + } + } + + public String getCertFile(String type) { + return certDir + File.separator + getCredentials(type).get("certFile"); + } + + public String getPrivateKeyFile(String type) { + return certDir + File.separator + getCredentials(type).get("privateKeyFile"); + } + + public String getPrivateKeyPassword(String type) { + return getCredentials(type).get("privateKeyPassword"); + } + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/interfaces/disabledparking/web/DisabledParkingController.java b/src/main/java/cokr/xit/interfaces/disabledparking/web/DisabledParkingController.java new file mode 100644 index 0000000..9378711 --- /dev/null +++ b/src/main/java/cokr/xit/interfaces/disabledparking/web/DisabledParkingController.java @@ -0,0 +1,47 @@ +package cokr.xit.interfaces.disabledparking.web; + +import javax.annotation.Resource; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +import cokr.xit.foundation.web.AbstractController; +import cokr.xit.interfaces.disabledparking.service.DisabledParkingService; + +/**장애인 표지 조회 서비스 컨트롤러 + * @author mjkhan + */ +@Controller("disabledParkingApi") +@RequestMapping("/api/disabledParking") +public class DisabledParkingController extends AbstractController { + @Resource(name = "disabledParkingService") + private DisabledParkingService service; + + /**지정한 차량번호의 장애인 표지 여부를 조회한다. + * @param vehicleNo 차량번호 + * @return "jsonView" + *
 {
+	 *     "parkingInfo": "장애인 표지 정보"
+	 * }
+ */ + @GetMapping(name = "장애인 표지 조회", value = "/parkingInfo.do") + public ModelAndView getParkingInfo(String vehicleNo) { + return new ModelAndView("jsonView") + .addObject("parkingInfo", service.getParkingInfo(vehicleNo)); + } + + /**지정한 차량번호들의 장애인 표지 여부를 조회한다. + * @param vehicleNos 차량번호 + * @return "jsonView" + *
 {
+	 *     "parkingList": "장애인 표지 목록"
+	 * }
+ */ + @GetMapping(name = "장애인 표지 목록 조회", value = "/parkingList.do") + public ModelAndView getParkingList(String... vehicleNos) { + return new ModelAndView("jsonView") + .addObject("parkingList", service.getParkingList(vehicleNos)); + } +} \ No newline at end of file diff --git a/src/main/resources/.gitignore b/src/main/resources/.gitignore new file mode 100644 index 0000000..7d32a6c --- /dev/null +++ b/src/main/resources/.gitignore @@ -0,0 +1,3 @@ +/message/ +/spring/ +/sql/ diff --git a/src/main/resources/intf-conf/disabled-parking.conf b/src/main/resources/intf-conf/disabled-parking.conf new file mode 100644 index 0000000..362c9a7 --- /dev/null +++ b/src/main/resources/intf-conf/disabled-parking.conf @@ -0,0 +1,16 @@ +{ + "template": "template/disabled-parking-request.xml", /* 장애인 표지 조회를 위한 요청 xml 템플릿의 클래스패스 상의 경로 */ + + "serviceUrl": "http://hub.share.go.kr/rid/ynservice/swsdn/DisabledParkingYnService", /* 장애인 표지 조회 서비스 url */ + "targetServer": "SVR1311000030", /* 장애인 표지 조회 서버인증서 아이디 */ + + "request": { /* 요청 xml의 파라미터 시작과 끝 태그 */ + "start": "", + "end": "" + }, + + "response": { /* 응답 xml의 데이터 시작과 끝 태그 */ + "start": "", + "end": "" + } +} \ No newline at end of file diff --git a/src/main/resources/intf-conf/gpki.conf b/src/main/resources/intf-conf/gpki.conf new file mode 100644 index 0000000..96e26f3 --- /dev/null +++ b/src/main/resources/intf-conf/gpki.conf @@ -0,0 +1,24 @@ +{ + "license": "C:\\GPKI\\Lic", /* 이용기관 GPKI API 라이센스 디렉토리 */ + + "charset": "UTF-8", /* 문자셋 */ + + "server": { + "local": "SVR3910262001", /* 이용기관 서버 CN */ + "targets": "SVR1311000030" /* 대상기관 서버인증서 아이디, 여러 개일 경우 컴마(,)로 구분 */ + }, + + "ldapUrl": "ldap://152.99.57.127:389/cn=", /* 대상기관 인증서 다운로드를 위한 LDAP URL */ + "certDir": "C:\\GPKI\\Certificate\\class1", /* 서버 인증서, 키 저장 디렉토리 */ + + "env": { /* 이용기관 서버 인증서 */ + "certFile": "SVR3910262001_env.cer", + "privateKeyFile": "SVR3910262001_env.key", + "privateKeyPassword": "wkddodls3322!" + }, + "sig": { /* 이용기관 서버 전자서명 */ + "certFile": "SVR3910262001_sig.cer", + "privateKeyFile": "SVR3910262001_sig.key", + "privateKeyPassword": "wkddodls3322!" + } +} \ No newline at end of file diff --git a/src/main/resources/template/disabled-parking-request.xml b/src/main/resources/template/disabled-parking-request.xml new file mode 100644 index 0000000..b3548d1 --- /dev/null +++ b/src/main/resources/template/disabled-parking-request.xml @@ -0,0 +1,20 @@ + + +
+ + DisabledParkingYnService + 3910404CMC + SVR1311000030 + {transactionID} + + + +
+ + + 3910000 + ERPTC901SSI638W22183 + {carsNo} + + +
\ No newline at end of file diff --git a/src/test/java/cokr/xit/interfaces/disabledparking/service/DisabledParkingServiceTest.java b/src/test/java/cokr/xit/interfaces/disabledparking/service/DisabledParkingServiceTest.java new file mode 100644 index 0000000..fd48e4d --- /dev/null +++ b/src/test/java/cokr/xit/interfaces/disabledparking/service/DisabledParkingServiceTest.java @@ -0,0 +1,57 @@ +package cokr.xit.interfaces.disabledparking.service; + +import java.util.Map; + +import javax.annotation.Resource; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cokr.xit.foundation.test.TestSupport; +import cokr.xit.interfaces.disabledparking.service.bean.DisabledParkingBean; +import cokr.xit.interfaces.disabledparking.service.bean.GPKI; + +public class DisabledParkingServiceTest extends TestSupport { + @Resource(name = "disabledParkingService") + private DisabledParkingService service; + + @Test + void gpkConfig() { + GPKI.Config conf = GPKI.Config.get(); + System.out.println("charset: " + conf.getCharset()); + System.out.println("licence: " + conf.getLicense()); + System.out.println("ldap url: " + conf.getLdapUrl()); + System.out.println("cert dir: " + conf.getCertDir()); + + System.out.println("local server: " + conf.getLocalServer()); + System.out.println("target servers: " + conf.getTargetServers()); + + for (String type: new String[] {"env", "sig"}) { + System.out.println(type + " certFile: " + conf.getCertFile(type)); + System.out.println(type + " privateKeyFile: " + conf.getPrivateKeyFile(type)); + System.out.println(type + " privateKeyPassword: " + conf.getPrivateKeyPassword(type)); + } + } + + @Test + void disabledParkingConfig() { + DisabledParkingBean.Config conf = DisabledParkingBean.Config.get(); + System.out.println("serviceUrl: " + conf.getServiceUrl()); + System.out.println("targetServer: " + conf.getTargetServer()); + System.out.println("request: " + conf.getRequest()); + System.out.println("response: " + conf.getResponse()); + } + + @Test + void getParkingYn() { + Map.of( + "xx가xxxx", "N", + "47너7721", "N", + "56저2472", "Y" + ) + .forEach((k, v) -> { + Map result = service.getParkingInfo(k); + Assertions.assertEquals(v, result.get("PARKING_PSBL_YN")); + }); + } +} \ No newline at end of file