Merge branch 'dev' into dev-feat-doc

main
jjh 2 years ago
commit ae7ddf8d9e

@ -56,8 +56,15 @@
</repository>
<repository>
<id>local-repository</id>
<url>file://${basedir}/repo</url>
<url>file://${project.basedir}/repo</url>
</repository>
<!--
<repository>
<id>in-project-jenkins</id>
<name>custom jars-jenkins</name>
<url>file://${JENKINS_HOME}/jobs/${JOB_NAME}/workspace/lib</url>
</repository>
-->
</repositories>
<dependencies>
@ -378,11 +385,41 @@
<artifactId>tiles-jsp</artifactId>
<version>${org.apache.tiles.version}</version>
</dependency>
<!--
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-core</artifactId>
<version>${org.apache.tiles.version}</version>
</dependency>
-->
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-extras</artifactId>
<version>${org.apache.tiles.version}</version>
</dependency>
<!-- freemaker -->
<!--
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-freemarker</artifactId>
<version>${org.apache.tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-extras</artifactId>
<version>${org.apache.tiles.version}</version>
</dependency>
-->
<!-- freemaker -->
<!--
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker-gae</artifactId>
<version>2.3.23</version>
</dependency>
-->
@ -674,7 +711,6 @@
<version>1.9.3</version>
</dependency>
</dependencies>
<build>
@ -740,8 +776,8 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>

@ -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", "게시판-첨부파일")

@ -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;

@ -35,4 +35,6 @@ public interface IFimsCrackdownMgtMapper {
List<FimsCrackdownDTO.CtznSttemntCmplt> selectCtznSttemntCmplt(final FimsCrackdownDTO.CtznSttemntCmplt dto);
void saveCtznSttemntCmplt(FimsCrackdownDTO.CtznSttemntCmplt dto);
int selectCrackdownVhcleNoCnt(final String vhcleNo);
}

@ -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(() -> "");
}
}

@ -37,6 +37,9 @@ public interface IFimsCrackdownMgtService {
String addCtznStmtAnswer(final String interfaceSeqN);
void addCtznStmtAnswers(final List<String> interfaceSeqList);
int findCrackdownVhcleNoCnt(final String vhcleNo);
default XitLoginVO getUserInfo(){
return XitCmmnUtil.getUserInfo();
}

@ -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));
}
}

@ -157,8 +157,8 @@ public class EcCctvCrackdownService implements IEcCctvCrackdownService {
/**
* <pre>
* (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();
}
});

@ -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;
/**
*

@ -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;
}
}

@ -15,9 +15,9 @@ public class ExtlFileParseUtils {
/**
* <pre>
* parsing
* parsing
* @param dto CctvCrackdownDTO.BusOnly DTO
* @param fullFilePath full file path info
* @param fullFilePath full file path info
* @param tempPath directory
* </pre>
*/
@ -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);
}

@ -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;
/**
* <pre>
* masking
* @MaskingRequired(type = MaskingType.NAME) annotaion masking
* MaskingType.NAME | RN | CONTACT | MAIL | CARD | ADDRESS
* <p/>
*/
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
//@JsonSerialize(using = MaskingPropertySerializer.class)
public @interface MaskRequired {
MaskingType type();
}

@ -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 "";
}
}
/**
* <pre>
*
* 2 .
* <p>
* @param name String
* @return String
* </pre>
*/
public static String maskingName(String name) {
String NAME_MASKING_KO = "(?<=.{1})(?<masking>.*)(?=.$)";
String NAME_MASKING_EN = "(?<=.{1})(?<masking>.*)(?=\\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
* <p>
* @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;
}
}

@ -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<String> 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);
*/
}
}

@ -0,0 +1,10 @@
package kr.xit.framework.core.annotation.mask;
public enum MaskingType {
NAME,
RN,
CONTACT,
MAIL,
CARD,
ADDRESS
}

@ -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 {
/**
* <pre>
* masking
* @MaskingRequired(type = MaskingType.NAME) annotaion masking
* MaskingType.NAME | RN | CONTACT | MAIL | CARD | ADDRESS
* <p/>
* @param src
* @return
* </pre>
*/
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;
}
}

