머리말
Spring의 JDBC Templet은 Spring이 JDBC에 사용하는 기본 캡슐화입니다. 주로 프로그래머가 데이터베이스 연결을 관리하는 데 도움이되며 나머지 사용 방법은 JDBC를 직접 사용하는 것과 큰 차이가 없습니다.
비즈니스 요구 사항
모든 사람은 JDBC 사용에 익숙합니다. 이는 주로 SpringBoot에서 Spring JDBC Templet을 사용하는 단계를 보여 주므로 간단한 요구 사항을 설계했습니다. 사용자 객체의 두부 작업. 객체에는 두 개의 속성이 있으며, 하나는 ID이고 다른 하나는 이름입니다. MySQL의 Auth_user 테이블에 저장되었습니다.
새로운 프로젝트를 만들고 종속성을 추가하십시오
Intellij 아이디어에서 빈 스프링 부츠 프로젝트를 만듭니다. 특정 단계 참조
Spring-Boot 프로젝트를 작성하기위한 Intellij Idea의 그래픽 자습서. 이 예제의 요구 사항에 따라 다음 세 가지 종속성을 추가해야합니다.
<pectionency> <groupId> org.springframework.boot </groupid> <artifactid> Spring-Boot-Starter-web </artifactid> </dependency> <groupid> org.springframework.boot </groupid> <artifactid> spring-boot-starter-jdbc </arepifactid> <groupid> mysql </groupid> <artifactid> mysql-connector-java </artifactid> <bersion> 6.0.6 </version> </fectionency>
HTTP REST Service를 게시하고 싶기 때문에 Spring-Boot-Starter-Web 의존성을 추가합니다. 여기서 JDBC Tempet 메소드를 사용하여 데이터베이스에 액세스하려면 Spring-Boot-Starter-JDBC 종속성을 추가하여 MySQL 데이터베이스에 액세스하므로 MySQL의 JDBC 드라이버의 최신 버전을 추가합니다.
데이터베이스 환경을 준비하십시오
MySQL 5.7이 이미 Linux 운영 체제에 설치되어 있다고 가정하십시오. 다음 작업은 운영 체제 명령 줄에서 실행되며 루트 사용자를 통해 MySQL의 명령 줄 클라이언트에 로그인됩니다.
데이터베이스 및 테이블을 빌드하십시오
데이터베이스 작성 SpringBoot_jdbc; 테이블 auth_user 작성 (UUID bigint not null, name varchar (32), 기본 키 (UUID)) 기본 charset = utf8mb4;
사용자 권한을 설정하십시오
SpringBoot_jdbc.*에 모든 권한을 부여하십시오.
데이터 소스 구성 (연결 풀)
SpringBoot의 데이터 소스가 자동으로 구성됩니다. SpringBoot 2.0에는 사용할 수있는 몇 가지 데이터 소스 구성이 있으며 Hikaricp -> Tomcat 풀링 -> Commons DBCP2의 마지막 순서에서 실제로 사용할 데이터 소스를 선택합니다.
프로젝트가 Spring-Boot-Starter-JDBC 종속성을 추가하면 Hikaricp 데이터 소스 종속성이 이미 포함되어 있으므로 Hikaricp Connection Pool 데이터 소스가 자동으로 구성됩니다.
Appplications.Properties에 다음 구성을 추가하십시오
#general 데이터 소스 구성 spring.datasource.driver-class-name = com.mysql.cj.jdbc.driverspring.datasource.url = jdbc : mysql : //10.110.2.5 : 3306/spri ng-boot-jdbc? charset = utf8mb4 & usessl = falsspring.datasource.username = springbootspring.datasource.password = springboot# Hikari 데이터 소스 특정 구성 Spring.datasource.hikari.maximum-pool-size = 20spring.datasource.hikari.minimum-idle = 5
그중에서도 Hikari 데이터 소스의 대부분이 아래 그림에 나와 있습니다. 각 구성의 의미를 확인할 수 있습니다
프로그램 개발
사용자 데이터베이스 엔티티
요구 사항에 따라 해당 사용자 데이터 엔티티에는 두 가지 속성이 있으며, 하나는 ID이고 다른 하나는 이름입니다. 이것은 순수한 포조 물체입니다.
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao;/*** 사용자 엔티티 객체** @author Yang Gaochao* @since 2018-03-09*/public class userdo {private long id; 개인 문자열 이름; public long getid () {return id; } public void setId (long id) {this.id = id; } public String getName () {return name; } public void setName (문자열 이름) {this.name = 이름; }} 일반 HTTP REST 리턴 객체
일반적으로 HTTP REST 인터페이스에서는 비즈니스 객체의 내용을 직접 반환하고 싶을뿐만 아니라 인터페이스 호출 결과, 통화 실패시 반환 된 사용자 정의 문자 메시지 등과 같은 몇 가지 일반적인 정보를 반환하려고합니다. 그런 다음 두 개의 일반적인 REST 리턴 객체를 설정해야하며, 공통 비즈니스 컨텐츠를 포함하고 하나는 여러 비즈니스 컨텐츠를 포함하는 컬렉션을 포함합니다. 특정 정의는 다음과 같습니다
별도의 비즈니스 컨텐츠에 대한 객체를 반환합니다
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo;/*** 단일 객체 반환 결과** @author yang gaochao* @since 2018-03-09*/public class reditemresult <t> {private string result; 개인 문자열 메시지; 개인 T 항목; 공개 문자열 getResult () {return result; } public void setResult (문자열 결과) {this.result = 결과; } public string getMessage () {return message; } public void setMessage (문자열 메시지) {this.message = 메시지; } public t getItem () {반환 항목; } public void setitem (t item) {this.item = 항목; }} 비즈니스 컨텐츠 수집 객체를 반환합니다
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo; import java.util.collection;/*** 수집 객체 반환 결과** @author yang gaochao* @since 2018-03-09*/public class restcollectionresult <t> {{virital string rest rest rest result; 개인 문자열 메시지; 개인 컬렉션 <t> 항목; 공개 문자열 getResult () {return result; } public void setResult (문자열 결과) {this.result = 결과; } public string getMessage () {return message; } public void setMessage (문자열 메시지) {this.message = 메시지; } public Collection <T> getItems () {반환 항목; } public void setitems (collection <t> 항목) {this.Items = 항목; }} 데이터 지속성 계층 개발
사용자 데이터 지속성 계층 인터페이스 정의
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn.dao; import com.yanggaochao.springboot.lear.learn.learn.springbootjdbclearn.domain.dao.userdo; import java.util.list;/** interface* @author yangochao* gaochao* gaochao* aughao. 2018-03-09*/public interface userDao {/*** 새 사용자를 데이터베이스에 저장* @Param 사용자 개체를 저장하여 근육 이득이 성공했는지*/boolean add (userdo user); / *** 데이터베이스에서 사용자를 업데이트* @param 사용자 사용자 사용자가 업데이트가 성공했는지*/ boolean update (userdo user); / *** 지정된 사용자를 삭제** @param id 삭제가 성공했는지* @return으로 삭제할 사용자의 ID*/ boolean delete (long id); / *** 지정된 사용자의 정확한 쿼리** @param id query* @return에 대한 사용자의 ID, 사용자 정보를 반환하고 그렇지 않으면 null*/ userdo location (long id); / *** 이름으로 사용자를 쿼리** @param 이름을 fuzzy로 표시하십시오* @return query*/ list <userdo> matchName (String name);}. 사용자 데이터 지속성 계층 구현
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn.dao.impl; import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.userdao; import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.userdo; import org.springframework.beans.beans.annotation.autowired; import org.springframework.jdbc.core.jdbctemplate; import org.springframework.jdbc.support.rowset.sqlrowset; import org.spramframework.stereotype.repository; import java.util.arraylist; import java.util.list;/*** 사용자 객체 데이터에 액세스 구현 클래스** @author aang 공개 2018-09-09-09-09-09-09-09-09-09-09-09-09-09-09-09-09-09-09- userdaojdbctempletimpl userdao {private final jdbctemplate jdbctemplate; @autowired public userdaojdbctempletimpl (jdbctemplate jdbctemplate) {this.jdbctemplate = jdbctemplate; } @override public boolean add (userdo user) {string sql = "auth_user (uuid, name) 값 (?,?)에 삽입."; return jdbctemplate.update (sql, user.getid (), user.getname ())> 0; } @override public boolean update (userdo user) {String sql = "update auth_user set name =? where uuid =?"; return jdbctemplate.update (sql, user.getname (), user.getid ())> 0; } @override public boolean delete (long id) {string sql = "auth_user에서 uuid =?"; jdbctemplate.update (sql, id)> 0을 반환합니다. } @override public userdo locate (long id) {string sql = "auth_user에서 uuid =?"; sqlrowset rs = jdbctemplate.queryforrowset (sql, id); if (rs.next ()) {return genetateentity (rs); } return null; } @override public list <userdo> matchName (String name) {String sql = "select * from auth_user where name where?"; sqlrowset rs = jdbctemplate.queryforseset (sql, "%" + name + "%"); List <userdo> user = new ArrayList <> (); while (rs.next ()) {userate.add (generateentity (rs)); } 반환 사용자; } private userdo generateentity (sqlrowset rs) {userdo wechatpay = new userdo (); wechatpay.setid (rs.getLong ( "uuid")); wechatpay.setName (rs.getString ( "name")); wechatpay를 반환; }} 여기서 우리는 먼저 주석 @repository를 사용하여 데이터가 데이터 지속 계층의 클래스임을 나타냅니다. SpringBoot는이 클래스를 자동으로 인스턴스화합니다. 그런 다음 생성자에 @autowired를 추가하십시오. SpringBoot 가이 클래스를 인스턴스화하면 JDBCTemplet 인스턴스를이 클래스에 자동으로 주입합니다. 여기서는 JDBCTemPlet 인스턴스가 응용 프로그램의 데이터 소스 관련 구성을 기반으로 SpringBoot로 자동 구성됩니다. 데이터 소스를 자동으로 구성하기위한 SpringBoot의 알고리즘에 따르면 여기에서 구성 할 데이터 소스는 hikaricp입니다.
나머지는 평범한 스프링 jdbctemplet 개발과 같습니다. 프로그래머가 객체와 데이터베이스 SQL을 수동으로 변환하여 사용자를 추가, 수정, 삭제, 퍼지 매칭, 정확한 쿼리 및 기타 기능을 추가 할 수 있습니다.
데이터 비즈니스 계층 개발
데이터 서비스 계층 인터페이스 정의
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn.service; import com.yanggaochao.springboot.lear.learn.learn.springbootjdbclearn.dao.userdo; import java.util.list;/** user service layer* @author yangochao* gaochao* goochao* goochao.suerdo.userdo. 2018-03-09 */public Interface userErvice {userdo add (userdo user); userdo update (userdo user); 부울 삭제 (긴 ID); userdo는 위치 (긴 ID); List <userdo> matchName (문자열 이름);} 데이터 서비스 계층 구현
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn.service.impl; import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.userdao; import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.userdo; import com.yanggaochao.springboot.learn.springbootjdbclearn.service.userservice; import org.springframework.bean.bean.antowation org.springframework.stereotyp.service; import java.util.date; import java.util.list;/*** 사용자 비즈니스 계층 구현 클래스** @author Yang Gaochao* @since 2018-03-09*/ @servicepublic userserviceimpl userservice {private user dao userdao; @autowired public usererviceimpl (userdao userdao) {this.userdao = userdao; } @override public userdo add (userdo user) {user.setid (new date (). gettime ()); if (userdao.add (user)) {return user; } return null; } @override public userdo update (userdo user) {if (userdao.update (user)) {return location (user.getid ()); } return null; } @override public boolean delete (long id) {return userdao.delete (id); } @override public userdo location (long id) {return userdao.locate (id); } @override public list <userdo> matchName (문자열 이름) {return userDao.MatchName (이름); }} 여기서이 구현 클래스는 @Service 주석을 통해 비즈니스 수준 클래스로 선언됩니다. 지속성 계층의 userDao를 사용하면 SpringBoot가 @autowired를 통해이 비즈니스 계층 클래스를 인스턴스화하고 해당 지속성 계층 클래스를이 비즈니스 클래스에 자동으로 주입 할 수 있습니다.
여기서 사용자 객체를 추가 할 때 사용자에 대한 식별을 설정할 때 현재 시간 수의 현재 시간이 단순히 식별으로 사용됩니다. 실제 개발 과정 에서이 장소는이 로고를 반복 할 수 없도록 전 세계적으로 고유 한 메커니즘을 사용해야합니다.
외부 서비스 계층 개발
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn.web; import com.yanggaochao.springboot.learn.springbootjdbclearn.bo.restcollectionResult; import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.userdo; import com.yanggaochao.springboot.learn.springbootjdbclearn.service.userservice; import org.springframework.bean.bean.antowation org.springframework.web.bind.annotation.*; import java.util.list;/*** 사용자 http rest 인터페이스** @author Yang Gaochao* @since 2018-03-09*/ @restController @requestMapping ( "api/v1/user" @requestmapping (value = "/add", method = requestmethod.post) public restitemresult <userdo> add (@requestbody userdo user) {restitemresult <userdo> result = new RestitemResult <> (); user = userervice.add (user); if (user! = null) {result.setitem (user); result.setResult ( "성공"); } else {result.setMessage ( "새 사용자 실패"); result.setResult ( "실패"); } 반환 결과; } @requestmapping (value = "/update", method = requestmethod.post) public restitemresult <userdo> update (@requestbody userdo user) {restitemresult <userdo> result = new Restitemresult <> (); user = userervice.update (user); if (user! = null) {result.setitem (user); result.setResult ( "성공"); } else {result.setMessage ( "userDO는 사용자를 수정하지 못했다"); result.setResult ( "실패"); } 반환 결과; } @requestmapping (value = "/delete/{uuid}", method = requestmethod.get) public restitemresult <userdo> delete (@pathvariable long uuid) {restitemresult <userdo> result = new Restitemresult <> (); if (userService.delete (uuid)) {result.setResult ( "success"); } else {result.setMessage ( "사용자 실패 삭제"); result.setResult ( "실패"); } 반환 결과; } @requestmapping (value = "/locate/{uuid}", method = requestmethod.get) public restitemresult <userdo> locate (@pathvariable long uuid) {restitemresult <userdo> result = new Restitemresult <> (); userdo user = userervice.locate (uuid); if (user! = null) {result.setitem (user); result.setResult ( "성공"); } else {result.setMessage ( "쿼리 사용자 실패"); result.setResult ( "실패"); } 반환 결과; } @RequestMapping (value = "/match/{name}", method = requestCollectionResult <userdo> match (@PathVariable String <userdo> result = new RestCollectionResult <> (); List <userdo> user = userervice.matchName (이름); result.setitems (사용자); result.setResult ( "성공"); 반환 결과; }} 여기서 @RestController는 이것이 HTTP REST 인터페이스 클래스라고 선언하는 데 사용됩니다. 각 인터페이스의 호출 경로는 클래스의 @requestmapping과 메소드의 @requestmapping을 결합하여 형성됩니다. 이 메소드에서 @requestmapping의 메소드 속성은 HTTP에서 호출 한 메소드를 선언합니다. @requestbody 주석은 게시물 데이터의 JSON 객체를 POJO 객체로 자동 변환합니다. @PathVariable은 HTTP URL 경로의 데이터를 서비스 메소드의 매개 변수로 자동 변환합니다.
HTTP REST 인터페이스 테스트
테스트 HTTP REST 서비스는 Apache Commons의 HTTPCLIEN을 통해 호출됩니다.
http resst는 보조 클래스를 호출합니다
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn; import org.apache.commons.httpclient.defaulthttpmethodretryhandler; import org.apache.commons.httpclient.httpclient; import org.apache.commons.httpclient org.apache.commons.httpclient.methods.getMethod; import org.apache.commons.httpclient.methods.stringRequestentity; import org.apache.commons.httpclient.httpclient.httpmethodparams; import java.io.bufferedreader; java.io.inputStreamReader; import java.io.reader; import java.util.map;/*** @author yang gaochao* @since 2018-03-09*/public class httpclientHelper {/*** http 요청* @Ret t to http to http to http to http http http http http http to http url. */ public String httpgetRequest (문자열 URL, MAP <String, String> 헤더) 이후에 얻은 응답 텍스트 {try {httpclient httppclient = new Httpclient (); getMethod 메서드 = New GetMethod (url); method.setRequestHeader ( "content-type", "application/json; charset = utf-8"); method.getParams (). setParameter (httpmethodparams.retry_handler, 새로운 defaulthttpmethodretryhandler (3, false)); if (headers! = null) {for (문자열 키 : headers.keyset ()) {method.setRequestHeader (key, headers.get (key)); }} int statusCode = httpclient.executemethod (method); if (statusCode == 200) {return parseInputStream (method.getResponseBodyAsStream ()); } else {system.out.println (url + "status =" + statusCode); }} catch (예외 e) {e.printstacktrace (); } return null; } / *** Post 메소드를 사용하여 HTTP 요청** @param URL 요청에서 액세스 할 http의 URL* @param 데이터 데이터에 액세스 한 후 얻은 응답 텍스트 http* / public httppostrequest (String URL, String Data, Map <String, String> Headers) {Httpclient httpplient = news httpplient = httpclient (); 메드 메드 메소드 = 새로운 후 메드 (URL); method.setRequestHeader ( "content-type", "application/json; charset = utf-8"); Method.setRequestHeader ( "사용자 에이전트", "Mozilla/5.0 (Wind if (headers! = null) {for (문자열 키 : headers.keyset ()) {method.setRequestHeader (key, headers.get (key)); }} method.setRequestentity (new StringRequestentity (data, "json", "utf-8")); int statusCode = httpclient.executemethod (method); if (statusCode == 200) {return parseInputStream (method.getResponseBodyAsStream ()); } else {system.out.println (url + "status =" + statusCode + parseInputStream (method.getResponseBodyAsStream ())); }} catch (예외 e) {e.printstacktrace (); } return null; } / *** java.io.reader에서 텍스트 데이터를 구문 분석하는 경우** @param rd java.io.reader object* @throws 예외* / private String parsereader (reader rd)는 예외 {bufferedreader brd = new bufferedreader (rd); 문자열 라인; StringBuilder ResponsSecOntext = new StringBuilder (); while ((line = brd.readline ())! = null) {responseesecontext.append (line) .append ( "/n"); } //rd.close (); if (responseContext.length ()> 0) {responseesecontext.deletecharat (responseContext.length () -1); } return responseContext.toString (); } / *** 입력 스트림에서 텍스트 데이터를 구문 분석* @Param IS 입력 스트림* @throws 예외는 오류가 발생할 때 예외를 던집니다* / private String parseInputStream (inputStream IS) 예외 {return parsEreader (new bufferedReader (new inputStreamReader (is)); }} 여기서 우리는 주로 Get 및 Post 메소드를 사용하여 HTTP REST 서비스를 호출하는 방법을 구현합니다.
테스트 사례
Junit을 사용하여 테스트 케이스를 실행하십시오. 테스트를 구현하기 위해 다음 Maven 의존성을 추가했습니다.
<pectionency> <groupId> commons-httpclient </groupid> <artifactid> commons-httpclient </artifactid> <버전> 3.1 </version> <copop> </scope> </fexendency> <groupid> org.codehaus.jettison </groupid> <artifactid> jettison </artifactid> 1. <Scope> 테스트 </scope> </의존성>
패키지 com.yanggaochao.springboot.learn.springbootjdbclearn; import org.codehaus.jettison.json.jsonobject; import org.junit.after; import org.junit.before; import org.junit.test; import java.net.urlencoder; import java.util java.util.list;/** * 설명 : * * * @author Yang Gaochao * @since 2018-03-09 */public class userApitest {private String userAddurl = "http : // localhost : 3030/security/api/v1/user/add"; 개인 문자열 userLocateUrl = "http : // localhost : 3030/security/api/v1/user/locate/"; 개인 문자열 userDeleteUrl = "http : // localhost : 3030/security/api/v1/user/delete/"; 개인 문자열 userUpDateUrl = "http : // localhost : 3030/security/api/v1/user/update"; 개인 문자열 usermatchurl = "http : // localhost : 3030/security/api/v1/user/match/"; jsonobject addUser = new JsonObject (); Long Adduserid = null; List <long> userIds = new ArrayList <> (); @public void wefore ()는 예외 {adduser.put ( "name", "beautiful sheep")을 던졌습니다. jsonobject addresultjson = new JsonObject (new httpclientHelper (). httppostRequest (userAddurl, addUser.toString (), null); assert ( "성공".equals (addresultjson.getstring ( "result"))); AddUserId = addResultjson.getJsonObject ( "항목"). getLong ( "id"); jsonobject user = new JsonObject (); user.put ( "이름", "Pleasant Goat"); addResultjson = new JsonObject (new httpclientHelper (). httppostRequest (userAddurl, user.toString (), null); assert ( "성공".equals (addresultjson.getstring ( "result"))); userIds.add (addresultjson.getJsonObject ( "item"). getLong ( "id"); user.put ( "이름", "그레이 늑대"); addResultjson = new JsonObject (new httpclientHelper (). httppostRequest (userAddurl, user.toString (), null); assert ( "성공".equals (addresultjson.getstring ( "result"))); userIds.add (addresultjson.getJsonObject ( "item"). getLong ( "id"); } @test public void testupdateUser ()는 예외를 던져 {jsonObject user = new JsonObject (); user.put ( "이름", "Smad Sheep"); user.put ( "id", adduserid); new httpclientHelper (). httppostRequest (userUpDateUrl, user.toString (), null); jsonObject locateresultjson = new JsonObject (new httpclientHelper (). httpgetRequest (userLocateUrl + addUserId, null)); assert (user.getString ( "name"). } @test public void testmatchUser ()는 예외를 겪고 {jsonobject matchresultjson = new JsonObject (new httpclientHelper (). httpgetRequest (usermatchUrl + urlencoder.encode ( "양", "UTF-8"), null); assert (matchresultjson.has ( "항목") && matchresultjson.getJsonArray ( "항목"). length () == 2); matchresultjson = new JsonObject (new httpclientHelper (). httpgetRequest (usermatchurl + urlencoder.encode ( "wolf", "utf-8"), null)); assert (matchresultjson.has ( "항목") && matchresultjson.getJsonArray ( "항목"). length () == 1); } @after public void at at at ()는 예외를 던졌습니다 {if (adduserid! = null) {jsonobject deleteresultjson = new JsonObject (new httpclientHelper (). httpgetRequest (userDeleteUrl + addUserId, null)); assert ( "성공".equals (deleteresultjson.getstring ( "result"))); } for (long userId : userIds) {jsonobject deleteresultjson = new JsonObject (new httpclientHelper (). httpgetRequest (userDelETEURL + userID, null)); assert ( "성공".equals (deleteresultjson.getstring ( "result"))); }}} 여기서는 @Test에서 두 가지 테스트 사례가 선언되며, 하나는 사용자 수정 기능을 테스트하고 다른 하나는 사용자 퍼지 쿼리 기능을 테스트합니다. @Before는 각 테스트 사례를 실행하기 전에 준비를 수행 할 준비를합니다. 여기서 먼저 데이터베이스에 세 가지 데이터를 삽입하고 동시에 데이터 추가 및 정확한 쿼리 기능을 테스트합니다. @After는 각 테스트 케이스가 실행 된 후 정리를 선언합니다. 여기서 우리는 주로 이전에 삽입 된 데이터를 삭제합니다. 사용자 삭제의 기능은 여기서 동기식으로 테스트됩니다.
추신
다음은 JDBC Templet을 사용한 SpringBoot의 전체 예입니다. 봄에 JDBC 템플릿을 사용한 경험이 있다면 봄에 많은 구성 작업을 줄이는 주요 목적입니다.
이 기사와 관련된 코드는 GitHub에 업로드되었으며 로컬로 다운로드 할 수도 있습니다.
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.