초기소스
This commit is contained in:
98
src/main/java/com/wb/domainserver/util/CookieUtils.java
Normal file
98
src/main/java/com/wb/domainserver/util/CookieUtils.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package com.wb.domainserver.util;
|
||||
|
||||
import com.wb.domainserver.realm.RealmContextHolder;
|
||||
import com.wb.domainserver.realm.util.UrlExtractor;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class CookieUtils {
|
||||
|
||||
|
||||
|
||||
public static String getCookieValue(String cookieName, HttpServletRequest request){
|
||||
|
||||
String cookieValue = "";
|
||||
if(request.getCookies() != null){
|
||||
for(Cookie cookie : request.getCookies()){
|
||||
|
||||
if(cookieName.equals(cookie.getName())){
|
||||
cookieValue = cookie.getValue();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
|
||||
public static void deleteCookie(String name, String path, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
String host = request.getHeader("X-Forwarded-Host");
|
||||
if (host == null) {
|
||||
host = request.getServerName(); // 기본값으로 현재 요청의 호스트명 사용
|
||||
}
|
||||
|
||||
|
||||
String originHost = UrlExtractor.getOriginalHost(host);
|
||||
|
||||
|
||||
Cookie cookie = new Cookie(name, null);
|
||||
cookie.setMaxAge(0);
|
||||
cookie.setPath(path);
|
||||
cookie.setDomain(originHost);
|
||||
cookie.setHttpOnly(true);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
public static void createCookie(String name, String value, String path, int maxAge, boolean httpOnly, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
String host = request.getHeader("X-Forwarded-Host");
|
||||
if (host == null) {
|
||||
host = request.getServerName(); // 기본값으로 현재 요청의 호스트명 사용
|
||||
}
|
||||
|
||||
String originHost = UrlExtractor.getOriginalHost(host);
|
||||
|
||||
Cookie cookie = new Cookie(name, value);
|
||||
cookie.setMaxAge(maxAge);
|
||||
cookie.setPath(path);
|
||||
cookie.setDomain(originHost);
|
||||
cookie.setHttpOnly(httpOnly);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
public static void createCookie(String name, String value, String path, boolean httpOnly, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
String host = request.getHeader("X-Forwarded-Host");
|
||||
if (host == null) {
|
||||
host = request.getServerName(); // 기본값으로 현재 요청의 호스트명 사용
|
||||
}
|
||||
|
||||
String originHost = UrlExtractor.getOriginalHost(host);
|
||||
|
||||
Cookie cookie = new Cookie(name, value);
|
||||
cookie.setPath(path);
|
||||
cookie.setDomain(originHost);
|
||||
cookie.setHttpOnly(httpOnly);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 로그인 쿠키 경로
|
||||
* */
|
||||
public static Map<String, String> loginCookiePath(){
|
||||
String realm = RealmContextHolder.getRealm().toLowerCase();
|
||||
|
||||
String ACTPath = "sopmal".equals(realm) ? "/" : "/" + realm;
|
||||
String RFTPath = "/" + realm + "/tokens/refresh";
|
||||
|
||||
return Map.of("ACTPath", ACTPath, "RFTPath", RFTPath);
|
||||
}
|
||||
|
||||
}
|
||||
131
src/main/java/com/wb/domainserver/util/ResourceCloseHelper.java
Normal file
131
src/main/java/com/wb/domainserver/util/ResourceCloseHelper.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package com.wb.domainserver.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.sql.*;
|
||||
|
||||
/**
|
||||
* 각종 resource close를 지원하는 util
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2024-01-03
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2024-01-03 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
public class ResourceCloseHelper {
|
||||
|
||||
/**
|
||||
* Resource close 처리.
|
||||
* @param resources
|
||||
*/
|
||||
public static void close(Closeable ... resources) {
|
||||
for (Closeable resource : resources) {
|
||||
if (resource != null) {
|
||||
try {
|
||||
resource.close();
|
||||
} catch (IOException ignore) {
|
||||
log.debug("Occurred IOException to close resource is ingored!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JDBC 관련 resource 객체 close 처리
|
||||
* @param objects
|
||||
*/
|
||||
public static void closeDBObjects(Wrapper ... objects) {
|
||||
for (Object object : objects) {
|
||||
if (object != null) {
|
||||
if (object instanceof ResultSet) {
|
||||
try {
|
||||
((ResultSet)object).close();
|
||||
} catch (SQLException ignore) {//KISA 보안약점 조치 (2018-10-29, 윤창원)
|
||||
log.debug("Occurred SQLException to close resource is ingored!!");
|
||||
}
|
||||
} else if (object instanceof Statement) {
|
||||
try {
|
||||
((Statement)object).close();
|
||||
} catch (SQLException ignore) {//KISA 보안약점 조치 (2018-10-29, 윤창원)
|
||||
log.debug("Occurred SQLException to close resource is ingored!!");
|
||||
}
|
||||
} else if (object instanceof Connection) {
|
||||
try {
|
||||
((Connection)object).close();
|
||||
} catch (SQLException ignore) {
|
||||
log.debug("Occurred SQLException to close resource is ingored!!");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Wrapper type is not found : " + object.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Socket 관련 resource 객체 close 처리
|
||||
* @param objects
|
||||
*/
|
||||
public static void closeSocketObjects(Socket socket, ServerSocket server) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.shutdownOutput();
|
||||
} catch (IOException ignore) {
|
||||
log.debug("Occurred IOException to close resource is ingored!!");
|
||||
}
|
||||
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ignore) {
|
||||
log.debug("Occurred IOException to close resource is ingored!!");
|
||||
}
|
||||
}
|
||||
|
||||
if (server != null) {
|
||||
try {
|
||||
server.close();
|
||||
} catch (IOException ignore) {
|
||||
log.debug("Occurred IOException to close resource is ingored!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Socket 관련 resource 객체 close 처리
|
||||
*
|
||||
* @param sockets
|
||||
*/
|
||||
public static void closeSockets(Socket ... sockets) {
|
||||
for (Socket socket : sockets) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.shutdownOutput();
|
||||
} catch (IOException ignore) {
|
||||
log.debug("Occurred IOException to close resource is ingored!!");
|
||||
}
|
||||
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ignore) {
|
||||
log.debug("Occurred IOException to close resource is ingored!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.wb.domainserver.util.communicate;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.wb.domainserver.common.mvc.tags.ui.pagination.PaginationInfo;
|
||||
import com.wb.domainserver.exception.WnbtRestException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* BO에서 전달받은 JSON String 변환을 지원하는 Object
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-28
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-28 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class BoResultMapConverter {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, Object> convert(ObjectMapper objectMapper, String resultStr) {
|
||||
try {
|
||||
Map<String, Object> resultMap = objectMapper.readValue(resultStr, new TypeReference<Map<String, Object>>() {});
|
||||
if(resultMap.containsKey("paginationInfo")) {
|
||||
PaginationInfo paginationInfo = new PaginationInfo();
|
||||
Map<String, Object> paginationMap = (Map<String, Object>)resultMap.get("paginationInfo");
|
||||
if(paginationMap != null) {
|
||||
if(paginationMap.get("currentPageNo") != null) {
|
||||
paginationInfo.setCurrentPageNo(Integer.parseInt(paginationMap.get("currentPageNo").toString()));
|
||||
}
|
||||
if(paginationMap.get("recordCountPerPage") != null) {
|
||||
paginationInfo.setRecordCountPerPage(Integer.parseInt(paginationMap.get("recordCountPerPage").toString()));
|
||||
}
|
||||
if(paginationMap.get("pageSize") != null) {
|
||||
paginationInfo.setPageSize(Integer.parseInt(paginationMap.get("pageSize").toString()));
|
||||
}
|
||||
if(paginationMap.get("totalRecordCount") != null) {
|
||||
paginationInfo.setTotalRecordCount(Integer.parseInt(paginationMap.get("totalRecordCount").toString()));
|
||||
}
|
||||
resultMap.put("paginationInfo", paginationInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
} catch (WnbtRestException wre){
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("BO에서 전달받은 결과 JsonString 변환 중 오류가 발생하였습니다. resultJsonString={}", resultStr, e);
|
||||
throw new IllegalStateException("BO에서 전달받은 결과 JsonString 변환 중 오류가 발생하였습니다");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.wb.domainserver.util.communicate;
|
||||
|
||||
import lombok.Data;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "kakao")
|
||||
public class KakaoProperties {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(KakaoProperties.class);
|
||||
|
||||
private Map<String, String> keys;
|
||||
|
||||
public String getKeyForDomain(String domain) {
|
||||
if (keys == null) {
|
||||
logger.error("Domains map is null!");
|
||||
}
|
||||
return keys != null ? keys.get(domain) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.wb.domainserver.util.communicate;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.wb.domainserver.exception.WnbtRestException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Slf4j
|
||||
public class MultiValueMapConverter {
|
||||
public static MultiValueMap<String, Object> convert(ObjectMapper objectMapper, Object dto) {
|
||||
try {
|
||||
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
|
||||
Map<String, Object> map = objectMapper.convertValue(dto, new TypeReference<Map<String, Object>>() {});
|
||||
params.setAll(map);
|
||||
|
||||
return params;
|
||||
} catch (WnbtRestException wre) {
|
||||
log.error("Url Parameter 변환중 오류가 발생했습니다. requestDto={}", dto, wre);
|
||||
throw new WnbtRestException("Url Parameter 변환중 오류가 발생했습니다.");
|
||||
} catch (Exception e) {
|
||||
log.error("Url Parameter 변환중 오류가 발생했습니다. requestDto={}", dto, e);
|
||||
throw new IllegalStateException("Url Parameter 변환중 오류가 발생했습니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.wb.domainserver.util.communicate;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RESRC {
|
||||
GCONEBO(RESRC_URL.gconeboServerUrl, "messaging-client"),
|
||||
GCONEBO2(RESRC_URL.gconeboServerUrl, "messaging-gconebo"),
|
||||
GCONEBO3(RESRC_URL.gconeboServerUrl, "messaging-sopmalfo-bd"),
|
||||
GCONEBO4(RESRC_URL.gconeboServerUrl, "messaging-sopmalfo-dl"),
|
||||
GCONEBO5(RESRC_URL.gconeboServerUrl, "messaging-sopmalfo-jm"),
|
||||
REVIEWBO(RESRC_URL.reviewboServerUrl, "messaging-reviewbo"),
|
||||
;
|
||||
|
||||
private final String registeredClientUrl;
|
||||
private final String registeredClientId;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.wb.domainserver.util.communicate;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class RESRC_URL {
|
||||
public static String gconeboServerUrl;
|
||||
public static String reviewboServerUrl;
|
||||
|
||||
// @Value("${url.resource.server.gconebo}")
|
||||
public void setGconeboServerUrl(String gconeboServerUrl) {
|
||||
RESRC_URL.gconeboServerUrl = gconeboServerUrl;
|
||||
}
|
||||
|
||||
// @Value("${url.resource.server.reviewbo}")
|
||||
public void setReviewboServerUrl(String reviewboServerUrl) {
|
||||
RESRC_URL.reviewboServerUrl = reviewboServerUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.wb.domainserver.util.communicate;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class ReplyFromResrc {
|
||||
private boolean isEmpty;
|
||||
private String reply;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.wb.domainserver.util.communicate;
|
||||
|
||||
import com.wb.domainserver.security.authentication.MemberJwtContextHolder;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SendToResrc {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SendToResrc.class);
|
||||
|
||||
private final WebClient webClient;
|
||||
private final MessageSource messageSource;
|
||||
private final HttpServletRequest request;
|
||||
|
||||
public SendToResrc(WebClient webClient, MessageSource messageSource, HttpServletRequest request){
|
||||
this.webClient = webClient;
|
||||
this.messageSource = messageSource;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public Mono<ReplyFromResrc> ofGetWithParam(RESRC resrc, String apiUri, Map<String, Object> param) {
|
||||
String requestApiUrl = apiUri + (!param.isEmpty() ? "?".concat(urlEncodeUTF8(param)) : "");
|
||||
return ofGet(resrc, requestApiUrl);
|
||||
}
|
||||
|
||||
public Mono<ReplyFromResrc> ofGet(RESRC resrc, String apiUri) {
|
||||
log.info("ReplyFromResrc ofGet ::: accessUrl = {}", MemberJwtContextHolder.getMemberInfo().getAccessUrl());
|
||||
|
||||
var authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
var requestApiUrl = resrc.getRegisteredClientUrl() + apiUri;
|
||||
|
||||
WebClient.RequestHeadersSpec<?> request = this.webClient
|
||||
.get()
|
||||
.uri(requestApiUrl)
|
||||
.header("X-Original-Host", MemberJwtContextHolder.getMemberInfo().getAccessUrl());
|
||||
|
||||
if (authentication instanceof Jwt accessToken) {
|
||||
request = request.headers(h -> h.setBearerAuth(accessToken.getTokenValue()));
|
||||
}
|
||||
|
||||
return request
|
||||
.retrieve()
|
||||
.toEntity(String.class)
|
||||
.map(responseEntity -> {
|
||||
boolean checkEmpty = responseEntity.getStatusCode().equals(HttpStatus.NO_CONTENT);
|
||||
String content = checkEmpty ? "no Content" : responseEntity.getBody();
|
||||
return ReplyFromResrc.builder().isEmpty(checkEmpty).reply(content).build();
|
||||
})
|
||||
.onErrorResume(this::handleError);
|
||||
}
|
||||
|
||||
public Mono<ReplyFromResrc> ofPost(RESRC resrc, String apiUri, MultiValueMap<String, ?> param) {
|
||||
return executePost(resrc, apiUri, param);
|
||||
}
|
||||
|
||||
public Mono<ReplyFromResrc> ofPost(RESRC resrc, String apiUri, Object obj) {
|
||||
return executePost(resrc, apiUri, obj);
|
||||
}
|
||||
|
||||
private Mono<ReplyFromResrc> executePost(RESRC resrc, String apiUri, Object body) {
|
||||
String tenantId = (String) request.getSession().getAttribute("X-Tenant-Id");
|
||||
var authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
var requestApiUrl = resrc.getRegisteredClientUrl() + apiUri;
|
||||
|
||||
WebClient.RequestBodySpec requestSpec = this.webClient
|
||||
.post()
|
||||
.uri(requestApiUrl)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML);
|
||||
|
||||
if (authentication instanceof Jwt jwt) {
|
||||
requestSpec = requestSpec
|
||||
.headers(h -> h.setBearerAuth(jwt.getTokenValue()))
|
||||
.header("X-Tenant-Id", tenantId);
|
||||
}
|
||||
|
||||
return requestSpec
|
||||
.bodyValue(body)
|
||||
.retrieve()
|
||||
.toEntity(String.class)
|
||||
.map(responseEntity -> {
|
||||
boolean checkEmpty = responseEntity.getStatusCode().equals(HttpStatus.NO_CONTENT);
|
||||
String content = checkEmpty ? "no Content" : responseEntity.getBody();
|
||||
return ReplyFromResrc.builder().isEmpty(checkEmpty).reply(content).build();
|
||||
})
|
||||
.onErrorResume(this::handleError);
|
||||
}
|
||||
|
||||
private Mono<ReplyFromResrc> handleError(Throwable e) {
|
||||
log.error("Error occurred during API call", e);
|
||||
return Mono.just(ReplyFromResrc.builder().isEmpty(true).reply("Error occurred: " + e.getMessage()).build());
|
||||
}
|
||||
|
||||
static String urlEncodeUTF8(String s) {
|
||||
return URLEncoder.encode(s, StandardCharsets.UTF_8);
|
||||
}
|
||||
static String urlEncodeUTF8(Map<?,?> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<?,?> entry : map.entrySet()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("&");
|
||||
}
|
||||
sb.append(String.format("%s=%s",
|
||||
urlEncodeUTF8(entry.getKey().toString()),
|
||||
urlEncodeUTF8(entry.getValue().toString())
|
||||
));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package com.wb.domainserver.util.communicate;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.wb.domainserver.common.msg.GconeMessageSource;
|
||||
import com.wb.domainserver.exception.WnbtRestException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.ObjectError;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 정합성 점검결과 메시지 처리를 지원하는 Object
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-28
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-28 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ValidateResultConverter {
|
||||
|
||||
public static String convert(BindingResult bindingResult,
|
||||
GconeMessageSource gconeMessageSource) {
|
||||
StringBuffer resultMsgBf = new StringBuffer();
|
||||
Map<String, Object> errorMap = new HashMap<>();
|
||||
List<String> errorFields = new ArrayList<>();
|
||||
errorMap.put("errorFiledNm", bindingResult.getFieldErrors().get(0).getField());
|
||||
for(FieldError fieldError : bindingResult.getFieldErrors()) {
|
||||
errorFields.add(fieldError.getField());
|
||||
}
|
||||
errorMap.put("errorFields", errorFields);
|
||||
Object minValue = null;
|
||||
Object maxValue = null;
|
||||
|
||||
for (ObjectError error : bindingResult.getAllErrors()) {
|
||||
switch(error.getCode()) {
|
||||
case "NotBlank" :
|
||||
case "NotNull" :
|
||||
case "NotEmpty" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.required", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
case "Min" :
|
||||
|
||||
if(error.getArguments().length >= 2) {
|
||||
minValue = error.getArguments()[1];
|
||||
}
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.min", new Object[] {error.getDefaultMessage(), minValue})).append("\n");
|
||||
break;
|
||||
case "Max" :
|
||||
if(error.getArguments().length >= 2) {
|
||||
maxValue = error.getArguments()[1];
|
||||
}
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.max", new Object[] {error.getDefaultMessage(), maxValue})).append("\n");
|
||||
break;
|
||||
case "Length" :
|
||||
if(error.getArguments().length >= 2
|
||||
&& error.getArguments().length < 3) {
|
||||
maxValue = error.getArguments()[1];
|
||||
} else if(error.getArguments().length >= 3) {
|
||||
maxValue = error.getArguments()[1];
|
||||
minValue = error.getArguments()[2];
|
||||
}
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.length", new Object[] {error.getDefaultMessage(), minValue, maxValue})).append("\n");
|
||||
break;
|
||||
case "Korean" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.korean", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
case "English" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.english", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
case "NumberOnly" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.integer", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
case "NumberWithHyphen" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.numberWithHyphen", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
case "Range" :
|
||||
if(error.getArguments().length >= 2
|
||||
&& error.getArguments().length < 3) {
|
||||
maxValue = error.getArguments()[1];
|
||||
} else if(error.getArguments().length >= 3) {
|
||||
maxValue = error.getArguments()[1];
|
||||
minValue = error.getArguments()[2];
|
||||
}
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.range", new Object[] {error.getDefaultMessage(), minValue, maxValue})).append("\n");
|
||||
break;
|
||||
case "Email" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.email", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
case "Size":
|
||||
if(error.getArguments().length >= 2
|
||||
&& error.getArguments().length < 3) {
|
||||
maxValue = error.getArguments()[1];
|
||||
} else if(error.getArguments().length >= 3) {
|
||||
maxValue = error.getArguments()[1];
|
||||
minValue = error.getArguments()[2];
|
||||
}
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.size", new Object[] {error.getDefaultMessage(), minValue, maxValue})).append("\n");
|
||||
break;
|
||||
case "Password" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.mngrPassword", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
case "Id" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.id", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
case "BoardId" :
|
||||
resultMsgBf.append(gconeMessageSource.getMessage("errors.boardId", new Object[] {error.getDefaultMessage()})).append("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errorMap.put("errorMsg", resultMsgBf.toString());
|
||||
return makeErrorString(errorMap);
|
||||
}
|
||||
|
||||
public static String convertCustomValidate(List<Map<String, String>> errorList) {
|
||||
Map<String, Object> errorMap = new HashMap<>();
|
||||
List<String> errorFields = new ArrayList<>();
|
||||
StringBuffer resultMsgBf = new StringBuffer();
|
||||
|
||||
errorMap.put("errorFiledNm", errorList.get(0).get("errorFiledNm"));
|
||||
for(Map<String, String> error : errorList) {
|
||||
errorFields.add(error.get("errorFiledNm"));
|
||||
resultMsgBf.append(error.get("errorMsg")).append("\n");
|
||||
}
|
||||
errorMap.put("errorMsg", resultMsgBf.toString());
|
||||
errorMap.put("errorFields", errorFields);
|
||||
return makeErrorString(errorMap);
|
||||
}
|
||||
|
||||
public static Map<String, String> setErrorMap(String fieldNm, String errorMsg) {
|
||||
Map<String, String> errorMap = new HashMap<>();
|
||||
errorMap.put("errorFiledNm", fieldNm);
|
||||
errorMap.put("errorMsg", errorMsg);
|
||||
return errorMap;
|
||||
}
|
||||
|
||||
private static String makeErrorString(Map<String, Object> errorMap) {
|
||||
String resultMsg = null;
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
resultMsg = objectMapper.writeValueAsString(errorMap);
|
||||
} catch (WnbtRestException wre){
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch(Exception e) {
|
||||
log.error("정합성 점검 결과 메시지 생성중 오류가 발생하였습니다.", e);
|
||||
}
|
||||
return resultMsg;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.wb.domainserver.util.cookie;
|
||||
|
||||
import jakarta.servlet.http.Cookie;
|
||||
|
||||
public class CookieUtil {
|
||||
|
||||
public static boolean hasAgentCookie(Cookie[] cookies) {
|
||||
if (cookies == null) return false;
|
||||
|
||||
for (Cookie cookie : cookies) {
|
||||
if ("gc_agent_id".equals(cookie.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getAgentCookieValue(Cookie[] cookies) {
|
||||
if (cookies == null) return null;
|
||||
|
||||
for (Cookie cookie : cookies) {
|
||||
if ("gc_agent_id".equals(cookie.getName())) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.wb.domainserver.util.dataaccess;
|
||||
|
||||
/**
|
||||
* 입력 문자열에 대하여 Camel 표기법으로 변환을 지원하는 Utility
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-24
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-24 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public final class CamelUtil {
|
||||
|
||||
private CamelUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* underscore ('_') 가 포함되어 있는 문자열을 Camel Case ( 낙타등
|
||||
* 표기법 - 단어의 변경시에 대문자로 시작하는 형태. 시작은 소문자) 로 변환해주는
|
||||
* utility 메서드 ('_' 가 나타나지 않고 첫문자가 대문자인 경우도 변환 처리
|
||||
* 함.)
|
||||
* @param underScore - '_' 가 포함된 변수명
|
||||
* @return Camel 표기법 변수명
|
||||
*/
|
||||
public static String convert2CamelCase(String underScore) {
|
||||
// '_' 가 나타나지 않으면 이미 camel case 로 가정함.
|
||||
// 단 첫째문자가 대문자이면 camel case 변환 (전체를 소문자로) 처리가
|
||||
// 필요하다고 가정함. --> 아래 로직을 수행하면 바뀜
|
||||
if (underScore.indexOf('_') < 0 && Character.isLowerCase(underScore.charAt(0))) {
|
||||
return underScore;
|
||||
}
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean nextUpper = false;
|
||||
int len = underScore.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char currentChar = underScore.charAt(i);
|
||||
if (currentChar == '_') {
|
||||
nextUpper = true;
|
||||
} else {
|
||||
if (nextUpper) {
|
||||
result.append(Character.toUpperCase(currentChar));
|
||||
nextUpper = false;
|
||||
} else {
|
||||
result.append(Character.toLowerCase(currentChar));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.wb.domainserver.util.dataaccess;
|
||||
|
||||
import org.apache.commons.collections4.map.ListOrderedMap;
|
||||
|
||||
public class DataMap extends ListOrderedMap<Object, Object> {
|
||||
|
||||
private static final long serialVersionUID = 6723434363565852261L;
|
||||
|
||||
/**
|
||||
* key 에 대하여 Camel Case 변환하여 super.put
|
||||
* (ListOrderedMap) 을 호출한다.
|
||||
* @param key
|
||||
* - '_' 가 포함된 변수명
|
||||
* @param value
|
||||
* - 명시된 key 에 대한 값 (변경 없음)
|
||||
* @return previous value associated with specified
|
||||
* key, or null if there was no mapping for
|
||||
* key
|
||||
*/
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return super.put(CamelUtil.convert2CamelCase((String) key), value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.wb.domainserver.util.dataaccess;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Mybatis 지원하는 Utility
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-24
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-24 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
public class MybaitsUtil {
|
||||
|
||||
/**
|
||||
* Empty 여부를 확인한다.
|
||||
* @param o Object
|
||||
* @return boolean
|
||||
* @exception IllegalArgumentException
|
||||
*/
|
||||
public static boolean isEmpty(Object o) throws IllegalArgumentException {
|
||||
try {
|
||||
if(o == null) return true;
|
||||
|
||||
if(o instanceof String) {
|
||||
if(((String)o).length() == 0){
|
||||
return true;
|
||||
}
|
||||
} else if(o instanceof Collection) {
|
||||
if(((Collection<?>)o).isEmpty()){
|
||||
return true;
|
||||
}
|
||||
} else if(o.getClass().isArray()) {
|
||||
if(Array.getLength(o) == 0){
|
||||
return true;
|
||||
}
|
||||
} else if(o instanceof Map) {
|
||||
if(((Map<?, ?>)o).isEmpty()){
|
||||
return true;
|
||||
}
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch(IllegalArgumentException e) {
|
||||
log.error("[IllegalArgumentException] Try/Catch...usingParameters Runing : "+ e.getMessage());
|
||||
} catch(Exception e) {
|
||||
log.error("["+e.getClass()+"] Try/Catch...Exception : " + e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Empty 여부를 확인한다.
|
||||
* @param o Object
|
||||
* @return boolean
|
||||
* @exception IllegalArgumentException
|
||||
*/
|
||||
public static boolean isNotEmpty(Object o) {
|
||||
return !isEmpty(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal 여부를 확인한다.
|
||||
* @param obj Object, obj Object
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
public static boolean isEquals(Object obj, Object obj2){
|
||||
if(isEmpty(obj)) return false;
|
||||
|
||||
if(obj instanceof String && obj2 instanceof String) {
|
||||
if( (String.valueOf(obj)).equals( String.valueOf(obj2) )){
|
||||
return true;
|
||||
}
|
||||
}else if(obj instanceof String && obj2 instanceof Character) {
|
||||
if( (String.valueOf(obj) ).equals( String.valueOf(obj2) )){
|
||||
return true;
|
||||
}
|
||||
}else if(obj instanceof String && obj2 instanceof Integer) {
|
||||
if( (String.valueOf(obj)).equals( String.valueOf((Integer)obj2) )){
|
||||
return true;
|
||||
}
|
||||
|
||||
}else if(obj instanceof Integer && obj2 instanceof String) {
|
||||
if( (String.valueOf(obj2)).equals( String.valueOf((Integer)obj) )){
|
||||
return true;
|
||||
}
|
||||
} else if(obj instanceof Integer && obj instanceof Integer) {
|
||||
if((Integer)obj == (Integer)obj2){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* String의 Equal 여부를 확인한다.
|
||||
* @param obj Object, obj Object
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isEqualsStr(Object obj, String s){
|
||||
if(isEmpty(obj)) return false;
|
||||
|
||||
if(s.equals(String.valueOf(obj))){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
785
src/main/java/com/wb/domainserver/util/date/DateUtil.java
Normal file
785
src/main/java/com/wb/domainserver/util/date/DateUtil.java
Normal file
@@ -0,0 +1,785 @@
|
||||
package com.wb.domainserver.util.date;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import com.wb.domainserver.util.string.StringUtil;
|
||||
|
||||
/**
|
||||
* Date 처리를 지원하는 Utility
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-24
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-24 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class DateUtil {
|
||||
|
||||
/**
|
||||
* <p>yyyyMMdd 혹은 yyyy-MM-dd 형식의 날짜 문자열을 입력 받아 년, 월, 일을
|
||||
* 증감한다. 년, 월, 일은 가감할 수를 의미하며, 음수를 입력할 경우 감한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* DateUtil.addYearMonthDay("19810828", 0, 0, 19) = "19810916"
|
||||
* DateUtil.addYearMonthDay("20060228", 0, 0, -10) = "20060218"
|
||||
* DateUtil.addYearMonthDay("20060228", 0, 0, 10) = "20060310"
|
||||
* DateUtil.addYearMonthDay("20060228", 0, 0, 32) = "20060401"
|
||||
* DateUtil.addYearMonthDay("20050331", 0, -1, 0) = "20050228"
|
||||
* DateUtil.addYearMonthDay("20050301", 0, 2, 30) = "20050531"
|
||||
* DateUtil.addYearMonthDay("20050301", 1, 2, 30) = "20060531"
|
||||
* DateUtil.addYearMonthDay("20040301", 2, 0, 0) = "20060301"
|
||||
* DateUtil.addYearMonthDay("20040229", 2, 0, 0) = "20060228"
|
||||
* DateUtil.addYearMonthDay("20040229", 2, 0, 1) = "20060301"
|
||||
* </pre>
|
||||
*
|
||||
* @param dateStr 날짜 문자열(yyyyMMdd, yyyy-MM-dd의 형식)
|
||||
* @param year 가감할 년. 0이 입력될 경우 가감이 없다
|
||||
* @param month 가감할 월. 0이 입력될 경우 가감이 없다
|
||||
* @param day 가감할 일. 0이 입력될 경우 가감이 없다
|
||||
* @return yyyyMMdd 형식의 날짜 문자열
|
||||
* @throws IllegalArgumentException 날짜 포맷이 정해진 바와 다를 경우.
|
||||
* 입력 값이 <code>null</code>인 경우.
|
||||
*/
|
||||
public static String addYearMonthDay(String sDate, int year, int month, int day) {
|
||||
|
||||
String dateStr = validChkDate(sDate);
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
|
||||
try {
|
||||
cal.setTime(sdf.parse(dateStr));
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Invalid date format: " + dateStr);
|
||||
}
|
||||
|
||||
if (year != 0) {
|
||||
cal.add(Calendar.YEAR, year);
|
||||
}
|
||||
if (month != 0) {
|
||||
cal.add(Calendar.MONTH, month);
|
||||
}
|
||||
if (day != 0) {
|
||||
cal.add(Calendar.DATE, day);
|
||||
}
|
||||
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>yyyyMMdd 혹은 yyyy-MM-dd 형식의 날짜 문자열을 입력 받아 년을
|
||||
* 증감한다. <code>year</code>는 가감할 수를 의미하며, 음수를 입력할 경우 감한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* DateUtil.addYear("20000201", 62) = "20620201"
|
||||
* DateUtil.addYear("20620201", -62) = "20000201"
|
||||
* DateUtil.addYear("20040229", 2) = "20060228"
|
||||
* DateUtil.addYear("20060228", -2) = "20040228"
|
||||
* DateUtil.addYear("19000101", 200) = "21000101"
|
||||
* </pre>
|
||||
*
|
||||
* @param dateStr 날짜 문자열(yyyyMMdd, yyyy-MM-dd의 형식)
|
||||
* @param year 가감할 년. 0이 입력될 경우 가감이 없다
|
||||
* @return yyyyMMdd 형식의 날짜 문자열
|
||||
* @throws IllegalArgumentException 날짜 포맷이 정해진 바와 다를 경우.
|
||||
* 입력 값이 <code>null</code>인 경우.
|
||||
*/
|
||||
public static String addYear(String dateStr, int year) {
|
||||
return addYearMonthDay(dateStr, year, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>yyyyMMdd 혹은 yyyy-MM-dd 형식의 날짜 문자열을 입력 받아 월을
|
||||
* 증감한다. <code>month</code>는 가감할 수를 의미하며, 음수를 입력할 경우 감한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* DateUtil.addMonth("20010201", 12) = "20020201"
|
||||
* DateUtil.addMonth("19800229", 12) = "19810228"
|
||||
* DateUtil.addMonth("20040229", 12) = "20050228"
|
||||
* DateUtil.addMonth("20050228", -12) = "20040228"
|
||||
* DateUtil.addMonth("20060131", 1) = "20060228"
|
||||
* DateUtil.addMonth("20060228", -1) = "20060128"
|
||||
* </pre>
|
||||
*
|
||||
* @param dateStr 날짜 문자열(yyyyMMdd, yyyy-MM-dd의 형식)
|
||||
* @param month 가감할 월. 0이 입력될 경우 가감이 없다
|
||||
* @return yyyyMMdd 형식의 날짜 문자열
|
||||
* @throws IllegalArgumentException 날짜 포맷이 정해진 바와 다를 경우.
|
||||
* 입력 값이 <code>null</code>인 경우.
|
||||
*/
|
||||
public static String addMonth(String dateStr, int month) {
|
||||
return addYearMonthDay(dateStr, 0, month, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>yyyyMMdd 혹은 yyyy-MM-dd 형식의 날짜 문자열을 입력 받아 일(day)를
|
||||
* 증감한다. <code>day</code>는 가감할 수를 의미하며, 음수를 입력할 경우 감한다.
|
||||
* <br/><br/>
|
||||
* 위에 정의된 addDays 메서드는 사용자가 ParseException을 반드시 처리해야 하는 불편함이
|
||||
* 있기 때문에 추가된 메서드이다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* DateUtil.addDay("19991201", 62) = "20000201"
|
||||
* DateUtil.addDay("20000201", -62) = "19991201"
|
||||
* DateUtil.addDay("20050831", 3) = "20050903"
|
||||
* DateUtil.addDay("20050831", 3) = "20050903"
|
||||
* // 2006년 6월 31일은 실제로 존재하지 않는 날짜이다 -> 20060701로 간주된다
|
||||
* DateUtil.addDay("20060631", 1) = "20060702"
|
||||
* </pre>
|
||||
*
|
||||
* @param dateStr 날짜 문자열(yyyyMMdd, yyyy-MM-dd의 형식)
|
||||
* @param day 가감할 일. 0이 입력될 경우 가감이 없다
|
||||
* @return yyyyMMdd 형식의 날짜 문자열
|
||||
* @throws IllegalArgumentException 날짜 포맷이 정해진 바와 다를 경우.
|
||||
* 입력 값이 <code>null</code>인 경우.
|
||||
*/
|
||||
public static String addDay(String dateStr, int day) {
|
||||
return addYearMonthDay(dateStr, 0, 0, day);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>yyyyMMdd 혹은 yyyy-MM-dd 형식의 날짜 문자열 <code>dateStr1</code>과 <code>
|
||||
* dateStr2</code> 사이의 일 수를 구한다.<br>
|
||||
* <code>dateStr2</code>가 <code>dateStr1</code> 보다 과거 날짜일 경우에는
|
||||
* 음수를 반환한다. 동일한 경우에는 0을 반환한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* DateUtil.getDaysDiff("20060228","20060310") = 10
|
||||
* DateUtil.getDaysDiff("20060101","20070101") = 365
|
||||
* DateUtil.getDaysDiff("19990228","19990131") = -28
|
||||
* DateUtil.getDaysDiff("20060801","20060802") = 1
|
||||
* DateUtil.getDaysDiff("20060801","20060801") = 0
|
||||
* </pre>
|
||||
*
|
||||
* @param dateStr1 날짜 문자열(yyyyMMdd, yyyy-MM-dd의 형식)
|
||||
* @param dateStr2 날짜 문자열(yyyyMMdd, yyyy-MM-dd의 형식)
|
||||
* @return 일 수 차이.
|
||||
* @throws IllegalArgumentException 날짜 포맷이 정해진 바와 다를 경우.
|
||||
* 입력 값이 <code>null</code>인 경우.
|
||||
*/
|
||||
public static int getDaysDiff(String sDate1, String sDate2) {
|
||||
String dateStr1 = validChkDate(sDate1);
|
||||
String dateStr2 = validChkDate(sDate2);
|
||||
|
||||
if (!checkDate(sDate1) || !checkDate(sDate2)) {
|
||||
throw new IllegalArgumentException("Invalid date format: args[0]=" + sDate1 + " args[1]=" + sDate2);
|
||||
}
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
|
||||
|
||||
Date date1 = null;
|
||||
Date date2 = null;
|
||||
try {
|
||||
date1 = sdf.parse(dateStr1);
|
||||
date2 = sdf.parse(dateStr2);
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Invalid date format: args[0]=" + dateStr1 + " args[1]=" + dateStr2);
|
||||
}
|
||||
|
||||
if (date1 != null && date2 != null) {
|
||||
int days1 = (int) ((date1.getTime() / 3600000) / 24);
|
||||
int days2 = (int) ((date2.getTime() / 3600000) / 24);
|
||||
return days2 - days1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>yyyyMMdd 혹은 yyyy-MM-dd 형식의 날짜 문자열을 입력 받아 유효한 날짜인지 검사.</p>
|
||||
*
|
||||
* <pre>
|
||||
* DateUtil.checkDate("1999-02-35") = false
|
||||
* DateUtil.checkDate("2000-13-31") = false
|
||||
* DateUtil.checkDate("2006-11-31") = false
|
||||
* DateUtil.checkDate("2006-2-28") = false
|
||||
* DateUtil.checkDate("2006-2-8") = false
|
||||
* DateUtil.checkDate("20060228") = true
|
||||
* DateUtil.checkDate("2006-02-28") = true
|
||||
* </pre>
|
||||
*
|
||||
* @param dateStr 날짜 문자열(yyyyMMdd, yyyy-MM-dd의 형식)
|
||||
* @return 유효한 날짜인지 여부
|
||||
*/
|
||||
public static boolean checkDate(String sDate) {
|
||||
String dateStr = validChkDate(sDate);
|
||||
|
||||
String year = dateStr.substring(0, 4);
|
||||
String month = dateStr.substring(4, 6);
|
||||
String day = dateStr.substring(6);
|
||||
|
||||
return checkDate(year, month, day);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>입력한 년, 월, 일이 유효한지 검사.</p>
|
||||
*
|
||||
* @param year 연도
|
||||
* @param month 월
|
||||
* @param day 일
|
||||
* @return 유효한 날짜인지 여부
|
||||
*/
|
||||
public static boolean checkDate(String year, String month, String day) {
|
||||
boolean isValidDate = false;
|
||||
|
||||
try {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd", Locale.getDefault());
|
||||
|
||||
Date result = formatter.parse(year + "." + month + "." + day);
|
||||
String resultStr = formatter.format(result);
|
||||
if (resultStr.equalsIgnoreCase(year + "." + month + "." + day)) {
|
||||
isValidDate = true; // 올바른 날짜 형식일 경우 true 설정
|
||||
} else {
|
||||
isValidDate = false; // 잘못된 날짜 형식일 경우 false 설정
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
isValidDate = false;
|
||||
}
|
||||
|
||||
return isValidDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 날짜형태의 String의 날짜 포맷 및 TimeZone을 변경해 주는 메서드
|
||||
*
|
||||
* @param strSource 바꿀 날짜 String
|
||||
* @param fromDateFormat 기존의 날짜 형태
|
||||
* @param toDateFormat 원하는 날짜 형태
|
||||
* @param strTimeZone 변경할 TimeZone(""이면 변경 안함)
|
||||
* @return 소스 String의 날짜 포맷을 변경한 String
|
||||
*/
|
||||
public static String convertDate(String strSource, String fromDateFormat, String toDateFormat, String strTimeZone) {
|
||||
SimpleDateFormat simpledateformat = null;
|
||||
Date date = null;
|
||||
String fromFormat = "";
|
||||
String toFormat = "";
|
||||
|
||||
if (StringUtil.isNullToString(strSource).trim().equals("")) {
|
||||
return "";
|
||||
}
|
||||
if (StringUtil.isNullToString(fromDateFormat).trim().equals(""))
|
||||
fromFormat = "yyyyMMddHHmmss"; // default값
|
||||
if (StringUtil.isNullToString(toDateFormat).trim().equals(""))
|
||||
toFormat = "yyyy-MM-dd HH:mm:ss"; // default값
|
||||
|
||||
try {
|
||||
simpledateformat = new SimpleDateFormat(fromFormat, Locale.getDefault());
|
||||
date = simpledateformat.parse(strSource);
|
||||
if (!StringUtil.isNullToString(strTimeZone).trim().equals("")) {
|
||||
simpledateformat.setTimeZone(TimeZone.getTimeZone(strTimeZone));
|
||||
}
|
||||
simpledateformat = new SimpleDateFormat(toFormat, Locale.getDefault());
|
||||
} catch (ParseException exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
|
||||
return simpledateformat.format(date);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* yyyyMMdd 형식의 날짜문자열을 원하는 캐릭터(ch)로 쪼개 돌려준다<br/>
|
||||
* <pre>
|
||||
* ex) 20030405, ch(.) -> 2003.04.05
|
||||
* ex) 200304, ch(.) -> 2003.04
|
||||
* ex) 20040101,ch(/) --> 2004/01/01 로 리턴
|
||||
* </pre>
|
||||
*
|
||||
* @param date yyyyMMdd 형식의 날짜문자열
|
||||
* @param ch 구분자
|
||||
* @return 변환된 문자열
|
||||
*/
|
||||
public static String formatDate(String sDate, String ch) {
|
||||
String dateStr = validChkDate(sDate);
|
||||
|
||||
String str = dateStr.trim();
|
||||
String yyyy = "";
|
||||
String mm = "";
|
||||
String dd = "";
|
||||
|
||||
if (str.length() == 8) {
|
||||
yyyy = str.substring(0, 4);
|
||||
if (yyyy.equals("0000")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
mm = str.substring(4, 6);
|
||||
if (mm.equals("00")) {
|
||||
return yyyy;
|
||||
}
|
||||
|
||||
dd = str.substring(6, 8);
|
||||
if (dd.equals("00")) {
|
||||
return yyyy + ch + mm;
|
||||
}
|
||||
|
||||
return yyyy + ch + mm + ch + dd;
|
||||
|
||||
} else if (str.length() == 6) {
|
||||
yyyy = str.substring(0, 4);
|
||||
if (yyyy.equals("0000")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
mm = str.substring(4, 6);
|
||||
if (mm.equals("00")) {
|
||||
return yyyy;
|
||||
}
|
||||
|
||||
return yyyy + ch + mm;
|
||||
|
||||
} else if (str.length() == 4) {
|
||||
yyyy = str.substring(0, 4);
|
||||
if (yyyy.equals("0000")) {
|
||||
return "";
|
||||
} else {
|
||||
return yyyy;
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HH24MISS 형식의 시간문자열을 원하는 캐릭터(ch)로 쪼개 돌려준다 <br>
|
||||
* <pre>
|
||||
* ex) 151241, ch(/) -> 15/12/31
|
||||
* </pre>
|
||||
*
|
||||
* @param str HH24MISS 형식의 시간문자열
|
||||
* @param ch 구분자
|
||||
* @return 변환된 문자열
|
||||
*/
|
||||
public static String formatTime(String sTime, String ch) {
|
||||
String timeStr = validChkTime(sTime);
|
||||
return timeStr.substring(0, 2) + ch + timeStr.substring(2, 4) + ch + timeStr.substring(4, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* 연도를 입력 받아 해당 연도 2월의 말일(일수)를 문자열로 반환한다.
|
||||
*
|
||||
* @param year
|
||||
* @return 해당 연도 2월의 말일(일수)
|
||||
*/
|
||||
public String leapYear(int year) {
|
||||
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
|
||||
return "29";
|
||||
}
|
||||
|
||||
return "28";
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>입력받은 연도가 윤년인지 아닌지 검사한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* DateUtil.isLeapYear(2004) = false
|
||||
* DateUtil.isLeapYear(2005) = true
|
||||
* DateUtil.isLeapYear(2006) = true
|
||||
* </pre>
|
||||
*
|
||||
* @param year 연도
|
||||
* @return 윤년 여부
|
||||
*/
|
||||
public static boolean isLeapYear(int year) {
|
||||
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재(한국기준) 날짜정보를 얻는다. <BR>
|
||||
* 표기법은 yyyy-mm-dd <BR>
|
||||
* @return String yyyymmdd형태의 현재 한국시간. <BR>
|
||||
*/
|
||||
public static String getToday() {
|
||||
return getCurrentDate("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재(한국기준) 날짜정보를 얻는다. <BR>
|
||||
* 표기법은 yyyy-mm-dd <BR>
|
||||
* @return String yyyymmdd형태의 현재 한국시간. <BR>
|
||||
*/
|
||||
public static String getCurrentDate(String dateType) {
|
||||
Calendar aCalendar = Calendar.getInstance();
|
||||
|
||||
int year = aCalendar.get(Calendar.YEAR);
|
||||
int month = aCalendar.get(Calendar.MONTH) + 1;
|
||||
int date = aCalendar.get(Calendar.DATE);
|
||||
String strDate = Integer.toString(year)
|
||||
+ ((month < 10) ? "0" + Integer.toString(month) : Integer.toString(month))
|
||||
+ ((date < 10) ? "0" + Integer.toString(date) : Integer.toString(date));
|
||||
|
||||
if (!"".equals(dateType)) {
|
||||
strDate = convertDate(strDate, "yyyyMMdd", dateType);
|
||||
}
|
||||
|
||||
return strDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 날짜형태의 String의 날짜 포맷만을 변경해 주는 메서드
|
||||
* @param sDate 날짜
|
||||
* @param sTime 시간
|
||||
* @param sFormatStr 포멧 스트링 문자열
|
||||
* @return 지정한 날짜/시간을 지정한 포맷으로 출력
|
||||
* @See Letter Date or Time Component Presentation Examples
|
||||
G Era designator Text AD
|
||||
y Year Year 1996; 96
|
||||
M Month in year Month July; Jul; 07
|
||||
w Week in year Number 27
|
||||
W Week in month Number 2
|
||||
D Day in year Number 189
|
||||
d Day in month Number 10
|
||||
F Day of week in month Number 2
|
||||
E Day in week Text Tuesday; Tue
|
||||
a Am/pm marker Text PM
|
||||
H Hour in day (0-23) Number 0
|
||||
k Hour in day (1-24) Number 24
|
||||
K Hour in am/pm (0-11) Number 0
|
||||
h Hour in am/pm (1-12) Number 12
|
||||
m Minute in hour Number 30
|
||||
s Second in minute Number 55
|
||||
S Millisecond Number 978
|
||||
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
|
||||
Z Time zone RFC 822 time zone -0800
|
||||
|
||||
Date and Time Pattern Result
|
||||
"yyyy.MM.dd G 'at' HH:mm:ss z" 2001.07.04 AD at 12:08:56 PDT
|
||||
"EEE, MMM d, ''yy" Wed, Jul 4, '01
|
||||
"h:mm a" 12:08 PM
|
||||
"hh 'o''clock' a, zzzz" 12 o'clock PM, Pacific Daylight Time
|
||||
"K:mm a, z" 0:08 PM, PDT
|
||||
"yyyyy.MMMMM.dd GGG hh:mm aaa" 02001.July.04 AD 12:08 PM
|
||||
"EEE, d MMM yyyy HH:mm:ss Z" Wed, 4 Jul 2001 12:08:56 -0700
|
||||
"yyMMddHHmmssZ" 010704120856-0700
|
||||
|
||||
*/
|
||||
public static String convertDate(String sDate, String sTime, String sFormatStr) {
|
||||
String dateStr = validChkDate(sDate);
|
||||
String timeStr = validChkTime(sTime);
|
||||
|
||||
Calendar cal = null;
|
||||
cal = Calendar.getInstance();
|
||||
|
||||
cal.set(Calendar.YEAR, Integer.parseInt(dateStr.substring(0, 4)));
|
||||
cal.set(Calendar.MONTH, Integer.parseInt(dateStr.substring(4, 6)) - 1);
|
||||
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStr.substring(6, 8)));
|
||||
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(timeStr.substring(0, 2)));
|
||||
cal.set(Calendar.MINUTE, Integer.parseInt(timeStr.substring(2, 4)));
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(sFormatStr, Locale.ENGLISH);
|
||||
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력받은 일자 사이의 임의의 일자를 반환
|
||||
* @param sDate1 시작일자
|
||||
* @param sDate2 종료일자
|
||||
* @return 임의일자
|
||||
*/
|
||||
public static String getRandomDate(String sDate1, String sDate2) {
|
||||
String dateStr1 = validChkDate(sDate1);
|
||||
String dateStr2 = validChkDate(sDate2);
|
||||
|
||||
String randomDate = null;
|
||||
|
||||
int sYear, sMonth, sDay;
|
||||
int eYear, eMonth, eDay;
|
||||
|
||||
sYear = Integer.parseInt(dateStr1.substring(0, 4));
|
||||
sMonth = Integer.parseInt(dateStr1.substring(4, 6));
|
||||
sDay = Integer.parseInt(dateStr1.substring(6, 8));
|
||||
|
||||
eYear = Integer.parseInt(dateStr2.substring(0, 4));
|
||||
eMonth = Integer.parseInt(dateStr2.substring(4, 6));
|
||||
eDay = Integer.parseInt(dateStr2.substring(6, 8));
|
||||
|
||||
GregorianCalendar beginDate = new GregorianCalendar(sYear, sMonth - 1, sDay, 0, 0);
|
||||
GregorianCalendar endDate = new GregorianCalendar(eYear, eMonth - 1, eDay, 23, 59);
|
||||
|
||||
if (endDate.getTimeInMillis() < beginDate.getTimeInMillis()) {
|
||||
throw new IllegalArgumentException("Invalid input date : " + sDate1 + "~" + sDate2);
|
||||
}
|
||||
|
||||
SecureRandom r = new SecureRandom();
|
||||
|
||||
r.setSeed(new Date().getTime());
|
||||
|
||||
long rand = ((r.nextLong() >>> 1) % (endDate.getTimeInMillis() - beginDate.getTimeInMillis() + 1)) + beginDate.getTimeInMillis();
|
||||
|
||||
GregorianCalendar cal = new GregorianCalendar();
|
||||
//SimpleDateFormat calformat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
SimpleDateFormat calformat = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
|
||||
cal.setTimeInMillis(rand);
|
||||
randomDate = calformat.format(cal.getTime());
|
||||
|
||||
// 랜덤문자열를 리턴
|
||||
return randomDate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 입력받은 요일의 영문명을 국문명의 요일로 반환
|
||||
* @param sWeek 영문 요일명
|
||||
* @return 국문 요일명
|
||||
*/
|
||||
public static String convertWeek(String sWeek) {
|
||||
String retStr = null;
|
||||
|
||||
if (sWeek.equals("SUN")) {
|
||||
retStr = "일요일";
|
||||
} else if (sWeek.equals("MON")) {
|
||||
retStr = "월요일";
|
||||
} else if (sWeek.equals("TUE")) {
|
||||
retStr = "화요일";
|
||||
} else if (sWeek.equals("WED")) {
|
||||
retStr = "수요일";
|
||||
} else if (sWeek.equals("THR")) {
|
||||
retStr = "목요일";
|
||||
} else if (sWeek.equals("FRI")) {
|
||||
retStr = "금요일";
|
||||
} else if (sWeek.equals("SAT")) {
|
||||
retStr = "토요일";
|
||||
}
|
||||
|
||||
return retStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력일자의 유효 여부를 확인
|
||||
* @param sDate 일자
|
||||
* @return 유효 여부
|
||||
*/
|
||||
public static boolean validDate(String sDate) {
|
||||
String dateStr = validChkDate(sDate);
|
||||
|
||||
Calendar cal;
|
||||
boolean ret = false;
|
||||
|
||||
cal = Calendar.getInstance();
|
||||
|
||||
cal.set(Calendar.YEAR, Integer.parseInt(dateStr.substring(0, 4)));
|
||||
cal.set(Calendar.MONTH, Integer.parseInt(dateStr.substring(4, 6)) - 1);
|
||||
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStr.substring(6, 8)));
|
||||
|
||||
String year = String.valueOf(cal.get(Calendar.YEAR));
|
||||
String month = String.valueOf(cal.get(Calendar.MONTH) + 1);
|
||||
String day = String.valueOf(cal.get(Calendar.DAY_OF_MONTH));
|
||||
|
||||
String pad4Str = "0000";
|
||||
String pad2Str = "00";
|
||||
|
||||
String retYear = (pad4Str + year).substring(year.length());
|
||||
String retMonth = (pad2Str + month).substring(month.length());
|
||||
String retDay = (pad2Str + day).substring(day.length());
|
||||
|
||||
String retYMD = retYear + retMonth + retDay;
|
||||
|
||||
if (sDate.equals(retYMD)) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력일자, 요일의 유효 여부를 확인
|
||||
* @param sDate 일자
|
||||
* @param sWeek 요일 (DAY_OF_WEEK)
|
||||
* @return 유효 여부
|
||||
*/
|
||||
public static boolean validDate(String sDate, int sWeek) {
|
||||
String dateStr = validChkDate(sDate);
|
||||
|
||||
Calendar cal;
|
||||
boolean ret = false;
|
||||
|
||||
cal = Calendar.getInstance();
|
||||
|
||||
cal.set(Calendar.YEAR, Integer.parseInt(dateStr.substring(0, 4)));
|
||||
cal.set(Calendar.MONTH, Integer.parseInt(dateStr.substring(4, 6)) - 1);
|
||||
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStr.substring(6, 8)));
|
||||
|
||||
int Week = cal.get(Calendar.DAY_OF_WEEK);
|
||||
|
||||
if (validDate(sDate)) {
|
||||
if (sWeek == Week) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력시간의 유효 여부를 확인
|
||||
* @param sTime 입력시간
|
||||
* @return 유효 여부
|
||||
*/
|
||||
public static boolean validTime(String sTime) {
|
||||
String timeStr = validChkTime(sTime);
|
||||
|
||||
Calendar cal;
|
||||
boolean ret = false;
|
||||
|
||||
cal = Calendar.getInstance();
|
||||
|
||||
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(timeStr.substring(0, 2)));
|
||||
cal.set(Calendar.MINUTE, Integer.parseInt(timeStr.substring(2, 4)));
|
||||
|
||||
String HH = String.valueOf(cal.get(Calendar.HOUR_OF_DAY));
|
||||
String MM = String.valueOf(cal.get(Calendar.MINUTE));
|
||||
|
||||
String pad2Str = "00";
|
||||
|
||||
String retHH = (pad2Str + HH).substring(HH.length());
|
||||
String retMM = (pad2Str + MM).substring(MM.length());
|
||||
|
||||
String retTime = retHH + retMM;
|
||||
|
||||
if (sTime.equals(retTime)) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력된 일자에 연, 월, 일을 가감한 날짜의 요일을 반환
|
||||
* @param sDate 날짜
|
||||
* @param year 연
|
||||
* @param month 월
|
||||
* @param day 일
|
||||
* @return 계산된 일자의 요일(DAY_OF_WEEK)
|
||||
*/
|
||||
public static String addYMDtoWeek(String sDate, int year, int month, int day) {
|
||||
String dateStr = validChkDate(sDate);
|
||||
|
||||
dateStr = addYearMonthDay(dateStr, year, month, day);
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
|
||||
try {
|
||||
cal.setTime(sdf.parse(dateStr));
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Invalid date format: " + dateStr);
|
||||
}
|
||||
|
||||
SimpleDateFormat rsdf = new SimpleDateFormat("E", Locale.ENGLISH);
|
||||
|
||||
return rsdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력된 일자에 연, 월, 일, 시간, 분을 가감한 날짜, 시간을 포멧스트링 형식으로 반환
|
||||
* @param sDate 날짜
|
||||
* @param sTime 시간
|
||||
* @param year 연
|
||||
* @param month 월
|
||||
* @param day 일
|
||||
* @param hour 시간
|
||||
* @param minute 분
|
||||
* @param formatStr 포멧스트링
|
||||
* @return
|
||||
*/
|
||||
public static String addYMDtoDayTime(String sDate, String sTime, int year, int month, int day, int hour, int minute, String formatStr) {
|
||||
String dateStr = validChkDate(sDate);
|
||||
String timeStr = validChkTime(sTime);
|
||||
|
||||
dateStr = addYearMonthDay(dateStr, year, month, day);
|
||||
|
||||
dateStr = convertDate(dateStr, timeStr, "yyyyMMddHHmm");
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm", Locale.ENGLISH);
|
||||
|
||||
try {
|
||||
cal.setTime(sdf.parse(dateStr));
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Invalid date format: " + dateStr);
|
||||
}
|
||||
|
||||
if (hour != 0) {
|
||||
cal.add(Calendar.HOUR, hour);
|
||||
}
|
||||
|
||||
if (minute != 0) {
|
||||
cal.add(Calendar.MINUTE, minute);
|
||||
}
|
||||
|
||||
SimpleDateFormat rsdf = new SimpleDateFormat(formatStr, Locale.ENGLISH);
|
||||
|
||||
return rsdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력된 일자를 int 형으로 반환
|
||||
* @param sDate 일자
|
||||
* @return int(일자)
|
||||
*/
|
||||
public static int datetoInt(String sDate) {
|
||||
return Integer.parseInt(convertDate(sDate, "0000", "yyyyMMdd"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력된 시간을 int 형으로 반환
|
||||
* @param sTime 시간
|
||||
* @return int(시간)
|
||||
*/
|
||||
public static int timetoInt(String sTime) {
|
||||
return Integer.parseInt(convertDate("00000101", sTime, "HHmm"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력된 일자 문자열을 확인하고 8자리로 리턴
|
||||
* @param sDate
|
||||
* @return
|
||||
*/
|
||||
public static String validChkDate(String dateStr) {
|
||||
if (dateStr == null || !(dateStr.trim().length() == 8 || dateStr.trim().length() == 10)) {
|
||||
throw new IllegalArgumentException("Invalid date format: " + dateStr);
|
||||
}
|
||||
|
||||
if (dateStr.length() == 10) {
|
||||
return StringUtil.removeMinusChar(dateStr);
|
||||
}
|
||||
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 입력된 일자 문자열을 확인하고 8자리로 리턴
|
||||
* @param sDate
|
||||
* @return
|
||||
*/
|
||||
public static String validChkTime(String timeStr) {
|
||||
if (timeStr == null || !(timeStr.trim().length() == 4)) {
|
||||
throw new IllegalArgumentException("Invalid time format: " + timeStr);
|
||||
}
|
||||
|
||||
if (timeStr.length() == 5) {
|
||||
timeStr = StringUtil.remove(timeStr, ':');
|
||||
}
|
||||
|
||||
return timeStr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package com.wb.domainserver.util.excel;
|
||||
|
||||
import com.wb.domainserver.util.ResourceCloseHelper;
|
||||
import com.wb.domainserver.util.string.StringUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* 엑셀 생성 및 다운로드를 처리해주는
|
||||
* @author 박철민
|
||||
* @since 2023-12-20
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-12-20 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
public class ExcelDownloadUtil {
|
||||
|
||||
/**
|
||||
* 엑셀파일 생성 및 다운로드 처리
|
||||
* @param excelFileName 다운로드될 엑셀파일명
|
||||
* @param headerMap 제목영역에 출력될 데이터 map
|
||||
* @param dataList 데이터영역에 출력될 데이터 map list
|
||||
* @param response 다운로드 처리를 위한 응답객체
|
||||
* @param useType cell 데이터 타입 적용여부
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void createExcel(String excelFileName,
|
||||
LinkedHashMap<String, String> headerMap,
|
||||
List<Map<String, Object>> dataList,
|
||||
HttpServletResponse response,
|
||||
boolean useType) throws IOException {
|
||||
Workbook wb = new SXSSFWorkbook();
|
||||
try {
|
||||
Sheet sheet = wb.createSheet();
|
||||
createHeaderRow(wb, sheet, headerMap);
|
||||
createDataRow(wb, sheet, headerMap, dataList, useType);
|
||||
response.setContentType("ms-vnd/excel");
|
||||
response.setHeader("Content-Disposition", "attachment;filename="+excelFileName+".xlsx");
|
||||
wb.write(response.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
log.error("Workbook write 수행 중 IOException 발생!");
|
||||
throw e;
|
||||
} finally {
|
||||
ResourceCloseHelper.close(wb);
|
||||
}
|
||||
}
|
||||
public static void createExcel(String excelFileName,
|
||||
LinkedHashMap<String, String> headerMap,
|
||||
List<Map<String, Object>> dataList,
|
||||
HttpServletResponse response) throws IOException {
|
||||
createExcel(excelFileName, headerMap, dataList, response, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 제목영역 생성
|
||||
* @param wb 엑셀workbook객체
|
||||
* @param sheet 엑셀sheet객체
|
||||
* @param headerMap 제목영역에 출력될 데이터 map
|
||||
*/
|
||||
private static void createHeaderRow(Workbook wb,
|
||||
Sheet sheet,
|
||||
LinkedHashMap<String, String> headerMap) {
|
||||
Row row = sheet.createRow(0);
|
||||
CellStyle excelheaderStyle = wb.createCellStyle();
|
||||
Font excelheaderFont = wb.createFont();
|
||||
|
||||
|
||||
getExcelHeaderCellStyle(excelheaderStyle, excelheaderFont);
|
||||
|
||||
headerMap.forEach((key, value)->{
|
||||
createCell(wb, row, value, excelheaderStyle, false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 데이터영역 생성
|
||||
* @param wb 엑셀workbook객체
|
||||
* @param sheet 엑셀sheet객체
|
||||
* @param headerMap 제목영역에 출력될 데이터 map
|
||||
* @param dataList 데이터영역에 출력될 데이터 map list
|
||||
* @param useType cell 데이터 타입 적용여부
|
||||
*/
|
||||
private static void createDataRow(Workbook wb,
|
||||
Sheet sheet,
|
||||
LinkedHashMap<String, String> headerMap,
|
||||
List<Map<String, Object>> dataList,
|
||||
boolean useType) {
|
||||
if(dataList != null
|
||||
&& !dataList.isEmpty()) {
|
||||
|
||||
|
||||
CellStyle excelheaderStyle = wb.createCellStyle();
|
||||
Font excelheaderFont = wb.createFont();
|
||||
getExcelDataCellStyle(excelheaderStyle, excelheaderFont);
|
||||
|
||||
|
||||
for(int idx=0; idx<dataList.size(); idx++) {
|
||||
Row row = sheet.createRow(idx+1);
|
||||
for( String key : headerMap.keySet() ){
|
||||
createCell(wb, row, dataList.get(idx).get(key), excelheaderStyle, useType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 셀생성
|
||||
* @param wb 엑셀workbook객체
|
||||
* @param row 엑셀sheet객체
|
||||
* @param cellValue cell에 설정될 값
|
||||
* @param cellStyle cell에 적용될 style
|
||||
* @param useType cell 데이터 타입 적용여부
|
||||
*/
|
||||
private static void createCell(Workbook wb,
|
||||
Row row,
|
||||
Object cellValue,
|
||||
CellStyle cellStyle,
|
||||
boolean useType) {
|
||||
int column=0;
|
||||
if(row.getLastCellNum() > 0) {
|
||||
column = row.getLastCellNum();
|
||||
}
|
||||
Cell cell = row.createCell(column);
|
||||
if (useType && cellValue instanceof Number) {
|
||||
cell.setCellValue(((Number) cellValue).doubleValue());
|
||||
} else {
|
||||
cell.setCellValue(StringUtil.isNullToString(cellValue));
|
||||
}
|
||||
cell.setCellStyle(cellStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 제목영역 cell style 설정
|
||||
* @param wb 엑셀workbook객체
|
||||
* @return CellStyle 엑셀 제목영역 cell style
|
||||
*/
|
||||
private static void getExcelHeaderCellStyle(CellStyle excelheaderStyle, Font excelheaderFont) {
|
||||
|
||||
//정렬설정
|
||||
excelheaderStyle.setAlignment(HorizontalAlignment.CENTER);
|
||||
excelheaderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
//제목영역 배경색 설정
|
||||
excelheaderStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
||||
excelheaderStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||
|
||||
//테두리 선 (우,좌,위,아래)
|
||||
excelheaderStyle.setBorderRight(BorderStyle.THIN);
|
||||
excelheaderStyle.setBorderLeft(BorderStyle.THIN);
|
||||
excelheaderStyle.setBorderTop(BorderStyle.THIN);
|
||||
excelheaderStyle.setBorderBottom(BorderStyle.THIN);
|
||||
|
||||
//폰트 설정
|
||||
excelheaderFont.setFontName("나눔고딕"); //글씨체
|
||||
excelheaderFont.setFontHeight((short)(10*20)); //사이즈
|
||||
excelheaderFont.setBold(true);
|
||||
excelheaderStyle.setFont(excelheaderFont);
|
||||
}
|
||||
|
||||
/**
|
||||
* 엑셀 데이터영역 cell style 설정
|
||||
* @param wb 엑셀workbook객체
|
||||
* @return CellStyle 엑셀 데이터영역 cell style
|
||||
*/
|
||||
private static void getExcelDataCellStyle(CellStyle excelheaderStyle, Font excelheaderFont) {
|
||||
|
||||
//정렬설정
|
||||
excelheaderStyle.setAlignment(HorizontalAlignment.LEFT);
|
||||
excelheaderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
|
||||
//테두리 선 (우,좌,위,아래)
|
||||
excelheaderStyle.setBorderRight(BorderStyle.THIN);
|
||||
excelheaderStyle.setBorderLeft(BorderStyle.THIN);
|
||||
excelheaderStyle.setBorderTop(BorderStyle.THIN);
|
||||
excelheaderStyle.setBorderBottom(BorderStyle.THIN);
|
||||
|
||||
//폰트 설정
|
||||
excelheaderFont.setFontName("나눔고딕"); //글씨체
|
||||
excelheaderFont.setFontHeight((short)(10*20)); //사이즈
|
||||
excelheaderFont.setBold(false);
|
||||
excelheaderStyle.setFont(excelheaderFont);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
347
src/main/java/com/wb/domainserver/util/file/FileMngUtil.java
Normal file
347
src/main/java/com/wb/domainserver/util/file/FileMngUtil.java
Normal file
@@ -0,0 +1,347 @@
|
||||
package com.wb.domainserver.util.file;
|
||||
|
||||
import com.wb.domainserver.exception.WnbtRestException;
|
||||
import com.wb.domainserver.util.string.StringUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.tika.Tika;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* multipart로 업로드된 파일을 처리하는 UTIL
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2024-01-03
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* CkEditor로 업로드 하는 경우 사용
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2024-01-03 박철민 최초 생성
|
||||
* 2024-02-21 김혜지 수정
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@Component("fileMngUtil")
|
||||
public class FileMngUtil {
|
||||
|
||||
/**
|
||||
* 첨부파일에 대한 목록 정보 취득 및 저장처리를 진행한다.
|
||||
* @param files 업로드된 multipartfile 목록
|
||||
* @param KeyStr rename되는 파일명 앞에 설정될 prefix
|
||||
* @param storePath 업로드된 파일이 저장될 경로
|
||||
* @param whiteListFileUploadExtensions 업로드가 허용된 파일확장자 목록
|
||||
* @return List<Map<String, Object>> 처리결과 목록 정보
|
||||
*/
|
||||
public List<Map<String, Object>> parseFileInf(List<MultipartFile> files,
|
||||
String prefix,
|
||||
String storePath,
|
||||
String whiteListFileUploadExtensions) {
|
||||
List<Map<String, Object>> resultList= new ArrayList<>();
|
||||
Map<String, Object> fileMap = null;
|
||||
File saveFolder = null;
|
||||
String storePathString = null;
|
||||
String orginFileName = null;
|
||||
String fileExt = null;
|
||||
String newName = null;
|
||||
String filePath = null;
|
||||
Long size = null;
|
||||
Integer fileKey = 0;
|
||||
try {
|
||||
|
||||
log.debug("whiteListFileUploadExtensions is {}", whiteListFileUploadExtensions);
|
||||
|
||||
storePathString = storePath;
|
||||
|
||||
if (storePath == null || "".equals(storePath)) {
|
||||
throw new WnbtRestException("파일 업로드 경로가 존재하지 않습니다.");
|
||||
}
|
||||
log.debug("storePathString is {}", storePathString);
|
||||
|
||||
//파일이 저장될 디렉토리 생성
|
||||
saveFolder = new File(filePathBlackList(storePathString));
|
||||
|
||||
if (!saveFolder.exists() || saveFolder.isFile()) {
|
||||
if (saveFolder.mkdirs()) {
|
||||
log.debug("[file.mkdirs] saveFolder : Creation Success ");
|
||||
} else {
|
||||
log.error("[file.mkdirs] saveFolder : Creation Fail ");
|
||||
}
|
||||
}
|
||||
|
||||
//MultipartFile 정보 parsing 및 확장자 허용여부 점검 후 파일 시스템에 저장
|
||||
for (MultipartFile file : files) {
|
||||
orginFileName = file.getOriginalFilename();
|
||||
|
||||
log.debug("orginFileName is {}", orginFileName);
|
||||
|
||||
if (StringUtil.isEmpty(orginFileName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//파일명, mimetype 검사
|
||||
if (!isSanitizeFileName(file)) {
|
||||
throw new WnbtRestException("허용되지 않은 파일명입니다.");
|
||||
}
|
||||
|
||||
//확장자검사
|
||||
String orgFileNm = FilenameUtils.getExtension(orginFileName);
|
||||
if(orgFileNm != null) {
|
||||
fileExt = orgFileNm.toUpperCase();
|
||||
}
|
||||
if(!StringUtil.isEmpty(whiteListFileUploadExtensions) && !StringUtil.isEmpty(fileExt)) {
|
||||
if(!whiteListFileUploadExtensions.contains("."+fileExt.toLowerCase())) {
|
||||
throw new WnbtRestException("허용되지 않은 파일유형입니다.");
|
||||
}
|
||||
}else {
|
||||
throw new WnbtRestException("지원하지 않는 파일확장자입니다.");
|
||||
}
|
||||
|
||||
//파일 중복을 방지하기 위해 rename 처리 : prefix(shopCd) + ddhhmmssSSS + 영문대소숫자 (20자)
|
||||
newName = RandomGenerator.genString(20, prefix+getTimeStamp());
|
||||
size = file.getSize();
|
||||
filePath = storePathString + File.separator + newName;
|
||||
|
||||
//MultipartFile 정보 parsing 결과 설정
|
||||
fileMap = new HashMap<>();
|
||||
fileMap.put("fileExt", fileExt);
|
||||
fileMap.put("fileStreCours", storePathString); //저장경로
|
||||
|
||||
// byte를 KB로 변환하기 위한 로직 추가
|
||||
if(StringUtil.isEmpty(size.toString())) {
|
||||
fileMap.put("size", "");
|
||||
} else {
|
||||
fileMap.put("size", String.valueOf(Math.round(size/1024.0)));
|
||||
}
|
||||
fileMap.put("orginFileName", orginFileName);
|
||||
fileMap.put("streFileNm", newName);
|
||||
fileMap.put("filePath", filePath);
|
||||
fileMap.put("multipartFile", file);
|
||||
|
||||
resultList.add(fileMap);
|
||||
fileKey++;
|
||||
}
|
||||
//업로드된 파일 파일시스템에 저장
|
||||
//확장자 점검 중 오류가 발생할 경우 불필요한 파일이 파일시스템에 남지않게 하기위해 점검 후 저장수행
|
||||
transferFile(resultList);
|
||||
log.debug("file upload result is {}", resultList);
|
||||
} catch(WnbtRestException wre) {
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch(Exception e) {
|
||||
throw new WnbtRestException(e.getMessage());
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 서버 파일에 대하여 다운로드를 처리한다.
|
||||
* @param response
|
||||
* @param streFileNm
|
||||
* @param orignFileNm
|
||||
* @throws Exception
|
||||
*/
|
||||
public void downFile(HttpServletResponse response, String streFileNm, String orignFileNm) throws Exception {
|
||||
downFile(response, streFileNm, orignFileNm, "application/x-msdownload");
|
||||
}
|
||||
|
||||
/**
|
||||
* 서버 파일에 대하여 다운로드를 처리한다.
|
||||
* @param response
|
||||
* @param streFileNm
|
||||
* @param orignFileNm
|
||||
* @param mimetype
|
||||
* @throws Exception
|
||||
*/
|
||||
public void downFile(HttpServletResponse response, String streFileNm, String orignFileNm, String mimetype) throws Exception {
|
||||
String downFileName = filePathBlackList(streFileNm);
|
||||
String orgFileName = orignFileNm;
|
||||
File file = new File(downFileName);
|
||||
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException(downFileName);
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
throw new FileNotFoundException(downFileName);
|
||||
}
|
||||
|
||||
int fSize = (int) file.length();
|
||||
if (fSize > 0) {
|
||||
// BufferedInputStream in = null;
|
||||
|
||||
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)) ) {
|
||||
// in = new BufferedInputStream(new FileInputStream(file));
|
||||
response.setContentType(mimetype);
|
||||
response.setHeader("Content-Disposition:", "attachment; filename=" + orgFileName);
|
||||
response.setContentLength(fSize);
|
||||
FileCopyUtils.copy(in, response.getOutputStream());
|
||||
|
||||
} finally {
|
||||
// ResourceCloseHelper.close(in);
|
||||
}
|
||||
// response.getOutputStream().flush();
|
||||
// response.getOutputStream().close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 서버 파일에 대하여 view를 처리한다.
|
||||
* @param response
|
||||
* @param serverSubPath
|
||||
* @param physicalName
|
||||
* @param orginalName
|
||||
* @param mimeTypeParam
|
||||
* @throws Exception
|
||||
*/
|
||||
public void viewFile(HttpServletResponse response,
|
||||
String serverSubPath,
|
||||
String physicalName,
|
||||
String orginalName,
|
||||
String mimeTypeParam) throws Exception {
|
||||
String mimeType = mimeTypeParam;
|
||||
String downFileName = serverSubPath + File.separator + physicalName;
|
||||
|
||||
log.debug("downFileName ========== {}", downFileName);
|
||||
|
||||
File file = new File(filePathBlackList(downFileName));
|
||||
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException(downFileName);
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
throw new FileNotFoundException(downFileName);
|
||||
}
|
||||
|
||||
byte[] b = new byte[8192];
|
||||
|
||||
if (mimeType == null) {
|
||||
mimeType = "application/octet-stream;";
|
||||
}
|
||||
|
||||
response.setContentType(removeCRLF(mimeType));
|
||||
response.setHeader("Content-Disposition", "filename="+orginalName+";");
|
||||
|
||||
// BufferedInputStream fin = null;
|
||||
// BufferedOutputStream outs = null;
|
||||
|
||||
try (
|
||||
BufferedInputStream fin = new BufferedInputStream(new FileInputStream(file));
|
||||
BufferedOutputStream outs = new BufferedOutputStream(response.getOutputStream());
|
||||
) {
|
||||
// fin = new BufferedInputStream(new FileInputStream(file));
|
||||
// outs = new BufferedOutputStream(response.getOutputStream());
|
||||
|
||||
int read = 0;
|
||||
|
||||
while ((read = fin.read(b)) != -1) {
|
||||
outs.write(b, 0, read);
|
||||
}
|
||||
|
||||
} finally {
|
||||
// ResourceCloseHelper.close(outs, fin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 업로드된 파일 파일시스템에 저장한다.
|
||||
* @param parseReulstList MultipartFile정보를 parsing한 결과 목록
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void transferFile(List<Map<String, Object>> parseReulstList) throws Exception {
|
||||
MultipartFile file;
|
||||
for(Map<String, Object> tempMap : parseReulstList) {
|
||||
file = (MultipartFile) tempMap.get("multipartFile");
|
||||
if(file != null && !StringUtil.isEmpty(StringUtil.nullConvert(tempMap.get("filePath")))) {
|
||||
Path fileDirectory = Paths.get((String) tempMap.get("filePath")).toAbsolutePath().normalize();
|
||||
file.transferTo(new File(filePathBlackList(StringUtil.nullConvert(fileDirectory+"."+tempMap.get("fileExt")))));
|
||||
//파일시스템 저장한 multipartFile은 parsing결과에서 삭제
|
||||
tempMap.remove("multipartFile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rename시 필요한 시간기반의 패턴정보 생성
|
||||
* @return String 시간기반의 패턴정보
|
||||
*/
|
||||
private static String getTimeStamp() {
|
||||
String rtnStr = null;
|
||||
// 문자열로 변환하기 위한 패턴 설정(연도-월-일 시:분:초:초(자정이후 초))
|
||||
String pattern = "ddhhmmssSSS"; //"yyyyMMddhhmmssSSS";
|
||||
SimpleDateFormat sdfCurrent = new SimpleDateFormat(pattern, Locale.KOREA);
|
||||
Timestamp ts = new Timestamp(System.currentTimeMillis());
|
||||
rtnStr = sdfCurrent.format(ts.getTime());
|
||||
return rtnStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 업로드된 파일을 저장할 경로에 허용되지 않은 문자열 치환
|
||||
* @param value 저장될 파일 경로 문자열
|
||||
* @return String 치환된 경로 문자열
|
||||
*/
|
||||
public static String filePathBlackList(String value) {
|
||||
String returnValue = value;
|
||||
if (returnValue == null || returnValue.trim().equals("")) {
|
||||
return "";
|
||||
}
|
||||
returnValue = returnValue.replaceAll("\\.\\.", "");
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public static String removeCRLF(String parameter) {
|
||||
return parameter.replaceAll("\r", "").replaceAll("\n", "");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 파일명, mimeType 검사
|
||||
* @param fileName 저장될 원본파일명
|
||||
* @return boolean 검사결과
|
||||
*/
|
||||
public static boolean isSanitizeFileName(MultipartFile file) {
|
||||
boolean isPermission = false;
|
||||
String orginFileName = file.getOriginalFilename();
|
||||
log.debug("isSanitizeFileName orginFileName ::: {}",orginFileName);
|
||||
|
||||
// 파일명 확인
|
||||
// 허용불가문자열 \ / : * ? " < > % |
|
||||
String regex = "[:\\\\/%*?:|\"<>]";
|
||||
if(Pattern.compile(regex).matcher(orginFileName).find()) {
|
||||
log.debug("isFileNameVaild orginFileName_error ::: {}",orginFileName);
|
||||
isPermission = false;
|
||||
}else {
|
||||
isPermission = true;
|
||||
}
|
||||
|
||||
// 허용된 MIME 타입 검사 (ck_editor는 이미지만 업로드 됨)
|
||||
try {
|
||||
if(isPermission) {
|
||||
String mimeType = new Tika().detect(file.getInputStream());
|
||||
if (mimeType.startsWith("image")) {
|
||||
isPermission = true;
|
||||
}else {
|
||||
isPermission = false;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new WnbtRestException("업로드 파일 검증 중 파일 입출력 오류 발생");
|
||||
}
|
||||
|
||||
return isPermission;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.wb.domainserver.util.file;
|
||||
|
||||
import com.wb.domainserver.exception.WnbtRestException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class RandomGenerator {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RandomGenerator.class);
|
||||
private static SecureRandom random = new SecureRandom();
|
||||
private static String englishLower = "abcdefghijklmnopqrstuvwxyz";
|
||||
private static String englishUpper = englishLower.toUpperCase();
|
||||
private static String number = "0123456789";
|
||||
private static String seed = englishLower + englishUpper + number;
|
||||
|
||||
private RandomGenerator() {
|
||||
try {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}catch(WnbtRestException wre) {
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch(Exception e) {
|
||||
logger.error("RandomGenerator 클래스는 생성자를 사용하여 초기화할 수 없습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
public static String genString(int length, String prefix) {
|
||||
try {
|
||||
if(length < 1) throw new IllegalArgumentException("Length must be a positive number.");
|
||||
} catch(WnbtRestException wre) {
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch(Exception e) {
|
||||
logger.error("파라미터 오류 ::: 길이는 최소한 0 보다 커야 합니다.");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
int prefixLength = prefix.length();
|
||||
for (int i = 0; i < length - prefixLength; i++) {
|
||||
sb.append( seed.charAt(random.nextInt(seed.length())));
|
||||
}
|
||||
return prefix + sb.toString();
|
||||
}
|
||||
|
||||
public static String genNumber(int length) {
|
||||
try {
|
||||
if(length < 1) throw new IllegalArgumentException("Length must be a positive number.");
|
||||
} catch(WnbtRestException wre) {
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch(Exception e) {
|
||||
logger.error("파라미터 오류 ::: 길이는 최소한 0 보다 커야 합니다.");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for(int i = 0;i<length; i++) {
|
||||
sb.append(number.charAt(random.nextInt(number.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package com.wb.domainserver.util.file.controller;
|
||||
|
||||
|
||||
import com.wb.domainserver.domain.gcone.common.service.BOCommonService;
|
||||
import com.wb.domainserver.domain.gcone.common.vo.BOCommonVO;
|
||||
import com.wb.domainserver.exception.WnbtRestException;
|
||||
import com.wb.domainserver.exception.code.ErrorCode;
|
||||
import com.wb.domainserver.response.WnbtWebClientResponseHandler;
|
||||
import com.wb.domainserver.security.authorization.annotation.AuthPolicy;
|
||||
import com.wb.domainserver.security.authorization.annotation.Policy;
|
||||
import com.wb.domainserver.util.communicate.SendToResrc;
|
||||
import com.wb.domainserver.util.file.FileMngUtil;
|
||||
import com.wb.domainserver.util.file.service.FileStorageService;
|
||||
import com.wb.domainserver.util.file.vo.FileStorageProperties;
|
||||
import com.wb.domainserver.util.string.StringUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
@RequestMapping("/mngr/file")
|
||||
public class FileController {
|
||||
|
||||
@Autowired
|
||||
WnbtWebClientResponseHandler restResponseHandler;
|
||||
|
||||
@Autowired
|
||||
private SendToResrc sendToResrc;
|
||||
|
||||
@Autowired
|
||||
private FileStorageService filestore;
|
||||
|
||||
@Autowired
|
||||
private FileStorageProperties fileStorageProperties;
|
||||
|
||||
@Autowired
|
||||
private FileMngUtil fileMngUtil;
|
||||
|
||||
@Autowired
|
||||
private BOCommonService boCommonService;
|
||||
|
||||
@Value("${sopmalfo.common.fileupload.cdnurl}")
|
||||
private String cdnUrl;
|
||||
|
||||
@Value("${sopmalfo.common.fileupload.uploaddirs.web}")
|
||||
private String uploadFilePath;
|
||||
|
||||
@Value("${sopmalfo.common.fileupload.extensions.images}")
|
||||
private String whiteListFileUploadExtensions;
|
||||
|
||||
//파일업로드는
|
||||
//filestore.fileUpload(request) 바로 실행함
|
||||
|
||||
// 파일 다운로드
|
||||
@ResponseBody
|
||||
@Policy(AuthPolicy.RESTRICTED)
|
||||
@RequestMapping("/fileDownload")
|
||||
public ResponseEntity<Resource> downloadFiles(HttpServletRequest request) {
|
||||
|
||||
String sopCd = request.getParameter("sopCd");
|
||||
String menuGb = request.getParameter("menuGb");
|
||||
String fileKey = request.getParameter("fileKey");
|
||||
|
||||
BOCommonVO vo = new BOCommonVO();
|
||||
vo.setShopCd(sopCd);
|
||||
vo.setMenuGb(menuGb);
|
||||
vo.setFileSeq(fileKey);
|
||||
|
||||
// 각 구분자별 이미지관련정보 삭제 및 경로조회
|
||||
Map<String, Object> message = new HashMap<>();
|
||||
message.put("fileInfo", boCommonService.selectImgPath(vo));
|
||||
|
||||
Map<String, Object> fileInfoMap = (Map<String, Object>) message.get("fileInfo");
|
||||
|
||||
if(fileInfoMap != null) {
|
||||
log.debug("fileFullPath :::: {}",fileInfoMap.get("fileFullPath"));
|
||||
}
|
||||
|
||||
//파일절대경로 조회
|
||||
Resource resource = filestore.loadFileAsResource(fileInfoMap);
|
||||
|
||||
String contentType = "application/octet-stream";
|
||||
String fileName = "";
|
||||
if(fileInfoMap != null) {
|
||||
fileName = (String)fileInfoMap.get("orginlFilNm");//orgFileId; //원본파일명
|
||||
}
|
||||
log.debug("orgFileId {} ",fileName);
|
||||
String headerValue = "";
|
||||
if(fileName != null) {
|
||||
headerValue = "attachment; filename=\"" + new String( fileName.getBytes(StandardCharsets.UTF_8),StandardCharsets.ISO_8859_1) + "\"";
|
||||
}
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, headerValue)
|
||||
.body(resource);
|
||||
}
|
||||
|
||||
// 파일 삭제
|
||||
@ResponseBody
|
||||
@Policy(AuthPolicy.RESTRICTED)
|
||||
// @PostMapping(path = "/deleteUploadedFile/{sopCd}/{menuGb}/{fileKey}/ajax")
|
||||
// public ResponseEntity<String> deleteUploadedFiles(@PathVariable String sopCd, @PathVariable String menuGb
|
||||
// , @PathVariable String fileKey, HttpServletRequest request) {
|
||||
@RequestMapping("/deleteUploadedFile")
|
||||
public ResponseEntity<String> deleteUploadedFiles(HttpServletRequest request) {
|
||||
|
||||
String sopCd = request.getParameter("sopCd");
|
||||
String menuGb = request.getParameter("menuGb");
|
||||
String fileKey = request.getParameter("fileKey");
|
||||
|
||||
log.debug(" [파일 삭제] FileVo sopCd : {}",sopCd + " :menuGb: " + menuGb + " :fileKey: " + fileKey);
|
||||
|
||||
//게시글첨부파일고유번호, 쇼핑몰코드 - DB조회로 경로 알아옴.
|
||||
BOCommonVO vo = new BOCommonVO();
|
||||
vo.setShopCd(sopCd);
|
||||
vo.setMenuGb(menuGb);
|
||||
vo.setFileSeq(fileKey);
|
||||
|
||||
// 각 구분자별 이미지관련정보 삭제 및 경로조회
|
||||
Map<String, Object> message = new HashMap<>();
|
||||
message = boCommonService.deleteFileProcess(vo);
|
||||
|
||||
String result = (String)message.get("result");
|
||||
|
||||
log.debug("파일삭제 return::::::::{}",result);
|
||||
|
||||
return ResponseEntity.ok().body(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CK에디터로 업로드된 이미지 파일 처리
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@Policy(AuthPolicy.PUBLIC)
|
||||
@RequestMapping(value = "/ckeditorFileUpload", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity<?> fileUpload(HttpServletRequest request) {
|
||||
Map<String, List<Map<String, Object>>> ulpladFileMap = new HashMap<>();
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
MultipartHttpServletRequest mptRequest = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
|
||||
String shopCd = request.getParameter("shopCd");
|
||||
String subFolder = "";
|
||||
|
||||
if (mptRequest != null) {
|
||||
//저장경로 생성 : /data/gcone/webFile/shop_cd/editor/YYYYMM
|
||||
subFolder = shopCd+"/editor"+fileStorageProperties.getDateDir("yyyyMM", false);
|
||||
|
||||
MultiValueMap<String, MultipartFile> files = mptRequest.getMultiFileMap();
|
||||
Iterator<String> fInputs = files.keySet().iterator();
|
||||
while (fInputs.hasNext()) {
|
||||
String key = fInputs.next();
|
||||
try {
|
||||
ulpladFileMap.put(key, fileMngUtil.parseFileInf(files.get(key), shopCd, uploadFilePath+"/"+subFolder , whiteListFileUploadExtensions));
|
||||
} catch (WnbtRestException wre){
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch (Exception e) {
|
||||
throw new WnbtRestException(ErrorCode.BAD_REQUEST_ERROR,"파일 업로드에 실패했습니다."+e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if(ulpladFileMap.get("upload") != null && !ulpladFileMap.get("upload").isEmpty()) {
|
||||
resultMap.put("uploaded", true);
|
||||
//resultMap.put("url", "/file/ckeditor/image/fileView?item01="+subFolder+"/"+ulpladFileMap.get("upload").get(0).get("streFileNm")+"."+ulpladFileMap.get("upload").get(0).get("fileExt"));
|
||||
//resultMap.put("url", "/file/ckeditorFileView?item01="+subFolder+"/"+ulpladFileMap.get("upload").get(0).get("streFileNm")+"."+ulpladFileMap.get("upload").get(0).get("fileExt"));
|
||||
resultMap.put("url", cdnUrl+"/"+subFolder+"/"+ulpladFileMap.get("upload").get(0).get("streFileNm")+"."+ulpladFileMap.get("upload").get(0).get("fileExt"));
|
||||
} else {
|
||||
resultMap.put("uploaded", false);
|
||||
resultMap.put("url", "");
|
||||
}
|
||||
|
||||
log.debug("ckeditor - fileUpload ==========={}",resultMap.get("url"));
|
||||
|
||||
return ResponseEntity.status(HttpStatus.OK).body(resultMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* CK에디터로 업로드된 이미지 view 처리
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
@Policy(AuthPolicy.PUBLIC)
|
||||
@RequestMapping("/ckeditorFileView")
|
||||
public void fileUpload(HttpServletRequest request, HttpServletResponse response, String uploadFilePath1) {
|
||||
String item01 = request.getParameter("item01");
|
||||
if(uploadFilePath1 == null) uploadFilePath1 = uploadFilePath;
|
||||
try {
|
||||
if(!StringUtil.isEmpty(item01)) {
|
||||
|
||||
//response, 서버경로중 고정경로, 변형경로+시스템파일명, orginalName, mimeTypeParam
|
||||
fileMngUtil.viewFile(response, uploadFilePath1, item01, "", null);
|
||||
}
|
||||
} catch (WnbtRestException wre){
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch(Exception e) {
|
||||
throw new WnbtRestException("에디터 업로드 이미지 조회 중 오류가 발생하였습니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
package com.wb.domainserver.util.file.service;//package com.wb.domainserver.util.file.service;
|
||||
//
|
||||
//import java.io.BufferedInputStream;
|
||||
//import java.io.BufferedOutputStream;
|
||||
//import java.io.File;
|
||||
//import java.io.FileInputStream;
|
||||
//import java.io.FileOutputStream;
|
||||
//import java.io.UnsupportedEncodingException;
|
||||
//import java.lang.reflect.Field;
|
||||
//import java.text.SimpleDateFormat;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Date;
|
||||
//import java.util.List;
|
||||
//import java.util.Locale;
|
||||
//import java.util.Map;
|
||||
//import java.util.zip.ZipEntry;
|
||||
//import java.util.zip.ZipOutputStream;
|
||||
//
|
||||
//import javax.servlet.ServletOutputStream;
|
||||
//import javax.servlet.http.HttpServletRequest;
|
||||
//import javax.servlet.http.HttpServletResponse;
|
||||
//
|
||||
//import org.apache.poi.ss.usermodel.Cell;
|
||||
//import org.apache.poi.ss.usermodel.CellStyle;
|
||||
//import org.apache.poi.ss.usermodel.Row;
|
||||
//import org.apache.poi.ss.usermodel.Sheet;
|
||||
//import org.apache.poi.ss.usermodel.Workbook;
|
||||
//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
//import org.celebpay.exception.CelebpayException;
|
||||
//import org.celebpay.model.common.file.ExcelFile;
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import org.springframework.util.StringUtils;
|
||||
//import org.springframework.web.servlet.view.document.AbstractXlsxView;
|
||||
//
|
||||
//public class ExcelDownloadViewSvc extends AbstractXlsxView {
|
||||
// private static final Logger logger = LoggerFactory.getLogger(ExcelDownloadViewSvc.class);
|
||||
// private static final String local_path = "D:/temp/";
|
||||
// private static final String server_path = "/temp/";
|
||||
//
|
||||
// @Override
|
||||
// protected void buildExcelDocument(Map modelMap, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
// List listSet = (List)modelMap.get("listSet");
|
||||
// List listExcel = (List) modelMap.get("list");
|
||||
// List<String> header = (List) modelMap.get("header");
|
||||
// List fileName = (List) modelMap.get("fileName");
|
||||
//
|
||||
// String excelName = "";
|
||||
//
|
||||
// if(listSet == null) {
|
||||
// String sCurTime = null;
|
||||
// sCurTime = new SimpleDateFormat("yyyyMMdd", Locale.KOREA).format(new Date());
|
||||
// excelName = sCurTime + "_" + (StringUtils.isEmpty(fileName) ? "엑셀파일" : fileName) + ".xlsx";
|
||||
//
|
||||
// Sheet worksheet = null;
|
||||
// Row row = null;
|
||||
// Cell cell = null;
|
||||
//
|
||||
// CellStyle style = workbook.createCellStyle(); // 셀 스타일을 위한 변수
|
||||
// style.setVerticalAlignment(CellStyle.VERTICAL_TOP); // 글 위치를 상단으로 설정
|
||||
// style.setAlignment(CellStyle.ALIGN_CENTER); // 글 위치를 중앙으로 설정
|
||||
// style.setWrapText(true);
|
||||
//
|
||||
// //새로운 Sheet를 생성
|
||||
// worksheet = workbook.createSheet("sheet1");
|
||||
//
|
||||
// //타이틀 ROW 생성
|
||||
// row = worksheet.createRow(0);
|
||||
// for(int i=0; i<header.size(); i++) {
|
||||
// cell = row.createCell(i);
|
||||
// cell.setCellValue(header.get(i));
|
||||
// cell.setCellStyle(style);
|
||||
// }
|
||||
//
|
||||
// for(int i=0; i<listExcel.size(); i++) {
|
||||
// row = worksheet.createRow(i+1);
|
||||
// ExcelFile colSet = (ExcelFile)listExcel.get(i);
|
||||
// for(int j=0; j<header.size(); j++) {
|
||||
// cell = row.createCell(j);
|
||||
//
|
||||
// Field field = colSet.getClass().getDeclaredField("col"+j);
|
||||
// field.setAccessible(true);
|
||||
// String v = (String)field.get(colSet);
|
||||
//
|
||||
// cell.setCellValue(v);
|
||||
// cell.setCellStyle(style);
|
||||
// // worksheet.autoSizeColumn(j);
|
||||
// worksheet.setColumnWidth(j, StringUtils.isEmpty(header.get(j)) ? 1200 : header.get(j).length() * 1200);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// response.setHeader("Content-Disposition", "attachement; filename=\""+java.net.URLEncoder.encode(excelName, "UTF-8")+"\";charset=\"UTF-8\"");
|
||||
// }catch(UnsupportedEncodingException e) {
|
||||
// throw new CelebpayException("엑셀 다운로드 도중 인코딩 오류 발생"+e);
|
||||
// }
|
||||
//
|
||||
// }else {
|
||||
// List<File> fileSet = new ArrayList<>();
|
||||
//
|
||||
// String path = "";
|
||||
// if(request.getRequestURL().indexOf("http://localhost:8090") > -1) {
|
||||
// path = local_path + new SimpleDateFormat("yyyyMMddHHmmss", Locale.KOREA).format(new Date()) + "/";
|
||||
// }else {
|
||||
// path = server_path + new SimpleDateFormat("yyyyMMddHHmmss", Locale.KOREA).format(new Date()) + "/";
|
||||
// }
|
||||
//
|
||||
// File Folder = new File(path);
|
||||
//
|
||||
// if(!Folder.exists()) {
|
||||
// Folder.setExecutable(false, true);
|
||||
// Folder.setReadable(true);
|
||||
// Folder.setWritable(false, true);
|
||||
// try {
|
||||
// Folder.mkdirs();
|
||||
// }catch(Exception e) {
|
||||
// throw new CelebpayException("엑셀 파일 압축을 위한 임시 폴더 생성 중 오류"+e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for(int idx=0; idx<listSet.size(); idx++) {
|
||||
// listExcel = (List)listSet.get(idx);
|
||||
//
|
||||
// String sCurTime = null;
|
||||
// sCurTime = new SimpleDateFormat("yyyyMMdd", Locale.KOREA).format(new Date());
|
||||
// excelName = sCurTime + "_엑셀다운로드"+idx+".xlsx";
|
||||
// Workbook book = new XSSFWorkbook();
|
||||
// Sheet worksheet = null;
|
||||
// Row row = null;
|
||||
// Cell cell = null;
|
||||
//
|
||||
// CellStyle style = book.createCellStyle(); // 셀 스타일을 위한 변수
|
||||
// style.setVerticalAlignment(CellStyle.VERTICAL_TOP); // 글 위치를 상단으로 설정
|
||||
// style.setAlignment(CellStyle.ALIGN_CENTER); // 글 위치를 중앙으로 설정
|
||||
// style.setWrapText(true);
|
||||
//
|
||||
// //새로운 Sheet를 생성
|
||||
// worksheet = book.createSheet("sheet1");
|
||||
//
|
||||
// //타이틀 ROW 생성
|
||||
// row = worksheet.createRow(0);
|
||||
// for(int i=0; i<header.size(); i++) {
|
||||
// cell = row.createCell(i);
|
||||
// cell.setCellValue(header.get(i));
|
||||
// cell.setCellStyle(style);
|
||||
// }
|
||||
//
|
||||
// for(int i=0; i<listExcel.size(); i++) {
|
||||
// row = worksheet.createRow(i+1);
|
||||
// ExcelFile colSet = (ExcelFile)listExcel.get(i);
|
||||
// for(int j=0; j<header.size(); j++) {
|
||||
// cell = row.createCell(j);
|
||||
//
|
||||
// Field field = colSet.getClass().getDeclaredField("col"+j);
|
||||
// field.setAccessible(true);
|
||||
// String v = (String)field.get(colSet);
|
||||
//
|
||||
// cell.setCellValue(v);
|
||||
// cell.setCellStyle(style);
|
||||
// // worksheet.autoSizeColumn(j);
|
||||
// worksheet.setColumnWidth(j, StringUtils.isEmpty(header.get(j)) ? 1200 : header.get(j).length() * 1200);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// File file = new File(path + excelName);
|
||||
// FileOutputStream fos = null;
|
||||
// fos = new FileOutputStream(file);
|
||||
// book.write(fos);
|
||||
// fileSet.add(file);
|
||||
//
|
||||
// if(book != null)book.close();
|
||||
// }
|
||||
// compressZip(fileSet, path, response);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void compressZip(List<File> fileSet, String path, HttpServletResponse response) {
|
||||
// ZipOutputStream zout = null;
|
||||
// String zipName = "엑셀파일.zip";
|
||||
// String tempPath = "";
|
||||
//
|
||||
// if(fileSet.size()>0) {
|
||||
// try {
|
||||
// tempPath = path;
|
||||
//
|
||||
// zout = new ZipOutputStream(new FileOutputStream(tempPath + zipName));
|
||||
// byte[] buffer = new byte[1024];
|
||||
// FileInputStream in = null;
|
||||
//
|
||||
// try {
|
||||
// for(int k=0; k<fileSet.size(); k++) {
|
||||
// in= new FileInputStream(fileSet.get(k));
|
||||
// zout.putNextEntry(new ZipEntry(fileSet.get(k).getName()));
|
||||
// int len;
|
||||
// while((len=in.read(buffer))>0) {
|
||||
// zout.write(buffer, 0, len);
|
||||
// }
|
||||
//
|
||||
// zout.closeEntry();
|
||||
// }
|
||||
// }catch(Exception e) {
|
||||
// throw new CelebpayException("엑셀 파일 압축 도중 오류 발생"+e);
|
||||
// }finally {
|
||||
// in.close();
|
||||
// }
|
||||
//
|
||||
// zout.close();
|
||||
//
|
||||
// response.setContentType("application/zip");
|
||||
// response.addHeader("Content-Disposition", "attachement; filename=\""+java.net.URLEncoder.encode(zipName, "UTF-8")+"\";charset=\"UTF-8\"");
|
||||
//
|
||||
// FileInputStream fis = new FileInputStream(tempPath+zipName);
|
||||
// BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
// ServletOutputStream so = response.getOutputStream();
|
||||
// BufferedOutputStream bos = new BufferedOutputStream(so);
|
||||
//
|
||||
// try {
|
||||
// int n = 0;
|
||||
// while((n=bis.read(buffer))>0) {
|
||||
// bos.write(buffer, 0, n);
|
||||
// bos.flush();
|
||||
// }
|
||||
// }catch(Exception e) {
|
||||
// throw new CelebpayException("엑셀 파일 압축 도중 오류 발생"+e);
|
||||
// }finally {
|
||||
// if(bos != null) bos.close();
|
||||
// if(bis != null) bis.close();
|
||||
// if(so != null) so.close();
|
||||
// if(fis != null) fis.close();
|
||||
// }
|
||||
//
|
||||
// }catch(Exception e) {
|
||||
// throw new CelebpayException("엑셀 파일 압축 도중 오류 발생"+e);
|
||||
// }finally {
|
||||
// if(zout != null) {
|
||||
// zout = null;
|
||||
// }
|
||||
//
|
||||
// deleteTempFolder(path);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void deleteTempFolder(String path) {
|
||||
// File folder = new File(path);
|
||||
//
|
||||
// try {
|
||||
// while(folder.exists()) {
|
||||
// File[] folder_list = folder.listFiles();
|
||||
// for(File f: folder_list) {
|
||||
// f.delete();
|
||||
// }
|
||||
// if(folder_list.length == 0 && folder.isDirectory()) {
|
||||
// folder.delete();
|
||||
// }
|
||||
// }
|
||||
// }catch(Exception e) {
|
||||
// throw new CelebpayException("임시 디렉토리 삭제 중 오류 발생"+e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,718 @@
|
||||
package com.wb.domainserver.util.file.service;
|
||||
|
||||
import com.wb.domainserver.exception.FileStorageException;
|
||||
import com.wb.domainserver.exception.WnbtRestException;
|
||||
import com.wb.domainserver.util.file.RandomGenerator;
|
||||
import com.wb.domainserver.util.file.vo.FileStorageProperties;
|
||||
import com.wb.domainserver.util.file.vo.FileVo;
|
||||
import com.wb.domainserver.util.file.vo.UploadFile;
|
||||
import com.wb.domainserver.util.string.StringUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.tika.Tika;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class FileStorageService {
|
||||
|
||||
private final Path docFileStorageLocation;
|
||||
private final Path imgFileStorageLocation;
|
||||
private final Path pharFileStorageLocation;
|
||||
private final Path rtrnFileStorageLocation;
|
||||
|
||||
@Autowired
|
||||
private FileStorageProperties fileStorageProperties;
|
||||
|
||||
@Value("${sopmalfo.common.fileupload.extensions.images}")
|
||||
private String whiteListFileUploadExtensions;
|
||||
|
||||
@Autowired
|
||||
public FileStorageService(FileStorageProperties fileStorageProperties) {
|
||||
this.docFileStorageLocation = Paths.get(fileStorageProperties.getDocUploadDir()).toAbsolutePath().normalize();
|
||||
this.imgFileStorageLocation = Paths.get(fileStorageProperties.getImgUploadDir()).toAbsolutePath().normalize();
|
||||
this.pharFileStorageLocation = Paths.get(fileStorageProperties.getPharUploadDir()).toAbsolutePath().normalize();
|
||||
this.rtrnFileStorageLocation = Paths.get(fileStorageProperties.getRtrnUploadDir()).toAbsolutePath().normalize();
|
||||
}
|
||||
|
||||
public Path getDocFileStorageLocation() {
|
||||
return this.docFileStorageLocation;
|
||||
}
|
||||
public Path getImgFileStorageLocation() {
|
||||
return this.imgFileStorageLocation;
|
||||
}
|
||||
public Path getPharFileStorageLocation() { return this.pharFileStorageLocation; }
|
||||
public Path getRtrnFileStorageLocation() { return this.rtrnFileStorageLocation; }
|
||||
|
||||
|
||||
/**
|
||||
* 파일 업로드 서비스
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public List<HashMap<String, Object>> fileUpload(HttpServletRequest request) {
|
||||
log.debug("====FileStorageService fileUpload");
|
||||
List<HashMap<String, Object>> ulpladFileMap = new ArrayList<HashMap<String, Object>>();
|
||||
|
||||
MultipartHttpServletRequest mptRequest = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
|
||||
|
||||
//구분자 받아와야 함. 이 구분자로 파일저장 경로가 지정됨.
|
||||
String shopCd = (String)request.getAttribute("shopCd");
|
||||
String pathGubun = (String)request.getAttribute("pathGubun");
|
||||
String subPathId = (String)request.getAttribute("subPathId");
|
||||
String validExp = (String)request.getAttribute("validExp");
|
||||
subPathId = (subPathId == null || subPathId.equals(""))? "" : "/"+subPathId;
|
||||
|
||||
if (mptRequest != null && mptRequest.getFiles("files").size()>0) {
|
||||
|
||||
List<MultipartFile> fileList = mptRequest.getFiles("files");
|
||||
log.debug("====fileList:{}",fileList);
|
||||
|
||||
MultipartFile[] filesparam = fileList.toArray(new MultipartFile[0]);
|
||||
UploadFile params = new UploadFile();
|
||||
|
||||
params.setShopCd(shopCd);
|
||||
params.setPathGubun(pathGubun);
|
||||
params.setSubPathId(subPathId);
|
||||
params.setValidExp(validExp);
|
||||
|
||||
//파일저장 메소드 호출
|
||||
ulpladFileMap = getFilesUpload(params,filesparam);
|
||||
}
|
||||
return ulpladFileMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 파일 저장처리 (퍼미션확인, 경로생성, 저장)
|
||||
* @param params
|
||||
* @param files
|
||||
* @return
|
||||
*/
|
||||
public List<HashMap<String, Object>> getFilesUpload(UploadFile params,MultipartFile[] files) {
|
||||
|
||||
List<HashMap<String, Object>> fileStoreResult = new ArrayList<HashMap<String, Object>>();
|
||||
|
||||
try {
|
||||
log.debug("files ::파일객체 퍼미션 확인: "+files);
|
||||
List<MultipartFile> allowedFiles = new ArrayList<>();
|
||||
log.debug("files ::파일객체 퍼미션 확인: "+params);
|
||||
//파일확장자 검증 - 파일명, 마임타입, 확장자 검증 : 게시판일반첨부파일 - 나머지 첨부파일(이미지)
|
||||
String validExp = params.getValidExp();
|
||||
if(params.getPathGubun().equals("BDFL")) {
|
||||
allowedFiles = Arrays.asList(files)
|
||||
.stream()
|
||||
.filter(t->isPermissionFileMimeType(t,validExp))
|
||||
.collect(Collectors.toList());
|
||||
}else {
|
||||
if(StringUtil.isEmpty(validExp)){
|
||||
allowedFiles = Arrays.asList(files)
|
||||
.stream()
|
||||
.filter(t->isPermissionImgMimeType(t))
|
||||
.collect(Collectors.toList());
|
||||
}else{
|
||||
allowedFiles = Arrays.asList(files)
|
||||
.stream()
|
||||
.filter(t->isPermissionFileMimeType(t,validExp))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("files ::파일경로 생성: "+allowedFiles);
|
||||
if(!allowedFiles.isEmpty()) {
|
||||
|
||||
log.debug("allowedFiles if : "+allowedFiles);
|
||||
|
||||
String uploadFilePath = getUploadFilePath(params,"yyyyMM",false); //코드에 따라 저장경로를 생성함.
|
||||
log.debug("getFilesUpload - UPLOADFILEPATH ::파일저장: "+uploadFilePath);
|
||||
|
||||
fileStoreResult = Arrays.asList(files)
|
||||
.stream()
|
||||
.map(file -> fileProcess(uploadFilePath, params, file))
|
||||
.collect(Collectors.toList());
|
||||
log.debug("getFilesUpload - FILESTORERESULT ::파일저장완료: "+fileStoreResult);
|
||||
|
||||
/* 파일데이터저장은 BO 단에서 처리 */
|
||||
}else {
|
||||
|
||||
log.debug("allowedFiles else : ");
|
||||
throw new WnbtRestException ("허용되지 않은 파일입니다.");
|
||||
}
|
||||
}catch (WnbtRestException wre){
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch (Exception e) {
|
||||
throw new WnbtRestException("파일 업로드시 오류 발생 ["+e.getMessage()+"]");
|
||||
}
|
||||
|
||||
return fileStoreResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 파일에 대하여 서버저장을 하고 정보를 처리한다. (파일저장, download_url, content_type, file_size 정보셋팅)
|
||||
* @param filePath 파일저장경로
|
||||
* @param file MultipartFile
|
||||
*/
|
||||
public HashMap<String, Object> fileProcess(String filePath, UploadFile params, MultipartFile file){
|
||||
HashMap<String, Object> param = new HashMap<>();
|
||||
param.put("domainPath", filePath);
|
||||
param.put("shopCd", params.getShopCd());
|
||||
log.debug("fileProcess - String.DOMAINPATH ::: "+filePath);
|
||||
|
||||
//파일저장
|
||||
HashMap<String, Object> fileMap = storeFile(file, param);
|
||||
|
||||
//파일 다운로드 url 생성 - 실제 큰 의미없는.....
|
||||
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
|
||||
.path("/bo/file")
|
||||
.path("/download/")
|
||||
.path((String)fileMap.get("fileId"))
|
||||
.toUriString();
|
||||
|
||||
fileMap.put("fileDownloadUri", fileDownloadUri);
|
||||
fileMap.put("fileContentType", file.getContentType());
|
||||
fileMap.put("fileSize", file.getSize());
|
||||
|
||||
return fileMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 파일 서버 저장
|
||||
* @param file MultipartFile
|
||||
* @param param 기타정보들
|
||||
*/
|
||||
public HashMap<String, Object> storeFile(MultipartFile file, HashMap<String, Object> param) {
|
||||
String domainPath = (String)param.get("domainPath");
|
||||
String prefix = (String)param.get("shopCd");
|
||||
int thumbnailWidth = 500;
|
||||
int thumbnailHeight = 500;
|
||||
if(param.get("thumbnailWidth") != null && param.get("thumbnailHeight") != null) {
|
||||
thumbnailWidth = (Integer)param.get("thumbnailWidth");
|
||||
thumbnailHeight = (Integer)param.get("thumbnailHeight");
|
||||
}
|
||||
|
||||
String originalFileName = StringUtils.cleanPath(file.getOriginalFilename()); //원본명
|
||||
String ext = FilenameUtils.getExtension(file.getOriginalFilename()); //확장자
|
||||
log.debug("storeFile - FILE_NAME ::: " + originalFileName);
|
||||
log.debug("storeFile - FILE_EXT ::: " + ext);
|
||||
|
||||
try {
|
||||
if(originalFileName.contains("..")) {
|
||||
throw new WnbtRestException("허용되지 않은 파일입니다. "+ originalFileName);
|
||||
}
|
||||
|
||||
String storeGubun = "";
|
||||
String fileId = "";
|
||||
Path targetLocation = null;
|
||||
if(!"".equals(domainPath) && domainPath !=null) {
|
||||
if(domainPath.indexOf("/goods/") > 0) {
|
||||
storeGubun = "GDIG";
|
||||
}
|
||||
}else {
|
||||
throw new WnbtRestException("파일 업로드 경로가 존재하지 않습니다.");
|
||||
}
|
||||
|
||||
//물리적 파일명 생성 : prefix(shopCd) + ddhhmmssSSS + 영문대소숫자 (20자)
|
||||
fileId = RandomGenerator.genString(20, prefix+getTimeStamp())+'.'+ext;
|
||||
log.debug("storeFile - 물리파일명 ::: " + fileId);
|
||||
|
||||
Path fileDirectory = Paths.get(domainPath).toAbsolutePath().normalize(); //저장경로를 파일시스템의 루트부터 시작하는 절대경로롤 바꿈.
|
||||
log.debug("storeFile - fileDirectory ::: " + fileDirectory);
|
||||
|
||||
Files.createDirectories(fileDirectory); //디렉토리 생성
|
||||
targetLocation = fileDirectory.resolve(fileId); //경로결합 - 절대경로/물리적파일명
|
||||
log.debug("PATH.TARGET_LOCATION ::: " + targetLocation);
|
||||
|
||||
FileVo thumbnail = new FileVo();
|
||||
FileVo listimg = new FileVo();
|
||||
if(storeGubun.equals("GDIG")) { //상품일 경우
|
||||
//1. 사이즈 줄임 500*500
|
||||
storeResize(file, fileId, targetLocation, thumbnailWidth, thumbnailHeight);
|
||||
//2. 리스트이미지 만들기 300*300
|
||||
listimg = storeThumbnail(file, fileId, "_list", domainPath, 300, 300);
|
||||
//3. 썸네일 만들기 100*100
|
||||
thumbnail = storeThumbnail(file, fileId, "_thumb", domainPath, 100, 100);
|
||||
}else {
|
||||
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("fileName", originalFileName);
|
||||
map.put("fileExt", ext);
|
||||
map.put("fileId", fileId);
|
||||
map.put("listImg", listimg);
|
||||
map.put("thumbNail", thumbnail);
|
||||
|
||||
//파일경로를 쇼핑몰코드부터 DB에 저장하기로 함.
|
||||
String docRoot = docFileStorageLocation.toString(); //일반첨부파일들
|
||||
String webRoot = imgFileStorageLocation.toString(); //웹서버첨부파일 (이미지등)
|
||||
domainPath = fileDirectory.toString().replace(docRoot, "").replace(webRoot, "");
|
||||
map.put("filePath", domainPath);
|
||||
log.debug("[쇼핑몰코드형이후 domainPath] :::{}",domainPath);
|
||||
|
||||
return map;
|
||||
|
||||
}catch(IOException ex) {
|
||||
throw new WnbtRestException(originalFileName+" 파일 저장 중 오류가 발생하였습니다. ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 이미지 크기 변경
|
||||
*/
|
||||
public void storeResize(MultipartFile file, String fileId, Path targetLocation, int imgWidth, int imgHeight) {
|
||||
try(ByteArrayOutputStream os = new ByteArrayOutputStream();) {
|
||||
log.debug("TARGET_LOCATION ::: " + targetLocation);
|
||||
try {
|
||||
BufferedImage image = null;
|
||||
if(file.getInputStream() != null) {
|
||||
image = ImageIO.read(file.getInputStream());
|
||||
}
|
||||
|
||||
int destWidth = 0, destHeight = 0;
|
||||
int posX = 0, posY = 0;
|
||||
|
||||
destWidth = imgWidth;
|
||||
destHeight = imgHeight;
|
||||
|
||||
Image thumbnail = null;
|
||||
if(image != null) {
|
||||
thumbnail = image.getScaledInstance(destWidth, destHeight, Image.SCALE_SMOOTH);
|
||||
}
|
||||
BufferedImage convertImage = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_INT_RGB);
|
||||
convertImage.getGraphics().drawImage(thumbnail, posX, posY, null);
|
||||
|
||||
String ext = FilenameUtils.getExtension(file.getOriginalFilename());
|
||||
ImageIO.write(convertImage, ext, os);
|
||||
|
||||
}catch (WnbtRestException wre){
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch(Exception e) {
|
||||
throw new WnbtRestException("이미지 크기 변경 중 오류가 발생하였습니다.");
|
||||
// e.getMessage();
|
||||
// e.printStackTrace();
|
||||
}
|
||||
|
||||
try(InputStream is = new ByteArrayInputStream(os.toByteArray());){
|
||||
Files.copy(is, targetLocation, StandardCopyOption.REPLACE_EXISTING);
|
||||
}catch(IOException e) {
|
||||
throw new WnbtRestException("파일 리사이즈 저장 중 오류가 발생하였습니다.");
|
||||
}
|
||||
|
||||
}catch(IOException ex) {
|
||||
throw new WnbtRestException("파일 리사이즈 저장 중 오류가 발생하였습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 썸네일이미지 저장
|
||||
*/
|
||||
public FileVo storeThumbnail(MultipartFile file, String fileId, String addFileId, String domainPath, int thumbnailWidth, int thumbnailHeight) {
|
||||
|
||||
FileVo thumbnail_file = new FileVo();
|
||||
String ext = FilenameUtils.getExtension(file.getOriginalFilename());
|
||||
String thumbAddId = "_thumb";
|
||||
if(addFileId != null && !addFileId.equals("")) thumbAddId = addFileId;
|
||||
String thumbNailId = fileId.substring(0, fileId.indexOf("."))+thumbAddId+"."+ext;
|
||||
|
||||
try(ByteArrayOutputStream os = new ByteArrayOutputStream();) {
|
||||
Path targetLocation = null;
|
||||
if("".equals(domainPath)) {
|
||||
throw new FileStorageException("파일 업로드 경로가 존재하지 않습니다.");
|
||||
}else {
|
||||
Path fileDirectory = Paths.get(domainPath).toAbsolutePath().normalize();
|
||||
Files.createDirectories(fileDirectory);
|
||||
targetLocation = fileDirectory.resolve(thumbNailId);
|
||||
}
|
||||
|
||||
log.debug("TARGET_LOCATION ::: " + targetLocation);
|
||||
|
||||
try {
|
||||
BufferedImage image = null;
|
||||
if(file.getInputStream() != null) {
|
||||
image = ImageIO.read(file.getInputStream());
|
||||
}
|
||||
|
||||
int destWidth = 0, destHeight = 0;
|
||||
int posX = 0, posY = 0;
|
||||
double ratio = 0.0;
|
||||
|
||||
destWidth = thumbnailWidth;
|
||||
destHeight = thumbnailHeight;
|
||||
|
||||
Image thumbnail = null;
|
||||
if(image != null) {
|
||||
thumbnail = image.getScaledInstance(destWidth, destHeight, Image.SCALE_SMOOTH);
|
||||
}
|
||||
BufferedImage convertImage = new BufferedImage(thumbnailWidth, thumbnailHeight, BufferedImage.TYPE_INT_RGB);
|
||||
convertImage.getGraphics().drawImage(thumbnail, posX, posY, null);
|
||||
|
||||
ImageIO.write(convertImage, ext, os);
|
||||
}catch (WnbtRestException wre){
|
||||
throw new WnbtRestException(wre.getMessage());
|
||||
} catch(Exception e) {
|
||||
throw new WnbtRestException("썸네일 파일 저장 중 오류가 발생하였습니다.");
|
||||
}
|
||||
|
||||
try(InputStream is = new ByteArrayInputStream(os.toByteArray());){
|
||||
Files.copy(is, targetLocation, StandardCopyOption.REPLACE_EXISTING);
|
||||
thumbnail_file.setFilePath(domainPath);
|
||||
thumbnail_file.setFileName(thumbNailId);
|
||||
thumbnail_file.setDocName(thumbNailId);
|
||||
thumbnail_file.setFileExt(ext);
|
||||
thumbnail_file.setFileType("21");
|
||||
thumbnail_file.setFileSize(Integer.toString(os.size()));
|
||||
}catch(IOException e) {
|
||||
throw new WnbtRestException("썸네일 파일 저장 중 오류가 발생하였습니다.");
|
||||
}
|
||||
|
||||
}catch(IOException ex) {
|
||||
throw new WnbtRestException("썸네일 파일 저장 중 오류가 발생하였습니다.");
|
||||
}
|
||||
log.debug("thumbnail_file ::: filePath ::: "+thumbnail_file.getFilePath());
|
||||
log.debug("thumbnail_file ::: fileName ::: "+thumbnail_file.getFileName());
|
||||
|
||||
return thumbnail_file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* combineFilePath 에 지정된 경로에 저장이 됨
|
||||
* @param lnkMasterId 저장위치 구분자
|
||||
* @param subPath1 구분자에 따른 하위폴더명
|
||||
* @return 저장경로
|
||||
*/
|
||||
public String getUploadFilePath(UploadFile param) {
|
||||
return combineFilePath(param);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* combineFilePath에 지정된 경로에 아래에 날짜폴더 만들어서 저장이 됨
|
||||
* @param lnkMasterId 저장위치 구분자
|
||||
* @param subPath1 구분자에 따른 내 하위폴더명
|
||||
* @param dateDirPattern 날짜폴더생성 패턴 (yyyy / yyyyMM / yyyyMMdd)
|
||||
* @param dateDirSeperate 날짜폴더생성시 년/월/일 형태의 구분 여부
|
||||
* @return 저장경로
|
||||
*/
|
||||
public String getUploadFilePath(UploadFile param, String dateDirPattern, boolean dateDirSeperate) {
|
||||
String path = combineFilePath(param);
|
||||
|
||||
if(!"".equals(dateDirPattern) && dateDirPattern != null) {
|
||||
path = path + fileStorageProperties.getDateDir(dateDirPattern, dateDirSeperate);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 구분자에 따라 저장 경로를 설정한다.
|
||||
* @param lnkMasterId 구분자
|
||||
* @param subPath1 구분자에 따른 내 하위폴더명
|
||||
* @return
|
||||
*/
|
||||
private String combineFilePath(UploadFile param) {
|
||||
String docRoot = docFileStorageLocation.toString(); //일반첨부파일들
|
||||
String webRoot = imgFileStorageLocation.toString(); //웹서버첨부파일 (이미지등)
|
||||
String pharRoot = pharFileStorageLocation.toString(); //약국첨부파일들 (사업자등록증, 약사면허증, 계약서)
|
||||
String rtrnRoot = rtrnFileStorageLocation.toString(); //반품이미지
|
||||
String path = "";
|
||||
|
||||
/* 경로규칙
|
||||
* 게시판 일반(BDFL): /docRoot/data/shop_cd/board/board_id/YYYYMM
|
||||
* 게시판 이미지(BDIG): /webRoot/data/shop_cd/board/board_id/YYYYMM
|
||||
* 상품 이미지(GDIG): /webRoot/data/shop_cd/goods/YYYYMM/ 기본파일명, 기본파일명_list(리스트파일), 기본파일명_view(썸네일파일) - 3가지 사이즈로 저장해야 함
|
||||
* 회원 이미지(MBRI): /pharRoot/data/shop_cd/mbr/YYYYMM
|
||||
* 모바일앱 이미지(APFL): /webRoot/shop_cd/app/YYYYMM
|
||||
* 기타 이미지(ETCM): /webRoot/data/shop_cd/etc/YYYYMM
|
||||
* 반품 이미지(RTRN): /rtrnRoot/data/shop_cd/mbr/YYYYMM
|
||||
* 에디터 이미지: /webRoot/data/shop_cd/editor/YYYYMM (FileMngUtil.java 사용)
|
||||
* */
|
||||
|
||||
String shopCd = param.getShopCd();
|
||||
String lnkMasterId = param.getPathGubun();
|
||||
String subPath = param.getSubPathId(); //게시판bbsid
|
||||
|
||||
if(!"".equals(lnkMasterId)&&lnkMasterId != null) {
|
||||
if(lnkMasterId.startsWith("BDFL")) {
|
||||
path = docRoot+"/"+shopCd+"/board"+subPath;
|
||||
}else if(lnkMasterId.startsWith("BDIG")) {
|
||||
path = webRoot+"/"+shopCd+"/board"+subPath;
|
||||
}else if(lnkMasterId.startsWith("GDIG")) {
|
||||
path = webRoot+"/"+shopCd+"/goods"+subPath;
|
||||
}else if(lnkMasterId.startsWith("MBRI")) {
|
||||
path = pharRoot+"/"+shopCd+"/mbr"+subPath;
|
||||
}else if(lnkMasterId.startsWith("APFL")) {
|
||||
path = webRoot+"/"+shopCd+"/app"+subPath;
|
||||
}else if(lnkMasterId.startsWith("ETCM")) {
|
||||
path = webRoot+"/"+shopCd+"/etc"+subPath;
|
||||
}else if(lnkMasterId.startsWith("RTRN")){
|
||||
path = rtrnRoot+"/"+shopCd+"/rtrn"+subPath;
|
||||
}
|
||||
} else {
|
||||
path = path + subPath;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/* 절대경로 반환 */
|
||||
public Resource loadFileAsResource(Map<String, Object> dataMap) {
|
||||
try {
|
||||
String path = null;
|
||||
if(dataMap != null && dataMap.get("fileFullPath") != null) {
|
||||
path = dataMap.get("fileFullPath").toString();
|
||||
}
|
||||
if(path != null && !path.equals("") && !path.equals("/")) {
|
||||
/* *************************************
|
||||
path는 DB경로. webroot , docroot 붙여줘야 함.
|
||||
************************************* */
|
||||
String fileDv = null;
|
||||
if(dataMap.get("filDvCd") != null) {
|
||||
fileDv = dataMap.get("filDvCd").toString();
|
||||
}
|
||||
|
||||
if(fileDv != null) {
|
||||
if(fileDv.equals("01")) {
|
||||
path = imgFileStorageLocation + path;
|
||||
}else if(fileDv.equals("02")) {
|
||||
path = docFileStorageLocation + path;
|
||||
}
|
||||
}
|
||||
|
||||
Path filePath = Paths.get(path).toAbsolutePath().normalize();
|
||||
log.debug("[파일DB경로 path] ::: "+path);
|
||||
log.debug("[파일절대경로 filePath] ::: "+filePath);
|
||||
|
||||
Resource resource = new UrlResource(filePath.toUri());
|
||||
|
||||
if(resource.exists()) {
|
||||
return resource;
|
||||
}else {
|
||||
throw new WnbtRestException("파일이 존재하지 않습니다.");
|
||||
}
|
||||
}else {
|
||||
throw new WnbtRestException("파일이 존재하지 않습니다.");
|
||||
}
|
||||
}catch(MalformedURLException ex) {
|
||||
throw new WnbtRestException("파일이 존재하지 않습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일명, 유효확장자, mimeType 검사
|
||||
* @param file 저장될 파일
|
||||
* @param validExp 유효한 확장자
|
||||
* @return boolean 검사결과
|
||||
*/
|
||||
public boolean isPermissionFileMimeType(MultipartFile file, String validExp){
|
||||
|
||||
log.debug("isPermissionFileMimeType ::: 게시판 ");
|
||||
|
||||
boolean isPermission = false;
|
||||
String orginFileName = file.getOriginalFilename();
|
||||
|
||||
// 1. 유효한 파일명 검사
|
||||
if(orginFileName != null && isFileNameVaild(orginFileName)) {
|
||||
|
||||
isPermission = true;
|
||||
log.debug("파일명 적합 ::: ");
|
||||
|
||||
//2. 허용확장자 검사 (DB 값 참조)
|
||||
String fileExt = FilenameUtils.getExtension(orginFileName);
|
||||
if(fileExt != null) {
|
||||
fileExt = fileExt.toUpperCase();
|
||||
}
|
||||
log.debug("isPermissionFileMimeType fileExt ::: {}",fileExt);
|
||||
log.debug("isPermissionFileMimeType validExp ::: {}",validExp);
|
||||
if(!StringUtil.isEmpty(validExp) && !StringUtil.isEmpty(fileExt)) {
|
||||
if(!(validExp).contains("."+fileExt.toLowerCase())) {
|
||||
isPermission = false;
|
||||
}
|
||||
}else {
|
||||
isPermission = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 허용된 MIME 타입 검사
|
||||
if(isPermission) {
|
||||
try {
|
||||
InputStream inputStream;
|
||||
inputStream = file.getInputStream();
|
||||
|
||||
String mimeType = new Tika().detect(inputStream);
|
||||
log.debug("MIME-TYPE ::: "+mimeType);
|
||||
|
||||
if(isAllowedMIMEType(mimeType)) {
|
||||
isPermission = true;
|
||||
}
|
||||
}catch(IOException e) {
|
||||
throw new WnbtRestException("업로드 파일 검증 중 파일 입출력 오류 발생");
|
||||
}
|
||||
}
|
||||
|
||||
return isPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일명, 유효확장자, mimeType(이미지) 검사
|
||||
* @param file 저장될 파일
|
||||
* @return boolean 검사결과
|
||||
*/
|
||||
private boolean isPermissionImgMimeType(MultipartFile file) {
|
||||
|
||||
log.debug("isPermissionImgMimeType ::: 이미지 ");
|
||||
|
||||
boolean isPermission = false;
|
||||
String orginFileName = file.getOriginalFilename();
|
||||
|
||||
// 1. 유효한 파일명 검사
|
||||
if(orginFileName != null && isFileNameVaild(orginFileName)) {
|
||||
|
||||
isPermission = true;
|
||||
log.debug("파일명 적합 ::: ");
|
||||
|
||||
//2. 허용확장자 검사 (.yml 파일 참조)
|
||||
String fileExt = FilenameUtils.getExtension(orginFileName);
|
||||
if(fileExt != null) {
|
||||
fileExt = fileExt.toUpperCase();
|
||||
}
|
||||
log.debug("isPermissionImgMimeType fileExt ::: {}",fileExt);
|
||||
log.debug("isPermissionImgMimeType 허용확장자 ::: {}",whiteListFileUploadExtensions);
|
||||
if(!StringUtil.isEmpty(whiteListFileUploadExtensions) && !StringUtil.isEmpty(fileExt)) {
|
||||
if(!(whiteListFileUploadExtensions).contains("."+fileExt.toLowerCase())) {
|
||||
isPermission = false;
|
||||
}
|
||||
}else {
|
||||
isPermission = false;
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("isPermission ::: 1 "+isPermission);
|
||||
// 3. 허용된 MIME 타입 검사
|
||||
if(isPermission) {
|
||||
try {
|
||||
String mimeType = new Tika().detect(file.getInputStream());
|
||||
if (mimeType.startsWith("image")) {
|
||||
isPermission = true;
|
||||
}else {
|
||||
isPermission = false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new WnbtRestException("업로드 파일 검증 중 파일 입출력 오류 발생");
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("isPermission ::: 2 "+isPermission);
|
||||
|
||||
return isPermission;
|
||||
}
|
||||
|
||||
|
||||
private boolean isAllowedMIMEType(String mimeType) {
|
||||
|
||||
if (mimeType == null || mimeType.equals("")) return false;
|
||||
|
||||
String[] allowedMIMETypesEquals = {
|
||||
"application/zip", // .zip
|
||||
"application/pdf", // .pdf
|
||||
"application/msword", // .doc, .dot
|
||||
"application/x-hwp", "applicaion/haansofthwp", // .hwp
|
||||
"application/x-tika-msoffice", // .docx
|
||||
"application/x-tika-ooxml" // .xlsx, .pptx
|
||||
};
|
||||
for (int i=0; i<allowedMIMETypesEquals.length; i++) {
|
||||
if (mimeType.equals(allowedMIMETypesEquals[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String[] allowedMIMETypesStartsWith = {
|
||||
"image", // .png, .jpg, .jpeg, .gif, .bmp
|
||||
"text", // .txt, .html 등
|
||||
"application/vnd.ms-word", // .docx 등 워드 관련
|
||||
"application/vnd.ms-excel", // .xls 등 엑셀 관련
|
||||
"application/vnd.ms-powerpoint", // .ppt 등 파워포인트 관련
|
||||
"application/vnd.openxmlformats-officedocument", // .docx, .dotx, .xlsx, .xltx, .pptx, .potx, .ppsx
|
||||
"applicaion/vnd.hancom" // .hwp 관련
|
||||
};
|
||||
for (int i=0; i<allowedMIMETypesStartsWith.length; i++) {
|
||||
if (mimeType.startsWith(allowedMIMETypesStartsWith[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean isFileNameVaild(String orginFileName) {
|
||||
|
||||
// 허용불가문자열 \ / : * ? " < > % | .sh
|
||||
String regex = "[:\\\\/%*?:|\"<>]|\\.sh";
|
||||
|
||||
log.debug("isFileNameVaild orginFileName ::: {}",orginFileName);
|
||||
if(Pattern.compile(regex).matcher(orginFileName).find()) {
|
||||
log.debug("isFileNameVaild orginFileName1111 ::: {}",orginFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
/* URL 디코딩
|
||||
String decodedFileName = "";
|
||||
decodedFileName = URLDecoder.decode(orginFileName, StandardCharsets.UTF_8);
|
||||
log.debug("isFileNameVaild decodedFileName 1 ::: {}",decodedFileName);
|
||||
|
||||
decodedFileName = decodedFileName.substring(0,decodedFileName.lastIndexOf("."));
|
||||
log.debug("isFileNameVaild decodedFileName 2 ::: {}",decodedFileName);
|
||||
|
||||
return !Pattern.compile(regex).matcher(decodedFileName).find();
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
private String getTimeStamp() {
|
||||
String rtnStr = null;
|
||||
// 문자열로 변환하기 위한 패턴 설정(연도-월-일 시:분:초:초(자정이후 초))
|
||||
String pattern = "ddhhmmssSSS"; //"yyyyMMddhhmmssSSS";
|
||||
SimpleDateFormat sdfCurrent = new SimpleDateFormat(pattern, Locale.KOREA);
|
||||
Timestamp ts = new Timestamp(System.currentTimeMillis());
|
||||
rtnStr = sdfCurrent.format(ts.getTime());
|
||||
return rtnStr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.wb.domainserver.util.file.service;
|
||||
|
||||
import com.wb.domainserver.util.file.vo.EmailProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.FileDataSource;
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
@Service
|
||||
@EnableAsync
|
||||
public class MailSenderSvc {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MailSenderSvc.class);
|
||||
|
||||
@Autowired
|
||||
EmailProperties emailProperties;
|
||||
|
||||
// 보낼사람의 이메일,제목 , 내용
|
||||
@Async
|
||||
public void sendMail(String toEmail, String fromEmail, String subject, String text, File file) throws MessagingException{
|
||||
|
||||
String smtpHostServer = emailProperties.getHost();
|
||||
String senderEmail = fromEmail;
|
||||
if("".equals(fromEmail) || fromEmail == null) {
|
||||
senderEmail = emailProperties.getUsername();
|
||||
}
|
||||
|
||||
Properties props = System.getProperties();
|
||||
// props.put("mail.smtp.host", smtpHostServer);
|
||||
props.put("mail.smtp.host", "127.0.0.1");
|
||||
Session session = Session.getInstance(props, null);
|
||||
|
||||
try {
|
||||
|
||||
MimeMessage msg = new MimeMessage(session);
|
||||
//set message headers
|
||||
msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
|
||||
msg.addHeader("format", "flowed");
|
||||
msg.addHeader("Content-Transfer-Encoding", "8bit");
|
||||
msg.setFrom(new InternetAddress(senderEmail, "셀럽페이"));
|
||||
msg.setReplyTo(InternetAddress.parse(senderEmail, false));
|
||||
msg.setSubject(subject, "UTF-8");
|
||||
|
||||
|
||||
MimeBodyPart mbp1 = new MimeBodyPart();
|
||||
mbp1.setContent(text, "text/html;charset=euc-kr");
|
||||
Multipart mp = new MimeMultipart();
|
||||
mp.addBodyPart(mbp1);
|
||||
|
||||
if(file != null) {
|
||||
MimeBodyPart mbp2 = new MimeBodyPart();
|
||||
FileDataSource fds = new FileDataSource(file.getAbsolutePath());
|
||||
mbp2.setDataHandler(new DataHandler(fds));
|
||||
mbp2.setFileName(fds.getName());
|
||||
|
||||
mp.addBodyPart(mbp2);
|
||||
}
|
||||
|
||||
msg.setContent(mp);
|
||||
|
||||
msg.setSentDate(new Date());
|
||||
|
||||
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
|
||||
System.out.println("Message is ready");
|
||||
Transport.send(msg);
|
||||
|
||||
System.out.println("EMail Sent Successfully!!");
|
||||
}catch(UnsupportedEncodingException e) {
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.wb.domainserver.util.file.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Data
|
||||
public class EmailProperties {
|
||||
@Value("${mail.host}")
|
||||
private String host;
|
||||
@Value("${mail.username}")
|
||||
private String username;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.wb.domainserver.util.file.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ExcelFile {
|
||||
private String col0;
|
||||
private String col1;
|
||||
private String col2;
|
||||
private String col3;
|
||||
private String col4;
|
||||
private String col5;
|
||||
private String col6;
|
||||
private String col7;
|
||||
private String col8;
|
||||
private String col9;
|
||||
private String col10;
|
||||
private String col11;
|
||||
private String col12;
|
||||
private String col13;
|
||||
private String col14;
|
||||
private String col15;
|
||||
private String col16;
|
||||
private String col17;
|
||||
private String col18;
|
||||
private String col19;
|
||||
private String col20;
|
||||
private String col21;
|
||||
private String col22;
|
||||
private String col23;
|
||||
private String col24;
|
||||
private String col25;
|
||||
private String col26;
|
||||
private String col27;
|
||||
private String col28;
|
||||
private String col29;
|
||||
private String col30;
|
||||
private String col31;
|
||||
private String col32;
|
||||
private String col33;
|
||||
private String col34;
|
||||
private String col35;
|
||||
private String col36;
|
||||
private String col37;
|
||||
private String col38;
|
||||
private String col39;
|
||||
private String col40;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.wb.domainserver.util.file.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
@Component
|
||||
@Data
|
||||
public class FileStorageProperties {
|
||||
@Value("${sopmalfo.common.fileupload.uploaddirs.doc}")
|
||||
private String docUploadDir;
|
||||
@Value("${sopmalfo.common.fileupload.uploaddirs.web}")
|
||||
private String imgUploadDir;
|
||||
@Value("${sopmalfo.common.fileupload.uploaddirs.phar}")
|
||||
private String pharUploadDir;
|
||||
@Value("${sopmalfo.common.fileupload.uploaddirs.rtrn}")
|
||||
private String rtrnUploadDir;
|
||||
|
||||
public String getDateDir(String pattern, boolean seperator) {
|
||||
String dirPath = "";
|
||||
DateFormat format = new SimpleDateFormat(pattern);
|
||||
Date nowDate = new Date();
|
||||
String toDate = format.format(nowDate);
|
||||
|
||||
if(seperator) {
|
||||
if("yyyy".equals(pattern)) {
|
||||
dirPath = "/" + toDate;
|
||||
}else if("yyyyMM".equals(pattern)) {
|
||||
dirPath = "/" + toDate.substring(0, 4) + "/" + toDate.substring(4, 6);
|
||||
}else if("yyyyMMdd".equals(pattern)) {
|
||||
dirPath = "/" + toDate.substring(0, 4) + "/" + toDate.substring(4, 6) + "/" + toDate.substring(6);
|
||||
}
|
||||
}else {
|
||||
dirPath = "/" + toDate;
|
||||
}
|
||||
|
||||
return dirPath;
|
||||
}
|
||||
}
|
||||
35
src/main/java/com/wb/domainserver/util/file/vo/FileVo.java
Normal file
35
src/main/java/com/wb/domainserver/util/file/vo/FileVo.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.wb.domainserver.util.file.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
public class FileVo {
|
||||
|
||||
//파일유형
|
||||
private String fileType;
|
||||
//파일일련번호
|
||||
private String fileSeq;
|
||||
//문서명
|
||||
private String docName;
|
||||
//파일경로
|
||||
private String filePath;
|
||||
//파일명
|
||||
private String fileName;
|
||||
//파일확장자
|
||||
private String fileExt;
|
||||
//파일크기
|
||||
private String fileSize;
|
||||
//파일상태
|
||||
private String status;
|
||||
|
||||
//구분도메인
|
||||
private String domain;
|
||||
//subPath
|
||||
private String subPath;
|
||||
//shopCd
|
||||
private String shopCd;
|
||||
//menuGb
|
||||
private String menuGb;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.wb.domainserver.util.file.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UploadFile {
|
||||
|
||||
private String foreignColumn;
|
||||
private String attachNo;
|
||||
private String fileId;
|
||||
private int fileSeq;
|
||||
private String fileType;
|
||||
private String docName;
|
||||
private String filePath;
|
||||
private String fileName;
|
||||
private String fileExt;
|
||||
private long fileSize;
|
||||
private int sort;
|
||||
private String status;
|
||||
private String fileDownloadUri;
|
||||
private String extFileNm;
|
||||
private String fileTabName;
|
||||
private String regDate;
|
||||
private String regId;
|
||||
private String modDate;
|
||||
private String modId;
|
||||
private String pathNumber;
|
||||
|
||||
private String shopCd;
|
||||
private String pathGubun="";
|
||||
private String subPathId="";
|
||||
private String validExp="";
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.wb.domainserver.util.format;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 날짜 및 시간에 대한 변환을 지원하는 Utility
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-24
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-24 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class DateFormatUtil {
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 날짜를 변환한다.
|
||||
*
|
||||
* @param date 날짜
|
||||
* @return 날짜 문자열
|
||||
*/
|
||||
public static String formatDate(Date date) {
|
||||
return DateFormat.getDateInstance().format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 날짜를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param date 날짜
|
||||
* @return 날짜 문자열
|
||||
*/
|
||||
public static String formatDate(Locale locale, Date date) {
|
||||
return DateFormat.getDateInstance(DateFormat.DEFAULT, locale).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 주어진 스타일에 따라, 기본 Locale에 해당하는 형식으로 날짜를 변환한다.
|
||||
*
|
||||
* @param style 날짜 스타일 (사용 가능한 값 : {@link DateFormat#FULL}, {@link DateFormat#LONG}, {@link DateFormat#MEDIUM}, {@link DateFormat#SHORT}, {@link DateFormat#DEFAULT})
|
||||
* @param date 날짜
|
||||
* @return 날짜 문자열
|
||||
*/
|
||||
public static String formatDate(int style, Date date) {
|
||||
return DateFormat.getDateInstance(style).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 주어진 스타일에 따라, Locale에 해당하는 형식으로 날짜를 변환한다.
|
||||
*
|
||||
* @param style 날짜 스타일 (사용 가능한 값 : {@link DateFormat#FULL}, {@link DateFormat#LONG}, {@link DateFormat#MEDIUM}, {@link DateFormat#SHORT}, {@link DateFormat#DEFAULT})
|
||||
* @param locale 로케일
|
||||
* @param date 날짜
|
||||
* @return 날짜 문자열
|
||||
*/
|
||||
public static String formatDate(int style, Locale locale, Date date) {
|
||||
return DateFormat.getDateInstance(style, locale).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 날짜 및 시간을 변환한다.
|
||||
*
|
||||
* @param date 날짜 및 시간
|
||||
* @return 날짜 및 시간 문자열
|
||||
*/
|
||||
public static String formatDateTime(Date date) {
|
||||
return DateFormat.getDateTimeInstance().format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 날짜 및 시간을 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param date 날짜 및 시간
|
||||
* @return 날짜 및 시간 문자열
|
||||
*/
|
||||
public static String formatDateTime(Locale locale, Date date) {
|
||||
return DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, locale).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 주어진 스타일에 따라, 기본 Locale에 해당하는 형식으로 날짜 및 시간을 변환한다.
|
||||
*
|
||||
* @param dateStyle 날짜 스타일 (사용 가능한 값 : {@link DateFormat#FULL}, {@link DateFormat#LONG}, {@link DateFormat#MEDIUM}, {@link DateFormat#SHORT}, {@link DateFormat#DEFAULT})
|
||||
* @param timeStyle 시간 스타일 (사용 가능한 값 : {@link DateFormat#FULL}, {@link DateFormat#LONG}, {@link DateFormat#MEDIUM}, {@link DateFormat#SHORT}, {@link DateFormat#DEFAULT})
|
||||
* @param date 날짜 및 시간
|
||||
* @return 날짜 및 시간 문자열
|
||||
*/
|
||||
public static String formatDateTime(int dateStyle, int timeStyle, Date date) {
|
||||
return DateFormat.getDateTimeInstance(dateStyle, timeStyle).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 주어진 스타일에 따라, Locale에 해당하는 형식으로 날짜 및 시간을 변환한다.
|
||||
*
|
||||
* @param dateStyle 날짜 스타일 (사용 가능한 값 : {@link DateFormat#FULL}, {@link DateFormat#LONG}, {@link DateFormat#MEDIUM}, {@link DateFormat#SHORT}, {@link DateFormat#DEFAULT})
|
||||
* @param timeStyle 시간 스타일 (사용 가능한 값 : {@link DateFormat#FULL}, {@link DateFormat#LONG}, {@link DateFormat#MEDIUM}, {@link DateFormat#SHORT}, {@link DateFormat#DEFAULT})
|
||||
* @param locale 로케일
|
||||
* @param date 날짜 및 시간
|
||||
* @return 날짜 및 시간 문자열
|
||||
*/
|
||||
public static String formatDateTime(int dateStyle, int timeStyle, Locale locale, Date date) {
|
||||
return DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 시간을 변환한다.
|
||||
*
|
||||
* @param date 시간
|
||||
* @return 시간 문자열
|
||||
*/
|
||||
public static String formatTime(Date date) {
|
||||
return DateFormat.getTimeInstance().format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 시간을 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param date 시간
|
||||
* @return 시간 문자열
|
||||
*/
|
||||
public static String formatTime(Locale locale, Date date) {
|
||||
return DateFormat.getTimeInstance(DateFormat.DEFAULT, locale).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 주어진 스타일에 따라, 기본 Locale에 해당하는 형식으로 시간을 변환한다.
|
||||
*
|
||||
* @param style 시간 스타일 (사용 가능한 값 : {@link DateFormat#FULL}, {@link DateFormat#LONG}, {@link DateFormat#MEDIUM}, {@link DateFormat#SHORT}, {@link DateFormat#DEFAULT})
|
||||
* @param date 시간
|
||||
* @return 시간 문자열
|
||||
*/
|
||||
public static String formatTime(int style, Date date) {
|
||||
return DateFormat.getTimeInstance(style).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 주어진 스타일에 따라, Locale에 해당하는 형식으로 시간을 변환한다.
|
||||
*
|
||||
* @param style 시간 스타일 (사용 가능한 값 : {@link DateFormat#FULL}, {@link DateFormat#LONG}, {@link DateFormat#MEDIUM}, {@link DateFormat#SHORT}, {@link DateFormat#DEFAULT})
|
||||
* @param locale 로케일
|
||||
* @param date 시간
|
||||
* @return 시간 문자열
|
||||
*/
|
||||
public static String formatTime(int style, Locale locale, Date date) {
|
||||
return DateFormat.getTimeInstance(style, locale).format(date);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
package com.wb.domainserver.util.format;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 숫자, 통화, 퍼센트에 대한 형식 변환을 지원하는 Utility
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-24
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-24 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class NumberFormatUtil {
|
||||
private static final int MAX_FRACTION_DIGIT = 3;
|
||||
private static final boolean GROUPING_USED = true;
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 숫자를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @return 숫자 문자열
|
||||
*/
|
||||
public static String formatNumber(Number number) {
|
||||
return formatNumber(number, GROUPING_USED, MAX_FRACTION_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 숫자를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @return 숫자 문자열
|
||||
*/
|
||||
public static String formatNumber(Locale locale, Number number) {
|
||||
return formatNumber(locale, number, GROUPING_USED, MAX_FRACTION_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 숫자를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @return 숫자 문자열
|
||||
*/
|
||||
public static String formatNumber(Number number, boolean groupingUsed) {
|
||||
return formatNumber(number, groupingUsed, MAX_FRACTION_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 숫자를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @return 숫자 문자열
|
||||
*/
|
||||
public static String formatNumber(Locale locale, Number number, boolean groupingUsed) {
|
||||
return formatNumber(locale, number, groupingUsed, MAX_FRACTION_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 숫자를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @param maxFactionDigits 변환된 문자열에서 출력할 소수점 이하 최대 자리수
|
||||
* @return 숫자 문자열
|
||||
*/
|
||||
public static String formatNumber(Number number, int maxFactionDigits) {
|
||||
return formatNumber(number, GROUPING_USED, maxFactionDigits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 숫자를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @param maxFactionDigits 변환된 문자열에서 출력할 소수점 이하 최대 자리수
|
||||
* @return 숫자 문자열
|
||||
*/
|
||||
public static String formatNumber(Locale locale, Number number, int maxFactionDigits) {
|
||||
return formatNumber(locale, number, GROUPING_USED, maxFactionDigits);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 숫자를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @param maxFactionDigits 변환된 문자열에서 출력할 소수점 이하 최대 자리수
|
||||
* @return 숫자 문자열
|
||||
*/
|
||||
public static String formatNumber(Number number, boolean groupingUsed, int maxFactionDigits) {
|
||||
NumberFormat numberberFormat = NumberFormat.getNumberInstance();
|
||||
numberberFormat.setGroupingUsed(groupingUsed);
|
||||
numberberFormat.setMaximumFractionDigits(maxFactionDigits);
|
||||
return numberberFormat.format(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 숫자를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @param maxFactionDigits 변환된 문자열에서 출력할 소수점 이하 최대 자리수
|
||||
* @return 숫자 문자열
|
||||
*/
|
||||
public static String formatNumber(Locale locale, Number number, boolean groupingUsed, int maxFactionDigits) {
|
||||
NumberFormat numberberFormat = NumberFormat.getNumberInstance(locale);
|
||||
numberberFormat.setGroupingUsed(groupingUsed);
|
||||
numberberFormat.setMaximumFractionDigits(maxFactionDigits);
|
||||
return numberberFormat.format(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 통화를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @return 통화 문자열
|
||||
*/
|
||||
public static String formatCurrency(Number number) {
|
||||
return formatCurrency(number, GROUPING_USED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 통화를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @return 통화 문자열
|
||||
*/
|
||||
public static String formatCurrency(Locale locale, Number number) {
|
||||
return formatCurrency(locale, number, GROUPING_USED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 통화를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @return 통화 문자열
|
||||
*/
|
||||
public static String formatCurrency(Number number, boolean groupingUsed) {
|
||||
NumberFormat numberberFormat = NumberFormat.getCurrencyInstance();
|
||||
numberberFormat.setGroupingUsed(groupingUsed);
|
||||
return numberberFormat.format(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 통화를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @return 통화 문자열
|
||||
*/
|
||||
public static String formatCurrency(Locale locale, Number number, boolean groupingUsed) {
|
||||
NumberFormat numberberFormat = NumberFormat.getCurrencyInstance(locale);
|
||||
numberberFormat.setGroupingUsed(groupingUsed);
|
||||
return numberberFormat.format(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 퍼센트를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @return 퍼센트 문자열
|
||||
*/
|
||||
public static String formatPercent(Number number) {
|
||||
return formatPercent(number, GROUPING_USED, MAX_FRACTION_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 퍼센트를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @return 퍼센트 문자열
|
||||
*/
|
||||
public static String formatPercent(Locale locale, Number number) {
|
||||
return formatPercent(locale, number, GROUPING_USED, MAX_FRACTION_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 퍼센트를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @return 퍼센트 문자열
|
||||
*/
|
||||
public static String formatPercent(Number number, boolean groupingUsed) {
|
||||
return formatPercent(number, groupingUsed, MAX_FRACTION_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 퍼센트를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @return 퍼센트 문자열
|
||||
*/
|
||||
public static String formatPercent(Locale locale, Number number, boolean groupingUsed) {
|
||||
return formatPercent(locale, number, groupingUsed, MAX_FRACTION_DIGIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 퍼센트를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @param maxFactionDigits 변환된 문자열에서 출력할 소수점 이하 최대 자리수
|
||||
* @return 퍼센트 문자열
|
||||
*/
|
||||
public static String formatPercent(Number number, int maxFactionDigits) {
|
||||
return formatPercent(number, GROUPING_USED, maxFactionDigits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 퍼센트를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @param maxFactionDigits 변환된 문자열에서 출력할 소수점 이하 최대 자리수
|
||||
* @return 퍼센트 문자열
|
||||
*/
|
||||
public static String formatPercent(Locale locale, Number number, int maxFactionDigits) {
|
||||
return formatPercent(locale, number, GROUPING_USED, maxFactionDigits);
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 Locale에 해당하는 형식으로 퍼센트를 변환한다.
|
||||
*
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @param maxFactionDigits 변환된 문자열에서 출력할 소수점 이하 최대 자리수
|
||||
* @return 퍼센트 문자열
|
||||
*/
|
||||
public static String formatPercent(Number number, boolean groupingUsed, int maxFactionDigits) {
|
||||
NumberFormat numberberFormat = NumberFormat.getPercentInstance();
|
||||
numberberFormat.setGroupingUsed(groupingUsed);
|
||||
numberberFormat.setMaximumFractionDigits(maxFactionDigits);
|
||||
return numberberFormat.format(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale에 해당하는 형식으로 퍼센트를 변환한다.
|
||||
*
|
||||
* @param locale 로케일
|
||||
* @param number 숫자
|
||||
* @param groupingUsed 그룹 분리기호 포함 여부
|
||||
* @param maxFactionDigits 변환된 문자열에서 출력할 소수점 이하 최대 자리수
|
||||
* @return 퍼센트 문자열
|
||||
*/
|
||||
public static String formatPercent(Locale locale, Number number, boolean groupingUsed, int maxFactionDigits) {
|
||||
NumberFormat numberberFormat = NumberFormat.getPercentInstance(locale);
|
||||
numberberFormat.setGroupingUsed(groupingUsed);
|
||||
numberberFormat.setMaximumFractionDigits(maxFactionDigits);
|
||||
return numberberFormat.format(number);
|
||||
}
|
||||
}
|
||||
216
src/main/java/com/wb/domainserver/util/number/NumberUtil.java
Normal file
216
src/main/java/com/wb/domainserver/util/number/NumberUtil.java
Normal file
@@ -0,0 +1,216 @@
|
||||
package com.wb.domainserver.util.number;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 숫자 처리를 지원하는 Utility
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-24
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-24 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class NumberUtil {
|
||||
|
||||
private static SecureRandom rnd = new SecureRandom();
|
||||
|
||||
/**
|
||||
* 특정숫자 집합에서 랜덤 숫자를 구하는 기능 시작숫자와 종료숫자 사이에서 구한 랜덤 숫자를 반환한다
|
||||
*
|
||||
* @param startNum - 시작숫자
|
||||
* @param endNum - 종료숫자
|
||||
* @return 랜덤숫자
|
||||
* @see
|
||||
*/
|
||||
public static int getRandomNum(int startNum, int endNum) {
|
||||
int randomNum = 0;
|
||||
|
||||
do {
|
||||
// 종료숫자내에서 랜덤 숫자를 발생시킨다.
|
||||
randomNum = rnd.nextInt(endNum + 1);
|
||||
} while (randomNum < startNum); // 랜덤 숫자가 시작숫자보다 작을경우 다시 랜덤숫자를 발생시킨다.
|
||||
|
||||
return randomNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 숫자 집합에서 특정 숫자가 있는지 체크하는 기능 12345678에서 7이 있는지 없는지 체크하는 기능을 제공함
|
||||
*
|
||||
* @param sourceInt - 특정숫자집합
|
||||
* @param searchInt - 검색숫자
|
||||
* @return 존재여부
|
||||
* @see
|
||||
*/
|
||||
public static Boolean getNumSearchCheck(int sourceInt, int searchInt) {
|
||||
String sourceStr = String.valueOf(sourceInt);
|
||||
String searchStr = String.valueOf(searchInt);
|
||||
|
||||
// 특정숫자가 존재하는지 하여 위치값을 리턴한다. 없을 시 -1
|
||||
if (sourceStr.indexOf(searchStr) == -1) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 숫자타입을 문자열로 변환하는 기능 숫자 20081212를 문자열 '20081212'로 변환하는 기능
|
||||
*
|
||||
* @param srcNumber - 숫자
|
||||
* @return 문자열
|
||||
* @see
|
||||
*/
|
||||
public static String getNumToStrCnvr(int srcNumber) {
|
||||
String rtnStr = null;
|
||||
|
||||
rtnStr = String.valueOf(srcNumber);
|
||||
|
||||
return rtnStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 숫자타입을 데이트 타입으로 변환하는 기능
|
||||
* 숫자 20081212를 데이트타입 '2008-12-12'로 변환하는 기능
|
||||
* @param srcNumber - 숫자
|
||||
* @return String
|
||||
* @see
|
||||
*/
|
||||
public static String getNumToDateCnvr(int srcNumber) {
|
||||
|
||||
String pattern = null;
|
||||
String cnvrStr = null;
|
||||
|
||||
String srcStr = String.valueOf(srcNumber);
|
||||
|
||||
// Date 형태인 8자리 및 14자리만 정상처리
|
||||
if (srcStr.length() != 8 && srcStr.length() != 14) {
|
||||
throw new IllegalArgumentException("Invalid Number: " + srcStr + " Length=" + srcStr.trim().length());
|
||||
}
|
||||
|
||||
if (srcStr.length() == 8) {
|
||||
pattern = "yyyyMMdd";
|
||||
} else if (srcStr.length() == 14) {
|
||||
pattern = "yyyyMMddhhmmss";
|
||||
}
|
||||
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat(pattern, Locale.KOREA);
|
||||
|
||||
Date cnvrDate = null;
|
||||
|
||||
try {
|
||||
cnvrDate = dateFormatter.parse(srcStr);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
cnvrStr = String.format("%1$tY-%1$tm-%1$td", cnvrDate);
|
||||
|
||||
return cnvrStr;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 체크할 숫자 중에서 숫자인지 아닌지 체크하는 기능
|
||||
* 숫자이면 True, 아니면 False를 반환한다
|
||||
* @param checkStr - 체크문자열
|
||||
* @return 숫자여부
|
||||
* @see
|
||||
*/
|
||||
public static Boolean getNumberValidCheck(String checkStr) {
|
||||
|
||||
int i;
|
||||
//String sourceStr = String.valueOf(sourceInt);
|
||||
|
||||
int checkStrLt = checkStr.length();
|
||||
|
||||
for (i = 0; i < checkStrLt; i++) {
|
||||
|
||||
// 아스키코드값( '0'-> 48, '9' -> 57)
|
||||
if (checkStr.charAt(i) > 47 && checkStr.charAt(i) < 58) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정숫자를 다른 숫자로 치환하는 기능 숫자 12345678에서 123를 999로 변환하는 기능을 제공(99945678)
|
||||
*
|
||||
* @param srcNumber - 숫자집합
|
||||
* @param cnvrSrcNumber - 원래숫자
|
||||
* @param cnvrTrgtNumber - 치환숫자
|
||||
* @return 치환숫자
|
||||
* @see
|
||||
*/
|
||||
public static int getNumberCnvr(int srcNumber, int cnvrSrcNumber, int cnvrTrgtNumber) {
|
||||
|
||||
// 입력받은 숫자를 문자열로 변환
|
||||
String source = String.valueOf(srcNumber);
|
||||
String subject = String.valueOf(cnvrSrcNumber);
|
||||
String object = String.valueOf(cnvrTrgtNumber);
|
||||
|
||||
StringBuffer rtnStr = new StringBuffer();
|
||||
String preStr = "";
|
||||
String nextStr = source;
|
||||
|
||||
// 원본숫자에서 변환대상숫자의 위치를 찾는다.
|
||||
while (source.indexOf(subject) >= 0) {
|
||||
preStr = source.substring(0, source.indexOf(subject)); // 변환대상숫자 위치까지 숫자를 잘라낸다
|
||||
nextStr = source.substring(source.indexOf(subject) + subject.length(), source.length());
|
||||
source = nextStr;
|
||||
rtnStr.append(preStr).append(object); // 변환대상위치 숫자에 변환할 숫자를 붙여준다.
|
||||
}
|
||||
rtnStr.append(nextStr); // 변환대상 숫자 이후 숫자를 붙여준다.
|
||||
|
||||
return Integer.parseInt(rtnStr.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정숫자가 실수인지, 정수인지, 음수인지 체크하는 기능 123이 실수인지, 정수인지, 음수인지 체크하는 기능을 제공함
|
||||
*
|
||||
* @param srcNumber - 숫자집합
|
||||
* @return -1(음수), 0(정수), 1(실수)
|
||||
* @see
|
||||
*/
|
||||
public static int checkRlnoInteger(double srcNumber) {
|
||||
|
||||
// byte 1바이트 ▶소수점이 없는 숫자로, 범위 -2^7 ~ 2^7 -1
|
||||
// short 2바이트 ▶소수점이 없는 숫자로, 범위 -2^15 ~ 2^15 -1
|
||||
// int 4바이트 ▶소수점이 없는 숫자로, 범위 -2^31 ~ 2^31 - 1
|
||||
// long 8바이트 ▶소수점이 없는 숫자로, 범위 -2^63 ~ 2^63-1
|
||||
|
||||
// float 4바이트 ▶소수점이 있는 숫자로, 끝에 F 또는 f 가 붙는 숫자 (예:3.14f)
|
||||
// double 8바이트 ▶소수점이 있는 숫자로, 끝에 아무것도 붙지 않는 숫자 (예:3.14)
|
||||
// ▶소수점이 있는 숫자로, 끝에 D 또는 d 가 붙는 숫자(예:3.14d)
|
||||
|
||||
String cnvrString = null;
|
||||
|
||||
if (srcNumber < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
cnvrString = String.valueOf(srcNumber);
|
||||
|
||||
if (cnvrString.indexOf(".") == -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
944
src/main/java/com/wb/domainserver/util/string/StringUtil.java
Normal file
944
src/main/java/com/wb/domainserver/util/string/StringUtil.java
Normal file
@@ -0,0 +1,944 @@
|
||||
package com.wb.domainserver.util.string;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.security.SecureRandom;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 문자열 관련 처리를 지원하는 Utility
|
||||
*
|
||||
* @author 박철민
|
||||
* @since 2023-11-24
|
||||
* @version 1.0
|
||||
* @see
|
||||
*
|
||||
* <pre>
|
||||
* == (Modification Information) == 개정이력
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ------- -------- ---------------------------
|
||||
* 2023-11-24 박철민 최초 생성
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class StringUtil {
|
||||
|
||||
public static final String EMPTY = "";
|
||||
private static SecureRandom rnd = new SecureRandom();
|
||||
|
||||
/**
|
||||
* 문자열이 지정한 길이를 초과했을때 지정한길이에다가 해당 문자열을 붙여주는 메서드.
|
||||
* @param source 원본 문자열 배열
|
||||
* @param output 더할문자열
|
||||
* @param slength 지정길이
|
||||
* @return 지정길이로 잘라서 더할분자열 합친 문자열
|
||||
*/
|
||||
public static String cutString(String source, String output, int slength) {
|
||||
String returnVal = null;
|
||||
if (source != null) {
|
||||
if (source.length() > slength) {
|
||||
returnVal = source.substring(0, slength) + output;
|
||||
} else {
|
||||
returnVal = source;
|
||||
}
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 문자열이 지정한 길이를 초과했을때 해당 문자열을 삭제하는 메서드
|
||||
* @param source 원본 문자열 배열
|
||||
* @param slength 지정길이
|
||||
* @return 지정길이로 잘라서 더할분자열 합친 문자열
|
||||
*/
|
||||
public static String cutString(String source, int slength) {
|
||||
String result = null;
|
||||
if (source != null) {
|
||||
if (source.length() > slength) {
|
||||
result = source.substring(0, slength);
|
||||
} else {
|
||||
result = source;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* String이 비었거나("") 혹은 null 인지 검증한다.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.isEmpty(null) = true
|
||||
* StringUtil.isEmpty("") = true
|
||||
* StringUtil.isEmpty(" ") = false
|
||||
* StringUtil.isEmpty("bob") = false
|
||||
* StringUtil.isEmpty(" bob ") = false
|
||||
* </pre>
|
||||
*
|
||||
* @param str - 체크 대상 스트링오브젝트이며 null을 허용함
|
||||
* @return <code>true</code> - 입력받은 String 이 빈 문자열 또는 null인 경우
|
||||
*/
|
||||
public static boolean isEmpty(String str) {
|
||||
return str == null || str.length() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>기준 문자열에 포함된 모든 대상 문자(char)를 제거한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.remove(null, *) = null
|
||||
* StringUtil.remove("", *) = ""
|
||||
* StringUtil.remove("queued", 'u') = "qeed"
|
||||
* StringUtil.remove("queued", 'z') = "queued"
|
||||
* </pre>
|
||||
*
|
||||
* @param str 입력받는 기준 문자열
|
||||
* @param remove 입력받는 문자열에서 제거할 대상 문자열
|
||||
* @return 제거대상 문자열이 제거된 입력문자열. 입력문자열이 null인 경우 출력문자열은 null
|
||||
*/
|
||||
public static String remove(String str, char remove) {
|
||||
if (isEmpty(str) || str.indexOf(remove) == -1) {
|
||||
return str;
|
||||
}
|
||||
char[] chars = str.toCharArray();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
if (chars[i] != remove) {
|
||||
chars[pos++] = chars[i];
|
||||
}
|
||||
}
|
||||
return new String(chars, 0, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>문자열 내부의 콤마 character(,)를 모두 제거한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.removeCommaChar(null) = null
|
||||
* StringUtil.removeCommaChar("") = ""
|
||||
* StringUtil.removeCommaChar("asdfg,qweqe") = "asdfgqweqe"
|
||||
* </pre>
|
||||
*
|
||||
* @param str 입력받는 기준 문자열
|
||||
* @return " , "가 제거된 입력문자열
|
||||
* 입력문자열이 null인 경우 출력문자열은 null
|
||||
*/
|
||||
public static String removeCommaChar(String str) {
|
||||
return remove(str, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>문자열 내부의 마이너스 character(-)를 모두 제거한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.removeMinusChar(null) = null
|
||||
* StringUtil.removeMinusChar("") = ""
|
||||
* StringUtil.removeMinusChar("a-sdfg-qweqe") = "asdfgqweqe"
|
||||
* </pre>
|
||||
*
|
||||
* @param str 입력받는 기준 문자열
|
||||
* @return " - "가 제거된 입력문자열
|
||||
* 입력문자열이 null인 경우 출력문자열은 null
|
||||
*/
|
||||
public static String removeMinusChar(String str) {
|
||||
return remove(str, '-');
|
||||
}
|
||||
|
||||
/**
|
||||
* 원본 문자열의 포함된 특정 문자열을 새로운 문자열로 변환하는 메서드
|
||||
* @param source 원본 문자열
|
||||
* @param subject 원본 문자열에 포함된 특정 문자열
|
||||
* @param object 변환할 문자열
|
||||
* @return sb.toString() 새로운 문자열로 변환된 문자열
|
||||
*/
|
||||
public static String replace(String source, String subject, String object) {
|
||||
StringBuffer rtnStr = new StringBuffer();
|
||||
String preStr = "";
|
||||
String nextStr = source;
|
||||
String srcStr = source;
|
||||
|
||||
while (srcStr.indexOf(subject) >= 0) {
|
||||
preStr = srcStr.substring(0, srcStr.indexOf(subject));
|
||||
nextStr = srcStr.substring(srcStr.indexOf(subject) + subject.length(), srcStr.length());
|
||||
srcStr = nextStr;
|
||||
rtnStr.append(preStr).append(object);
|
||||
}
|
||||
rtnStr.append(nextStr);
|
||||
|
||||
return rtnStr.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 원본 문자열의 포함된 특정 문자열 첫번째 한개만 새로운 문자열로 변환하는 메서드
|
||||
* @param source 원본 문자열
|
||||
* @param subject 원본 문자열에 포함된 특정 문자열
|
||||
* @param object 변환할 문자열
|
||||
* @return sb.toString() 새로운 문자열로 변환된 문자열 / source 특정문자열이 없는 경우 원본 문자열
|
||||
*/
|
||||
public static String replaceOnce(String source, String subject, String object) {
|
||||
StringBuffer rtnStr = new StringBuffer();
|
||||
String preStr = "";
|
||||
String nextStr = source;
|
||||
if (source.indexOf(subject) >= 0) {
|
||||
preStr = source.substring(0, source.indexOf(subject));
|
||||
nextStr = source.substring(source.indexOf(subject) + subject.length(), source.length());
|
||||
rtnStr.append(preStr).append(object).append(nextStr);
|
||||
|
||||
return rtnStr.toString();
|
||||
} else {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>subject</code>에 포함된 각각의 문자를 object로 변환한다.
|
||||
*
|
||||
* @param source 원본 문자열
|
||||
* @param subject 원본 문자열에 포함된 특정 문자열
|
||||
* @param object 변환할 문자열
|
||||
* @return sb.toString() 새로운 문자열로 변환된 문자열
|
||||
*/
|
||||
public static String replaceChar(String source, String subject, String object) {
|
||||
StringBuffer rtnStr = new StringBuffer();
|
||||
String preStr = "";
|
||||
String nextStr = source;
|
||||
String srcStr = source;
|
||||
|
||||
char chA;
|
||||
|
||||
for (int i = 0; i < subject.length(); i++) {
|
||||
chA = subject.charAt(i);
|
||||
|
||||
if (srcStr.indexOf(chA) >= 0) {
|
||||
preStr = srcStr.substring(0, srcStr.indexOf(chA));
|
||||
nextStr = srcStr.substring(srcStr.indexOf(chA) + 1, srcStr.length());
|
||||
srcStr = rtnStr.append(preStr).append(object).append(nextStr).toString();
|
||||
}
|
||||
}
|
||||
|
||||
return srcStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p><code>str</code> 중 <code>searchStr</code>의 시작(index) 위치를 반환.</p>
|
||||
*
|
||||
* <p>입력값 중 <code>null</code>이 있을 경우 <code>-1</code>을 반환.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.indexOf(null, *) = -1
|
||||
* StringUtil.indexOf(*, null) = -1
|
||||
* StringUtil.indexOf("", "") = 0
|
||||
* StringUtil.indexOf("aabaabaa", "a") = 0
|
||||
* StringUtil.indexOf("aabaabaa", "b") = 2
|
||||
* StringUtil.indexOf("aabaabaa", "ab") = 1
|
||||
* StringUtil.indexOf("aabaabaa", "") = 0
|
||||
* </pre>
|
||||
*
|
||||
* @param str 검색 문자열
|
||||
* @param searchStr 검색 대상문자열
|
||||
* @return 검색 문자열 중 검색 대상문자열이 있는 시작 위치 검색대상 문자열이 없거나 null인 경우 -1
|
||||
*/
|
||||
public static int indexOf(String str, String searchStr) {
|
||||
if (str == null || searchStr == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return str.indexOf(searchStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>오라클의 decode 함수와 동일한 기능을 가진 메서드이다.
|
||||
* <code>sourStr</code>과 <code>compareStr</code>의 값이 같으면
|
||||
* <code>returStr</code>을 반환하며, 다르면 <code>defaultStr</code>을 반환한다.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.decode(null, null, "foo", "bar")= "foo"
|
||||
* StringUtil.decode("", null, "foo", "bar") = "bar"
|
||||
* StringUtil.decode(null, "", "foo", "bar") = "bar"
|
||||
* StringUtil.decode("하이", "하이", null, "bar") = null
|
||||
* StringUtil.decode("하이", "하이 ", "foo", null) = null
|
||||
* StringUtil.decode("하이", "하이", "foo", "bar") = "foo"
|
||||
* StringUtil.decode("하이", "하이 ", "foo", "bar") = "bar"
|
||||
* </pre>
|
||||
*
|
||||
* @param sourceStr 비교할 문자열
|
||||
* @param compareStr 비교 대상 문자열
|
||||
* @param returnStr sourceStr와 compareStr의 값이 같을 때 반환할 문자열
|
||||
* @param defaultStr sourceStr와 compareStr의 값이 다를 때 반환할 문자열
|
||||
* @return sourceStr과 compareStr의 값이 동일(equal)할 때 returnStr을 반환하며,
|
||||
* <br/>다르면 defaultStr을 반환한다.
|
||||
*/
|
||||
public static String decode(String sourceStr, String compareStr, String returnStr, String defaultStr) {
|
||||
// if (sourceStr == null && compareStr == null) {
|
||||
// return returnStr;
|
||||
// }
|
||||
//
|
||||
// if (sourceStr == null && compareStr != null) {
|
||||
// return defaultStr;
|
||||
// }
|
||||
//
|
||||
// if (sourceStr.trim().equals(compareStr)) {
|
||||
// return returnStr;
|
||||
// }
|
||||
|
||||
if (sourceStr == null) { //2022.01. Possible null pointer dereference
|
||||
if (compareStr == null) {
|
||||
return returnStr;
|
||||
} else {
|
||||
return defaultStr;
|
||||
}
|
||||
} else {
|
||||
if (sourceStr.trim().equals(compareStr)) {
|
||||
return returnStr;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>오라클의 decode 함수와 동일한 기능을 가진 메서드이다.
|
||||
* <code>sourStr</code>과 <code>compareStr</code>의 값이 같으면
|
||||
* <code>returStr</code>을 반환하며, 다르면 <code>sourceStr</code>을 반환한다.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.decode(null, null, "foo") = "foo"
|
||||
* StringUtil.decode("", null, "foo") = ""
|
||||
* StringUtil.decode(null, "", "foo") = null
|
||||
* StringUtil.decode("하이", "하이", "foo") = "foo"
|
||||
* StringUtil.decode("하이", "하이 ", "foo") = "하이"
|
||||
* StringUtil.decode("하이", "바이", "foo") = "하이"
|
||||
* </pre>
|
||||
*
|
||||
* @param sourceStr 비교할 문자열
|
||||
* @param compareStr 비교 대상 문자열
|
||||
* @param returnStr sourceStr와 compareStr의 값이 같을 때 반환할 문자열
|
||||
* @return sourceStr과 compareStr의 값이 동일(equal)할 때 returnStr을 반환하며,
|
||||
* <br/>다르면 sourceStr을 반환한다.
|
||||
*/
|
||||
public static String decode(String sourceStr, String compareStr, String returnStr) {
|
||||
return decode(sourceStr, compareStr, returnStr, sourceStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 객체가 null인지 확인하고 null인 경우 "" 로 바꾸는 메서드
|
||||
* @param object 원본 객체
|
||||
* @return resultVal 문자열
|
||||
*/
|
||||
public static String isNullToString(Object object) {
|
||||
String string = "";
|
||||
|
||||
if (object != null) {
|
||||
string = object.toString().trim();
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
*<pre>
|
||||
* 인자로 받은 String이 null일 경우 ""로 리턴한다.
|
||||
* @param src null값일 가능성이 있는 String 값.
|
||||
* @return 만약 String이 null 값일 경우 ""로 바꾼 String 값.
|
||||
*</pre>
|
||||
*/
|
||||
public static String nullConvert(Object src) {
|
||||
//if (src != null && src.getClass().getName().equals("java.math.BigDecimal")) {
|
||||
if (src != null && src instanceof BigDecimal) {
|
||||
return ((BigDecimal)src).toString();
|
||||
}
|
||||
|
||||
if (src == null || src.equals("null")) {
|
||||
return "";
|
||||
} else {
|
||||
return ((String)src).trim();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*<pre>
|
||||
* 인자로 받은 String이 null일 경우 ""로 리턴한다.
|
||||
* @param src null값일 가능성이 있는 String 값.
|
||||
* @return 만약 String이 null 값일 경우 ""로 바꾼 String 값.
|
||||
*</pre>
|
||||
*/
|
||||
public static String nullConvertInt(Object src) {
|
||||
//if (src != null && src.getClass().getName().equals("java.math.BigDecimal")) {
|
||||
if (src != null && src instanceof BigDecimal) {
|
||||
return ((BigDecimal)src).toString();
|
||||
}
|
||||
|
||||
if (src == null || src.equals("null")) {
|
||||
return "0";
|
||||
} else {
|
||||
return ((String)src).trim();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*<pre>
|
||||
* 인자로 받은 String이 null일 경우 ""로 리턴한다.
|
||||
* @param src null값일 가능성이 있는 String 값.
|
||||
* @return 만약 String이 null 값일 경우 ""로 바꾼 String 값.
|
||||
*</pre>
|
||||
*/
|
||||
public static String nullConvert(String src) {
|
||||
|
||||
if (src == null || src.equals("null") || "".equals(src) || " ".equals(src)) {
|
||||
return "";
|
||||
} else {
|
||||
return src.trim();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*<pre>
|
||||
* 인자로 받은 String이 null일 경우 "0"로 리턴한다.
|
||||
* @param src null값일 가능성이 있는 String 값.
|
||||
* @return 만약 String이 null 값일 경우 "0"로 바꾼 String 값.
|
||||
*</pre>
|
||||
*/
|
||||
public static int zeroConvert(Object src) {
|
||||
|
||||
if (src == null || src.equals("null")) {
|
||||
return 0;
|
||||
} else {
|
||||
return Integer.parseInt(((String)src).trim());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*<pre>
|
||||
* 인자로 받은 String이 null일 경우 ""로 리턴한다.
|
||||
* @param src null값일 가능성이 있는 String 값.
|
||||
* @return 만약 String이 null 값일 경우 ""로 바꾼 String 값.
|
||||
*</pre>
|
||||
*/
|
||||
public static int zeroConvert(String src) {
|
||||
|
||||
if (src == null || src.equals("null") || "".equals(src) || " ".equals(src)) {
|
||||
return 0;
|
||||
} else {
|
||||
return Integer.parseInt(src.trim());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>문자열에서 {@link Character#isWhitespace(char)}에 정의된
|
||||
* 모든 공백문자를 제거한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.removeWhitespace(null) = null
|
||||
* StringUtil.removeWhitespace("") = ""
|
||||
* StringUtil.removeWhitespace("abc") = "abc"
|
||||
* StringUtil.removeWhitespace(" ab c ") = "abc"
|
||||
* </pre>
|
||||
*
|
||||
* @param str 공백문자가 제거도어야 할 문자열
|
||||
* @return the 공백문자가 제거된 문자열, null이 입력되면 <code>null</code>이 리턴
|
||||
*/
|
||||
public static String removeWhitespace(String str) {
|
||||
if (isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
int sz = str.length();
|
||||
char[] chs = new char[sz];
|
||||
int count = 0;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
if (!Character.isWhitespace(str.charAt(i))) {
|
||||
chs[count++] = str.charAt(i);
|
||||
}
|
||||
}
|
||||
if (count == sz) {
|
||||
return str;
|
||||
}
|
||||
|
||||
return new String(chs, 0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Html 코드가 들어간 문서를 표시할때 태그에 손상없이 보이기 위한 메서드
|
||||
*
|
||||
* @param strString
|
||||
* @return HTML 태그를 치환한 문자열
|
||||
*/
|
||||
public static String checkHtmlView(String strString) {
|
||||
String strNew = "";
|
||||
|
||||
StringBuffer strTxt = new StringBuffer("");
|
||||
|
||||
char chrBuff;
|
||||
int len = strString.length();
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
chrBuff = strString.charAt(i);
|
||||
|
||||
switch (chrBuff) {
|
||||
case '<':
|
||||
strTxt.append("<");
|
||||
break;
|
||||
case '>':
|
||||
strTxt.append(">");
|
||||
break;
|
||||
case '"':
|
||||
strTxt.append(""");
|
||||
break;
|
||||
case 10:
|
||||
strTxt.append("<br>");
|
||||
break;
|
||||
case ' ':
|
||||
strTxt.append(" ");
|
||||
break;
|
||||
//case '&' :
|
||||
//strTxt.append("&");
|
||||
//break;
|
||||
default:
|
||||
strTxt.append(chrBuff);
|
||||
}
|
||||
}
|
||||
|
||||
strNew = strTxt.toString();
|
||||
|
||||
return strNew;
|
||||
}
|
||||
|
||||
/**
|
||||
* 문자열을 지정한 분리자에 의해 배열로 리턴하는 메서드.
|
||||
* @param source 원본 문자열
|
||||
* @param separator 분리자
|
||||
* @return result 분리자로 나뉘어진 문자열 배열
|
||||
*/
|
||||
public static String[] split(String source, String separator) throws NullPointerException {
|
||||
String[] returnVal = null;
|
||||
int cnt = 1;
|
||||
|
||||
int index = source.indexOf(separator);
|
||||
int index0 = 0;
|
||||
while (index >= 0) {
|
||||
cnt++;
|
||||
index = source.indexOf(separator, index + 1);
|
||||
}
|
||||
returnVal = new String[cnt];
|
||||
cnt = 0;
|
||||
index = source.indexOf(separator);
|
||||
while (index >= 0) {
|
||||
returnVal[cnt] = source.substring(index0, index);
|
||||
index0 = index + 1;
|
||||
index = source.indexOf(separator, index + 1);
|
||||
cnt++;
|
||||
}
|
||||
returnVal[cnt] = source.substring(index0);
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>{@link String#toLowerCase()}를 이용하여 소문자로 변환한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.lowerCase(null) = null
|
||||
* StringUtil.lowerCase("") = ""
|
||||
* StringUtil.lowerCase("aBc") = "abc"
|
||||
* </pre>
|
||||
*
|
||||
* @param str 소문자로 변환되어야 할 문자열
|
||||
* @return 소문자로 변환된 문자열, null이 입력되면 <code>null</code> 리턴
|
||||
*/
|
||||
public static String lowerCase(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return str.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>{@link String#toUpperCase()}를 이용하여 대문자로 변환한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.upperCase(null) = null
|
||||
* StringUtil.upperCase("") = ""
|
||||
* StringUtil.upperCase("aBc") = "ABC"
|
||||
* </pre>
|
||||
*
|
||||
* @param str 대문자로 변환되어야 할 문자열
|
||||
* @return 대문자로 변환된 문자열, null이 입력되면 <code>null</code> 리턴
|
||||
*/
|
||||
public static String upperCase(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return str.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>입력된 String의 앞쪽에서 두번째 인자로 전달된 문자(stripChars)를 모두 제거한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.stripStart(null, *) = null
|
||||
* StringUtil.stripStart("", *) = ""
|
||||
* StringUtil.stripStart("abc", "") = "abc"
|
||||
* StringUtil.stripStart("abc", null) = "abc"
|
||||
* StringUtil.stripStart(" abc", null) = "abc"
|
||||
* StringUtil.stripStart("abc ", null) = "abc "
|
||||
* StringUtil.stripStart(" abc ", null) = "abc "
|
||||
* StringUtil.stripStart("yxabc ", "xyz") = "abc "
|
||||
* </pre>
|
||||
*
|
||||
* @param str 지정된 문자가 제거되어야 할 문자열
|
||||
* @param stripChars 제거대상 문자열
|
||||
* @return 지정된 문자가 제거된 문자열, null이 입력되면 <code>null</code> 리턴
|
||||
*/
|
||||
public static String stripStart(String str, String stripChars) {
|
||||
int strLen;
|
||||
if (str == null || (strLen = str.length()) == 0) {
|
||||
return str;
|
||||
}
|
||||
int start = 0;
|
||||
if (stripChars == null) {
|
||||
while ((start != strLen) && Character.isWhitespace(str.charAt(start))) {
|
||||
start++;
|
||||
}
|
||||
} else if (stripChars.length() == 0) {
|
||||
return str;
|
||||
} else {
|
||||
while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != -1)) {
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
return str.substring(start);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>입력된 String의 뒤쪽에서 두번째 인자로 전달된 문자(stripChars)를 모두 제거한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.stripEnd(null, *) = null
|
||||
* StringUtil.stripEnd("", *) = ""
|
||||
* StringUtil.stripEnd("abc", "") = "abc"
|
||||
* StringUtil.stripEnd("abc", null) = "abc"
|
||||
* StringUtil.stripEnd(" abc", null) = " abc"
|
||||
* StringUtil.stripEnd("abc ", null) = "abc"
|
||||
* StringUtil.stripEnd(" abc ", null) = " abc"
|
||||
* StringUtil.stripEnd(" abcyx", "xyz") = " abc"
|
||||
* </pre>
|
||||
*
|
||||
* @param str 지정된 문자가 제거되어야 할 문자열
|
||||
* @param stripChars 제거대상 문자열
|
||||
* @return 지정된 문자가 제거된 문자열, null이 입력되면 <code>null</code> 리턴
|
||||
*/
|
||||
public static String stripEnd(String str, String stripChars) {
|
||||
int end;
|
||||
if (str == null || (end = str.length()) == 0) {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (stripChars == null) {
|
||||
while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
|
||||
end--;
|
||||
}
|
||||
} else if (stripChars.length() == 0) {
|
||||
return str;
|
||||
} else {
|
||||
while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != -1)) {
|
||||
end--;
|
||||
}
|
||||
}
|
||||
|
||||
return str.substring(0, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>입력된 String의 앞, 뒤에서 두번째 인자로 전달된 문자(stripChars)를 모두 제거한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.strip(null, *) = null
|
||||
* StringUtil.strip("", *) = ""
|
||||
* StringUtil.strip("abc", null) = "abc"
|
||||
* StringUtil.strip(" abc", null) = "abc"
|
||||
* StringUtil.strip("abc ", null) = "abc"
|
||||
* StringUtil.strip(" abc ", null) = "abc"
|
||||
* StringUtil.strip(" abcyx", "xyz") = " abc"
|
||||
* </pre>
|
||||
*
|
||||
* @param str 지정된 문자가 제거되어야 할 문자열
|
||||
* @param stripChars 제거대상 문자열
|
||||
* @return 지정된 문자가 제거된 문자열, null이 입력되면 <code>null</code> 리턴
|
||||
*/
|
||||
public static String strip(String str, String stripChars) {
|
||||
if (isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
|
||||
String srcStr = str;
|
||||
srcStr = stripStart(srcStr, stripChars);
|
||||
|
||||
return stripEnd(srcStr, stripChars);
|
||||
}
|
||||
|
||||
/**
|
||||
* 문자열을 지정한 분리자에 의해 지정된 길이의 배열로 리턴하는 메서드.
|
||||
* @param source 원본 문자열
|
||||
* @param separator 분리자
|
||||
* @param arraylength 배열 길이
|
||||
* @return 분리자로 나뉘어진 문자열 배열
|
||||
*/
|
||||
public static String[] split(String source, String separator, int arraylength) throws NullPointerException {
|
||||
String[] returnVal = new String[arraylength];
|
||||
int cnt = 0;
|
||||
int index0 = 0;
|
||||
int index = source.indexOf(separator);
|
||||
while (index >= 0 && cnt < (arraylength - 1)) {
|
||||
returnVal[cnt] = source.substring(index0, index);
|
||||
index0 = index + 1;
|
||||
index = source.indexOf(separator, index + 1);
|
||||
cnt++;
|
||||
}
|
||||
returnVal[cnt] = source.substring(index0);
|
||||
if (cnt < (arraylength - 1)) {
|
||||
for (int i = cnt + 1; i < arraylength; i++) {
|
||||
returnVal[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 문자열 A에서 Z사이의 랜덤 문자열을 구하는 기능을 제공 시작문자열과 종료문자열 사이의 랜덤 문자열을 구하는 기능
|
||||
*
|
||||
* @param startChr - 첫 문자
|
||||
* @param endChr - 마지막문자
|
||||
* @return 랜덤문자
|
||||
* @exception MyException
|
||||
* @see
|
||||
*/
|
||||
public static String getRandomStr(char startChr, char endChr) {
|
||||
|
||||
int randomInt;
|
||||
String randomStr = null;
|
||||
|
||||
// 시작문자 및 종료문자를 아스키숫자로 변환한다.
|
||||
int startInt = Integer.valueOf(startChr);
|
||||
int endInt = Integer.valueOf(endChr);
|
||||
|
||||
// 시작문자열이 종료문자열보가 클경우
|
||||
if (startInt > endInt) {
|
||||
throw new IllegalArgumentException("Start String: " + startChr + " End String: " + endChr);
|
||||
}
|
||||
|
||||
do {
|
||||
// 시작문자 및 종료문자 중에서 랜덤 숫자를 발생시킨다.
|
||||
randomInt = rnd.nextInt(endInt + 1);
|
||||
} while (randomInt < startInt); // 입력받은 문자 'A'(65)보다 작으면 다시 랜덤 숫자 발생.
|
||||
|
||||
// 랜덤 숫자를 문자로 변환 후 스트링으로 다시 변환
|
||||
randomStr = (char)randomInt + "";
|
||||
|
||||
// 랜덤문자열를 리턴
|
||||
return randomStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 문자열을 다양한 문자셋(EUC-KR[KSC5601],UTF-8..)을 사용하여 인코딩하는 기능 역으로 디코딩하여 원래의 문자열을
|
||||
* 복원하는 기능을 제공함 String temp = new String(문자열.getBytes("바꾸기전 인코딩"),"바꿀 인코딩");
|
||||
* String temp = new String(문자열.getBytes("8859_1"),"KSC5601"); => UTF-8 에서
|
||||
* EUC-KR
|
||||
*
|
||||
* @param srcString - 문자열
|
||||
* @param srcCharsetNm - 원래 CharsetNm
|
||||
* @param charsetNm - CharsetNm
|
||||
* @return 인(디)코딩 문자열
|
||||
* @exception MyException
|
||||
* @see
|
||||
*/
|
||||
public static String getEncdDcd(String srcString, String srcCharsetNm, String cnvrCharsetNm) {
|
||||
|
||||
String rtnStr = null;
|
||||
|
||||
if (srcString == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
rtnStr = new String(srcString.getBytes(srcCharsetNm), cnvrCharsetNm);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
rtnStr = null;
|
||||
}
|
||||
|
||||
return rtnStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 특수문자를 웹 브라우저에서 정상적으로 보이기 위해 특수문자를 처리('<' -> & lT)하는 기능이다
|
||||
* @param srcString - '<'
|
||||
* @return 변환문자열('<' -> "<"
|
||||
* @exception MyException
|
||||
* @see
|
||||
*/
|
||||
public static String getSpclStrCnvr(String srcString) {
|
||||
|
||||
String rtnStr = null;
|
||||
|
||||
StringBuffer strTxt = new StringBuffer("");
|
||||
|
||||
char chrBuff;
|
||||
int len = srcString.length();
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
chrBuff = srcString.charAt(i);
|
||||
|
||||
switch (chrBuff) {
|
||||
case '<':
|
||||
strTxt.append("<");
|
||||
break;
|
||||
case '>':
|
||||
strTxt.append(">");
|
||||
break;
|
||||
case '&':
|
||||
strTxt.append("&");
|
||||
break;
|
||||
default:
|
||||
strTxt.append(chrBuff);
|
||||
}
|
||||
}
|
||||
|
||||
rtnStr = strTxt.toString();
|
||||
|
||||
return rtnStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 응용어플리케이션에서 고유값을 사용하기 위해 시스템에서17자리의TIMESTAMP값을 구하는 기능
|
||||
*
|
||||
* @param
|
||||
* @return Timestamp 값
|
||||
* @exception MyException
|
||||
* @see
|
||||
*/
|
||||
public static String getTimeStamp() {
|
||||
|
||||
String rtnStr = null;
|
||||
|
||||
// 문자열로 변환하기 위한 패턴 설정(연도-월-일 시:분:초:초(자정이후 초))
|
||||
String pattern = "yyyyMMddhhmmssSSS";
|
||||
|
||||
SimpleDateFormat sdfCurrent = new SimpleDateFormat(pattern, Locale.KOREA);
|
||||
Timestamp ts = new Timestamp(System.currentTimeMillis());
|
||||
|
||||
rtnStr = sdfCurrent.format(ts.getTime());
|
||||
|
||||
return rtnStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* html의 특수문자를 표현하기 위해
|
||||
*
|
||||
* @param srcString
|
||||
* @return String
|
||||
* @exception Exception
|
||||
* @see
|
||||
*/
|
||||
public static String getHtmlStrCnvr(String srcString) {
|
||||
|
||||
String tmpString = srcString;
|
||||
|
||||
tmpString = tmpString.replaceAll("<", "<");
|
||||
tmpString = tmpString.replaceAll(">", ">");
|
||||
tmpString = tmpString.replaceAll("&", "&");
|
||||
tmpString = tmpString.replaceAll(" ", " ");
|
||||
tmpString = tmpString.replaceAll("'", "\'");
|
||||
tmpString = tmpString.replaceAll(""", "\"");
|
||||
|
||||
return tmpString;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>날짜 형식의 문자열 내부에 마이너스 character(-)를 추가한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.addMinusChar("20100901") = "2010-09-01"
|
||||
* </pre>
|
||||
*
|
||||
* @param date 입력받는 문자열
|
||||
* @return " - "가 추가된 입력문자열
|
||||
*/
|
||||
public static String addMinusChar(String date) {
|
||||
if (date.length() == 8) {
|
||||
return date.substring(0, 4).concat("-").concat(date.substring(4, 6)).concat("-")
|
||||
.concat(date.substring(6, 8));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>시간 형식의 문자열 내부에 character(:)를 추가한다.</p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtil.addColonChar("0000") = "00:00"
|
||||
* </pre>
|
||||
*
|
||||
* @param time 입력받는 문자열
|
||||
* @return ":"가 추가된 입력문자열
|
||||
*/
|
||||
public static String addColonChar(String time) {
|
||||
if (time.length() == 4) {
|
||||
return time.substring(0, 2).concat(":").concat(time.substring(2, 4));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 휴대폰번호를 전환한다.
|
||||
*
|
||||
* @param rawPhone EX) "+82 10-1234-5678"
|
||||
* @return DB에 넣을 번호
|
||||
*/
|
||||
public static String formatKoreanPhoneNumber(String rawPhone) {
|
||||
if (rawPhone == null || rawPhone.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Step 1: 공백 -> 하이픈, 숫자/하이픈만 남김
|
||||
String cleaned = rawPhone.replaceAll("\\s+", "-").replaceAll("[^0-9\\-]", "");
|
||||
|
||||
// Step 2: 국가번호 +82 → 0으로 변경
|
||||
if (cleaned.startsWith("82")) {
|
||||
cleaned = "0" + cleaned.substring(2);
|
||||
}
|
||||
|
||||
// Step 3: 하이픈 제거 후 숫자만 추출
|
||||
String digits = cleaned.replaceAll("-", "");
|
||||
|
||||
// Step 4: 패턴 매칭 및 하이픈 삽입
|
||||
String formatted;
|
||||
if (digits.matches("^01[016789]\\d{7,8}$")) {
|
||||
// 휴대폰
|
||||
formatted = digits.replaceFirst("(\\d{3})(\\d{3,4})(\\d{4})", "$1-$2-$3");
|
||||
|
||||
} else if (digits.matches("^02\\d{7,8}$")) {
|
||||
// 서울
|
||||
formatted = digits.replaceFirst("(02)(\\d{3,4})(\\d{4})", "$1-$2-$3");
|
||||
|
||||
} else if (digits.matches("^0\\d{2}\\d{7,8}$")) {
|
||||
// 지방 지역번호
|
||||
formatted = digits.replaceFirst("(0\\d{2})(\\d{3,4})(\\d{4})", "$1-$2-$3");
|
||||
|
||||
} else {
|
||||
return digits; // 매칭 안 되면 숫자만 반환
|
||||
}
|
||||
|
||||
// Step 5: 최종적으로 하이픈 제거
|
||||
return formatted.replaceAll("-", "");
|
||||
}
|
||||
}
|
||||
94
src/main/java/com/wb/domainserver/util/util/Util.java
Normal file
94
src/main/java/com/wb/domainserver/util/util/Util.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package com.wb.domainserver.util.util;
|
||||
|
||||
import com.wb.domainserver.util.string.StringUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Util {
|
||||
|
||||
/**
|
||||
* 값 비교후 checked 처리
|
||||
*
|
||||
* @param arg1 비교값 1
|
||||
* @param arg2 비교값 2
|
||||
* @return the string
|
||||
*/
|
||||
public static String setChecked(String arg1, String arg2) {
|
||||
return (arg1.equals(arg2)) ? " checked" : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 값 비교후 checked 처리
|
||||
*
|
||||
* @param arg1 the arg1
|
||||
* @param arg2 the arg2
|
||||
* @return the string
|
||||
*/
|
||||
public static String setChecked(boolean arg1,boolean arg2) {
|
||||
return (arg1 == arg2) ? " checked" : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 값 비교후 checked 처리
|
||||
*
|
||||
* @param arg1 the arg1
|
||||
* @param arg2 the arg2
|
||||
* @return the string
|
||||
*/
|
||||
public static String setChecked(int arg1,int arg2) {
|
||||
return (arg1 == arg2) ? " checked" : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 값 비교후 selected 처리
|
||||
*
|
||||
* @param arg1 비교값 1
|
||||
* @param arg2 비교값 2
|
||||
* @return the string
|
||||
*/
|
||||
public static String setSelected(String arg1, String arg2) {
|
||||
return (arg1.equals(arg2)) ? " selected" : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 값 비교
|
||||
*
|
||||
* @param arg1 the arg1
|
||||
* @param arg2 the arg2
|
||||
* @return the string
|
||||
*/
|
||||
public static String setCheckedArray(String[] arg1, String arg2) {
|
||||
|
||||
return Arrays.asList(arg1).contains(arg2) ? " checked" : "";
|
||||
}
|
||||
|
||||
public static String getDeviceType(HttpServletRequest request) {
|
||||
Object deviceTypeAttr = request.getAttribute("deviceType");
|
||||
return deviceTypeAttr != null ? deviceTypeAttr.toString() : "unknown";
|
||||
}
|
||||
|
||||
public static Map<String, String> getRequestInfo(HttpServletRequest request) {
|
||||
Map<String, String> requestInfo = new HashMap<>();
|
||||
|
||||
requestInfo.put("referer", request.getHeader("referer")); // 접속 경로
|
||||
requestInfo.put("userAgent", request.getHeader("User-Agent")); // 시스템 정보
|
||||
requestInfo.put("host", request.getHeader("host")); // 접속 ip
|
||||
|
||||
// 접속 ip
|
||||
String clientIp = request.getHeader("X-Forwarded-For");
|
||||
if (!StringUtil.isEmpty(clientIp) && clientIp.contains(",")) {
|
||||
clientIp = clientIp.split(",")[0];
|
||||
}
|
||||
|
||||
if (StringUtil.isEmpty(clientIp)) {
|
||||
clientIp = request.getRemoteAddr();
|
||||
}
|
||||
requestInfo.put("XForwardedFor", clientIp); // 클라이언트 ip 주소
|
||||
|
||||
return requestInfo;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user