jaxb xml Unmarshaller

JAVA 2022. 2. 28. 16:37

프로젝트 준비 중 기존 소스에서 내부 api 수신시 xml기반으로 수신을 하게 되어 있어 관련 내용을

소스로 정리 합니다.

jaxb 패키지를 이용해서 unmarshal을 진행 하는 소스 이고 간단한 테스트를 위해 아직 xml로 서비스

하는 공공데이터 포털의 데이터를 이용 합니다.

 

테스트 url은 아래와 같습니다.

https://www.data.go.kr/data/15056803/openapi.do

 

한국공항공사_전국공항 실시간 주차정보

한국공항공사에서 운영하고 있는 전국공항 실시간 주차정보 서비스

www.data.go.kr

해당 데이터를 기준으로 수집을 위해 아래 소스를 작성 했습니다.

package com.unmarshalling;

import java.io.StringReader;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(1)
@Component
public class AirportParkingInfo  implements ApplicationRunner{

	@Override
	public void run(ApplicationArguments args) throws Exception {
		HttpClient client 				= HttpClientBuilder.create().build();
        HttpGet request 				= new HttpGet("http://openapi.airport.co.kr/service/rest/AirportParking/airportparkingRT?serviceKey=");
        
        HttpResponse response 	= client.execute(request);
        HttpEntity entity 				= response.getEntity();
        

        String returnXml 				= EntityUtils.toString(entity, "UTF-8");
        
        System.out.println("returnXml: "+returnXml);
        
        //getter사용하는 경우 counts of IllegalAnnotationExceptions 관련 에러가 발생 될 수 있음
        //@XmlAccessorType 과 관련된 문제 인데 get, set이 필드맵핑과 연결 되기 때문에 변수명이 element명과 같은 경우 동일한 key로 생각 되서 에러가
        //발생됨 테스트 소스 이기 때문에 get없이 변수에 바로 접근
        //get메소드를 만드는 경우 https://code.google.com/archive/p/smw2010-prj3-rest/wikis/JAXBSummary.wiki 참고
        
        JAXBContext jaxbContext 		= JAXBContext .newInstance(XmlResponse.class);
        Unmarshaller unmarshaller 	= jaxbContext.createUnmarshaller();
        
        XmlResponse xmlResponse 	= (XmlResponse)unmarshaller.unmarshal(new StringReader(returnXml));
        
        List<XmlItem> xmlItemList = xmlResponse.bodyInfo().itemsInfo().itemList();
        for(XmlItem tempInfo:xmlItemList) {
        	System.out.println("aprKor: "+tempInfo.aprKor);
        	System.out.println("parkingFullSpace: "+tempInfo.parkingFullSpace);
        }
	}
}

xml element의 구종에 맞춰서 vo를 작성 하면 xml<->object를 자동으로 맵핑 해주기 때문에 아주 편리 합니다.

vo정보는 첨부한 파일을 보면 됩니다.

xml_vo.zip
0.00MB

테스트로 사용한 어노테이션은 2개만 있습니다.

 

@XmlRootElement(name="response") <- 최상위 노드를 지정 합니다.

@XmlElement(name = "body") <- 데이터 맵핑할 노드 정보를 지정 합니다.

복수의 자식 노드들을 지정 하는 경우 

@XmlElement(name = "item")
public List<XmlItem> xmlItemList;

같이 선언 해주는 것으로 맵핑을 해주기 때문에 xml데이터를 가지고 오기 좋습니다.

반응형
Posted by 질주하는구
,

java11에서 jaxb Unmarshaller 를 사용하려고 할때 해당 클래스를 찾지 못하는 에러가 나는경우

아래의 패키지를 추가 해줘야 합니다.

 

implementation 'javax.xml.bind:jaxb-api' 
implementation 'org.glassfish.jaxb:jaxb-runtime' 
implementation 'javax.activation:activation:1.1.1'

 

java11부터는 jaxb관련 라이브러리가 없기 때문에 추가가 필요 합니다.

(8버전 까지는 정상적으로 사용이 가능 합니다. 9버전은 vm옵션 추가로 사용 가능 합니다.)

