온나라 결재 반영

dev
Jonguk. Lim 6 months ago
parent 52bd6e7331
commit 44d156fb9b

@ -1,8 +1,10 @@
package cokr.xit.adds.core.util;
import java.net.URLEncoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@ -11,13 +13,21 @@ import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONObject;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.xml.sax.SAXException;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import com.fasterxml.jackson.core.type.TypeReference;
import cokr.xit.adds.core.spring.exception.ApiCustomException;
import cokr.xit.foundation.data.JSON;
@ -97,20 +107,6 @@ public class ApiUtil {
}
}
public static String getUtf8UrlEncoding(final String str) {
if(!org.springframework.util.StringUtils.hasText(str)) return StringUtils.EMPTY;
try {
return URLEncoder.encode(
org.apache.commons.codec.binary.StringUtils.newStringUtf8(
org.apache.commons.codec.binary.StringUtils.getBytesUtf8(str)),
StandardCharsets.UTF_8
);
} catch (Exception e) {
throw ApiCustomException.create(e.getLocalizedMessage());
}
}
/**
* NimsApi - x-www-form-urlencoded
* @param uri String
@ -155,6 +151,14 @@ public class ApiUtil {
}
}
public static <T> T toObjByObj(final Object obj, final TypeReference<T> typeRef) {
try {
return ObjectUtils.isNotEmpty(obj)? new JSON().getObjectMapper().convertValue(obj, typeRef) : null;
} catch (IllegalArgumentException e) {
throw ApiCustomException.create(e.getLocalizedMessage());
}
}
public static void toData(final WebClient.Request request, final Object obj){
if(ObjectUtils.isEmpty(obj)) return;
//MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
@ -164,19 +168,55 @@ public class ApiUtil {
}
}
/**
* Object
* -> MultiValueMap<String, String> return
* @param obj Object
* @return MultiValueMap<String, String>
*/
public static MultiValueMap<String, String> toMultiValue(final Object obj){
if(ObjectUtils.isEmpty(obj)) return null;
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
JSONObject jsonObj = toObjByObj(obj, JSONObject.class);
for (Object key : jsonObj.keySet()) {
formData.add((String) key, (String) jsonObj.get(key));
public static boolean validateXml(final String xmlStr, final String xsdFilePathName) {
try {
FileInputStream fis = new FileInputStream(xsdFilePathName);
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new StreamSource(fis));
javax.xml.validation.Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(xmlStr)));
return true;
} catch (SAXException | IOException e) {
throw ApiCustomException.create(e.getMessage());
}
}
public static boolean validateXmlFromXmlStr(final String xmlStr, final String xsdFilePath) {
try {
FileInputStream fis = new FileInputStream(xsdFilePath);
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new StreamSource(fis));
javax.xml.validation.Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(xmlStr)));
return true;
} catch (SAXException | IOException e) {
throw ApiCustomException.create(e.getMessage());
}
return formData;
}
public static boolean validateXmlFromFile(String xmlFilePath, final String xsdFilePath) {
try (FileInputStream fileInputStream = new FileInputStream(xmlFilePath)) {
byte[] bytes = fileInputStream.readAllBytes();
return validateXmlFromXmlStr(new String(bytes), xsdFilePath);
}catch (IOException e) {
throw ApiCustomException.create(e.getMessage());
}
}
public static void main(String[] args) {
File imageFile = new File("src/main/resources/static/images/approval.jpg");
ITesseract instance = new Tesseract(); // JNA Interface Mapping
try {
String result = instance.doOCR(imageFile);
System.out.println(result);
} catch (TesseractException e) {
System.err.println(e.getMessage());
}
}
}