@ -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<Font> fontList = new ArrayList<Font>();
fontList.add(new Font("", Font.HANGING_BASELINE, 40));
fontList.add(new Font("Courier", Font.ITALIC, 40));
fontList.add(new Font("", Font.PLAIN, 40));
List<Color> colorList = new ArrayList<Color>();
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());
@ -53,5 +75,20 @@ 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());
}
}

@ -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<ApplicationResource> getSources(ApplicationContext applicationContext) {
List<ApplicationResource> retValue = new ArrayList<ApplicationResource>(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;
// }
}

@ -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
* <p>
* <appender name="mask" class="ch.qos.logback.core.ConsoleAppender">
* <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
* <layout class="kr.xit.framework.support.logback.LogbackMaskingPatternLayout">
* <maskPattern>\"SSN\"\s*:\s*\"(.*?)\"</maskPattern> <!-- SSN JSON pattern -->
* <maskPattern>\"address\"\s*:\s*\"(.*?)\"</maskPattern> <!-- Address JSON pattern -->
* <maskPattern>(\d+\.\d+\.\d+\.\d+)</maskPattern> <!-- Ip address IPv4 pattern -->
* <maskPattern>(\w+@\w+\.\w+)</maskPattern> <!-- Email pattern -->
* <pattern>%-5p [%d{ISO8601,UTC}] [%thread] %c: %m%n%rootException</pattern>
* </layout>
* </encoder>
* </appender>
*
*/
public class LogbackMaskingPatternLayout extends PatternLayout {
private Pattern multilinePattern;
private List<String> 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();
}
}

@ -11,7 +11,11 @@
<property name="REQUEST_PARAM_LEVEL" value="INFO" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<encoder> <!--class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
<!-- <maskPattern>\"SSN\"\s*:\s*\"(.*?)\"</maskPattern> &lt;!&ndash; SSN JSON pattern &ndash;&gt;-->
<!-- <maskPattern>\"address\"\s*:\s*\"(.*?)\"</maskPattern> &lt;!&ndash; Address JSON pattern &ndash;&gt;-->
<!-- <maskPattern>(\d+\.\d+\.\d+\.\d+)</maskPattern> &lt;!&ndash; Ip address IPv4 pattern &ndash;&gt;-->
<!-- <maskPattern>(\w+@\w+\.\w+)</maskPattern> &lt;!&ndash; Email pattern &ndash;&gt;-->
<pattern>${LOG_PATTERN}</pattern>
</encoder>
</appender>

@ -22,4 +22,6 @@
<import resource="classpath:/spring/service/context-scheduling-sym-log-lgm.xml"/>
<import resource="classpath:/spring/service/context-scheduling.xml"/>
<import resource="classpath:/spring/service/context-validator.xml"/>
<!-- <import resource="classpath:/spring/service/context-freemaker.xml"/>-->
</beans>

@ -65,6 +65,18 @@
<property name="preparerFactoryClass" value="org.springframework.web.servlet.view.tiles3.SpringBeanPreparerFactory"/>
</bean>
<!-- freemaker -->
<!--
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="order" value="2" />
<property name="cache" value="true" />
<property name="suffix" value=".ftl" />
<property name="contentType" value="text/html; charset=UTF-8" />
<property name="exposeSpringMacroHelpers" value="true" />
</bean>
-->
<!-- Annotation 을 사용하지 않는 경우에 대한 MVC 처리 설정 -->
<mvc:view-controller path="/cmmn/validator.do" view-name="cmmn/validator"/>

@ -46,6 +46,7 @@
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:exclude-filter type="aspectj" expression="*..ignore..*" />
</context:component-scan>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="DEFAULT_INCOMPATIBLE_IMPROVEMENTS" value="2.3.23"/>
<property name="freemarkerSettings">
<map>
<entry key="template_update_delay" value="60000"/>
<entry key="auto_flush" value="false"/>
<entry key="default_encoding" value="UTF-8"/>
<entry key="whitespace_stripping" value="true"/>
</map>
</property>
</bean>
</beans>

