diff --git a/pom.xml b/pom.xml index 883fef5a..ccccf764 100644 --- a/pom.xml +++ b/pom.xml @@ -56,8 +56,15 @@ local-repository - file://${basedir}/repo + file://${project.basedir}/repo + @@ -378,13 +385,43 @@ tiles-jsp ${org.apache.tiles.version} + + + org.apache.tiles + tiles-extras + ${org.apache.tiles.version} + + + + + + + + + @@ -674,7 +711,6 @@ 1.9.3 - @@ -740,8 +776,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 11 + 11 UTF-8 diff --git a/src/main/java/kr/xit/fims/biz/FimsConst.java b/src/main/java/kr/xit/fims/biz/FimsConst.java index 1882a6e5..3b907201 100644 --- a/src/main/java/kr/xit/fims/biz/FimsConst.java +++ b/src/main/java/kr/xit/fims/biz/FimsConst.java @@ -21,7 +21,7 @@ public class FimsConst { @AllArgsConstructor public enum FileJobSeCode { NATL_NEWS_PAPER_RCV("NATL_NEWS_PAPER_RCV", "민원심사-국민신문고") - ,BUS_ONLY("BUS_ONLY", "버스전용차로-버스장착형CCTV") + ,BUS_ONLY("BUS_ONLY", "버스장착형CCTV") ,CCTV_FIX("CCTV_FIX", "cctv-고정형") ,CCTV_DRV("CCTV_DRV", "cctv-주행형") ,CMM_BOARD("CMM_BOARD", "게시판-첨부파일") diff --git a/src/main/java/kr/xit/fims/biz/cmm/dto/FimsCrackdownDTO.java b/src/main/java/kr/xit/fims/biz/cmm/dto/FimsCrackdownDTO.java index 1dccf61c..1ad5681e 100644 --- a/src/main/java/kr/xit/fims/biz/cmm/dto/FimsCrackdownDTO.java +++ b/src/main/java/kr/xit/fims/biz/cmm/dto/FimsCrackdownDTO.java @@ -20,6 +20,7 @@ public class FimsCrackdownDTO { public static class Info extends RtDTO.Reglt { private String regltDeTime; + private int vhcleNoCnt; // CCTV 연계 key private String extrlRegltCntcId; diff --git a/src/main/java/kr/xit/fims/biz/cmm/mapper/IFimsCrackdownMgtMapper.java b/src/main/java/kr/xit/fims/biz/cmm/mapper/IFimsCrackdownMgtMapper.java index 96d01dee..4eb36249 100644 --- a/src/main/java/kr/xit/fims/biz/cmm/mapper/IFimsCrackdownMgtMapper.java +++ b/src/main/java/kr/xit/fims/biz/cmm/mapper/IFimsCrackdownMgtMapper.java @@ -35,4 +35,6 @@ public interface IFimsCrackdownMgtMapper { List selectCtznSttemntCmplt(final FimsCrackdownDTO.CtznSttemntCmplt dto); void saveCtznSttemntCmplt(FimsCrackdownDTO.CtznSttemntCmplt dto); + + int selectCrackdownVhcleNoCnt(final String vhcleNo); } diff --git a/src/main/java/kr/xit/fims/biz/cmm/service/FimsCrackdownMgtService.java b/src/main/java/kr/xit/fims/biz/cmm/service/FimsCrackdownMgtService.java index 739ed3fe..b1e9e22b 100644 --- a/src/main/java/kr/xit/fims/biz/cmm/service/FimsCrackdownMgtService.java +++ b/src/main/java/kr/xit/fims/biz/cmm/service/FimsCrackdownMgtService.java @@ -406,6 +406,16 @@ public class FimsCrackdownMgtService implements IFimsCrackdownMgtService { } } + public int findCrackdownVhcleNoCnt(final String vhcleNo){ + return mapper.selectCrackdownVhcleNoCnt(vhcleNo); + } + + + + + + + private CtznStmtDTO.Request getCtznRequestDTO(final FimsCrackdownDTO.SaveRequest saveDTO){ return CtznStmtDTO.Request .builder() @@ -422,4 +432,5 @@ public class FimsCrackdownMgtService implements IFimsCrackdownMgtService { + (Checks.isNotEmpty(o.getTlface())? o.getTlface(): "")) .orElseGet(() -> ""); } + } diff --git a/src/main/java/kr/xit/fims/biz/cmm/service/IFimsCrackdownMgtService.java b/src/main/java/kr/xit/fims/biz/cmm/service/IFimsCrackdownMgtService.java index a7d0275c..23b65ced 100644 --- a/src/main/java/kr/xit/fims/biz/cmm/service/IFimsCrackdownMgtService.java +++ b/src/main/java/kr/xit/fims/biz/cmm/service/IFimsCrackdownMgtService.java @@ -37,6 +37,9 @@ public interface IFimsCrackdownMgtService { String addCtznStmtAnswer(final String interfaceSeqN); void addCtznStmtAnswers(final List interfaceSeqList); + + int findCrackdownVhcleNoCnt(final String vhcleNo); + default XitLoginVO getUserInfo(){ return XitCmmnUtil.getUserInfo(); } diff --git a/src/main/java/kr/xit/fims/biz/cmm/web/FimsCrackDownMgtController.java b/src/main/java/kr/xit/fims/biz/cmm/web/FimsCrackDownMgtController.java index dc694f91..54b1886f 100644 --- a/src/main/java/kr/xit/fims/biz/cmm/web/FimsCrackDownMgtController.java +++ b/src/main/java/kr/xit/fims/biz/cmm/web/FimsCrackDownMgtController.java @@ -243,4 +243,9 @@ public class FimsCrackDownMgtController { AjaxMessageMapRenderer.success(mav, MessageKey.CMM_SUCCESS); return mav; } + + @RequestMapping("findCrackdownVhcleNoCnt") + public ModelAndView findCrackdownVhcleNoCnt(final String vhcleNo){ + return ResultResponse.of(service.findCrackdownVhcleNoCnt(vhcleNo)); + } } diff --git a/src/main/java/kr/xit/fims/biz/ec/service/EcCctvCrackdownService.java b/src/main/java/kr/xit/fims/biz/ec/service/EcCctvCrackdownService.java index 2e2b34ff..b42aa3b9 100644 --- a/src/main/java/kr/xit/fims/biz/ec/service/EcCctvCrackdownService.java +++ b/src/main/java/kr/xit/fims/biz/ec/service/EcCctvCrackdownService.java @@ -157,8 +157,8 @@ public class EcCctvCrackdownService implements IEcCctvCrackdownService { /** *
-     * 외부연계(tb_ec_extrl_reglt_cntc) 단속(버스전용차로(버스고정형CCTV) 데이타 생성
-     * 1) 버스전용차로 CCTV 단속정보파일 parsing
+     * 외부연계(tb_ec_extrl_reglt_cntc) 단속(버스장착형CCTV) 데이타 생성
+     * 1) 버스장착형 CCTV 단속정보파일 parsing
      * 2) tb_ec_extrl_reglt_cntc insert
      * 3) tb_cmm_file_mastr insert
      *    tb_cmm_file_detail insert
@@ -237,11 +237,11 @@ public class EcCctvCrackdownService implements IEcCctvCrackdownService {
                 );
 
             } catch (NullPointerException npe){
-                log.error("{}[{}]", "버스전용차로 데이타 parsing 에러::처리할 파일이 부정확 합니다.", fi.getFileNm());
+                log.error("{}[{}]", "버스장착형 데이타 parsing 에러::처리할 파일이 부정확 합니다.", fi.getFileNm());
             } catch (FileExistsException fee){
-                log.error("{}[{}]", "버스전용차로 데이타 parsing 에러::처리된 데이타 입니다.", fi.getFileNm());
+                log.error("{}[{}]", "버스장착형 데이타 parsing 에러::처리된 데이타 입니다.", fi.getFileNm());
             } catch (IOException ie){
-                log.error("버스전용차로 데이타 parsing 에러::{}", ie.getLocalizedMessage());
+                log.error("버스장착형 데이타 parsing 에러::{}", ie.getLocalizedMessage());
                 ie.printStackTrace();
             }
         });