반응형

'JAVA' 카테고리의 다른 글

jaxb xml Unmarshaller  (0) 2022.02.28
java custom validation 추가  (0) 2022.02.14
@Retention 간략 설명  (0) 2022.02.14
java 정규식 개인정보 마스킹  (0) 2022.02.09
엑셀 날짜(date) 형식 컬럼 처리  (0) 2021.11.29
Posted by 질주하는구
,

java custom validation 추가

JAVA 2022. 2. 14. 15:11

작업 중 javax.validation 기본 규칙 이외에 추가로 규칙을 정의 해야 하는 경우 아래와 같은 방식으로 정의 할 수 있습니다.

(전자정부 apache-common-validation은 xml에 소스 작업을 하면 view 부분까지 모두 정의가 가능 한데... 하다가 마음에 안들면 전자정부 형식으로 변경 하려고 합니다.)

 

우선 사용할 validation 어노테이션을 정의 해줍니다.

 


import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

import egovframework.validation.PasswordValidator;

@Documented
@Target({ FIELD, METHOD })
@Constraint(validatedBy = PasswordValidator.class) //검증에 사용할 class정보를 정의 해당 클래스의 isValid 메소드를 통해서 데이터 검증 진행
//@Retention은 해당 어노테이션의 생명주기를 정의 합니다.
/*
RetentionPolicy.SOURCE : 소스 코드(.java)까지 남아있는다
RetentionPolicy.CLASS : 클래스 파일(.class)까지 남아있는다.(=바이트 코드)
RetentionPolicy.RUNTIME : 런타임까지 남아있는다.(=사실상 안 사라진다.)

SOURCE => lombok의 @getter, @setter 어노테이션의 경우 해당 설정으로 되어 있어 소스 작업시에는 보이지만 해당 소스가 class파일이 되면 해당 어노테이션은 삭제 되고
get, set 메소드가 class파일에 생성 되게 됩니다.
CLASS => @notnull의 경우 해당 합니디 .jar작업 시에도 해당 어노테이션이 살아 있어야 한다면 class로 설정 해줍니다. log4j등에서 @notnull
을 사용하게 되는데 이 경우 해당 정보는 java->class로 변경시 null체크만 추가 되는게 아닌 배포시에도 유의미 해야 하기 때문에 해당 설정으로 처리 합니다.
(배포형 소스가 아니라면 사용할 일이 거의 없습니다.)
RUNTIME => @Controller, @Service, @Autowired 같이 서비스가 실행 중일때도 확인이 가능한 어노테이션의 경우(해당 예시의 어노테이션은 서버 실행시 spring객체에 어노테이션 정보를 기준으로
데이터를 수집하고 직렬화 하기 때문에 runtime으로 되어 있습니다)
* */
@Retention(RetentionPolicy.RUNTIME)
public @interface PasswordCheck {
	//기본 내용 시작
	String message() default "비밀번호 양식을 확인 해주세요"; //validation이 실패할 경우 반환되는 default 메세지
    Class<?>[] groups() default {}; //특정 validation을 group을 지정하는 값( Validation Grouping )
    Class<? extends Payload>[] payload() default {}; //사용자가 추가 정보를 위해 전달할 수 있는 값으로 주로 심각도를 나타낼 때 사용됩니다.
    //기본 내용 끝
    //상단의 기본 내용은 어노테이션 작성시 반드시 들어가야 하는 내용으로 ConstraintHelper가 확인 하게 되어있습니다.
}

 

그리고 검증에 사용할 구현 소스를 정의 해줍니다.

 

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.apache.commons.lang.StringUtils;

import egovframework.validation.annotation.PasswordCheck;

public class PasswordValidator implements ConstraintValidator<PasswordCheck, String> {

	@Override
	public void initialize(PasswordCheck constraintAnnotation) {
	}

	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
//체크로직 구현
		return false;
	}

}

위에 정의한 어노테이션을 원하는 곳에 추가 해주면 됩니다.

https://wedul.site/562

 

Custom Validation 만들어서 추가하기

