Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- renameTo
- TRANCOUNT
- getChannel()
- SQLSTATE=42705
- java
- 아이
- transferTo
- dm_exec_requests
- 홈스쿨링
- 요약
- 앵커멤버
- 자바
- 재귀멤버
- 디스패처서블릿
- SQL
- 요청매핑
- ERROR_MESSAGE
- XACT_STATE
- 튜닝
- XWPF
- 진경혜
- HWPF
- git
- MSSQL
- 프론트컨트롤러
- 스프링
- 함수
- 배치
- spring
- 교육법
Archives
- Today
- Total
필기노트
JAVA 전문 생성과 파싱(반복, 저장, XML) 본문
반응형
reference 점프 투 자바 - B1 전문 생성과 파싱 https://wikidocs.net/266
전문 생성과 파싱에 대한 내용은 위 글에서 너무 잘 설명하고 있어서 생략한다.
본 글은 위 글에서 3가지를 더 할 것이다.
1. 반복구간을 설정하고 반복구간만큼 파싱하는 방법
2. 파싱한 데이터를 테이블에 저장하는 방법
3. XML을 파싱해서 객체를 생성하는 방법
총 6개의 파일이 존재한다.
1. SubItem.java - 반복구간을 파싱하기 위한 객체
4. LoadXml.java - XML을 파싱해서 Packet 객체를 생성한다.
5. Packet.java - Item 객체들을 담는다.
6. FullText.java - 전문을 요청하고 응답을 받는다.
1. SubItem
public class SubItem {
private String id;
private String name;
private int length;
private String value;
private String field;
private String type;
private ArrayList<String> values = new ArrayList<>();
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getLength() { return length; }
public void setLength(int length) { this.length = length; }
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
public String getField() { return field; }
public void setField(String field) { this.field = field; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getValues(int i) { return values.get(i); }
public void addValues(String value) { this.values.add(value); }
public String raw() {
StringBuffer padded = new StringBuffer(this.value);
while (padded.toString().getBytes().length < this.length) {
padded.append(" ");
}
return padded.toString();
}
}
- private String field; -> 데이터베이스에 저장하기 위한 필드명 속성이 추가되었다.
- private String type; -> 데이터베이스에 저장하기 위한 필드타입 속성이 추가되었다. (문자 or 숫자)
- private ArrayList<String> values -> 파싱한 반복구간 필드의 값들을 가변으로 담는다.
2. Item
public class Item extends SubItem {
private boolean group;
private int count;
private String table;
private ArrayList<SubItem> subItems = new ArrayList<>();
public boolean getGroup() { return group; }
public void setGroup(boolean group) { this.group = group; }
public int getCount() { return count; }
public void setCount(int count) { this.count = count; }
public String getTable() { return table; }
public void setTable(String table) { this.table = table; }
public ArrayList<SubItem> getSubItems() { return subItems; }
public void setSubItems(ArrayList<SubItem> subItems) { this.subItems = subItems; }
public static Item create( String id, String name, int length, String value
, boolean group
, String table, String field, String type ) {
Item item = new Item();
item.setId(id);
item.setName(name);
item.setLength(length);
item.setValue(value);
item.setGroup(group);
item.setTable(table);
item.setType(type);
item.setField(field);
return item;
}
}
- public class Item extends SubItem // 반복구간을 추가하면서 기존의 Item 속성들을 SubItem으로 상속 받고 있다.
- private ArrayList<SubItem> subItems // 또한 ArrayList로 SubItem에 반복구간의 항목들을 가변으로 담는다.
- private boolean group; // 반복구간이 존재하는지 여부를 판단한다.
- private int count; // 반복구간의 수를 저장한다.
- private String table; // 반복구간의 데이터를 저장하기 위한 테이블을 저장한다.
3. cust.xml
<?xml version="1.0" encoding="UTF-8"?>
<msg>
<input>
<item id="name" name="이름" length="20" />
<item id="jumin" name="주민번호" length="13" />
</input>
<output table="tbl">
<item id="name" name="이름" length="20" field="WH001" type="C" />
<item id="jumin" name="주민번호" length="13" field="WH002" type="C" />
<item id="nbr_cnt" name="전화번호 건수" length="3" field="WH003" type="N" />
<item group="nbr_grp" name="전화번호 그룹" length="3" table="tblnbr">
<item id="type" name="타입" length="3" field="WN001" type="C" />
<item id="number" name="번호" length="11" field="WN002" type="C" />
</item>
<item id="adr_cnt" name="주소 건수" length="3" field="WH004" type="N" />
<item group="adr_grp" name="주소 그룹" length="3" table="tbladr">
<item id="type" name="타입" length="3" field="WJ001" type="C" />
<item id="juso" name="주소" length="50" field="WJ002" type="C" />
</item>
</output>
</msg>
- XML에 전문을 정의해서 파싱함으로써 동적으로 객체를 생성해 주고 전문 가독성 또한 올라가고 유지보수에 용이해진다.
- recvPacket.addItem(Item.create("주소", 50, null)); // 기존에는 이렇게 직접 객체를 생성.
- <input> // 요청 전문을 정의하고 있다.
- <output> // 응답 전문을 정의하고 있다.
- table // 데이터베이스에 저장할 테이블명을 명시하고 있다.
- field // 데이터베이스에 저장할 필드명을 명시하고 있다.
- type // 데이터베이스에 저장할 때 필드의 타입을 명시하고 있다. (C(har) -> 문자, N(umeric) -> 숫자)
- nbr_cnt, nbr_grp // 전화번호 그룹 데이터가 오기 전에는 전화번호 건수를 먼저 받기로 정의되어 있다.
4. LoadXml
public class LoadXml {
private Packet reqPckt = new Packet();
private Packet resPckt = new Packet();
public Packet getReqPckt() {
return reqPckt;
}
public Packet getResPckt() {
return resPckt;
}
public LoadXml(String pathname) {
try {
// 파일경로
File file = new File(pathname);
// 파일읽기
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dbuilder = dbFactory.newDocumentBuilder();
Document doc = dbuilder.parse(file);
Element root = doc.getDocumentElement();
if (root.hasChildNodes()) {
NodeList nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
String nodeName = nodes.item(i).getNodeName();
if(nodeName.equals("input"))
readNode(nodes.item(i), reqPckt);
else if(nodeName.equals("output"))
readNode(nodes.item(i), resPckt);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
. . . (생략)
}
- DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); // 팩토리 생성
- DocumentBuilder dbuilder = dbFactory.newDocumentBuilder(); // 팩토리로부터 빌더 생성
- Document doc = dbuilder.parse(file); // 빌더를 통해 XML 문서를 파싱해서 Document 객체로 가져온다.
- Element root = doc.getDocumentElement(); // 최상위 노드 가져오기 -> <msg>
- if (root.hasChildNodes()) { // 자식 노드를 가지고 있는지 확인
- NodeList nodes = root.getChildNodes(); // 자식 노드들을 노드리스트에 담는다. -> <input>, <output>
- for (int i = 0; i < nodes.getLength(); i++) { // 노드 길이만큼 반복
- String nodeName = nodes.item(i).getNodeName(); // 해당 노드의 태그 값을 가져온다.
- if(nodeName.equals("input")) readNode(nodes.item(i), reqPckt); // <input>이냐 <output>이냐에 따라 다른 Packet에 담아준다.
readNode
public class LoadXml {
. . . (생략)
private static void readNode(Node node, Packet packet, boolean is_group) {
Map<String, String> map = new HashMap<>();
boolean group = false;
if (node.hasAttributes()) {
Element element = (Element) node;
String id = element.getAttribute("id");
String name = element.getAttribute("name");
int length = element.getAttribute("length").equals("") ? 0 : Integer.parseInt(element.getAttribute("length"));
group = element.getAttribute("group").equals("") ? false : true;
String table = element.getAttribute("table");
String field = element.getAttribute("field");
String type = element.getAttribute("type");
if (node.getNodeName().equals("output"))
packet.setTable(table);
else if (is_group == false)
packet.addItems(Item.create(id, name, length, null, group, table, field, type));
else if (is_group == true)
packet.getItem(packet.getItemsSize()-1).getSubItems()
.add(Item.create(id, name, length, null, false, table, field, type));
}
if (node.hasChildNodes()) {
NodeList childs = node.getChildNodes();
for (int i = 0; i < childs.getLength(); i++) {
Node child = childs.item(i);
readNode(child, packet, group);
}
}
}
}
- if (node.hasAttributes()) { // 해당 노드에 속성이 있는지 본다.
- Element element = (Element) node; // 노드를 엘리먼트로 치환시키고
- String id = element.getAttribute("id"); // 해당 속성들을 받아온다.
- if (node.getNodeName().equals("output")) packet.setTable(table); // 응답전문 항목들의 테이블은 Item의 상위 객체인 Packet 객체에 저장해야 한다. (반복구간 항목들의 테이블은 subItem의 상위 객체인 Item에 저장)
- else if (is_group == false) // 반복구간이 아닐 땐 아래와 같은 Packet 객체를 생성한다.
packet.addItems(Item.create(id, name, length, null, group, table, field, type)); - else if (is_group == true) // 반복구간의 항목을 객체생성 할 때는 마지막 Item을 가지고 온다. (반복구간을 readNode 하기 전에 마지막에 생성된 Item은 그룹아이템이기 때문), 가지고 온 마지막 Item의 subItem에 반복구간의 항목을 아래와 같이 객체 생성한다.
packet.getItem(packet.getItemsSize()-1).getSubItems().add(Item.create(id, name, length, null, false, table, field, type)); - if (node.hasChildNodes()) { // 해당 노드의 자식 노드들이 있는지 본다.
- for (int i = 0; i < childs.getLength(); i++) Node child = childs.item(i); // 해당 노드의 자식노드들을 하나씩 Node로 가져온다.
- readNode(child, packet, group); // 가져온 노드를 readNode로 재귀함수 호출
5. Packet
public class Packet {
private ArrayList<Item> items = new ArrayList<Item>();
private String table;
public ArrayList<Item> getItems() { return items; }
public void addItems(Item item) { this.items.add(item); }
public Item getItem(int index) { return items.get(index); }
public int getItemsSize() { return items.size(); }
public String getTable() { return table; }
public void setTable(String table) { this.table = table; }
public String raw() {
StringBuffer result = new StringBuffer();
for (Item item : items) {
result.append(item.raw());
}
return result.toString();
}
public void set(Map<String, String> map) {
for (String key : map.keySet()) {
for (Item item : items) {
if (item.getId().equals(key)) {
item.setValue(map.get(key));
}
}
}
}
public void allPrint() {
for (Item item : items) {
if (item.getGroup() == false) {
System.out.println("name : " + item.getName() + " , value : " + item.getValue());
} else {
if (item.getCount() == 0)
System.out.println("name : " + item.getName() + " , value : " + item.getValue());
for (int i = 0; i < item.getCount(); i++) {
for (SubItem subItem : item.getSubItems())
System.out.println("name : " + subItem.getName() + " , value : " + subItem.getValues(i));
}
}
}
}
}
- private String table; // 응답전문의 데이터를 저장하기 위한 테이블 속성이 추가되었다.
- set(Map<string, string> map) // 전문 요청을 하고자 하는 항목의 id와 value를 map에 태워서 set을 호출하면 items를 돌면서 같은 id를 찾으면 value의 값을 셋팅한다.
parse
public class Packet {
. . . (생략)
public void parse(String data) {
byte[] bdate = data.getBytes();
int pos = 0;
int count = 0;
for (Item item : items) {
if(item.getGroup() == false) {
byte[] temp = new byte[item.getLength()];
System.arraycopy(bdate, pos, temp, 0, item.getLength());
pos += item.getLength();
item.setValue(new String(temp));
if (item.getName().indexOf("건수") != -1) {
count = Integer.parseInt(item.getValue());
}
} else {
item.setCount(count);
for (int i = 0; i < item.getCount(); i++) {
for (SubItem subItem : item.getSubItems()) {
byte[] temp = new byte[subItem.getLength()];
System.arraycopy(bdate, pos, temp, 0, subItem.getLength());
pos += subItem.getLength();
subItem.addValues(new String(temp));
}
}
}
}
}
}
- 기존 parse에서 반복구간을 파싱하기 위한 코드가 추가되었다.
- 그룹데이터가 오기 전에는 항상 건수가 먼저 오기 때문에 아래와 같이 건수 필드의 값을 따로 가지고 있다가
- if (item.getName().indexOf("건수") != -1) count = Integer.parseInt(item.getValue());
- 그룹 데이터가 오면 가지고 있던 건수를 item.setCount(count)하고 반복구문을 count만큼 돌린다.
- for (SubItem subItem : item.getSubItems()) // 그룹데이터의 항목 개수만큼 반복문을 다시 돌린다.
- subItem.addValues(new String(temp)); // 해당 항목에 count만큼 값이 가변적으로 들어올 것이다.
toDatabase
public class Packet {
. . . (생략)
public void toDatabase() {
String table = "";
StringBuffer fields = new StringBuffer();
StringBuffer values = new StringBuffer();
for (Item item : items) {
if (item.getGroup() == false) {
fields.append(item.getField() + ",");
if(item.getType().equals("C"))
values.append("'"+item.getValue().replace(" ", "") + "',");
else if (item.getType().equals("N"))
values.append(item.getValue().replace(" ", "") + ",");
}
}
if(fields.length() > 0) fields.deleteCharAt(fields.length()-1);
if(values.length() > 0) values.deleteCharAt(values.length()-1);
System.out.println("insert into " + this.table + "(" + fields.toString() + ") valeus (" + values.toString() + ")");
fields.delete(0, fields.length());
values.delete(0, values.length());
for (Item item : items) {
if (item.getGroup() == true) {
for (int i = 0; i < item.getCount(); i++) {
table = item.getTable();
for (SubItem subItem : item.getSubItems()) {
fields.append(subItem.getField() + ",");
if(subItem.getType().equals("C"))
values.append("'"+ subItem.getValues(i).replace(" ", "") + "',");
else if (subItem.getType().equals("N"))
values.append(subItem.getValues(i).replace(" ", "") + ",");
}
if(fields.length() > 0) fields.deleteCharAt(fields.length()-1);
if(values.length() > 0) values.deleteCharAt(values.length()-1);
System.out.println("insert into " + table + "(" + fields.toString() + ") valeus (" + values.toString() + ")");
fields.delete(0, fields.length());
values.delete(0, values.length());
}
}
}
}
}
- 먼저 응답전문의 항목들부터 테이블 인설트 구문을 뽑아내고
- 다음 반복구간의 항목들을 테이블 인설트 구문을 뽑아낸다.
- type으로 문자 타입 필드인지 숫자 타입 필드인지 확인하고 있다.
6. FullText
public class FullText {
public static void main(String[] args) {
LoadXml loadXml = new LoadXml(Paths.get("").toAbsolutePath()+"/src/main/resources/templates/cust.xml");
Packet reqPacket = loadXml.getReqPckt();
Packet resPacket = loadXml.getResPckt();
System.out.println("요청");
reqPacket.allPrint();
System.out.println("응답");
resPacket.allPrint();
Map<String, String> map = new HashMap<>();
map.put("name", "홍길동");
map.put("jumin", "6666667777777");
reqPacket.set(map);
System.out.println("");
System.out.println("[" + reqPacket.raw() + "]");
resPacket.parse("홍길동 6666667777777003phn01099998888hom01077776666cpn01055554444002hom서울시 송파구 잠실동 123-3 cpn서울시 송파구 잠실동 456-7 ");
System.out.println("");
resPacket.allPrint();
System.out.println("");
resPacket.toDatabase();
}
}
LoadXml loadXml = new LoadXml // 생성자로 XML을 파싱해서 요청 패킷 객체와 응답 패킷 객체를 받아오고 있다. (전문 송수신이 빈번 할 시 생성자보다는 static으로 메모리에 띄워놓고 가져다 쓰는 편이 좋다.)
reqPacket.set(map) // map에 요청하고자 하는 항목들을 담아서 요청 패킷 객체에 셋팅하고 있다.
resPacket.parse // 응답 받은 전문을 응답 패킷 객체에 파싱하고 있다.
resPacket.toDatabase(); // 응답 데이터들을 디비에 저장하고 있다.
반응형
'JAVA' 카테고리의 다른 글
JAVA 대용량 엑셀 업로드 및 다운로드 (0) | 2023.06.02 |
---|---|
JAVA 암호화와 복호화 Cipher (0) | 2023.03.01 |
자바 FileReader & FileWriter (문자 입출력 스트림) (0) | 2023.02.21 |
JAVA FTP 다운로드, 목록읽기, 업로드 (0) | 2023.01.31 |
자바 File 클래스, renameTo (0) | 2023.01.20 |
Comments