@ -0,0 +1,618 @@
package cokr.xit.adds.core.util;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* <pre>
* description : Date uitility
* 8 java.time
* localDate :
* localDateTime :
* localtime :
* author : julim
* date : 2023-04-28
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-28 julim
*
* </pre>
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DateUtils {
private static final String DEFAULT_YMD_DT_FMT ="yyyy-MM-dd HH:mm:ss";
public static Date toDateFromLocalDate(final LocalDate localDate){
final Instant instant = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
return Date.from(instant);
//return java.sql.Date.valueOf(localDate);
}
public static Date toDateFromLocalDateTime(final LocalDateTime localDateTime){
final Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
return Date.from(instant);
//return java.sql.Timestamp.valueOf(localDateTime);
}
// public static LocalDate toLocalDateFromDate(Date date){
// return LocalDate.ofInstant(date.toInstant(), ZoneId.systemDefault());
// //return new java.sql.Date(date.getTime()).toLocalDate();
// }
public static LocalDateTime toLocalDateTimeFromDate(final Date date){
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
//return new java.sql.Timestamp(date.getTime()).toLocalDateTime();
}
/**
* LocalDate
*
* @return LocalDate
*/
public static LocalDate localDate() {
return LocalDate.now();
}
/**
* LocalDate.parse
*
* @param target yyyy-MM-dd
* @return LocalDate.parse(tartget);
*/
public static LocalDate parseLocalDate(final String target) {
return LocalDate.parse(target);
}
/**
* LocalDateTime
*
* @return LocalDateTime
*/
public static LocalDateTime localDateTime() {
return LocalDateTime.now();
}
/**
* LocalDateTime.parse
*
* @param target yyyy-MM-dd HH:mm:ss
* @return LocalDateTime.parse(tartget);
*/
public static LocalDateTime parseLocalDateTime(final String target) {
return LocalDateTime.parse(target);
}
/**
* LocalDateTime.parse
*
* @param target yyyy-MM-dd HH:mm:ss
* @return LocalDateTime.parse(tartget);
*/
public static LocalDateTime parseLocalDateTimeForm(final String target, final String pattern) {
return LocalDateTime.parse(target, DateTimeFormatter.ofPattern(StringUtils.defaultString(pattern, DEFAULT_YMD_DT_FMT)));
}
/**
* String format -> long
* @param target 20230610115959
* @param fmt yyyyMMddHHmmss
* @return long long seconds
*/
public static long parseStringToLong(final String target, final String fmt) {
final String format = StringUtils.defaultString(fmt, DEFAULT_YMD_DT_FMT);
final LocalDateTime ldt = LocalDateTime.parse(target, DateTimeFormatter.ofPattern(format));
return ldt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()/1000;
}
/**
* LocalDateTime -> long
* @param ldt LocalDateTime
* @return long long seconds
*/
public static long parseToLong(final LocalDateTime ldt) {
return ldt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()/1000;
}
/**
* Date -> long
* @param date Date
* @return long long seconds
*/
public static long parseToLong(final Date date) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault())
.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()/1000;
}
/**
*
*
* @return int
*/
public static int getCurrentYear() {
return localDate().getYear();
}
/**
*
*
* @return int
*/
public static int getCurrentMonth() {
return localDate().getMonthValue();
}
/**
*
*
* @return int
*/
public static int getCurrentDay() {
return localDate().getDayOfMonth();
}
/**
*
*
* @return boolean
*/
public static boolean isLeapYear() {
return localDate().isLeapYear();
}
/**
* : --
* BASIC_ISO_DATE : 20200621
*
* @return LocalDate
*/
public static LocalDate getToday() {
return localDate();
}
/**
* : --
* BASIC_ISO_DATE : 20200621
*
* @param delimiter
* @return String
*/
public static String getToday(String delimiter) {
final String pattern = "yyyy" + delimiter + "MM" + delimiter + "dd";
String result = "";
try {
if (delimiter == null) {
result = localDate().format(DateTimeFormatter.BASIC_ISO_DATE);
} else {
result = localDate().format(DateTimeFormatter.ofPattern(pattern));
}
} catch (final Exception e) {
log.error("DateUtils::getToday", e);
}
return result;
}
/**
* : --
*
* @return LocalDate
*/
public static LocalDateTime getTodayAndNowTime() {
return localDateTime();
}
/**
* -> long return
*
* @return long
*/
public static long getLongTodayAndNowTime() {
return localDateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()/1000;
}
/**
* : --
*
* @param delimiter
* @param isMillisecond
* @return String
*/
public static String getTodayAndNowTime(final String delimiter, final boolean isMillisecond) {
String pattern = "";
final String dlr = StringUtils.defaultString(delimiter, "");
try {
pattern = "yyyy" + dlr + "MM" + dlr + "dd" + " HH:mm:ss" + (isMillisecond ? ".SSS" : "");
} catch (Exception e) {
log.error("DateUtils::getTodayAndNowTime", e);
}
return localDateTime().format(DateTimeFormatter.ofPattern(pattern));
}
/**
* : --
*
* @param userFormat
* @return String
*/
public static String getTodayAndNowTime(final String userFormat) {
String pattern = "";
try {
pattern = DEFAULT_YMD_DT_FMT;
if (!StringUtils.isEmpty(userFormat)) {
pattern = userFormat;
}
} catch (Exception e) {
log.error("DateUtils::getTodayAndNowTime", e);
}
return localDateTime().format(DateTimeFormatter.ofPattern(pattern));
}
/**
*
* -- ( )
*
* .
* ex : -1 = 1
*
* @param targetDate --
* @param year
* @param month
* @param day
* @return String
*/
public static String getCalculatorDate(final String targetDate, final int year, final int month, final int day) {
String result = "";
try {
LocalDate localDate = parseLocalDate(targetDate);
localDate = localDate.plusYears(year);
localDate = localDate.plusMonths(month);
localDate = localDate.plusDays(day);
result = localDate.toString();
} catch (Exception e) {
log.error("DateUtils::getCalculatorDate", e);
}
return result;
}
/**
*
* -- ( )
*
* .
* ex : -1 = 1
*
* @param targetDate --
* @param year
* @param month
* @return String
*/
public static String getCalculatorDate(String targetDate, int year, int month) {
return getCalculatorDate(targetDate, year, month, 0);
}
/**
*
* -- ( )
*
* .
* ex : -1 = 1
*
* @param targetDate --
* @param year
* @return String
*/
public static String getCalculatorDate(final String targetDate, final int year) {
return getCalculatorDate(targetDate, year, 0, 0);
}
/**
* & --THH:mm:ss ( )
* 2020-06-22T23:20:32 ISO 'T' .
* ex : -1 = 1
*
* @param targetDate --T::
* @param year
* @param month
* @param day
* @param hour
* @param minute
* @param second
* @return String
*/
public static String getCalculatorDateAndTime(final String targetDate, final int year, final int month, final int day, int hour, int minute, int second) {
String result = "";
try {
LocalDateTime localDateTime = parseLocalDateTime(targetDate);
localDateTime = localDateTime.plusYears(year);
localDateTime = localDateTime.plusMonths(month);
localDateTime = localDateTime.plusDays(day);
localDateTime = localDateTime.plusHours(hour);
localDateTime = localDateTime.plusMinutes(minute);
localDateTime = localDateTime.plusSeconds(second);
result = localDateTime.toString();
} catch (Exception e) {
log.error("DateUtils::getCalculatorDateAndTime", e);
}
return result;
}
/**
*
* & --THH:mm:ss ( )
* 2020-06-22T23:20:32 ISO 'T' .
* ex : -1 = 1
*
* @param targetDate --T::
* @param year
* @param month
* @param day
* @param hour
* @param minute
* @return String
*/
public static String getCalculatorDateAndTime(final String targetDate, final int year, final int month, final int day, final int hour, final int minute) {
return getCalculatorDateAndTime(targetDate, year, month, day, hour, minute, 0);
}
/**
*
* 2020-06-22T23:20:32 ISO 'T' .
* ex : -1 = 1
*
* @param targetDate --T::
* @param year
* @param month
* @param day
* @param hour
* @return String
*/
public static String getCalculatorDateAndTime(final String targetDate, final int year, final int month, final int day, final int hour) {
return getCalculatorDateAndTime(targetDate, year, month, day, hour, 0, 0);
}
/**
*
* 2020-06-22T23:20:32 ISO 'T' .
* ex : -1 = 1
*
* @param targetDate --T::
* @param year
* @param month
* @param day
* @return String
*/
public static String getCalculatorDateAndTime(final String targetDate, final int year, final int month, final int day) {
return getCalculatorDateAndTime(targetDate, year, month, day, 0, 0, 0);
}
/**
*
* 2020-06-22T23:20:32 ISO 'T' .
* ex : -1 = 1
*
* @param targetDate --T::
* @param year
* @param month
* @return String
*/
public static String getCalculatorDateAndTime(final String targetDate, final int year, final int month) {
return getCalculatorDateAndTime(targetDate, year, month, 0, 0, 0, 0);
}
/**
*
* 2020-06-22T23:20:32 ISO 'T' .
* ex : -1 = 1
*
* @param targetDate --T::
* @param year
* @return String
*/
public static String getCalculatorDateAndTime(final String targetDate, final int year) {
return getCalculatorDateAndTime(targetDate, year, 0, 0, 0, 0, 0);
}
/**
* 2020-06-22
*
* sourceDate < compareDate = true
* sourceDate > compareDate = false
* sourceDate == compareDate = false
*
* @param sourceDate --
* @param compareDate --
* @return boolean
*/
public static boolean isBeforeLocalDate(final String sourceDate, final String compareDate) {
boolean result = false;
try {
LocalDate source = parseLocalDate(sourceDate);
result = source.isBefore(parseLocalDate(compareDate));
} catch (Exception e) {
log.error("DateUtils::isBeforeLocalDate", e);
}
return result;
}
/**
* 2020-06-22
*
* sourceDate > compareDate = true
* sourceDate < compareDate = false
* sourceDate == compareDate = false
*
* @param sourceDate --
* @param compareDate --
* @return boolean
*/
public static boolean isAfterLocalDate(final String sourceDate, final String compareDate) {
boolean result = false;
try {
LocalDate source = parseLocalDate(sourceDate);
result = source.isAfter(parseLocalDate(compareDate));
} catch (Exception e) {
log.error("DateUtils::isAfterLocalDate", e);
}
return result;
}
/**
* 2020-06-22T22:57:33
* &
* sourceDate < compareDate = true
* sourceDate > compareDate = false
* sourceDate == compareDate = false
*
* @param sourceDate
* @param compareDate
* @return boolean
*/
public static boolean isBeforeLocalDateTime(final String sourceDate, final String compareDate) {
boolean result = false;
try {
LocalDateTime source = parseLocalDateTime(sourceDate);
result = source.isBefore(parseLocalDateTime(compareDate));
} catch (final Exception e) {
log.error("DateUtils::isBeforeLocalDateTime", e);
}
return result;
}
/**
* 20230620235733 (Default: 2023-06-20 23:57:33)
* pattern: yyyyMMddHHmmss (Default: yyyy-MM-dd HH:mm:ss)
* &
* sourceDate < compareDate = true
* sourceDate > compareDate = false
* sourceDate == compareDate = false
*
* @param sourceDate
* @param compareDate
* @param pattern
* @return boolean
*/
public static boolean isBeforeLocalDateTime(final String sourceDate, final String compareDate, final String pattern) {
boolean result = false;
try {
LocalDateTime source = parseLocalDateTimeForm(sourceDate,pattern);
result = source.isBefore(parseLocalDateTimeForm(compareDate,pattern));
} catch (final Exception e) {
log.error("DateUtils::isBeforeLocalDateTime", e);
}
return result;
}
/**
* 2020-06-22T22:57:33
* &
* sourceDate > compareDate = true
* sourceDate < compareDate = false
* sourceDate == compareDate = false
*
* @param sourceDate
* @param compareDate
* @return boolean
*/
public static boolean isAfterLocalDateTime(final String sourceDate, final String compareDate) {
boolean result = false;
try {
LocalDateTime source = parseLocalDateTime(sourceDate);
result = source.isAfter(parseLocalDateTime(compareDate));
} catch (final Exception e) {
log.error("DateUtils::isAfterLocalDateTime", e);
}
return result;
}
/**
*
* 2020-06-23 - 2020-06-22 = 1
* 2020-06-23 - 2020-06-24 = -1
* -
*
* @param startDate String
* @param endDate String
* @return int
*/
public static int getDateDiffPeriodForLocalDate(final String startDate, final String endDate) {
int result = 0;
try {
LocalDate source = parseLocalDate(endDate);
result = (int) ChronoUnit.DAYS.between(source, parseLocalDate(startDate));
} catch (final Exception e) {
log.error("DateUtils::getDateDiffPeriodForLocalDate", e);
}
return result;
}
/**
* ( )
* 2020-06-23T23:12:45 - 2020-06-22T23:12:45 = 1
* 2020-07-23T23:59:59 - 2020-07-24T23:59:58 = 0
* 2020-07-23T23:59:58 - 2020-07-24T23:59:59 = -1
* -
*
* @param startDate String
* @param endDate String
* @return int
*/
public static int getDateDiffPeriodForLocalDateTime(final String startDate, final String endDate) {
int result = 0;
try {
LocalDateTime source = parseLocalDateTime(endDate);
result = (int) ChronoUnit.DAYS.between(source, parseLocalDateTime(startDate));
} catch (final Exception e) {
log.error("DateUtils::getDateDiffPeriodForLocalDateTime", e);
}
return result;
}
/**
*
* @param date
* @param sDateFormat
* @return
*/
public static String getFormatedDT(final Date date, final String sDateFormat) {
SimpleDateFormat sdf = new SimpleDateFormat(sDateFormat);
return sdf.format(date);
}
}