Spring에서 @NotBlank, @Email등 여러 템플릿에 맞게 Validation을 넣을 수 있다. 하지만 추가적으로 패스워드 규칙과 같이 별도 체크할 validator가 필요할 때 만들어서 사용해야 하는데 만들어서 지정해보

wedul.site

https://devonce.tistory.com/42

 

[Spring Boot] Custom Constraint / Validation 파헤치기

이번 글에서는 Spring Boot에서 validation이 동작하는 원리를 간단하게 살펴보고 직접 validator를 정의하는 방법을 정리해보겠습니다. 참고로, validation에 대한 설명을 따로 하지는 않기 때문에 validation

devonce.tistory.com

https://bamdule.tistory.com/107

 

[Spring Boot] ConstraintValidator Custom 하기

Spring에서 JSR 303 어노테이션을 이용해 데이터 유효성검사를 진행할 수 있습니다. 보통 @NotBlank, @Size, @NotNull ...등 이미 만들어진 검증 어노테이션을 이용할 수 있지만, 자신의 목적에 맞는 검증 어

bamdule.tistory.com

 

반응형
Posted by 질주하는구
,

@Retention 간략 설명

JAVA 2022. 2. 14. 14:38

소스 작업 중 validation을 추가 하기 위해 작업 하다 어노테이션 상단의 @Retention 을 보고 정리한 내용 입니다.

작업 중 어노테이션을 추가 해야 하는 경우가 많은건 아니겠지만 알아 두면 좋은 내용으로 생각 되어 정리 합니다.

 

@Retention 어노테이션은 생명주기를 정의 합니다.

 

SOURCE, CLASS, RUNTIME 3가지로 나누어 지며 이중 가능 이해하기 쉬운 2가지인 SOURCE, RUNTIME의 경우

 

SOURCE = .JAVA소스 작업시에만 해당 어노테이션 확인이 가능 합니다. java->class파일로 변환시 어노테이션은 삭제되고 실제 동작하는 소스로 변경 되게 됩니다. lombok의 @getter, @setter 등이 해당 합니다.

class파일로 변경 되며 getter, setter 어노테이션은 실제 get(), set()메소드로 치환되고 사라지게 됩니다.

 

RUNTIME = 서비스중, 서버기동 중에도 해당 어노테이션이 유지 됩니다. @Controller, @Service, @Autowired같은 어노테이션은 서버 기동중 확인이 필요한 정보들로 유지 되어야 하기 때문에 RUNTIME으로 설정을 하게 되고 

제가 작업한 validation 어노테이션 역시 해당 설정으로 작업 했습니다.

 

CLASS 의 경우(@notnull이 해당합니다.) 한 블로그 댓글에 친절하게 설명이 되어 있어 링크를 걸어 놓습니다.

https://jeong-pro.tistory.com/234

 

아무 관심 없던 @Retention 어노테이션 정리(RetentionPolicy SOURCE vs CLASS vs RUNTIME)

@Retention annotation 관심 갖게 된 이유 자바에서 지향하는 방법은 아니지만 필요에 의해서 커스텀 애노테이션(Annotation)을 만들어야 할 때가 있습니다. 보통 예제 샘플 코드를 보면 메타 애노테이션

jeong-pro.tistory.com

보면 이해가 되는데 설명은 안되는거 보면 정확하게 이해를 못한거 같습니다.

대충 이해한 내용은 .jar같은 배포 소스의 경우 java소스가 없기 때문에 배포 후 체크해야 하는 사항의 경우 class로

설정 한다고 합니다. class가 올라오면서 행위가 이루어 져야 하는 경우(이런 경우는 뭘까...)도 포함 된다고 하네요

 

반응형
Posted by 질주하는구
,

개인정보 마스킹에 사용할 java정규식 정리

 

1. 주민번호

ex> 811008-1000000 -> 811008-1******

tempStr.replaceAll("(.{6}$)", "******") => 6자리 숫자로 끝나는 문자를 * 6자리로 변경

tempStr = "저의 주민번호는 801208-1000000 입니다.";