@ -11,6 +11,7 @@
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="aspectj" expression="*..ignore..*" />
</context:component-scan>
</beans>

@ -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 @@
</if>
</where>
</select>
<select id="selectCrackdownVhcleNoCnt" resultType="int">
/*cmm-fims-crackdown-mysql-mapper|selectCrackdownVhcleNoCnt-단속횟수 조회|cjm */
SELECT COUNT(reglt_id)
FROM tb_rt_reglt trr
WHERE trr.vhcle_no = #{vhcle_no}
AND NOT NULLIF(#{vhvle_no}, '') IS NULL
</select>
</mapper>

@ -456,7 +456,7 @@
ON tcfm.file_mastr_id = tcfd.file_mastr_id
WHERE tcfm.job_se_code = #{jobSeCode}
<if test='regltSeCode eq "01" or regltSeCode eq "02" or regltSeCode eq "07"'>
-- 외부연계 : 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})

@ -0,0 +1,10 @@
<#ftl encoding="utf-8"/>
<html>
<head>
<title>네이바 프리마카</title>
</head>
<body>
<h1>컨트롤러의 메세지: ${message}</h1>
</body>
</html>

@ -36,7 +36,7 @@ Date Author Description
</td>
<td colspan="6">
<input id="folder" type="file" webkitdirectory multiple="false"/>
<input id="busOnlyDirPath" name="dirPath" type="text" size="400" value="<c:out value='${busOnlyDirPath}'/>" title="버스전용차로데이타경로" style="display: none; width: 100%" readonly/>
<input id="busOnlyDirPath" name="dirPath" type="text" size="400" value="<c:out value='${busOnlyDirPath}'/>" title="버스장착형데이타경로" style="display: none; width: 100%" readonly/>
<input id="ctznDirPath" name="dirPath" type="text" size="400" value="<c:out value='${ctznDirPath}'/>" title="시민신고" style="display: none; width: 100%" readonly/>
<span id="warnMsg" style="color: red; font-weight: bold; display: inline-block">동일한 데이타 선택시 중복 처리될수 있습니다.</span>
</td>