@ -32,75 +32,142 @@ import lombok.NoArgsConstructor;
*/
public class ExchangeCommon {
/**
* <pre>
*
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Common {
/**
*
*/
@JacksonXmlProperty(localName = "SENDER")
@JsonProperty(required = true)
private Sender sender;
/**
*
*/
@JacksonXmlProperty(localName = "RECEIVER")
@JsonProperty(required = true)
private Receiver receiver;
/**
* <pre>
*
*
* </pre>>
*/
@JacksonXmlProperty(localName = "TITLE")
@JsonProperty(required = true)
@JacksonXmlCData
private String title;
/**
* : YYYY-MM-DD HH:mm:ss
*/
@JacksonXmlProperty(localName = "CREATED_DATE")
@JsonProperty(required = true)
private String createdDate;
/**
*
*/
@JacksonXmlProperty(localName = "ATTACHNUM")
@JsonProperty(required = true)
private int attachnum;
/**
* <pre>
*
* ( ID)
* </pre>
*/
@JacksonXmlProperty(localName = "ADMINISTRATIVE_NUM")
@JsonProperty(required = true)
private String administrativeNum;
}
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Sender {
/**
* ID
*/
@JacksonXmlProperty(localName = "SERVERID")
@JsonProperty(required = true)
private String serverid;
/**
* ID
*/
@JacksonXmlProperty(localName = "USERID")
@JsonProperty(required = true)
private String userid;
/**
*
*/
@JacksonXmlProperty(localName = "EMAIL")
private String email;
}
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Receiver {
/**
* ID
*/
@JacksonXmlProperty(localName = "SERVERID")
@JsonProperty(required = true)
private String serverid;
/**
* ID
*/
@JacksonXmlProperty(localName = "USERID")
@JsonProperty(required = true)
private String userid;
/**
*
*/
@JacksonXmlProperty(localName = "EMAIL")
private String email;
}
/**
* <pre>
*
*
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Docnum {
/**
* <pre>
*
* - 7 + 6 13
* ) -36 : 1310505000036
* </pre>
*/
@JacksonXmlProperty(localName = "docnumcode", isAttribute = true)
@JsonProperty(required = true)
@JacksonXmlCData
@ -111,6 +178,11 @@ public class ExchangeCommon {
private String value;
}
/**
* <pre>
* -
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@ -123,11 +195,17 @@ public class ExchangeCommon {
@JsonProperty(required = true)
private String status;
/**
*
*/
@JacksonXmlProperty(localName = "LINES")
@JsonProperty(required = true)
private Lines lines;
}
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@ -139,20 +217,37 @@ public class ExchangeCommon {
private List<Line> line;
}
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Line {
/**
* <pre>
*
* - 1
* - 2, 3, 4
* (, , ) - final
* </pre>
*/
@JacksonXmlProperty(localName = "LEVEL")
@JsonProperty(required = true)
private String level;
/**
*
*/
@JacksonXmlProperty(localName = "SANCTION")
@JsonProperty(required = true)
private Sanction sanction;
}
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@ -160,6 +255,7 @@ public class ExchangeCommon {
public static class Sanction {
/**
* <pre>
*
* | | | |
* </pre>
*/
@ -169,6 +265,7 @@ public class ExchangeCommon {
/**
* <pre>
*
* | | | | |
* </pre>
*/
@ -176,18 +273,36 @@ public class ExchangeCommon {
@JsonProperty(required = true)
private String type;
/**
* <pre>
*
* / / / / /
* </pre>
*/
@JacksonXmlProperty(localName = "PERSON")
@JsonProperty(required = true)
private Person person;
/**
*
*/
@JacksonXmlProperty(localName = "COMMENT")
private String comment;
/**
* : YYYY-MM-DD HH:mm:ss
*/
@JacksonXmlProperty(localName = "DATE")
@JsonProperty(required = true)
private String date;
}
/**
* <pre>
*
* / / / / /
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@ -201,39 +316,80 @@ public class ExchangeCommon {
@JsonProperty(required = true)
private String name;
/**
* <pre>
* ()
* ,
* </pre>
*/
@JacksonXmlProperty(localName = "POSITION")
@JsonProperty(required = true)
private String position;
/**
*
*/
@JacksonXmlProperty(localName = "DEPT")
@JsonProperty(required = true)
private String dept;
/**
*
*/
@JacksonXmlProperty(localName = "ORG")
@JsonProperty(required = true)
private String org;
}
/**
* <pre>
* ()
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ModificationFlag {
/**
* <pre>
* ()
* -> -
* -> -
* </pre>
*/
@JacksonXmlProperty(localName = "MODIFIABLE")
@JsonProperty(required = true)
private Modifiable modifiable;
/**
* <pre>
*
* ( , )
* ->
* </pre>
*/
@JacksonXmlProperty(localName = "MODIFIED")
private String modified;
}
/**
* <pre>
*
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Modifiable {
/**
* <pre>
* () : default no
* -> -
* -> -
* yes | no
* </pre>
*/
@JacksonXmlProperty(localName = "modifyflag", isAttribute = true)
@JsonProperty(required = true)
@ -241,25 +397,49 @@ public class ExchangeCommon {
private String modifyflag = "no";
}
/**
* <pre>
*
*
*
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Addenda {
/**
*
*/
@JacksonXmlProperty(localName = "ADDENDUM")
@JsonProperty(required = true)
private Addendum addendum;
}
/**
* <pre>
*
*
*
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Addendum {
/**
*
*/
@JacksonXmlProperty(localName = "comment", isAttribute = true)
@JsonProperty(required = true)
@JacksonXmlCData
private String comment;
/**
*
*/
@JacksonXmlProperty(localName = "name", isAttribute = true)
@JsonProperty(required = true)
@JacksonXmlCData
@ -270,32 +450,51 @@ public class ExchangeCommon {
private String value;
}
/**
* <pre>
*
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Attachments {
/**
*
*/
@JacksonXmlProperty(localName = "ADMINISTRATIVE_DB")
private AdministrativeDB administrativeDB;
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "ATTACHMENT")
@JsonProperty(required = true)
private List<Attachment> attachment;
}
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class AdministrativeDB {
/**
* XML
*/
@JacksonXmlProperty(localName = "XMLFILE")
private XMLFile xmlfile;
/**
* XSL
*/
@JacksonXmlProperty(localName = "XSLFILE")
private XSLFile xslfile;
}
/**
* XML
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@ -307,7 +506,6 @@ public class ExchangeCommon {
private String filename;
@JacksonXmlProperty(localName = "desc", isAttribute = true)
@JsonProperty(required = true)
@JacksonXmlCData
private String desc;
@ -317,6 +515,9 @@ public class ExchangeCommon {
private String value;
}
/**
* XSL
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@ -328,7 +529,6 @@ public class ExchangeCommon {
private String filename;
@JacksonXmlProperty(localName = "desc", isAttribute = true)
@JsonProperty(required = true)
@JacksonXmlCData
private String desc;
@ -338,6 +538,9 @@ public class ExchangeCommon {
private String value;
}
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@ -349,13 +552,13 @@ public class ExchangeCommon {
private String filename;
@JacksonXmlProperty(localName = "desc", isAttribute = true)
@JsonProperty(required = true)
@JacksonXmlCData
private String desc;
@XmlValue
@JacksonXmlText
@JsonProperty(required = true)
@JacksonXmlCData
private String value;
}
}

@ -2,6 +2,7 @@ package cokr.xit.adds.inf.mois.model;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@ -34,33 +35,62 @@ public class ExchangeDto extends ExchangeCommon {
@JsonProperty(required = true)
private Header header;
/**
* <pre>
* ->
* -
* ,
* MODIFICATION_FLAG
*
* ->
* -
* ->
* , ,
* ->
*
* </pre>
*/
@JacksonXmlProperty(localName = "BODY")
@JacksonXmlCData
private String body;
@JacksonXmlProperty(localName = "ATTACHMENTS")
private Attachments attachments;
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Header {
/**
*
*/
@JacksonXmlProperty(localName = "COMMON")
@JsonProperty(required = true)
private Common common;
/**
*
*/
@JacksonXmlProperty(localName = "DIRECTION")
@JsonProperty(required = true)
private Direction direction;
/**
*
*/
@JacksonXmlProperty(localName = "ADDENDA")
private Addenda addenda;
}
/**
* <pre>
* ToDocumentSystem | ToAdministrativeSystem
* or -
*
* ToAdministrativeSystem : ->
* ToDocumentSystem : ->
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -68,49 +98,91 @@ public class ExchangeDto extends ExchangeCommon {
@AllArgsConstructor
@Builder
public static class Direction {
@JacksonXmlProperty(localName = "TO_DOCUMENT_SYSTEM")
private ToDocumentSystem toDocumentSystem;
/**
*
*/
@JacksonXmlProperty(localName = "TO_ADMINISTRATIVE_SYSTEM")
private ToAdministrativeSystem toAdministrativeSystem;
/**
*
*/
@JacksonXmlProperty(localName = "TO_DOCUMENT_SYSTEM")
private ToDocumentSystem toDocumentSystem;
}
/**
* <pre>
* ->
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ToDocumentSystem {
public static class ToAdministrativeSystem {
/**
* all | final
* <pre>
*
*
* </pre>
*/
@JacksonXmlProperty(isAttribute = true, localName = "notification")
@JacksonXmlProperty(localName = "DOCNUM")
@JsonProperty(required = true)
@Builder.Default
String notification = "all";
private Docnum docnum;
@JacksonXmlProperty(localName = "LINES")
private Lines lines;
/**
*
*/
@JacksonXmlProperty(localName = "SANCTION_INFO")
@JsonProperty(required = true)
private SanctionInfo sanctionInfo;
/**
*
*/
@JacksonXmlProperty(localName = "MODIFICATION_FLAG")
@JsonProperty(required = true)
private ModificationFlag modificationFlag;
}
/**
* <pre>
* ->
* </pre>
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ToAdministrativeSystem {
@JacksonXmlProperty(localName = "DOCNUM")
public static class ToDocumentSystem {
/**
* <pre>
* ( , )
* all | final
* </pre>
*/
@JacksonXmlProperty(isAttribute = true, localName = "notification")
@JsonProperty(required = true)
private Docnum docnum;
@Builder.Default
String notification = "all";
@JacksonXmlProperty(localName = "SANCTION_INFO")
@JsonProperty(required = true)
private SanctionInfo sanctionInfo;
/**
*
*/
@JacksonXmlProperty(localName = "LINES")
private Lines lines;
/**
* <pre>
*
*
* </pre>
*/
@JacksonXmlProperty(localName = "MODIFICATION_FLAG")
@JsonProperty(required = true)
private ModificationFlag modificationFlag;
}
}