- 숫자6자리-1~4한자리숫자6자리 정보중 마지막6자리를 *으로 변경
tempStr.replaceAll("([0-9]{6})-([1-4]{1})([0-9]{6})", "$1-$2******");

 

2. 전화번호

ex> 010-0000-0000 -> 010-****-0000

tempStr.replaceAll("-[0-9]{4}-", "-****-") => -으로 시작하고 4자리 숫자-으로 끝나는 문장을 -****- 으로 변경

 

ex> 010-0000-0000 -> 010-0000-****

tempStr.replaceAll("-[0-9]{4}$", "-****") => -으로 시작하고 4자리 숫자로 끝나는 부분을 -**** 으로 변경

 

3. 이메일

ex> test12345@naver.com -> ******@naver.com

tempStr.replaceAll("[a-z,A-Z,0-9]+@", "******@") => @이 마지막에 포함된 문장을 *****@으로 변경

->주간만 변경 해야 하는경우가 있어서 갱신 예정

 

4. 이름

ex> 홍길동 -> 홍길* or 홍**

tempStr.replaceAll("(?<=.{2}).", "*") => 길이 기준으로 2글자 이후의 문자는 *으로 변경

tempStr.replaceAll("(?<=.{1}).", "*") => 길이 기준으로 1글자 이후의 문자는 *으로 변경

앞에만 변경 하려는 경우

tempStr.replaceAll(".(?=.{2})", "*") => 길이 기준으로 2글자 남기고 앞에만 *으로 변경(*길동)

위에서 사용한 정규식의 경우 전방탐색, 후방탐색에 해당하는 내용으로 아래의 내용을 참고해서 좀더 검색 하면 다른

부분에도 활용 가능 합니다.

(

(?=) 긍정형 전방탐색
(?!) 부정형 전방탐색
(?<=) 긍정형 후방탐색
(?<!) 부정형 후방탐색

)

 

5. 여권번호

ex> M12345678 -> M1234****

- M으로 시작하고(^인자를 넣으면 진짜 문장의 시작값 이어야 해서 처리 안함) 숫자로된 4자리와 이어진 숫자4자리의 문장의 경우 뒤의 숫자4자리를 ****으로 변경
tempStr = tempStr.replaceAll("(M[0-9]{4})([0-9]{4})", "$1****");

 

ex> TJ 0012345 T* 0012***
tempStr = "여권번호 TJ 0012345 입니다.";
- 영문2글자로 시작하고 가운데 공백 숫자7자리인 정보를 영문+영문 숫자4+숫자3 기준으로 나눠서 2,4마스킹
tempStr = tempStr.replaceAll("([A-Z])([A-Z])\\s([0-9]{4})([0-9]{3})", "$1* $3***");

 

6. 운전면허

ex> 서울12-123456-78 → 서울1*-1234**-*8
//한글2자리+숫자1자리+숫자1자리-숫자4자리+숫자2자리-숫자1자리+숫자1자리 에 맞는 정보를 치환 [0-9]는 너무 길어 지니까 \\d 로 사용
tempStr = tempStr.replaceAll("([가-힣]{2})(\\d{1})(\\d{1})-(\\d{4})(\\d{2})-(\\d{1})(\\d{1})", "$1$2*-$4**-*$7");

 

7. 카드번호 

ex> 4000-1234-5678-0000 -> 40000-****-****-0000

tempStr.replaceAll("(\\d{4})-(\\d{4})-(\\d{4})-(\\d{4})", "$1-****-****-$4")

=> 4글자 기준 형식에 맞춰서 가운데 부분만 ****으로 변경 $1, $4의 경우 앞의 정규식 () 기준 문장의 순서를 의미 합니다. ()가 4개로 구성 되어 있어 $1, $2, $3, $4로 정의 할 수 있습니다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/RegExp/n

 

RegExp.$1-$9 - JavaScript | MDN

비표준 $1, $2, $3, $4, $5, $6, $7, $8, $9 속성들은 정적이며, 괄호로 묶인 하위 문자열 match들을 포함하는 정규 표현식의 읽기 전용 속성들입니다.

developer.mozilla.org

