-
[XML] 002. XML 관찰 실습(2) : 로컬 XML 파일 읽기SsY/Class 2023. 7. 25. 09:11728x90
XmlApp04
- 로컬(local) XML 파일 읽기- XmlDomTest01
/*=============================================== XmlDomTest01.java - 콘솔 기반 자바 프로그램 - XML DOM 활용 → 로컬(local) XML 읽어내기 (VEHICLES.xml) ===============================================*/ package com.test.xml; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; // 주소 확인! import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class XmlDomTest01 { public static void main(String[] args) { // 1. XML 파일을 메모리에 로드 → XML DOM 형성 // 2. 루트 엘리먼트 접근 // 3. 특정 하위 엘리먼트 접근 → 위치, 이름을 기준으로 접근 // 4. 텍스트 노드(속성 노드) 접근 → 데이터 획득 // 5. 결과 처리(출력) try { // XML 파일을 메모리에 로드시킬 준비 // → XML DOM 형성을 위한 준비 // (이를 위해 필요한 리소스 구성) //-- 공장 부터 지어야한다... DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //-- static 메소드 newInstance(); //-- 추상메소드이기 때문에 new로 생성 불가. DocumentBuilder builder = factory.newDocumentBuilder(); Document xmlObj = null; // XML 파일을 메모리에 로드 → XML DOM 형성 String url = "VEHICLES.xml"; //-- 현재 최상위 경로에 두었음 xmlObj = builder.parse(url); //-- builder 로 xml 파일 파싱 //-- 여기까지하면 XML 파일 로드 끝 // 루트 엘리먼트 접근 Element root = xmlObj.getDocumentElement(); //-- 문서의 element 는 루트 엘리먼트 // 확인-- 얻어낸 루트 엘리먼트의 노드이름 확인 //System.out.println(root.getNodeName()); //--==>> VEHICLES // 특정 하위 엘리먼트 접근 → 위치, 이름을 기준으로 접근 // 『getElementsByTagName()』 메소드는 태그의 이름을 가지고 // 자식(자손) 노드에 접근할 수 있도록 해주는 메소드 NodeList vehicleNodeList = root.getElementsByTagName("VEHICLE"); //-- XML 의 구조상 같은 태그 이름을 가진 것이 다수 있을 수 있기 때문에 Element's' 조심! // ※ NodeList 객체에 들어있는 Node 의 갯수를 // 『getLength()』 메소드를 통해 확인할 수 있다. // 확인 //System.out.println(vehicleNodeList.getLength()); //--==>> 10 //-- VEHICLE 이라는 노드가 10개 있다 for (int i=0; i<vehicleNodeList.getLength(); i++) //-- 10번 반복 { // NodeList 의 『item()』 메소드는 // 파라미터에 해당하는 인덱스에 위치한 노드 접근 메소드 Node vehicleNode = vehicleNodeList.item(i); //-- i → 0 ~ 9 // 캐스트 연산자를 이용하면 // Node 객체를 Element 객체로 변환하는 것이 가능하다. // Node 는 상위 자료형, Element 는 하위 자료형으로 다루고 있기 때문이다. Element vehicleElement = (Element)vehicleNode; /* NodeList makeNodeList = vehicleElement.getElementsByTagName("MAKE"); Node makeNode = makeNodeList.item(0); Element makeElement = (Element)makeNode; System.out.printf("%s : %s%n" , makeElement.getNodeName() , makeElement.getTextContent()); NodeList modelNodeList = vehicleElement.getElementsByTagName("MODEL"); Node modelNode = modelNodeList.item(0); Element modelElement = (Element)modelNode; System.out.printf("%s : %s%n" , modelElement.getNodeName() , modelElement.getTextContent()); //-- 사용자 정의 메소드로 재구성 */ // 특정 엘리먼트의 텍스트 데이터를 얻는 // 사용자 정의 메소드 『getText()』 메소드 호출 System.out.printf("%s %s %s %s %s %n" , getText(vehicleElement, "MAKE") , getText(vehicleElement, "MODEL") , getText(vehicleElement, "YEAR") , getText(vehicleElement, "PICTURE") , getText(vehicleElement, "STYLE")); } } catch (Exception e) { System.out.println(e.toString()); } }// end main() private static String getText(Element parent, String tagName) { // 반환할 결과 값 String result = ""; // 특정 태그 이름을 가진 객체의 첫 번째 자식 노드를 얻어온 다음 Node node = parent.getElementsByTagName(tagName).item(0); Element element = (Element)node; // 특정 엘리먼트의 자식노드(TextNode)의 값(NodeValue)를 얻어올 수 있도록 처리 result = element.getChildNodes().item(0).getNodeValue(); // 결과 값 반환 return result; } } // 실행 결과 /* Dodge Durango 1998 DodgeDurango.jpg Sport Utility Honda Civic 1997 HondaCivic.jpg Sedan Dodge Neon 1996 DodgeNeon.jpg Sedan Ferrari F355 1995 FerrariF355.jpg Sport BMW 3 Series 1998 BMWSeries3.jpg Sedan BMW Z3 1998 BMWZ3.jpg Convertible Dodge RAM 1997 DodgeRAM1500.jpg Truck Honda Accord 1995 HondaAccord.jpg Sedan Dodge RAM 2500 1996 DodgeRAM2500.jpg Truck Ford Explorer 1996 FordExplorer.jpg Sport Utility */
- XmlDomTest02
/*=============================================== XmlDomTest03.java - 콘솔 기반 자바 프로그램 - XML DOM 활용 → 로컬(local) XML 읽어내기 (breakfast_menu.xml) ===============================================*/ // breakfast_menu.xml 파일을 대상으로 // 다음과 같은 데이터를 획득하여 출력할 수 있도록 처리한다. /* ■ [Belgian Waffles] $5.95 650칼로리 - Two of our famous Belgian Waffles with plenty of real maple syrup ------------------------------------------------------------------------- ■ [Strawberry Belgian Waffles] $7.95 900칼로리 - Light Belgian waffles covered with strawberries and whipped cream ------------------------------------------------------------------------- : : */ /* 1. XML 파일 (breakfast_menu.xml)을 메모리에 로드 → XML DOM 생성 2. 루트 엘리먼트 접근 3. 루트 엘리먼트 특정 하위 엘리먼트 접근 → 위치, 이름 등을 기준으로 접근(사실상 문법적으로 다양한 접근 방법 지원) 4. 텍스트 노드(속성 노드) 접근 → 원하는 데이터 얻어내기 5. 결과처리 → 출력 */ package com.test.xml; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class XmlDomTest03 { public static void main(String[] args) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document xmlObj = null; String url = "breakfast_menu.xml"; xmlObj = builder.parse(url); Element root = xmlObj.getDocumentElement(); //System.out.println(root.getNodeName()); //--==>> breakfast_menu NodeList foodNodeList = root.getElementsByTagName("food"); for (int i=0; i<foodNodeList.getLength(); i++) { Node foodNode = foodNodeList.item(i); Element foodElement = (Element)foodNode; System.out.printf("■ [%s]\t%s\t%s칼로리\n - %s\n" , getText(foodElement, "name") , getText(foodElement, "price") , getText(foodElement, "calories") , getText(foodElement, "description") ); System.out.println("-------------------------------------------------------------------------"); } } catch (Exception e) { System.out.println(e.toString()); } }// end main() private static String getText(Element parent, String tagName) { String result = ""; Node node = parent.getElementsByTagName(tagName).item(0); Element element = (Element)node; result = element.getChildNodes().item(0).getNodeValue(); return result; } } // 실행 결과 /* ■ [Belgian Waffles] $5.95 650칼로리 - Two of our famous Belgian Waffles with plenty of real maple syrup ------------------------------------------------------------------------- ■ [Strawberry Belgian Waffles] $7.95 900칼로리 - Light Belgian waffles covered with strawberries and whipped cream ------------------------------------------------------------------------- ■ [Berry-Berry Belgian Waffles] $8.95 900칼로리 - Light Belgian waffles covered with an assortment of fresh berries and whipped cream ------------------------------------------------------------------------- ■ [French Toast] $4.50 600칼로리 - Thick slices made from our homemade sourdough bread ------------------------------------------------------------------------- ■ [Homestyle Breakfast] $6.95 950칼로리 - Two eggs, bacon or sausage, toast, and our ever-popular hash browns ------------------------------------------------------------------------- */
- XmlDomTest03
/*=============================================== XmlDomTest03.java - 콘솔 기반 자바 프로그램 - XML DOM 활용 → 로컬(local) XML 읽어내기 (breakfast_menu.xml) ===============================================*/ // breakfast_menu.xml 파일을 대상으로 // 다음과 같은 데이터를 획득하여 출력할 수 있도록 처리한다. /* ■ [Belgian Waffles] $5.95 650칼로리 - Two of our famous Belgian Waffles with plenty of real maple syrup ------------------------------------------------------------------------- ■ [Strawberry Belgian Waffles] $7.95 900칼로리 - Light Belgian waffles covered with strawberries and whipped cream ------------------------------------------------------------------------- : : */ /* 1. XML 파일 (breakfast_menu.xml)을 메모리에 로드 → XML DOM 생성 2. 루트 엘리먼트 접근 3. 루트 엘리먼트 특정 하위 엘리먼트 접근 → 위치, 이름 등을 기준으로 접근(사실상 문법적으로 다양한 접근 방법 지원) 4. 텍스트 노드(속성 노드) 접근 → 원하는 데이터 얻어내기 5. 결과처리 → 출력 */ package com.test.xml; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class XmlDomTest03 { public static void main(String[] args) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document xmlObj = null; String url = "breakfast_menu.xml"; xmlObj = builder.parse(url); Element root = xmlObj.getDocumentElement(); //System.out.println(root.getNodeName()); //--==>> breakfast_menu NodeList foodNodeList = root.getElementsByTagName("food"); for (int i=0; i<foodNodeList.getLength(); i++) { Node foodNode = foodNodeList.item(i); Element foodElement = (Element)foodNode; System.out.printf("■ [%s]\t%s\t%s칼로리\n - %s\n" , getText(foodElement, "name") , getText(foodElement, "price") , getText(foodElement, "calories") , getText(foodElement, "description") ); System.out.println("-------------------------------------------------------------------------"); } } catch (Exception e) { System.out.println(e.toString()); } }// end main() private static String getText(Element parent, String tagName) { String result = ""; Node node = parent.getElementsByTagName(tagName).item(0); Element element = (Element)node; result = element.getChildNodes().item(0).getNodeValue(); return result; } } // 실행 결과 /* ■ [Belgian Waffles] $5.95 650칼로리 - Two of our famous Belgian Waffles with plenty of real maple syrup ------------------------------------------------------------------------- ■ [Strawberry Belgian Waffles] $7.95 900칼로리 - Light Belgian waffles covered with strawberries and whipped cream ------------------------------------------------------------------------- ■ [Berry-Berry Belgian Waffles] $8.95 900칼로리 - Light Belgian waffles covered with an assortment of fresh berries and whipped cream ------------------------------------------------------------------------- ■ [French Toast] $4.50 600칼로리 - Thick slices made from our homemade sourdough bread ------------------------------------------------------------------------- ■ [Homestyle Breakfast] $6.95 950칼로리 - Two eggs, bacon or sausage, toast, and our ever-popular hash browns ------------------------------------------------------------------------- */
- XmlDomTest04
더보기※ 내 풀이
/*=============================================== XmlDomTest04_1.java - 콘솔 기반 자바 프로그램 - XML DOM 활용 → 로컬(local) XML 읽어내기 (VEHICLES.xml) ===============================================*/ // VEHICLES.xml 파일을 대상으로 // 다음과 같은 데이터를 획득하여 출력할 수 있도록 처리한다. /* ---------------------------------------------------------------- NO MAKE MODEL YEAR STYLE PRICE ---------------------------------------------------------------- 1 Dodge Durango 1998 Sport Utility 18000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Stereo : Radio/Cassette/CD Air_Conditioning : Yes Automatic : Yes Four_Wheel_Drive : Full/Partial Note: Very clean ---------------------------------------------------------------- 2 Honda Civic 1997 Sedan 8000 Options--------------------------------------- : : */ package com.test.xml; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class XmlDomTest04_1 { public static void main(String[] args) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document xmlObj = null; String url = "VEHICLES.xml"; xmlObj = builder.parse(url); Element root = xmlObj.getDocumentElement(); //System.out.println(root.getNodeName()); //--==>> VEHICLES NodeList vehicleNodeList = root.getElementsByTagName("VEHICLE"); System.out.println("----------------------------------------------------------------"); System.out.println("NO\tMAKE\tMODEL\t\tYEAR\tSTYLE\t\t\t\tPRICE"); System.out.println("----------------------------------------------------------------"); for (int i=0; i<vehicleNodeList.getLength(); i++) { Node vehicleNode = vehicleNodeList.item(i); Element vehicleElement = (Element)vehicleNode; System.out.printf("%s\t%s\t%s\t\t%s\t%s\t\t%s\n" ,getText(vehicleElement, "INVENTORY_NUMBER") ,getText(vehicleElement, "MAKE") ,getText(vehicleElement, "MODEL") ,getText(vehicleElement, "YEAR") ,getText(vehicleElement, "STYLE") ,getText(vehicleElement, "PRICE")); System.out.println("Options---------------------------------------"); NodeList optionsList = vehicleElement.getElementsByTagName("OPTIONS"); for (int j=0; j<optionsList.getLength(); j++) { Node node = optionsList.item(j); if (node.getNodeType()==1) { Element optionElement = (Element)node; NodeList optionChildList = optionElement.getChildNodes(); for (int k=0; k<optionChildList.getLength(); k++) { Node childNode = optionChildList.item(k); if (childNode.getNodeType()==1) { Element optionChildElement = (Element)childNode; System.out.printf("%s : %s\n" , optionChildElement.getTagName() , optionChildElement.getTextContent() ); } } } } System.out.println("----------------------------------------------------------------"); } } catch (Exception e) { System.out.println(e.toString()); } }// end main() private static String getText(Element parent, String tagName) { String result = ""; Node node = parent.getElementsByTagName(tagName).item(0); Element element = (Element)node; result = element.getChildNodes().item(0).getNodeValue(); return result; } } // 실행 결과 1 (목록만) /* ---------------------------------------------------------------- NO MAKE MODEL YEAR STYLE PRICE ---------------------------------------------------------------- 1 Dodge Durango 1998 Sport Utility 18000 2 Honda Civic 1997 Sedan 8000 3 Dodge Neon 1996 Sedan 7000 4 Ferrari F355 1995 Sport 45000 5 BMW 3 Series 1998 Sedan 40000 6 BMW Z3 1998 Convertible 33000 7 Dodge RAM 1997 Truck 22000 8 Honda Accord 1995 Sedan 8500 9 Dodge RAM 2500 1996 Truck 25000 10 Ford Explorer 1996 Sport Utility 18000 */ // 실행 결과 2 (옵션까지) /* ---------------------------------------------------------------- NO MAKE MODEL YEAR STYLE PRICE ---------------------------------------------------------------- 1 Dodge Durango 1998 Sport Utility 18000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Stereo : Radio/Cassette/CD Air_Conditioning : Yes Automatic : Yes Four_Wheel_Drive : Full/Partial Note : Very clean ---------------------------------------------------------------- 2 Honda Civic 1997 Sedan 8000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Stereo : Radio/Cassette Automatic : Yes Note : Like New ---------------------------------------------------------------- 3 Dodge Neon 1996 Sedan 7000 Options--------------------------------------- Stereo : Radio/Cassette Automatic : Yes Note : Need minor body works ---------------------------------------------------------------- 4 Ferrari F355 1995 Sport 45000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Stereo : Radio/Cassette/CD Air_Conditioning : Yes Note : Luxury car ---------------------------------------------------------------- 5 BMW 3 Series 1998 Sedan 40000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Interiors : Leather Stereo : Radio/Cassette/CD Air_Conditioning : Yes Note : Pre-owned ---------------------------------------------------------------- 6 BMW Z3 1998 Convertible 33000 Options--------------------------------------- Cover_Material : Plastic Power_Locks : Yes Power_Window : Yes Alarm : Yes Interiors : Fabric Stereo : Radio/Cassette/CD Air_Conditioning : Yes Note : Pre-owned, very clean ---------------------------------------------------------------- 7 Dodge RAM 1997 Truck 22000 Options--------------------------------------- Stereo : Radio Max_Load : 1500 Note : Heavy duty Vehicle ---------------------------------------------------------------- 8 Honda Accord 1995 Sedan 8500 Options--------------------------------------- Power_Locks : Yes Stereo : Radio/Cassette Automatic : Yes ---------------------------------------------------------------- 9 Dodge RAM 2500 1996 Truck 25000 Options--------------------------------------- Stereo : Radio/Cassette Max_Load : 2500 Note : Heavy duty truck ---------------------------------------------------------------- 10 Ford Explorer 1996 Sport Utility 18000 Options--------------------------------------- Power_Locks : Yes Stereo : Radio/Cassette Automatic : Yes Interiors : Fabric Air_Conditioning : Yes Note : Pre-owned, very clean ---------------------------------------------------------------- */
/*=============================================== XmlDomTest04.java - 콘솔 기반 자바 프로그램 - XML DOM 활용 → 로컬(local) XML 읽어내기 (VEHICLES.xml) ===============================================*/ // VEHICLES.xml 파일을 대상으로 // 다음과 같은 데이터를 획득하여 출력할 수 있도록 처리한다. /* ---------------------------------------------------------------- NO MAKE MODEL YEAR STYLE PRICE ---------------------------------------------------------------- 1 Dodge Durango 1998 Sport Utility 18000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Stereo : Radio/Cassette/CD Air_Conditioning : Yes Automatic : Yes Four_Wheel_Drive : Full/Partial Note: Very clean ---------------------------------------------------------------- 2 Honda Civic 1997 Sedan 8000 Options--------------------------------------- : : */ package com.test.xml; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class XmlDomTest04 { public static void main(String[] args) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document xmlObj = null; String url = "VEHICLES.xml"; xmlObj = builder.parse(url); Element root = xmlObj.getDocumentElement(); NodeList vehicleNodeList = root.getElementsByTagName("VEHICLE"); System.out.println("----------------------------------------------------------------"); System.out.println("NO MAKE MODEL YEAR STYLE PRICE"); System.out.println("----------------------------------------------------------------"); for (int i=0; i<vehicleNodeList.getLength(); i++) { Node vehicleNode = vehicleNodeList.item(i); Element vehicleElement = (Element)vehicleNode; System.out.printf("%2s %7s %10s %5s %13s %7s\n" ,vehicleElement.getElementsByTagName("INVENTORY_NUMBER").item(0).getTextContent() ,vehicleElement.getElementsByTagName("MAKE").item(0).getTextContent() ,vehicleElement.getElementsByTagName("MODEL").item(0).getTextContent() ,vehicleElement.getElementsByTagName("YEAR").item(0).getTextContent() ,vehicleElement.getElementsByTagName("STYLE").item(0).getTextContent() ,vehicleElement.getElementsByTagName("PRICE").item(0).getTextContent()); System.out.println("Options---------------------------------------"); NodeList options = vehicleElement.getElementsByTagName("OPTIONS"); Node option = options.item(0); Element optionElement = (Element)option; NodeList childNodes = optionElement.getChildNodes(); //-- check for (int k=0; k<childNodes.getLength(); k++) { Node childNode = childNodes.item(k); if (childNode.getNodeType()==1) // ELEMENT_NODE //--check { System.out.printf(" %s : %s\n" , childNode.getNodeName() , childNode.getTextContent() ); } } System.out.println("----------------------------------------------------------------"); } } catch (Exception e) { System.out.println(e.toString()); } }// end main() } // 실행 결과 2 (옵션까지) /* ---------------------------------------------------------------- NO MAKE MODEL YEAR STYLE PRICE ---------------------------------------------------------------- 1 Dodge Durango 1998 Sport Utility 18000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Stereo : Radio/Cassette/CD Air_Conditioning : Yes Automatic : Yes Four_Wheel_Drive : Full/Partial Note : Very clean ---------------------------------------------------------------- 2 Honda Civic 1997 Sedan 8000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Stereo : Radio/Cassette Automatic : Yes Note : Like New ---------------------------------------------------------------- 3 Dodge Neon 1996 Sedan 7000 Options--------------------------------------- Stereo : Radio/Cassette Automatic : Yes Note : Need minor body works ---------------------------------------------------------------- 4 Ferrari F355 1995 Sport 45000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Stereo : Radio/Cassette/CD Air_Conditioning : Yes Note : Luxury car ---------------------------------------------------------------- 5 BMW 3 Series 1998 Sedan 40000 Options--------------------------------------- Power_Locks : Yes Power_Window : Yes Interiors : Leather Stereo : Radio/Cassette/CD Air_Conditioning : Yes Note : Pre-owned ---------------------------------------------------------------- 6 BMW Z3 1998 Convertible 33000 Options--------------------------------------- Cover_Material : Plastic Power_Locks : Yes Power_Window : Yes Alarm : Yes Interiors : Fabric Stereo : Radio/Cassette/CD Air_Conditioning : Yes Note : Pre-owned, very clean ---------------------------------------------------------------- 7 Dodge RAM 1997 Truck 22000 Options--------------------------------------- Stereo : Radio Max_Load : 1500 Note : Heavy duty Vehicle ---------------------------------------------------------------- 8 Honda Accord 1995 Sedan 8500 Options--------------------------------------- Power_Locks : Yes Stereo : Radio/Cassette Automatic : Yes ---------------------------------------------------------------- 9 Dodge RAM 2500 1996 Truck 25000 Options--------------------------------------- Stereo : Radio/Cassette Max_Load : 2500 Note : Heavy duty truck ---------------------------------------------------------------- 10 Ford Explorer 1996 Sport Utility 18000 Options--------------------------------------- Power_Locks : Yes Stereo : Radio/Cassette Automatic : Yes Interiors : Fabric Air_Conditioning : Yes Note : Pre-owned, very clean ---------------------------------------------------------------- */
728x90'SsY > Class' 카테고리의 다른 글
[XML] 004. XML 관찰 실습(4)(JSP 기반) : XPath 개요 (0) 2023.07.27 [XML] 003. XML 관찰 실습(3) : 원격지 XML 파일 읽기 (콘솔 기반) (0) 2023.07.25 [XML] 001. XML 개요 (0) 2023.07.21 [FileSystem] 02. 파일시스템 및 파일업로드(2) (0) 2023.07.20 [FileSystem] 01. 파일시스템 및 파일업로드 (0) 2023.07.19