@ -0,0 +1,54 @@
package cokr.xit.adds.inf.mois.model;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.*;
import java.util.List;
import javax.validation.constraints.NotEmpty;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* <pre>
* description :
*
* packageName : cokr.xit.adds.inf.mois.model
* fileName : MoisApiRequest
* author : limju
* date : 2024-04-21
* ======================================================================
*
* ----------------------------------------------------------------------
* 2024-04-21 limju
*
* </pre>
*/
@Schema(name = "MoisExchangeRequest", description = "전자 결재 연계 request")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MoisExchangeRequest {
/**
* ID
*/
@Schema(requiredMode = REQUIRED, title = "사용자ID", description = "사용자ID", example = "admin")
@NotEmpty(message = "사용자 ID는 필수 입니다")
private String userId;
/**
* ID - administrativeNum(COMMON > ADMINISTRATIVE_NUM )
*/
@Schema(requiredMode = REQUIRED, title = "폐기관리ID", description = "폐기관리ID-행정정보처리번호로 사용", example = "admin")
@NotEmpty(message = "폐기관리ID ID는 필수 입니다")
private String dscdmngId;
private List<MultipartFile> files;
}

@ -9,7 +9,6 @@ import org.springframework.util.Base64Utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
@ -43,17 +42,23 @@ import lombok.NoArgsConstructor;
@Builder
@Getter
public class PackDto {
/**
* -
*/
@JacksonXmlProperty
@JsonProperty(required = true)
protected Header header;
/**
* -
*/
@JacksonXmlProperty
@JsonProperty(required = true)
protected Contents contents;
/**
* <pre>
*
* -
* </pre>
*/
@JacksonXmlProperty(localName = "filename", isAttribute = true)
@ -67,7 +72,7 @@ public class PackDto {
public static class Header {
/**
* <pre>
* docType
* docType -
* send | fail |arrive | receive | invalid | submit | return |approval
* | | | || | |
*</pre>
@ -78,7 +83,8 @@ public class PackDto {
/**
* <pre>
* : YYYY-MM-DD HH:mm:ss
* -
* YYYY-MM-DD HH:mm:ss
*</pre>
*/
@JacksonXmlProperty
@ -86,36 +92,28 @@ public class PackDto {
protected String date;
/**
* <pre>
*
*</pre>
* -
*/
@JacksonXmlProperty
@JsonProperty(required = true)
protected String sender;
/**
* <pre>
*
*</pre>
* -
*/
@JacksonXmlProperty
@JsonProperty(required = true)
protected String receiver;
/**
* <pre>
* ID
*</pre>
* ID -
*/
@JacksonXmlProperty(localName = "sender_userid")
@JsonProperty(required = true)
protected String senderUserid;
/**
* <pre>
* ID
*</pre>
* ID -
*/
@JacksonXmlProperty(localName = "receiver_userid")
@JsonProperty(required = true)
@ -132,42 +130,26 @@ public class PackDto {
/**
* <pre>
* - base64 encoding
* CDATA
* -
* base64 encoding
*</pre>
*/
@JacksonXmlProperty(localName = "sender_orgname")
@JsonProperty(required = true)
@JacksonXmlCData
protected String senderOrgname;
// public String getSenderOrgname() {
// return new String(Base64Utils.decodeFromString(senderOrgname));
// }
// public void setSenderOrgname(String senderOrgname) {
// this.senderOrgname = Base64Utils.encodeToString(senderOrgname.getBytes(StandardCharsets.UTF_8));
// }
/**
* <pre>
* - base64 encoding
* CDATA
* -
* base64 encoding
* </pre>
*/
@JacksonXmlProperty(localName = "sender_systemname")
@JsonProperty(required = true)
@JacksonXmlCData
protected String senderSystemname;
// public String getSenderSystemname() {
// return new String(Base64Utils.decodeFromString(senderSystemname));
// }
//public void setSenderSystemname(String senderSystemname) {
// this.senderSystemname = Base64Utils.encodeToString(senderSystemname.getBytes(StandardCharsets.UTF_8));
//}
/**
* <pre>
*
*</pre>
* -
*/
@JacksonXmlProperty(localName = "administrative_num")
@JsonProperty(required = true)
@ -205,7 +187,7 @@ public class PackDto {
public static class Type {
/**
* <pre>
* docType
* docType -
* send|fail|arrive|receive|invalid|submit|return|approval
*</pre>
*/
@ -238,24 +220,17 @@ public class PackDto {
public static class Content {
/**
* <pre>
* content - base64 encoding
* CDATA
* content -
* base64 encoding
* </pre>
*/
@XmlValue
@JacksonXmlText
@JacksonXmlCData
protected String value;
// public String getValue() {
// return new String(Base64Utils.decodeFromString(value));
// }
// public void setValue(String value) {
// this.value = Base64Utils.encodeToString(value.getBytes(StandardCharsets.UTF_8));
// }
/**
* <pre>
* content
* content -
* exchange -
* notification -
* attch -
@ -266,40 +241,37 @@ public class PackDto {
*/
@JacksonXmlProperty(localName = "content-role", isAttribute = true)
@JsonProperty(required = true)
@JacksonXmlCData
protected String contentRole;
/**
* - default base64
*/
@JacksonXmlProperty(localName = "content-transfer-encoding", isAttribute = true)
@JacksonXmlCData
protected String contentTransferEncoding = "base64";
/**
* - base64 encoding
* CDATA
* -
* base64 encoding
*/
@JacksonXmlProperty(localName = "filename", isAttribute = true)
@JsonProperty(required = true)
@JacksonXmlCData
protected String filename;
// public String getFilename() {
// return new String(Base64Utils.decodeFromString(filename));
// }
// public void setFilename(String filename) {
// this.filename = Base64Utils.encodeToString(filename.getBytes(StandardCharsets.UTF_8));
// }
/**
* content-type(MIME)
*/
@JacksonXmlProperty(localName = "content-type", isAttribute = true)
@JacksonXmlCData
protected String contentType;
/**
* charset
*/
@JacksonXmlProperty(localName = "charset", isAttribute = true)
@JacksonXmlCData
protected String charset;
public Content(
@ -319,9 +291,4 @@ public class PackDto {
this.charset = charset;
}
}
public void configureXmlMapper(XmlMapper xmlMapper) {
// 필수 필드 체크를 활성화
xmlMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS, true);
}
}

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="EUC-KR" ?>
<!ELEMENT pack (header, contents)>
<!ATTLIST pack filename CDATA #REQUIRED >
<!ELEMENT header (type, date, sender, receiver, sender_userid, receiver_userid, sender_email?,sender_orgname, sender_systemname?, administrative_num)>
<!ELEMENT type EMPTY>
<!ATTLIST type doc-type (send|fail|arrive|receive|invalid|submit|return|approval) #REQUIRED >
<!ELEMENT date (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender_userid (#PCDATA)>
<!ELEMENT receiver_userid (#PCDATA)>
<!ELEMENT sender_email (#PCDATA)>
<!ELEMENT sender_orgname (#PCDATA)>
<!ELEMENT sender_systemname (#PCDATA)>
<!ELEMENT administrative_num (#PCDATA)>
<!ELEMENT contents (content)*>
<!ELEMENT content (#PCDATA)>
<!ATTLIST content content-role CDATA #REQUIRED >
<!ATTLIST content content-transfer-encoding CDATA "base64" >
<!ATTLIST content filename CDATA #REQUIRED >
<!ATTLIST content content-type CDATA #IMPLIED >
<!ATTLIST content charset CDATA #IMPLIED >

@ -0,0 +1,21 @@
package cokr.xit.adds.inf.mois.service;
import cokr.xit.adds.inf.mois.model.MoisExchangeRequest;
/**
* <pre>
* description :
* packageName : cokr.xit.adds.inf.mois.service
* fileName : InfMoisService
* author : limju
* date : 2024-05-08
* ======================================================================
*
* ----------------------------------------------------------------------
* 2024-05-08 limju
*
* </pre>
*/
public interface InfMoisService {
void sendExchange(MoisExchangeRequest dto);
}

@ -0,0 +1,389 @@
package cokr.xit.adds.inf.mois.service.bean;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import cokr.xit.adds.core.spring.exception.ApiCustomException;
import cokr.xit.adds.core.util.DateUtils;
import cokr.xit.adds.inf.mois.model.ExchangeCommon;
import cokr.xit.adds.inf.mois.model.ExchangeDto;
import cokr.xit.adds.inf.mois.model.MoisExchangeRequest;
import cokr.xit.adds.inf.mois.model.PackDto;
import cokr.xit.adds.inf.mois.service.InfMoisService;
import cokr.xit.foundation.component.AbstractServiceBean;
import cokr.xit.foundation.data.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* <pre>
* description :
* packageName : cokr.xit.adds.inf.mois.service.bean
* fileName : InfMoisServiceBean
* author : limju
* date : 2024-05-08
* ======================================================================
*
* ----------------------------------------------------------------------
* 2024-05-08 limju
*
* </pre>
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class InfMoisServiceBean extends AbstractServiceBean implements InfMoisService {
@Value("${app.inf.mois.sender.systemId}")
private String senderSystemId;
@Value("${app.inf.mois.sender.systemNm}")
private String senderSystemNm;
@Value("${app.inf.mois.sender.orgname}")
private String senderOrgname;
@Value("${app.inf.mois.receiver.systemId}")
private String receiverSystemId;
@Value("${app.inf.mois.receiver.userId}")
private String receiverUserId;
@Value("${app.inf.mois.dataPath.root}")
private String dataRootPath;
@Value("${app.inf.mois.dataPath.sendTemp}")
private String sendTemp;
private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
private static JSON json = new JSON();
/**
* <pre>
*
* - exchange.dtd -> exchange.xml, pack.dtd ->
*
* </pre>
*/
public void sendExchange(MoisExchangeRequest reqDto) {
final String pathName = String.format(
"%s%s%s%s%s",
receiverUserId,
senderSystemId,
receiverSystemId,
DateUtils.getTodayAndNowTime("YYYYMMDDHHmmss"),
new Random().nextInt(100000));
createHeaderFromPackDto(pathName, getPackDto(reqDto));
createEofFile(pathName);
createExchangeXml(getExchangeDto(reqDto, pathName), pathName, "exchange");
//log.info("sendExchange");
}
private void createExchangeXml(final ExchangeDto dto, final String pathName, final String filename) {
JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(true);
XmlMapper mapper = new XmlMapper(module);
XMLOutputFactory factory = mapper.getFactory().getXMLOutputFactory();
String dtd = """
<!DOCTYPE EXCHANGE SYSTEM "exchange.dtd">
""";
// FIXME: 파일명 생성
final String path = dataRootPath + sendTemp + pathName;
try (FileOutputStream w = new FileOutputStream(path + "/" + filename + ".xml")) {
XMLStreamWriter sw = factory.createXMLStreamWriter(w, "EUC-KR");
//XMLStreamWriter sw = factory.createXMLStreamWriter(w);
sw.writeStartDocument("EUC-KR", "1.0");
sw.writeDTD("\n"+dtd);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.writeValue(sw, dto);
// ApiUtil.validateXmlFromFile(filename + ".xml", "src/main/resources/xsd/exchange.xsd");
}catch (IOException | XMLStreamException e) {
throw ApiCustomException.create(e.getMessage());
}
}
public void packXmlWriteTest(MoisExchangeRequest reqDto) throws IOException {
PackDto dto = getPackDto(reqDto);
JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(true);
XmlMapper mapper = new XmlMapper(module);
XMLOutputFactory factory = mapper.getFactory().getXMLOutputFactory();
String dtd = """
<!DOCTYPE pack SYSTEM "exchange.dtd">
""";
// FIXME: 파일명 생성
try (FileWriter w = new FileWriter("pack.xml")) {
XMLStreamWriter sw = factory.createXMLStreamWriter(w);
sw.writeStartDocument("EUC-KR", "1.0");
sw.writeDTD("\n"+dtd);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.writeValue(sw, dto);
}catch (IOException | XMLStreamException e) {
throw ApiCustomException.create(e.getMessage());
}
}
private ExchangeDto getExchangeDto(MoisExchangeRequest reqDto, String pathName) {
// │ ─ ┃┣┫ ┠ ┨┯┷┏┓┗┛┳⊥┌┐└┘├┤┬┼ ·
final String bodyText =
"""
1. .
2. 23
(www.nims.go.kr) .
3.
.
2.
------------------------------------------------------------------------------
9. . ()
1 : 15
2 : 1
3 : 2 ··
4 : ··
9. . 1) , , ,
1 : 7
2 : 15
3 : 1 ··
4 : ··
9. . 2)
1 : 3
2 : 7
3 : 15 ··
4 : ··
------------------------------------------------------------------------------
- "경기도 용인시 수지보건소/4050149"
- : (2024. 56. 10.)
""";
final String path = dataRootPath + sendTemp + pathName;
reqDto.getFiles().forEach(mf -> {
//try(FileInputStream fis = (FileInputStream) mf.getInputStream();
// FileOutputStream fos = new FileOutputStream(new File(pathName+"/"+mf.getOriginalFilename()));){
try{
mf.transferTo(new File(path+"/attach_"+mf.getOriginalFilename()));
// Files.copy(mf.getInputStream(), fos, StandardCopyOption.REPLACE_EXISTING);
}catch (IOException e) {
throw ApiCustomException.create(e.getMessage());
}
});
// 첨부 파일
List<ExchangeDto.Attachment> files = reqDto.getFiles().stream().map(mf ->
{
try {
String filename = new String(Objects.requireNonNull(mf.getOriginalFilename()).getBytes("EUC-KR"), "EUC-KR");
return ExchangeDto.Attachment.builder()
.filename("attach_"+filename)
//.desc("001")
.value(filename)
.build();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
).toList();
ExchangeDto.Common common = ExchangeDto.Common.builder()
.sender(
ExchangeDto.Sender.builder()
.serverid(senderSystemId)
.userid(reqDto.getUserId())
//.email("ttt@g.co.kr")
.build())
.receiver(
ExchangeDto.Receiver.builder()
.serverid(receiverSystemId)
.userid(receiverUserId)
//.email("ldlldld@k.r")
.build())
.title("마약류 폐기 결과 보고")
.createdDate(DateUtils.getTodayAndNowTime("-", false))
.attachnum(files.size())
//FIXME: 시스템 키 - 폐기관리ID
.administrativeNum(reqDto.getDscdmngId())
.build();
ExchangeDto.Docnum docnum = ExchangeCommon.Docnum.builder()
.docnumcode("1310000012699")
.value("고도화팀-2699")
.build();
ExchangeCommon.Line line1 = ExchangeCommon.Line.builder()
.level("1")
.sanction(
ExchangeCommon.Sanction.builder()
.result("상신")
.type("기안")
.person(
ExchangeCommon.Person.builder()
.userid("userId")
.name("홍길동")
.position("전산주사")
.dept("고도화팀")
.org("행정안전부")
.build())
.comment("보고자 의견입니다.")
.date("2007-01-25 14:45:34")
.build())
.build();
ExchangeCommon.Line line2 = ExchangeCommon.Line.builder()
.level("1")
.sanction(
ExchangeCommon.Sanction.builder()
.result("상신")
.type("기안")
.person(
ExchangeCommon.Person.builder()
.userid("hongkildong1")
.name("홍길동1")
.position("전산주사1")
.dept("고도화팀1")
.org("행정안전부1")
.build())
.comment("보고자 의견입니다1.")
.date("2007-01-25 14:45:34")
.build())
.build();
ExchangeDto.Direction direction = ExchangeDto.Direction.builder()
.toDocumentSystem(
ExchangeDto.ToDocumentSystem.builder()
.modificationFlag(
ExchangeDto.ModificationFlag.builder()
.modifiable(
ExchangeDto.Modifiable.builder()
.modifyflag("yes")
.build())
.build())
.build()
)
.build();
ExchangeDto.Header header = ExchangeDto.Header.builder()
.common(common)
.direction(direction)
.build();
ExchangeDto dto = ExchangeDto.builder()
.header(header)
.body(bodyText)
.attachments(ExchangeDto.Attachments.builder()
.attachment(files).build())
.build();
return dto;
}
private PackDto getPackDto(MoisExchangeRequest dto) {
PackDto.Header header = PackDto.Header.builder()
.type(PackDto.Type.builder()
.docType("send")
.build())
.date(DateUtils.getTodayAndNowTime("-", false))
.sender(senderSystemId)
.receiver(receiverSystemId)
.senderUserid(dto.getUserId())
.receiverUserid("receiverUserid")
.senderEmail("senderEmail")
.senderOrgname(senderOrgname)
.senderSystemname(senderSystemNm)
.administrativeNum(dto.getDscdmngId())
.build();
PackDto.Content content = PackDto.Content.builder()
.contentRole("contentRole")
.contentType("constentType")
.charset("utf8")
.value("content-value")
.build();
PackDto packDto = PackDto.builder()
.header(header)
.contents(PackDto.Contents.builder()
.content(List.of(content))
.build())
.filename("filename")
.build();
return packDto;
}
private void createHeaderFromPackDto(final String pathName, final PackDto dto) {
final String path = dataRootPath + sendTemp + pathName;
File dirPath = new File(path);
if(!dirPath.exists()){
dirPath.mkdirs();
}
PackDto.Header header = dto.getHeader();
StringBuilder sb = new StringBuilder();
sb.append("type=").append(header.getType().getDocType()).append("\n");
sb.append("date=").append(header.getDate()).append("\n");
sb.append("sender=").append(header.getSender()).append("\n");
sb.append("receiver=").append(header.getReceiver()).append("\n");
sb.append("sender_userid=").append(header.getSenderUserid()).append("\n");
sb.append("receiver_userid=").append(header.getReceiverUserid()).append("\n");
sb.append("sender_email=").append(header.getSenderEmail()).append("\n");
sb.append("sender_orgname=").append(header.getSenderOrgname()).append("\n");
sb.append("sender_systemname=").append(header.getSenderSystemname()).append("\n");
sb.append("administrative_num=").append(header.getAdministrativeNum()).append("\n");
try(PrintWriter fw = new PrintWriter(dirPath+"/header.inf", "euc-kr");){
fw.write(sb.toString());
fw.flush();
} catch (FileNotFoundException | UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private void createEofFile(final String pathName) {
final String path = dataRootPath + sendTemp + pathName;
File dirPath = new File(path);
try(PrintWriter fw = new PrintWriter(dirPath+"/eof.inf", "euc-kr");){
fw.write(StringUtils.EMPTY);
fw.flush();
} catch (FileNotFoundException | UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}

@ -0,0 +1,46 @@
package cokr.xit.adds.inf.mois.web;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cokr.xit.adds.inf.mois.model.MoisExchangeRequest;
import cokr.xit.adds.inf.mois.service.InfMoisService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
/**
* <pre>
* description :
* packageName : cokr.xit.adds.inf.mois.web
* fileName : InfMoisController
* author : limju
* date : 2024-05-10
* ======================================================================
*
* ----------------------------------------------------------------------
* 2024-05-10 limju
*
* </pre>
*/
@Tag(name = "InfMoisController", description = "온나라전자결재 Interface API - Api Interface call Test(테스트용)")
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/inf/mois/v1")
public class InfMoisController {
private final InfMoisService infMoisService;
/**
*
* multipart/form-data
* @param dto
*/
@Operation(summary = "온나라 전자결재 송신", description = "온나라 전자결재 송신")
@PostMapping(value = "/sendExchange", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public void sendExchange(final MoisExchangeRequest dto) {
infMoisService.sendExchange(dto);
}
}

@ -16,7 +16,29 @@ app:
placeinfoV1: /api/placeinfo_v1.do
reportinfo: /api/reportinfo_ggg.do
mois:
serverId: ADM405000069
sender:
systemId: ADM405000069
systemNm: ADDS
orgname: 용인시
receiver:
systemId: DOC131000001
userId: cskim
dataPath:
root: ${app.data.root.path}/exchange/data
# 송신 연계 보관
send: /send
# 송신오류
sender: /sender
# 임시송신함 - 송신 대상 임시 보관
sendTemp: /sendtemp/
# 수신 연계 보관
receive: /receive
# 수신 오류
receiver: /receiver
# 결재연계 임시수신함 - 수신 대상 임시 보관
receiveTemp: /receivetemp
# 연계에서 사용하는 임시 수신함
exreceivetemp: /exreceivetemp
iros:
url: https://apis.data.go.kr
api-key: 0fTkYnZU6XjaAPAp6GzKW9Q6fYq8iaoSH9wKUZwz2PBjRXGM04aUgtO3a61xYGjL8nFZn4fjLGS9XErhMSXq%2Bw%3D%3D

@ -4,13 +4,13 @@
"settings": {
"width": 2000,
"height": 2000,
"scrollTop": -400,
"scrollLeft": 0,
"scrollTop": -225,
"scrollLeft": -2.609,
"zoomLevel": 1,
"show": 431,
"database": 1,
"databaseName": "",
"canvasType": "@dineug/erd-editor/builtin-generator-code",
"canvasType": "ERD",
"language": 4,
"tableNameCase": 2,
"columnNameCase": 2,

@ -29,7 +29,7 @@
<!ELEMENT LEVEL (#PCDATA)>
<!ELEMENT SANCTION (PERSON, COMMENT?, DATE)>
<!ATTLIST SANCTION
<!ATTLIST
type ( | | | | | ) #REQUIRED
result ( | | | | ) #REQUIRED
>

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="EUC-KR" ?>
<!ELEMENT pack (header, contents)>
<!ATTLIST pack filename CDATA #REQUIRED >
<!ELEMENT header (type, date, sender, receiver, sender_userid, receiver_userid, sender_email?,sender_orgname, sender_systemname?, administrative_num)>
<!ELEMENT type EMPTY>
<!ATTLIST type doc-type (send|fail|arrive|receive|invalid|submit|return|approval) #REQUIRED >
<!ELEMENT date (#PCDATA)>
@ -16,9 +13,7 @@
<!ELEMENT sender_orgname (#PCDATA)>
<!ELEMENT sender_systemname (#PCDATA)>
<!ELEMENT administrative_num (#PCDATA)>
<!ELEMENT contents (content)*>
<!ELEMENT content (#PCDATA)>
<!ATTLIST content content-role CDATA #REQUIRED >
<!ATTLIST content content-transfer-encoding CDATA "base64" >

@ -2,9 +2,9 @@ package cokr.xit.adds.inf.mois.model;
import static org.junit.jupiter.api.Assertions.*;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import javax.xml.stream.XMLOutputFactory;
@ -16,10 +16,13 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import cokr.xit.adds.core.util.ApiUtil;
import cokr.xit.foundation.data.XML;
import lombok.extern.slf4j.Slf4j;
/**
@ -155,19 +158,85 @@ public class ExchangeDtoTest {
try (FileWriter w = new FileWriter("exchange.xml")) {
XMLStreamWriter sw = factory.createXMLStreamWriter(w);
sw.writeStartDocument("EUC-KR", "1.0");
sw.writeDTD("\n"+dtd);
//sw.writeDTD("\n"+dtd);
sw.writeDTD("\n");
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.writeValue(sw, dto);
StringWriter swr = new StringWriter();
mapper.writeValue(swr, dto);
System.out.println(swr.toString());
ApiUtil.validateXmlFromFile("exchange.xml", "src/main/resources/xsd/exchange.xsd");
}catch (XMLStreamException e) {
e.printStackTrace();
}
}
@DisplayName("전자결재 response xml read 테스트")
@Test
public void exchangeResXmlReadTest() throws IOException {
FileInputStream fileInputStream = new FileInputStream("src/test/resources/test_data/notification.xml");
byte[] bytes = fileInputStream.readAllBytes();
String content = new String(bytes, "EUC-KR");
JacksonXmlModule jacksonXmlModule = new JacksonXmlModule();
jacksonXmlModule.setDefaultUseWrapper(false);
//ObjectMapper xmlMapper = new XmlMapper(jacksonXmlModule);
XmlMapper xmlMapper = new XmlMapper(jacksonXmlModule);
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
ExchangeDto dto
= xmlMapper.readValue(content, ExchangeDto.class);
assertNotNull(dto);
xmlMapper.writeValue(System.out, dto);
XML xml = new XML();
//ApiUtil.validateXmlFromXmlStr(content, "src/main/resources/xsd/pack.xsd");
ExchangeDto dto2 = xml.parse(content, new TypeReference<ExchangeDto>() {});
log.info("dto: {}", dto2);
xml.write(System.out, dto2, true);
// assertEquals("senderOrgname", new String(Base64Utils.decodeFromString(dto.getHeader().getSenderOrgname())));
// assertEquals("senderSystemname", new String(Base64Utils.decodeFromString(dto.getHeader().getSenderSystemname())));
// assertEquals("filename", new String(Base64Utils.decodeFromString(dto.getContents().getContent().get(0).getFilename())));
// assertEquals("content-value", new String(Base64Utils.decodeFromString(dto.getContents().getContent().get(0).getValue())));
}
@DisplayName("전자결재 send xml read 테스트")
@Test
public void exchangeSendXmlReadTest() throws IOException {
FileInputStream fileInputStream = new FileInputStream("D:\\data\\exchange\\data\\sendtemp\\cskimADM405000069DOC13100000120240513518034846931\\exchange.xml");
byte[] bytes = fileInputStream.readAllBytes();
String content = new String(bytes, "EUC-KR");
JacksonXmlModule jacksonXmlModule = new JacksonXmlModule();
jacksonXmlModule.setDefaultUseWrapper(false);
//ObjectMapper xmlMapper = new XmlMapper(jacksonXmlModule);
XmlMapper xmlMapper = new XmlMapper(jacksonXmlModule);
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
ExchangeDto dto
= xmlMapper.readValue(content, ExchangeDto.class);
assertNotNull(dto);
xmlMapper.writeValue(System.out, dto);
XML xml = new XML();
//ApiUtil.validateXmlFromXmlStr(content, "src/main/resources/xsd/pack.xsd");
ExchangeDto dto2 = xml.parse(content, new TypeReference<ExchangeDto>() {});
log.info("dto: {}", dto2);
xml.write(System.out, dto2, true);
// assertEquals("senderOrgname", new String(Base64Utils.decodeFromString(dto.getHeader().getSenderOrgname())));
// assertEquals("senderSystemname", new String(Base64Utils.decodeFromString(dto.getHeader().getSenderSystemname())));
// assertEquals("filename", new String(Base64Utils.decodeFromString(dto.getContents().getContent().get(0).getFilename())));
// assertEquals("content-value", new String(Base64Utils.decodeFromString(dto.getContents().getContent().get(0).getValue())));
}
private static ExchangeDto getExchangeDto() {
ExchangeDto.Common common = ExchangeDto.Common.builder()
.sender(
@ -251,19 +320,19 @@ public class ExchangeDtoTest {
.build();
ExchangeDto.Direction direction = ExchangeDto.Direction.builder()
// .toDocumentSystem(
// ExchangeDto.ToDocumentSystem.builder()
// .notification("all")
// .modificationFlag(
// ExchangeDto.ModificationFlag.builder()
// .modifiable(
// ExchangeDto.Modifiable.builder()
// .modifyflag("yes")
// .build())
// .build())
// .build()
// )
.toAdministrativeSystem(administrativeSystem)
.toDocumentSystem(
ExchangeDto.ToDocumentSystem.builder()
.notification("all")
.modificationFlag(
ExchangeDto.ModificationFlag.builder()
.modifiable(
ExchangeDto.Modifiable.builder()
.modifyflag("yes")
.build())
.build())
.build()
)
//.toAdministrativeSystem(administrativeSystem)
.build();
ExchangeDto.Header header = ExchangeDto.Header.builder()

@ -5,12 +5,8 @@ import static org.junit.jupiter.api.Assertions.*;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
@ -20,17 +16,13 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.util.Base64Utils;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import cokr.xit.adds.core.spring.exception.ApiCustomException;
import cokr.xit.adds.core.util.ApiUtil;
import cokr.xit.foundation.data.XML;
import lombok.extern.slf4j.Slf4j;
@ -52,52 +44,14 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@ExtendWith(SpringExtension.class)
public class PackDtoTest {
String packXml = """
<?xml version='1.1' encoding='UTF-8'?>
<pack filename="filename">
<header>
<doc-type>send</doc-type>
<date>20241231</date>
<sender>sender</sender>
<receiver>receiver</receiver>
<sender_userid>senderUserid</sender_userid>
<receiver_userid>receiverUserid</receiver_userid>
<sender_email>senderEmail</sender_email>
<sender_orgname>senderOrgname</sender_orgname>
<sender_systemname>senderSystemname</sender_systemname>
<administrative_num>administrativeNum</administrative_num>
</header>
<contents>
<content content-role="contentRole" content-type="constentType" charset="utf8">content-value</content>
</contents>
</pack>
""";
@DisplayName("전자결재 pack xml read 테스트")
@Test
public void packXmlReadTest() throws IOException {
// JacksonXmlModule jacksonXmlModule = new JacksonXmlModule();
// jacksonXmlModule.setDefaultUseWrapper(false);
// //ObjectMapper xmlMapper = new XmlMapper(jacksonXmlModule);
// XmlMapper xmlMapper = new XmlMapper(jacksonXmlModule);
// xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
//
// PackDto dto
// = xmlMapper.readValue(packXml, PackDto.class);
//
// assertNotNull(dto);
//
// xmlMapper.writeValue(System.out, dto);
XML xml = new XML();
// Consumer<XmlMapper> configurer = xmlMapper -> {
// // 필수 필드 체크를 활성화
// xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, true);
// };
// xml.configure(configurer);
FileInputStream fileInputStream = new FileInputStream("pack.xml");
byte[] bytes = fileInputStream.readAllBytes();
String content = new String(bytes);
ApiUtil.validateXmlFromXmlStr(content, "src/main/resources/xsd/pack.xsd");
PackDto dto = xml.parse(content, new TypeReference<PackDto>() {});
log.info("dto: {}", dto);
@ -107,13 +61,6 @@ public class PackDtoTest {
assertEquals("senderSystemname", new String(Base64Utils.decodeFromString(dto.getHeader().getSenderSystemname())));
assertEquals("filename", new String(Base64Utils.decodeFromString(dto.getContents().getContent().get(0).getFilename())));
assertEquals("content-value", new String(Base64Utils.decodeFromString(dto.getContents().getContent().get(0).getValue())));
// XmlMapper xmlMapper = new XmlMapper();
// xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, true);
// PackDto dto = xmlMapper.readValue(packXml, PackDto.class);
// System.out.println("Generated XML:");
// xmlMapper.writeValue(System.out, dto);
}
@DisplayName("전자결재 pack xml write 테스트")
@ -128,53 +75,22 @@ public class PackDtoTest {
XMLOutputFactory factory = mapper.getFactory().getXMLOutputFactory();
String dtd = """
<!DOCTYPE pack SYSTEM "pack.dtd">
<!DOCTYPE pack SYSTEM "src/main/resources/xsd/pack.dtd">
""";
try (FileWriter w = new FileWriter("pack.xml")) {
XMLStreamWriter sw = factory.createXMLStreamWriter(w);
sw.writeStartDocument("EUC-KR", "1.0");
sw.writeDTD("\n"+dtd);
//sw.writeDTD("\n"+dtd);
sw.writeDTD("\n");
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.writeValue(sw, dto);
// StringWriter swr = new StringWriter();
// mapper.writeValue(swr, dto);
// System.out.println(swr.toString());
// FileInputStream fileInputStream = new FileInputStream("pack.xml");
// byte[] bytes = fileInputStream.readAllBytes();
// String content = new String(bytes);
// System.out.println(content);
ApiUtil.validateXmlFromFile("pack.xml", "src/main/resources/xsd/pack.xsd");
// PackDto rtnDto = toObjByXml(content, PackDto.class);
//
// StringWriter swr = new StringWriter();
// mapper.writeValue(swr, content);
//System.out.println(swr.toString());
}catch (XMLStreamException e) {
e.printStackTrace();
}
// FIXME: 파일명 생성
// try (FileOutputStream fos = new FileOutputStream("pack.xml");) {
// XML xml = new XML();
// //dto.configureXmlMapper(xml.getXmlMapper());
// xml.write(fos, dto, true);
// xml.write(System.out, dto, true);
// // XmlMapper xmlMapper = new XmlMapper();
// // dto.configureXmlMapper(xmlMapper);
// // //xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, true);
// // String str = xmlMapper.writeValueAsString(dto);
// // System.out.println("Generated XML:");
// // System.out.println(str);
// //fos.flush();
//
// }catch (Exception e) {
// e.printStackTrace();
// }
}
private static PackDto getPackDto() {
@ -213,17 +129,4 @@ public class PackDtoTest {
return packDto;
}
private static <T> T toObjByXml(String xml, final Class<T> cls){
ObjectMapper OM = new ObjectMapper();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(xml)));
return new XML().parse(xml, cls);
} catch (ParserConfigurationException | SAXException | IOException e) {
throw ApiCustomException.create(e.getMessage());
}
}
}

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="EUC-KR"?>
<!DOCTYPE EXCHANGE SYSTEM "exchange.dtd">
<EXCHANGE>
<HEADER>
<COMMON>
<SENDER>
<SERVERID>hangjung_groupware1</SERVERID>
<USERID>jspark</USERID>
</SENDER>
<RECEIVER>
<SERVERID>hangjung</SERVERID>
<USERID>cskim</USERID>
</RECEIVER>
<TITLE>전보대상자 명단제출</TITLE>
<CREATED_DATE>2005-07-15 17:44:06</CREATED_DATE>
<ATTACHNUM>0</ATTACHNUM>
<ADMINISTRATIVE_NUM>1234</ADMINISTRATIVE_NUM>
</COMMON>
<DIRECTION>
<TO_ADMINISTRATIVE_SYSTEM>
<DOCNUM docnumcode="1310505-90">총무-90</DOCNUM>
<SANCTION_INFO status="완료">
<LINES>
<LINE>
<LEVEL>1</LEVEL>
<SANCTION type="기안" result="상신">
<PERSON>
<USERID>honggilddong</USERID>
<NAME>홍길동</NAME>
<POSITION>주사</POSITION>
<DEPT>행정정보화팀</DEPT>
<ORG>행정자치부</ORG>
</PERSON>
<DATE>2005-07-16 10:05:03</DATE>
</SANCTION>
</LINE>
<LINE>
<LEVEL>2</LEVEL>
<SANCTION type="검토" result="승인">
<PERSON>
<USERID>chulsu</USERID>
<NAME>김철수</NAME>
<POSITION>사무관</POSITION>
<DEPT>행정정보화팀</DEPT>
<ORG>행정자치부</ORG>
</PERSON>
<DATE>2005-07-16 11:05:03</DATE>
</SANCTION>
</LINE>
<LINE>
<LEVEL>final</LEVEL>
<SANCTION type="전결" result="승인">
<PERSON>
<USERID>mjkim</USERID>
<NAME>김민주</NAME>
<POSITION>팀장</POSITION>
<DEPT>행정정보화팀</DEPT>
<ORG>행정자치부</ORG>
</PERSON>
<DATE/>
</SANCTION>
</LINE>
</LINES>
</SANCTION_INFO>
<MODIFICATION_FLAG>
<MODIFIABLE/>
</MODIFICATION_FLAG>
</TO_ADMINISTRATIVE_SYSTEM>
</DIRECTION>
</HEADER>
</EXCHANGE>
Loading…
Cancel
Save