마스킹 방식의 경우 단어를 쪼개서 조합하는 방식으로 처리 하게 되면서 비표준(javascript기준 지원 브라우저 확인 필요) 방식을 사용합니다. 마스킹 처리를 하지 않고 체크만 하는 경우에는 더 간단하게 패턴을 정의 할 수 있습니다.

이 부분은 추가 작업 예정 입니다.

반응형

'JAVA' 카테고리의 다른 글

java custom validation 추가  (0) 2022.02.14
@Retention 간략 설명  (0) 2022.02.14
엑셀 날짜(date) 형식 컬럼 처리  (0) 2021.11.29
Jwts 에러 발생시 확인 사항  (0) 2021.11.25
Base64 한글 인코딩(한글깨짐)  (0) 2021.11.22
Posted by 질주하는구
,

엑셀 데이터 처리 중 날짜(date)형의 경우 44470(2021-10-01)과 같이 넘어 오게 되는데 이 경우 

해당 데이터(CELL_TYPE_NUMERIC)를 날짜 형식에 맞게 변환 하려면

 

DateUtil.isCellDateFrmatted(cell) 함수를 사용해서 날짜 형식인지 확인 후 

Date tempDate = cell.getDateCellValue();

new SimpleDateFormat("yyyy-MM-dd").format(tempDate);

처럼 변경 하는 작업을 거쳐야 합니다.

반응형

'JAVA' 카테고리의 다른 글

@Retention 간략 설명  (0) 2022.02.14
java 정규식 개인정보 마스킹  (0) 2022.02.09
Jwts 에러 발생시 확인 사항  (0) 2021.11.25
Base64 한글 인코딩(한글깨짐)  (0) 2021.11.22
OS 환경 변수 가지고 오기  (0) 2021.11.08
Posted by 질주하는구
,

jwts이용한 토큰 생성 및 검증시 아래와 같은 에러가 발생되는 경우 확인 해야 하는 사항들 입니다.

 

A signing key must be specified if the specified JWT is digitally signed

이 에러의 경우 secret key 등록시 해당 정보를 일반 평문으로 주는 경우 발생되는 에러 입니다.

 

String secretKey  ="A";
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());

와 같이 base64로 인코딩 해준뒤 key등록을 해줘야 합니다

https://stackoverflow.com/questions/41661821/java-lang-illegalargumentexception-a-signing-key-must-be-specified-if-the-speci

 

java.lang.IllegalArgumentException: A signing key must be specified if the specified JWT is digitally signed

I'm looking to implement JWT in my application for that I'm doing some R&D on it by taking a reference from : https://stormpath.com/blog/jwt-java-create-verify. I was successfully able to imple...

stackoverflow.com

 

JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted

에러가 발생되는 경우

해당 에러는 토큰 검증시 시간이 만료되거나 key가 변경되어 맞지 않거나(간혹 데이터 전송중 특수문자가 들어가는 등의 문제가 생겨 해당 에러를 보는 분들이 있습니다.) 할때 발생되는 문제 입니다.

데이터 확인 시 전달 받은 토큰과 확인 하려는 토큰이 완전 동일한 경우

 

 Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);

이렇게 코딩 되어 있는건 아닌지 확인 해봐야 합니다. 

setSigningKey부분에 key설정 시 

Base64.getEncoder().encodeToString(secretKey.getBytes());

과 같이 getBytes를 해줘야 정상적으로 인증 되게 되어 있습니다.(secret key 설정시 byte로 등록 후 검증시 string으로 넘겨줘서 key가 달라서 검증 오류가 발생 되는거 같습니다.)

 

 

String secretKey  ="A";
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());

long tokenValidMilisecond = 1000L * 60 * 60;

Map<String, Object> headers = new HashMap<>();
headers.put("typ", "JWT"); // Type 설정
headers.put("alg", "HS256"); // HS256는 해시 알고리즘의 일종으로, base64와 같이 임의로 디코딩을 할 수 없다.

Date ext = new Date(); // 토큰 만료 시간
ext.setTime(ext.getTime() + tokenValidMilisecond);