diff --git a/src/main/java/kr/xit/fims/biz/rt/dto/RtDTO.java b/src/main/java/kr/xit/fims/biz/rt/dto/RtDTO.java
index 0551b3ac..a25165e1 100644
--- a/src/main/java/kr/xit/fims/biz/rt/dto/RtDTO.java
+++ b/src/main/java/kr/xit/fims/biz/rt/dto/RtDTO.java
@@ -2,6 +2,8 @@ package kr.xit.fims.biz.rt.dto;
 
 import java.io.Serializable;
 
+import kr.xit.framework.core.annotation.MaskRequired;
+import kr.xit.framework.core.annotation.mask.MaskingType;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
@@ -108,6 +110,7 @@ public class RtDTO {
         /**
          * 차량 번호
          */
+        @MaskRequired(type = MaskingType.NAME)
         private String vhcleNo;
         /**
          * 차량 명
diff --git a/src/main/java/kr/xit/fims/biz/sample/web/SampleController.java b/src/main/java/kr/xit/fims/biz/sample/web/SampleController.java
index 8c411ee6..05fbadfd 100644
--- a/src/main/java/kr/xit/fims/biz/sample/web/SampleController.java
+++ b/src/main/java/kr/xit/fims/biz/sample/web/SampleController.java
@@ -32,4 +32,14 @@ public class SampleController {
     public ModelAndView findSample(){
         return ResultResponse.of(sampleService.findSample());
     }
+
+    @RequestMapping("/hello")
+    public ModelAndView hello(){
+        String message = "프리마커";
+
+        ModelAndView mv = new ModelAndView();
+        mv.setViewName("hello");
+        mv.addObject("message", message);
+        return mv;
+    }
 }
diff --git a/src/main/java/kr/xit/framework/biz/util/ExtlFileParseUtils.java b/src/main/java/kr/xit/framework/biz/util/ExtlFileParseUtils.java
index dbc385c4..def6a1db 100644
--- a/src/main/java/kr/xit/framework/biz/util/ExtlFileParseUtils.java
+++ b/src/main/java/kr/xit/framework/biz/util/ExtlFileParseUtils.java
@@ -15,9 +15,9 @@ public class ExtlFileParseUtils {
 
     /**
      * 
-     * 버스전용차로 파일 parsing
+     * 버스장착형 파일 parsing
      * @param dto CctvCrackdownDTO.BusOnly DTO
-     * @param fullFilePath 버스전용차로 파일 full file path info
+     * @param fullFilePath 버스장착형 파일 full file path info
      * @param tempPath 파싱시 임시로 사용할 directory
      * 
*/ @@ -138,7 +138,7 @@ public class ExtlFileParseUtils { //FIXME: moving image수 체크 : 불필요 하면 삭제 // dto.getImgCnt() - moving image count 이므로, car image and carNum image (2개) 제외한 수량으로 check if(Integer.parseInt(dto.getImgCnt()) != dto.getBusonlyImgList().size() - 2){ - String errMsg = String.format("버스전용차로 단속이미지 정보[이미지수: %d, 실제이미지: %d]가 부정확 합니다[%s]", Integer.parseInt(dto.getImgCnt()), dto.getBusonlyImgList().size() - 2, fullFilePath); + String errMsg = String.format("버스장착형 단속이미지 정보[이미지수: %d, 실제이미지: %d]가 부정확 합니다[%s]", Integer.parseInt(dto.getImgCnt()), dto.getBusonlyImgList().size() - 2, fullFilePath); throw BizRuntimeException.create(MessageKey.CUSTOM_MSG, errMsg); } diff --git a/src/main/java/kr/xit/framework/core/annotation/MaskRequired.java b/src/main/java/kr/xit/framework/core/annotation/MaskRequired.java new file mode 100644 index 00000000..ef09a852 --- /dev/null +++ b/src/main/java/kr/xit/framework/core/annotation/MaskRequired.java @@ -0,0 +1,25 @@ +package kr.xit.framework.core.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.fasterxml.jackson.annotation.JacksonAnnotation; + +import kr.xit.framework.core.annotation.mask.MaskingType; + +/** + *
+ * masking 처리
+ * @MaskingRequired(type = MaskingType.NAME) annotaion이 붙은 필드 masking
+ * MaskingType.NAME | RN | CONTACT | MAIL | CARD | ADDRESS
+ * 

+ */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotation +//@JsonSerialize(using = MaskingPropertySerializer.class) +public @interface MaskRequired { + MaskingType type(); +} diff --git a/src/main/java/kr/xit/framework/core/annotation/mask/Masking.java b/src/main/java/kr/xit/framework/core/annotation/mask/Masking.java new file mode 100644 index 00000000..121d10cf --- /dev/null +++ b/src/main/java/kr/xit/framework/core/annotation/mask/Masking.java @@ -0,0 +1,169 @@ +package kr.xit.framework.core.annotation.mask; + +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Masking { + final static String MASKING_STAR = "*"; + final static char CHAR_STAR = '*'; + + public static String mask(MaskingType type, String value) { + switch (type) { + case NAME: + return maskingName(value); + case RN: + return maskingRn(value); + case CONTACT: + return maskingContact(value); + case MAIL: + return maskingMail(value); + case CARD: + return maskingCard(value); + case ADDRESS: + return maskingAddress(value); + default: + return ""; + } + } + + /** + *

+     * 이름 마스킹
+     * 2글자 이상의 이름은 가운데 글자 마스킹. 외자는 끝자리만 마스킹
+     * 

+ * @param name String + * @return String + *

+ */ + public static String maskingName(String name) { + + String NAME_MASKING_KO = "(?<=.{1})(?.*)(?=.$)"; + String NAME_MASKING_EN = "(?<=.{1})(?.*)(?=\\s)"; + + if(name.length() < 3) return name.substring(0, name.length() -1) + MASKING_STAR; + + // 영어인 경우 + if(name.charAt(0) >= 65 && name.charAt(0) <= 122){ + Pattern pattern = Pattern.compile(NAME_MASKING_EN); + Matcher m = pattern.matcher(name); + + if(m.find()) return name.replaceFirst(NAME_MASKING_EN, MASKING_STAR.repeat(m.group().length())); + //if(m.find()) return name.replaceFirst(NAME_MASKING_EN, StringUtils.repeat(MASKING_STAR, m.group().length())); + } + + // 한글인 경우 + return name.replaceFirst(NAME_MASKING_KO, MASKING_STAR.repeat(name.length() - 2)); + //return name.replaceFirst(NAME_MASKING_KO, StringUtils.repeat(MASKING_STAR, name.length() - 2)); + } + + /** + * 주민번호 마스킹 + * @param regNumber + * @return + */ + public static String maskingRn(String regNumber) { + + return regNumber.replaceAll("([0-9]{6})-([1-4]{1})([0-9]{6})", "$1-$2".concat(MASKING_STAR.repeat(6))); + } + + /** + * 휴대폰번호 마스킹 + * 가운데 숫자 4자리 마스킹이고, '-'(하이픈)이 들어오나 안들어오나, 숫자 길이와 형식이 맞으면 마스킹 처리 + * @param contactNo + * @return + */ + public static String maskingContact(String contactNo) { + String regex = "(\\d{2,3})-?(\\d{3,4})-?(\\d{4})$"; + + Matcher matcher = Pattern.compile(regex).matcher(contactNo); + if(matcher.find()) { + String target = matcher.group(2); + int length = target.length(); + char[] c = new char[length]; + Arrays.fill(c, CHAR_STAR); + + return contactNo.replace(target, String.valueOf(c)); + } + return contactNo; + } + + /** + * 이메일 마스킹(앞3자리 이후 '@'전까지 마스킹) + * @param email + * @return + */ + public static String maskingMail(String email) { + return email.replaceAll("[A-z|0-9|.-]+@", MASKING_STAR.repeat(5).concat("@")); + } + + + /** + * 카드번호 마스킹 + * 카드번호 가운데 8자리 마스킹 + *

+ * @param cardNo + * @return + */ + public static String maskingCard(String cardNo) { + return cardNo.replaceAll("(\\d{4})-(\\d{4})-(\\d{4})-(\\d{4})", "$1-****-****-$4"); + } + + + /** + * 주소 마스킹 + * 신주소, 구주소, 도로명 주소 숫자만 전부 마스킹 + * @param address + * @return + */ + public static String maskingAddress(String address) { + // 신(구)주소, 도로명 주소 + String regex = "(([가-힣]+(\\d{1,5}|\\d{1,5}(,|.)\\d{1,5}|)+(읍|면|동|가|리))(^구|)((\\d{1,5}(~|-)\\d{1,5}|\\d{1,5})(가|리|)|))([ ](산(\\d{1,5}(~|-)\\d{1,5}|\\d{1,5}))|)|"; + String newRegx = "(([가-힣]|(\\d{1,5}(~|-)\\d{1,5})|\\d{1,5})+(로|길))"; + + Matcher matcher = Pattern.compile(regex).matcher(address); + Matcher newMatcher = Pattern.compile(newRegx).matcher(address); + if(matcher.find()) { + return address.replaceAll("[0-9]", "*"); + } else if(newMatcher.find()) { + return address.replaceAll("[0-9]", "*"); + } + return address; + } + + + + /** + * 계좌번호 마스킹(뒤 5자리) + * @param accountNo + * @return + * @throws Exception + */ + public static String accountNoMasking(String accountNo) throws Exception { + // 계좌번호는 숫자만 파악하므로 + String regex = "(^[0-9]+)$"; + + Matcher matcher = Pattern.compile(regex).matcher(accountNo); + if(matcher.find()) { + int length = accountNo.length(); + if(length > 5) { + char[] c = new char[5]; + Arrays.fill(c, '*'); + + return accountNo.replace(accountNo, accountNo.substring(0, length-5) + String.valueOf(c)); + } + } + return accountNo; + } + + // 생년월일 마스킹(8자리) + public static String birthMasking(String birthday) throws Exception { + String regex = "^((19|20)\\d\\d)?([-/.])?(0[1-9]|1[012])([-/.])?(0[1-9]|[12][0-9]|3[01])$"; + + Matcher matcher = Pattern.compile(regex).matcher(birthday); + if(matcher.find()) { + return birthday.replace("[0-9]", "*"); + } + return birthday; + } +} diff --git a/src/main/java/kr/xit/framework/core/annotation/mask/MaskingPropertySerializer.java b/src/main/java/kr/xit/framework/core/annotation/mask/MaskingPropertySerializer.java new file mode 100644 index 00000000..f26edc51 --- /dev/null +++ b/src/main/java/kr/xit/framework/core/annotation/mask/MaskingPropertySerializer.java @@ -0,0 +1,54 @@ +package kr.xit.framework.core.annotation.mask; + +import java.io.IOException; +import java.util.Optional; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.introspect.Annotated; +import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import kr.xit.framework.core.annotation.MaskRequired; +public class MaskingPropertySerializer extends StdSerializer implements ContextualSerializer { + private MaskingType maskingType; + + protected MaskingPropertySerializer() { + super(String.class); + } + + public MaskingPropertySerializer(MaskingType maskingType) { + super(String.class); + this.maskingType = maskingType; + } + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeString(Masking.mask(maskingType, value)); + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) { + + return Optional.ofNullable(property) + .map(p -> p.getAnnotation(MaskRequired.class)) + .map(maskRequired -> new MaskingPropertySerializer(maskRequired.type())) + .orElse(null); + /* + MaskingType maskingTypeValue = null; + MaskRequired ann = null; + if (property != null) { + ann = property.getAnnotation(MaskRequired.class); + } + if (ann != null) { + maskingTypeValue = ann.type(); + } + return new MaskingPropertySerializer(maskingTypeValue); + + */ + } +} diff --git a/src/main/java/kr/xit/framework/core/annotation/mask/MaskingType.java b/src/main/java/kr/xit/framework/core/annotation/mask/MaskingType.java new file mode 100644 index 00000000..3836d470 --- /dev/null +++ b/src/main/java/kr/xit/framework/core/annotation/mask/MaskingType.java @@ -0,0 +1,10 @@ +package kr.xit.framework.core.annotation.mask; + +public enum MaskingType { + NAME, + RN, + CONTACT, + MAIL, + CARD, + ADDRESS +} diff --git a/src/main/java/kr/xit/framework/core/annotation/mask/MaskingUtils.java b/src/main/java/kr/xit/framework/core/annotation/mask/MaskingUtils.java new file mode 100644 index 00000000..41444e93 --- /dev/null +++ b/src/main/java/kr/xit/framework/core/annotation/mask/MaskingUtils.java @@ -0,0 +1,93 @@ +package kr.xit.framework.core.annotation.mask; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.AnnotationIntrospector; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.Annotated; +import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; +import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector; + +import kr.xit.framework.core.annotation.MaskRequired; +import lombok.Builder; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MaskingUtils { + + /** + *

+   * masking 처리
+   * @MaskingRequired(type = MaskingType.NAME) annotaion이 붙은 필드 masking
+   * MaskingType.NAME | RN | CONTACT | MAIL | CARD | ADDRESS
+   * 

+ * @param src + * @return + *

+ */ + public static String buildMaskingObject(final Object src) { + try { + ObjectMapper mapper = new ObjectMapper(); + AnnotationIntrospector sis = mapper.getSerializationConfig().getAnnotationIntrospector(); + AnnotationIntrospector ais = AnnotationIntrospectorPair.pair(sis, new MaskPropertyAnnotationIntrospector()); + + return mapper + .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE) + .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) + .setAnnotationIntrospector(ais) + + .writeValueAsString(src); + } catch (Exception e) { + log.error(e.getMessage()); + e.printStackTrace(); + } + return null; + } + + public static class MaskPropertyAnnotationIntrospector extends NopAnnotationIntrospector { + private static final long serialVersionUID = 1L; + + @Override + public Object findSerializer(Annotated am) { + MaskRequired annotation = am.getAnnotation(MaskRequired.class); + if (annotation != null) { + return MaskingPropertySerializer.class; + } + return null; + } + } + + public static void main(String[] args) { + TestDTO dto = TestDTO.builder() + .name("황길동") + .rn("200102-2039432") + .contact("0212345678") + .email("dm.m3dk.345@kk.co.kr") + .card("1234-5678-9012-3456") + .build(); + + log.debug(MaskingUtils.buildMaskingObject(dto)); + } + + + @Data + @Builder + static class TestDTO { + + @MaskRequired(type = MaskingType.NAME) + String name; + + @MaskRequired(type = MaskingType.RN) + String rn; + + @MaskRequired(type = MaskingType.CONTACT) + String contact; + + @MaskRequired(type = MaskingType.MAIL) + String email; + + @MaskRequired(type = MaskingType.CARD) + String card; + } +} diff --git a/src/main/java/kr/xit/framework/core/utils/captcha/XitCaptchaUtil.java b/src/main/java/kr/xit/framework/core/utils/captcha/XitCaptchaUtil.java index a454d8d3..96d57ebd 100644 --- a/src/main/java/kr/xit/framework/core/utils/captcha/XitCaptchaUtil.java +++ b/src/main/java/kr/xit/framework/core/utils/captcha/XitCaptchaUtil.java @@ -1,15 +1,25 @@ package kr.xit.framework.core.utils.captcha; +import java.awt.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; +import kr.xit.framework.support.captcha.SimpleCaptchaUtil; import nl.captcha.Captcha; +import nl.captcha.audio.AudioCaptcha; import nl.captcha.backgrounds.GradiatedBackgroundProducer; import nl.captcha.servlet.CaptchaServletUtil; +import nl.captcha.text.producer.NumbersAnswerProducer; +import nl.captcha.text.renderer.DefaultWordRenderer; @Controller public class XitCaptchaUtil { @@ -27,22 +37,34 @@ public class XitCaptchaUtil { */ public static void getImage(HttpServletRequest request, HttpServletResponse response) { - Captcha captcha = new Captcha.Builder(250, 50) //캡차 이미지 크기(가로,세로) - .addText() //이미지문구 생성(default: 5자리의 랜덤한 알파벳과 숫자 생성) -// .addText(new NumbersAnswerProducer()) //이미지문구 생성(5자리의 랜덤한 숫자 생성) - .addBackground(new GradiatedBackgroundProducer()) //바탕색 흰색 - Default - .addNoise() //한번 호출할 떄마다 하나의 라인이 추가된다. - .gimp() //Gradiated 백그라운드 -// .gimp(new DropShadowGimpyRenderer()) //그림자 효과 추가 - .addBorder() //검정 테두리 선 생성 - .build(); //필수 호출 함수 + /*폰트 및 컬러 설정*/ + List fontList = new ArrayList(); + fontList.add(new Font("", Font.HANGING_BASELINE, 40)); + fontList.add(new Font("Courier", Font.ITALIC, 40)); + fontList.add(new Font("", Font.PLAIN, 40)); + List colorList = new ArrayList(); + colorList.add(Color.BLACK); + //Captcha captcha = new Captcha.Builder(250, 50) //캡차 이미지 크기(가로,세로) + Captcha captcha = new Captcha.Builder(250, 50) //캡차 이미지 크기(가로,세로) + .addText(new NumbersAnswerProducer(6), new DefaultWordRenderer(colorList, fontList)) //이미지문구 생성(default: 5자리의 랜덤한 알파벳과 숫자 생성) +// .addText(new NumbersAnswerProducer()) //이미지문구 생성(5자리의 랜덤한 숫자 생성) + .addBackground(new GradiatedBackgroundProducer()) //바탕색 흰색 - Default + .addNoise() //한번 호출할 떄마다 하나의 라인이 추가된다. + .gimp() //Gradiated 백그라운드 +// .gimp(new DropShadowGimpyRenderer()) //그림자 효과 추가 + .addBorder() //검정 테두리 선 생성 + .build(); //필수 호출 함수 +/* response.setHeader("Cache-Control", "no-store"); response.setHeader("Pragma", "no-cache"); //브라우저 캐시 설정 response.setDateHeader("Expires", 0); response.setContentType("image/jpeg"); //리턴 컨텐츠타입 설정 - + + Capchas.net + JCAPCHA +*/ //image 생성 CaptchaServletUtil.writeImage(response, captcha.getImage()); @@ -52,6 +74,21 @@ public class XitCaptchaUtil { //요청세션에 저장 request.getSession().setAttribute("captcha", captcha); } - + + public void getAudioCaptCha(HttpServletRequest req, HttpServletResponse res, String answer) throws IOException { + HttpSession session = req.getSession(); + + Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME); + String getAnswer = answer; + + if(getAnswer == null || getAnswer.equals("")) getAnswer = captcha.getAnswer(); + + AudioCaptcha audiocaptcha = new AudioCaptcha.Builder() + .addAnswer(new SimpleCaptchaUtil.SetTextProducer(getAnswer)) + .addNoise() /*잡음 추가*/ + .build(); + + CaptchaServletUtil.writeAudio(res, audiocaptcha.getChallenge()); + } } diff --git a/src/main/java/kr/xit/framework/support/freemaker/FreeMarkerConfig.java b/src/main/java/kr/xit/framework/support/freemaker/FreeMarkerConfig.java new file mode 100644 index 00000000..02683786 --- /dev/null +++ b/src/main/java/kr/xit/framework/support/freemaker/FreeMarkerConfig.java @@ -0,0 +1,65 @@ +package kr.xit.framework.support.freemaker; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tiles.TilesContainer; +import org.apache.tiles.evaluator.AttributeEvaluatorFactory; +import org.apache.tiles.extras.complete.CompleteAutoloadTilesContainerFactory; +import org.apache.tiles.extras.complete.CompleteAutoloadTilesInitializer; +import org.apache.tiles.factory.AbstractTilesContainerFactory; +import org.apache.tiles.request.ApplicationContext; +import org.apache.tiles.request.ApplicationResource; +import org.apache.tiles.request.freemarker.render.FreemarkerRendererBuilder; +import org.apache.tiles.request.render.BasicRendererFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.view.UrlBasedViewResolver; +import org.springframework.web.servlet.view.tiles3.TilesConfigurer; + +//@Configuration +public class FreeMarkerConfig{ + + @Bean + public TilesConfigurer tilesConfigurer() { + + String tilesDefinitionPath = "classpath*:/WEB-INF/freemarker/layout-definition/tiles-layout.xml"; + + TilesConfigurer tilesConfigurer = new TilesConfigurer(); + tilesConfigurer.setTilesInitializer(new CompleteAutoloadTilesInitializer() { + @Override + protected AbstractTilesContainerFactory createContainerFactory(ApplicationContext context) { + // BasicTilesContainerFactory + return new CompleteAutoloadTilesContainerFactory() { + @Override + protected List getSources(ApplicationContext applicationContext) { + List retValue = new ArrayList(1); + retValue.add(applicationContext.getResource(tilesDefinitionPath)); + return retValue; + } + + @Override + protected void registerAttributeRenderers(BasicRendererFactory rendererFactory, ApplicationContext applicationContext, TilesContainer container, AttributeEvaluatorFactory attributeEvaluatorFactory) { + super.registerAttributeRenderers(rendererFactory, applicationContext, container, attributeEvaluatorFactory); + FreemarkerRendererBuilder freemarkerRenderer = FreemarkerRendererBuilder.createInstance(); + freemarkerRenderer.setApplicationContext(applicationContext); + freemarkerRenderer.setParameter("defaultEncoding", "UTF-8"); + //freemarkerRenderer.setParameter("ClasspathTlds", "/META-INF/tld/tiles-jsp.tld, /META-INF/spring.tld"); + //freemarkerRenderer.setParameter("autoInclude", "/WEB-INF/freemarker/common/common.ftl"); + freemarkerRenderer.setParameter("NoCache", "true"); + rendererFactory.registerRenderer("freemarker", freemarkerRenderer.build()); + } + }; + } + }); + return tilesConfigurer; + } + + // @Bean + // public UrlBasedViewResolver tilesViewResolver() { + // UrlBasedViewResolver urlBasedViewResolver = new UrlBasedViewResolver(); + // urlBasedViewResolver.setViewClass(TilesView.class); + // urlBasedViewResolver.setRequestContextAttribute("rc"); + // return urlBasedViewResolver; + // } +} diff --git a/src/main/java/kr/xit/framework/support/logback/LogbackMaskingPatternLayout.java b/src/main/java/kr/xit/framework/support/logback/LogbackMaskingPatternLayout.java new file mode 100644 index 00000000..131b2bd1 --- /dev/null +++ b/src/main/java/kr/xit/framework/support/logback/LogbackMaskingPatternLayout.java @@ -0,0 +1,59 @@ +package kr.xit.framework.support.logback; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.PatternLayout; + +/** + * logback log masking + *

+ * + * + * + * \"SSN\"\s*:\s*\"(.*?)\" + * \"address\"\s*:\s*\"(.*?)\" + * (\d+\.\d+\.\d+\.\d+) + * (\w+@\w+\.\w+) + * %-5p [%d{ISO8601,UTC}] [%thread] %c: %m%n%rootException + * + * + * + * + */ +public class LogbackMaskingPatternLayout extends PatternLayout { + + private Pattern multilinePattern; + private List maskPatterns = new ArrayList<>(); + + public void addMaskPattern(String maskPattern) { + maskPatterns.add(maskPattern); + multilinePattern = Pattern.compile(maskPatterns.stream().collect(Collectors.joining("|")), Pattern.MULTILINE); + } + + @Override + public String doLayout(ILoggingEvent event) { + return maskMessage(super.doLayout(event)); + } + + private String maskMessage(String message) { + if (multilinePattern == null) { + return message; + } + StringBuilder sb = new StringBuilder(message); + Matcher matcher = multilinePattern.matcher(sb); + while (matcher.find()) { + IntStream.rangeClosed(1, matcher.groupCount()).forEach(group -> { + if (matcher.group(group) != null) { + IntStream.range(matcher.start(group), matcher.end(group)).forEach(i -> sb.setCharAt(i, '*')); + } + }); + } + return sb.toString(); + } +} diff --git a/src/main/resources/logback-local.xml b/src/main/resources/logback-local.xml index f1157003..71bac6a9 100644 --- a/src/main/resources/logback-local.xml +++ b/src/main/resources/logback-local.xml @@ -11,7 +11,11 @@ - + + + + + ${LOG_PATTERN} diff --git a/src/main/resources/spring/context-service.xml b/src/main/resources/spring/context-service.xml index 0d867004..5a545f8d 100644 --- a/src/main/resources/spring/context-service.xml +++ b/src/main/resources/spring/context-service.xml @@ -22,4 +22,6 @@ + + diff --git a/src/main/resources/spring/mvc/mvc-resolver.xml b/src/main/resources/spring/mvc/mvc-resolver.xml index c5c6ad33..b3ad8946 100644 --- a/src/main/resources/spring/mvc/mvc-resolver.xml +++ b/src/main/resources/spring/mvc/mvc-resolver.xml @@ -65,6 +65,18 @@ + + + + diff --git a/src/main/resources/spring/mvc/mvc-scan.xml b/src/main/resources/spring/mvc/mvc-scan.xml index b23cc8af..04dc8ba3 100644 --- a/src/main/resources/spring/mvc/mvc-scan.xml +++ b/src/main/resources/spring/mvc/mvc-scan.xml @@ -46,6 +46,7 @@ + diff --git a/src/main/resources/spring/service/context-freemaker.xml b/src/main/resources/spring/service/context-freemaker.xml new file mode 100644 index 00000000..326ea347 --- /dev/null +++ b/src/main/resources/spring/service/context-freemaker.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/spring/service/context-scan.xml b/src/main/resources/spring/service/context-scan.xml index 68504966..9e0fa8a4 100644 --- a/src/main/resources/spring/service/context-scan.xml +++ b/src/main/resources/spring/service/context-scan.xml @@ -11,6 +11,7 @@ + diff --git a/src/main/resources/sqlmapper/biz/cmm/cmm-fims-crackdown-mysql-mapper.xml b/src/main/resources/sqlmapper/biz/cmm/cmm-fims-crackdown-mysql-mapper.xml index 2ee3aff0..1d729543 100644 --- a/src/main/resources/sqlmapper/biz/cmm/cmm-fims-crackdown-mysql-mapper.xml +++ b/src/main/resources/sqlmapper/biz/cmm/cmm-fims-crackdown-mysql-mapper.xml @@ -63,6 +63,11 @@ , trp.detail_adres , trp.legaldong_code -- 법정동 코드 , IF(trr.reglt_se_code = '09', tecsd.violt_dtls_nm, teerc.violt_dtls_nm) AS violtDtlsNm -- 위반내용 + , (SELECT COUNT(reglt_id) + FROM tb_rt_reglt tgt + WHERE tgt.vhcle_no = trr.vhcle_no + AND NOT NULLIF(trr.vhcle_no, '') IS NULL + ) AS vhcleNoCnt FROM tb_rt_reglt trr LEFT JOIN tb_ec_extrl_reglt_cntc teerc ON trr.reglt_id = teerc.reglt_id @@ -417,4 +422,12 @@ + + diff --git a/src/main/resources/sqlmapper/biz/rt/rt-reglt-and-erpp-mysql-mapper.xml b/src/main/resources/sqlmapper/biz/rt/rt-reglt-and-erpp-mysql-mapper.xml index 562f7161..49309d06 100644 --- a/src/main/resources/sqlmapper/biz/rt/rt-reglt-and-erpp-mysql-mapper.xml +++ b/src/main/resources/sqlmapper/biz/rt/rt-reglt-and-erpp-mysql-mapper.xml @@ -456,7 +456,7 @@ ON tcfm.file_mastr_id = tcfd.file_mastr_id WHERE tcfm.job_se_code = #{jobSeCode} - -- 외부연계 : CCTV-고정형, CCTV-이동형, CCTV-버스장착형(버스전용차로) + -- 외부연계 : CCTV-고정형, CCTV-이동형, CCTV-버스장착형 AND tcfm.file_job_id = (SELECT extrl_reglt_cntc_id FROM tb_ec_extrl_reglt_cntc WHERE reglt_id = #{regltId}) diff --git a/src/main/webapp/WEB-INF/ftl/hello.ftl b/src/main/webapp/WEB-INF/ftl/hello.ftl new file mode 100644 index 00000000..6acd18b1 --- /dev/null +++ b/src/main/webapp/WEB-INF/ftl/hello.ftl @@ -0,0 +1,10 @@ +<#ftl encoding="utf-8"/> + + + + 네이바 프리마카 + + +

컨트롤러의 메세지: ${message}

+ + diff --git a/src/main/webapp/WEB-INF/jsp/fims/biz/cmm/cmmCrackdownRcvFilePopup.jsp b/src/main/webapp/WEB-INF/jsp/fims/biz/cmm/cmmCrackdownRcvFilePopup.jsp index c3776fc5..5765f039 100644 --- a/src/main/webapp/WEB-INF/jsp/fims/biz/cmm/cmmCrackdownRcvFilePopup.jsp +++ b/src/main/webapp/WEB-INF/jsp/fims/biz/cmm/cmmCrackdownRcvFilePopup.jsp @@ -36,7 +36,7 @@ Date Author Description - + 동일한 데이타 선택시 중복 처리될수 있습니다. diff --git a/src/main/webapp/WEB-INF/jsp/fims/biz/cmm/cmmFimsCrackdownEditPopup.jsp b/src/main/webapp/WEB-INF/jsp/fims/biz/cmm/cmmFimsCrackdownEditPopup.jsp index 43d08695..3ae11736 100644 --- a/src/main/webapp/WEB-INF/jsp/fims/biz/cmm/cmmFimsCrackdownEditPopup.jsp +++ b/src/main/webapp/WEB-INF/jsp/fims/biz/cmm/cmmFimsCrackdownEditPopup.jsp @@ -45,6 +45,11 @@ Date Author Description .curImgData { border: 1px solid black; } + /* 단속 건수 */ + .empCls { + color: #2a48ff; + background-color: #d8e7ff; + } @@ -563,14 +564,14 @@ Date Author Description

개별자료 민원 등록내역

신규작성 -
+

차량번호 민원 등록내역

신규작성 -
+
@@ -613,6 +614,7 @@ Date Author Description <%-- --%> + <%@include file="/WEB-INF/jsp/framework/biz-popup-tab-btn.jsp" %> @@ -629,6 +631,8 @@ Date Author Description const ARR_TAP_TOTCNT = [0, 0, 0, 0, 0]; let CUR_TAB_SEQ = 0; //var callbackSearch = () => fnPopupBiz.search(); + // 처리상태변경이력 : regltId, 주소변경이력, 전자고지발송이력 : payerId, 개별민원등록이력: interfaceSeqN, 차량번호민원등록리력: vhcleNo + let schParam = null; /* ******************************* @@ -658,6 +662,14 @@ Date Author Description setFormData(document.querySelector('#frmReglt'), {...res.ctznDTO, ...res.infoDTO}); setFormData(document.querySelector('#frmPayer'), res.payerDTO); + + schParam = { + regltId: res.infoDTO?.regltId, + payerId: res.payerDTO?.payerId, + interfaceSeqN: res.infoDTO.interfaceSeqN, + vhcleNo: res.infoDTO?.vhcleNo + } + fnPopupBiz.reloadGrid(); } }) } @@ -728,6 +740,9 @@ Date Author Description $('tr[id*=ctzn]').hide(); } } + ,reloadGrid: (idx) => { + ARR_TAP_GRID.forEach(grid => grid.reloadData()) + } }; /************************************************************************** @@ -773,15 +788,16 @@ Date Author Description }); $("#popupTabs").on("click", "li", function () { - const popTab = parseInt($("#popupTabs .ui-tabs-active a").attr("id")); - if(popTab === 2){ - ARR_TAP_GRID[0].reloadData(); - ARR_TAP_GRID[1].reloadData(); - ARR_TAP_GRID[2].reloadData(); - }else if(popTab === 3){ - ARR_TAP_GRID[3].reloadData(); - ARR_TAP_GRID[4].reloadData(); - } + fnPopupBiz.reloadGrid(); + //const popTab = parseInt($("#popupTabs .ui-tabs-active a").attr("id")); + // if(popTab === 2){ + // ARR_TAP_GRID[0].reloadData(); + // ARR_TAP_GRID[1].reloadData(); + // ARR_TAP_GRID[2].reloadData(); + // }else if(popTab === 3){ + // ARR_TAP_GRID[3].reloadData(); + // ARR_TAP_GRID[4].reloadData(); + // } }); $('#btnMinWonNew').on('click', () => { @@ -818,37 +834,46 @@ Date Author Description * Grid ****************************** */ const initPopupGrid = () => { - const tab0Columns = [ //Grid 컬럼 정보(명칭,매핑 field, 기타옵션 등) + const changeStsHisColumns = [ //Grid 컬럼 정보(명칭,매핑 field, 기타옵션 등) { header: '일시', name: 'registDt', - width: 90, - //editor: 'text', + minWidth: 120, sortable: true, align: 'center', - filter: { - type: 'text', - showClearBtn: true + formatter({value}) { + return setDateTimeFmt(value); } + // filter: { + // type: 'text', + // showClearBtn: true + // } }, { header: '처리상태', name: 'regltProcessSttusCode', - width: 90, - //editor: 'text', + minWidth: 90, sortable: true, - align: 'center' + align: 'center', + formatter: 'listItemText', + disabled: true, + editor: { + type: "select", + options: { + listItems: ComboCodeData.regltProcessSttusCode + } + } }, { header: '특기사항', name: 'spcmntMatter', - width: 110, + minWidth: 110, //editor: 'text', sortable: true, align: 'center' } ]; - const tab1Columns = [ //Grid 컬럼 정보(명칭,매핑 field, 기타옵션 등) + const addrHisColumns = [ //Grid 컬럼 정보(명칭,매핑 field, 기타옵션 등) { header: '변경일시', name: 'registDt', @@ -866,7 +891,8 @@ Date Author Description align: 'center' } ]; - const tab2Columns = [ //Grid 컬럼 정보(명칭,매핑 field, 기타옵션 등) + + const etrnNotiHisColumns = [ //Grid 컬럼 정보(명칭,매핑 field, 기타옵션 등) { header: '전자고지발송여부', name: '', @@ -1012,7 +1038,7 @@ Date Author Description align: 'center' } ]; - const tab4Columns = [ //Grid 컬럼 정보(명칭,매핑 field, 기타옵션 등) + const vhcleNoCplntHisColumns = [ //Grid 컬럼 정보(명칭,매핑 field, 기타옵션 등) { header: '등록일시', name: 'registDt', @@ -1055,66 +1081,72 @@ Date Author Description } ]; - const tab3Columns = tab4Columns.filter((_, index) => index !== 3 ); + const cplntHisColumns = vhcleNoCplntHisColumns.filter((_, index) => index !== 3 ); - //DataSource - const tab0Datasource = { - //initialRequest: false, // 화면 load시 조회 안함 - default + // 처리상태 변경 이력 DataSource + const changStsHisDatasource = { + //initialRequest: true, // 화면 load시 조회 안함 - default api: { readData: { url: fimsApiUrl.FIND_PROCESS_STTUS_CHANGE_HIST - , serializer: (params) => fnAddPageInfo(document.frmReglt, params) + , serializer: (params) => getPageParam({regltId: schParam.regltId}, params) } } }; - const tab1Datasource = { - //initialRequest: false, // 화면 load시 조회 안함 - default + + // 주소 변경 이력 datasource + const addrHisDatasource = { + //initialRequest: true, // 화면 load시 조회 안함 - default api: { readData: { url: fimsApiUrl.FIND_PAYER_ADRES_HIST - , serializer: (params) => { - return fnAddPageInfo(document.frmPayer, params) - } + , serializer: (params) => getPageParam({payerId: schParam.payerId}, params) } } }; - const tab2Datasource = { - //initialRequest: false, // 화면 load시 조회 안함 - default + + // 전자고지 발송 이력 datasource + const etrnNotiSndHisDatasource = { + //initialRequest: true, // 화면 load시 조회 안함 - default api: { readData: { url: fimsApiUrl.FIND_ELCTRN_NTIC_SNDNG - , serializer: (params) => { - return fnAddPageInfo(document.frmReglt, params); - } + , serializer: (params) => getPageParam({payerId: schParam.payerId}, params) } } }; - const tab3Datasource = { - //initialRequest: false, // 화면 load시 조회 안함 - default + + // 민원 등록 이력 datasource + const cplntHisDatasource = { + //initialRequest: true, // 화면 load시 조회 안함 - default api: { readData: { url: fimsApiUrl.FIND_CTZN_STTEMNT_CMPLT - , serializer: (params) => { - params = Object.assign(params,{gubun:0, payerId: $("#payerId").val(), regltId: '${param.regltId}'}); - return fnAddPageInfo(document.frmCmplt, params); - } + , serializer: (params) => getPageParam({gubun: 0, payerId: schParam.payerId, regltId: schParam.regltId}, params) + //params = Object.assign(params,{gubun:0, payerId: $("#payerId").val(), regltId: '${param.regltId}'}); + //return fnAddPageInfo(document.frmCmplt, params); + //} } } }; - const tab4Datasource = { + + // 차량번호 민원 등록 이력 datasource + const vhcleNoCplntHisHisDatasource = { //initialRequest: false, // 화면 load시 조회 안함 - default api: { readData: { url: fimsApiUrl.FIND_CTZN_STTEMNT_CMPLT - , serializer: (params) => { - params = Object.assign(params,{gubun:1, vhcleNo: $("#vhcleNo").val()}); - return fnAddPageInfo(document.frmCmplt, params); - } + , serializer: (params) => getPageParam({gubun: 1, vhcleNo: schParam.vhcleNo}, params) + //params = Object.assign(params,{gubun:1, vhcleNo: $("#vhcleNo").val()}); + //return fnAddPageInfo(document.frmCmplt, params); + //} } } }; - const tab0Options = { - el: 'grid_t0', + + // 처리상태 변경 이력 + const changStsHisOptions = { + el: 'grid_sts_change_his', minBodyHeight: 100, bodyHeight: 250, //[선택]Grid 높이 (number(단위: px)|'auto'|'fitToParent') rowHeaders: ['rowNum'], @@ -1127,31 +1159,33 @@ Date Author Description , minWidth: 80 //최소 사이즈 }, }; - const tab1Options = $.extend(true, {}, tab0Options, { + + // 주소 변경 이력 + const addrHisOptions = $.extend(true, {}, changStsHisOptions, { minBodyHeight: 100, bodyHeight: 100, }); - const tab2Options = $.extend(true, {}, tab0Options, { + + // 전자고지 발송 이력 + const etrnNotiHisOptions = $.extend(true, {}, changStsHisOptions, { minBodyHeight: 250, bodyHeight: 250, }); - ARR_TAP_GRID[0] = TuiGrid.of({...tab0Options, columns: tab0Columns}, tab0Datasource, (res) => { - // ARR_TAP_TOTCNT[0] = res.data.pagination.totalCount; + ARR_TAP_GRID[0] = TuiGrid.of({...changStsHisOptions, columns: changeStsHisColumns}, changStsHisDatasource, (res) => { + ARR_TAP_GRID[0].resetData([]); + ARR_TAP_GRID[0].refreshLayout(); }); - ARR_TAP_GRID[1] = TuiGrid.of({...tab1Options, el: 'grid_d1', columns: tab1Columns}, tab1Datasource, (res) => { - // ARR_TAP_TOTCNT[1] = res.data.pagination.totalCount; + + ARR_TAP_GRID[1] = TuiGrid.of({...addrHisOptions, el: 'grid_addr_his', columns: addrHisColumns}, addrHisDatasource, (res) => { }); - ARR_TAP_GRID[2] = TuiGrid.of({...tab1Options, el: 'grid_d2', columns: tab2Columns}, tab2Datasource, (res) => { - // ARR_TAP_TOTCNT[2] = res.data.pagination.totalCount; + ARR_TAP_GRID[2] = TuiGrid.of({...addrHisOptions, el: 'grid_etrn_noti_his', columns: etrnNotiHisColumns}, etrnNotiSndHisDatasource, (res) => { }); - ARR_TAP_GRID[3] = TuiGrid.of({...tab2Options, el: 'grid_m1', columns: tab3Columns}, tab3Datasource, (res) => { - // ARR_TAP_TOTCNT[3] = res.data.pagination.totalCount; + ARR_TAP_GRID[3] = TuiGrid.of({...etrnNotiHisOptions, el: 'grid_cplnt', columns: cplntHisColumns}, cplntHisDatasource, (res) => { console.log(res); ARR_TAP_GRID[3].resetData(res.data?.contents); }); - ARR_TAP_GRID[4] = TuiGrid.of({...tab2Options, el: 'grid_m2', columns: tab4Columns}, tab4Datasource, (res) => { - // ARR_TAP_TOTCNT[4] = res.data.pagination.totalCount; + ARR_TAP_GRID[4] = TuiGrid.of({...etrnNotiHisOptions, el: 'grid_vhcle_no_cplnt', columns: vhcleNoCplntHisColumns}, vhcleNoCplntHisHisDatasource, (res) => { }); const gridResposeSet = (res, idx) => { @@ -1178,13 +1212,15 @@ Date Author Description $(document).ready(function(){ initPopupGrid(); $("#popupTabs").tabs({active : 0}); - orgData = $('form').serialize(); +// orgData = $('form').serialize(); fnPopupBiz.search({ regltId: '${param.regltId}' ,regltSeCode: '${param.regltSeCode}' ,regltProcessSttusCode: '${param.regltProcessSttusCode}' }) + //initPopupGrid(); + }); diff --git a/src/main/webapp/WEB-INF/jsp/fims/biz/ec/ecCctvCrackdownFileSelPopup.jsp b/src/main/webapp/WEB-INF/jsp/fims/biz/ec/ecCctvCrackdownFileSelPopup.jsp index ba34d4c3..55f77e7e 100644 --- a/src/main/webapp/WEB-INF/jsp/fims/biz/ec/ecCctvCrackdownFileSelPopup.jsp +++ b/src/main/webapp/WEB-INF/jsp/fims/biz/ec/ecCctvCrackdownFileSelPopup.jsp @@ -24,7 +24,7 @@ - + 동일한 데이타 선택시 중복 처리될수 있습니다. diff --git a/src/main/webapp/WEB-INF/jsp/fims/biz/rt/rtCrackdownMgtMainForm.jsp b/src/main/webapp/WEB-INF/jsp/fims/biz/rt/rtCrackdownMgtMainForm.jsp index cdce115a..e1bffacc 100644 --- a/src/main/webapp/WEB-INF/jsp/fims/biz/rt/rtCrackdownMgtMainForm.jsp +++ b/src/main/webapp/WEB-INF/jsp/fims/biz/rt/rtCrackdownMgtMainForm.jsp @@ -574,7 +574,8 @@ Date Author Description frozenCount: 6 } ,pageOptions: { - perPage: 1000 + perPage: 1000, + type: 'scroll' } }; @@ -589,7 +590,11 @@ Date Author Description } } }; - const gridResposeSet = (res, idx) => { + const gridResponseReset = (res, idx) => { + // FIXME:: scroll type 사용시 + ARR_GRID[idx].resetData([]); + ARR_GRID[idx].refreshLayout(); + // FIXME:: scroll type 사용시 ARR_TOTCNT[idx] = res.data.pagination.totalCount; $('#totCnt span').text(ARR_TOTCNT[idx]); const gridInfo = ARR_NAV[idx]?.gridInfo; @@ -614,12 +619,12 @@ Date Author Description fnBiz.setDblClickEvent(idx); } const initGrid = () => { - ARR_GRID[0] = TuiGrid.of(gridOptions, gridDatasource, (res) => gridResposeSet(res, 0)); + ARR_GRID[0] = TuiGrid.of(gridOptions, gridDatasource, (res) => gridResponseReset(res, 0)); const options = $.extend(gridOptions, gridOptions.columns[1].renderer = null, true); //const options = {...gridOptions} //options.columns[1].renderer = null; - ARR_GRID[1] = TuiGrid.of({...options, el: 'grid_t1', rowHeaders: ['checkbox','rowNum']}, gridDatasource, (res) => gridResposeSet(res, 1)); - ARR_GRID[2] = TuiGrid.of({...options, el: 'grid_t2', rowHeaders: ['checkbox','rowNum']}, gridDatasource, (res) => gridResposeSet(res, 2)); + ARR_GRID[1] = TuiGrid.of({...options, el: 'grid_t1', rowHeaders: ['checkbox','rowNum']}, gridDatasource, (res) => gridResponseReset(res, 1)); + ARR_GRID[2] = TuiGrid.of({...options, el: 'grid_t2', rowHeaders: ['checkbox','rowNum']}, gridDatasource, (res) => gridResponseReset(res, 2)); }; /************************************************************************** * initialize diff --git a/src/main/webapp/resources/biz/common/js/codeComboData.js b/src/main/webapp/resources/biz/common/js/codeComboData.js index b7f9ae48..fab6b19e 100644 --- a/src/main/webapp/resources/biz/common/js/codeComboData.js +++ b/src/main/webapp/resources/biz/common/js/codeComboData.js @@ -67,9 +67,9 @@ ComboCodeData = { // 위반내역코드(전용차로) : FIM005 ,violtDtlsCode2: [ {value: '01', text: '버스전용차로'} - ,{value: '02', text: '버스전용차로'} - ,{value: '03', text: '다인승전용차로'} - ,{value: '04', text: '자전거전용차'} + ,{value: '02', text: '다인승전용차로'} + ,{value: '03', text: '자전거전용차로'} + ,{value: '04', text: '간선급행버스(BRT)전용주행로'} ] // 단속 특별 구역 구분 코드 : FIM006 diff --git a/src/main/webapp/resources/biz/common/js/fimsApiURL.js b/src/main/webapp/resources/biz/common/js/fimsApiURL.js index 5858fc64..5757b45c 100644 --- a/src/main/webapp/resources/biz/common/js/fimsApiURL.js +++ b/src/main/webapp/resources/biz/common/js/fimsApiURL.js @@ -17,6 +17,7 @@ const fimsApiUrl = { ,ADD_CTZN_ANS: '/fims/biz/cmm/addCtznStmtAnswer.do' //시민신고 답변 생성 ,ADD_CTZN_ANS_LIST: '/fims/biz/cmm/addCtznStmtAnswers.do' //시민신고 목록 답변 생성 ,FIND_CTZN_ANS_TMPL_INFO: '/fims/biz/cmm/findCtznAnswerTmplInfo.do' //시민신고 답변 템플릿 조회 + ,FIND_CRACKDOWN_VHCLE_NO_CNT: '/fims/biz/cmm/findCrackdownVhcleNoCnt.do' //차량 단속건수 조회 ,FIND_PROCESS_STTUS_CHANGE_HIST: '/fims/biz/cmm/findProcessSttusChangeHist.do' ,FIND_PAYER_ADRES_HIST: '/fims/biz/cmm/findPayerAdresHist.do' @@ -46,18 +47,18 @@ const fimsApiUrl = { ,SAVE_EC_CTZN_STMT_ANSWER: '/fims/biz/ec/saveCtznStmtAns.do' //주민신고 답변 생성 - //외부연계처리 - CCTV 데이타 관리(cctv고정형 / 이동형, 버스전용차로) + //외부연계처리 - CCTV 데이타 관리(cctv고정형 / 이동형 / 버스장착형) ,POPUP_CCTV_EC_EXTRL_REGLT_CNTC_INFO: '/fims/biz/ec/ecCctvCrackdownPopup.do' //CCTV 외부연계 데이타 상세 ,POPUP_CCTV_EC_EXTRL_REGLT_CNTC_DATA_SEL: '/fims/biz/ec/ecCctvCrackdownFileSelPopup.do' //CCTV 외부연계 데이타 선택 ,FIND_CCTV_EC_EXTRL_REGLT_CNTCS: '/fims/biz/ec/findExtrlRegltCntcs.do' //CCTV 외부연계 데이타 목록 조회 ,FIND_CCTV_EC_EXTRL_REGLT_CNTC: '/fims/biz/ec/findExtrlRegltCntc.do' //CCTV 외부연계 데이타 목록 조회 ,FIND_CCTV_EC_EXTRL_REGLT_CNTC_AND_ATTCH_FILES: '/fims/biz/ec/findExtrlRegltCntcAndAttchFiles.do' //CCTV 외부연계 정보 및 첨부파일 조회 ,SAVE_CCTV_EC_EXTRL_REGLT_CNTCS: '/fims/biz/ec/saveCctvCrackdownDatas.do' //CCTV 외부연계(고정형 / 이동형) 데이타 저장 - ,SAVE_BUS_ONLY_EC_EXTRL_REGLT_CNTC: '/fims/biz/ec/saveBusCctvCrackdownDatas.do' //CCTV 외부연계(버스전용차료) 데이타 저장 + ,SAVE_BUS_ONLY_EC_EXTRL_REGLT_CNTC: '/fims/biz/ec/saveBusCctvCrackdownDatas.do' //CCTV 외부연계(버스장착형) 데이타 저장 ,MODIFY_EC_EXTRL_REGLT_CNTC: '/fims/biz/ec/modifyExtrlRegltCntc.do' //CCTV 외부연계 데이타 변경 ,SAVE_EC_EXTRL_REGLT_CNTC_RT_REGLT: '/fims/biz/ec/saveExtrRtReglt.do' //CCTV 외부연계 데이타 단속자료 생성 ,SAVE_EC_EXTRL_REGLT_CNTC_RT_ERPP: '/fims/biz/ec/saveExtrRtErpp.do' //CCTV 외부연계 데이타 서손자료 생성 - ,FIND_BUS_ONLY_EC_EXTRL_REGLT_CNTC_ATTCH_FILES: '/fims/biz/ec/findBusCctvCrackdownFiles.do' //CCTV 외부연계(버스전용차료) 데이타 조회 + ,FIND_BUS_ONLY_EC_EXTRL_REGLT_CNTC_ATTCH_FILES: '/fims/biz/ec/findBusCctvCrackdownFiles.do' //CCTV 외부연계(버스장착형) 데이타 조회 ,FIND_EC_EXTRL_REGLT_CNTC_ATTCH_FILES: '/fims/biz/ec/findExtrlRegltCntcAttchFiles.do' //CCTV 외부연계 첨부파일 목록 조회 //단속관리 - 단속현황관리 diff --git a/src/main/webapp/resources/biz/common/js/popupPageNavigation.js b/src/main/webapp/resources/biz/common/js/popupPageNavigation.js index b7316212..ae120feb 100644 --- a/src/main/webapp/resources/biz/common/js/popupPageNavigation.js +++ b/src/main/webapp/resources/biz/common/js/popupPageNavigation.js @@ -30,16 +30,34 @@ class PageNavigation { * @param {number} gridDataPos 현재 그리드 페이지의 데이타 row */ constructor(GRID, gridDatas, gridDataPos) { - const {itemsPerPage, totalItems} = GRID.getPagination()._options; - const page = GRID.getPagination()._currentPage; + let pageInfo = { + page: 1, + perPage: null, + totalCount: null + } + // pageOptions type에 따라 paging 정보 위치가 달라 분기 처리 + if(GRID.store.data.pageOptions.type === 'scroll'){ + //const {page, perPage, totalCount} = GRID.store.data.pageOptions; + const {page, perPage, totalCount} = GRID.store.data.pageOptions; + pageInfo.page = page; + pageInfo.perPage = perPage; + pageInfo.totalCount = totalCount; + + }else{ + const {itemsPerPage, totalItems} = GRID.getPagination()._options; + pageInfo.page = GRID.getPagination()._currentPage; + pageInfo.perPage = itemsPerPage; + pageInfo.totalCount = totalItems; + } + this.gridInfo = { gridDatas ,gridDataPos ,curRowData: gridDatas[gridDataPos] - ,curRowPos: (page - 1) * itemsPerPage + gridDataPos + 1 - ,page - ,perPage: itemsPerPage - ,totalCount: totalItems + ,curRowPos: (pageInfo.page - 1) * pageInfo.perPage + gridDataPos + 1 + ,page: pageInfo.page + ,perPage: pageInfo.perPage + ,totalCount: pageInfo.totalCount ,pageMove: null ,next: null } diff --git a/src/main/webapp/resources/framework/js/cmm/xit-tui-grid.js b/src/main/webapp/resources/framework/js/cmm/xit-tui-grid.js index 205ee05b..de5ad0ef 100644 --- a/src/main/webapp/resources/framework/js/cmm/xit-tui-grid.js +++ b/src/main/webapp/resources/framework/js/cmm/xit-tui-grid.js @@ -76,9 +76,10 @@ class CustomRowNumberRenderer { } getRowNum(props) { - const currentPage = props.grid.getPagination()._currentPage; + // paging 처리시 : scroll인 경우 제외 + const currentPage = props.grid.getPagination()?._currentPage; // You can change the number `5` as your perPage option. - return Number(props.formattedValue) + (currentPage - 1) * props.grid.getPagination()._options.itemsPerPage; + return Number(props.formattedValue) + (currentPage - 1) * props.grid.getPagination()?._options?.itemsPerPage; } getElement() { @@ -140,16 +141,18 @@ const TuiGrid = { this.instance = null; // rowNum fix - options.rowHeaders.filter((r, idx) => { - if(r === 'rowNum'){ - options.rowHeaders[idx] = { - type: 'rowNum', - renderer: { - type: CustomRowNumberRenderer + if(options.pageOptions?.type !== 'scroll') { + options.rowHeaders.filter((r, idx) => { + if (r === 'rowNum') { + options.rowHeaders[idx] = { + type: 'rowNum', + renderer: { + type: CustomRowNumberRenderer + } } } - } - }) + }) + } const newOptions = $.extend(true, {}, this.defaultOptions, options, {data: dataSource}); newOptions.el = document.getElementById(options.el); //this.elId = options.el; diff --git a/template/settings.xml b/template/settings.xml deleted file mode 100644 index c0dc1ba8..00000000 --- a/template/settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - C:/repo - \ No newline at end of file