@ -45,6 +45,11 @@ Date Author Description
.curImgData {
border: 1px solid black;
}
/* 단속 건수 */
.empCls {
color: #2a48ff;
background-color: #d8e7ff;
}
</style>
<div class="popup" style="min-width: 100px;">
@ -159,14 +164,15 @@ Date Author Description
<tr>
<th>차량번호</th>
<td>
<input type="text" name="vhcleNo" style="width: 60%" class="act_bg_color"/>
<input type="text" name="vhcleNo" style="width: 50%" class="act_bg_color"/>
<a id ="vhcleSearch">
<img src="<c:url value='/resources/images/btn/search.png'/>" alt="차적조회" style="cursor: hand"/>
</a>
<em id="markdownCnt" class="empCls">단속횟수: &nbsp;<span id="vhcleNoCnt"></span>&nbsp;회</em>
</td>
<th>면제차량여부</th>
<td>
<input type="text" name="" value="" readonly/>
<input type="text" name="" style="width: 50%" readonly/>
</td>
</tr>
<tr>
@ -279,6 +285,9 @@ Date Author Description
var callbackEnlightErpp = (data) => fnPopupBiz.callbackEnlightErpp(data)
let orgData;
let callPopup;
let isCtzn = false;
let imgPk = '';
let regltSeCode = '';
/* *******************************
* Biz function
@ -292,18 +301,37 @@ Date Author Description
,success: (res) => {
let dataKey = '';
let curId = '';
const regltSeCode = res.infoDTO.regltSeCode;
let vhcleNoCnt = 0;
regltSeCode = res.infoDTO.regltSeCode;
if(regltSeCode === '${citizen}'){
dataKey = res.infoDTO.interfaceSeqN + ' - ' + res.infoDTO.ctznSttemntDetailSn;
curId = res.infoDTO.interfaceSeqN + res.infoDTO.ctznSttemntDetailSn;
isCtzn = true;
imgPk = res.infoDTO.interfaceSeqN;
dataKey = imgPk + ' - ' + res.infoDTO.ctznSttemntDetailSn;
curId = imgPk + res.infoDTO.ctznSttemntDetailSn;
}else{
dataKey = res.infoDTO.extrlRegltCntcId;
curId = dataKey;
isCtzn = false;
imgPk = res.infoDTO.extrlRegltCntcId;
dataKey = imgPk;
curId = imgPk;
}
$('#txtTitle').html(
ComboCodeData.regltSeCode.filter(d => d.value === res.infoDTO.regltSeCode)[0].text
ComboCodeData.regltSeCode.filter(d => d.value === regltSeCode)[0].text
+ '&nbsp;&nbsp;&nbsp;[&nbsp;' + dataKey + '&nbsp;]'
);
fnPopupBiz.showCrackdownVhcleNoCnt(res.infoDTO.vhcleNoCnt);
/*
if(res.infoDTO.vhcleNoCnt > 0) {
console.log(res.infoDTO.vhcleNoCnt);
$('#vhcleNoCnt').text(
res.infoDTO.vhcleNoCnt
);
$('#markdownCnt').show();
}else{
$('#markdownCnt').hide();
}
*/
cmmImgDownload('#imgList', res.attchFiles, fnPopupBiz.pagePopup, true, '60px',
() => document.getElementById(curId).className += ' curImgData'
);
@ -316,6 +344,16 @@ Date Author Description
}
})
}
,downloadImg: () => {
cmmAjax({
showSuccessMsg: false
,url: isCtzn? fimsApiUrl.FIND_EC_NATL_NEWS_PAPER_ATTCH_FILES : fimsApiUrl.FIND_EC_EXTRL_REGLT_CNTC_ATTCH_FILES
,data: isCtzn? {interfaceSeqN: imgPk} : {extrlRegltCntcId: imgPk, regltSeCode: regltSeCode}
,success: (res) => {
cmmImgDownload('#imgList', res.data?.contents, fnPopupBiz.pagePopup, true);
}
})
}
,pagePopup: function(flag, params) {
let url;
let popTitle;
@ -367,9 +405,29 @@ Date Author Description
}
}
,findVhcleNo: () => {
alert('call 차적조회 인터페이스');
$('input[name=vhcleNm]').val('차량명칭');
$('input[name=vhcleColor]').val('차량색상');
if(!$('input[name=vhcleNo]').val()){
alert('먼처 차량번호를 입력해 주세요.');
$('input[name=vhcleNo]').focus();
return false;
}
// FIXME :: callback 형태로 단속 건수 조회
cmmAjax({
showSuccessMsg: false
, url: fimsApiUrl.FIND_CRACKDOWN_VHCLE_NO_CNT
, data: {vhcleNo: $('input[name=vhcleNo]').val()}
, success: (res) => {
fnPopupBiz.showCrackdownVhcleNoCnt(res.data?.contents);
alert('call 차적조회 인터페이스후 해당 차량번호의 단속건수 조회');
$('input[name=vhcleNm]').val('차량명칭');
$('input[name=vhcleColor]').val('차량색상');
}
})
}
,callbackEnlightErpp: (data) => {
//if(!fnPopupBiz.validate()) return false;
@ -517,7 +575,15 @@ Date Author Description
});
}
// 차량 단속 건수 표시
,showCrackdownVhcleNoCnt: (cnt) => {
if(cnt > 0) {
$('#vhcleNoCnt').html(cnt);
$('#markdownCnt').show();
}else{
$('#markdownCnt').hide();
}
}
};
/**************************************************************************

@ -37,6 +37,7 @@ Date Author Description
<div class="conttitle">
<img src="${ctx }/resources/biz/content/images/common/main/titleLogo_01.png"/>
<p class="title">개별총정보</p>
<%-- <%@include file="/WEB-INF/jsp/framework/biz-popup-tab-btn.jsp" %>--%>
</div>
<div class="row">
@ -273,7 +274,7 @@ Date Author Description
</tbody>
</table>
</form>
<%@include file="/WEB-INF/jsp/framework/biz-popup-tab-btn.jsp" %>
<%-- <%@include file="/WEB-INF/jsp/framework/biz-popup-tab-btn.jsp" %>--%>
</div>
<div class="w_fix09 gridGroup" style="width:0px; min-width:300px!important;">
@ -409,7 +410,7 @@ Date Author Description
<div class="w_fix04 gridGroup">
<div style="width: 100%; border:0px solid black">
<p class="title deco_01">처리상태 변동이력</p>
<div id="grid_t0"></div>
<div id="grid_sts_change_his"></div>
<%--삭제조심--%>
</div>
</div>
@ -495,13 +496,13 @@ Date Author Description
<%-- <div class="w_fix06 gridGroup">--%>
<%-- <p class="title deco_02">처리상태 변동이력</p>--%>
<%-- <div style="display: flex; width: 100%; border:0px solid chocolate; margin-bottom: 5px;">--%>
<%-- <div id="grid_t0" style="width:100%;"></div>--%>
<%-- <div id="grid_sts_change_his" style="width:100%;"></div>--%>
<%-- </div>--%>
<%-- </div>--%>
<div class="w_fix06 gridGroup" style="width: 1100px;">
<p class="title deco_02">주소 변동이력</p>
<div style="display: flex; width: 100%; border:0px solid chocolate; margin-bottom: 5px;">
<div id="grid_d1" style="width:100%;"></div>
<div id="grid_addr_his" style="width:100%;"></div>
</div>
</div>
@ -543,7 +544,7 @@ Date Author Description
</div>
</form>
<div style="display: flex; width: 100%; height:150px; border:0px solid black; margin-bottom: 20px;">
<div id="grid_d2" style="width:100%;"></div>
<div id="grid_etrn_noti_his" style="width:100%;"></div>
</div>
</div>
@ -563,14 +564,14 @@ Date Author Description
<div style="width: 100%; border:0px solid black">
<p class="title deco_01">개별자료 민원 등록내역</p>
<a href="#" class="btn green" id="btnMinWonNew">신규작성</a>
<div id="grid_m1"></div>
<div id="grid_cplnt"></div>
</div>
</div>
<div class="w_fix04 gridGroup">
<div style="width: 100%; border:0px solid black">
<p class="title deco_01">차량번호 민원 등록내역</p>
<a href="#" class="btn green" id="btnCarMinWonNew">신규작성</a>
<div id="grid_m2"></div>
<div id="grid_vhcle_no_cplnt"></div>
</div>
</div>
</div>
@ -613,6 +614,7 @@ Date Author Description
<%-- </div>--%>
</div>
</div><!--popupTabs -->
<%@include file="/WEB-INF/jsp/framework/biz-popup-tab-btn.jsp" %>
</div><!--row -->
<script type="text/javascript" src="${pageContext.request.contextPath}/resources/framework/js/cmm/cmmDownloadImg.js"></script>
@ -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();
});
</script>

@ -24,7 +24,7 @@
</td>
<td colspan="6">
<input id="folder" type="file" webkitdirectory multiple="false"/>
<input id="dirPath" name="dirPath" type="text" size="400" value="<c:out value='${dirPath}'/>" title="버스전용차로데이타경로" style="display: none; width: 100%" readonly/>
<input id="dirPath" name="dirPath" type="text" size="400" value="<c:out value='${dirPath}'/>" title="버스장착형데이타경로" style="display: none; width: 100%" readonly/>
<span id="warnMsg" style="color: red; font-weight: bold; display: inline-block">동일한 데이타 선택시 중복 처리될수 있습니다.</span>
</td>
</tr>

@ -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

@ -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

@ -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 외부연계 첨부파일 목록 조회
//단속관리 - 단속현황관리

@ -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
}

@ -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;

@ -1,5 +0,0 @@
<?xml version="1.0"?>
<settings xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/SETTINGS/1.0.0">
<localRepository>C:/repo</localRepository>
</settings>
Loading…
Cancel
Save