Map<String, Object> payloads = new HashMap<>();
payloads.put("data", "test"); // API 용도에 맞게 properties로 관리하여 사용하는것을 권장한다.
payloads.put("exp", ext);

String jwt = Jwts.builder()
.setHeader(headers) 		// Headers 설정
.setClaims(payloads) 		// Claims 설정
.setSubject("user-auth")	// 토큰 용도  
.setExpiration(ext) 		// 토큰 만료 시간 설정
.signWith(SignatureAlgorithm.HS256, secretKey.getBytes()) // HS256과 Key로 Sign
.compact(); // 토큰 생성


Jws claims = Jwts.parser().setSigningKey(secretKey.getBytes()).parseClaimsJws(jwt);

System.out.println(claims.getBody().getExpiration().before(new Date()));
반응형
Posted by 질주하는구
,

Base64로 데이터를 주고 받아 한글이 깨지는 경우가 있어 관련한 내용을 정리 합니다.

 


String temp				= "테스트";
byte[] tempBytes		= temp.getBytes("UTF-8"); //getBytes시 인코딩 지정

//인코딩
Encoder encoder			= Base64.getEncoder();

byte[] encodByte		= encoder.encode(tempBytes);
System.out.println(new String(encodByte));

String encodString		= encoder.encodeToString(tempBytes);
System.out.println(encodString);

//디코딩
Decoder decoder			= Base64.getDecoder();

byte[] decodByte1		= decoder.decode(encodByte);
byte[] decodByte2		= decoder.decode(encodString);

String decodString		= new String(decodByte1, "EUC-KR");//String 생성시 인코딩 지정
System.out.println(decodString);

System.out.println(new String(decodByte2, "UTF-8"));//String 생성시 인코딩 지정

인코딩 디코딩 작업 시 charsetName이 다른 경우 아래와 같은 실행 결과가 출력 됩니다.

7YWM7Iqk7Yq4
7YWM7Iqk7Yq4
���ㅽ��
테스트

 

반응형

'JAVA' 카테고리의 다른 글

엑셀 날짜(date) 형식 컬럼 처리  (0) 2021.11.29
Jwts 에러 발생시 확인 사항  (0) 2021.11.25
OS 환경 변수 가지고 오기  (0) 2021.11.08
stream LinkedList filter cannot be cast  (0) 2021.11.04
Integer to Date java  (0) 2021.11.01
Posted by 질주하는구
,

작업중 OS의 환경변수(path)등의 정보를 가지고 와야 하는경우

System.getenv() 소스를 이용해서 데이터를 가지고 올 수 있습니다.

 

전체 환경변수: System.getenv(); -> Map<String,String>

특정 NAME(GoLand)의 변수 정보: System.getenv("GoLand"); -> String(C:\JetBrains\GoLand 2021.2.3\bin;)

반응형

'JAVA' 카테고리의 다른 글

Jwts 에러 발생시 확인 사항  (0) 2021.11.25
Base64 한글 인코딩(한글깨짐)  (0) 2021.11.22
stream LinkedList filter cannot be cast  (0) 2021.11.04
Integer to Date java  (0) 2021.11.01
okhttp 사용(파라미터 전달)  (0) 2021.10.27
Posted by 질주하는구
,

LinkedList 데이터를 stream filter 를 이용해서 원하는 데이터만 가지고 오는 경우 아래와 같이 형변환을 해줘야 합니다.

 

LinkedList<TelMessVO> clone2 = clone.stream().filter(telMessVO -> telMessVO.getMessText().indexOf("test")!=-1).collect(Collectors.toCollection(LinkedList::new));

 

혹은

 

LinkedList<TelMessVO> clone2 = new LinkedList<TelMessVO>(clone.stream().filter(telMessVO -> telMessVO.getMessText().indexOf("test")!=-1).collect(Collectors.toList()));

 

Collectors.toList() 를 호출하는 경우 결과가 ArrayList로 넘어오기 때문에 해당 데이터를 LinkedList로 

변경 하는 작업이 필요 합니다.

 

for(TelMessVO tempData : clone2) {
   System.out.println(tempData);
}

반응형
Posted by 질주하는구
,