NaverPriceInfo.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. package com.exrkorea.batch.biz.affiliate.naver.search;
  2. import java.io.BufferedReader;
  3. import java.io.InputStreamReader;
  4. import java.io.UnsupportedEncodingException;
  5. import java.net.HttpURLConnection;
  6. import java.net.URL;
  7. import java.net.URLEncoder;
  8. import java.sql.Connection;
  9. import java.sql.PreparedStatement;
  10. import java.sql.ResultSet;
  11. import java.sql.SQLException;
  12. import java.util.ArrayList;
  13. import java.util.List;
  14. import java.util.concurrent.TimeUnit;
  15. import org.json.JSONArray;
  16. import org.json.JSONObject;
  17. import com.exrkorea.batch.framework.base.DataBatch;
  18. import com.exrkorea.batch.framework.var.Var;
  19. import com.nogdooframework.web.parameter.NGMap;
  20. public class NaverPriceInfo extends DataBatch {
  21. private static final String requestUrl = "https://openapi.naver.com/v1/search/shop.json"; //request value 를 제외한 요청 URL
  22. private static final String clientId = "p9BcE9JoeZEUNuYnpqUC"; //NAVER CLIENT ID
  23. private static final String clientSecret = "ALsYw0LUvo"; //NAVER SECRET
  24. //private static List<NGMap> lowestPriceProdList = new ArrayList<NGMap>(); // NAVER SEARCH API로 가져온 데이터리스트
  25. private static int successCnt = 0; // 성공
  26. private static int failCnt = 0; // 성공했지만 가져올 상품이 존재하지 않는 경우
  27. private static int errorCnt = 0; // ERROR인 경우
  28. private static int prodCnt = 0; //api key 변경 가격 비교 상품수
  29. long startTime = System.currentTimeMillis(); // LOG 출력을 위한 시작시간
  30. /**
  31. * 상품정보 (재고여부, 전시여부)
  32. * @param conn
  33. * @return List<NGMap>
  34. * @throws Exception
  35. */
  36. private List<NGMap> getProductInfo(Connection conn) throws Exception {
  37. PreparedStatement pstmt = null;
  38. ResultSet rs = null;
  39. String sql = null;
  40. //System.out.println("getProductInfo======>");
  41. //List<NGMap> prodList = new LinkedList<NGMap>();
  42. List<NGMap> prodList = new ArrayList<NGMap>();
  43. try {
  44. int dataCnt = 0;
  45. sql = super.getSqlStatement("/biz/affiliate/" + Var.NAVER + "/search/getProductInfo.sql");
  46. log.debug("== SQL statement ===============================================================");
  47. log.debug("\n{}", sql);
  48. log.debug("================================================================================");
  49. pstmt = conn.prepareStatement(sql);
  50. rs = pstmt.executeQuery();
  51. while (rs.next()) {
  52. if (dataCnt == 0)
  53. log.info("================================DB 조회 시작================================");
  54. NGMap resultMap = new NGMap();
  55. //resultMap.setString("PROD_CD", rs.getString("STYLECD")); // 상품코드 (ERP 스타일 코드)
  56. resultMap.setString("TEXT", rs.getString("TEXT")); // 검색어
  57. resultMap.setString("PROD_CD", rs.getString("PROD_CD")); // 상품코드
  58. //resultMap.setString("LIST_PRICE", rs.getString("LIST_PRICE")); // 최초소비자가
  59. //resultMap.setString("PROD_PRICE", rs.getString("PROD_PRICE")); // 현재판매가
  60. //System.out.println("resultMap==========>"+resultMap);
  61. prodList.add(resultMap);
  62. dataCnt++;
  63. }
  64. log.info("================================DB 조회 완료================================");
  65. } catch (Exception e) {
  66. //e.printStackTrace();
  67. throw e;
  68. } finally {
  69. if(pstmt != null) pstmt.close();
  70. if(rs != null) rs.close();
  71. }
  72. return prodList;
  73. }
  74. private List<NGMap> getPriceInfo(List<NGMap> prodList, boolean loopCnt) throws InterruptedException {
  75. //private void getPriceInfo(List<NGMap> prodList, boolean loopCnt) {
  76. List<NGMap> reRequestValueList = new ArrayList<NGMap>(); // 에러로 누락되어 다시 검색할 데이터
  77. List<NGMap> lowestPriceProdList = new ArrayList<NGMap>();
  78. String prodCd = "";
  79. String text = "";
  80. String comRequestUrl = ""; //LOG 보여주기 위한 수정된 URL(request value 포함 전체 URL)
  81. for (NGMap prodMap : prodList) {
  82. TimeUnit.SECONDS.sleep(1);
  83. text = prodMap.getString("TEXT");
  84. prodCd = prodMap.getString("PROD_CD");
  85. log.info("text : " + text + "prodCd : " + prodCd);
  86. prodCnt++;
  87. try {
  88. text = URLEncoder.encode(text, "UTF-8");
  89. } catch (UnsupportedEncodingException e1) {
  90. e1.printStackTrace();
  91. }
  92. String display = "5";
  93. String sort = "asc";
  94. String apiURL = "";
  95. // URL 보내는 형태로 replace
  96. comRequestUrl = text + "&display="+ display + "&sort=" + sort;
  97. apiURL = requestUrl +"?query="+ comRequestUrl;
  98. try {
  99. //System.out.println("clientId====>"+clientId);
  100. //System.out.println("clientSecret====>"+clientSecret);
  101. URL url = new URL(apiURL);
  102. HttpURLConnection con = (HttpURLConnection)url.openConnection();
  103. con.setRequestMethod("GET");
  104. con.setRequestProperty("X-Naver-Client-Id", clientId);
  105. con.setRequestProperty("X-Naver-Client-Secret", clientSecret);
  106. int responseCode = con.getResponseCode();
  107. BufferedReader br;
  108. if(responseCode==200) { // 정상 호출
  109. //br = new BufferedReader(new InputStreamReader(con.getInputStream()));
  110. br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
  111. } else { // 에러 발생
  112. //br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
  113. br = new BufferedReader(new InputStreamReader(con.getErrorStream(), "UTF-8"));
  114. }
  115. String inputLine;
  116. StringBuffer response = new StringBuffer();
  117. while ((inputLine = br.readLine()) != null) {
  118. log.info(inputLine);
  119. response.append(inputLine);
  120. }
  121. br.close();
  122. //JSONObject obj = new JSONObject(response.toString().getBytes("UTF-8"));
  123. JSONObject obj = new JSONObject(response.toString());
  124. log.info("OBJ : {}", obj);
  125. int total = obj.getInt("total");
  126. //System.out.println("total====>"+total);
  127. JSONArray arr = obj.getJSONArray("items");
  128. for (int i = 0; i < arr.length(); i++)
  129. {
  130. NGMap resultMap2 = new NGMap();
  131. if(total > 0){ //정상처리
  132. String lprice = arr.getJSONObject(i).getString("lprice");
  133. String mallName = arr.getJSONObject(i).getString("mallName");
  134. //mallName = URLEncoder.encode(mallName , "UTF-8");
  135. //mallName = URLDecoder.decode(mallName , "UTF-8");
  136. //URLDecoder.decode(name, "UTF-8");
  137. if (Integer.parseInt(lprice) > 0 && !mallName.equals("네이버")) {
  138. resultMap2.setString("PROD_CD", prodCd);
  139. resultMap2.setString("LOWEST_PRICE", lprice);
  140. resultMap2.setString("MALL_NM", mallName);
  141. lowestPriceProdList.add(resultMap2);
  142. successCnt++;
  143. }
  144. }else if(total < 0 ){ // ERROR페이지 처리
  145. errorCnt++;
  146. // ERROR LOG 출력
  147. log.info("=================================ERROR========================================");
  148. log.info("\n PROD_CD : "+prodCd);
  149. log.info("\n REQUEST_URL : "+ apiURL);
  150. //log.info("\n ERROR_CODE : "+ rtnMap.getString("ERROR_CD"));
  151. //log.info("\n ERROR_MESSAGE : "+ rtnMap.getString("ERROR_MSG"));
  152. log.info("==============================================================================");
  153. }else if(total == 0){ //TOTAL 0 인 상품 처리
  154. failCnt++;
  155. // ERROR LOG 출력
  156. log.info("============================PRODUCT DOSE NOT EXIST============================");
  157. log.info("\n PROD_CD : "+prodCd);
  158. log.info("\n REQUEST_URL : "+ apiURL);
  159. log.info("\n FAIL_MESSAGE : "+ "상품이 존재하지 않습니다.");
  160. log.info("==============================================================================");
  161. }else{
  162. log.info("=================================ERROR========================================");
  163. log.info("\n PROD_CD : "+prodCd);
  164. log.info("\n REQUEST_URL : "+ apiURL);
  165. //log.info("\n ERROR_CODE : "+ rtnMap.getString("ERROR_CD"));
  166. //log.info("\n ERROR_MESSAGE : "+ rtnMap.getString("ERROR_MSG"));
  167. log.info("==============================================================================");
  168. }
  169. }
  170. //for - end
  171. } catch (Exception e) {
  172. // ERROR LOG 출력
  173. log.info("=================================TIMEOUT_ERROR========================================");
  174. log.info("\n PROD_CD : "+prodCd);
  175. log.info("\n REQUEST_URL : "+ apiURL);
  176. log.info("\n ERROR_CODE : "+ "998"); //임의 코드 (알 수 없는 에러)
  177. log.info("\n ERROR_MESSAGE : "+ e);
  178. log.info("==============================================================================");
  179. //System.out.println(e);
  180. reRequestValueList.add(prodMap); //알수 없는 에러가 생길경우 에러난 값을 따로 담음
  181. e.printStackTrace();
  182. }
  183. }
  184. log.info("========================================JSON 읽어오기 완료!!!");
  185. log.info("Success :" + successCnt + " Fail : "+ failCnt + " , Error : "+ errorCnt +" \n");
  186. // 누락된 데이터 저장을 위한 재귀호출의 무한루프를 방지하기 위한 값 : loopCnt
  187. if(loopCnt){
  188. return lowestPriceProdList;
  189. }
  190. // 알수 없는 에러로 누락된 데이터가 있을경우
  191. if(reRequestValueList.size() != 0){
  192. log.info("========================================TIMEOUT_ERROR 로 누락된 데이터 다시읽기");
  193. getPriceInfo(reRequestValueList, true);
  194. }
  195. return lowestPriceProdList;
  196. }
  197. /**
  198. * 네이버에서 가져온 최저가 정보를 DB에 Batch 작업
  199. *
  200. * @param conn - Connection
  201. * @param lowestPriceProdList - 네이버에서 가져온 최저가 정보 List<LSMap>
  202. * @return int[]
  203. * @throws Exception
  204. */
  205. private void insertPriceInfo(Connection conn,List<NGMap> lowestPriceProdList) throws Exception {
  206. PreparedStatement pstmt = null;
  207. NGMap lowestPriceProd = new NGMap();
  208. try {
  209. String sql = super.getSqlStatement("/biz/affiliate/" + Var.NAVER + "/search/insertLowestPrice.sql");
  210. pstmt = conn.prepareStatement(sql);
  211. log.debug("== SQL statement ===============================================================");
  212. log.debug("\n" + sql);
  213. log.debug("==============================================================================");
  214. int batchSize = 1000;
  215. for (int j = 0; j<lowestPriceProdList.size(); j++) {
  216. lowestPriceProd = lowestPriceProdList.get(j);
  217. String prod_cd = lowestPriceProd.getString("PROD_CD");
  218. String mall_nm = lowestPriceProd.getString("MALL_NM");
  219. int lowest_price = lowestPriceProd.getInt("LOWEST_PRICE");
  220. pstmt.clearParameters();
  221. pstmt.setString(1, prod_cd);
  222. pstmt.setString(2, prod_cd);
  223. pstmt.setString(3, mall_nm);
  224. pstmt.setInt(4, lowest_price);
  225. pstmt.addBatch();
  226. // OutOfMemory를 고려하여 batchSize 단위로 커밋
  227. if( (j % batchSize) == 0){
  228. // Batch 실행
  229. pstmt.executeBatch() ;
  230. // Batch 초기화
  231. pstmt.clearBatch();
  232. // 커밋
  233. //conn.commit() ;
  234. }
  235. }
  236. if(lowestPriceProdList.size() % batchSize != 0){
  237. pstmt.executeBatch();
  238. }
  239. } catch (SQLException sqle) {
  240. log.info("error:\n" + lowestPriceProdList);
  241. throw new Exception(sqle.getMessage(), sqle);
  242. } catch(Exception e) {
  243. throw e;
  244. } finally {
  245. if (pstmt != null) pstmt.close();
  246. }
  247. }
  248. @Override
  249. public void execute(Connection conn) throws Exception {
  250. //상품리스트
  251. List<NGMap> prodList = getProductInfo(conn);
  252. // 최저가 정보 리스트
  253. List<NGMap> lowestPriceProdList = getPriceInfo(prodList, false);
  254. //getPriceInfo(prodList, false);
  255. //System.out.println("lowestPriceProdList===>"+lowestPriceProdList);
  256. //System.out.println("lowestPriceProdList.size===>"+lowestPriceProdList.size());
  257. insertPriceInfo(conn, lowestPriceProdList);
  258. }
  259. @Override
  260. public void init() throws Exception {
  261. //clientId = props.getProperty("NAVER_API_CLIENT_ID");
  262. //clientSecret = props.getProperty("NAVER_API_CLIENT_SECRET");
  263. //requestUrl = props.getProperty("NAVER_PRICE_INFO_URL");
  264. //System.out.println("init======>");
  265. }
  266. /**
  267. * @param args
  268. */
  269. public static void main(String[] args) throws Exception {
  270. NaverPriceInfo batch = new NaverPriceInfo();
  271. System.out.println("네이버 - 최저가 연동 시작");
  272. batch.run("네이버 - 최저가 연동");
  273. }
  274. }