Compare commits

79 Commits

Author SHA1 Message Date
00e736d668 .. 2026-04-08 19:43:38 +09:00
e75400cdc4 광주시립도서관 - 하남 추가 (최영진) 2026-03-26 23:41:43 +09:00
7288d8c95c 마크정리에서. 파일불러올때 마지막 줄이 불러오지 않는 현상 수 2026-03-12 19:28:21 +09:00
054e1c9c10 마크목록화면에서 신규마크인 경우에 비고란이 초기화되지 않는 현상 수정(비고란업데이트 코드 추가)
마크목록에서 신규 마크저장 후 바로 화면이 업데이트 되지 않는 현상 수정(데이터정보불일치로 업데이트 SKIP)
마크정리에서 일부 마크파일 불러오기에서 오류가 발생하는 현상 수정(원인 : 가격정보없음)
마크목록에서 적색데이터의 기본 마크 100a 에 서명이 입력되는 현상 수정(기본마크로직오류)
2026-03-08 17:37:39 +09:00
90ed6e285f 마크목록에서 개별 마크데이터 지정시 해당 값이 자동업데이트되지 않는 현상 수정
권차, 권차서명, 판차 정보 추출하여 저장하게 함
마크선태고하면에서 마크삭제시 삭제할 인덱스값 표시
obj_list_book 에  품절컬럼 추가,
2026-03-02 16:35:37 +09:00
a226c370b2 인덱스 컬럼의 포맷변경 string -> int 2026-02-28 15:55:20 +09:00
b13f01a3dd 마크정리->마크파일불러오기(fullparser 를 적용하여 데이터를 추출 함)
DLS 조회입력 화면 null 개체오류 분석 : 해당 화면은 고친적 없는 원본화면  https://reading.jnei.go.kr  페이지를 열어서 작업하는 것을 추정되나 해당 사이트가 접속이 되지 않은 것이 원인이됨 (프로그램이 멈추지 않고 오류 메세지가 나오도록 수정 함)
마크등급용 전용컨트롤 생성 및 공유
Grade - E 추가
마크목록 데이터 조회시 (ISBN검색결과 서명,저자,출판사,설명,URL 추가 )
2026-02-25 23:42:49 +09:00
5978d45af6 마크정리->마크파일불러오기(fullparser 를 적용하여 데이터를 추출 함) 2026-02-25 22:20:45 +09:00
3a503dda6d ISBN검색시 지연시간 추가 (설정에 저장됨)
ISBN검색중 알라딘의 경우 도서정보(html),URL 가 추가됨
ISBN검색결과  도서명, 저자, 출판사, 도서정보,URL이  DB에 저장되도록 함
2026-02-24 22:57:34 +09:00
c813ffe9e6 등급저장기능 추가, 비고기능 추가 2026-02-23 23:49:30 +09:00
c5571a98ab 유사본 저장시 마크외 정보도 저장되도록 함 2026-02-23 23:37:21 +09:00
3cfd7ff12c Messagebox 모두 변경 2026-02-23 23:11:54 +09:00
1b77fd02b0 마크작성기능 완료, fullmarc 해석기 1차완료 2026-02-23 22:29:01 +09:00
5271f9f1c3 마크파서 추가,, 신규 마크 추가 테스트 중. 2026-02-23 00:31:59 +09:00
6add9a00bc 마크편집창 및 신규생성 수정 중 2026-02-22 13:33:12 +09:00
c2c9122c55 편집기 통합작업 중, 등급 미적용 데이터 수정 2026-02-22 01:04:35 +09:00
ad866c1384 마크편집기를 공용으로 분리작업(90%) 2026-02-21 23:22:03 +09:00
86dbda1d21 ¸¶ũ º¹Á¦ ±â´É ±¸Çö ¹× Dµî±Þ »ö»ó ¼öÁ¤ (Grade E Ã߰¡ Ãë¼Ò) 2026-02-21 11:21:52 +09:00
82aa5a21d9 미소장 전체가져오기 기능 정상화 2026-02-20 16:17:17 +09:00
ed60319978 마크목록등록 ctrl+v 기능 오류 수정
목록창에서 isbn 조회 창으로 바로 진입할 수 있는 버튼이 필요(ppt15)
마크편집창 저장시 ISBN중복여부 확인
마크편집창 서브필드 정렬수정(245,440)- PPT21
2026-02-20 14:39:19 +09:00
35792b0a72 마크목록(new), 정렬,필터 기능 업데이트 2026-02-19 18:42:25 +09:00
77ef720197 .. 2026-02-19 18:28:22 +09:00
c0782ea5c1 마크편집창에서 isbn 을 복사할 수있도록 텍스트박스로 변경 2026-02-14 22:49:17 +09:00
6e25a3d4e9 일부 폼. .신규파일이름 2로 추가 2026-02-14 22:10:32 +09:00
f6dcd5630a 목록 생성 이후 수정 할 수 있는 기능이 필요
Ex) 목록일, 완료일, 목록명, 납품처, 담당자 등
2026-02-14 21:58:29 +09:00
9108993612 현재 마크목록 -> 목록생성(추후 목록 등록으로 수정요망) 버튼을 누르면
마크 목록 생성(추후 목록 등록으로 수정요망) 창이 뜨는 데 항목 순서 변경이 필요기존 가격 수량 합계 순서를 수량 가격 합계 순서로 변경요망
(북엔피에 적용된 순서와 동일하게 하려고 함)
2026-02-14 21:38:57 +09:00
f9d29c7629 marc2에서 마크목록생성시 색상불일치로 데이터 생성갯수가 달라진 부분 수정, 연결된 폼들때문에 addmarc2 도 수정하고 marcopyselect2 생성, marc_mklist2 생성 2026-02-04 22:31:27 +09:00
ad0be3fef5 마크목록생성 화면에서 오류 발생 가능성 분석 및 예상 코드 업데이트
트(null object ->  convert.tostring)
2026-02-03 22:45:26 +09:00
cfe68509f6 단축키 입력 관련 오류 수정 및 요청사항 수정
반출 오류 수정 (에디터 분리 건으로 인함)
2026-01-30 23:52:14 +09:00
87dbe17ec9 마크정리 목록오류 수정(compidx 전체 적용항목 수정, suername 도 전체 login정보로 수정), 매크로목록안나오는거(이상없음 -1번항목오류엿을수있음) , 문학형식 만환관련 오류 수정 2026-01-28 22:14:49 +09:00
92f36e78a5 DB 연결 관리 개선 및 연결 해제(Dispose) 오류 해결: Helper_DB의 연결 생성 및 해제 로직을 안전하게 리팩토링하고 Search_Infor에서 지역 변수를 사용하도록 수정 2026-01-25 13:56:18 +09:00
e3d5674b0a DB_Send_CMD_reVoid 를 ExecuteNoneQuery 로 대체 2026-01-25 13:21:54 +09:00
6c66cdb54a 마크편집창 alt+(a~z), alt+enter 단축키 추가
D등급자료의 색상을 Red -> Darkviolet 변경, red는 데이터가 신규로 저장된다.
신규로 저장되는 자료의 인덱스를 저장하면서 바로 수집하도록 한다
2026-01-25 11:19:12 +09:00
b7a2474ec2 메인화면의 compidx 와 username 을 . 전역 변수 PUB.user 로 이동 2026-01-24 16:30:24 +09:00
6e4e2eb982 마크목록 데이터바인딩 적용 2026-01-24 15:16:33 +09:00
47c443e9a3 네임스페이스 통일 UniMarc 2026-01-24 14:55:53 +09:00
568868602f 편집창 100 700 900 에서 쩜(.) 이 제거되지 않도록 함 2026-01-24 11:47:13 +09:00
c44f40a651 addmar2 작업중 2026-01-24 00:35:09 +09:00
4ffbb2fa2e 마크정리 에디터컨트롤 통합 작업 1차완료 2026-01-23 22:40:36 +09:00
ed9afeab80 미소장 화면이 폼에 직접 연결되지 않도록 수정 중 2026-01-22 23:11:25 +09:00
0f0f745964 마크정리화면에서 에디터통합 작업 중 일단 화면 open 성공 2026-01-22 23:00:08 +09:00
d40ffda4fd 마크정리에서 목록선택하면 나오는 목록창 바인딩소스 연결 2026-01-22 21:38:11 +09:00
409317c099 marc2 목록을 바인딩소스에 연결 2026-01-22 21:32:27 +09:00
eee6aeb514 prev, next 기능 활성화 2026-01-21 23:55:00 +09:00
23cf444cba 마크편집화면 : 색인, 등급 업데이트 오류 수정 및 불필요 코드 정리 작업, 중복실행코드 제거 2026-01-21 23:20:16 +09:00
aa5f33eedb Marc2 화면에서 저장시 사용자 이름이 저장되도록 함
미소장 마크 코리스 창 채우기 기능 오류 수정 완료
마크정리화면에 에디터창 붙이기 작업시작(컨트롤 정리작업 중)
2026-01-20 22:13:56 +09:00
d5aa0fe59d [NewEditor] 저장기능 확인, 목록다시불러오기 기능추가
[2601152030] v- 마크편집 마크칸 채우기를 왔다갔다 하면 300 p.에 .이 없어져서 p로만 남음 (300 p. <-> 300) ,  p. 에 공백없게
[2601152030] v- 미소장마크 불러오기 할때 코리스에서 보이는 창 넓게(부차적)
[2601152030] v- D등급 저장이 필요 -> 그냥 저장할 수 있게 -> 데이터가 부족하더라도 저장이 되게
[2601152030] v- db에 저장된 isbn과 마크에 저장된 이 다를 경우 저장을 하면 저장 전에 오류표시 및 저장 가능하게
[2601152030] v- 사진 더블클릭시 미리보기 나오게, 오류창 제거요망
2026-01-15 21:28:17 +09:00
66e4392d7c 정렬필터기능복원(23:10~23:40) 2026-01-14 23:44:11 +09:00
6574a84c24 마크편집기 폼입력 화면에ㅓㅅ dpi auto scale 해제 후 크기 조정 작업 2026-01-09 22:15:46 +09:00
2bc502d7db 닫기버튼 추가 2026-01-09 20:11:23 +09:00
d75585cf26 mareditor 분리작업중 2026-01-09 00:14:59 +09:00
d48440f8bd mdiparent 추가 폼 추가 2026-01-08 22:42:54 +09:00
e14fb633fb 메인 화면의 서브폼을 탭메뉴 형태로 표시하도록 함
마크목록에서 창이 다중으로 열리게  하고, 제목줄도 내용에 맞도록 변경
전체 창 닫기 메뉴 추가
2026-01-08 22:29:00 +09:00
ChiKyun Kim
ef2f8537fb 데모기간 26년으로 변경 2026-01-08 10:31:17 +09:00
cdecb76faf 복사임시기능 추가 2026-01-07 22:57:27 +09:00
d9223c4e61 마크->마크작업->마크목록 더블클릭시 나오는 마크작성화면의 이름을 마크작성(1) 로 변경(PPT-10p)
마크->마크작업->마크작성 이름을  마크작성(2) 로 변경
마크->마크작업->마크작성(2)의 메뉴 이름을 신규마크작성 으로 변경
마크->마크작업 메뉴에 마크작성(1) 추가
마크 편집창 별도 분리 작업 진행 중 - (기존 코드와  연결관련 분석 필요 - 시간 많이 필요 할듯)
마크 편집창 내에서 복사 버튼 추가 (관련 코드 점검 필요)
2026-01-07 22:41:04 +09:00
40c2acd7de 마크생성화면 전체 컨트롤 탭순서 조정
마크목록생성시 납품처 정보가 저장되지 않는 현상 수정
2025-12-29 22:16:17 +09:00
c2e1ed7246 탭순서변경 2025-12-26 19:53:06 +09:00
e989c5aac8 복본검사시 오류발생한 항목의 수량을 -1 로 설정하도록 함 (해당 자료가 오류가 되도록)
마크생성화면에서 업체명 검색시 SQL오류 수정
2025-12-25 21:57:10 +09:00
241cf656b4 영문저자기호셋팅화면추가, 4인이상 처리시에 서명+출판사 옵션 추가, 4인이상 셋팅여부를 거래처정보에 추가 2025-11-10 21:55:02 +09:00
f516deaf69 납품처 셋팅 .. 다음에는 실제 내보내기 부분에 연결을 해야함. 2025-11-06 23:53:33 +09:00
77646f0e66 변경중.. 2025-11-05 23:43:13 +09:00
0a034954ff 납품처 연결 작업 중 2025-11-05 23:26:52 +09:00
e4b8ead056 알라딘 API 응답 처리 구조화 및 URL 브라우저 열기 개선
- AladinBookData 클래스 추가하여 API 응답 데이터 구조화
- ToString() 메서드 오버라이드로 파이프 구분자 형식 출력 지원
- Aladin_struct() 메서드 추가: List<AladinBookData> 반환
- 기존 Aladin() 메서드는 호환성 유지를 위해 보존
- URL 링크 클릭 시 탐색기 대신 기본 웹 브라우저로 열리도록 수정 (UseShellExecute = true)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 23:15:04 +09:00
a36372b17c 납품처관리에. 저자기호, 및 분류기호 관련 컬럼 5개 추가 DB-CRUD 2025-10-22 22:52:34 +09:00
7d1286b7a7 필드없고 지시기호만 있는데이터도 필터링 2025-10-11 14:31:24 +09:00
2835f8d14e remove files
마크문자열 변환시 1d 1e 1f와  빈 값이 있는 태그 삭제 함
2025-10-11 00:43:19 +09:00
bbc47c50db Marc_Plan: 범위 입력받아 여러 행 삭제 기능 추가
- toolStripButton1_Click 메서드에 범위 삭제 기능 구현
- InputBox로 "1~100" 형식의 범위 입력 받음
- 입력 형식 검증 및 범위 유효성 확인
- 뒤에서부터 삭제하여 인덱스 오류 방지
- 디버그 모드에서만 toolStrip 표시하도록 설정

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-11 00:40:55 +09:00
12f190a0b8 DLS 검색 개선 및 복본조사 서브 셀렉터 기능 추가
- DLS 검색기에 고창군립도서관, 대불대학도서관 추가
- Check_Copy_Sub_Selector 폼 추가 (도서관별 상세 선택 기능)
- 복본조사 화면 UI 개선 (체크박스 간격 조정)
- 버전 정보 업데이트 (1.4.1.7 → 1.4.1.8)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-24 23:53:03 +09:00
1ae2b93490 전라남도립도서관 검색기 구현
- JeonnamProvLibSearcher.cs 추가 (HTTP 방식)
- 실제 사이트 URL 파라미터 구조 분석 및 적용
- HTML 결과 패턴 정규식 구현 (<font>전체 N</font>개가 검색되었습니다)
- Check_copyWD.cs에 검색기 등록
- 버전 업데이트 (2025.09.17.2300)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-17 22:35:06 +09:00
216311b558 검색결과 없음 HTML 추출 개선 및 도서관별 지연시간 저장 기능 구현
- 모든 도서관 검색기에서 검색결과 없음시 구체적인 HTML 조각 추출
- BookSearchResult에 Resulthtml 속성 추가하여 매칭된 HTML 컨텍스트 저장
- Helper_LibraryDelaySettings.cs 추가로 도서관별 검색 지연시간 XML 저장
- Check_copyWD.cs에 dvc_resulthtml 컬럼 표시 및 지연시간 저장 UI 구현
- 15개 SearchModel 파일에서 htmlContent 1000자 자르기를 의미있는 메시지로 교체
- HTTP 검색기들에 한글 인코딩 문제 해결을 위한 헤더 개선

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-15 23:39:04 +09:00
Arin(asus)
c0e6c9039e add claude info 2025-09-03 20:29:10 +09:00
Arin(asus)
65065442a1 고창군립도서관 검색기 구현 및 라이선스 기간 연장
- GochangLibSearcher.cs: 고창군립도서관 HTTP API 검색기 추가
- 고창군립도서관 및 산하 9개 분관 검색 대상에 등록
- 라이선스 기간 2025.12.30까지 연장
- 어셈블리 버전 2025.09.03.2030으로 업데이트

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 20:28:34 +09:00
8e7df6f68d 광주시립통합도서관 검색시간 15->30, 대기시간+1초 추가 (나유민) 2025-09-02 23:19:45 +09:00
8f74fb5557 알라딘데이터추출시 버퍼꼬이는 증상 수정 2025-09-02 23:08:49 +09:00
SeungHo Yang
0cc71611d0 가격에 값이 없는 경우 발생하는 null 오류 수정 2025-08-20 20:43:34 +09:00
405c1d9c46 구두점 적용 로직 개선: ▼d/▼e 필드 세미콜론 적용 규칙 수정 2025-08-19 22:51:02 +09:00
Arin(asus)
e815c02feb 빌드버젼업 2025-08-14 22:58:06 +09:00
Arin(asus)
e2ae5d2937 매크로 113번 추가 2025-08-14 22:56:17 +09:00
399 changed files with 34385 additions and 6744 deletions

View File

@@ -2,7 +2,16 @@
"permissions": {
"allow": [
"Bash(git add:*)",
"WebFetch(domain:jnelib.jne.go.kr)"
"WebFetch(domain:jnelib.jne.go.kr)",
"Bash(node:*)",
"Bash(npm --version)",
"Bash(echo $OS)",
"Bash(claude mcp:*)",
"WebSearch",
"WebSearch",
"Bash(git commit:*)",
"Bash(git config:*)",
"Bash(git push:*)"
],
"deny": [],
"ask": []

3
ISBN_Check/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"dotnet.preferCSharpExtension": true
}

3
ISBN_Check/Main/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"dotnet.preferCSharpExtension": true
}

View File

@@ -29,12 +29,29 @@ namespace ISBN_Check_test
/// </summary>
private void InitializeComponent()
{
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
this.cb_filter = new System.Windows.Forms.ComboBox();
this.button1 = new System.Windows.Forms.Button();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.label1 = new System.Windows.Forms.Label();
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
this.start_idx = new System.Windows.Forms.TextBox();
this.end_idx = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.button2 = new System.Windows.Forms.Button();
this.cb_api = new System.Windows.Forms.ComboBox();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.btn_Yes24 = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
this.button3 = new System.Windows.Forms.Button();
this.panel2 = new System.Windows.Forms.Panel();
this.panel3 = new System.Windows.Forms.Panel();
this.button4 = new System.Windows.Forms.Button();
this.tbDelay = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.book_name = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.author = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.book_comp = new System.Windows.Forms.DataGridViewTextBoxColumn();
@@ -46,18 +63,8 @@ namespace ISBN_Check_test
this.sold_out = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.count = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.label1 = new System.Windows.Forms.Label();
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
this.start_idx = new System.Windows.Forms.TextBox();
this.end_idx = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.button2 = new System.Windows.Forms.Button();
this.cb_api = new System.Windows.Forms.ComboBox();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.btn_Yes24 = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
this.panel2 = new System.Windows.Forms.Panel();
this.panel3 = new System.Windows.Forms.Panel();
this.dvc_link = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.dvc_remark = new System.Windows.Forms.DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
@@ -76,7 +83,7 @@ namespace ISBN_Check_test
//
// button1
//
this.button1.Location = new System.Drawing.Point(416, 10);
this.button1.Location = new System.Drawing.Point(530, 11);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 2;
@@ -86,14 +93,14 @@ namespace ISBN_Check_test
//
// dataGridView1
//
dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
dataGridViewCellStyle4.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle4.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
dataGridViewCellStyle4.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle4.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle4.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.dataGridView1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle4;
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle1.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.dataGridView1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.book_name,
this.author,
@@ -105,28 +112,203 @@ namespace ISBN_Check_test
this.category,
this.sold_out,
this.Column1,
this.count});
this.count,
this.dvc_link,
this.dvc_remark});
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dataGridView1.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnF2;
this.dataGridView1.Location = new System.Drawing.Point(0, 0);
this.dataGridView1.Name = "dataGridView1";
dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
dataGridViewCellStyle6.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle6.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
dataGridViewCellStyle6.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle6.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle6.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle6.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.dataGridView1.RowHeadersDefaultCellStyle = dataGridViewCellStyle6;
dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle3.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
dataGridViewCellStyle3.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle3.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.dataGridView1.RowHeadersDefaultCellStyle = dataGridViewCellStyle3;
this.dataGridView1.RowTemplate.Height = 23;
this.dataGridView1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.CellSelect;
this.dataGridView1.Size = new System.Drawing.Size(1001, 471);
this.dataGridView1.Size = new System.Drawing.Size(1309, 471);
this.dataGridView1.TabIndex = 3;
this.dataGridView1.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellContentClick);
this.dataGridView1.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellDoubleClick);
this.dataGridView1.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dataGridView1_RowPostPaint);
this.dataGridView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.dataGridView1_KeyDown);
//
// label1
//
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(1046, 16);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(65, 12);
this.label1.TabIndex = 4;
this.label1.Text = "00:00:00.00";
this.label1.Click += new System.EventHandler(this.label1_Click);
//
// richTextBox1
//
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
this.richTextBox1.Name = "richTextBox1";
this.richTextBox1.Size = new System.Drawing.Size(1309, 100);
this.richTextBox1.TabIndex = 5;
this.richTextBox1.Text = "";
//
// start_idx
//
this.start_idx.Location = new System.Drawing.Point(272, 11);
this.start_idx.Name = "start_idx";
this.start_idx.Size = new System.Drawing.Size(42, 21);
this.start_idx.TabIndex = 6;
this.start_idx.Text = "1";
this.start_idx.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);
//
// end_idx
//
this.end_idx.Location = new System.Drawing.Point(340, 11);
this.end_idx.Name = "end_idx";
this.end_idx.Size = new System.Drawing.Size(42, 21);
this.end_idx.TabIndex = 6;
this.end_idx.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(320, 15);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(14, 12);
this.label2.TabIndex = 4;
this.label2.Text = "~";
//
// button2
//
this.button2.Location = new System.Drawing.Point(609, 11);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 2;
this.button2.Text = "리 셋";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// cb_api
//
this.cb_api.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cb_api.FormattingEnabled = true;
this.cb_api.Location = new System.Drawing.Point(12, 10);
this.cb_api.Name = "cb_api";
this.cb_api.Size = new System.Drawing.Size(121, 20);
this.cb_api.TabIndex = 0;
this.cb_api.SelectedIndexChanged += new System.EventHandler(this.cb_api_SelectedIndexChanged);
//
// progressBar1
//
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.progressBar1.Location = new System.Drawing.Point(1113, 10);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(184, 23);
this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
this.progressBar1.TabIndex = 7;
//
// btn_Yes24
//
this.btn_Yes24.Location = new System.Drawing.Point(767, 11);
this.btn_Yes24.Name = "btn_Yes24";
this.btn_Yes24.Size = new System.Drawing.Size(75, 23);
this.btn_Yes24.TabIndex = 8;
this.btn_Yes24.Text = "Yes반출";
this.btn_Yes24.UseVisualStyleBackColor = true;
this.btn_Yes24.Click += new System.EventHandler(this.btn_Yes24_Click);
//
// panel1
//
this.panel1.Controls.Add(this.label4);
this.panel1.Controls.Add(this.tbDelay);
this.panel1.Controls.Add(this.label3);
this.panel1.Controls.Add(this.button4);
this.panel1.Controls.Add(this.button3);
this.panel1.Controls.Add(this.cb_api);
this.panel1.Controls.Add(this.btn_Yes24);
this.panel1.Controls.Add(this.cb_filter);
this.panel1.Controls.Add(this.label1);
this.panel1.Controls.Add(this.button1);
this.panel1.Controls.Add(this.progressBar1);
this.panel1.Controls.Add(this.button2);
this.panel1.Controls.Add(this.end_idx);
this.panel1.Controls.Add(this.label2);
this.panel1.Controls.Add(this.start_idx);
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(1309, 47);
this.panel1.TabIndex = 9;
//
// button3
//
this.button3.Location = new System.Drawing.Point(688, 11);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(75, 23);
this.button3.TabIndex = 9;
this.button3.Text = "리셋(전체)";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// panel2
//
this.panel2.Controls.Add(this.richTextBox1);
this.panel2.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panel2.Location = new System.Drawing.Point(0, 518);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(1309, 100);
this.panel2.TabIndex = 10;
//
// panel3
//
this.panel3.Controls.Add(this.dataGridView1);
this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel3.Location = new System.Drawing.Point(0, 47);
this.panel3.Name = "panel3";
this.panel3.Size = new System.Drawing.Size(1309, 471);
this.panel3.TabIndex = 11;
//
// button4
//
this.button4.Location = new System.Drawing.Point(848, 11);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(75, 23);
this.button4.TabIndex = 10;
this.button4.Text = "목록초기화";
this.button4.UseVisualStyleBackColor = true;
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// tbDelay
//
this.tbDelay.Location = new System.Drawing.Point(454, 12);
this.tbDelay.Name = "tbDelay";
this.tbDelay.Size = new System.Drawing.Size(42, 21);
this.tbDelay.TabIndex = 12;
this.tbDelay.Text = "500";
this.tbDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(398, 17);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(53, 12);
this.label3.TabIndex = 11;
this.label3.Text = "지연시간";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(502, 17);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(23, 12);
this.label4.TabIndex = 13;
this.label4.Text = "ms";
//
// book_name
//
this.book_name.HeaderText = "도서명";
@@ -186,136 +368,27 @@ namespace ISBN_Check_test
//
// count
//
dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
this.count.DefaultCellStyle = dataGridViewCellStyle5;
dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
this.count.DefaultCellStyle = dataGridViewCellStyle2;
this.count.HeaderText = "검색갯수";
this.count.Name = "count";
this.count.Width = 80;
//
// label1
// dvc_link
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(719, 16);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(65, 12);
this.label1.TabIndex = 4;
this.label1.Text = "00:00:00.00";
this.label1.Click += new System.EventHandler(this.label1_Click);
this.dvc_link.HeaderText = "URL";
this.dvc_link.Name = "dvc_link";
//
// richTextBox1
// dvc_remark
//
this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.richTextBox1.Location = new System.Drawing.Point(0, 0);
this.richTextBox1.Name = "richTextBox1";
this.richTextBox1.Size = new System.Drawing.Size(1001, 100);
this.richTextBox1.TabIndex = 5;
this.richTextBox1.Text = "";
//
// start_idx
//
this.start_idx.Location = new System.Drawing.Point(272, 11);
this.start_idx.Name = "start_idx";
this.start_idx.Size = new System.Drawing.Size(42, 21);
this.start_idx.TabIndex = 6;
this.start_idx.Text = "1";
this.start_idx.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);
//
// end_idx
//
this.end_idx.Location = new System.Drawing.Point(340, 11);
this.end_idx.Name = "end_idx";
this.end_idx.Size = new System.Drawing.Size(42, 21);
this.end_idx.TabIndex = 6;
this.end_idx.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(320, 15);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(14, 12);
this.label2.TabIndex = 4;
this.label2.Text = "~";
//
// button2
//
this.button2.Location = new System.Drawing.Point(503, 10);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 2;
this.button2.Text = "리 셋";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// cb_api
//
this.cb_api.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cb_api.FormattingEnabled = true;
this.cb_api.Location = new System.Drawing.Point(12, 10);
this.cb_api.Name = "cb_api";
this.cb_api.Size = new System.Drawing.Size(121, 20);
this.cb_api.TabIndex = 0;
this.cb_api.SelectedIndexChanged += new System.EventHandler(this.cb_api_SelectedIndexChanged);
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(786, 10);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(184, 23);
this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
this.progressBar1.TabIndex = 7;
//
// btn_Yes24
//
this.btn_Yes24.Location = new System.Drawing.Point(590, 10);
this.btn_Yes24.Name = "btn_Yes24";
this.btn_Yes24.Size = new System.Drawing.Size(75, 23);
this.btn_Yes24.TabIndex = 8;
this.btn_Yes24.Text = "Yes반출";
this.btn_Yes24.UseVisualStyleBackColor = true;
this.btn_Yes24.Click += new System.EventHandler(this.btn_Yes24_Click);
//
// panel1
//
this.panel1.Controls.Add(this.cb_api);
this.panel1.Controls.Add(this.btn_Yes24);
this.panel1.Controls.Add(this.cb_filter);
this.panel1.Controls.Add(this.label1);
this.panel1.Controls.Add(this.button1);
this.panel1.Controls.Add(this.progressBar1);
this.panel1.Controls.Add(this.button2);
this.panel1.Controls.Add(this.end_idx);
this.panel1.Controls.Add(this.label2);
this.panel1.Controls.Add(this.start_idx);
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(1001, 47);
this.panel1.TabIndex = 9;
//
// panel2
//
this.panel2.Controls.Add(this.richTextBox1);
this.panel2.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panel2.Location = new System.Drawing.Point(0, 518);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(1001, 100);
this.panel2.TabIndex = 10;
//
// panel3
//
this.panel3.Controls.Add(this.dataGridView1);
this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel3.Location = new System.Drawing.Point(0, 47);
this.panel3.Name = "panel3";
this.panel3.Size = new System.Drawing.Size(1001, 471);
this.panel3.TabIndex = 11;
this.dvc_remark.HeaderText = "비고";
this.dvc_remark.Name = "dvc_remark";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1001, 618);
this.ClientSize = new System.Drawing.Size(1309, 618);
this.Controls.Add(this.panel3);
this.Controls.Add(this.panel2);
this.Controls.Add(this.panel1);
@@ -346,6 +419,14 @@ namespace ISBN_Check_test
private System.Windows.Forms.ComboBox cb_api;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Button btn_Yes24;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Panel panel3;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox tbDelay;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.DataGridViewTextBoxColumn book_name;
private System.Windows.Forms.DataGridViewTextBoxColumn author;
private System.Windows.Forms.DataGridViewTextBoxColumn book_comp;
@@ -357,9 +438,8 @@ namespace ISBN_Check_test
private System.Windows.Forms.DataGridViewTextBoxColumn sold_out;
private System.Windows.Forms.DataGridViewTextBoxColumn Column1;
private System.Windows.Forms.DataGridViewTextBoxColumn count;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Panel panel3;
private System.Windows.Forms.DataGridViewTextBoxColumn dvc_link;
private System.Windows.Forms.DataGridViewTextBoxColumn dvc_remark;
}
}

View File

@@ -11,6 +11,8 @@ using System.Threading;
using System.Windows.Forms;
using WindowsFormsApp1;
using System.Text.RegularExpressions;
using System.Diagnostics.Eventing.Reader;
using Org.BouncyCastle.Pkcs;
namespace ISBN_Check_test
{
@@ -20,12 +22,20 @@ namespace ISBN_Check_test
public Form1()
{
InitializeComponent();
this.dataGridView1.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2;
this.Text = $"{Application.ProductName} ver {Application.ProductVersion}";
}
private void Form1_Load(object sender, EventArgs e)
{
this.Show();
Application.DoEvents();
string[] api_list = { "다음", "네이버", "알라딘" };
cb_api.Items.AddRange(api_list);
cb_api.SelectedIndex = 2;
Application.DoEvents();
cb_filter_SelectedIndexChanged(null, null);
Application.DoEvents();
}
private void button2_Click(object sender, EventArgs e)
{
@@ -44,8 +54,16 @@ namespace ISBN_Check_test
if (cb_api.SelectedIndex == -1) { MessageBox.Show("조건이 선택되지 않았습니다."); return; }
if (cb_filter.SelectedIndex == -1) { MessageBox.Show("조건이 선택되지 않았습니다."); return; }
this.dataGridView1.AutoResizeColumn(3);
this.Refresh();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
if (int.TryParse(tbDelay.Text, out int delayms) == false)
{
MessageBox.Show("지연시간 입력 오류");
return;
}
var sistr = start_idx.Text.Trim();
var eistr = end_idx.Text.Trim();
@@ -68,7 +86,7 @@ namespace ISBN_Check_test
ei = ei - 1;
si = si - 1;
if(si < 0 || ei <0)
if (si < 0 || ei < 0)
{
MessageBox.Show("시작,종료번호를 확인하세요");
return;
@@ -96,7 +114,7 @@ namespace ISBN_Check_test
Naver_API(dataGridView1, si, ei);
break;
case 2:
Aladin_API(dataGridView1, si, ei);
Aladin_API(dataGridView1, si, ei, delayms);
break;
}
@@ -118,7 +136,7 @@ namespace ISBN_Check_test
/// 알라딘 API
/// </summary>
/// <param name="gridview"></param>
private void Aladin_API(DataGridView gridview, int start, int end)
private void Aladin_API(DataGridView gridview, int start, int end, int delayms)
{
// 도서명 / 저자 / 출판사 / isbn / 정가
// 발행일 / 도서분류 / 재고
@@ -151,20 +169,32 @@ namespace ISBN_Check_test
break;
}
// string query = dataGridView1.Rows[a].Cells["isbn"].Value?.ToString() ?? string.Empty;
string query = Set_query(type, a ); //a=는줄번호이고 idx는 -1 해야함
string query = Set_query(type, a); //a=는줄번호이고 idx는 -1 해야함
if (gridview.Rows[a].DefaultCellStyle.BackColor == Color.Yellow)
continue;
else if (gridview.Rows[a ].DefaultCellStyle.BackColor == Color.LightGray)
gridview.Rows[a ].DefaultCellStyle.BackColor = Color.Empty;
else if (gridview.Rows[a].DefaultCellStyle.BackColor == Color.LightGray)
gridview.Rows[a].DefaultCellStyle.BackColor = Color.Empty;
// string aladin = api.Aladin(query, "ISBN13", param);
string aladin = api.Aladin(query, type, param);
insert_By_Aladin(aladin, a);
try
{
richTextBox1.Text = aladin;
}
catch { }
//var aladin = api.Aladin(query, type, param);
var aladin_struct = api.Aladin_struct(query, type, out string xmlString);
insert_By_Aladin(aladin_struct, a, xmlString);
if (aladin_struct.Any())
richTextBox1.Text = aladin_struct.First().ToString();
else
richTextBox1.Text = "No Data";
System.Threading.Thread.Sleep(delayms);
//try
//{
// var sb = new StringBuilder();
// foreach (var item in aladin)
// {
// sb.AppendLine(string.Join("|", item));
// }
// richTextBox1.Text = aladin_struct.ToString();// sb.ToString();
//}
//catch { }
}
}
string Set_query(string type, int idx)
@@ -308,17 +338,63 @@ namespace ISBN_Check_test
{
progressBar1.PerformStep();
}
void insert_By_Aladin(string data, int row)
void insert_By_Aladin(List<AladinBookData> insert, int row, string xmlString)
{
if (row >0)
if (row > 0)
{
dataGridView1.Rows[row - 1].Selected = false;
}
dataGridView1.Rows[row ].Selected = true;
dataGridView1.Rows[row].Selected = true;
string[] insert = data.Split('|');
//데이터가 없다면 처리하지 않는다.
if (insert.Any() == false)
{
dataGridView1.Rows[row].Cells["count"].Value = "0";
dataGridView1.Rows[row].Cells["dvc_remark"].Value = $"No Data\n{xmlString}";
return;
}
if (data == "") { return; }
var item = insert.First();
// pubDate형 보기편하게 DateTime형으로 재정리
string pubdate = item.PubDate;
try
{
//pubdate = item.PubDate;
pubdate = String.Format("{0:yyyy/MM/dd}",
DateTime.Parse(pubdate.Remove(pubdate.IndexOf(" G"))));
}
catch (Exception ex) { MessageBox.Show(item.ToString()); }
//카테고리명 정리
item.CategoryName = Aladin_CategorySort(item.CategoryName);
//for (int a = 0; a < insert.Length; a++)
//{
// if (a % 8 == 6) { insert[a] = Aladin_CategorySort(insert[a]); }
//}
dataGridView1.Rows[row].Cells["Column1"].Value += item.ToString();// string.Join("|", insert) + "|";
if (item.Description.StartsWith("<")) item.Description = item.Description.Substring(item.Description.IndexOf(">")+1);
dataGridView1.Rows[row].Cells["dvc_remark"].Value = item.Description;// $"{insert.Count}건";
dataGridView1.Rows[row].Cells["dvc_link"].Value = $"{item.Link}";
dataGridView1.Rows[row].Cells["count"].Value = $"{insert.Count}";
dataGridView1.Rows[row].DefaultCellStyle.BackColor = Color.LightGray;
if (cb_filter.SelectedItem.ToString() == "별치조사")
input_api_aladin(item, row, pubdate);
input_api(item, row, pubdate);
}
void insert_By_Aladin(string[] insert, int row)
{
if (row > 0)
{
dataGridView1.Rows[row - 1].Selected = false;
}
dataGridView1.Rows[row].Selected = true;
if (insert.Any() == false) { return; }
// pubDate형 보기편하게 DateTime형으로 재정리
string newstring = "";
@@ -327,7 +403,7 @@ namespace ISBN_Check_test
newstring = String.Format("{0:yyyy/MM/dd}",
DateTime.Parse(insert[5].Remove(insert[5].IndexOf(" G"))));
}
catch (Exception ex) { MessageBox.Show(data); }
catch (Exception ex) { MessageBox.Show(string.Join("|", insert)); }
for (int a = 0; a < insert.Length; a++)
{
@@ -352,6 +428,17 @@ namespace ISBN_Check_test
return insert;
}
void input_api_aladin(AladinBookData data, int row, string date)
{
dataGridView1.Rows[row].Cells["book_name"].Value = data.Title;
dataGridView1.Rows[row].Cells["author"].Value = data.Author;
dataGridView1.Rows[row].Cells["book_comp"].Value = data.Publisher;
dataGridView1.Rows[row].Cells["price2"].Value = data.PriceStandard;
dataGridView1.Rows[row].Cells["pubDate"].Value = date;
dataGridView1.Rows[row].Cells["category"].Value = data.CategoryName;
}
void input_api_aladin(string[] data, int row, string date)
{
dataGridView1.Rows[row].Cells["book_name"].Value = data[0];
@@ -363,7 +450,7 @@ namespace ISBN_Check_test
}
void insert_By_Naver(string value, int row)
{
if (row > 0) { dataGridView1.Rows[row -1].Selected = false; }
if (row > 0) { dataGridView1.Rows[row - 1].Selected = false; }
dataGridView1.Rows[row].Selected = true;
if (value == "") return;
@@ -474,6 +561,46 @@ namespace ISBN_Check_test
input_api(grid, row, newstring);
}
void input_api(AladinBookData value, int idx, string date)
{
//string[] param = { "title", "authors", "publisher", "isbn", "price",
// "datetime", "status" };
//string[] param = { "title", "author", "publisher", "isbn13", "priceStandard",
// "pubDate", "categoryName", "stockStatus", };
bool[] chk = { false, false, false };
string book_name = dataGridView1.Rows[idx].Cells["book_name"].Value?.ToString() ?? string.Empty;
string author = dataGridView1.Rows[idx].Cells["author"].Value?.ToString() ?? string.Empty;
string book_comp = dataGridView1.Rows[idx].Cells["book_comp"].Value?.ToString() ?? string.Empty;
if (value.Title == book_name) chk[0] = true;
if (value.Author.Contains(author) == true) chk[1] = true;
else if (author.Contains(value.Author) == true) chk[1] = true;
else if (value.Author == author) chk[1] = true;
if (value.Publisher.Contains(book_comp) == true) chk[2] = true;
else if (book_comp.Contains(value.Publisher) == true) chk[2] = true;
else if (value.Publisher == book_comp) chk[2] = true;
if (chk[0] == true && chk[1] == true && chk[2] == true)
{
dataGridView1.Rows[idx].Cells["isbn"].Value = value.Isbn13;
dataGridView1.Rows[idx].Cells["price2"].Value = value.PriceStandard;
dataGridView1.Rows[idx].Cells["pubDate"].Value = date;
//if (cb_api.SelectedIndex == 2)
dataGridView1.Rows[idx].Cells["category"].Value = value.CategoryName;
dataGridView1.Rows[idx].Cells["sold_out"].Value = value.StockStatus;
dataGridView1.Rows[idx].DefaultCellStyle.BackColor = Color.Yellow;
}
count_res();
}
/// <summary>
/// API에서 가져온 데이터가 요구한 데이터와 일치하는지 알아보는 함수
/// </summary>
@@ -514,15 +641,15 @@ namespace ISBN_Check_test
#region
private void count_res()
{
String_Text st = new String_Text();
int count = dataGridView1.Rows.Count;
for (int a = 0; a < count; a++)
{
string search_data = dataGridView1.Rows[a].Cells["Column1"].Value?.ToString() ?? string.Empty;
int tmp_count = st.Char_count(search_data, '|');
int lcount = tmp_count / 8;
dataGridView1.Rows[a].Cells["count"].Value = lcount.ToString();
}
//String_Text st = new String_Text();
//int count = dataGridView1.Rows.Count;
//for (int a = 0; a < count; a++)
//{
// string search_data = dataGridView1.Rows[a].Cells["Column1"].Value?.ToString() ?? string.Empty;
// int tmp_count = st.Char_count(search_data, '|');
// int lcount = tmp_count / 8;
// dataGridView1.Rows[a].Cells["count"].Value = lcount.ToString();
//}
}
#endregion
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
@@ -569,12 +696,49 @@ namespace ISBN_Check_test
}
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Rows[rowidx].Cells["Column1"].Value == null ||
dataGridView1.Rows[rowidx].Cells["Column1"].Value.ToString() == "") { return; }
Form2 f2 = new Form2(this);
f2.row = rowidx;
f2.Call_API = cb_api.Text;
f2.Show();
if (e.RowIndex < 0 || e.ColumnIndex < 0) return;
var column = this.dataGridView1.Columns[e.ColumnIndex];
if (column.Name.Equals("dvc_remark"))
{
var value = this.dataGridView1.Rows[e.RowIndex].Cells[column.Name].Value?.ToString() ?? string.Empty;
if(value.StartsWith("<"))
{
value = value.Substring(value.IndexOf(">") + 1);
}
else this.richTextBox1.Text = value;
}
else if (column.Name.Equals("Column"))
{
var value = this.dataGridView1.Rows[e.RowIndex].Cells[column.Name].Value?.ToString() ?? string.Empty;
if (value == string.Empty) return;
Form2 f2 = new Form2(this);
f2.row = rowidx;
f2.Call_API = cb_api.Text;
f2.Show();
}
else if (column.Name.Equals("dvc_link"))
{
var value = this.dataGridView1.Rows[e.RowIndex].Cells[column.Name].Value?.ToString() ?? string.Empty;
if (value == string.Empty) return;
try
{
var prc = new System.Diagnostics.Process();
prc.StartInfo = new System.Diagnostics.ProcessStartInfo()
{
FileName = value,
UseShellExecute = true
};
prc.Start();
}
catch (Exception ex)
{
}
}
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
@@ -601,6 +765,7 @@ namespace ISBN_Check_test
{
string[] aladin = { "도서명 + 저자", "도서명", "저자", "출판사", "별치조사" };
cb_filter.Items.AddRange(aladin);
cb_filter.SelectedIndex = cb_filter.Items.Count - 1;
}
Must_Col(cb_api.SelectedIndex);
}
@@ -640,7 +805,8 @@ namespace ISBN_Check_test
{
if (System.Diagnostics.Debugger.IsAttached)
{
string[] lst = { "9791193110584",
string[] lst = { "9788965427520",
"9791193110584",
"9791168672260",
"9788993858396",
"9791171200351",
@@ -657,5 +823,22 @@ namespace ISBN_Check_test
end_idx.Text = (this.dataGridView1.Rows.Count - 1).ToString();
}
}
private void button3_Click(object sender, EventArgs e)
{
for (int a = 0; a < dataGridView1.Rows.Count - 1; a++)
{
//if (dataGridView1.Rows[a].DefaultCellStyle.BackColor != Color.Yellow)
{
dataGridView1.Rows[a].Cells["Column1"].Value = "";
dataGridView1.Rows[a].DefaultCellStyle.BackColor = Color.Empty;
}
}
}
private void button4_Click(object sender, EventArgs e)
{
dataGridView1.Rows.Clear();
}
}
}

View File

@@ -150,4 +150,10 @@
<metadata name="count.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dvc_link.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dvc_remark.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>

View File

@@ -10,9 +10,45 @@ using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
namespace ISBN_Check_test
{
/// <summary>
/// 알라딘 API 응답 데이터 구조체
/// </summary>
public class AladinBookData
{
public string Title { get; set; }
public string Link { get; set; }
public string Author { get; set; }
public string PubDate { get; set; }
public string Description { get; set; }
public string Isbn { get; set; }
public string Isbn13 { get; set; }
public string PriceSales { get; set; }
public string PriceStandard { get; set; }
public string StockStatus { get; set; }
public string Mileage { get; set; }
public string Cover { get; set; }
public string CategoryId { get; set; }
public string CategoryName { get; set; }
public string Publisher { get; set; }
public string CustomerReviewRank { get; set; }
public string FullDescription { get; set; }
public string FullDescription2 { get; set; }
public string ItemId { get; set; }
/// <summary>
/// 지정된 필드들을 "|" 구분자로 출력
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"{Title}|{Author}|{Publisher}|{Isbn13}|{PriceStandard}|{PubDate}|{CategoryName}|{StockStatus}";
}
}
class API
{
/// <summary>
@@ -22,7 +58,7 @@ namespace ISBN_Check_test
/// <param name="QueryType"></param>
/// <param name="Param"></param>
/// <returns></returns>
public string Aladin(string Query, string QueryType, string[] Param)
public string[] Aladin(string Query, string QueryType, string[] Param)
{
string result = string.Empty;
// 쿼리 생성
@@ -49,58 +85,127 @@ namespace ISBN_Check_test
// xml형식을 json형식으로 변환
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var json = JsonConvert.SerializeXmlNode(doc);
// json형식 분석을 위해 JavaScriptSerializer 개체 생성
JavaScriptSerializer js = new JavaScriptSerializer();
var xdoc = XDocument.Parse(xml);
var xroot = xdoc.Root;
// 런타임에 개체를 확인하여 사용할수 있는 dynamic을 이용해 역직렬화
dynamic dob = js.Deserialize<dynamic>(json);
// XML에서 직접 totalResults와 item 추출 (XDocument 사용)
XNamespace ns = "http://www.aladin.co.kr/ttb/apiguide.aspx";
// "object"내에 있는것을 얻어오기 위해 다시 dynamic변수에 참조
dynamic docs = "";
try
// totalResults 추출
string totalResults = xdoc.Descendants(ns + "totalResults").FirstOrDefault()?.Value ?? "0";
// item들 추출
var itemElements = xdoc.Descendants(ns + "item");
if (!itemElements.Any())
{
docs = dob["object"]["item"];
return new string[] { };
}
catch
{
return "";
}
int length = 0;
int length = itemElements.Count();
int ID_length = Param.Length;
// 검색 결과가 1개 이하일 경우, 오류가 발생하여 try/catch문 사용.
try
// XML item들을 순회하면서 필요한 데이터 추출 (XDocument 사용)
List<string[]> retval = new List<string[]>();
foreach (var itemElement in itemElements)
{
// docs는 요소 컬렉션으로 object로 변환.
object[] buf = docs;
length = buf.Length;
}
catch
{
object buf = docs;
length = 1;
}
for (int a = 0; a < length; a++)
{
List<string> tmp_data = new List<string>();
string[] buffer = new string[ID_length];
for (int b = 0; b < ID_length; b++)
{
if (length == 1)
{
tmp_data.Add(docs[Param[b]]);
}
else
{
tmp_data.Add(docs[a][Param[b]]);
}
result += tmp_data[b] + "|";
buffer[b] = itemElement.Element(ns + Param[b])?.Value ?? "";
}
result += "\n";
//retval.Add(buffer);
return buffer;
}
return result;
return new string[] { };
}
/// <summary>
/// https://blog.aladin.co.kr/openapi 참고 (구조체 반환 버전)
/// </summary>
/// <param name="Query"></param>
/// <param name="QueryType"></param>
/// <returns>AladinBookData 리스트</returns>
public List<AladinBookData> Aladin_struct(string Query, string QueryType,out string xml)
{
// 쿼리 생성
string key = "ttbgloriabook1512001";
string site = "http://www.aladin.co.kr/ttb/api/ItemSearch.aspx";
string query = string.Format("{0}?query={1}&TTBKey={2}&output=xml&querytype={3}&MaxResults={4}",
site, Query, key, QueryType, 30.ToString());
xml = string.Empty;
try
{
// 쿼리를 입력인자로 WebRequest 개채 생성
WebRequest request = WebRequest.Create(query);
// WebResponse개체를 통해 서비스 요청.
WebResponse response = request.GetResponse();
// 결과문자열 확인
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
xml = reader.ReadToEnd();
stream.Close();
var xdoc = XDocument.Parse(xml);
// XML에서 직접 totalResults와 item 추출 (XDocument 사용)
XNamespace ns = "http://www.aladin.co.kr/ttb/apiguide.aspx";
// totalResults 추출
string totalResults = xdoc.Descendants(ns + "totalResults").FirstOrDefault()?.Value ?? "0";
// item들 추출
var itemElements = xdoc.Descendants(ns + "item");
List<AladinBookData> resultList = new List<AladinBookData>();
if (!itemElements.Any())
{
Console.WriteLine(Query);
return resultList;
}
// 모든 item을 순회하며 리스트에 추가
foreach (var itemElement in itemElements)
{
AladinBookData bookData = new AladinBookData
{
ItemId = itemElement.Attribute("itemId")?.Value ?? "",
Title = itemElement.Element(ns + "title")?.Value ?? "",
Link = itemElement.Element(ns + "link")?.Value ?? "",
Author = itemElement.Element(ns + "author")?.Value ?? "",
PubDate = itemElement.Element(ns + "pubDate")?.Value ?? "",
Description = itemElement.Element(ns + "description")?.Value ?? "",
Isbn = itemElement.Element(ns + "isbn")?.Value ?? "",
Isbn13 = itemElement.Element(ns + "isbn13")?.Value ?? "",
PriceSales = itemElement.Element(ns + "priceSales")?.Value ?? "",
PriceStandard = itemElement.Element(ns + "priceStandard")?.Value ?? "",
StockStatus = itemElement.Element(ns + "stockStatus")?.Value ?? "",
Mileage = itemElement.Element(ns + "mileage")?.Value ?? "",
Cover = itemElement.Element(ns + "cover")?.Value ?? "",
CategoryId = itemElement.Element(ns + "categoryId")?.Value ?? "",
CategoryName = itemElement.Element(ns + "categoryName")?.Value ?? "",
Publisher = itemElement.Element(ns + "publisher")?.Value ?? "",
CustomerReviewRank = itemElement.Element(ns + "customerReviewRank")?.Value ?? "",
FullDescription = itemElement.Element(ns + "fulldescription")?.Value ?? "",
FullDescription2 = itemElement.Element(ns + "fulldescription2")?.Value ?? ""
};
resultList.Add(bookData);
}
return resultList;
}
catch (Exception ex)
{
// 에러 발생 시 빈 리스트 반환
return new List<AladinBookData>();
}
}
/// <summary>
/// https://blog.aladin.co.kr/openapi 참고
/// </summary>
@@ -194,7 +299,7 @@ namespace ISBN_Check_test
// url 생성
string url = "https://openapi.naver.com/v1/search/book_adv?";
for(int a = 0; a < Query.Length; a++)
for (int a = 0; a < Query.Length; a++)
{
url += string.Format("{0}={1}&", QueryType[a], Query[a]);
}
@@ -278,7 +383,7 @@ namespace ISBN_Check_test
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
string json = reader.ReadToEnd();
stream.Close();
JavaScriptSerializer js = new JavaScriptSerializer();
dynamic dob = js.Deserialize<dynamic>(json);
dynamic docs = dob["documents"];
@@ -287,18 +392,20 @@ namespace ISBN_Check_test
int length = buf.Length;
int ID_length = Param.Length;
for(int a = 0; a < length; a++)
for (int a = 0; a < length; a++)
{
List<object> tmp_data = new List<object>();
for(int b = 0; b < ID_length; b++)
for (int b = 0; b < ID_length; b++)
{
if (Param[b] == "authors") {
if (Param[b] == "authors")
{
object[] tmp = docs[a][Param[b]];
string tmp_str = string.Empty;
for(int j = 0; j < tmp.Length; j++)
for (int j = 0; j < tmp.Length; j++)
{
tmp_str += tmp[j];
if (j < tmp.Length - 1) {
if (j < tmp.Length - 1)
{
tmp_str += ", ";
}
}
@@ -306,7 +413,8 @@ namespace ISBN_Check_test
result += tmp_data[b] + "|";
tmp_str = "";
}
else {
else
{
tmp_data.Add(docs[a][Param[b]]);
result += tmp_data[b] + "|";
}

View File

@@ -41,15 +41,15 @@ namespace ISBN_Check_test
else { tb_price.Text = ""; }
string data = f1GridView.Rows[row].Cells["Column1"].Value.ToString();
var data = (string[])f1GridView.Rows[row].Cells["Column1"].Value;
inputGrid(data);
}
private void inputGrid(string data)
private void inputGrid(string[] tmp)
{
dataGridView1.Rows.Clear();
// 도서명 / 저자 / 출판사 / isbn / 출간일 / 카테고리 / 품절여부
string[] tmp = data.Split('|');
//string[] tmp = data.Split('|');
string[] grid = { "", "", "", "", "", "", "", "" };
for (int a = 0; a < tmp.Length; a++)
@@ -186,8 +186,8 @@ namespace ISBN_Check_test
string type = "Title";
string query = tb_book_name.Text;
string aladin = api.Aladin(query, type, param);
if (aladin == "") return;
var aladin = api.Aladin(query, type, param);
if (aladin.Any()==false) return;
inputGrid(aladin);
}

View File

@@ -65,32 +65,32 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.8.5.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
<HintPath>packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll</HintPath>
<HintPath>..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf, Version=3.14.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<HintPath>packages\Google.Protobuf.3.14.0\lib\net45\Google.Protobuf.dll</HintPath>
<HintPath>..\packages\Google.Protobuf.3.14.0\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="K4os.Compression.LZ4, Version=1.1.11.0, Culture=neutral, PublicKeyToken=2186fa9121ef231d, processorArchitecture=MSIL">
<HintPath>packages\K4os.Compression.LZ4.1.1.11\lib\net46\K4os.Compression.LZ4.dll</HintPath>
<HintPath>..\packages\K4os.Compression.LZ4.1.1.11\lib\net46\K4os.Compression.LZ4.dll</HintPath>
</Reference>
<Reference Include="K4os.Compression.LZ4.Streams, Version=1.1.11.0, Culture=neutral, PublicKeyToken=2186fa9121ef231d, processorArchitecture=MSIL">
<HintPath>packages\K4os.Compression.LZ4.Streams.1.1.11\lib\net46\K4os.Compression.LZ4.Streams.dll</HintPath>
<HintPath>..\packages\K4os.Compression.LZ4.Streams.1.1.11\lib\net46\K4os.Compression.LZ4.Streams.dll</HintPath>
</Reference>
<Reference Include="K4os.Hash.xxHash, Version=1.0.6.0, Culture=neutral, PublicKeyToken=32cd54395057cec3, processorArchitecture=MSIL">
<HintPath>packages\K4os.Hash.xxHash.1.0.6\lib\net46\K4os.Hash.xxHash.dll</HintPath>
<HintPath>..\packages\K4os.Hash.xxHash.1.0.6\lib\net46\K4os.Hash.xxHash.dll</HintPath>
</Reference>
<Reference Include="MySql.Data, Version=8.0.25.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<HintPath>packages\MySql.Data.8.0.25\lib\net452\MySql.Data.dll</HintPath>
<HintPath>..\packages\MySql.Data.8.0.25\lib\net452\MySql.Data.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Renci.SshNet, Version=2020.0.1.0, Culture=neutral, PublicKeyToken=1cee9f8bde3db106, processorArchitecture=MSIL">
<HintPath>packages\SSH.NET.2020.0.1\lib\net40\Renci.SshNet.dll</HintPath>
<HintPath>..\packages\SSH.NET.2020.0.1\lib\net40\Renci.SshNet.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel" />
<Reference Include="System.ComponentModel.DataAnnotations" />
@@ -99,14 +99,14 @@
<Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Transactions" />
<Reference Include="System.Web.Extensions" />
@@ -120,10 +120,10 @@
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Ubiety.Dns.Core, Version=2.2.1.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<HintPath>packages\MySql.Data.8.0.25\lib\net452\Ubiety.Dns.Core.dll</HintPath>
<HintPath>..\packages\MySql.Data.8.0.25\lib\net452\Ubiety.Dns.Core.dll</HintPath>
</Reference>
<Reference Include="Zstandard.Net, Version=1.1.7.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<HintPath>packages\MySql.Data.8.0.25\lib\net452\Zstandard.Net.dll</HintPath>
<HintPath>..\packages\MySql.Data.8.0.25\lib\net452\Zstandard.Net.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>

24
ISBN_Check/Main/Main.sln Normal file
View File

@@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ISBN_Check_test", "ISBN_Check_test.csproj", "{B1FE7D47-6EFF-E4AE-FF42-BADB7C89CEEE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B1FE7D47-6EFF-E4AE-FF42-BADB7C89CEEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1FE7D47-6EFF-E4AE-FF42-BADB7C89CEEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1FE7D47-6EFF-E4AE-FF42-BADB7C89CEEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1FE7D47-6EFF-E4AE-FF42-BADB7C89CEEE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E8EB61EB-992B-4C29-AC57-A0B63137A787}
EndGlobalSection
EndGlobal

View File

@@ -31,6 +31,6 @@ using System.Runtime.InteropServices;
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("25.10.29.2300")]
// [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("25.10.29.2300")]

View File

@@ -12,6 +12,7 @@ using WindowsFormsApp1;
using System.Reflection;
using System.Text.RegularExpressions;
namespace ISBN_Check_test
{
public partial class Yes24 : Form
@@ -55,16 +56,17 @@ namespace ISBN_Check_test
int count = f1.dataGridView1.Rows.Count - 1;
string price = "";
for (int a = 0; a < count; a++)
foreach(DataGridViewRow drowview in f1.dataGridView1.Rows)
{
if (f1.dataGridView1.Rows[a].Cells["price"].Value != null)
if (drowview.Cells["price"].Value != null)
{
price = f1.dataGridView1.Rows[a].Cells["price"].Value.ToString();
price = drowview.Cells["price"].Value.ToString();
}
var bookName = f1.dataGridView1.Rows[a].Cells["book_name"].Value?.ToString() ?? string.Empty;
var author = f1.dataGridView1.Rows[a].Cells["author"].Value?.ToString() ?? string.Empty;
var bookComp = f1.dataGridView1.Rows[a].Cells["book_comp"].Value?.ToString() ?? string.Empty;
var bookName = drowview.Cells["book_name"].Value?.ToString() ?? string.Empty;
var author = drowview.Cells["author"].Value?.ToString() ?? string.Empty;
var bookComp = drowview.Cells["book_comp"].Value?.ToString() ?? string.Empty;
if (string.IsNullOrEmpty(bookName) && string.IsNullOrEmpty(author) && string.IsNullOrEmpty(bookComp)) continue;
List<string> grid = new List<string>();
grid.Add(bookName);
@@ -73,7 +75,7 @@ namespace ISBN_Check_test
grid.Add(Replace_target(author, "author"));
grid.Add(bookComp);
grid.Add(Replace_target(bookComp, "book_comp"));
grid.Add(price);
dataGridView1.Rows.Add(grid.ToArray());
}
@@ -124,15 +126,17 @@ namespace ISBN_Check_test
private void btn_change_Click(object sender, EventArgs e)
{
string[,] grid = new string[dataGridView1.Rows.Count, 6];
for (int a = 0; a < dataGridView1.Rows.Count; a++)
var idx = 0;
foreach (DataGridViewRow drv in dataGridView1.Rows)// int a = 0; a < dataGridView1.Rows.Count; a++)
{
string price = dataGridView1.Rows[a].Cells["price"].Value.ToString();
int count = a + 1;
grid[a, 0] = count.ToString();
grid[a, 1] = dataGridView1.Rows[a].Cells["after_book_name"].Value.ToString();
grid[a, 3] = dataGridView1.Rows[a].Cells["after_book_comp"].Value.ToString();
grid[a, 4] = Regex.Replace(price, @"[^0-9]", "");
grid[a, 5] = "1";
string price = drv.Cells["price"].Value?.ToString() ?? string.Empty;
int count = idx + 1;
grid[idx, 0] = count.ToString();
grid[idx, 1] = drv.Cells["after_book_name"].Value.ToString();
grid[idx, 3] = drv.Cells["after_book_comp"].Value.ToString();
grid[idx, 4] = Regex.Replace(price, @"[^0-9]", "");
grid[idx, 5] = "1";
idx += 1;
}
Excel_change(grid);
}

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@@ -1,280 +0,0 @@
namespace ISBN_Client
{
partial class Client
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.rtb_Ip = new System.Windows.Forms.RichTextBox();
this.lbl_cnt = new System.Windows.Forms.Label();
this.lbl_filename = new System.Windows.Forms.Label();
this.lbl_ClientVer = new System.Windows.Forms.Label();
this.lbl_SerVer = new System.Windows.Forms.Label();
this.lbl_Files = new System.Windows.Forms.Label();
this.lbl_status = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.btn_Close = new System.Windows.Forms.Button();
this.btn_ok = new System.Windows.Forms.Button();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.file_name = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.update_status = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// panel1
//
this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panel1.Controls.Add(this.rtb_Ip);
this.panel1.Controls.Add(this.lbl_cnt);
this.panel1.Controls.Add(this.lbl_filename);
this.panel1.Controls.Add(this.lbl_ClientVer);
this.panel1.Controls.Add(this.lbl_SerVer);
this.panel1.Controls.Add(this.lbl_Files);
this.panel1.Controls.Add(this.lbl_status);
this.panel1.Controls.Add(this.label7);
this.panel1.Controls.Add(this.progressBar1);
this.panel1.Controls.Add(this.label3);
this.panel1.Controls.Add(this.label2);
this.panel1.Controls.Add(this.label1);
this.panel1.Location = new System.Drawing.Point(12, 12);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(325, 268);
this.panel1.TabIndex = 5;
//
// rtb_Ip
//
this.rtb_Ip.BackColor = System.Drawing.SystemColors.Control;
this.rtb_Ip.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.rtb_Ip.Location = new System.Drawing.Point(124, 102);
this.rtb_Ip.Name = "rtb_Ip";
this.rtb_Ip.ReadOnly = true;
this.rtb_Ip.Size = new System.Drawing.Size(190, 61);
this.rtb_Ip.TabIndex = 5;
this.rtb_Ip.Text = "";
//
// lbl_cnt
//
this.lbl_cnt.AutoSize = true;
this.lbl_cnt.Location = new System.Drawing.Point(265, 217);
this.lbl_cnt.Name = "lbl_cnt";
this.lbl_cnt.Size = new System.Drawing.Size(45, 12);
this.lbl_cnt.TabIndex = 4;
this.lbl_cnt.Text = "(10/10)";
//
// lbl_filename
//
this.lbl_filename.Location = new System.Drawing.Point(20, 217);
this.lbl_filename.Name = "lbl_filename";
this.lbl_filename.Size = new System.Drawing.Size(211, 12);
this.lbl_filename.TabIndex = 3;
//
// lbl_ClientVer
//
this.lbl_ClientVer.AutoSize = true;
this.lbl_ClientVer.Location = new System.Drawing.Point(124, 52);
this.lbl_ClientVer.Name = "lbl_ClientVer";
this.lbl_ClientVer.Size = new System.Drawing.Size(0, 12);
this.lbl_ClientVer.TabIndex = 2;
//
// lbl_SerVer
//
this.lbl_SerVer.AutoSize = true;
this.lbl_SerVer.Location = new System.Drawing.Point(124, 26);
this.lbl_SerVer.Name = "lbl_SerVer";
this.lbl_SerVer.Size = new System.Drawing.Size(0, 12);
this.lbl_SerVer.TabIndex = 2;
//
// lbl_Files
//
this.lbl_Files.AutoSize = true;
this.lbl_Files.Location = new System.Drawing.Point(124, 79);
this.lbl_Files.Name = "lbl_Files";
this.lbl_Files.Size = new System.Drawing.Size(0, 12);
this.lbl_Files.TabIndex = 2;
//
// lbl_status
//
this.lbl_status.Font = new System.Drawing.Font("굴림", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.lbl_status.ForeColor = System.Drawing.Color.DeepPink;
this.lbl_status.Location = new System.Drawing.Point(-3, 166);
this.lbl_status.Name = "lbl_status";
this.lbl_status.Size = new System.Drawing.Size(317, 29);
this.lbl_status.TabIndex = 0;
this.lbl_status.Text = "최신파일입니다 !!";
this.lbl_status.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label7
//
this.label7.AutoSize = true;
this.label7.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.label7.Location = new System.Drawing.Point(12, 52);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(106, 12);
this.label7.TabIndex = 0;
this.label7.Text = "클라이언트버전 :";
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(22, 232);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(288, 16);
this.progressBar1.TabIndex = 1;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.label3.Location = new System.Drawing.Point(51, 26);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(67, 12);
this.label3.TabIndex = 0;
this.label3.Text = "서버버전 :";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.label2.Location = new System.Drawing.Point(2, 79);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(116, 12);
this.label2.TabIndex = 0;
this.label2.Text = "업데이트 파일 수 :";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.label1.Location = new System.Drawing.Point(51, 105);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(67, 12);
this.label1.TabIndex = 0;
this.label1.Text = "설치경로 :";
//
// btn_Close
//
this.btn_Close.Font = new System.Drawing.Font("굴림", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.btn_Close.Location = new System.Drawing.Point(197, 294);
this.btn_Close.Name = "btn_Close";
this.btn_Close.Size = new System.Drawing.Size(123, 34);
this.btn_Close.TabIndex = 3;
this.btn_Close.Text = "취 소";
this.btn_Close.UseVisualStyleBackColor = true;
this.btn_Close.Click += new System.EventHandler(this.btn_Close_Click);
//
// btn_ok
//
this.btn_ok.Font = new System.Drawing.Font("굴림", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.btn_ok.Location = new System.Drawing.Point(30, 294);
this.btn_ok.Name = "btn_ok";
this.btn_ok.Size = new System.Drawing.Size(123, 34);
this.btn_ok.TabIndex = 4;
this.btn_ok.Text = "button1";
this.btn_ok.UseVisualStyleBackColor = true;
this.btn_ok.Click += new System.EventHandler(this.btn_ok_Click);
//
// dataGridView1
//
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToDeleteRows = false;
this.dataGridView1.AllowUserToResizeRows = false;
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.file_name,
this.update_status});
this.dataGridView1.Location = new System.Drawing.Point(397, 12);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.RowTemplate.Height = 23;
this.dataGridView1.Size = new System.Drawing.Size(399, 269);
this.dataGridView1.TabIndex = 6;
//
// file_name
//
this.file_name.DataPropertyName = "file_name";
this.file_name.HeaderText = "파일명";
this.file_name.Name = "file_name";
this.file_name.ReadOnly = true;
this.file_name.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
this.file_name.Width = 200;
//
// update_status
//
this.update_status.DataPropertyName = "chk";
this.update_status.FalseValue = "F";
this.update_status.HeaderText = "업데이트완료";
this.update_status.IndeterminateValue = "F";
this.update_status.Name = "update_status";
this.update_status.ReadOnly = true;
this.update_status.TrueValue = "T";
//
// Client
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(351, 347);
this.Controls.Add(this.dataGridView1);
this.Controls.Add(this.panel1);
this.Controls.Add(this.btn_Close);
this.Controls.Add(this.btn_ok);
this.Name = "Client";
this.Text = "ISBN 조회 자동 업데이트";
this.Load += new System.EventHandler(this.Client_Load);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.RichTextBox rtb_Ip;
private System.Windows.Forms.Label lbl_cnt;
private System.Windows.Forms.Label lbl_filename;
private System.Windows.Forms.Label lbl_ClientVer;
private System.Windows.Forms.Label lbl_SerVer;
private System.Windows.Forms.Label lbl_Files;
private System.Windows.Forms.Label lbl_status;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button btn_Close;
private System.Windows.Forms.Button btn_ok;
private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.DataGridViewTextBoxColumn file_name;
private System.Windows.Forms.DataGridViewCheckBoxColumn update_status;
}
}

View File

@@ -1,240 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
// 추가된 참조
using System.IO;
using System.Net;
using System.Diagnostics;
namespace ISBN_Client
{
public partial class Client : Form
{
// FTP ID / PW
private string Login_id = "ftpgloria";
private string Login_pw = "admin@!@#$";
// 서버 / 클라이언트 버전
private string Sr_Vers = "";
private string Cl_Vers = "";
// 서버 아이피
private string Server_Ip = "";
// 종료시 실행시킬 파일명
private string Start_Prg = "";
// 파일 개수
private int Files_Count = 0;
// 업데이트 진행 파일 수
private int down_Count = 0;
// 업데이트 여부
bool tf = false;
private string sLine = "";
private string[] str = new string[2];
int i = -1;
DataSet ds = new DataSet("files");
public Client()
{
InitializeComponent();
}
private void Client_Load(object sender, EventArgs e)
{
try
{
// 파일 목록 생성을 위한 데이터 셋
ds.Tables.Add("파일");
ds.Tables["파일"].Columns.Add("file_name");
ds.Tables["파일"].Columns.Add("chk");
File_info();
dataGridView1.DataSource = ds.Tables["파일"];
// 서버의 update_isbn.inf 파일에서 버전 추출
FtpWebRequest fwr = (FtpWebRequest)WebRequest.Create("ftp://" + Login_id + "@" + Server_Ip + "/ISBN/Update_isbn.inf");
fwr.Credentials = new NetworkCredential(Login_id, Login_pw);
fwr.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse fr = (FtpWebResponse)fwr.GetResponse();
StreamReader sr = new StreamReader(fr.GetResponseStream());
while (!sr.EndOfStream)
{
sLine = sr.ReadLine();
i = sLine.IndexOf("count=", 0);
// 서버 버전 추출
if(sLine.IndexOf("count=", 0) != -1)
{
Sr_Vers = sLine.Replace("count=", "");
lbl_SerVer.Text = Sr_Vers;
break;
}
}
sr.Close();
// 버전이 같은 경우 버튼 변경
if (Convert.ToDecimal(Sr_Vers) == Convert.ToDecimal(Cl_Vers))
{
btn_ok.Text = "프로그램 실행";
lbl_status.Text = "최신 버전입니다!";
lbl_status.ForeColor = Color.Blue;
lbl_filename.Text = "";
lbl_cnt.Text = "";
for(int a = 0; a < dataGridView1.Rows.Count; a++)
{
dataGridView1.Rows[a].Cells["update_status"].Value = "T";
}
btn_ok_Click(null, null);
}
else if (Convert.ToDecimal(Sr_Vers) > Convert.ToDecimal(Cl_Vers))
{
btn_ok.Text = "업데이트";
tf = true;
lbl_cnt.Text = "(1/" + dataGridView1.Rows.Count.ToString() + ")";
lbl_status.Text = "업데이트가 존재합니다!";
lbl_status.ForeColor = Color.DeepPink;
}
}
catch(System.Exception ex)
{
}
}
private void btn_ok_Click(object sender, EventArgs e)
{
if (tf)
{
// 업데이트가 존재할 때
download(0);
}
else
{
// 업데이트가 없을 때
string start_program = Application.StartupPath + "\\" + Start_Prg;
Process prc = new Process();
prc.StartInfo = new System.Diagnostics.ProcessStartInfo(start_program);
prc.Start();
this.Close();
}
}
private void download(int cnt)
{
if (cnt < Convert.ToInt32(lbl_Files.Text))
{
WebClient clnt = new WebClient();
clnt.Credentials = new NetworkCredential(Login_id, Login_pw);
lbl_status.Text = "업데이트 진행중!";
progressBar1.Value = (progressBar1.Maximum / Convert.ToInt32(lbl_Files.Text)) * (down_Count + 1);
lbl_filename.Text = dataGridView1.Rows[cnt].Cells["file_name"].Value.ToString();
dataGridView1.Rows[cnt].Cells["update_status"].Value = "T";
lbl_cnt.Text = "(" + (cnt + 1).ToString() + "/" + (dataGridView1.Rows.Count).ToString() + ")";
File.Delete(Application.StartupPath + lbl_filename.Text);
clnt.DownloadFileAsync(new Uri("ftp://" + Login_id + "@" + Server_Ip + "/ISBN/" + lbl_filename.Text),
Application.StartupPath + "\\" + lbl_filename.Text);
clnt.DownloadFileCompleted += new AsyncCompletedEventHandler(clnt_DownloadFileCompleted);
}
else
{
File_info();
progressBar1.Value = progressBar1.Maximum;
btn_ok.Text = "프로그램 실행";
lbl_status.Text = "최신 파일입니다!";
lbl_status.ForeColor = Color.Blue;
lbl_filename.Text = "";
lbl_cnt.Text = "";
tf = false;
}
}
void clnt_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
down_Count += 1;
download(down_Count);
}
private void File_info()
{
// 클라이언트 파일 정보
// update.inf 파일에서 파일개수, 파일명, 버전 추출
StreamReader sr = new StreamReader(Application.StartupPath + "\\Update_isbn.inf");
int i = -1;
while(sr.EndOfStream != true)
{
sLine = sr.ReadLine();
i = sLine.IndexOf("count=", 0);
// 버전 추출
if (sLine.IndexOf("count=", 0) != -1)
{
Cl_Vers = sLine.Replace("count=", "");
lbl_ClientVer.Text = Cl_Vers;
}
// 설치 경로 추출
else if (sLine.IndexOf("server_url=", 0) != -1)
{
Server_Ip = sLine.Replace("server_url=", "");
rtb_Ip.Text = Server_Ip;
//rtb_Ip.Text = Application.StartupPath;
}
// 종료시 실행 파일
else if (sLine.IndexOf("exe=", 0) != -1)
{
Start_Prg = sLine.Replace("exe=", "");
}
// 파일 개수 추출
else if (sLine.IndexOf("Files=", 0) != -1)
{
Files_Count = Convert.ToInt32(sLine.Replace("Files=", ""));
lbl_Files.Text = Files_Count.ToString();
}
else if(sLine.IndexOf("\\", 0) != -1)
{
str[0] = sLine.Replace("\\", "");
str[1] = "F";
ds.Tables["파일"].Rows.Add(str);
}
i = -1;
}
sr.Close();
}
private void btn_Close_Click(object sender, EventArgs e)
{
this.Close();
}
}
}

View File

@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1A792D56-127B-446B-8B01-0A60902E0086}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>ISBN_Client</RootNamespace>
<AssemblyName>ISBN_Client</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<TargetZone>LocalIntranet</TargetZone>
</PropertyGroup>
<PropertyGroup>
<GenerateManifests>false</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ISBN_Client.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ISBN_Client.Designer.cs">
<DependentUpon>ISBN_Client.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="ISBN_Client.resx">
<DependentUpon>ISBN_Client.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ISBN_Client
{
static class Program
{
/// <summary>
/// 해당 애플리케이션의 주 진입점입니다.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Client());
}
}
}

View File

@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("ISBN_Client")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("ISBN_Client")]
[assembly: AssemblyCopyright("Copyright © Microsoft Corporation 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("1a792d56-127b-446b-8b01-0a60902e0086")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,70 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ISBN_Client.Properties
{
/// <summary>
/// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
/// </summary>
// 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
// 클래스에서 자동으로 생성되었습니다.
// 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여
// ResGen을 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ISBN_Client.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해 현재 스레드의 CurrentUICulture 속성을
/// 재정의합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@@ -1,29 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ISBN_Client.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 매니페스트 옵션
Windows 사용자 계정 컨트롤 수준을 변경하려면
requestedExecutionLevel 노드를 다음 중 하나로 바꿉니다.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
requestedExecutionLevel 요소를 지정하면 파일 및 레지스트리 가상화를 사용하지 않습니다.
이전 버전과의 호환성을 위해 애플리케이션에 가상화가 필요한 경우
이 요소를 제거합니다.
-->
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
<applicationRequestMinimum>
<defaultAssemblyRequest permissionSetReference="Custom" />
<PermissionSet class="System.Security.PermissionSet" version="1" ID="Custom" SameSite="site" Unrestricted="true" />
</applicationRequestMinimum>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 이 애플리케이션이 테스트되고 함께 작동하도록 설계된 Windows 버전
목록입니다. 해당 요소의 주석 처리를 제거하면 Windows에서
호환 가능성이 가장 큰 환경을 자동으로 선택합니다. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
<!-- Windows 8 -->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
<!-- Windows 8.1 -->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<!-- Windows 10 -->
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
</application>
</compatibility>
<!-- 애플리케이션이 DPI를 인식하며 높은 DPI에서 Windows가 자동으로 스케일링하지
않음을 나타냅니다. WPF(Windows Presentation Foundation) 애플리케이션은 자동으로 DPI를 인식하며
옵트인할 필요가 없습니다. 이 설정에 옵트인한 .NET Framework 4.6을 대상으로 하는
Windows Forms 애플리케이션은 app.config에서 'EnableWindowsFormsHighDpiAutoResizing' 설정도 'true'로 설정해야 합니다.
애플리케이션이 긴 경로를 인식하도록 설정합니다. https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation을 참조하세요. -->
<!--
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
-->
<!-- Windows 공용 컨트롤 및 대화 상자의 테마 사용(Windows XP 이상) -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
-->
</assembly>

View File

@@ -14,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("pofalApi_tmp")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+8e7df6f68d424e8b9f20e24f017b877849125171")]
[assembly: System.Reflection.AssemblyProductAttribute("pofalApi_tmp")]
[assembly: System.Reflection.AssemblyTitleAttribute("pofalApi_tmp")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
c13c9c2f2e12bc007cbcab6ccdb94397f9d2465a
1e22963f41eb10ec8b7d5cf0f11446afcd4c7c64669758c39d9d6d7a2dc5abbf

View File

@@ -18,7 +18,7 @@
},
"permissions": {
"allow": [
"Bash(git add:*)"
"Bash(git push:*)"
],
"deny": [],
"ask": []

View File

@@ -1,6 +0,0 @@
{
"hooks": {
"conversation-start": "새로운 대화를 시작할 때 항상 CLAUDE.md 파일을 자동으로 읽고 프로젝트 컨텍스트를 파악하세요",
"user-prompt-submit": "작업을 시작하기 전에 항상 CLAUDE.md 파일을 읽고 참조하세요"
}
}

View File

@@ -10,6 +10,9 @@
- **데이터베이스**: MySQL
- **주요기능**: 마크 작성, 복본조사, DLS 연동, 도서 정보 관리
## 데이터베이스 정보
- Server=1.215.250.130;Port=3306;Database=unimarc;uid=root;pwd=Admin21234;
## 코딩 컨벤션
- 파일명: PascalCase (예: DLS_Copy.cs)
- 클래스명: PascalCase

19
unimarc/NuGet.Config Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="grapecity" value="https://nuget.grapecity.com/nuget" />
</packageSources>
<packageSourceCredentials />
<packageRestore>
<add key="enabled" value="True" />
<add key="automatic" value="True" />
</packageRestore>
<bindingRedirects>
<add key="skip" value="False" />
</bindingRedirects>
<packageManagement>
<add key="format" value="0" />
<add key="disabled" value="False" />
</packageManagement>
</configuration>

View File

@@ -9,6 +9,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Factory_Client", "Factory_C
EndProject
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "UniMarcSetup", "UniMarcSetup\UniMarcSetup.vdproj", "{B0A88F76-DC68-44F9-90B4-CD94625CC1F4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "솔루션 항목", "솔루션 항목", "{2A3A057F-5D22-31FD-628C-DF5EF75AEF1E}"
ProjectSection(SolutionItems) = preProject
CLAUDE.md = CLAUDE.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

View File

@@ -56,12 +56,6 @@
</runtime>
<userSettings>
<UniMarc.Properties.Settings>
<setting name="compidx" serializeAs="String">
<value />
</setting>
<setting name="User" serializeAs="String">
<value />
</setting>
<setting name="IP" serializeAs="String">
<value>1.11010111.11111010.10000010</value>
</setting>

View File

@@ -8,7 +8,7 @@ using System.Threading.Tasks;
using System.Windows.Forms;
namespace ExcelTest
namespace UniMarc
{
public static class CExt
{
@@ -121,5 +121,4 @@ namespace ExcelTest
catch { }
}
}
}

View File

@@ -0,0 +1,34 @@
using AR;
namespace UniMarc
{
public static class DB_Utils
{
public static bool ExistISBN(string value)
{
if (value.isEmpty())
{
UTIL.MsgE("중복검사할 ISBN값이 입력되지 않았습니다");
return false;
}
// ISBN 중복체크
string checkSql = string.Format("SELECT COUNT(*) FROM Marc WHERE isbn = '{0}' AND compidx = '{1}'", value, PUB.user.CompanyIdx);
var ret = Helper_DB.ExcuteScalar(checkSql);
if (ret.value == null)
{
UTIL.MsgE($"Database error [ExistISBN]\n{ret.errorMessage}");
return false;
}
if (int.TryParse(ret.value.ToString(), out int cnt) == false)
return false;
else
{
if (cnt > 0)
{
return true;
}
return false;
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using AR;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -9,7 +10,7 @@ using System.Threading.Tasks;
using System.Web.Mail;
using System.Windows.Forms;
namespace WindowsFormsApp1
namespace UniMarc
{
class Email
{
@@ -74,12 +75,12 @@ namespace WindowsFormsApp1
{
SmtpMail.SmtpServer = smtp_server;
SmtpMail.Send(msg);
MessageBox.Show("다음 메일 전송 성공");
UTIL.MsgI("다음 메일 전송 성공");
return true;
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
UTIL.MsgE(e.ToString());
return false;
}
}
@@ -118,12 +119,12 @@ namespace WindowsFormsApp1
try
{
smtp.Send(mail);
MessageBox.Show("메일 전송 완료");
UTIL.MsgI("메일 전송 완료");
return true;
}
catch (SmtpException e)
{
MessageBox.Show(e.ToString());
UTIL.MsgE(e.ToString());
return false;
}
}
@@ -156,7 +157,7 @@ namespace WindowsFormsApp1
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
UTIL.MsgE(e.ToString());
}
}
else
@@ -187,7 +188,7 @@ namespace WindowsFormsApp1
}
catch (SmtpException e)
{
MessageBox.Show(e.ToString());
UTIL.MsgE(e.ToString());
}
}
}

View File

@@ -0,0 +1,402 @@
using AR;
using MySql.Data.MySqlClient;
using OpenQA.Selenium;
using Renci.SshNet;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO.Ports;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;
using System.Windows.Forms;
using UniMarc.BaroService_TI;
using UniMarc.Properties;
namespace UniMarc
{
public partial class Helper_DB
{
//static string cs = "";
public enum eDbType
{
unimarc,
cl_marc
}
public static MySqlConnection CreateConnection(eDbType dbtype)
{
var dbname = dbtype.ToString();
string strConnection = string.Format(
"Server={0};" +
"Port={1};" +
$"Database={dbname};" +
"uid={2};" +
"pwd={3};", ServerData[0], DBData[0], DBData[1], DBData[2]);
return new MySqlConnection(strConnection);
}
/// <summary>
/// 입력한 쿼리의 결과를 데이터테이블로 반환합니다
/// </summary>
/// <param name="query"></param>
/// <param name="cn"></param>
/// <returns></returns>
public static DataTable ExecuteDataTable(string query, MySqlConnection cn = null)
{
var bLocalCN = cn == null;
DataTable dt = new DataTable();
try
{
if (cn == null) cn = CreateConnection(eDbType.unimarc);// new MySqlConnection(cs);
var cmd = new MySqlCommand(query, cn);
cn.Open();
using (MySqlDataAdapter adapter = new MySqlDataAdapter(cmd))
{
adapter.Fill(dt);
}
cmd.Dispose();
cn.Close();
if (bLocalCN) cn.Dispose();
return dt;
}
catch (Exception ex)
{
UTIL.MsgE(ex.ToString());
return null;
}
}
/// <summary>
/// 오류발생시 null을 반환합니다
/// </summary>
/// <param name="tableName"></param>
/// <param name="columns"></param>
/// <param name="wheres"></param>
/// <param name="orders"></param>
/// <returns></returns>
public static DataTable ExecuteQueryData(string tableName, string columns = "*", string wheres = "", string orders = "", MySqlConnection cn = null)
{
var sql = $"select {columns} from {tableName}";
if (wheres.isEmpty() == false) sql += " where " + wheres;
if (orders.isEmpty() == false) sql += " order by " + orders;
return ExecuteDataTable(sql, cn);
}
/// <summary>
/// 오류발생시 -1을 반환합니다
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public static (int applyCount, string errorMessage) ExcuteNonQuery(string query, MySqlConnection cn = null)
{
try
{
var bLocalCN = cn == null;
if (cn == null) cn = CreateConnection(eDbType.unimarc);//new MySqlConnection(cs);
var cmd = new MySqlCommand(query, cn);
cn.Open();
var cnt = cmd.ExecuteNonQuery();
cmd.Dispose();
if (bLocalCN) cn.Dispose();
return (cnt, string.Empty);
}
catch (Exception ex)
{
return (-1, ex.Message);
}
}
public static (long value, string errorMessage) ExcuteInsertGetIndex(string cmd, MySqlConnection cn = null)
{
long lastId = -1;
var bLocalCN = cn == null;
string message;
try
{
if (cn == null) cn = CreateConnection(eDbType.unimarc);//new MySqlConnection(cs);
using (var sqlcmd = new MySqlCommand(cmd, cn))
{
cn.Open();
sqlcmd.ExecuteNonQuery();
lastId = sqlcmd.LastInsertedId;
}
if (bLocalCN) cn.Dispose();
message = "";
}
catch (Exception ex)
{
lastId = -1;
message = ex.Message;
}
return (lastId, message);
}
/// <summary>
/// 단일항목값을 반환 합니다
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public static (object value, string errorMessage) ExcuteScalar(string query, MySqlConnection cn = null)
{
try
{
var bLocalCN = cn == null;
if (cn == null) cn = CreateConnection(eDbType.unimarc);//new MySqlConnection(cs);
var cmd = new MySqlCommand(query, cn);
cn.Open();
var val = cmd.ExecuteScalar();
cmd.Dispose();
if (bLocalCN) cn.Dispose();
return (val, string.Empty);
}
catch (Exception ex)
{
return (null, ex.Message);
}
}
/// <summary>
/// Insert 명령을 수행한 후 자동 생성된 index값을 반환합니다.
/// 오류발생시에는 -1을 반환합니다
/// </summary>
/// <param name="cmd"></param>
/// <param name="cn"></param>
/// <returns></returns>
public static long DB_Send_CMD_Insert_GetIdx(string cmd, MySqlConnection cn = null)
{
long lastId = -1;
var bLocalCN = cn == null;
try
{
if (cn == null) cn = CreateConnection(eDbType.unimarc);//new MySqlConnection(cs);
using (var sqlcmd = new MySqlCommand(cmd, cn))
{
cn.Open();
sqlcmd.ExecuteNonQuery();
lastId = sqlcmd.LastInsertedId;
}
if (bLocalCN) cn.Dispose();
}
catch (Exception ex)
{
UTIL.MsgE($"데이터베이스 실행오류\n{ex.Message}");
}
return lastId;
}
public static MarcBasicInfo GetBasicMarcInfo(string FullMarc)
{
MarcBasicInfo retval = new MarcBasicInfo();
//상황에 맞게 업데이트 명령을 처리한다.
var parser = new MarcParser();
var ret = parser.ParseFullMarc(FullMarc);
if (ret.success == false)
{
retval.Success = false;
retval.Message = ret.message;
return retval;
}
//ISBN와 가격 (처음나오는 020태그의 값을 적용)
var tag_020 = parser.GetTag<MarcField>("020").FirstOrDefault();
if (tag_020 != null)
{
retval.ISBN = tag_020.GetSubfieldValue('a');
retval.Price = tag_020.GetSubfieldValue('c');
}
//저자(100 -> 110 -> 111 순으로 적용)
var tag_100 = parser.GetTag<MarcField>("100").FirstOrDefault();
var tag_110 = parser.GetTag<MarcField>("110").FirstOrDefault();
var tag_111 = parser.GetTag<MarcField>("111").FirstOrDefault();
if (tag_111 != null)
retval.Author = tag_111.GetSubfieldValue('a');
else if (tag_110 != null)
retval.Author = tag_110.GetSubfieldValue('a');
else if (tag_100 != null)
retval.Author = tag_100.GetSubfieldValue('a');
//서명
retval.Title = parser.GetTag<MarcSubfield>("245a").FirstOrDefault()?.Value ?? string.Empty;
//string x245 = parser.GetTag<MarcSubfield>("245x").FirstOrDefault()?.Value ?? string.Empty;
//string b245 = parser.GetTag<MarcSubfield>("245b").FirstOrDefault()?.Value ?? string.Empty;
//if (x245 != "") retval.Title += " = " + x245;
//if (b245 != "") retval.Title += " : " + b245;
//출판사
var tag_264b = parser.GetTag<MarcSubfield>("264b").FirstOrDefault();
var tag_260b = parser.GetTag<MarcSubfield>("260b").FirstOrDefault();
if (tag_264b != null)
retval.Publisher = tag_264b?.Value ?? string.Empty;
else if (tag_260b != null)
retval.Publisher = tag_260b?.Value ?? string.Empty;
//056a
retval.Tag056 = parser.GetTag("056a").FirstOrDefault() ?? string.Empty;
retval.Tag008 = parser.GetTag("008").FirstOrDefault() ?? string.Empty;
//총서명(440a)
retval.fulltitle = parser.GetTag("440a").FirstOrDefault() ?? string.Empty;
//총서번호(440v)
retval.fulltitleno = parser.GetTag("440v").FirstOrDefault() ?? string.Empty;
//권차(245n)
retval.kwoncha = parser.GetTag("245n").FirstOrDefault() ?? string.Empty;
//권차서명(245p)
retval.kwoncha_title = parser.GetTag("245p").FirstOrDefault() ?? string.Empty;
//판차(250a)
retval.pancha = parser.GetTag("250a").FirstOrDefault() ?? string.Empty;
retval.Success = true;
return retval;
}
public static string Make_InsertQuery(string tableName, Dictionary<string, object> column_and_values)
{
string columns = string.Join(", ", column_and_values.Keys.Select(k => $"`{k}`"));
string values = string.Join(", ", column_and_values.Values.Select(v =>
{
string s = v?.ToString() ?? "";
return $"\"{s.Replace("\"", "\"\"")}\"";
}));
return $"INSERT INTO `{tableName}` ({columns}) VALUES ({values});";
}
public static string Make_UpdateQuery(string tableName, Dictionary<string, object> column_and_values, Dictionary<string, object> where_column_and_values)
{
string setClause = string.Join(", ", column_and_values.Select(kv =>
{
string s = kv.Value?.ToString() ?? "";
return $"`{kv.Key}` = \"{s.Replace("\"", "\"\"")}\"";
}));
string whereClause = string.Join(" AND ", where_column_and_values.Select(kv =>
{
string s = kv.Value?.ToString() ?? "";
return $"`{kv.Key}` = \"{s.Replace("\"", "\"\"")}\"";
}));
return $"UPDATE `{tableName}` SET {setClause} WHERE {whereClause};";
}
public static (bool result, int newidx, string message,string date) UpdateMarc(int midx, string FullMarc, int v_grade,
string etc1, string etc2, string url, string v_orgmarc)
{
var isUpdate = midx > 0;
var v_username = PUB.user.UserName;
var v_compidx = PUB.user.CompanyIdx;
string v_date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
//상황에 맞게 업데이트 명령을 처리한다.
var basicinfo = GetBasicMarcInfo(FullMarc);
if (basicinfo.Success == false) return (false, 0, basicinfo.Message,v_date);
// 1. DB 작업 (저장 전략 결정: Status 기준)
if (isUpdate == false)
{
var insertData = new Dictionary<string, object>
{
{ "compidx", v_compidx },
{ "ISBN", basicinfo.ISBN },
{ "서명", basicinfo.Title },
{ "저자", basicinfo.Author },
{ "출판사", basicinfo.Publisher },
{ "가격", basicinfo.Price },
{ "총서명", basicinfo.fulltitle },
{ "총서번호", basicinfo.fulltitleno },
{ "권차", basicinfo.kwoncha },
{ "권차서명", basicinfo.kwoncha_title },
{ "판차", basicinfo.pancha },
{ "marc", FullMarc },
{ "marc_chk", "1" },
{ "비고1", etc1 },
{ "비고2", etc2 },
{ "url", url },
{ "division", basicinfo.Tag056 },
{ "008tag", basicinfo.Tag008 },
{ "date", v_date },
{ "user", v_username },
{ "grade", v_grade.ToString() }
};
string Incmd = Make_InsertQuery("Marc", insertData);
PUB.log.Add("INSERT", string.Format("{0}({1}) : {2}", v_username, v_compidx, Incmd));
var newIdx = Helper_DB.DB_Send_CMD_Insert_GetIdx(Incmd);
if (newIdx > 0)
{
midx = (int)newIdx;
}
}
else
{
var updateData = new Dictionary<string, object>
{
{ "ISBN", basicinfo.ISBN },
{ "서명", basicinfo.Title },
{ "저자", basicinfo.Author },
{ "출판사", basicinfo.Publisher },
{ "가격", basicinfo.Price },
{ "총서명", basicinfo.fulltitle },
{ "총서번호", basicinfo.fulltitleno },
{ "권차", basicinfo.kwoncha },
{ "권차서명", basicinfo.kwoncha_title },
{ "판차", basicinfo.pancha },
{ "marc", FullMarc },
{ "marc1", v_orgmarc },
{ "marc_chk", "1" },
{ "marc_chk1", "0" },
{ "비고1", etc1 },
{ "비고2", etc2 },
{ "url", url },
{ "division", basicinfo.Tag056 },
{ "008tag", basicinfo.Tag008 },
{ "date", v_date },
{ "user", v_username },
{ "grade", v_grade.ToString() }
};
var whereClause = new Dictionary<string, object>
{
{ "idx", midx },
{ "compidx", v_compidx }
};
string U_cmd = Make_UpdateQuery("Marc", updateData, whereClause);
PUB.log.Add("Update", string.Format("{0}({1}) : {2}", v_username, v_compidx, U_cmd.Replace("\r", " ").Replace("\n", " ")));
var ret = Helper_DB.ExcuteNonQuery(U_cmd);
if (ret.applyCount != 1)
{
return (false, midx, $"업데이트된 행의 수가 1이 아닙니다. 적용된 행 수: {ret.applyCount}, 오류 메시지: {ret.errorMessage}", v_date);
}
}
return (true, midx, string.Empty, v_date);
}
}
}

View File

@@ -0,0 +1,378 @@
using Org.BouncyCastle.Pkcs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniMarc
{
public class MarcSubfield
{
public char Code { get; set; }
public string Value { get; set; }
public MarcSubfield(char code, string value)
{
Code = code;
Value = value;
}
public override string ToString()
{
return $"▼{Code}{Value}";
}
}
public class MarcField
{
public string Tag { get; set; }
public string Indicators { get; set; } = " ";
public string ControlValue { get; set; }
public List<MarcSubfield> Subfields { get; set; } = new List<MarcSubfield>();
public bool IsControlField => int.TryParse(Tag, out int tagNum) && tagNum < 10;
public MarcField(string tag)
{
Tag = tag;
}
public string GetSubfieldValue(char code)
{
var sub = Subfields.FirstOrDefault(s => s.Code == code);
return sub != null ? sub.Value : string.Empty;
}
public override string ToString()
{
if (IsControlField)
return $"{Tag}\t \t{ControlValue}▲";
StringBuilder sb = new StringBuilder();
sb.Append($"{Tag}\t{Indicators}\t");
foreach (var sub in Subfields)
{
sb.Append(sub.ToString());
}
sb.Append("▲");
return sb.ToString();
}
}
public class MarcParser
{
public string Leader { get; set; } = "00000nam 2200000 k 4500";
public List<MarcField> Fields { get; set; } = new List<MarcField>();
private const char SUBFIELD_MARKER = '▼';
private const char FIELD_TERMINATOR = '▲';
private const char RECORD_TERMINATOR = '\x1D';
public MarcParser() { }
public void ParseMnemonic(string data)
{
Fields.Clear();
if (string.IsNullOrEmpty(data)) return;
string[] lines = data.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
string cleanLine = line.Trim();
if (cleanLine.Length < 3) continue;
string tag = cleanLine.Substring(0, 3);
MarcField field = new MarcField(tag);
string[] parts = cleanLine.Split('\t');
if (field.IsControlField)
{
if (parts.Length >= 3)
field.ControlValue = parts[2].TrimEnd(FIELD_TERMINATOR, ' ');
else
field.ControlValue = cleanLine.Substring(Math.Min(cleanLine.Length, 3)).Trim('\t', ' ', FIELD_TERMINATOR);
}
else
{
if (parts.Length >= 2)
field.Indicators = parts[1].PadRight(2).Substring(0, 2);
string dataPart = parts.Length >= 3 ? parts[2] : "";
if (parts.Length < 3 && cleanLine.Length > 5)
dataPart = cleanLine.Substring(5);
dataPart = dataPart.TrimEnd(FIELD_TERMINATOR);
ParseSubfields(field, dataPart);
}
Fields.Add(field);
}
}
private void ParseSubfields(MarcField field, string dataPart)
{
if (string.IsNullOrEmpty(dataPart)) return;
if (dataPart.Contains(SUBFIELD_MARKER))
{
string[] subfields = dataPart.Split(new[] { SUBFIELD_MARKER }, StringSplitOptions.RemoveEmptyEntries);
foreach (var s in subfields)
{
if (s.Length >= 1)
field.Subfields.Add(new MarcSubfield(s[0], s.Substring(1).TrimEnd(FIELD_TERMINATOR)));
}
}
else if (dataPart.Contains('\x1F'))
{
string[] subfields = dataPart.Split(new[] { '\x1F' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var s in subfields)
{
if (s.Length >= 1)
field.Subfields.Add(new MarcSubfield(s[0], s.Substring(1)));
}
}
else
{
for (int k = 0; k < dataPart.Length; k++)
{
if (char.IsLetter(dataPart[k]) && (k == 0 || dataPart[k - 1] == ' ' || dataPart[k - 1] == '^' || dataPart[k - 1] == '\x1F'))
{
char code = dataPart[k];
int next = -1;
for (int m = k + 1; m < dataPart.Length - 1; m++)
{
if (dataPart[m] == ' ' && char.IsLetter(dataPart[m + 1]))
{
next = m;
break;
}
}
string val = next == -1 ? dataPart.Substring(k + 1) : dataPart.Substring(k + 1, next - k - 1);
field.Subfields.Add(new MarcSubfield(code, val.Trim()));
if (next != -1) k = next;
else break;
}
}
}
}
public (bool success, string message) ParseFullMarc(string data)
{
System.Text.StringBuilder AlertMessage = new StringBuilder();
Fields.Clear();
if (data.Length < 24) return (false, "마크데이터가 24보다 작습니다");
//리더부는 항상 24바이트이다. 0~23까지이다.
Leader = data.Substring(0, 24);
if (!int.TryParse(Leader.Substring(12, 5), out int baseAddress)) return (false, string.Empty);
//data Length
if (int.TryParse(Leader.Substring(0, 5), out int dataLength) == false)
{
return (false, "Leader 전체 데이터 길이를 확인할 수 없습니다");
}
bool isScaled = false;
int directoryLength = baseAddress - 24;
int entryCount = directoryLength / 12;
var directory = data.Substring(24, directoryLength);
var RealData = data.Substring(24 + directoryLength);
if (RealData.Contains((char)0x1D) == false)
{
AlertMessage.AppendLine($"레코드식별기호 0x1D 가 없습니다");
}
else RealData = RealData.Trim((char)0x1D);
//태그별식별기호로 분리한다.
if (RealData[RealData.Length - 1] == (char)0x1E)
RealData = RealData.Substring(0, RealData.Length - 1);
var Tags = RealData.Split((char)0x1E);
if(Tags.Length != entryCount)
{
AlertMessage.AppendLine($"디렉토리 카운트({entryCount})와 태그수량({Tags.Length})이 일치하지 않습니다");
}
for (int i = 0; i < Math.Min(entryCount,Tags.Length); i++)
{
int entryStart = (i * 12);
//TAG(3)+LENGTH(4)+OFFSET(5)=12
if (entryStart + 12 > directory.Length) break;
if (directory[entryStart] == '\x1E' || directory[entryStart] == '^' || directory[entryStart] == FIELD_TERMINATOR) break;
string tag = directory.Substring(entryStart, 3);
var tag_len = directory.Substring(entryStart + 3, 4);
var tag_off = directory.Substring(entryStart + 7, 5);
if (!int.TryParse(tag_len, out int length))
{
AlertMessage.AppendLine($"태그({tag}) 길이를 확인할 수 없습니다 값:{tag_len}");
}
if (!int.TryParse(tag_off, out int offset))
{
AlertMessage.AppendLine($"태그({tag}) 오프셋을 확인할 수 없습니다 값:{offset}");
}
string fieldData = Tags[i];
fieldData = fieldData.TrimEnd('\x1E', '\x1D', FIELD_TERMINATOR, '^', ' ');
MarcField field = new MarcField(tag);
if (field.IsControlField)
field.ControlValue = fieldData;
else
{
var subfieldIndex = fieldData.IndexOf((char)0x1f);
string fielddata = "";
if (subfieldIndex < 0)
{
//1f가 없는 것은 오류 처리한다.
continue;
}
else if (subfieldIndex < 1)
{
//지시기호없이 데이터가 시작되는경우이다.
field.Indicators = " ";
ParseSubfields(field, fieldData);
}
else if (subfieldIndex < 2)
{
//지시기호가1개이다 뒤에 공백을 넣자
field.Indicators = fieldData.Substring(0, subfieldIndex) + " ";
ParseSubfields(field, fieldData.Substring(1));
}
else if (subfieldIndex > 2)
{
//지시기호가 2자리보다 길다? 이건 오류처리하자.
field.Indicators = " ";
ParseSubfields(field, fieldData.Substring(subfieldIndex));
}
else
{
field.Indicators = fieldData.Substring(0, 2);
ParseSubfields(field, fieldData.Substring(2));
}
}
Fields.Add(field);
}
return (true, AlertMessage.ToString());
}
public List<T> GetTag<T>(string path)
{
if (string.IsNullOrEmpty(path)) return new List<T>();
string tag = path.Substring(0, 3);
char? subCode = path.Length > 3 ? (char?)path[3] : null;
var fields = Fields.Where(f => f.Tag == tag).ToList();
if (fields.Count == 0) return new List<T>();
if (typeof(T) == typeof(MarcField))
return fields.Cast<T>().ToList();
if (typeof(T) == typeof(MarcSubfield))
{
if (!subCode.HasValue) return new List<T>();
var subResults = new List<MarcSubfield>();
foreach (var f in fields)
subResults.AddRange(f.Subfields.Where(s => s.Code == subCode.Value));
return subResults.Cast<T>().ToList();
}
if (typeof(T) == typeof(string))
{
var stringResults = new List<string>();
foreach (var f in fields)
{
if (f.IsControlField)
stringResults.Add(f.ControlValue);
else
{
if (subCode.HasValue)
stringResults.AddRange(f.Subfields.Where(s => s.Code == subCode.Value).Select(s => s.Value));
else
stringResults.AddRange(f.Subfields.Select(s => s.Value));
}
}
return stringResults.Cast<T>().ToList();
}
return new List<T>();
}
public List<string> GetTag(string path)
{
return GetTag<string>(path);
}
public void SetTag(string path, string value, string indicators = " ")
{
if (string.IsNullOrEmpty(path) || path.Length < 3) return;
string tag = path.Substring(0, 3);
bool isControl = int.TryParse(tag, out int tagNum) && tagNum < 10;
var field = Fields.FirstOrDefault(f => f.Tag == tag);
if (field == null)
{
field = new MarcField(tag) { Indicators = indicators };
Fields.Add(field);
Fields = Fields.OrderBy(f => f.Tag).ToList();
}
if (isControl)
field.ControlValue = value;
else
{
if (path.Length < 4) throw new ArgumentException("Subfield code required for data fields");
char subCode = path[3];
var sub = field.Subfields.FirstOrDefault(s => s.Code == subCode);
if (sub != null) sub.Value = value;
else field.Subfields.Add(new MarcSubfield(subCode, value));
}
}
public string Get008Segment(int offset, int length)
{
var valLine = GetTag("008").FirstOrDefault();
if (string.IsNullOrEmpty(valLine) || valLine.Length < offset + length) return string.Empty;
return valLine.Substring(offset, length);
}
public void Set008Segment(int offset, int length, string value)
{
var valLine = GetTag("008").FirstOrDefault() ?? new string(' ', 40);
if (valLine.Length < 40) valLine = valLine.PadRight(40);
StringBuilder sb = new StringBuilder(valLine);
for (int i = 0; i < length; i++)
{
char c = (i < value.Length) ? value[i] : ' ';
if (offset + i < sb.Length)
sb[offset + i] = c;
}
SetTag("008", sb.ToString());
}
public string ToMnemonicString()
{
StringBuilder sb = new StringBuilder();
foreach (var field in Fields)
sb.AppendLine(field.ToString());
return sb.ToString();
}
}
}

View File

@@ -0,0 +1 @@
00559nam 2200229 k 4500008004100000020003300041020002400074041000800098049000600106056001300112082001200125090001800137100001100155245004500166260002500211300001600236520000500252653003900257700001100296740001100307950001100318200306s2011 ggk 000 f kor  a9788954615860g04810c^158001 a9788954615853(세트)1 akor v1 a813.6240 a895.734 a813.6b이67퇴1 a이우혁00a퇴마록x退魔錄n1b국내편d이우혁 [지음] a파주b엘릭시르c2011 a663p.c20cm a a퇴마록a한국현대소설a한국장편소설1 a이우혁 0a국내편0 b^15800

View File

@@ -0,0 +1,15 @@
020 ▼a9788954615877▼g04810▼c\15800▲
020 1 ▼a9788954615853(세트)▲
049 ▼v2▲
056 ▼a813.6▼24▲
082 0 ▼a895.734▲
090 ▼a813.6▼b이67퇴▲
100 1 ▼a이우혁▲
245 00 ▼a퇴마록▼x退魔錄▼n2▼b국내편▼d이우혁 [지음]▲
260 ▼a파주▼b엘릭시르▼c2011▲
300 ▼a600p.▼c20cm▲
520 ▼a▲
653 ▼a퇴마록▼a한국현대소설▼a한국장편소설▲
700 1 ▼a이우혁▲
740 0 ▼a국내편▲
950 0 ▼b\15800▲

View File

@@ -1,20 +1,23 @@
using System;
using AR;
using MySql.Data.MySqlClient;
using Renci.SshNet;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
using Renci.SshNet;
using UniMarc.BaroService_TI;
using UniMarc.Properties;
namespace WindowsFormsApp1
namespace UniMarc
{
/// <summary>
/// DB접속을 도와주는 클래스
/// </summary>
class Helper_DB
public partial class Helper_DB
{
// 접속
MySqlConnection conn;
@@ -22,14 +25,14 @@ namespace WindowsFormsApp1
/// <summary>
/// IP / Port / Uid / pwd
/// </summary>
string[] ServerData = {
static string[] ServerData = {
Settings.Default.IP,
Settings.Default.Uid,
Settings.Default.pwd
};
int port = Settings.Default.Port;
string[] DBData = {
static string[] DBData = {
Settings.Default.dbPort,
Settings.Default.dbUid,
Settings.Default.dbPwd
@@ -39,47 +42,12 @@ namespace WindowsFormsApp1
MySqlCommand sqlcmd = new MySqlCommand();
MySqlDataReader sd;
public string comp_idx { get; internal set; }
/// <summary>
/// DB를 사용하고 싶을 때 미리 저장된 DB의 기본 접속정보를 이용하여 DB에 접근한다.
/// </summary>
public void DBcon() // DB접속 함수
{
//"Server=1.215.250.130;Port=3306;Database=unimarc;uid=root;pwd=Admin21234;"
PasswordConnectionInfo connectionInfo = new PasswordConnectionInfo(ServerData[0], port, ServerData[1], ServerData[2]);
connectionInfo.Timeout = TimeSpan.FromSeconds(30);
using (var client = new SshClient(connectionInfo))
{
if (conn != null) {
conn.Close();
conn.Dispose();
}
client.Connect();
if (client.IsConnected)
{
string strConnection = string.Format(
"Server={0};" +
"Port={1};" +
"Database=unimarc;" +
"uid={2};" +
"pwd={3};", ServerData[0], DBData[0], DBData[1], DBData[2]);
conn = new MySqlConnection(strConnection);
}
}
}
public MySql.Data.MySqlClient.MySqlConnection CreateConnection()
public MySqlConnection CreateConnection()
{
PasswordConnectionInfo connectionInfo = new PasswordConnectionInfo(ServerData[0], port, ServerData[1], ServerData[2]);
connectionInfo.Timeout = TimeSpan.FromSeconds(30);
using (var client = new SshClient(connectionInfo))
{
if (conn != null)
{
conn.Close();
conn.Dispose();
}
client.Connect();
if (client.IsConnected)
{
@@ -96,6 +64,37 @@ namespace WindowsFormsApp1
return null;
}
/// <summary>
/// DB를 사용하고 싶을 때 미리 저장된 DB의 기본 접속정보를 이용하여 DB에 접근한다.
/// </summary>
public void DBcon() // DB접속 함수
{
//"Server=1.215.250.130;Port=3306;Database=unimarc;uid=root;pwd=Admin21234;"
PasswordConnectionInfo connectionInfo = new PasswordConnectionInfo(ServerData[0], port, ServerData[1], ServerData[2]);
connectionInfo.Timeout = TimeSpan.FromSeconds(30);
using (var client = new SshClient(connectionInfo))
{
if (conn != null)
{
conn.Close();
conn.Dispose();
}
client.Connect();
if (client.IsConnected)
{
var cs = string.Format(
"Server={0};" +
"Port={1};" +
"Database=unimarc;" +
"uid={2};" +
"pwd={3};", ServerData[0], DBData[0], DBData[1], DBData[2]);
conn = new MySqlConnection(cs);
}
}
}
/// <summary>
/// 국중DB를 사용하고 싶을 때 미리 저장된 DB의 기본 접속정보를 이용하여 DB에 접근한다.
/// </summary>
@@ -123,8 +122,11 @@ namespace WindowsFormsApp1
}
}
}
public string DB_Send_CMD_Search(string cmd)
{
// DB 연결
conn.Open();
// 쿼리 맵핑
@@ -147,6 +149,32 @@ namespace WindowsFormsApp1
conn.Close();
return result;
}
public DataTable DB_Send_CMD_Search_DataTable(string cmd)
{
DataTable dt = new DataTable();
try
{
if (conn.State == ConnectionState.Closed)
conn.Open();
using (MySqlDataAdapter adapter = new MySqlDataAdapter(cmd, conn))
{
adapter.Fill(dt);
}
}
catch (Exception ex)
{
UTIL.MsgE($"데이터베이스 실행오류\n{ex.Message}");
return null;
}
finally
{
if (conn.State == ConnectionState.Open)
conn.Close();
}
return dt;
}
public void DB_Send_CMD_Search_ApplyGrid(string cmd, DataGridView dgv)
{
// DB 연결
@@ -157,7 +185,7 @@ namespace WindowsFormsApp1
sqlcmd.Connection = conn;
// 쿼리 날리기, sqlDataReader에 결과값 저장
sd = sqlcmd.ExecuteReader();
int colCount = dgv.ColumnCount;
string[] grid = new string[colCount];
int AddCol = 0;
@@ -184,7 +212,7 @@ namespace WindowsFormsApp1
conn.Close();
}
public void DB_Send_CMD_Search_GetGridData(string cmd,DataGridView pDgv)
public void DB_Send_CMD_Search_GetGridData(string cmd, DataGridView pDgv)
{
// DB 연결
conn.Open();
@@ -209,7 +237,7 @@ namespace WindowsFormsApp1
if (colCount - 1 == AddCol)
{
AddCol = 0;
grid[colCount]="추가";
grid[colCount] = "추가";
pDgv.Rows.Add(grid);
}
else
@@ -220,32 +248,8 @@ namespace WindowsFormsApp1
}
conn.Close();
}
public void DB_Send_CMD_reVoid(string cmd)
{
//using (conn)
{
conn.Open();
MySqlTransaction tran = conn.BeginTransaction();
sqlcmd.Connection = conn;
sqlcmd.Transaction = tran;
try
{
sqlcmd.CommandText = cmd;
sqlcmd.ExecuteNonQuery();
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
if (conn != null && conn.State != System.Data.ConnectionState.Closed)
conn.Close();
}
}
}
/// <summary>
/// DBcon이 선진행되어야함.
/// SELECT * FROM [DB_Table_Name] WHERE [DB_Where_Table] LIKE \"%DB_Search_Data%\"
@@ -255,10 +259,10 @@ namespace WindowsFormsApp1
/// <param name="DB_Where_Table">검색할 테이블</param>
/// <param name="DB_Search_Data">검색할 텍스트</param>
/// <returns>검색된 결과값이 반환됨.</returns>
public string DB_Contains(string DB_Table_Name, string compidx,
public string DB_Contains(string DB_Table_Name, string compidx,
string DB_Where_Table = "", string DB_Search_Data = "",
string Search_col = "",
string DB_Where_Table1 = "", string DB_Search_Data1 = "" )
string Search_col = "",
string DB_Where_Table1 = "", string DB_Search_Data1 = "")
{
string cmd = "SELECT ";
if (Search_col == "") { cmd += "*"; }
@@ -268,16 +272,16 @@ namespace WindowsFormsApp1
if (DB_Table_Name == "Obj_List") { cmd += " WHERE `comp_num` = \"" + compidx + "\""; }
else if (DB_Table_Name == "Client") { cmd += " WHERE `campanyidx` = \"" + compidx + "\""; }
else if (DB_Table_Name == "Purchase") { cmd += " WHERE `comparyidx` = \"" + compidx + "\""; }
else if(compidx == "none") { cmd += " WHERE `grade` = \"2\""; }
else if (compidx == "none") { cmd += " WHERE `grade` = \"2\""; }
else { cmd += " WHERE `compidx` = \"" + compidx + "\""; }
if(DB_Search_Data != "")
{
cmd += " AND `"+ DB_Where_Table + "` LIKE \"%" + DB_Search_Data + "%\"";
if (DB_Search_Data != "")
{
cmd += " AND `" + DB_Where_Table + "` LIKE \"%" + DB_Search_Data + "%\"";
}
if(DB_Search_Data1 != "")
{
cmd += " AND `"+ DB_Where_Table1 + "` LIKE \"%" + DB_Search_Data1 + "%\"";
if (DB_Search_Data1 != "")
{
cmd += " AND `" + DB_Where_Table1 + "` LIKE \"%" + DB_Search_Data1 + "%\"";
}
cmd += ";";
return cmd;
@@ -290,17 +294,17 @@ namespace WindowsFormsApp1
/// <param name="DB_Where_Table">검색할 테이블</param>
/// <param name="DB_Search_Data">검색할 텍스트</param>
/// <returns>검색된 결과값이 반환됨.</returns>
public string DB_Select_Search(string Search_Area, string DB_Table_Name,
public string DB_Select_Search(string Search_Area, string DB_Table_Name,
string DB_Where_Table = "", string DB_Search_Data = "",
string DB_Where_Table1 = "", string DB_Search_Data1 = "")
{
string cmd = string.Format("SELECT {0} FROM ", Search_Area);
cmd += DB_Table_Name;
if(DB_Where_Table != "" && DB_Search_Data != "")
if (DB_Where_Table != "" && DB_Search_Data != "")
{
cmd += string.Format(" WHERE `{0}` = \"{1}\"", DB_Where_Table, DB_Search_Data);
}
if(DB_Where_Table1 != "" && DB_Search_Data1 != "")
if (DB_Where_Table1 != "" && DB_Search_Data1 != "")
{
cmd += string.Format(" AND `{0}` = \"{1}\"", DB_Where_Table1, DB_Search_Data1);
}
@@ -314,15 +318,15 @@ namespace WindowsFormsApp1
/// <param name="DB_Where_Table">검색할 테이블</param>
/// <param name="DB_Search_Data">검색할 텍스트</param>
/// <returns>검색된 결과값이 반환됨.</returns>
public string DB_Search(string DB_Table_Name,
public string DB_Search(string DB_Table_Name,
string DB_Where_Table = "", string DB_Search_Data = "",
string DB_Where_Table1 = "", string DB_Search_Data1 = "")
{
string cmd = "SELECT * FROM ";
cmd += DB_Table_Name;// + " where id=\"id\"";
if(DB_Search_Data != "")
{
cmd += " WHERE "+ DB_Where_Table + "=\"" + DB_Search_Data +"\"";
if (DB_Search_Data != "")
{
cmd += " WHERE " + DB_Where_Table + "=\"" + DB_Search_Data + "\"";
}
if (DB_Where_Table1 != "" && DB_Search_Data1 != "")
{
@@ -339,18 +343,18 @@ namespace WindowsFormsApp1
/// <param name="DB_Search_Data"></param>
/// <param name="Search_Table">추출할 열의 이름."`num1`, `num2`" 이런식으로</param>
/// <returns></returns>
public string More_DB_Search(String DB_Table_Name, String[] DB_Where_Table,
public string More_DB_Search(String DB_Table_Name, String[] DB_Where_Table,
String[] DB_Search_Data, String Search_Table = "")
{
if(DB_Where_Table.Length != DB_Search_Data.Length) { return "오류발생"; }
if (DB_Where_Table.Length != DB_Search_Data.Length) { return "오류발생"; }
string cmd = "SELECT ";
if(Search_Table == "") { cmd += "*"; }
if (Search_Table == "") { cmd += "*"; }
else { cmd += Search_Table; }
cmd += " FROM " + DB_Table_Name + " WHERE ";
for(int a = 0; a < DB_Where_Table.Length; a++)
for (int a = 0; a < DB_Where_Table.Length; a++)
{
cmd += "`" + DB_Where_Table[a] + "` = \"" + DB_Search_Data[a] + "\" ";
if(a == DB_Where_Table.Length - 1) { cmd += ";"; }
if (a == DB_Where_Table.Length - 1) { cmd += ";"; }
else { cmd += " AND "; }
}
return cmd;
@@ -365,7 +369,7 @@ namespace WindowsFormsApp1
/// <param name="end_date">끝낼 날짜 0000-00-00</param>
/// <param name="compidx">회사 인덱스 main.com_idx</param>
/// <returns></returns>
public string Search_Date(string Table_name, string Search_Table, string Search_date,
public string Search_Date(string Table_name, string Search_Table, string Search_date,
string start_date, string end_date, string compidx)
{
if (Search_Table == "") { Search_Table = "*"; }
@@ -373,7 +377,7 @@ namespace WindowsFormsApp1
string cmd = "SELECT " + Search_Table + " FROM `" + Table_name + "` " +
"WHERE `comp_num` = '" + compidx + "' AND `" +
Search_date + "` >= '" + start_date + "'";
if(Table_name != "Obj_List") { cmd = cmd.Replace("`comp_num`", "`compidx`"); }
if (Table_name != "Obj_List") { cmd = cmd.Replace("`comp_num`", "`compidx`"); }
if (end_date != "") { cmd += " AND `" + Search_date + "` <= '" + end_date + "';"; }
else { cmd += ";"; }
return cmd;
@@ -381,13 +385,13 @@ namespace WindowsFormsApp1
public string DB_INSERT(String DB_Table_name, String[] DB_col_name, String[] setData)
{
string cmd = "INSERT INTO " + DB_Table_name + "(";
for(int a = 0; a < DB_col_name.Length; a++)
for (int a = 0; a < DB_col_name.Length; a++)
{
if (a == DB_col_name.Length - 1) { cmd += "`" + DB_col_name[a] + "`) "; }
else { cmd += "`" + DB_col_name[a] + "`, "; }
}
cmd += "values(";
for(int a = 0; a < setData.Length; a++)
for (int a = 0; a < setData.Length; a++)
{
setData[a] = setData[a].Replace("\"", "\"\"");
if (a == setData.Length - 1) { cmd += "\"" + setData[a] + "\")"; }
@@ -425,8 +429,8 @@ namespace WindowsFormsApp1
/// <param name="comp_idx">삭제할 대상의 인덱스</param>
/// <param name="target_area">삭제할 대상이 있는 열명</param>
/// <param name="target">삭제할 대상</param>
public string DB_Delete(string DB_Table_Name,
string target_idx, string comp_idx,
public string DB_Delete(string DB_Table_Name,
string target_idx, string comp_idx,
string target_area, string target)
{
string cmd = "DELETE FROM " + DB_Table_Name + " WHERE " +
@@ -442,12 +446,12 @@ namespace WindowsFormsApp1
/// <param name="comp_idx">회사 인덱스</param>
/// <param name="target_area">삭제 대상의 컬럼명</param>
/// <param name="target">삭제 대상</param>
public string DB_Delete_No_Limit(string DB_Table,
string target_idx, string comp_idx,
public string DB_Delete_No_Limit(string DB_Table,
string target_idx, string comp_idx,
string[] target_area, string[] target)
{
string cmd = string.Format("DELETE FROM {0} WHERE `{1}`= \"{2}\" AND", DB_Table, target_idx, comp_idx);
for(int a= 0; a < target_area.Length; a++)
for (int a = 0; a < target_area.Length; a++)
{
cmd += string.Format("`{0}`=\"{1}\"", target_area[a], target[a]);
if (a != target_area.Length - 1) { cmd += " AND"; }
@@ -458,13 +462,13 @@ namespace WindowsFormsApp1
/// <summary>
/// 대상 컬럼 삭제 / DELETE FROM "DB_Table_Name" WHERE "target_idx"="comp_idx" AND "target_area"="target";
/// </summary>
public string DB_Delete_More_term(string DB_Table_Name,
string target_idx, string comp_idx,
public string DB_Delete_More_term(string DB_Table_Name,
string target_idx, string comp_idx,
string[] target_area, string[] target)
{
string cmd = "DELETE FROM " + DB_Table_Name + " WHERE " +
"`" + target_idx + "`=\"" + comp_idx + "\" AND";
for(int a = 0; a < target_area.Length; a++)
for (int a = 0; a < target_area.Length; a++)
{
cmd += " `" + target_area[a] + "`=\"" + target[a] + "\" ";
if (a == target_area.Length - 1) { cmd += "LIMIT 1;"; }
@@ -482,7 +486,7 @@ namespace WindowsFormsApp1
/// <param name="Search_Data">검색할 데이터</param>
public string DB_Update(string DB_Tabel_Name, string Edit_colum, string Edit_Name, string Search_Name, string Search_Data)
{
string cmd = "UPDATE `" + DB_Tabel_Name + "` SET `" + Edit_colum + "`=\"" + Edit_Name + "\" WHERE `"+Search_Name+"`=\"" + Search_Data + "\";";
string cmd = "UPDATE `" + DB_Tabel_Name + "` SET `" + Edit_colum + "`=\"" + Edit_Name + "\" WHERE `" + Search_Name + "`=\"" + Search_Data + "\";";
cmd = cmd.Replace("|", "");
return cmd;
}
@@ -494,12 +498,12 @@ namespace WindowsFormsApp1
/// <param name="Edit_name">바꿀 데이터값</param>
/// <param name="Search_col">대상 테이블명</param>
/// <param name="Search_Name">대상 데이터값</param>
public string More_Update(String DB_Table_Name,
String[] Edit_col, String[] Edit_name,
public string More_Update(String DB_Table_Name,
String[] Edit_col, String[] Edit_name,
String[] Search_col, String[] Search_Name, int limit = 0)
{
string cmd = "UPDATE `" + DB_Table_Name + "` SET ";
for(int a = 0; a < Edit_col.Length; a++)
for (int a = 0; a < Edit_col.Length; a++)
{
Edit_name[a] = Edit_name[a].Replace("\"", "\"\"");
cmd += "`" + Edit_col[a] + "` = \"" + Edit_name[a] + "\"";
@@ -507,14 +511,14 @@ namespace WindowsFormsApp1
else { cmd += " "; }
}
cmd += "WHERE ";
for(int a = 0; a < Search_col.Length; a++)
for (int a = 0; a < Search_col.Length; a++)
{
cmd += "`" + Search_col[a] + "` = \"" + Search_Name[a] + "\" ";
if (a != Search_col.Length - 1) { cmd += "AND "; }
}
if(limit != 0) { cmd += string.Format("LIMIT {0}", limit); }
if (limit != 0) { cmd += string.Format("LIMIT {0}", limit); }
cmd += ";";
cmd = cmd.Replace("|", "");
cmd = cmd.Replace("|", "");
return cmd;
}
/// <summary>
@@ -570,10 +574,9 @@ namespace WindowsFormsApp1
}
}
}
catch(Exception e)
catch (Exception e)
{
MessageBox.Show("{0} Exception caught.\n"+ e.ToString());
MessageBox.Show(cmd);
UTIL.MsgE(e.ToString());
}
conn.Close();
return result;

View File

@@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Text;
namespace UniMarc
{
/// <summary>
/// 도서관별 지연시간 설정을 관리하는 클래스
/// </summary>
public class Helper_LibraryDelaySettings
{
private static readonly string SettingsFileName = "LibraryDelaySettings.xml";
private static readonly string SettingsFilePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"UniMarc",
SettingsFileName
);
private Dictionary<string, int> _libraryDelaySettings;
public Helper_LibraryDelaySettings()
{
_libraryDelaySettings = new Dictionary<string, int>();
LoadSettings();
}
/// <summary>
/// 도서관별 지연시간 설정을 로드
/// </summary>
private void LoadSettings()
{
try
{
if (File.Exists(SettingsFilePath))
{
var xmlDoc = new XmlDocument();
xmlDoc.Load(SettingsFilePath);
var libraryNodes = xmlDoc.SelectNodes("//LibraryDelaySettings/Library");
if (libraryNodes != null)
{
foreach (XmlNode node in libraryNodes)
{
var name = node.Attributes?["Name"]?.Value;
var delayStr = node.Attributes?["Delay"]?.Value;
if (!string.IsNullOrEmpty(name) && int.TryParse(delayStr, out int delay))
{
_libraryDelaySettings[name] = delay;
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"도서관 지연시간 설정 로드 오류: {ex.Message}");
_libraryDelaySettings = new Dictionary<string, int>();
}
}
/// <summary>
/// 도서관별 지연시간 설정을 저장
/// </summary>
private void SaveSettings()
{
try
{
// 디렉토리 생성
var directory = Path.GetDirectoryName(SettingsFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// XML 파일로 저장
var xmlDoc = new XmlDocument();
var declaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
xmlDoc.AppendChild(declaration);
var root = xmlDoc.CreateElement("LibraryDelaySettings");
xmlDoc.AppendChild(root);
foreach (var kvp in _libraryDelaySettings)
{
var libraryElement = xmlDoc.CreateElement("Library");
libraryElement.SetAttribute("Name", kvp.Key);
libraryElement.SetAttribute("Delay", kvp.Value.ToString());
root.AppendChild(libraryElement);
}
xmlDoc.Save(SettingsFilePath);
}
catch (Exception ex)
{
Console.WriteLine($"도서관 지연시간 설정 저장 오류: {ex.Message}");
}
}
/// <summary>
/// 특정 도서관의 지연시간 설정을 가져옴
/// </summary>
/// <param name="libraryName">도서관 이름</param>
/// <returns>지연시간(초), 설정이 없으면 0</returns>
public int GetDelay(string libraryName)
{
if (string.IsNullOrEmpty(libraryName))
return 0;
return _libraryDelaySettings.TryGetValue(libraryName, out int delay) ? delay : 0;
}
/// <summary>
/// 특정 도서관의 지연시간 설정을 저장
/// </summary>
/// <param name="libraryName">도서관 이름</param>
/// <param name="delaySeconds">지연시간(초)</param>
public void SetDelay(string libraryName, int delaySeconds)
{
if (string.IsNullOrEmpty(libraryName))
return;
if (delaySeconds < 0)
delaySeconds = 0;
_libraryDelaySettings[libraryName] = delaySeconds;
SaveSettings();
Console.WriteLine($"도서관 지연시간 설정 저장: {libraryName} = {delaySeconds}초");
}
/// <summary>
/// 모든 도서관 지연시간 설정을 가져옴
/// </summary>
/// <returns>도서관명-지연시간 딕셔너리</returns>
public Dictionary<string, int> GetAllSettings()
{
return new Dictionary<string, int>(_libraryDelaySettings);
}
/// <summary>
/// 특정 도서관의 지연시간 설정을 제거
/// </summary>
/// <param name="libraryName">도서관 이름</param>
public void RemoveDelay(string libraryName)
{
if (string.IsNullOrEmpty(libraryName))
return;
if (_libraryDelaySettings.ContainsKey(libraryName))
{
_libraryDelaySettings.Remove(libraryName);
SaveSettings();
Console.WriteLine($"도서관 지연시간 설정 제거: {libraryName}");
}
}
/// <summary>
/// 모든 지연시간 설정을 초기화
/// </summary>
public void ClearAllSettings()
{
_libraryDelaySettings.Clear();
SaveSettings();
Console.WriteLine("모든 도서관 지연시간 설정 초기화");
}
}
}

View File

@@ -0,0 +1,258 @@
namespace UniMarc.ListOfValue
{
partial class fSelectDT
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(fSelectDT));
this.dv1 = new System.Windows.Forms.DataGridView();
this.bn = new System.Windows.Forms.BindingNavigator(this.components);
this.bs = new System.Windows.Forms.BindingSource(this.components);
this.bindingNavigatorCountItem = new System.Windows.Forms.ToolStripLabel();
this.bindingNavigatorMoveFirstItem = new System.Windows.Forms.ToolStripButton();
this.bindingNavigatorMovePreviousItem = new System.Windows.Forms.ToolStripButton();
this.bindingNavigatorSeparator = new System.Windows.Forms.ToolStripSeparator();
this.bindingNavigatorPositionItem = new System.Windows.Forms.ToolStripTextBox();
this.bindingNavigatorSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.bindingNavigatorMoveNextItem = new System.Windows.Forms.ToolStripButton();
this.bindingNavigatorMoveLastItem = new System.Windows.Forms.ToolStripButton();
this.bindingNavigatorSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel();
this.tbFind = new System.Windows.Forms.ToolStripTextBox();
this.btfind = new System.Windows.Forms.ToolStripButton();
this.btSelect = new System.Windows.Forms.ToolStripButton();
((System.ComponentModel.ISupportInitialize)(this.dv1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.bn)).BeginInit();
this.bn.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.bs)).BeginInit();
this.SuspendLayout();
//
// dv1
//
this.dv1.AllowUserToAddRows = false;
this.dv1.AllowUserToDeleteRows = false;
this.dv1.AllowUserToResizeRows = false;
this.dv1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;
dataGridViewCellStyle1.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
dataGridViewCellStyle1.Padding = new System.Windows.Forms.Padding(0, 3, 0, 3);
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
this.dv1.DefaultCellStyle = dataGridViewCellStyle1;
this.dv1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dv1.Location = new System.Drawing.Point(0, 0);
this.dv1.MultiSelect = false;
this.dv1.Name = "dv1";
this.dv1.ReadOnly = true;
this.dv1.RowTemplate.Height = 23;
this.dv1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.dv1.Size = new System.Drawing.Size(768, 423);
this.dv1.TabIndex = 0;
//
// bn
//
this.bn.AddNewItem = null;
this.bn.BindingSource = this.bs;
this.bn.CountItem = this.bindingNavigatorCountItem;
this.bn.DeleteItem = null;
this.bn.Dock = System.Windows.Forms.DockStyle.Bottom;
this.bn.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.bindingNavigatorMoveFirstItem,
this.bindingNavigatorMovePreviousItem,
this.bindingNavigatorSeparator,
this.bindingNavigatorPositionItem,
this.bindingNavigatorCountItem,
this.bindingNavigatorSeparator1,
this.bindingNavigatorMoveNextItem,
this.bindingNavigatorMoveLastItem,
this.bindingNavigatorSeparator2,
this.toolStripLabel1,
this.tbFind,
this.btfind,
this.btSelect});
this.bn.Location = new System.Drawing.Point(0, 423);
this.bn.MoveFirstItem = this.bindingNavigatorMoveFirstItem;
this.bn.MoveLastItem = this.bindingNavigatorMoveLastItem;
this.bn.MoveNextItem = this.bindingNavigatorMoveNextItem;
this.bn.MovePreviousItem = this.bindingNavigatorMovePreviousItem;
this.bn.Name = "bn";
this.bn.PositionItem = this.bindingNavigatorPositionItem;
this.bn.Size = new System.Drawing.Size(768, 25);
this.bn.TabIndex = 1;
this.bn.Text = "bindingNavigator1";
//
// bindingNavigatorCountItem
//
this.bindingNavigatorCountItem.Name = "bindingNavigatorCountItem";
this.bindingNavigatorCountItem.Size = new System.Drawing.Size(27, 22);
this.bindingNavigatorCountItem.Text = "/{0}";
this.bindingNavigatorCountItem.ToolTipText = "전체 항목 수";
//
// bindingNavigatorMoveFirstItem
//
this.bindingNavigatorMoveFirstItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.bindingNavigatorMoveFirstItem.Image = ((System.Drawing.Image)(resources.GetObject("bindingNavigatorMoveFirstItem.Image")));
this.bindingNavigatorMoveFirstItem.Name = "bindingNavigatorMoveFirstItem";
this.bindingNavigatorMoveFirstItem.RightToLeftAutoMirrorImage = true;
this.bindingNavigatorMoveFirstItem.Size = new System.Drawing.Size(23, 22);
this.bindingNavigatorMoveFirstItem.Text = "처음으로 이동";
//
// bindingNavigatorMovePreviousItem
//
this.bindingNavigatorMovePreviousItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.bindingNavigatorMovePreviousItem.Image = ((System.Drawing.Image)(resources.GetObject("bindingNavigatorMovePreviousItem.Image")));
this.bindingNavigatorMovePreviousItem.Name = "bindingNavigatorMovePreviousItem";
this.bindingNavigatorMovePreviousItem.RightToLeftAutoMirrorImage = true;
this.bindingNavigatorMovePreviousItem.Size = new System.Drawing.Size(23, 22);
this.bindingNavigatorMovePreviousItem.Text = "이전으로 이동";
//
// bindingNavigatorSeparator
//
this.bindingNavigatorSeparator.Name = "bindingNavigatorSeparator";
this.bindingNavigatorSeparator.Size = new System.Drawing.Size(6, 25);
//
// bindingNavigatorPositionItem
//
this.bindingNavigatorPositionItem.AccessibleName = "위치";
this.bindingNavigatorPositionItem.AutoSize = false;
this.bindingNavigatorPositionItem.Font = new System.Drawing.Font("맑은 고딕", 9F);
this.bindingNavigatorPositionItem.Name = "bindingNavigatorPositionItem";
this.bindingNavigatorPositionItem.Size = new System.Drawing.Size(50, 23);
this.bindingNavigatorPositionItem.Text = "0";
this.bindingNavigatorPositionItem.ToolTipText = "현재 위치";
//
// bindingNavigatorSeparator1
//
this.bindingNavigatorSeparator1.Name = "bindingNavigatorSeparator1";
this.bindingNavigatorSeparator1.Size = new System.Drawing.Size(6, 25);
//
// bindingNavigatorMoveNextItem
//
this.bindingNavigatorMoveNextItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.bindingNavigatorMoveNextItem.Image = ((System.Drawing.Image)(resources.GetObject("bindingNavigatorMoveNextItem.Image")));
this.bindingNavigatorMoveNextItem.Name = "bindingNavigatorMoveNextItem";
this.bindingNavigatorMoveNextItem.RightToLeftAutoMirrorImage = true;
this.bindingNavigatorMoveNextItem.Size = new System.Drawing.Size(23, 22);
this.bindingNavigatorMoveNextItem.Text = "다음으로 이동";
//
// bindingNavigatorMoveLastItem
//
this.bindingNavigatorMoveLastItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.bindingNavigatorMoveLastItem.Image = ((System.Drawing.Image)(resources.GetObject("bindingNavigatorMoveLastItem.Image")));
this.bindingNavigatorMoveLastItem.Name = "bindingNavigatorMoveLastItem";
this.bindingNavigatorMoveLastItem.RightToLeftAutoMirrorImage = true;
this.bindingNavigatorMoveLastItem.Size = new System.Drawing.Size(23, 22);
this.bindingNavigatorMoveLastItem.Text = "마지막으로 이동";
//
// bindingNavigatorSeparator2
//
this.bindingNavigatorSeparator2.Name = "bindingNavigatorSeparator2";
this.bindingNavigatorSeparator2.Size = new System.Drawing.Size(6, 25);
//
// toolStripLabel1
//
this.toolStripLabel1.Name = "toolStripLabel1";
this.toolStripLabel1.Size = new System.Drawing.Size(31, 22);
this.toolStripLabel1.Text = "검색";
//
// tbFind
//
this.tbFind.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.tbFind.Font = new System.Drawing.Font("맑은 고딕", 9F);
this.tbFind.Name = "tbFind";
this.tbFind.Size = new System.Drawing.Size(200, 25);
this.tbFind.TextBoxTextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.tbFind.KeyDown += new System.Windows.Forms.KeyEventHandler(this.tbFind_KeyDown);
//
// btfind
//
this.btfind.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.btfind.Image = ((System.Drawing.Image)(resources.GetObject("btfind.Image")));
this.btfind.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btfind.Name = "btfind";
this.btfind.Size = new System.Drawing.Size(23, 22);
this.btfind.Text = "toolStripButton1";
this.btfind.Click += new System.EventHandler(this.btfind_Click);
//
// btSelect
//
this.btSelect.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.btSelect.Image = ((System.Drawing.Image)(resources.GetObject("btSelect.Image")));
this.btSelect.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btSelect.Name = "btSelect";
this.btSelect.Size = new System.Drawing.Size(51, 22);
this.btSelect.Text = "선택";
this.btSelect.TextAlign = System.Drawing.ContentAlignment.TopLeft;
this.btSelect.Click += new System.EventHandler(this.btSelect_Click);
//
// fSelectDT
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(768, 448);
this.Controls.Add(this.dv1);
this.Controls.Add(this.bn);
this.KeyPreview = true;
this.Name = "fSelectDT";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "fSelectDT";
this.Load += new System.EventHandler(this.fSelectDT_Load);
((System.ComponentModel.ISupportInitialize)(this.dv1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.bn)).EndInit();
this.bn.ResumeLayout(false);
this.bn.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.bs)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.DataGridView dv1;
private System.Windows.Forms.BindingNavigator bn;
private System.Windows.Forms.ToolStripLabel bindingNavigatorCountItem;
private System.Windows.Forms.ToolStripButton bindingNavigatorMoveFirstItem;
private System.Windows.Forms.ToolStripButton bindingNavigatorMovePreviousItem;
private System.Windows.Forms.ToolStripSeparator bindingNavigatorSeparator;
private System.Windows.Forms.ToolStripTextBox bindingNavigatorPositionItem;
private System.Windows.Forms.ToolStripSeparator bindingNavigatorSeparator1;
private System.Windows.Forms.ToolStripButton bindingNavigatorMoveNextItem;
private System.Windows.Forms.ToolStripButton bindingNavigatorMoveLastItem;
private System.Windows.Forms.ToolStripSeparator bindingNavigatorSeparator2;
private System.Windows.Forms.BindingSource bs;
private System.Windows.Forms.ToolStripLabel toolStripLabel1;
private System.Windows.Forms.ToolStripTextBox tbFind;
private System.Windows.Forms.ToolStripButton btfind;
private System.Windows.Forms.ToolStripButton btSelect;
}
}

View File

@@ -0,0 +1,143 @@
using AR;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace UniMarc.ListOfValue
{
public partial class fSelectDT : Form
{
public DataRow SelectedRow = null;
public fSelectDT(DataTable dt)
{
InitializeComponent();
this.KeyDown += (s1, e1) =>
{
if (e1.KeyCode == Keys.Escape) Close();
};
this.bs.DataSource = dt;
this.bn.BindingSource = this.bs;
this.dv1.DataSource = this.bs;
this.dv1.MultiSelect = false;
this.dv1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
this.dv1.EditMode = DataGridViewEditMode.EditProgrammatically;
this.dv1.CellDoubleClick += Dv1_CellDoubleClick;
this.dv1.KeyDown += Dv1_KeyDown;
}
private void Dv1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
e.Handled = true;
e.SuppressKeyPress = true;
btSelect_Click(sender, e);
}
}
private void Dv1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
var row = this.dv1.Rows[e.RowIndex];
if (row.DataBoundItem is DataRowView drv)
{
SelectedRow = drv.Row;
this.DialogResult = DialogResult.OK;
this.Close();
}
}
}
private void fSelectDT_Load(object sender, EventArgs e)
{
this.Show();
Application.DoEvents();
this.dv1.AutoResizeColumns();
this.dv1.Focus();
}
private void btfind_Click(object sender, EventArgs e)
{
find();
}
void find()
{
var search = tbFind.Text.Trim();
var filter = "";
try
{
if (!search.isEmpty())
{
// 검색어에서 작은따옴표 이스케이프 처리
var escapedSearch = search.Replace("'", "''");
// DataTable의 모든 컬럼에 대해 검색 필터 생성
var dt = this.bs.DataSource as DataTable;
if (dt != null && dt.Columns.Count > 0)
{
var filters = new List<string>();
foreach (DataColumn column in dt.Columns)
{
// 문자열 컬럼만 검색 (숫자나 날짜 컬럼은 Convert 사용)
if (column.DataType == typeof(string))
{
filters.Add($"ISNULL(CONVERT([{column.ColumnName}], 'System.String'), '') LIKE '%{escapedSearch}%'");
}
else
{
filters.Add($"CONVERT([{column.ColumnName}], 'System.String') LIKE '%{escapedSearch}%'");
}
}
// OR 조건으로 연결
filter = string.Join(" OR ", filters);
}
}
this.bs.Filter = filter;
if (search.isEmpty()) tbFind.BackColor = Color.White;
else tbFind.BackColor = Color.Lime;
}
catch (Exception ex)
{
this.bs.Filter = "";
tbFind.BackColor = Color.HotPink;
}
finally
{
tbFind.SelectAll();
tbFind.Focus();
}
}
private void btSelect_Click(object sender, EventArgs e)
{
if (this.bs.Current == null)
{
UTIL.MsgE("선택된 데이터가 없습니다.");
return;
}
if (this.bs.Current is DataRowView drv)
{
SelectedRow = drv.Row;
this.DialogResult = DialogResult.OK;
this.Close();
}
}
private void tbFind_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter) find();
}
}
}

View File

@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="bn.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="bs.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>171, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="bindingNavigatorMoveFirstItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wAAADsABataJCQAAATFJREFUOE9jYBg0oHDW8/9NC57/z5z4+D+6HAyEtz/AKceQO/PZ/1VH3v/HpSi+
+8H/4IZrWOXAIGPK0/8L933Aqii+5+H/pfv///evvoAhBwcJPU/+T9vyHkNRRPt9sObMWf//e5WewG1A
ZNej/72rP6AoCm29B9bcuu7/f//Ov/9d8g/gNiCw+eH/uvnv4IqCW+7+X7T3//+Odf//Z8z5+d+u7ud/
+4ztuA3wqLr/P3/aGxRFdsW3/6fP+f3fv+vbf53Cd/8tEtbjNsC+9O7/7MmvMRTpp5z/b1L04r9K1qf/
xpHLcBtgkXfnf2r/a6yKDJJO/JdN+/pfN3gehhwcGGbd/h/W8hKnIv3Uy/81fKdhlQMDnbQb//2qH+JV
pOIxAaccg1Pulf8gBXgVDUoAAPB2wKtYlLYeAAAAAElFTkSuQmCC
</value>
</data>
<data name="bindingNavigatorMovePreviousItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wAAADsABataJCQAAALtJREFUOE9jYBgyILz9wX90MaJBfPeD/8EN18gzIL7n4f+l+///96++QLoBEe33
wZozZ/3/71V6gjQDQlvvgTW3rvv/37/z73+X/APEGxDccvf/or3//3es+/8/Y87P/3Z1P//bZ2wn3gAQ
sCu+/T99zu///l3f/usUvvtvkbCeNANAQD/l/H+Tohf/VbI+/TeOXEa6ASBgkHTiv2za1/+6wfPIMwAE
9FMv/9fwnUa+ASCg4jGBMgMGLwAA0BRgmCws/7cAAAAASUVORK5CYII=
</value>
</data>
<data name="bindingNavigatorMoveNextItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wAAADsABataJCQAAAKRJREFUOE9jYBh0oHDW8//oYiSB3JnP/id03yPfkIwpT//P2//7f0LXHfIMSeh5
8n/2vl//O7f+/e9Wepl0QyK7Hv2fsu3X/5Klf/8nTP/73yb3LGmGBDY//N+69j1Ys3HJl//S0df+G0cu
I94Qj6r7/0vmvoNrVnTpIV4zCNiX3v0f2PKMPM0gYJF3579NwRXyNIOAYdZt8jWDgE7aDfI1D00AAKB+
X6Bjq5qXAAAAAElFTkSuQmCC
</value>
</data>
<data name="bindingNavigatorMoveLastItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wAAADsABataJCQAAAStJREFUOE9jYBhUoHDW8//oYjAAkmta8Px/5sTHONUw5M589j+h+x5WBSC5VUfe
/w9vf4BVHgwypjz9P2//7/8JXXcwFIHkFu778D+44RqGHBwk9Dz5P3vfr/+dW//+dyu9jKIQJDdty/v/
/tUXcBsQ2fXo/5Rtv/6XLP37P2H63/82uWfhikFyvas//PcqPYHbgMDmh/9b174HazYu+fJfOvraf+PI
ZWANILm6+e/+u+QfwG2AR9X9/yVz38E1K7r0wBWD5PKnvflvn7EdtwH2pXf/B7Y8w9AMk8ue/Pq/RcJ6
3AZY5N35b1NwBUMzTC61/zXcS1iBYdZtrJpBACQX1vLyv27wPKzyYKCTdgOnJEjOr/rhfw3faTjV4AVO
uVf+q3hMAGN0uYEFAL7Rv7NmXVYYAAAAAElFTkSuQmCC
</value>
</data>
<data name="btfind.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIqSURBVDhPY2AYdKCxf9ajJRv2/G+dOPc/iD95wTowOzQ2
+Ra6WqygrLHv0bodh/+HxqaCDcgoqvnfN3vF/8b+2U/Q1aKApOyS/13Tl/yv7Zz6v23S/P8mlnZgAxzc
fP5nldT9L6hqBYtZ2bks19LS4mFgYGACa5w/fz9HYXWbR1PfbLBTC6vb/nv4h/138Qr4n1PW8D82Le9/
RE7T/9qJy/6XtEwBy3Fx8VQxMDAwgg2or9/PMmX+uoeL1u36n1veBMbVE1f9n7J81/+eJVt/NU7f8L+2
d/7/6Nzm/+HJhWAXMrOwPGBgYGAGGzBz5kxWkM3TFm/8n11a/x/k55Tc8v/RyTn/1bT0wDaCXAITj0sv
AHntHwMDAyvYgLS0NFaf4JifFrZO/70CI/4bW9j+19Y3/i+toPRUVFTUQFJGdquYhNR/BSXV/6Likv95
+fj/MzIyvoOHAQh4BUUdBgXcrsNn/q/acuB/94xl/40t7VaA5FTUdVZUtkz4v3bHIbAcKEb4+PgPwzWD
gItX4J/8imawAWkFlf/jMwr/6xqbXwXJKSiqXgXFAMiA1PyK/+mF1f85OLn+oBjg6O77H2YATJGatv5P
UEiLSUq/AwUczABQWLCysoGjGA6sHd3A8QxKQCAFoMDUNTL7L6ikxK+gqnYFZAAolmByjIyMqAaAEoiB
iSU48FQ1df4rqqj/l5ZV+C8sLCzFwy94m5OL+z8bOzso+kAaYXiQAABSzSGsYv7dkQAAAABJRU5ErkJg
gg==
</value>
</data>
<data name="btSelect.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGTSURBVDhP1c/bL4JxHMfx5w79E27c2zwZ5RCzsZRDeYaS
iiLimdksPTr8OqiGOTyXrCXn2XJYdIHZXMoh428w/wT6WLbaCi3uvC5/v+/7d6Cof6d7o41XBltJ7npB
UjF7YsDokQ5SvpHL3c+LCcv48egglh898F3PQL/bg/rZKlvu3LeYkIw3H+ux+ODGwgPBwF4vGnwiSIik
ODNkPtc1mWLqoaySoihlSMannjyfIJhLOD9vrnFVvmXHF/21xlPNC3fFQhthJjJxUMqPHGoxd+9A4N4O
3U43xESYHY+eaZuNMdWzP85hMeGCervjjQm3T3SuSRdMBxr47+zw3XLo32YgInR2nDK5z5QYjlWwXI5h
5WkWvvgMzFE92FMDvHErPLdWaLa6IHYI37/EacNRuUC9qwAbM3z+M3Bng/vGAnfcAvWmEmKnMPljnCZf
lQsUa1IYI33w3EzDeT0FVVgBkYNOSkhp/jgtdUjLUgM0Wwx61jtQba8oPE6TE1pQ561CJVf+WsaWFeXu
F4QmtODP8W99AIUYxS+0cG7HAAAAAElFTkSuQmCC
</value>
</data>
</root>

View File

@@ -1,4 +1,4 @@
namespace WindowsFormsApp1
namespace UniMarc
{
partial class login
{

View File

@@ -11,8 +11,9 @@ using System.IO;
using System.Net;
using System.Net.Sockets;
using Application = System.Windows.Forms.Application;
using AR;
namespace WindowsFormsApp1
namespace UniMarc
{
public partial class login : Form
{
@@ -25,7 +26,7 @@ namespace WindowsFormsApp1
private void login_Load(object sender, EventArgs e)
{
lbl_IP.Text = String.Format("{0}", ip.GetIP);
lbl_IP.Text = String.Format("{0}", ip.GetIP());
lbl_Version.Text = string.Format("Ver.{0}", ip.VersionInfo());
this.ActiveControl = ID_text;
@@ -62,7 +63,7 @@ namespace WindowsFormsApp1
((Main)(this.Owner)).User_Name = ID_text.Text;
if (db_res == "")
{
MessageBox.Show("아이디 혹은 비밀번호가 정확하지않습니다.");
UTIL.MsgE("아이디 혹은 비밀번호가 정확하지않습니다.");
return;
}
@@ -75,11 +76,11 @@ namespace WindowsFormsApp1
WriteFile();
if (!CheckIP(lbl_IP.Text, result[4]))
{
MessageBox.Show("허용된 아이피가 아닙니다!");
UTIL.MsgE("허용된 아이피가 아닙니다!");
return;
}
((Main)(this.Owner)).IPText.Text = string.Format("접속 아이피 : {0}", lbl_IP.Text);
db.DB_Send_CMD_reVoid(
Helper_DB.ExcuteNonQuery(
string.Format("UPDATE `User_Data` SET `lastIP` = \"{0}\", `lastDate` = \"{2}\" WHERE `ID` = \"{1}\"",
lbl_IP.Text, ID_text.Text, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
);
@@ -88,12 +89,12 @@ namespace WindowsFormsApp1
}
else
{
MessageBox.Show("아이디 혹은 비밀번호가 정확하지않습니다.");
UTIL.MsgE("아이디 혹은 비밀번호가 정확하지않습니다.");
}
}
else
{
MessageBox.Show("아이디 혹은 비밀번호가 정확하지않습니다.");
UTIL.MsgE("아이디 혹은 비밀번호가 정확하지않습니다.");
}
}
#region CheckIP

View File

@@ -1,4 +1,4 @@
namespace WindowsFormsApp1
namespace UniMarc
{
partial class Main
{
@@ -67,6 +67,7 @@
this. = new System.Windows.Forms.ToolStripMenuItem();
this. = new System.Windows.Forms.ToolStripMenuItem();
this. = new System.Windows.Forms.ToolStripMenuItem();
this.NewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this. = new System.Windows.Forms.ToolStripMenuItem();
this. = new System.Windows.Forms.ToolStripMenuItem();
this. = new System.Windows.Forms.ToolStripMenuItem();
@@ -111,6 +112,8 @@
this.ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.btDevDb = new System.Windows.Forms.ToolStripMenuItem();
this.menu_allclose = new System.Windows.Forms.ToolStripMenuItem();
this.panel1 = new System.Windows.Forms.Panel();
this.ShortCut12 = new System.Windows.Forms.Button();
this.ShortCut11 = new System.Windows.Forms.Button();
@@ -125,7 +128,7 @@
this.ShortCut2 = new System.Windows.Forms.Button();
this.ShortCut1 = new System.Windows.Forms.Button();
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel();
this.lbCompanyName = new System.Windows.Forms.ToolStripLabel();
this.VersionText = new System.Windows.Forms.ToolStripLabel();
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.botUserLabel = new System.Windows.Forms.ToolStripLabel();
@@ -134,14 +137,19 @@
this.IPText = new System.Windows.Forms.ToolStripLabel();
this.lblStatus = new System.Windows.Forms.ToolStripLabel();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.btDevDb = new System.Windows.Forms.ToolStripMenuItem();
this.mdiTabControl = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.NewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
this.panel1.SuspendLayout();
this.toolStrip1.SuspendLayout();
this.mdiTabControl.SuspendLayout();
this.SuspendLayout();
//
// menuStrip1
//
this.menuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.ToolStripMenuItem,
this.ToolStripMenuItem,
@@ -149,10 +157,11 @@
this.ToolStripMenuItem,
this.ToolStripMenuItem,
this.ToolStripMenuItem,
this.ToolStripMenuItem});
this.ToolStripMenuItem,
this.menu_allclose});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(1259, 24);
this.menuStrip1.Size = new System.Drawing.Size(1664, 24);
this.menuStrip1.TabIndex = 0;
this.menuStrip1.Text = "menuStrip1";
//
@@ -299,14 +308,14 @@
// 송금내역조회
//
this..Name = "송금내역조회";
this..Size = new System.Drawing.Size(154, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "송금 내역 조회";
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
// 송금등록
//
this..Name = "송금등록";
this..Size = new System.Drawing.Size(154, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "송금 등록";
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
@@ -317,7 +326,7 @@
this.,
this.ToolStripMenuItem});
this..Name = "매입";
this..Size = new System.Drawing.Size(154, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "매입";
//
// 매입집계
@@ -350,7 +359,7 @@
this.,
this.});
this..Name = "매출";
this..Size = new System.Drawing.Size(154, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "매출";
//
// 매출입력
@@ -384,7 +393,7 @@
// 파트타임관리
//
this..Name = "파트타임관리";
this..Size = new System.Drawing.Size(154, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "파트타임 관리";
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
@@ -410,13 +419,13 @@
this.,
this.});
this..Name = "마크설정";
this..Size = new System.Drawing.Size(156, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "설정";
//
// 단축키설정
//
this..Name = "단축키설정";
this..Size = new System.Drawing.Size(138, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "단축키";
this..Visible = false;
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
@@ -424,14 +433,14 @@
// 매크로문구
//
this..Name = "매크로문구";
this..Size = new System.Drawing.Size(138, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "매크로 문구";
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
// 불용어
//
this..Name = "불용어";
this..Size = new System.Drawing.Size(138, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "불용어";
this..Visible = false;
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
@@ -439,7 +448,7 @@
// 작업지시서
//
this..Name = "작업지시서";
this..Size = new System.Drawing.Size(138, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "작업지시서";
this..Visible = false;
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
@@ -448,62 +457,72 @@
//
this..DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.,
this.NewToolStripMenuItem,
this.,
this.,
this.NewToolStripMenuItem,
this.,
this.1,
this.2,
this.iSBN조회});
this..Name = "마크작업";
this..Size = new System.Drawing.Size(156, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "마크 작업";
//
// 마크작성
//
this..Name = "마크작성";
this..Size = new System.Drawing.Size(154, 22);
this..Text = "마크 작성";
this..Size = new System.Drawing.Size(182, 22);
this..Text = "신규마크 작성";
this..ToolTipText = "마크 작성(2)";
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
// 신규마크작성NewToolStripMenuItem
//
this.NewToolStripMenuItem.Name = "신규마크작성NewToolStripMenuItem";
this.NewToolStripMenuItem.Size = new System.Drawing.Size(182, 22);
this.NewToolStripMenuItem.Text = "신규마크 작성(New)";
this.NewToolStripMenuItem.Click += new System.EventHandler(this.NewToolStripMenuItem_Click);
//
// 마크목록
//
this..Name = "마크목록";
this..Size = new System.Drawing.Size(154, 22);
this..Size = new System.Drawing.Size(182, 22);
this..Text = "마크 목록";
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
// 소장자료검색
//
this..Name = "소장자료검색";
this..Size = new System.Drawing.Size(154, 22);
this..Size = new System.Drawing.Size(182, 22);
this..Text = "소장자료검색";
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
// 마크정리
//
this..Name = "마크정리";
this..Size = new System.Drawing.Size(154, 22);
this..Size = new System.Drawing.Size(182, 22);
this..Text = "마크 정리";
this..Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
// 복본조사1
//
this.1.Name = "복본조사1";
this.1.Size = new System.Drawing.Size(154, 22);
this.1.Size = new System.Drawing.Size(182, 22);
this.1.Text = "복본조사";
this.1.Click += new System.EventHandler(this.ToolStripMenuItem1_Click);
//
// 복본조사2
//
this.2.Name = "복본조사2";
this.2.Size = new System.Drawing.Size(154, 22);
this.2.Size = new System.Drawing.Size(182, 22);
this.2.Text = "복본조사(New)";
this.2.Click += new System.EventHandler(this.2_Click);
//
// iSBN조회
//
this.iSBN조회.Name = "iSBN조회";
this.iSBN조회.Size = new System.Drawing.Size(154, 22);
this.iSBN조회.Size = new System.Drawing.Size(182, 22);
this.iSBN조회.Text = "ISBN 조회";
this.iSBN조회.Click += new System.EventHandler(this.iSBN조회ToolStripMenuItem_Click);
//
@@ -513,7 +532,7 @@
this.,
this.});
this.dVDCDLPToolStripMenuItem.Name = "dVDCDLPToolStripMenuItem";
this.dVDCDLPToolStripMenuItem.Size = new System.Drawing.Size(156, 22);
this.dVDCDLPToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.dVDCDLPToolStripMenuItem.Text = "DVD / CD / LP";
//
// 목록
@@ -537,7 +556,7 @@
this.,
this.});
this..Name = "반입및반출";
this..Size = new System.Drawing.Size(156, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "반입 및 반출";
//
// 마크반입
@@ -562,7 +581,7 @@
this.,
this.});
this..Name = "부가기능";
this..Size = new System.Drawing.Size(156, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "부가기능";
//
// 마크수집
@@ -603,7 +622,7 @@
this.DLS조회,
this.dLS복본조사});
this.DLS.Name = "DLS";
this.DLS.Size = new System.Drawing.Size(156, 22);
this.DLS.Size = new System.Drawing.Size(180, 22);
this.DLS.Text = "DLS";
//
// DLS조회
@@ -627,7 +646,7 @@
this.,
this.});
this..Name = "마크기타";
this..Size = new System.Drawing.Size(156, 22);
this..Size = new System.Drawing.Size(180, 22);
this..Text = "기타";
//
// 서류작성
@@ -818,6 +837,23 @@
this.ToolStripMenuItem.Text = "일괄처리 관리";
this.ToolStripMenuItem.Click += new System.EventHandler(this.ToolStripMenuItem_Click);
//
// btDevDb
//
this.btDevDb.ForeColor = System.Drawing.Color.Blue;
this.btDevDb.Name = "btDevDb";
this.btDevDb.Size = new System.Drawing.Size(202, 22);
this.btDevDb.Text = "데이터베이스편집(개발)";
this.btDevDb.Visible = false;
this.btDevDb.Click += new System.EventHandler(this.btDevDb_Click);
//
// menu_allclose
//
this.menu_allclose.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.menu_allclose.Name = "menu_allclose";
this.menu_allclose.Size = new System.Drawing.Size(87, 20);
this.menu_allclose.Text = "전체 창 닫기";
this.menu_allclose.Click += new System.EventHandler(this.menu_allclose_Click);
//
// panel1
//
this.panel1.BackColor = System.Drawing.SystemColors.ControlDark;
@@ -837,7 +873,7 @@
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
this.panel1.Location = new System.Drawing.Point(0, 24);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(1259, 64);
this.panel1.Size = new System.Drawing.Size(1664, 64);
this.panel1.TabIndex = 2;
//
// ShortCut12
@@ -1013,8 +1049,9 @@
//
this.toolStrip1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
this.toolStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripLabel2,
this.lbCompanyName,
this.VersionText,
this.toolStripSeparator1,
this.botUserLabel,
@@ -1022,17 +1059,17 @@
this.toolStripSeparator3,
this.IPText,
this.lblStatus});
this.toolStrip1.Location = new System.Drawing.Point(0, 681);
this.toolStrip1.Location = new System.Drawing.Point(0, 801);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(1259, 25);
this.toolStrip1.Size = new System.Drawing.Size(1664, 25);
this.toolStrip1.TabIndex = 4;
this.toolStrip1.Text = "toolStrip1";
//
// toolStripLabel2
// lbCompanyName
//
this.toolStripLabel2.Name = "toolStripLabel2";
this.toolStripLabel2.Size = new System.Drawing.Size(43, 22);
this.toolStripLabel2.Text = "회사명";
this.lbCompanyName.Name = "lbCompanyName";
this.lbCompanyName.Size = new System.Drawing.Size(43, 22);
this.lbCompanyName.Text = "회사명";
//
// VersionText
//
@@ -1076,28 +1113,58 @@
this.lblStatus.Size = new System.Drawing.Size(27, 22);
this.lblStatus.Text = "WD";
//
// btDevDb
// mdiTabControl
//
this.btDevDb.ForeColor = System.Drawing.Color.Blue;
this.btDevDb.Name = "btDevDb";
this.btDevDb.Size = new System.Drawing.Size(202, 22);
this.btDevDb.Text = "데이터베이스편집(개발)";
this.btDevDb.Visible = false;
this.btDevDb.Click += new System.EventHandler(this.btDevDb_Click);
this.mdiTabControl.Controls.Add(this.tabPage1);
this.mdiTabControl.Controls.Add(this.tabPage2);
this.mdiTabControl.Dock = System.Windows.Forms.DockStyle.Fill;
this.mdiTabControl.Location = new System.Drawing.Point(0, 88);
this.mdiTabControl.Name = "mdiTabControl";
this.mdiTabControl.SelectedIndex = 0;
this.mdiTabControl.Size = new System.Drawing.Size(1664, 713);
this.mdiTabControl.TabIndex = 5;
//
// tabPage1
//
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(1656, 687);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "tabPage1";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tabPage2
//
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(1656, 687);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "tabPage2";
this.tabPage2.UseVisualStyleBackColor = true;
//
// 소장자료검색NewToolStripMenuItem
//
this.NewToolStripMenuItem.Name = "소장자료검색NewToolStripMenuItem";
this.NewToolStripMenuItem.Size = new System.Drawing.Size(182, 22);
this.NewToolStripMenuItem.Text = "소장자료검색(New)";
this.NewToolStripMenuItem.Click += new System.EventHandler(this.NewToolStripMenuItem_Click);
//
// Main
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1259, 706);
this.ClientSize = new System.Drawing.Size(1664, 826);
this.Controls.Add(this.mdiTabControl);
this.Controls.Add(this.toolStrip1);
this.Controls.Add(this.panel1);
this.Controls.Add(this.menuStrip1);
this.HelpButton = true;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.IsMdiContainer = true;
this.MainMenuStrip = this.menuStrip1;
this.Name = "Main";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "메인";
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
this.Load += new System.EventHandler(this.Main_Load);
@@ -1106,6 +1173,7 @@
this.panel1.ResumeLayout(false);
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.mdiTabControl.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@@ -1189,7 +1257,7 @@
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.ToolStripMenuItem ;
private System.Windows.Forms.ToolStripMenuItem ;
public System.Windows.Forms.ToolStripLabel toolStripLabel2;
public System.Windows.Forms.ToolStripLabel lbCompanyName;
private System.Windows.Forms.ToolStripMenuItem ;
public System.Windows.Forms.ToolStripLabel botUserLabel;
private System.Windows.Forms.ToolStripMenuItem 1;
@@ -1219,5 +1287,11 @@
private System.Windows.Forms.ToolStripLabel lblStatus;
private System.Windows.Forms.ToolStripMenuItem 2;
private System.Windows.Forms.ToolStripMenuItem btDevDb;
private System.Windows.Forms.TabControl mdiTabControl;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.ToolStripMenuItem menu_allclose;
private System.Windows.Forms.ToolStripMenuItem NewToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem NewToolStripMenuItem;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
namespace UniMarc
{
public class BookGridItem
{
public string header { get; set; }
public string num { get; set; }
public string BookName { get; set; }
public string Author { get; set; }
public string BookComp { get; set; }
public string Count { get; set; } = "1";
public string Price { get; set; } = "0";
public string Total { get; set; } = "0";
public string ISBN { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UniMarc
{
public class FillBlankItem
{
public int Idx { get; set; }
public string Isbn { get; set; }
public string BookName { get; set; }
public string Author { get; set; }
public string Publisher { get; set; }
public int Price { get; set; }
public string BookMarc { get; set; } = ""; // Hidden column likely
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UniMarc
{
public class IsbnGridItem
{
public string idx { get; set; }
public string num { get; set; }
public string isbn { get; set; }
public string book_name { get; set; }
public string search_book_name { get; set; }
public string author { get; set; }
public string search_author { get; set; }
public string book_comp { get; set; }
public string search_book_comp { get; set; }
public string count { get; set; }
public string unit { get; set; }
public string total { get; set; }
public string condition { get; set; }
public string price { get; set; }
public string etc { get; set; }
public string pubDate { get; set; }
public string persent { get; set; }
public string category { get; set; }
public string sold_out { get; set; }
public string image { get; set; }
public string api_data { get; set; }
public string search_description { get; set; }
public string search_url { get; set; }
}
}

View File

@@ -0,0 +1,26 @@
//using Microsoft.Office.Interop.Excel;
namespace UniMarc
{
public class MacEditorParameter
{
public string ISBN13 { get; set; }
public string URL { get; set; }
public int MarcIdx { get; set; }
public string User { get; set; }
public string SaveDate { get; set; }
public int ListIdx { get; set; }
public string BookName { get; set; }
public string Author { get; set; }
public string Publisher { get; set; }
public int Price { get; set; }
public string text008 { get; set; }
public string tag056 { get; set; }
public bool NewMake { get; set; }
public string OriginalMarc { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
namespace UniMarc
{
public class MacListItem
{
/// <summary>
/// List Index
/// </summary>
public string idx { get; set; }
public string start_date { get; set; }
public string end_date { get; set; }
public string customer_name { get; set; }
public string list_name { get; set; }
public string work_name { get; set; }
public string count { get; set; }
public string stock { get; set; }
public string unstock { get; set; }
public string state { get; set; }
public string etc { get; set; }
public string charge { get; set; }
public string check { get; set; }
public string customer { get; set; } // For hidden customer index
}
}

View File

@@ -0,0 +1,40 @@
namespace UniMarc
{
public partial class Helper_DB
{
public class MarcBasicInfo
{
public string ISBN { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Publisher { get; set; }
public string Price { get; set; }
public string Tag056 { get; set; }
public string Tag008 { get; set; }
public string kwoncha { get; set; }
public string kwoncha_title { get; set; }
public string pancha { get; set; }
/// <summary>
/// 총서명(440a)
/// </summary>
public string fulltitle { get; set; }
/// <summary>
/// 총서번호(440v)
/// </summary>
public string fulltitleno { get; set; }
public bool Success { get; set; }
public string Message { get; set; }
public MarcBasicInfo()
{
Success = false;
Message = string.Empty;
}
}
}
}

View File

@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UniMarc
{
public enum MarcRecordStatus
{
None, // No record in DB (Red)
OtherCompany, // Found but not ours (Orange)
MyCompany, // Found and ours (Black/Blue etc.)
NewFetched // Temporary status after external search (Blue)
}
public class MarcBookItem
{
public int ListIdx { get; set; }
public string ISBN13 { get; set; }
public string Num { get; set; }
public string BookName { get; set; }
public string Author { get; set; }
public string BookComp { get; set; }
public string Count { get; set; }
/// <summary>
/// ´Ü°¡(Á¤°¡´Â price¿¡ ÀÖ´Ù)
/// </summary>
public int Pay { get; set; }
public string Url { get; set; }
public int MarcIdx { get; set; }
public string DbMarc { get; set; }
private MarcRecordStatus _status = MarcRecordStatus.None;
public MarcRecordStatus Status
{
get => _status;
set { _status = value; ApplySyncColor(); }
}
private string _grade = "";
public string Grade
{
get => _grade;
set { _grade = value; ApplySyncColor(); }
}
public string ColCheck { get; set; } = "V";
public string User { get; set; }
public string SaveDate { get; set; }
public string search_book_name { get; set; }
public string search_author { get; set; }
public string search_book_comp { get; set; }
public string search_description { get; set; }
public string search_url { get; set; }
public string category { get; set; }
public System.Drawing.Color ForeColor { get; set; } = System.Drawing.Color.Black;
public System.Drawing.Color BackColor { get; set; } = System.Drawing.Color.White;
private void ApplySyncColor()
{
if (Status == MarcRecordStatus.None)
{
ForeColor = System.Drawing.Color.Red;
}
else if (Status == MarcRecordStatus.OtherCompany)
{
ForeColor = System.Drawing.Color.Orange;
}
else if (Status == MarcRecordStatus.NewFetched)
{
ForeColor = System.Drawing.Color.Blue;
}
else if (Status == MarcRecordStatus.MyCompany)
{
switch (Grade)
{
case "0": // A
ForeColor = System.Drawing.Color.Blue;
break;
case "1": // B
ForeColor = System.Drawing.Color.Black;
break;
case "2": // C
ForeColor = System.Drawing.Color.Gray;
break;
//case "3": // D
// ForeColor = System.Drawing.Color.DarkViolet;
// break;
default:
ForeColor = System.Drawing.Color.DarkViolet;
break;
}
}
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
namespace UniMarc
{
public class MarcCopyItem
{
public int idx { get; set; }
public string compidx { get; set; }
public string ISBN { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Comp { get; set; }
public string User { get; set; }
public string Date { get; set; }
public string Grade { get; set; }
public string Tag008 { get; set; }
public string Marc { get; set; } // Calculated real MARC
// Raw MARC segments from DB
public string marc_db { get; set; }
public string marc_chk { get; set; }
public string marc1 { get; set; }
public string marc_chk1 { get; set; }
public string marc2 { get; set; }
public string marc_chk2 { get; set; }
public string kwoncha { get; set; }
public string kwoncha_title { get; set; }
public string KwonchaFull { get; set; } // Combined kwoncha + kwoncha_title
public string TotalTitleFull { get; set; } // Combined 총서명 + 총서번호
public string pancha { get; set; }
public string publishdate { get; set; }
public string remark1 { get; set; }
public string remark2 { get; set; }
public string DisplayGrade
{
get
{
switch (Grade)
{
case "0": return "A";
case "1": return "B";
case "2": return "C";
case "3": return "D";
default: return Grade;
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UniMarc
{
public class MarcPlanItem
{
public int Idx { get; set; }
public string Num { get; set; }
public string RegNum { get; set; }
public string ClassCode { get; set; }
public string AuthorCode { get; set; }
public string Volume { get; set; }
public string Copy { get; set; }
public string Prefix { get; set; }
public string Gu { get; set; }
public string Isbn { get; set; }
public string BookName { get; set; }
public string SBookName1 { get; set; }
public string SBookNum1 { get; set; }
public string SBookName2 { get; set; }
public string SBookNum2 { get; set; }
public string Author { get; set; }
public string BookComp { get; set; }
public int Price { get; set; }
public int Midx { get; set; }
public string Marc { get; set; }
public string SearchTag2 { get; set; }
public string ColCheck { get; set; } = "F";
// Properties used in SelectList specific loading (if needed, or mapped to above)
public string ListName { get; set; }
public string Date { get; set; }
public string User { get; set; }
public string etc1 { get; set; }
public string etc2 { get; set; }
public int grade { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using System;
namespace UniMarc
{
public class SearchInforItem
{
public string idx { get; set; }
public string grade { get; set; }
public string User { get; set; }
public string date { get; set; }
public string ISBN { get; set; }
public string book_name { get; set; }
public string sBookName { get; set; }
public string author { get; set; }
public string book_comp { get; set; }
public string price { get; set; }
public string pub_date { get; set; }
public string Marc { get; set; }
public string marc2 { get; set; }
public string etc1 { get; set; }
public string etc2 { get; set; }
}
}

View File

@@ -1,18 +1,26 @@
using System;
using AR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI.WebControls.WebParts;
using System.Windows.Forms;
using UniMarc.Properties;
namespace UniMarc
{
public class LoginInfo
{
public string UserName { get; set; }
public string CompanyIdx { get; set; }
public string CompanyName { get; set; }
}
public static class PUB
{
public static arUtil.Log log;
public static UserSetting setting;
public static LoginInfo user;
public static void Init()
{
#region "Log setting"
@@ -22,10 +30,42 @@ namespace UniMarc
PUB.log.SubDirectory = logsubdir;
PUB.log.FileNameFormat = "{yyMMdd}";
#endregion
setting = new UserSetting();
setting.Load();
user = new LoginInfo();
}
/// <summary>
/// 빈 MARC String 을 생성한다
/// </summary>
/// <param name="ISBN13"></param>
/// <param name="BookName"></param>
/// <param name="Author"></param>
/// <param name="Publisher"></param>
/// <param name="Price"></param>
/// <returns></returns>
public static string MakeEmptyMarc(string ISBN13, string BookName, string Author, string Publisher, int Price)
{
string yyMMdd = DateTime.Now.ToString("yyMMdd");
string yyyy = DateTime.Now.ToString("yyyy");
string Empty_008 = yyMMdd + "s" + yyyy + " 000 kor ▲";
var tag_008 = Empty_008.Replace("▲", "");
string Empty_text = string.Format(
"020\t \t▼a{1}▼c\\{5}▲\n" +
"056\t \t▼a▼25▲\n" +
"100\t \t▼a{3}▲\n" +
"245\t \t▼a{2}▼d{3}▲\n" +
"260\t \t▼b{4}▲\n" +
"300\t \t▼a▼c▲\n" +
"653\t \t▼a▲\n" +
"700\t \t▼a▲\n" +
"950\t \t▼b\\{5}▲\n",
Empty_008, ISBN13, BookName, Author, Publisher, Price);
return Empty_text;
}
}
}

View File

@@ -1,10 +1,11 @@
using System;
using AR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
namespace UniMarc
{
static class Program
{
@@ -16,6 +17,12 @@ namespace WindowsFormsApp1
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//var parserF = new UniMarc.MarcParser();
//var fullMarc = System.IO.File.ReadAllText(".\\Helper\\sample_fullmarc.txt");
//var rlt = parserF.ParseFullMarc(fullMarc);
//if(rlt.success==false)
//AR.UTIL.MsgE("unitmarc");
try
{
@@ -24,20 +31,15 @@ namespace WindowsFormsApp1
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
UTIL.MsgE(ex.Message);
}
Application.Run(new Main());
}
static void DB_InitSetting()
{
UniMarc.Properties.Settings.Default.IP = ConvertIP(UniMarc.Properties.Settings.Default.IP);
UniMarc.Properties.Settings.Default.IP = ConvertIP(UniMarc.Properties.Settings.Default.IP);
UniMarc.Properties.Settings.Default.Port = Convert2to10(UniMarc.Properties.Settings.Default.Port);
UniMarc.Properties.Settings.Default.Uid = ConvertAscii(UniMarc.Properties.Settings.Default.Uid);
UniMarc.Properties.Settings.Default.pwd = ConvertAscii(UniMarc.Properties.Settings.Default.pwd);

View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2025.08.14.1630")]
[assembly: AssemblyFileVersion("2025.08.14.1630")]
[assembly: AssemblyVersion("2026.03.26.2350")]
[assembly: AssemblyFileVersion("2026.03.26.2350")]

View File

@@ -12,7 +12,7 @@ namespace UniMarc.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -23,30 +23,6 @@ namespace UniMarc.Properties {
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string compidx {
get {
return ((string)(this["compidx"]));
}
set {
this["compidx"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string User {
get {
return ((string)(this["User"]));
}
set {
this["User"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("1.11010111.11111010.10000010")]

View File

@@ -2,12 +2,6 @@
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="UniMarc.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="compidx" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="User" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="IP" Type="System.String" Scope="User">
<Value Profile="(Default)">1.11010111.11111010.10000010</Value>
</Setting>

View File

@@ -17,7 +17,6 @@ using System.Threading.Tasks;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using UniMarc.SearchModel;
using UniMarc.;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;
@@ -397,8 +396,10 @@ namespace BokBonCheck
// 페이지 변경을 감지하는 메서드
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
// SearchAsync에서 PageSource 가져오기
var htmlContent = _driver.PageSource;
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -423,128 +424,40 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
if (driver.Url.EndsWith("DetailSearchResult") == false)
{
errmessage = "결과페이지가아님";
return -1;
}
resulthtml = string.Empty;
try
{
// 1. 검색결과가 없는 경우 확인
try
// 검색 결과가 없메시지 확인
var noResultPatterns = new[]
{
var noResultElements = driver.FindElements(By.XPath("//*[contains(text(), '검색결과가 없습니다') or contains(text(), '검색된 자료가 없습니다')]"));
if (noResultElements.Count > 0)
@"검색결과가 없습니다",
@"검색된 자료가 없습니다",
@"자료가 없습니다",
@"총 0 건",
@"총 0건"
};
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
errmessage = "검색결과없음";
return 0;
}
}
catch
{
// 검색결과가 있는 경우로 진행
}
RetryPoint:
bool retry = false;
// 2. 안산시 도서관 특화: span.count.gothic em 요소에서 직접 추출
try
{
var countElement = driver.FindElement(By.CssSelector("span.count.gothic em"));
if (countElement != null)
{
// Text 대신 InnerHtml이나 GetAttribute 사용해보기
var countText = countElement.Text.Trim();
var innerHTML = countElement.GetAttribute("innerHTML");
var outerHTML = countElement.GetAttribute("outerHTML");
Console.WriteLine($"count 요소 .Text: '{countText}'");
Console.WriteLine($"count 요소 innerHTML: '{innerHTML}'");
Console.WriteLine($"count 요소 outerHTML: '{outerHTML}'");
// innerHTML이나 outerHTML에서 텍스트 추출 시도
string textToUse = !string.IsNullOrEmpty(countText) ? countText : innerHTML;
if (string.IsNullOrEmpty(textToUse))
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
textToUse = outerHTML;
}
Console.WriteLine($"추출할 텍스트: '{textToUse}'");
// "총 0 건 " 형태에서 숫자 추출
var match = Regex.Match(textToUse, @"총\s*(\d+)\s*건", RegexOptions.IgnoreCase);
if (match.Success && int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
Console.WriteLine("검색 결과: 0건");
return 0;
}
errmessage = $"검색성공({count}권)";
Console.WriteLine($"검색 결과: {count}건");
return count;
resulthtml = ExtractResultContext(htmlContent, match);
}
else
{
Console.WriteLine($"정규식 매칭 실패: '{textToUse}'");
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
return 0;
}
}
catch (Exception ex1)
{
Console.WriteLine($"span.count.gothic em 요소 추출 실패: {ex1.Message}");
}
// 3. span.count 전체에서 추출 시도
try
{
var countSpan = driver.FindElement(By.CssSelector("span.count"));
if (countSpan != null)
{
var fullText = countSpan.Text.Trim();
Console.WriteLine($"count span 전체 텍스트: '{fullText}'");
var match = Regex.Match(fullText, @"총\s*(\d+)\s*건", RegexOptions.IgnoreCase);
if (match.Success && int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({count}권)";
return count;
}
}
}
catch (Exception ex2)
{
Console.WriteLine($"span.count 요소 추출 실패: {ex2.Message}");
}
// 3. 페이지 소스에서 정규식으로 추출 시도
var pageSource = driver.PageSource;
// 검색 결과가 없다는 메시지 확인
if (pageSource.Contains("검색결과가 없습니다") ||
pageSource.Contains("검색된 자료가 없습니다") ||
pageSource.Contains("자료가 없습니다") ||
pageSource.Contains("총 0 건") ||
pageSource.Contains("총 0건"))
{
errmessage = "검색결과없음";
return 0;
}
// HTML에서 다양한 패턴 찾기 (안산시 도서관 특화)
var htmlPatterns = new[]
@@ -560,11 +473,14 @@ namespace BokBonCheck
foreach (var pattern in htmlPatterns)
{
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
resulthtml = ExtractResultContext(htmlContent, match);
if (count == 0)
{
errmessage = "검색결과없음";
@@ -576,28 +492,81 @@ namespace BokBonCheck
}
}
if (retry == false)
{
Console.WriteLine( "결과를 찾을 수 없어 재시도");
retry = true;
Task.Delay(1000);
goto RetryPoint;
}
else
{
errmessage = "결과수량을찾을수없음";
return -1;
}
errmessage = "결과수량을찾을수없음";
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return -1;
}
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 페이지 변경을 감지하는 메서드
public async Task WaitForPageChange(WebDriverWait wait)
{

View File

@@ -13,6 +13,8 @@ namespace BokBonCheck
public DateTime SearchTime { get; set; }
public string ErrorMessage { get; set; }
public bool IsSuccess { get; set; }
public string Resulthtml { get; set; }
}
public class BookSearchService

View File

@@ -12,7 +12,6 @@ using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using UniMarc.SearchModel;
using UniMarc.;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;
@@ -244,8 +243,9 @@ namespace BokBonCheck
// 페이지 변경을 감지하는 메서드
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var htmlContent = _driver.PageSource;
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -270,73 +270,39 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
// 1. totalCount 요소에서 직접 추출 시도
try
// 검색 결과가 없다는 메시지 확인
var noResultPatterns = new[]
{
var totalCountElement = driver.FindElement(By.CssSelector("p.totalCount"));
if (totalCountElement != null)
{
// strong 태그에서 직접 숫자 추출 시도
try
{
var strongElement = totalCountElement.FindElement(By.TagName("strong"));
if (strongElement != null)
{
var countText = strongElement.Text.Trim();
if (int.TryParse(countText, out int strongCount))
{
if (strongCount == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({strongCount}권)";
return strongCount;
}
}
}
catch { }
@"검색결과가 없습니다",
@"검색된 자료가 없습니다",
@"자료가 없습니다",
@"전체 0 건"
};
// 전체 텍스트에서 정규식으로 추출
var totalCountText = totalCountElement.Text;
var match = Regex.Match(totalCountText, @"전체\s*(\d+)\s*건", RegexOptions.IgnoreCase);
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
errmessage = "검색결과없음";
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({count}권)";
return count;
}
resulthtml = ExtractResultContext(htmlContent, match);
}
else
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
return 0;
}
}
catch (Exception ex)
{
Console.WriteLine($"totalCount 요소 검색 중 오류: {ex.Message}");
}
// 2. 페이지 소스에서 정규식으로 추출 시도
var pageSource = driver.PageSource;
// 검색 결과가 없다는 메시지 확인
if (pageSource.Contains("검색결과가 없습니다") ||
pageSource.Contains("검색된 자료가 없습니다") ||
pageSource.Contains("자료가 없습니다") ||
pageSource.Contains("전체 0 건"))
{
errmessage = "검색결과없음";
return 0;
}
// HTML에서 다양한 패턴 찾기
var htmlPatterns = new[]
@@ -350,11 +316,14 @@ namespace BokBonCheck
foreach (var pattern in htmlPatterns)
{
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
resulthtml = ExtractResultContext(htmlContent, match);
if (count == 0)
{
errmessage = "검색결과없음";
@@ -367,16 +336,80 @@ namespace BokBonCheck
}
errmessage = "결과수량을찾을수없음";
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return -1;
}
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 페이지 변경을 감지하는 메서드
public async Task WaitForPageChange(WebDriverWait wait)
{

View File

@@ -12,7 +12,6 @@ using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using UniMarc.SearchModel;
using UniMarc.;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;

View File

@@ -12,7 +12,6 @@ using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using UniMarc.SearchModel;
using UniMarc.;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;

View File

@@ -69,7 +69,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -84,7 +84,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -112,19 +113,21 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage)
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
// 1. 검색 결과가 없는 경우 확인
if (htmlContent.Contains("검색결과가 없습니다") ||
htmlContent.Contains("검색된 자료가 없습니다") ||
htmlContent.Contains("자가 없습니다") ||
htmlContent.Contains("자가 없습니다") ||
htmlContent.Contains("<strong>0</strong> Results:"))
{
errorMessage = "검색결과없음";
resulthtml = "검색결과없음";
return 0;
}
@@ -147,8 +150,11 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
Console.WriteLine($"조선이공대학교도서관 검색 결과: {count}건");
return count;
@@ -173,22 +179,27 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
Console.WriteLine($"조선이공대학교도서관 검색 결과: {count}건");
return count;
}
}
}
// 패턴을 찾지 못한 경우
errorMessage = "검색결과 패턴을 찾을 수 없음";
resulthtml = "검색결과 패턴을 찾을 수 없음";
Console.WriteLine("조선이공대학교도서관 검색결과 패턴을 찾을 수 없음");
return -1;
}
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "결과 분석 오류: " + ex.Message;
return -1;
}
}
@@ -197,5 +208,67 @@ namespace BokBonCheck
{
throw new NotImplementedException();
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -69,7 +69,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -84,7 +84,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -112,9 +113,10 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage)
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
@@ -125,6 +127,7 @@ namespace BokBonCheck
htmlContent.Contains("총 <strong>0</strong>건"))
{
errorMessage = "검색결과없음";
resulthtml = "검색결과없음";
return 0;
}
@@ -147,8 +150,11 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
Console.WriteLine($"조선대학교중앙도서관 검색 결과: {count}건");
return count;
@@ -173,22 +179,28 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
Console.WriteLine($"조선대학교중앙도서관 검색 결과: {count}건");
return count;
}
}
}
// 패턴을 찾지 못한 경우
errorMessage = "검색결과 패턴을 찾을 수 없음";
resulthtml = "검색결과 패턴을 찾을 수 없음";
Console.WriteLine("조선대학교중앙도서관 검색결과 패턴을 찾을 수 없음");
return -1;
}
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "결과 분석 오류: " + ex.Message;
return -1;
}
}
@@ -197,5 +209,67 @@ namespace BokBonCheck
{
throw new NotImplementedException();
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -9,10 +9,10 @@ using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using UniMarc.;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
using AR;
namespace BokBonCheck
{
@@ -169,6 +169,11 @@ namespace BokBonCheck
if (_driver.Url.EndsWith("/bookMain") == false)
{
retrycnt += 1;
if (retrycnt > 3)
{
UTIL.MsgE("3회 연속 로그인 시도로 인해 자동 로그인을 중단합니다\n사용자가 직접 로그인을 하세요");
break;
}
Console.WriteLine($"도서검색화면으로 이동({retrycnt})");
_driver.Navigate().GoToUrl(this.SiteUrl);
wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
@@ -190,6 +195,8 @@ namespace BokBonCheck
this.SCHOOL = schoolname;
this.STYPE = searchtype;
}
string BookMainURL = string.Empty;
public async Task<BookSearchResult> SearchAsync(string searchTerm)
{
var result = new BookSearchResult
@@ -247,6 +254,19 @@ namespace BokBonCheck
}
}
if (string.IsNullOrEmpty(BookMainURL))
{
BookMainURL = _driver.Url;
}
else
{
//확실하게 하기위해 메인페이지로 다시 이동한다.
_driver.Navigate().GoToUrl(this.SiteUrl);
new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
await Task.Delay(500);
}
// 페이지 로딩 대기
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
@@ -378,23 +398,24 @@ namespace BokBonCheck
{
SafeClick(buttomelm);
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
Thread.Sleep(200);
Thread.Sleep(500);
}
}
catch
{
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
errmessage = "검색결과없음";
errmessage = "검색결과없음";
return 0;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
@@ -422,7 +443,7 @@ namespace BokBonCheck
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

View File

@@ -0,0 +1,366 @@
using System;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using System.Text.RegularExpressions;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
using AR;
namespace BokBonCheck
{
public class GochangLibSearcher : ILibrarySearcher
{
public string AreaCode { get; set; } = string.Empty;
public string SiteName { get; protected set; }
public string SiteUrl => "https://libsearch.gochang.go.kr:8443/book/bookAdvancedSearch";
public bool HttpApiMode { get; set; } = false;
public int No { get; set; }
private ChromiumDriver _driver;
public GochangLibSearcher(int no, string areaCode, string areaName)
{
this.No = no;
this.AreaCode = areaCode;
this.SiteName = $"고창군립({areaName})";
}
public void StopDriver()
{
if (_driver != null)
{
_driver.Quit();
_driver.Dispose();
_driver = null;
}
}
public async Task StartDriver(bool showdriver = false)
{
if (_driver == null)
{
try
{
if (SeleniumHelper.IsReady == false) await SeleniumHelper.Download();
_driver = await SeleniumHelper.CreateDriver(ShowBrowser: showdriver);
Console.WriteLine("GochangLibSearcher Driver 초기화 완료");
}
catch (Exception ex)
{
Console.WriteLine($"GochangLibSearcher Driver 초기화 실패: {ex.Message}");
throw new InvalidOperationException($"GochangLibSearcher Driver 초기화에 실패했습니다: {ex.Message}", ex);
}
}
}
virtual protected bool SelectLibrary(WebDriverWait wait)
{
try
{
if (!string.IsNullOrEmpty(AreaCode))
{
var libSelect = wait.Until(d => d.FindElement(By.Id("MANAGE_CODE")));
var selectElement = new SelectElement(libSelect);
selectElement.SelectByValue(AreaCode);
Thread.Sleep(300);
Console.WriteLine($"{AreaCode} 도서관으로 선택됨");
}
else
{
Console.WriteLine("전체 도서관으로 검색");
}
return true;
}
catch (Exception ex)
{
Console.WriteLine($"도서관 선택 실패: {ex.Message}");
return false;
}
}
public async Task<BookSearchResult> SearchAsync(string searchTerm)
{
var result = new BookSearchResult
{
SiteName = SiteName,
SearchTerm = searchTerm,
SearchTime = DateTime.Now
};
try
{
if (_driver == null)
{
await StartDriver();
}
var cururl = _driver.Url;
if (cururl.Equals(SiteUrl) == false)
_driver.Navigate().GoToUrl(SiteUrl);
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
if (SelectLibrary(wait) == false)
{
result.ErrorMessage = "도서관선택실패";
result.BookCount = -1;
result.IsSuccess = false;
return result;
}
try
{
var titleInput = wait.Until(d => d.FindElement(By.Id("title")));
titleInput.Clear();
titleInput.SendKeys(searchTerm);
}
catch (Exception ex)
{
result.ErrorMessage = $"검색어입력실패({ex.Message})";
result.BookCount = -1;
result.IsSuccess = false;
return result;
}
try
{
var jsExecutor = (IJavaScriptExecutor)_driver;
jsExecutor.ExecuteScript("fn_openBookAdvancedSearch();");
}
catch (Exception ex)
{
result.ErrorMessage = $"검색실행실패({ex.Message})";
result.BookCount = -1;
result.IsSuccess = false;
return result;
}
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// SearchAsync에서 PageSource 가져오기
var htmlContent = _driver.PageSource;
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
result.IsSuccess = false;
result.ErrorMessage = ermsg;
}
else
{
result.BookCount = resultCount;
result.IsSuccess = true;
result.ErrorMessage = ermsg;
}
}
catch (Exception ex)
{
result.IsSuccess = false;
result.ErrorMessage = ex.Message;
result.BookCount = 0;
}
return result;
}
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
var noResultPatterns = new[]
{
@"검색된 도서가 없습니다",
@"검색결과가 없습니다",
@"검색된 자료가 없습니다"
};
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
errmessage = "검색결과없음";
// 검색결과 없음 메시지를 포함한 HTML 조각 추출
var index = htmlContent.IndexOf(pattern);
if (index >= 0)
{
var startIndex = Math.Max(0, index - 100);
var endIndex = Math.Min(htmlContent.Length, index + pattern.Length + 100);
resulthtml = htmlContent.Substring(startIndex, endIndex - startIndex);
// 상위 태그 찾기 시도
try
{
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
resulthtml = ExtractResultContext(htmlContent, match);
}
}
catch
{
// 실패시 기본 추출 결과 사용
}
}
else
{
resulthtml = pattern;
}
return 0;
}
}
var htmlPatterns = new[]
{
@"<span[^>]*class=""bluecolor""[^>]*>총\s*(\d+)건</span>",
@"총\s*<span[^>]*class=""bluecolor""[^>]*>(\d+)</span>건",
@"총\s*(\d+)건"
};
foreach (var pattern in htmlPatterns)
{
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
resulthtml = ExtractResultContext(htmlContent, match);
if (count == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({count}권)";
return count;
}
}
}
errmessage = "결과수량을찾을수없음";
resulthtml = "결과수량을찾을수없음";
return -1;
}
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "ExtractBookCount 오류: " + ex.Message;
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
public async Task WaitForPageChange(WebDriverWait wait)
{
try
{
await Task.Delay(500);
wait.Until(d =>
{
var readyState = ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState");
return readyState.Equals("complete");
});
wait.Until(d =>
{
try
{
var pageSource = d.PageSource;
return pageSource.Contains("검색결과입니다") ||
pageSource.Contains("총") ||
pageSource.Contains("건") ||
pageSource.Contains("검색된 도서가 없습니다");
}
catch
{
return false;
}
});
}
catch (Exception ex)
{
await Task.Delay(3000);
Console.WriteLine($"페이지 변경 감지 실패: {ex.Message}");
}
}
}
}

View File

@@ -9,7 +9,6 @@ using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using UniMarc.;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
@@ -218,8 +217,9 @@ namespace BokBonCheck
// 페이지 변경을 감지하는 메서드
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var htmlContent = _driver.PageSource;
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -244,67 +244,21 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
// 1. 먼저 totalCount 요소에서 직접 추출 시도
try
{
var totalCountElement = driver.FindElement(By.CssSelector("p.totalCount"));
if (totalCountElement != null)
{
var totalCountText = totalCountElement.Text; // 예: "전체 1 건"
var match = Regex.Match(totalCountText, @"전체\s+(\d+)\s+건", RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({count}권)";
return count;
}
}
// strong 태그에서 직접 숫자 추출 시도
try
{
var strongElement = totalCountElement.FindElement(By.TagName("strong"));
if (strongElement != null && int.TryParse(strongElement.Text, out int strongCount))
{
if(strongCount == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({strongCount}권)";
return strongCount;
}
}
catch { }
}
}
catch (Exception ex)
{
Console.WriteLine($"totalCount 요소 검색 중 오류: {ex.Message}");
}
// 2. 페이지 소스에서 정규식으로 추출 시도
var pageSource = driver.PageSource;
// 검색 결과가 없다는 메시지 확인
if (pageSource.Contains("검색결과가 없습니다") ||
pageSource.Contains("검색된 자료가 없습니다") ||
pageSource.Contains("자료가 없습니다") ||
pageSource.Contains("전체 0 건"))
if (htmlContent.Contains("검색결과가 없습니다") ||
htmlContent.Contains("검색된 자료가 없습니다") ||
htmlContent.Contains("자료가 없습니다") ||
htmlContent.Contains("전체 0 건"))
{
errmessage = "검색결과없음";
resulthtml = "검색결과가 없습니다";
return 0;
}
@@ -319,11 +273,14 @@ namespace BokBonCheck
foreach (var pattern in htmlPatterns)
{
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
resulthtml = ExtractResultContext(htmlContent, match);
if (count == 0)
{
errmessage = "검색결과없음";
@@ -335,49 +292,81 @@ namespace BokBonCheck
}
}
// 3. 결과 테이블이나 리스트가 있는지 확인
try
{
var resultElements = driver.FindElements(By.CssSelector(".bookList, .searchResult, .result-list, table tbody tr"));
if (resultElements.Count > 0)
{
// 테이블 헤더나 빈 행을 제외한 실제 결과 개수 계산
var actualCount = 0;
foreach (var element in resultElements)
{
var text = element.Text?.Trim();
if (!string.IsNullOrEmpty(text) &&
!text.Contains("도서명") &&
!text.Contains("저자") &&
!text.Contains("출판사"))
{
actualCount++;
}
}
if (actualCount > 0)
{
errmessage = $"검색성공({actualCount}권)";
return actualCount;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"결과 요소 검색 중 오류: {ex.Message}");
}
errmessage = "결과수량을찾을수없음";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 페이지 변경을 감지하는 메서드
public async Task WaitForPageChange(WebDriverWait wait)
{

View File

@@ -9,7 +9,6 @@ using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using UniMarc.;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
@@ -155,8 +154,9 @@ namespace BokBonCheck
// 페이지 변경을 감지하는 메서드
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var htmlContent = _driver.PageSource;
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -181,87 +181,38 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
// 1. 검색결과가 없는 경우 확인
try
// 검색 결과가 없메시지 확인
var noResultPatterns = new[]
{
var noResultElement = driver.FindElement(By.XPath("//p[contains(text(), '조회된 도서가 없습니다')]"));
if (noResultElement != null)
@"조회된 도서가 없습니다",
@"검색결과가 없습니다",
@"검색된 자료가 없습니다"
};
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
errmessage = "검색결과없음";
return 0;
}
}
catch
{
// 검색결과가 있는 경우로 진행
}
// 2. srch_info div에서 직접 추출 시도
try
{
var srchInfoElement = driver.FindElement(By.CssSelector("div.srch_info"));
if (srchInfoElement != null)
{
// span.heighlight에서 숫자 추출 시도
try
{
var highlightElement = srchInfoElement.FindElement(By.CssSelector("span.heighlight"));
if (highlightElement != null)
{
var countText = highlightElement.Text.Trim();
if (int.TryParse(countText, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({count}권)";
return count;
}
}
}
catch { }
// 전체 텍스트에서 정규식으로 추출
var srchInfoText = srchInfoElement.Text;
var match = Regex.Match(srchInfoText, @"검색결과\s*총\s*(\d+)\s*건", RegexOptions.IgnoreCase);
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({count}권)";
return count;
}
resulthtml = ExtractResultContext(htmlContent, match);
}
else
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
return 0;
}
}
catch (Exception ex)
{
Console.WriteLine($"srch_info 요소 검색 중 오류: {ex.Message}");
}
// 3. 페이지 소스에서 정규식으로 추출 시도
var pageSource = driver.PageSource;
// 검색 결과가 없다는 메시지 확인
if (pageSource.Contains("조회된 도서가 없습니다") ||
pageSource.Contains("검색결과가 없습니다") ||
pageSource.Contains("검색된 자료가 없습니다"))
{
errmessage = "검색결과없음";
return 0;
}
// HTML에서 다양한 패턴 찾기
var htmlPatterns = new[]
@@ -274,11 +225,14 @@ namespace BokBonCheck
foreach (var pattern in htmlPatterns)
{
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
resulthtml = ExtractResultContext(htmlContent, match);
if (count == 0)
{
errmessage = "검색결과없음";
@@ -291,16 +245,80 @@ namespace BokBonCheck
}
errmessage = "결과수량을찾을수없음";
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return -1;
}
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 페이지 변경을 감지하는 메서드
public async Task WaitForPageChange(WebDriverWait wait)
{

View File

@@ -81,10 +81,11 @@ namespace BokBonCheck
// HTTP GET 요청 실행 (추가 헤더 포함)
using (var request = new HttpRequestMessage(HttpMethod.Get, searchUrl))
{
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
// 브라우저와 유사한 헤더 추가 (인코딩 문제 방지를 위해 압축 해제)
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.9,en;q=0.1");
request.Headers.Add("Accept-Charset", "UTF-8,*;q=0.1");
// Accept-Encoding 제거 - 압축으로 인한 인코딩 문제 방지
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -96,10 +97,50 @@ namespace BokBonCheck
throw new HttpRequestException($"HTTP {(int)response.StatusCode} {response.StatusCode}: {errorContent}");
}
var htmlContent = await response.Content.ReadAsStringAsync();
// 인코딩 문제 해결: 서버 응답의 Content-Type 확인 후 적절한 인코딩 사용
string htmlContent;
var contentType = response.Content.Headers.ContentType?.ToString() ?? "";
Console.WriteLine($"광주동구 Content-Type: {contentType}");
if (contentType.Contains("charset="))
{
// 서버에서 지정한 charset 사용
htmlContent = await response.Content.ReadAsStringAsync();
}
else
{
// charset이 명시되지 않은 경우 수동 처리
var responseBytes = await response.Content.ReadAsByteArrayAsync();
// UTF-8 먼저 시도
htmlContent = Encoding.UTF8.GetString(responseBytes);
// 한글이 없거나 깨진 경우 EUC-KR 시도
if (!ContainsKorean(htmlContent) || htmlContent.Contains("<22>"))
{
try
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var euckrEncoding = Encoding.GetEncoding("EUC-KR");
var euckrContent = euckrEncoding.GetString(responseBytes);
if (ContainsKorean(euckrContent))
{
htmlContent = euckrContent;
Console.WriteLine("광주동구: EUC-KR 인코딩 사용");
}
}
catch (Exception encEx)
{
Console.WriteLine($"광주동구 EUC-KR 변환 오류: {encEx.Message}");
}
}
}
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
// ResultHtml에 분석용 HTML 저장 (디버깅용으로 일부만)
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -126,10 +167,11 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage)
private int ExtractBookCount(string htmlContent, out string errorMessage,out string resulthtml)
{
errorMessage = string.Empty;
resulthtml=string.Empty;
try
{
// 1. 검색 결과가 없는 경우 확인
@@ -141,18 +183,23 @@ namespace BokBonCheck
return 0;
}
// 2. 검색 결과 수량 추출: <p class="totalCount">전체 <strong>2</strong> 건</p>
// 2. 검색 결과 수량 추출 - 더 포괄적인 패턴 사용
var patterns = new[]
{
@"<p[^>]*class=""totalCount""[^>]*>전체\s*<strong>\s*(\d+)\s*</strong>\s*건</p>",
@"전체\s*<strong>\s*(\d+)\s*</strong>\s*건",
@"<strong>\s*(\d+)\s*</strong>\s*건",
@"총\s*(\d+)\s*건"
// 기본 패턴들
@"전체\s*(?:\*\*)?(\d+)(?:\*\*)?\s*건", // 전체 **N** 건 또는 전체 N 건
@"<h[1-6][^>]*>.*?전체\s*(?:\*\*)?(\d+)(?:\*\*)?\s*건.*?</h[1-6]>", // h태그 안의 전체 N 건
@"<p[^>]*class=""totalCount""[^>]*>전체\s*<strong>\s*(\d+)\s*</strong>\s*건</p>", // 원래 패턴
@"전체\s*<strong>\s*(\d+)\s*</strong>\s*건", // strong 태그
@"<strong>\s*(\d+)\s*</strong>\s*건", // strong만
@"총\s*(\d+)\s*건", // 총 N 건
@"검색결과\s*:\s*(\d+)\s*건", // 검색결과: N 건
@"(\d+)\s*건의\s*검색결과", // N 건의 검색결과
};
foreach (var pattern in patterns)
{
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
@@ -160,25 +207,31 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value; // 매칭된 부분만 저장
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
Console.WriteLine($"광주동구 검색 결과: {count}건");
Console.WriteLine($"광주동구 검색 결과: {count}건 (패턴: {pattern})");
return count;
}
}
}
// 3. 더 자세한 패턴으로 시도 (줄바꿈 포함)
// 3. 멀티라인 패턴으로 시도
var multilinePatterns = new[]
{
@"전체\s*<strong>\s*\r?\n?\s*(\d+)\s*\r?\n?\s*</strong>\s*건",
@"<strong>\s*\r?\n?\s*(\d+)\s*\r?\n?\s*</strong>\s*건"
@"전체\s*(?:\*\*)?[\r\n\s]*(\d+)[\r\n\s]*(?:\*\*)?\s*건",
@"전체\s*<strong>\s*[\r\n]*\s*(\d+)\s*[\r\n]*\s*</strong>\s*건",
@"<strong>\s*[\r\n]*\s*(\d+)\s*[\r\n]*\s*</strong>\s*건"
};
foreach (var pattern in multilinePatterns)
{
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
@@ -186,15 +239,24 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value; // 매칭된 부분만 저장
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
Console.WriteLine($"광주동구 검색 결과: {count}건");
Console.WriteLine($"광주동구 검색 결과: {count}건 (멀티라인 패턴)");
return count;
}
}
}
// 4. 패턴을 찾지 못한 경우 - 디버깅을 위한 HTML 내용 일부 출력
resulthtml = "검색결과 패턴을 찾을 수 없음";
Console.WriteLine($"광주동구 HTML 샘플: {resulthtml}");
errorMessage = "검색결과 패턴을 찾을 수 없음";
Console.WriteLine("광주동구 검색결과 패턴을 찾을 수 없음");
return -1;
@@ -202,6 +264,8 @@ namespace BokBonCheck
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "검색결과 패턴을 찾을 수 없음"; // 오류 시 HTML 일부 저장
Console.WriteLine($"광주동구 결과 분석 오류: {ex.Message}");
return -1;
}
}
@@ -210,5 +274,83 @@ namespace BokBonCheck
{
throw new NotImplementedException();
}
/// <summary>
/// 문자열에 한글이 포함되어 있는지 확인
/// </summary>
private bool ContainsKorean(string text)
{
if (string.IsNullOrEmpty(text))
return false;
foreach (char c in text)
{
if (c >= 0xAC00 && c <= 0xD7A3) // 한글 유니코드 범위
return true;
}
return false;
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -15,7 +15,6 @@ using System.Threading.Tasks;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using UniMarc.SearchModel;
using UniMarc.;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;
@@ -337,7 +336,8 @@ namespace BokBonCheck
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출 (페이징 포함)
var (resultCount, ermsg) = await ExtractBookCountWithPaging(_driver, searchTerm);
var (resultCount, ermsg, resultHtml) = await ExtractBookCountWithPaging(_driver, searchTerm);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -362,13 +362,15 @@ namespace BokBonCheck
return result;
}
private async Task<(int count, string message)> ExtractBookCountWithPaging(IWebDriver driver, string searchTerm)
private async Task<(int count, string message, string resultHtml)> ExtractBookCountWithPaging(IWebDriver driver, string searchTerm)
{
string errmessage = string.Empty;
int totalCount = 0;
try
{
var htmlContent = driver.PageSource;
string resultHtml = string.Empty;
// 첫 번째 페이지에서 테이블 row 수 확인
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
@@ -381,7 +383,28 @@ namespace BokBonCheck
if (firstPageRows.Count == 0)
{
errmessage = "검색결과없음";
return (0, errmessage);
// "검색결과가 없습니다"와 같은 메시지를 찾아 context 추출 시도
var noResultPatterns = new[]
{
@"검색결과가 없습니다",
@"검색된 자료가 없습니다",
@"자료가 없습니다"
};
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
resultHtml = ExtractResultContext(htmlContent, match);
return (0, errmessage, resultHtml);
}
}
}
resultHtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return (0, errmessage, resultHtml);
}
totalCount += firstPageRows.Count;
@@ -390,7 +413,28 @@ namespace BokBonCheck
catch
{
errmessage = "검색결과없음";
return (0, errmessage);
// "검색결과가 없습니다"와 같은 메시지를 찾아 context 추출 시도
var noResultPatterns = new[]
{
@"검색결과가 없습니다",
@"검색된 자료가 없습니다",
@"자료가 없습니다"
};
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
resultHtml = ExtractResultContext(htmlContent, match);
return (0, errmessage, resultHtml);
}
}
}
resultHtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return (0, errmessage, resultHtml);
}
// 페이징이 있는지 확인하고 각 페이지 방문
@@ -436,18 +480,42 @@ namespace BokBonCheck
if (totalCount == 0)
{
errmessage = "검색결과없음";
return (0, errmessage);
// "검색결과가 없습니다"와 같은 메시지를 찾아 context 추출 시도
var noResultPatterns = new[]
{
@"검색결과가 없습니다",
@"검색된 자료가 없습니다",
@"자료가 없습니다",
@"전체\s*0\s*건"
};
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
resultHtml = ExtractResultContext(htmlContent, match);
return (0, errmessage, resultHtml);
}
}
}
resultHtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return (0, errmessage, resultHtml);
}
resultHtml = $"검색성공 - 총 {totalCount}건";
errmessage = $"검색성공({totalCount}권)";
Console.WriteLine($"전체 검색 결과: {totalCount}건");
return (totalCount, errmessage);
return (totalCount, errmessage, resultHtml);
}
catch (Exception ex)
{
errmessage = ex.Message;
return (-1, errmessage);
string resultHtml = "오류 발생";
return (-1, errmessage, resultHtml);
}
}
@@ -492,5 +560,67 @@ namespace BokBonCheck
Console.WriteLine($"페이지 변경 감지 실패: {ex.Message}");
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, System.Text.RegularExpressions.Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = System.Text.RegularExpressions.Regex.Matches(searchText, tagPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = System.Text.RegularExpressions.Regex.Match(tagMatch.Value, @"<(\w+)", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = System.Text.RegularExpressions.Regex.Match(searchText, closeTagPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -74,7 +74,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -84,7 +84,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -112,9 +113,10 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage)
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
@@ -124,6 +126,7 @@ namespace BokBonCheck
htmlContent.Contains("자료가 없습니다"))
{
errorMessage = "검색결과없음";
resulthtml = "검색결과없음";
return 0;
}
@@ -146,8 +149,11 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
return count;
}
@@ -171,20 +177,25 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
return count;
}
}
}
// 패턴을 찾지 못한 경우
resulthtml = "검색결과 패턴을 찾을 수 없음";
errorMessage = "검색결과 패턴을 찾을 수 없음";
return -1;
}
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
@@ -193,5 +204,67 @@ namespace BokBonCheck
{
throw new NotImplementedException();
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -107,8 +107,9 @@ namespace BokBonCheck
// JavaScript 렌더링 대기
await Task.Delay(3000);
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var htmlContent = _driver.PageSource;
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -133,71 +134,21 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
// JavaScript 실행 후 실제 렌더링된 DOM에서 결과 추출
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// 1. 검색결과가 없는 경우 확인
try
{
var noResultElements = driver.FindElements(By.XPath("//*[contains(text(), '검색결과가 없습니다') or contains(text(), '검색된 자료가 없습니다')]"));
if (noResultElements.Count > 0)
{
errmessage = "검색결과없음";
return 0;
}
}
catch
{
// 검색결과가 있는 경우로 진행
}
// 2. total_area에서 결과 수량 추출 (JavaScript 렌더링 후)
try
{
var totalAreaElement = wait.Until(d => d.FindElement(By.CssSelector("div.total_area p.total span")));
if (totalAreaElement != null)
{
var countText = totalAreaElement.Text.Trim();
Console.WriteLine($"total_area 텍스트: '{countText}'");
// "총 3건" 형태에서 숫자 추출
var match = Regex.Match(countText, @"총\s*(\d+)\s*건", RegexOptions.IgnoreCase);
if (match.Success && int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
Console.WriteLine("검색 결과: 0건");
return 0;
}
errmessage = $"검색성공({count}권)";
Console.WriteLine($"검색 결과: {count}건");
return count;
}
}
}
catch (Exception ex1)
{
Console.WriteLine($"total_area 요소 추출 실패: {ex1.Message}");
}
// 3. 페이지 소스에서 렌더링된 결과 추출
var pageSource = driver.PageSource;
Console.WriteLine("페이지 소스에서 결과 추출 시도");
// 검색 결과가 없다는 메시지 확인
if (pageSource.Contains("검색결과가 없습니다") ||
pageSource.Contains("검색된 자료가 없습니다") ||
pageSource.Contains("자료가 없습니다") ||
pageSource.Contains("총 0건"))
if (htmlContent.Contains("검색결과가 없습니다") ||
htmlContent.Contains("검색된 자료가 없습니다") ||
htmlContent.Contains("자료가 없습니다") ||
htmlContent.Contains("총 0건"))
{
errmessage = "검색결과없음";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return 0;
}
@@ -212,11 +163,14 @@ namespace BokBonCheck
foreach (var pattern in htmlPatterns)
{
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
resulthtml = ExtractResultContext(htmlContent, match);
if (count == 0)
{
errmessage = "검색결과없음";
@@ -229,16 +183,80 @@ namespace BokBonCheck
}
errmessage = "결과수량을찾을수없음";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 완전한 페이지 로딩 대기 메서드
private async Task WaitForCompletePageLoad(WebDriverWait wait)
{

View File

@@ -74,7 +74,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -84,7 +84,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -110,9 +111,10 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
// 실제 HTML 구조에 맞는 패턴으로 수정
@@ -139,6 +141,7 @@ namespace BokBonCheck
if (pattern.Contains(@"\s*0\s*"))
{
errmessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
@@ -148,17 +151,21 @@ namespace BokBonCheck
if (count == 0)
{
errmessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errmessage = $"검색성공({count}권)";
return count;
}
}
}
// 디버깅을 위해 HTML 내용 일부 출력
// 패턴을 찾지 못한 경우
resulthtml = "검색결과 패턴을 찾을 수 없음";
Console.WriteLine($"HTML 내용 일부: {htmlContent.Substring(0, Math.Min(1000, htmlContent.Length))}");
errmessage = "결과수량을찾을수없음";
return -1;
@@ -166,6 +173,7 @@ namespace BokBonCheck
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
@@ -177,5 +185,66 @@ namespace BokBonCheck
await Task.CompletedTask;
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -9,7 +9,6 @@ using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using UniMarc.;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
@@ -227,8 +226,9 @@ namespace BokBonCheck
// 페이지 변경을 감지하는 메서드
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var htmlContent = _driver.PageSource;
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -253,71 +253,20 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
// 1. search-info div에서 직접 추출 시도
try
{
var searchInfoElement = driver.FindElement(By.CssSelector("div.search-info"));
if (searchInfoElement != null)
{
var searchInfoText = searchInfoElement.Text;
// "총 N건이 검색되었습니다" 패턴 찾기
var match = Regex.Match(searchInfoText, @"총\s*(\d+)\s*건이\s*검색되었습니다", RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({count}권)";
return count;
}
}
// <b> 태그에서 직접 숫자 추출 시도
try
{
var boldElements = searchInfoElement.FindElements(By.TagName("b"));
foreach (var boldElement in boldElements)
{
var boldText = boldElement.Text.Trim();
if (int.TryParse(boldText, out int boldCount))
{
if (boldCount == 0)
{
errmessage = "검색결과없음";
return 0;
}
errmessage = $"검색성공({boldCount}권)";
return boldCount;
}
}
}
catch { }
}
}
catch (Exception ex)
{
Console.WriteLine($"search-info 요소 검색 중 오류: {ex.Message}");
}
// 2. 페이지 소스에서 정규식으로 추출 시도
var pageSource = driver.PageSource;
// 검색 결과가 없다는 메시지 확인
if (pageSource.Contains("0건이 검색되었습니다") ||
pageSource.Contains("검색결과가 없습니다") ||
pageSource.Contains("검색된 자료가 없습니다"))
if (htmlContent.Contains("0건이 검색되었습니다") ||
htmlContent.Contains("검색결과가 없습니다") ||
htmlContent.Contains("검색된 자료가 없습니다"))
{
errmessage = "검색결과없음";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return 0;
}
@@ -332,11 +281,14 @@ namespace BokBonCheck
foreach (var pattern in htmlPatterns)
{
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
resulthtml = ExtractResultContext(htmlContent, match);
if (count == 0)
{
errmessage = "검색결과없음";
@@ -349,16 +301,80 @@ namespace BokBonCheck
}
errmessage = "결과수량을찾을수없음";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 페이지 변경을 감지하는 메서드
public async Task WaitForPageChange(WebDriverWait wait)
{

View File

@@ -0,0 +1,263 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Web;
using UniMarc.SearchModel;
using System.Text;
using OpenQA.Selenium.Support.UI;
namespace BokBonCheck
{
public class JeonnamProvLibSearcher : ILibrarySearcher
{
public string AreaCode { get; set; } = string.Empty;
public string SiteName { get; protected set; }
public string SiteUrl => "https://lib.jeonnam.go.kr/plus/search_list.php";
public bool HttpApiMode { get; set; } = true;
public int No { get; set; }
private static readonly HttpClient _httpClient = new HttpClient()
{
DefaultRequestHeaders =
{
{ "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" }
}
};
public JeonnamProvLibSearcher(int no, string areaCode, string areaName)
{
this.No = no;
this.AreaCode = areaCode;
this.SiteName = $"전라남도립({areaName})";
}
public async Task StartDriver(bool showdriver = false)
{
// HTTP 클라이언트 사용으로 별도 드라이버 불필요
await Task.CompletedTask;
}
public void StopDriver()
{
// HTTP 클라이언트 사용으로 별도 정리 불필요
}
public async Task<BookSearchResult> SearchAsync(string searchTerm)
{
var result = new BookSearchResult
{
SiteName = SiteName,
SearchTerm = searchTerm,
SearchTime = DateTime.Now
};
try
{
// 검색어 URL 인코딩
var encodedSearchTerm = HttpUtility.UrlEncode(searchTerm, Encoding.UTF8);
// 실제 검색 URL 구성 (사용자가 확인한 정확한 파라미터 사용)
var searchUrl = $"{SiteUrl}?act=1&aon1=AND&msa=M&jongbook=1&value1={encodedSearchTerm}&field1=IAL&formclass=&local=&sort=";
Console.WriteLine($"전라남도립도서관 검색 URL: {searchUrl}");
// HTTP GET 요청 실행 (추가 헤더 포함)
using (var request = new HttpRequestMessage(HttpMethod.Get, searchUrl))
{
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
request.Headers.Add("Referer", "https://lib.jeonnam.go.kr/plus/search_simple.php");
var response = await _httpClient.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
throw new HttpRequestException($"HTTP {(int)response.StatusCode} {response.StatusCode}: {errorContent}");
}
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
result.IsSuccess = false;
result.ErrorMessage = errorMessage;
}
else
{
result.BookCount = resultCount;
result.IsSuccess = true;
result.ErrorMessage = $"검색성공({resultCount}권)";
}
}
}
catch (Exception ex)
{
result.IsSuccess = false;
result.ErrorMessage = $"검색 오류: {ex.Message}";
result.BookCount = 0;
Console.WriteLine($"전라남도립도서관 검색 오류: {ex.Message}");
}
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
// 전라남도립도서관 실제 HTML 패턴: <font>전체 1</font>개가 검색되었습니다
var patterns = new[]
{
@"<font[^>]*>전체\s*(\d+)</font>\s*개가\s*검색되었습니다",
@"'[^']*'\s*에\s*대하여\s*<font[^>]*>전체\s*(\d+)</font>\s*개가\s*검색되었습니다",
@"전체\s*(\d+)\s*개가\s*검색되었습니다"
};
foreach (var pattern in patterns)
{
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
return count;
}
}
}
// Page X / Y 패턴으로도 확인 (총 페이지 수에서 결과 유무 판단)
var pagePattern = @"Page\s*\d+\s*/\s*(\d+)";
var pageMatch = Regex.Match(htmlContent, pagePattern, RegexOptions.IgnoreCase);
if (pageMatch.Success)
{
if (int.TryParse(pageMatch.Groups[1].Value, out int totalPages))
{
if (totalPages == 0)
{
errorMessage = "검색결과없음";
resulthtml = pageMatch.Value;
return 0;
}
// 페이지가 있지만 정확한 개수를 알 수 없는 경우 -1 반환
resulthtml = pageMatch.Value;
errorMessage = "결과수량을찾을수없음";
return -1;
}
}
// 검색 결과가 없다는 메시지 확인
if (htmlContent.Contains("검색결과가 없습니다") ||
htmlContent.Contains("검색된 자료가 없습니다") ||
htmlContent.Contains("자료가 없습니다") ||
htmlContent.Contains("개가 검색되었습니다") && !Regex.IsMatch(htmlContent, @"\d+\s*개가"))
{
errorMessage = "검색결과없음";
resulthtml = "검색결과없음";
return 0;
}
// 패턴을 찾지 못한 경우
resulthtml = "검색결과 패턴을 찾을 수 없음";
errorMessage = "검색결과 패턴을 찾을 수 없음";
return -1;
}
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
public Task WaitForPageChange(WebDriverWait wait)
{
throw new NotImplementedException();
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -9,7 +9,6 @@ using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using UniMarc.;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
@@ -260,7 +259,8 @@ namespace BokBonCheck
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -285,11 +285,13 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
var htmlContent = driver.PageSource;
// 먼저 검색결과가 없는 경우 확인
try
{
@@ -298,6 +300,7 @@ namespace BokBonCheck
if (noResultText.Contains("검색결과가 없습니다"))
{
errmessage = "검색결과없음";
resulthtml = noResultText;
return 0;
}
}
@@ -318,17 +321,36 @@ namespace BokBonCheck
if (int.TryParse(match.Groups[1].Value, out int vqty))
{
errmessage = $"검색성공({vqty}건)";
resulthtml = ExtractResultContext(htmlContent, match);
return vqty;
}
else
{
errmessage = $"수량값오류({match.Groups[1].Value})";
resulthtml = match.Value;
return -1;
}
}
else
{
errmessage = "수량항목없음";
// 매칭된 부분이 없는 경우, 기본적으로 pageInfoText 부분 추출 시도
try
{
var dummyMatch = System.Text.RegularExpressions.Regex.Match(pageInfoText, @"전체.*");
if (dummyMatch.Success)
{
resulthtml = ExtractResultContext(htmlContent, dummyMatch);
}
else
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
}
catch
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
return -1;
}
}
@@ -336,6 +358,7 @@ namespace BokBonCheck
{
// page_info가 없는 경우 검색결과가 없는 것으로 판단
errmessage = "검색결과없음";
resulthtml = "검색결과 없음: " + ex.Message;
return 0;
}
@@ -343,11 +366,72 @@ namespace BokBonCheck
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "ExtractBookCount 오류: " + ex.Message;
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 페이지 변경을 감지하는 메서드
public async Task WaitForPageChange(WebDriverWait wait)

View File

@@ -9,7 +9,6 @@ using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using UniMarc.;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
@@ -272,7 +271,8 @@ namespace BokBonCheck
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -297,11 +297,13 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
var htmlContent = driver.PageSource;
// 먼저 검색결과가 없는 경우 확인
try
{
@@ -310,6 +312,7 @@ namespace BokBonCheck
if (noResultText.Contains("검색결과가 없습니다"))
{
errmessage = "검색결과없음";
resulthtml = noResultText;
return 0;
}
}
@@ -330,17 +333,36 @@ namespace BokBonCheck
if (int.TryParse(match.Groups[1].Value, out int vqty))
{
errmessage = $"검색성공({vqty}건)";
resulthtml = ExtractResultContext(htmlContent, match);
return vqty;
}
else
{
errmessage = $"수량값오류({match.Groups[1].Value})";
resulthtml = match.Value;
return -1;
}
}
else
{
errmessage = "수량항목없음";
// 매칭된 부분이 없는 경우, 기본적으로 pageInfoText 부분 추출 시도
try
{
var dummyMatch = System.Text.RegularExpressions.Regex.Match(pageInfoText, @"전체.*");
if (dummyMatch.Success)
{
resulthtml = ExtractResultContext(htmlContent, dummyMatch);
}
else
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
}
catch
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
return -1;
}
}
@@ -348,6 +370,27 @@ namespace BokBonCheck
{
// page_info가 없는 경우 검색결과가 없는 것으로 판단
errmessage = "검색결과없음";
// "검색결과가 없습니다"와 같은 메시지를 찾아 context 추출 시도
var noResultPatterns = new[]
{
@"검색결과가 없습니다",
@"검색된 자료가 없습니다",
@"자료가 없습니다"
};
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
resulthtml = ExtractResultContext(htmlContent, match);
return 0;
}
}
}
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
return 0;
}
@@ -355,11 +398,72 @@ namespace BokBonCheck
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "ExtractBookCount 오류: " + ex.Message;
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 페이지 변경을 감지하는 메서드
public async Task WaitForPageChange(WebDriverWait wait)

View File

@@ -85,7 +85,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -100,7 +100,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -128,9 +129,10 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage)
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
@@ -141,6 +143,7 @@ namespace BokBonCheck
htmlContent.Contains("총 0 건이 검색되었습니다"))
{
errorMessage = "검색결과없음";
resulthtml = "검색결과없음";
return 0;
}
@@ -163,8 +166,11 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
Console.WriteLine($"KCM자료검색시스템 검색 결과: {count}건");
return count;
@@ -189,15 +195,19 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
Console.WriteLine($"KCM자료검색시스템 검색 결과: {count}건");
return count;
}
}
}
// 패턴을 찾지 못한 경우
resulthtml = "검색결과 패턴을 찾을 수 없음";
errorMessage = "검색결과 패턴을 찾을 수 없음";
Console.WriteLine("KCM자료검색시스템 검색결과 패턴을 찾을 수 없음");
return -1;
@@ -205,6 +215,7 @@ namespace BokBonCheck
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
@@ -213,5 +224,67 @@ namespace BokBonCheck
{
throw new NotImplementedException();
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -13,7 +13,7 @@ using OpenQA.Selenium.Chromium;
namespace BokBonCheck
{
public class KwangjuCityEduLibrarySearcher : ILibrarySearcher
public class KwangjuCityEduLibrarySearcher : ILibrarySearcher
{
public int No { get; set; }
@@ -39,7 +39,7 @@ namespace BokBonCheck
try
{
if (SeleniumHelper.IsReady == false) await SeleniumHelper.Download();
_driver = await SeleniumHelper.CreateDriver(ShowBrowser:showBrowser);
_driver = await SeleniumHelper.CreateDriver(ShowBrowser: showBrowser);
Console.WriteLine("KwangjuCityLibrarySearcher Driver 초기화 완료");
}
catch (Exception ex)
@@ -94,7 +94,7 @@ namespace BokBonCheck
_driver.Navigate().GoToUrl(SiteUrl);
// 페이지 로딩 대기
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(30));
// 모든 감지 방법이 끝나면 크롬창 최소화
// whale 브라우저가 최소화되어 우선해제
@@ -190,13 +190,24 @@ namespace BokBonCheck
}
// 페이지 변경을 감지하는 메서드
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(30)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver);
var resultCount = ExtractBookCount(_driver, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
result.BookCount = resultCount;
result.IsSuccess = true;
if (resultCount == -1)
{
result.BookCount = 0;
result.IsSuccess = false;
result.ErrorMessage = errorMessage;
}
else
{
result.BookCount = resultCount;
result.IsSuccess = true;
result.ErrorMessage = errorMessage;
}
}
catch (Exception ex)
{
@@ -204,14 +215,21 @@ namespace BokBonCheck
result.ErrorMessage = ex.Message;
result.BookCount = 0;
}
finally
{
await Task.Delay(1000);//.Threading.Thread.Sleep(500);
}
return result;
}
private int ExtractBookCount(IWebDriver driver)
private int ExtractBookCount(IWebDriver driver, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
var htmlContent = driver.PageSource;
// div.search-result 내부의 span에서 '전체 N' 텍스트 추출
var resultDiv = driver.FindElement(By.CssSelector("div.ndls_result"));
var span = resultDiv.FindElement(By.XPath(".//span[contains(text(),'전체')]"));
@@ -219,13 +237,106 @@ namespace BokBonCheck
var match = System.Text.RegularExpressions.Regex.Match(text, @"전체\s*(\d+)");
if (match.Success)
{
return int.Parse(match.Groups[1].Value);
if (int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = text;
return 0;
}
errorMessage = $"검색성공({count}건)";
resulthtml = ExtractResultContext(htmlContent, match);
return count;
}
}
return 0;
errorMessage = "수량항목없음";
// 매칭된 부분이 없는 경우, 기본적으로 text 부분 추출 시도
try
{
var dummyMatch = System.Text.RegularExpressions.Regex.Match(text, @"전체.*");
if (dummyMatch.Success)
{
resulthtml = ExtractResultContext(htmlContent, dummyMatch);
}
else
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
}
catch
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
return -1;
}
catch
catch (Exception ex)
{
return 0;
errorMessage = ex.Message;
resulthtml = "오류발생";
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}

View File

@@ -77,7 +77,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -92,7 +92,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -120,9 +121,10 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage)
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
@@ -146,8 +148,11 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
return count;
}
@@ -161,6 +166,7 @@ namespace BokBonCheck
htmlContent.Contains("총 0권(개)"))
{
errorMessage = "검색결과없음";
resulthtml = "검색결과없음";
return 0;
}
@@ -183,20 +189,25 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
return count;
}
}
}
// 패턴을 찾지 못한 경우
resulthtml = "검색결과 패턴을 찾을 수 없음";
errorMessage = "검색결과 패턴을 찾을 수 없음";
return -1;
}
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
@@ -205,5 +216,67 @@ namespace BokBonCheck
{
throw new NotImplementedException();
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -196,9 +196,9 @@ namespace BokBonCheck
// 페이지 변경을 감지하는 메서드
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var htmlContent = _driver.PageSource;
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -223,71 +223,56 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
// 검색결과 페이지 대기
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
// 1. 검색결과가 없는 경우 확인
try
// 검색 결과가 없다는 메시지 확인
var noResultPatterns = new[]
{
var noResultElements = driver.FindElements(By.XPath("//*[contains(text(), '검색결과가 없습니다') or contains(text(), '검색된 자료가 없습니다')]"));
if (noResultElements.Count > 0)
@"검색결과가 없습니다",
@"검색된 자료가 없습니다",
@"자료가 없습니다",
@"전체 <strong>0</strong> 건"
};
foreach (var pattern in noResultPatterns)
{
if (htmlContent.Contains(pattern))
{
errmessage = "검색결과없음";
// 검색결과 없음 메시지를 포함한 HTML 조각 추출
var index = htmlContent.IndexOf(pattern);
if (index >= 0)
{
var startIndex = Math.Max(0, index - 100);
var endIndex = Math.Min(htmlContent.Length, index + pattern.Length + 100);
resulthtml = htmlContent.Substring(startIndex, endIndex - startIndex);
// 상위 태그 찾기 시도
try
{
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
if (match.Success)
{
resulthtml = ExtractResultContext(htmlContent, match);
}
}
catch
{
// 실패시 기본 추출 결과 사용
}
}
else
{
resulthtml = pattern;
}
return 0;
}
}
catch
{
// 검색결과가 있는 경우로 진행
}
// 2. totalCount에서 결과 수량 추출
try
{
var totalCountElement = wait.Until(d => d.FindElement(By.CssSelector("p.totalCount strong")));
if (totalCountElement != null)
{
var countText = totalCountElement.Text.Trim();
Console.WriteLine($"totalCount 텍스트: '{countText}'");
if (int.TryParse(countText, out int count))
{
if (count == 0)
{
errmessage = "검색결과없음";
Console.WriteLine("검색 결과: 0건");
return 0;
}
errmessage = $"검색성공({count}권)";
Console.WriteLine($"검색 결과: {count}건");
return count;
}
}
}
catch (Exception ex1)
{
Console.WriteLine($"totalCount 요소 추출 실패: {ex1.Message}");
}
// 3. 페이지 소스에서 결과 추출
var pageSource = driver.PageSource;
Console.WriteLine("페이지 소스에서 결과 추출 시도");
// 검색 결과가 없다는 메시지 확인
if (pageSource.Contains("검색결과가 없습니다") ||
pageSource.Contains("검색된 자료가 없습니다") ||
pageSource.Contains("자료가 없습니다") ||
pageSource.Contains("전체 <strong>0</strong> 건"))
{
errmessage = "검색결과없음";
return 0;
}
// HTML에서 다양한 패턴 찾기
var htmlPatterns = new[]
@@ -299,11 +284,14 @@ namespace BokBonCheck
foreach (var pattern in htmlPatterns)
{
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
resulthtml = ExtractResultContext(htmlContent, match);
if (count == 0)
{
errmessage = "검색결과없음";
@@ -316,16 +304,80 @@ namespace BokBonCheck
}
errmessage = "결과수량을찾을수없음";
resulthtml = "결과수량을찾을수없음";
return -1;
}
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "ExtractBookCount 오류: " + ex.Message;
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 완전한 페이지 로딩 대기 메서드
private async Task WaitForCompletePageLoad(WebDriverWait wait)
{

View File

@@ -9,7 +9,6 @@ using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using UniMarc.;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
@@ -269,7 +268,8 @@ namespace BokBonCheck
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
// 검색 결과 수 추출
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
result.BookCount = 0;
@@ -294,11 +294,14 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
var htmlContent = driver.PageSource;
// div.search-result 내부의 span에서 '전체 N' 텍스트 추출
var resultDiv = driver.FindElement(By.CssSelector("div.search-result"));
@@ -306,6 +309,7 @@ namespace BokBonCheck
if (bodytext.Contains("검색결과가 없습니다"))
{
errmessage = "검색결과없음";
resulthtml = bodytext;
return 0;
}
@@ -315,6 +319,7 @@ namespace BokBonCheck
if (searchTerm.Contains(searchtitle) == false)
{
errmessage = $"검색어불일치({searchtitle}/{searchTerm})";
resulthtml = searchtitle;
return -1;
}
var span = resultDiv.FindElement(By.XPath(".//span[contains(text(),'전체')]"));
@@ -325,10 +330,13 @@ namespace BokBonCheck
if (int.TryParse(match.Groups[1].Value, out int vqty) == false)
{
errmessage = $"수량값오류({match.Groups[1].Value})";
resulthtml = match.Value;
return -1;
}
else
{
errmessage = $"검색성공({vqty}건)";
resulthtml = ExtractResultContext(htmlContent, match);
searchTerm = string.Empty;
return vqty;
}
@@ -336,6 +344,23 @@ namespace BokBonCheck
else
{
errmessage = "수량항목없음";
// 매칭된 부분이 없는 경우, 기본적으로 text 부분 추출 시도
try
{
var dummyMatch = System.Text.RegularExpressions.Regex.Match(text, @"전체.*");
if (dummyMatch.Success)
{
resulthtml = ExtractResultContext(htmlContent, dummyMatch);
}
else
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
}
catch
{
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
}
return -1;
}
@@ -343,11 +368,72 @@ namespace BokBonCheck
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "ExtractBookCount 오류: " + ex.Message;
return -1;
}
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
// 페이지 변경을 감지하는 메서드
public async Task WaitForPageChange(WebDriverWait wait)

View File

@@ -82,7 +82,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -97,7 +97,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -125,9 +126,10 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage)
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
@@ -150,8 +152,11 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
return count;
}
@@ -165,6 +170,7 @@ namespace BokBonCheck
htmlContent.Contains("총 0건"))
{
errorMessage = "검색결과없음";
resulthtml = "검색결과없음";
return 0;
}
@@ -178,8 +184,10 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = resultConMatch.Value;
return 0;
}
resulthtml = ExtractResultContext(htmlContent, resultConMatch);
errorMessage = $"검색성공({count}권)";
return count;
}
@@ -203,20 +211,25 @@ namespace BokBonCheck
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
return count;
}
}
}
// 패턴을 찾지 못한 경우
resulthtml = "검색결과 패턴을 찾을 수 없음";
errorMessage = "검색결과 패턴을 찾을 수 없음";
return -1;
}
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
@@ -225,5 +238,67 @@ namespace BokBonCheck
{
throw new NotImplementedException();
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -9,7 +9,6 @@ using WebDriverManager.DriverConfigs.Impl;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using UniMarc.;
using OpenQA.Selenium.Chromium;
using UniMarc.SearchModel;
using System.Runtime.CompilerServices;
@@ -86,7 +85,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -96,7 +95,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -122,15 +122,17 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errmessage)
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
{
errmessage = string.Empty;
resulthtml = string.Empty;
try
{
// 검색 결과가 없다는 메시지 확인
if (htmlContent.Contains("0권(개)") || htmlContent.Contains("검색결과가 없습니다"))
{
errmessage = "검색결과없음";
resulthtml = "검색결과없음";
return 0;
}
@@ -153,14 +155,19 @@ namespace BokBonCheck
if (count == 0)
{
errmessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errmessage = $"검색성공({count}권)";
return count;
}
}
}
// 패턴을 찾지 못한 경우
resulthtml = "검색결과 패턴을 찾을 수 없음";
errmessage = "결과수량을찾을수없음";
return -1;
@@ -168,6 +175,7 @@ namespace BokBonCheck
catch (Exception ex)
{
errmessage = ex.Message;
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
@@ -178,5 +186,67 @@ namespace BokBonCheck
// HTTP 방식에서는 즉시 응답이 오므로 대기 불필요
await Task.CompletedTask;
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -82,7 +82,7 @@ namespace BokBonCheck
// 브라우저와 유사한 헤더 추가
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
//request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
request.Headers.Add("Connection", "keep-alive");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
@@ -92,7 +92,8 @@ namespace BokBonCheck
var htmlContent = await response.Content.ReadAsStringAsync();
// 검색 결과 수 추출
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
result.Resulthtml = resultHtml;
if (resultCount == -1)
{
@@ -120,9 +121,10 @@ namespace BokBonCheck
return result;
}
private int ExtractBookCount(string htmlContent, out string errorMessage)
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
{
errorMessage = string.Empty;
resulthtml = string.Empty;
try
{
@@ -134,12 +136,21 @@ namespace BokBonCheck
{
if (int.TryParse(match.Groups[1].Value, out int count))
{
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = match.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, match);
errorMessage = $"검색성공({count}권)";
return count;
}
else
{
errorMessage = $"수량값오류({match.Groups[1].Value})";
resulthtml = match.Value;
return -1;
}
}
@@ -153,11 +164,21 @@ namespace BokBonCheck
{
if (int.TryParse(alternateMatch.Groups[1].Value, out int count))
{
if (count == 0)
{
errorMessage = "검색결과없음";
resulthtml = alternateMatch.Value;
return 0;
}
// 매칭된 부분과 그 상위 태그를 찾아서 저장
resulthtml = ExtractResultContext(htmlContent, alternateMatch);
errorMessage = $"검색성공({count}권)";
return count;
}
}
// 패턴을 찾지 못한 경우
resulthtml = "검색결과 패턴을 찾을 수 없음";
errorMessage = "검색결과 패턴을 찾을 수 없음";
return -1;
}
@@ -165,6 +186,7 @@ namespace BokBonCheck
catch (Exception ex)
{
errorMessage = $"결과 분석 오류: {ex.Message}";
resulthtml = "검색결과 패턴을 찾을 수 없음";
return -1;
}
}
@@ -173,5 +195,67 @@ namespace BokBonCheck
{
throw new NotImplementedException();
}
/// <summary>
/// 매칭된 결과와 그 상위 태그를 추출
/// </summary>
private string ExtractResultContext(string htmlContent, Match match)
{
try
{
var matchIndex = match.Index;
var matchLength = match.Length;
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
string resultContext = match.Value; // 기본값은 매칭된 부분만
foreach (var tagPattern in tagPatterns)
{
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
for (int i = tagMatches.Count - 1; i >= 0; i--)
{
var tagMatch = tagMatches[i];
if (tagMatch.Index < (matchIndex - startSearchIndex))
{
// 태그 이름 추출
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
// 닫는 태그 찾기
var closeTagPattern = $@"</{tagName}[^>]*>";
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
{
// 상위 태그와 그 내용을 포함하여 반환
var startIdx = tagMatch.Index;
var endIdx = closeMatch.Index + closeMatch.Length;
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
return resultContext;
}
}
}
}
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
var contextStart = Math.Max(0, matchIndex - 50);
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
return resultContext;
}
catch (Exception ex)
{
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
return match.Value; // 오류 시 매칭된 부분만 반환
}
}
}
}

View File

@@ -5,11 +5,12 @@ namespace UniMarc.Properties {
public class UserSetting : AR.Setting
{
public int ISBNSearchDelay { get; set; }
public string LastSearchTarget { get; set; }
public string LastSearchTargetDLS { get; set; }
public override void AfterLoad()
{
if (ISBNSearchDelay == 0) ISBNSearchDelay = 500;
}
public override void AfterSave()

View File

@@ -23,8 +23,10 @@ using System.Drawing.Text;
using System.Globalization;
using System.Threading;
using System.Data.SqlTypes;
using AR;
using System.Runtime.InteropServices.WindowsRuntime;
namespace WindowsFormsApp1
namespace UniMarc
{
/// <summary>
/// 여러 기능들이 추가될 예정.
@@ -63,7 +65,7 @@ namespace WindowsFormsApp1
else
dataGridView.Sort(dataGridView.Columns[col], System.ComponentModel.ListSortDirection.Ascending);
}
/// <summary>
/// * Row헤더에 체크박스를 넣는 기능*
@@ -99,7 +101,7 @@ namespace WindowsFormsApp1
}
private void datagridview_checkBox_Click(object sender, EventArgs e)
{
foreach(DataGridViewRow r in ((DataGridView)sender).Rows)
foreach (DataGridViewRow r in ((DataGridView)sender).Rows)
{
r.Cells["colCheck"].Value = ((CheckBox)sender).Checked;
}
@@ -119,23 +121,32 @@ namespace WindowsFormsApp1
char[] columnSplitter = { '\t' };
//get the text from clipboard
IDataObject dataInClipboard = Clipboard.GetDataObject();
string stringInClipboard = (string)dataInClipboard.GetData(DataFormats.Text);
if (Clipboard.ContainsText() == false) return;
string stringInClipboard = null;
if (e.Alt)
stringInClipboard = Clipboard.GetText(TextDataFormat.UnicodeText);
else
stringInClipboard = Clipboard.GetText();// (string)objdata;
//split it into lines
//20230209 \r텝 기능과 \n 줄넘김 기능을 같이 공백 제거 처리해버려 공백칸을 활용해야 함에도 제거하는 현상 발생.
//텝 공백 문자열 동시에 사용하여 분류
// stringInClipboard= stringInClipboard.Replace("\r", "");
if (stringInClipboard == null) return;
List<string>rowsInClipboard = stringInClipboard.Split(rowSpliteter, StringSplitOptions.None).ToList();
rowsInClipboard.RemoveAt(rowsInClipboard.Count-1);
//get the row and column of selected cell in dataGridView1
int r = ((DataGridView)sender).SelectedCells[0].RowIndex;
int c = ((DataGridView)sender).SelectedCells[0].ColumnIndex;
List<string> rowsInClipboard = stringInClipboard.Split(rowSpliteter, StringSplitOptions.None).ToList();
if (rowsInClipboard.Last().isEmpty()) rowsInClipboard.RemoveAt(rowsInClipboard.Count - 1);
var dv = sender as DataGridView;
int r = dv.SelectedCells[0].RowIndex;
int c = dv.SelectedCells[0].ColumnIndex;
//add rows into dataGridView1 to fit clipboard lines
if (((DataGridView)sender).Rows.Count < (r + rowsInClipboard.Count))
if (dv.Rows.Count < (r + rowsInClipboard.Count))
{
((DataGridView)sender).Rows.Add(r + rowsInClipboard.Count - ((DataGridView)sender).Rows.Count);
dv.Rows.Add(r + rowsInClipboard.Count - dv.Rows.Count);
}
// loop through the lines, split them into cells and place the values in the corresponding cell.
for (int iRow = 0; iRow < rowsInClipboard.Count; iRow++)
@@ -146,10 +157,10 @@ namespace WindowsFormsApp1
for (int iCol = 0; iCol < valuesInRow.Length; iCol++)
{
//assign cell value, only if it within columns of the dataGridView1
if (((DataGridView)sender).ColumnCount - 1 >= c + iCol)
if (dv.ColumnCount - 1 >= c + iCol)
{
if (((DataGridView)sender).Rows.Count <= r + iRow) continue;
((DataGridView)sender).Rows[r + iRow].Cells[c + iCol].Value = valuesInRow[iCol];
if (dv.Rows.Count <= r + iRow) continue;
dv.Rows[r + iRow].Cells[c + iCol].Value = valuesInRow[iCol];
}
}
}
@@ -209,7 +220,7 @@ namespace WindowsFormsApp1
private Rectangle dragBoxFromMouseDown;
private int rowIndexFromMouseDown;
private int rowIndexOfItemUnderMouseToDrop;
public void MouseMove(object sender, MouseEventArgs e)
{
DataGridView dataGridView = sender as DataGridView;
@@ -276,7 +287,7 @@ namespace WindowsFormsApp1
Helper_DB db = new Helper_DB();
db.DBcon();
if (Pur == "") { MessageBox.Show("입력된 주문처가 없습니다!"); return "False"; }
if (Pur == "") { UTIL.MsgE("입력된 주문처가 없습니다!"); return "False"; }
string Area = "`comp_name`, `tel`, `fax`, `bubin`, `uptae`, " +
"`jongmok`, `addr`, `boss`, `email`, `barea`";
@@ -292,28 +303,35 @@ namespace WindowsFormsApp1
string[] db_data = db_res1.Split('|');
string[] db_pur = db_res2.Split('|');
if (db_res1.Length < 3) {
MessageBox.Show("DB호출 에러!", "Error");
if (db_res1.Length < 3)
{
UTIL.MsgE("DB호출 에러!");
return "False";
}
string tel = string.Empty;
string fax = string.Empty;
string emchk = string.Empty;
if (db_pur.Length > 3) {
for(int a= 0; a < db_pur.Length; a++)
if (db_pur.Length > 3)
{
for (int a = 0; a < db_pur.Length; a++)
{
if (a % 3 == 0) { // 전화번호
if (db_pur[a] != "") {
if (a % 3 == 0)
{ // 전화번호
if (db_pur[a] != "")
{
tel = db_pur[a];
}
}
if (a % 3 == 1) { // 팩스
if (db_pur[a] != "") {
if (a % 3 == 1)
{ // 팩스
if (db_pur[a] != "")
{
fax = db_pur[a];
}
}
if (a % 3 == 2) { // 팩스 이메일 체크
if (a % 3 == 2)
{ // 팩스 이메일 체크
emchk = db_pur[a];
}
}
@@ -360,7 +378,7 @@ namespace WindowsFormsApp1
// 엑셀 파일 이름 설정
string now = DateTime.Now.ToString("yy-MM-dd-HH-mm");
string FileName = string.Format("{0}_{1}_{2}_{3}.xlsx", now.Replace("-", ""), emchk, Pur, db_data[0]);
MessageBox.Show(FileName);
UTIL.MsgI(FileName);
// 엑셀 파일 저장 경로
string Savepath = Path.Combine(tempPath, FileName);
@@ -401,7 +419,7 @@ namespace WindowsFormsApp1
#region / (4)
rng = ws.Range["A4", "C4"];
rng.MergeCells = true;
rng.Value2 = "주문일자 : "+DateTime.Now.ToString("yyyy-MM-dd H:m:ss");
rng.Value2 = "주문일자 : " + DateTime.Now.ToString("yyyy-MM-dd H:m:ss");
rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
rng.Font.Bold = true;
@@ -495,7 +513,7 @@ namespace WindowsFormsApp1
#region
endcount++;
string = "D"+endcount.ToString();
string = "D" + endcount.ToString();
rng = ws.Range["A" + endcount, "C" + endcount];
rng.MergeCells = true;
@@ -551,7 +569,7 @@ namespace WindowsFormsApp1
rng2.Font.Bold = true;
////////
rng = ws.Range[, "D"+endcount];
rng = ws.Range[, "D" + endcount];
rng.MergeCells = true;
rng.Value2 = "발 송 처";
rng.Font.Bold = true;
@@ -580,12 +598,12 @@ namespace WindowsFormsApp1
application.Interactive = true;
application.Quit();
return FileName;
}
catch(Exception e)
catch (Exception e)
{
MessageBox.Show(e.ToString());
UTIL.MsgE(e.ToString());
return "False";
}
}
@@ -623,16 +641,16 @@ namespace WindowsFormsApp1
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
UTIL.MsgE(e.ToString());
}
}
#region MK_Excel_Sub
private string Excel_Sub(string[] data)
{
string[] length = {
"1", "2", "3", "4", "5",
"6", "7", "8", "9", "10",
"11", "12", "13", "14", "15",
"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"
};
@@ -646,8 +664,8 @@ namespace WindowsFormsApp1
string count = data.Length.ToString();
string res = string.Empty;
for(int a = 0; a < length.Length; a++)
for (int a = 0; a < length.Length; a++)
{
if (length[a] == count)
{
@@ -658,7 +676,7 @@ namespace WindowsFormsApp1
}
#endregion
}
public class Helper_Print
public class Helper_Print
{
/// <summary>
/// 행의 갯수
@@ -788,7 +806,7 @@ namespace WindowsFormsApp1
/// <param name="file_name"></param>
/// <param name="fax_param">[0] 발신번호 / [1] 수신번호
/// / [2] 수신자 회사명 / [3 ]수신자명 </param>
public string Send_BaroFax(string file_name, string[] fax_param )
public string Send_BaroFax(string file_name, string[] fax_param)
{
BaroService_FAXSoapClient fAXSoapClient = new BaroService_FAXSoapClient();
@@ -807,9 +825,9 @@ namespace WindowsFormsApp1
string ErrMsg = FAX_GetErrString(result);
if (ErrMsg != "")
MessageBox.Show(msg, "전송완료");
UTIL.MsgI(msg);
else
MessageBox.Show(ErrMsg, "Error");
UTIL.MsgE(ErrMsg);
return result;
}
@@ -824,7 +842,7 @@ namespace WindowsFormsApp1
BaroService_FAXSoapClient fAXSoapClient = new BaroService_FAXSoapClient();
// 수신자회사명, 수신번호, 전송일시, 전송결과, 전송페이지수, 성공페이지수, 전송파일명
string[] MsgBox_Array = {
string[] MsgBox_Array = {
fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).ReceiveCorp,
fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).ReceiverNum,
fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).SendDT,
@@ -1190,9 +1208,9 @@ namespace WindowsFormsApp1
public bool IsConnected { get; set; }
private string ipAddr = string.Empty;
private string Port = string.Empty;
private string Port = string.Empty;
private string userId = string.Empty;
private string Pwd = string.Empty;
private string Pwd = string.Empty;
public FTP() { }
@@ -1219,7 +1237,7 @@ namespace WindowsFormsApp1
using (ftpRequest.GetResponse()) { }
this.IsConnected = true;
}
catch(Exception ex)
catch (Exception ex)
{
this.LastException = ex;
System.Reflection.MemberInfo info = System.Reflection.MethodInfo.GetCurrentMethod();
@@ -1288,9 +1306,9 @@ namespace WindowsFormsApp1
buff = null;
}
}
catch(Exception ex)
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
UTIL.MsgE(ex.ToString());
this.LastException = ex;
System.Reflection.MemberInfo info = System.Reflection.MethodInfo.GetCurrentMethod();
string id = string.Format("{0}.{1}", info.ReflectedType.Name, info.Name);
@@ -1309,8 +1327,6 @@ namespace WindowsFormsApp1
string url = string.Format(@"FTP://{0}:{1}/{2}", ipAddr, Port, serverFullPathFile);
FtpWebRequest ftp = (FtpWebRequest)WebRequest.Create(url);
MessageBox.Show(url);
ftp.Credentials = new NetworkCredential(userId, Pwd);
ftp.KeepAlive = false;
ftp.UseBinary = true;
@@ -1348,7 +1364,7 @@ namespace WindowsFormsApp1
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
UTIL.MsgE(ex.ToString());
this.LastException = ex;
if (serverFullPathFile.Contains(@"\ZOOM\"))
@@ -1392,14 +1408,14 @@ namespace WindowsFormsApp1
if (reader != null) reader.Close();
foreach(string file in result.ToString().Split('\n'))
foreach (string file in result.ToString().Split('\n'))
{
resultList.Add(file);
}
}
return resultList;
}
catch(Exception ex)
catch (Exception ex)
{
this.LastException = ex;
@@ -1420,12 +1436,12 @@ namespace WindowsFormsApp1
try
{
foreach(string tmpFolder in arrDir)
foreach (string tmpFolder in arrDir)
{
try
{
if (tmpFolder == string.Empty) continue;
currentDir += @"/" + tmpFolder;
string url = string.Format(@"FTP://{0}:{1}/{2}", this.ipAddr, this.Port, currentDir);
@@ -1453,9 +1469,11 @@ namespace WindowsFormsApp1
private void checkDir(string localFullPathFile)
{
FileInfo finfo = new FileInfo(localFullPathFile);
if (!finfo.Exists) {
if (!finfo.Exists)
{
DirectoryInfo dInfo = new DirectoryInfo(finfo.DirectoryName);
if (!dInfo.Exists) {
if (!dInfo.Exists)
{
dInfo.Create();
}
}
@@ -1552,30 +1570,35 @@ namespace WindowsFormsApp1
int tDown = 0;
for (int a = 0; a < array_text.Count; a++)
{
// if (array_text[a] == "") continue;
// if (array_text[a] == "") continue;
num.Add(array_text[a].Substring(0, 3));
if (array_text[a][5] == '▼') {
if (array_text[a][5] == '▼')
{
array_text[a] = array_text[a].Remove(0, 3);
}
else {
else
{
array_text[a] = array_text[a].Remove(0, 5);
}
+= array_text[a] + "\n";
int textLength = 0;
if (EncodingType == "UTF-8") {
if (EncodingType == "UTF-8")
{
textLength = Encoding.UTF8.GetBytes(array_text[a]).Length
- WordCheck(array_text[a], "▲")
- WordCheck(array_text[a], "▼");
}
else if (EncodingType == "UniCode") {
else if (EncodingType == "UniCode")
{
textLength = Encoding.Unicode.GetBytes(array_text[a]).Length
- WordCheck(array_text[a], "▲")
- WordCheck(array_text[a], "▼");
}
else { // ANSI
else
{ // ANSI
textLength = Encoding.Default.GetBytes(array_text[a]).Length
- WordCheck(array_text[a], "▲")
- WordCheck(array_text[a], "▼");
@@ -1587,12 +1610,13 @@ namespace WindowsFormsApp1
for (int a = 0; a < array_text.Count; a++)
{
if (a == 0) { //total.Add("0");
if (a == 0)
{ //total.Add("0");
tTotal.Add(0);
}
else
{
// total.Add(total[a - 1] + count[a - 1]);
// total.Add(total[a - 1] + count[a - 1]);
tTotal.Add(tTotal[a - 1] + tCount[a - 1]);
}
//else if (a == 1)
@@ -1609,7 +1633,7 @@ namespace WindowsFormsApp1
// else c = Convert.ToInt32(Encoding.Default.GetBytes(array_text[a - 2]).Length.ToString()) - WordCheck(array_text[a - 2], "▲") - WordCheck(array_text[a - 2], "▼");
// int res = b + c;
// total.Add(res.ToString());
}
string[] str_num = num.ToArray();
@@ -1626,7 +1650,7 @@ namespace WindowsFormsApp1
// else if (total[a].Length == 2) { total[a] = total[a].Insert(0, "000"); }
// else if (total[a].Length == 1) { total[a] = total[a].Insert(0, "0000"); }
// 디렉토리 += str_num[a] + count[a] + total[a] + "\n";
+= str_num[a] + tCount[a].ToString().PadLeft(4, '0') + tTotal[a].ToString().PadLeft(5, '0');
+= str_num[a] + tCount[a].ToString().PadLeft(4, '0') + tTotal[a].ToString().PadLeft(5, '0');
}
string[] = { "00000","n", "a", "m", " ",
@@ -1642,11 +1666,11 @@ namespace WindowsFormsApp1
string dp = + ;
int recode = 0;
if (EncodingType == "UTF-8") recode = Encoding.UTF8.GetBytes(dp).Length- WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
if (EncodingType == "UTF-8") recode = Encoding.UTF8.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
else if (EncodingType == "UniCode") recode = Encoding.Unicode.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
else recode = Encoding.Default.GetBytes(dp).Length- WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
else recode = Encoding.Default.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
[0] = insert_Zero(recode + 24, 5);
int data_addr = 24 + Encoding.Default.GetBytes().Length - WordCheck(, "▲");
@@ -1693,7 +1717,7 @@ namespace WindowsFormsApp1
return result;
}
#endregion
/// <summary>
/// 추가하고 싶은 태그를 뷰형태의 마크에 추가하는 함수.
@@ -1706,7 +1730,7 @@ namespace WindowsFormsApp1
if (Tag.Length < 3) return "";
int TargetTagNum = Convert.ToInt32(Tag.Substring(0, 3));
string[] SplitView = TypeView.Split('\n');
List<string> View = new List<string>(SplitView);
@@ -1731,9 +1755,9 @@ namespace WindowsFormsApp1
/// <param name="pAddTag">추가할 태그 (태그명\t지시기호\t태그내용)</param>
/// <param name="pTargetData">뷰형태의 마크</param>
/// <returns></returns>
public string AddTagInMarc(int pTargetTagNum,string pAddTag, string pTargetData)//TagTarget Num 을 찾아서 있을경우는 해당 Tag 데이터를 전송, 없을경우는 신규로 해야함.
public string AddTagInMarc(int pTargetTagNum, string pAddTag, string pTargetData)//TagTarget Num 을 찾아서 있을경우는 해당 Tag 데이터를 전송, 없을경우는 신규로 해야함.
{
if (pAddTag.Length < 3) return "";
string tRet = pTargetData;
// ex ) 020 : ~~~ 에 XXXX 내용줄 뒤에 추가
@@ -1827,7 +1851,7 @@ namespace WindowsFormsApp1
}
}
}
}
}
else
{// 기존 태그 변경
int endIdx = SplitView[a].IndexOf("▼", startIdx + 1);
@@ -1906,9 +1930,9 @@ namespace WindowsFormsApp1
/// <param name="marc">마크 데이터</param>
/// <param name="search">추출할 함수(배열)</param>
/// <returns></returns>
public string[] Take_Tag(string marc, string[] search,bool pSearchTag = false)
public string[] Take_Tag(string marc, string[] search, bool pSearchTag = false)
{
string[] ary = marc.Split('');
string[] ary = marc.Split(''); //0x1E
string[] tag = res_dir(ary[0].Substring(24));
(string[] jisi, string[] mrc) = jisi_Symbol(tag, ary);
@@ -1958,7 +1982,7 @@ namespace WindowsFormsApp1
//memo = result[b];
start += 2;
int end = -1;
if (tmp.Length > 1) end=tmp.IndexOf("", start);
if (tmp.Length > 1) end = tmp.IndexOf("", start);
if (memo == result[b])
break;
@@ -2130,9 +2154,14 @@ namespace WindowsFormsApp1
/// </summary>
/// <param name="Marc">한줄짜리 마크</param>
/// <returns></returns>
public string ConvertMarcType(string Marc)
public string ConvertMarcType(string Marc, out string errmessage)
{
if (Marc.Length < 3) return "";
errmessage = string.Empty;
if (Marc.Length < 3)
{
errmessage = "MARC 데이터길이가 너무 짧습니다.";
return "";
}
string result = "";
@@ -2140,12 +2169,15 @@ namespace WindowsFormsApp1
List<string> Field = new List<string>(); // 가변길이필드 저장용
Marc = Marc.Replace("", "▼").Replace("", "▲");
Marc = Marc.Replace(((char)0x1D).ToString(), "");
Marc = Marc.Replace(((char)0x1E).ToString(), "");
Marc = Marc.Replace(((char)0x1F).ToString(), "");
int StartIdx = 0;
// 리더부를 제외한 디렉토리, 가변길이필드 저장
string[] data = Marc.Substring(24).Split('▲');
for (int a = 1; a < data.Length - 1; a++)
string[] data = Marc.Substring(24).Split(new char[] { '▲' }, StringSplitOptions.RemoveEmptyEntries);
for (int a = 1; a < data.Length; a++)
{
TagNum.Add(data[0].Substring(StartIdx, 3));
StartIdx += 12;
@@ -2161,10 +2193,32 @@ namespace WindowsFormsApp1
else if (res.StartsWith("00")) { res += "\t \t" + Field[a]; }
else
{
string temp = Field[a].Insert(2, "\t");
res += "\t" + temp;
var fieldValue = Field[a].Trim();
bool isEmpty = false;
if (fieldValue.IndexOf("▼") != -1)
{
var dataArea = fieldValue.Substring(fieldValue.IndexOf("▼") + 1);
isEmpty = dataArea.ToString().isEmpty();
}
else
{
isEmpty = fieldValue.Replace("▲", "").Trim().isEmpty();
}
if (isEmpty) //no data
{
errmessage = (errmessage.isEmpty() == false ? "\n" : "") + "태그 " + TagNum[a] + " 에 데이터가 없습니다.";
Console.WriteLine("field length error");
res = string.Empty;
}
else
{
string temp = Field[a].Insert(2, "\t");
res += "\t" + temp;
}
}
result += res + "\n";
if (res.isEmpty() == false)
result += res + "\n";
}
return result;
}
@@ -2188,7 +2242,8 @@ namespace WindowsFormsApp1
/// <param name="e">EventArgs</param>
public void Int_Comma(object sender, EventArgs e)
{
if (((TextBox)sender).Text != "") {
if (((TextBox)sender).Text != "")
{
string text;
text = ((TextBox)sender).Text.Replace(",", "");
((TextBox)sender).Text = String.Format("{0:#,###}", Convert.ToInt32(text));
@@ -2204,7 +2259,7 @@ namespace WindowsFormsApp1
public bool isContainHangul(string value)
{
char[] charArr = value.ToCharArray();
foreach(char c in charArr)
foreach (char c in charArr)
{
if (char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
return true;
@@ -2221,7 +2276,7 @@ namespace WindowsFormsApp1
public bool CheckString(string value, string chkString)
{
int index = value.IndexOf(chkString);
if (index < 0)
if (index < 0)
return false;
return true;
@@ -2264,10 +2319,10 @@ namespace WindowsFormsApp1
public class API
{
public string CheckString(string pText,string pStr)
public string CheckString(string pText, string pStr)
{
string tRet = pText;
Regex reg = new Regex(@"([\"+pStr+"]+)" + @"[가-힣]+");//+ @"([\>]+)");//new Regex(@"([\<]+)"+ @"[ㄱ-ㅎ가-힣]+"+@"([\>]+)");
Regex reg = new Regex(@"([\" + pStr + "]+)" + @"[가-힣]+");//+ @"([\>]+)");//new Regex(@"([\<]+)"+ @"[ㄱ-ㅎ가-힣]+"+@"([\>]+)");
MatchCollection tMatch = reg.Matches(tRet);
for (int i = 0; i < tMatch.Count; i++)
{
@@ -2285,9 +2340,9 @@ namespace WindowsFormsApp1
/// <param name="QueryType"></param>
/// <param name="Param"></param>
/// <returns></returns>
public string Aladin(string Query, string QueryType, string[] Param)
public List<string> Aladin(string Query, string QueryType, string[] Param)
{
string result = string.Empty;
List<string> result = new List<string>();
// 쿼리 생성
string key = "ttbgloriabook1512001";
string site = "http://www.aladin.co.kr/ttb/api/ItemSearch.aspx";
@@ -2326,8 +2381,9 @@ namespace WindowsFormsApp1
xml = CheckString(xml, "〈");
doc.LoadXml(xml);
}
catch (Exception ex){
return "";
catch (Exception ex)
{
return result;
}
var json = JsonConvert.SerializeXmlNode(doc);
@@ -2345,7 +2401,7 @@ namespace WindowsFormsApp1
}
catch
{
return "";
return result;
}
int length = 0;
int ID_length = Param.Length;
@@ -2362,6 +2418,7 @@ namespace WindowsFormsApp1
object buf = docs;
length = 1;
}
// List<string> retval = new List<string>();
for (int a = 0; a < length; a++)
{
List<string> tmp_data = new List<string>();
@@ -2375,9 +2432,10 @@ namespace WindowsFormsApp1
{
tmp_data.Add(docs[a][Param[b]]);
}
result += tmp_data[b].Replace("|", "") + "|";
result.Add(tmp_data[b].Replace("|", ""));
//result += tmp_data[b].Replace("|", "") + "|";
}
result += "\n";
//result += "\n";
}
return result;
}
@@ -2402,7 +2460,7 @@ namespace WindowsFormsApp1
}
else
{
MessageBox.Show(status, "Error");
UTIL.MsgE(status);
return "Error";
}
@@ -2520,19 +2578,23 @@ namespace WindowsFormsApp1
{
if (length == 1)
{
try {
try
{
tmp_data.Add(docs[Param[b]]["#text"]);
}
catch (KeyNotFoundException e) {
catch (KeyNotFoundException e)
{
tmp_data.Add("");
}
}
else
{
try {
try
{
tmp_data.Add(docs[a][Param[b]]["#text"]);
}
catch (KeyNotFoundException e) {
catch (KeyNotFoundException e)
{
tmp_data.Add("");
}
}
@@ -2649,8 +2711,8 @@ namespace WindowsFormsApp1
return dialogResult;
}
}
public class PrintLine
{
public class PrintLine
{
string num { get; set; }
string count { get; set; }
string list_name { get; set; }
@@ -2944,26 +3006,54 @@ namespace WindowsFormsApp1
public class IP
{
/// <summary>
/// 현 PC의 외부아이피를 가져옴
/// 프로그램에서 가져올 방법이 딱히 없어 꼼수로 웹사이트 크롤링을 통해 가져옴
/// </summary>
public string GetIP
public string GetIP()
{
get
{
string externalIp = new WebClient().DownloadString("http://ipinfo.io/ip").Trim(); // http://icanhazip.com
// 최신 사이트 접속을 위한 TLS 1.2 활성화 (강제 지정)
// Windows 7 / .NET 4.0에서는 이 설정이 없으면 HTTPS 접속이 실패할 수 있습니다.
try { ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; } catch { }
if (string.IsNullOrWhiteSpace(externalIp))
externalIp = GetIP;
return externalIp;
string[] urls = {
"http://checkip.amazonaws.com",
"http://ipinfo.io/ip",
"https://api.ipify.org"
};
foreach (var url in urls)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 2000;
// 브라우저처럼 보이게 하기 위해 User-Agent 추가 (많은 사이트가 이를 요구함)
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
string ip = reader.ReadToEnd().Trim();
// IP 형식인지 검증
IPAddress address;
if (IPAddress.TryParse(ip, out address))
{
// IPv4인 경우에만 반환 (필요시 IPv6 허용 가능)
if (address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
return ip;
}
}
}
catch { continue; } // 다음 URL 시도
}
return "IP 확인 실패";
}
public string VersionInfo()
{
string version = "0";
var fn = Application.StartupPath + "\\update.inf";
if(System.IO.File.Exists(fn))
if (System.IO.File.Exists(fn))
{
StreamReader sr = new StreamReader(fn);
while (!sr.EndOfStream)
@@ -2976,7 +3066,7 @@ namespace WindowsFormsApp1
}
}
}
return version;
}
}

View File

@@ -0,0 +1,169 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
namespace UniMarc
{
public class SortableBindingList<T> : BindingList<T>, IBindingListView
{
private bool _isSorted;
private ListSortDirection _sortDirection;
private PropertyDescriptor _sortProperty;
private string _filter;
private readonly List<T> _originalItems = new List<T>();
public SortableBindingList() : base() { }
public SortableBindingList(IList<T> list) : base(list)
{
foreach (var item in list)
_originalItems.Add(item);
}
protected override void OnListChanged(ListChangedEventArgs e)
{
if (e.ListChangedType == ListChangedType.ItemAdded)
{
_originalItems.Insert(e.NewIndex, this[e.NewIndex]);
}
else if (e.ListChangedType == ListChangedType.ItemDeleted)
{
// This is slightly tricky if filtered, but we assume basic usage for now
// Ideally we'd track IDs
}
base.OnListChanged(e);
}
#region Sorting
protected override bool SupportsSortingCore => true;
protected override bool IsSortedCore => _isSorted;
protected override ListSortDirection SortDirectionCore => _sortDirection;
protected override PropertyDescriptor SortPropertyCore => _sortProperty;
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
var items = this.Items as List<T>;
if (items != null)
{
PropertyComparer<T> pc = new PropertyComparer<T>(prop, direction);
items.Sort(pc);
_isSorted = true;
_sortDirection = direction;
_sortProperty = prop;
}
else
{
_isSorted = false;
}
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
protected override void RemoveSortCore()
{
_isSorted = false;
_sortProperty = null;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
#endregion
#region Filtering (IBindingListView)
public string Filter
{
get => _filter;
set
{
_filter = value;
if (string.IsNullOrEmpty(_filter))
RemoveFilter();
else
ApplyFilter(_filter);
}
}
public bool SupportsFiltering => true;
public void ApplyFilter(string filter)
{
_filter = filter;
if (_originalItems.Count == 0 && this.Count > 0)
{
foreach (var item in this) _originalItems.Add(item);
}
// Simple parser for "Property=Value" or "Property='Value'"
var parts = filter.Split('=');
if (parts.Length != 2) return;
string propName = parts[0].Trim();
string valStr = parts[1].Trim().Trim('\'');
var prop = TypeDescriptor.GetProperties(typeof(T))[propName];
if (prop == null) return;
this.RaiseListChangedEvents = false;
this.Clear();
foreach (var item in _originalItems)
{
var val = prop.GetValue(item);
if (val != null && val.ToString().Equals(valStr, StringComparison.OrdinalIgnoreCase))
{
this.Add(item);
}
}
this.RaiseListChangedEvents = true;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
public void RemoveFilter()
{
_filter = null;
if (_originalItems.Count > 0)
{
this.RaiseListChangedEvents = false;
this.Clear();
foreach (var item in _originalItems) this.Add(item);
this.RaiseListChangedEvents = true;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
public ListSortDescriptionCollection SortDescriptions => null;
public bool SupportsAdvancedSorting => false;
public void ApplySort(ListSortDescriptionCollection sorts) => throw new NotSupportedException();
#endregion
private class PropertyComparer<TItem> : IComparer<TItem>
{
private readonly PropertyDescriptor _prop;
private readonly ListSortDirection _direction;
public PropertyComparer(PropertyDescriptor prop, ListSortDirection direction)
{
_prop = prop;
_direction = direction;
}
public int Compare(TItem x, TItem y)
{
object xVal = _prop.GetValue(x);
object yVal = _prop.GetValue(y);
int result;
if (xVal == null && yVal == null) result = 0;
else if (xVal == null) result = -1;
else if (yVal == null) result = 1;
else if (xVal is IComparable comparable)
result = comparable.CompareTo(yVal);
else if (xVal.Equals(yVal))
result = 0;
else
result = xVal.ToString().CompareTo(yVal.ToString());
return _direction == ListSortDirection.Ascending ? result : -result;
}
}
}
}

136
unimarc/unimarc/UC_SelectGrade.Designer.cs generated Normal file
View File

@@ -0,0 +1,136 @@
namespace UniMarc
{
partial class UC_SelectGrade
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
this.radD = new System.Windows.Forms.RadioButton();
this.radC = new System.Windows.Forms.RadioButton();
this.radB = new System.Windows.Forms.RadioButton();
this.radA = new System.Windows.Forms.RadioButton();
this.label6 = new System.Windows.Forms.Label();
this.radE = new System.Windows.Forms.RadioButton();
this.SuspendLayout();
//
// radD
//
this.radD.AutoSize = true;
this.radD.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.radD.Location = new System.Drawing.Point(147, 4);
this.radD.Name = "radD";
this.radD.Size = new System.Drawing.Size(34, 20);
this.radD.TabIndex = 328;
this.radD.TabStop = true;
this.radD.Text = "D";
this.radD.UseVisualStyleBackColor = true;
//
// radC
//
this.radC.AutoSize = true;
this.radC.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.radC.Location = new System.Drawing.Point(112, 4);
this.radC.Name = "radC";
this.radC.Size = new System.Drawing.Size(33, 20);
this.radC.TabIndex = 327;
this.radC.TabStop = true;
this.radC.Text = "C";
this.radC.UseVisualStyleBackColor = true;
//
// radB
//
this.radB.AutoSize = true;
this.radB.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.radB.Location = new System.Drawing.Point(77, 4);
this.radB.Name = "radB";
this.radB.Size = new System.Drawing.Size(33, 20);
this.radB.TabIndex = 326;
this.radB.TabStop = true;
this.radB.Text = "B";
this.radB.UseVisualStyleBackColor = true;
//
// radA
//
this.radA.AutoSize = true;
this.radA.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.radA.Location = new System.Drawing.Point(40, 4);
this.radA.Name = "radA";
this.radA.Size = new System.Drawing.Size(35, 20);
this.radA.TabIndex = 325;
this.radA.TabStop = true;
this.radA.Text = "A";
this.radA.UseVisualStyleBackColor = true;
//
// label6
//
this.label6.AutoSize = true;
this.label6.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.label6.Location = new System.Drawing.Point(7, 8);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(31, 12);
this.label6.TabIndex = 324;
this.label6.Text = "등급";
//
// radE
//
this.radE.AutoSize = true;
this.radE.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.radE.Location = new System.Drawing.Point(183, 4);
this.radE.Name = "radE";
this.radE.Size = new System.Drawing.Size(32, 20);
this.radE.TabIndex = 329;
this.radE.TabStop = true;
this.radE.Text = "E";
this.radE.UseVisualStyleBackColor = true;
//
// UC_SelectGrade
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.Controls.Add(this.radE);
this.Controls.Add(this.radD);
this.Controls.Add(this.radC);
this.Controls.Add(this.radB);
this.Controls.Add(this.radA);
this.Controls.Add(this.label6);
this.Name = "UC_SelectGrade";
this.Size = new System.Drawing.Size(221, 29);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.RadioButton radD;
private System.Windows.Forms.RadioButton radC;
private System.Windows.Forms.RadioButton radB;
private System.Windows.Forms.RadioButton radA;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.RadioButton radE;
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace UniMarc
{
public partial class UC_SelectGrade : UserControl
{
public UC_SelectGrade()
{
InitializeComponent();
}
public string GradeName
{
get
{
if(Grade == 0) return "A";
else if (Grade == 1) return "B";
else if (Grade == 2) return "C";
else if (Grade == 3) return "D";
else if (Grade == 4) return "E";
else return "";
}
set
{
if (value == "A") Grade = 0;
else if (value == "B") Grade = 1;
else if (value == "C") Grade = 2;
else if (value == "D") Grade = 3;
else if (value == "E") Grade = 4;
else Grade = -1;
}
}
public int Grade
{
get
{
if (radA.Checked) return 0;
else if (radB.Checked) return 1;
else if (radC.Checked) return 2;
else if (radD.Checked) return 3;
else if (radE.Checked) return 4;
else return -1;
}
set
{
if (value == -1)
{
radA.Checked = false;
radB.Checked = false;
radC.Checked = false;
radD.Checked = false;
radE.Checked = false;
}
else if (value == 0) radA.Checked = true;
else if (value == 1) radB.Checked = true;
else if (value == 2) radC.Checked = true;
else if (value == 3) radD.Checked = true;
else if (value == 4) radE.Checked = true;
}
}
}
}

View File

@@ -224,6 +224,17 @@
<DesignTime>True</DesignTime>
<DependentUpon>Reference.svcmap</DependentUpon>
</Compile>
<Compile Include="DB_Utils.cs" />
<Compile Include="Helper\Database.cs" />
<Compile Include="Models\MarcBasicInfo.cs" />
<Compile Include="Helper\MarcParser.cs" />
<Compile Include="Helper_LibraryDelaySettings.cs" />
<Compile Include="ListOfValue\fSelectDT.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ListOfValue\fSelectDT.Designer.cs">
<DependentUpon>fSelectDT.cs</DependentUpon>
</Compile>
<Compile Include="PUB.cs" />
<Compile Include="SearchModel\AnsanLibSearcher.cs" />
<Compile Include="SearchModel\BookSearchService.cs" />
@@ -236,6 +247,7 @@
<Compile Include="SearchModel\DownloadProgressForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="SearchModel\GochangLibSearcher.cs" />
<Compile Include="SearchModel\GoheungLibSearcher.cs" />
<Compile Include="SearchModel\GwangjuCityLibSearcher.cs" />
<Compile Include="SearchModel\GwangjuDongguLibSearcher.cs" />
@@ -247,6 +259,7 @@
<Compile Include="SearchModel\IksanLibSearcher.cs" />
<Compile Include="SearchModel\ILibrarySearcher.cs" />
<Compile Include="SearchModel\JeonbukEduLibSearcher.cs" />
<Compile Include="SearchModel\JeonnamProvLibSearcher.cs" />
<Compile Include="SearchModel\KcmLibSearcher.cs" />
<Compile Include="SearchModel\MokpoLibSearcher.cs" />
<Compile Include="SearchModel\MuanLibSearcher.cs" />
@@ -258,18 +271,43 @@
<Compile Include="SearchModel\JunnamEduSearcher.cs" />
<Compile Include="SearchModel\NamguLibrarySearcher.cs" />
<Compile Include="SearchModel\SeleniumHelper.cs" />
<Compile Include="SortableBindingList.cs" />
<Compile Include="UC_SelectGrade.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="UC_SelectGrade.Designer.cs">
<DependentUpon>UC_SelectGrade.cs</DependentUpon>
</Compile>
<Compile Include="개발자용\fDevDB.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="개발자용\fDevDB.Designer.cs">
<DependentUpon>fDevDB.cs</DependentUpon>
</Compile>
<Compile Include="납품관리\Book_Lookup2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="납품관리\Book_Lookup2.Designer.cs">
<DependentUpon>Book_Lookup2.cs</DependentUpon>
</Compile>
<Compile Include="납품관리\Order_input_Search2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="납품관리\Order_input_Search2.Designer.cs">
<DependentUpon>Order_input_Search2.cs</DependentUpon>
</Compile>
<Compile Include="마스터\From_User_manage_List.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마스터\From_User_manage_List.Designer.cs">
<DependentUpon>From_User_manage_List.cs</DependentUpon>
</Compile>
<Compile Include="마크\AddMarc2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\AddMarc2.Designer.cs">
<DependentUpon>AddMarc2.cs</DependentUpon>
</Compile>
<Compile Include="마크\AddMarc.cs">
<SubType>Form</SubType>
</Compile>
@@ -282,6 +320,7 @@
<Compile Include="마크\AddMarc_FillBlank.Designer.cs">
<DependentUpon>AddMarc_FillBlank.cs</DependentUpon>
</Compile>
<Compile Include="Models\BookGridItem.cs" />
<Compile Include="마크\CD_LP.cs">
<SubType>Form</SubType>
</Compile>
@@ -324,6 +363,37 @@
<Compile Include="마크\Check_Copy_Login.Designer.cs">
<DependentUpon>Check_Copy_Login.cs</DependentUpon>
</Compile>
<Compile Include="마크\Check_Copy_Sub_Selector.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Check_Copy_Sub_Selector.Designer.cs">
<DependentUpon>Check_Copy_Sub_Selector.cs</DependentUpon>
</Compile>
<Compile Include="마크\Check_ISBN2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Check_ISBN2.Designer.cs">
<DependentUpon>Check_ISBN2.cs</DependentUpon>
</Compile>
<Compile Include="마크\Check_ISBN_ItemEdit.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Check_ISBN_ItemEdit.Designer.cs">
<DependentUpon>Check_ISBN_ItemEdit.cs</DependentUpon>
</Compile>
<Compile Include="마크\Check_ISBN_Sub2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Check_ISBN_Sub2.Designer.cs">
<DependentUpon>Check_ISBN_Sub2.cs</DependentUpon>
</Compile>
<Compile Include="마크\Check_ISBN_Yes242.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Check_ISBN_Yes242.Designer.cs">
<DependentUpon>Check_ISBN_Yes242.cs</DependentUpon>
</Compile>
<Compile Include="Models\FillBlankItem.cs" />
<Compile Include="마크\Help_007.cs">
<SubType>Form</SubType>
</Compile>
@@ -336,18 +406,57 @@
<Compile Include="마크\Help_008.Designer.cs">
<DependentUpon>Help_008.cs</DependentUpon>
</Compile>
<Compile Include="Models\IsbnGridItem.cs" />
<Compile Include="Models\MacEditorParameter.cs" />
<Compile Include="Models\MacListItem.cs" />
<Compile Include="마크\Mac_List_Add2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Mac_List_Add2.Designer.cs">
<DependentUpon>Mac_List_Add2.cs</DependentUpon>
</Compile>
<Compile Include="마크\Mac_List_Add.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Mac_List_Add.Designer.cs">
<DependentUpon>Mac_List_Add.cs</DependentUpon>
</Compile>
<Compile Include="마크\Mac_List_Edit.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Mac_List_Edit.Designer.cs">
<DependentUpon>Mac_List_Edit.cs</DependentUpon>
</Compile>
<Compile Include="Models\MarcBookItem.cs" />
<Compile Include="Models\MarcCopyItem.cs" />
<Compile Include="마크\MarcCopySelect2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\MarcCopySelect2.Designer.cs">
<DependentUpon>MarcCopySelect2.cs</DependentUpon>
</Compile>
<Compile Include="마크\MarcCopySelect.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\MarcCopySelect.Designer.cs">
<DependentUpon>MarcCopySelect.cs</DependentUpon>
</Compile>
<Compile Include="마크\MarcEditorControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="마크\MarcEditorControl.Designer.cs">
<DependentUpon>MarcEditorControl.cs</DependentUpon>
</Compile>
<Compile Include="마크\Marc.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Marc.designer.cs">
<DependentUpon>Marc.cs</DependentUpon>
</Compile>
<Compile Include="Models\MarcPlanItem.cs" />
<Compile Include="마크\Marc_CopyForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Marc_FillBlank.cs">
<SubType>Form</SubType>
</Compile>
@@ -459,6 +568,12 @@
<DependentUpon>Mac_Stat_Stat.cs</DependentUpon>
</Compile>
<Compile Include="마크\Marc_Macro_Sub.cs" />
<Compile Include="마크\Marc_mkList2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Marc_mkList2.Designer.cs">
<DependentUpon>Marc_mkList2.cs</DependentUpon>
</Compile>
<Compile Include="마크\Marc_mkList.cs">
<SubType>Form</SubType>
</Compile>
@@ -483,6 +598,12 @@
<Compile Include="마크\Marc_Plan_PrintLabel.Designer.cs">
<DependentUpon>Marc_Plan_PrintLabel.cs</DependentUpon>
</Compile>
<Compile Include="마크\fMarc_Editor.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\fMarc_Editor.Designer.cs">
<DependentUpon>fMarc_Editor.cs</DependentUpon>
</Compile>
<Compile Include="마크\Marc_Plan_Sub_MarcEdit.cs">
<SubType>Form</SubType>
</Compile>
@@ -519,11 +640,11 @@
<Compile Include="마크\Make_Document.Designer.cs">
<DependentUpon>Make_Document.cs</DependentUpon>
</Compile>
<Compile Include="마크\Marc.cs">
<Compile Include="마크\Marc2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Marc.designer.cs">
<DependentUpon>Marc.cs</DependentUpon>
<Compile Include="마크\Marc2.designer.cs">
<DependentUpon>Marc2.cs</DependentUpon>
</Compile>
<Compile Include="마크\Marc_memo.cs">
<SubType>Form</SubType>
@@ -531,11 +652,12 @@
<Compile Include="마크\Marc_memo.Designer.cs">
<DependentUpon>Marc_memo.cs</DependentUpon>
</Compile>
<Compile Include="마크\Search_Infor_Sub.cs">
<Compile Include="Models\SearchInforItem.cs" />
<Compile Include="마크\Search_Infor2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="마크\Search_Infor_Sub.Designer.cs">
<DependentUpon>Search_Infor_Sub.cs</DependentUpon>
<Compile Include="마크\Search_Infor2.Designer.cs">
<DependentUpon>Search_Infor2.cs</DependentUpon>
</Compile>
<Compile Include="마크\SHDocVw.cs" />
<Compile Include="마크\ShowDeleteMarc.cs">
@@ -988,12 +1110,27 @@
<Compile Include="작업일지\Work_Log.Designer.cs">
<DependentUpon>Work_Log.cs</DependentUpon>
</Compile>
<EmbeddedResource Include="ListOfValue\fSelectDT.resx">
<DependentUpon>fSelectDT.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UC_SelectGrade.resx">
<DependentUpon>UC_SelectGrade.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="개발자용\fDevDB.resx">
<DependentUpon>fDevDB.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="납품관리\Book_Lookup2.resx">
<DependentUpon>Book_Lookup2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="납품관리\Order_input_Search2.resx">
<DependentUpon>Order_input_Search2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마스터\From_User_manage_List.resx">
<DependentUpon>From_User_manage_List.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\AddMarc2.resx">
<DependentUpon>AddMarc2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\AddMarc.resx">
<DependentUpon>AddMarc.cs</DependentUpon>
</EmbeddedResource>
@@ -1021,18 +1158,51 @@
<EmbeddedResource Include="마크\Check_Copy_Login.resx">
<DependentUpon>Check_Copy_Login.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Check_Copy_Sub_Selector.resx">
<DependentUpon>Check_Copy_Sub_Selector.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Check_ISBN2.resx">
<DependentUpon>Check_ISBN2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Check_ISBN_ItemEdit.resx">
<DependentUpon>Check_ISBN_ItemEdit.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Check_ISBN_Sub2.resx">
<DependentUpon>Check_ISBN_Sub2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Check_ISBN_Yes242.resx">
<DependentUpon>Check_ISBN_Yes242.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Help_007.resx">
<DependentUpon>Help_007.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Help_008.resx">
<DependentUpon>Help_008.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Mac_List_Add2.resx">
<DependentUpon>Mac_List_Add2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Mac_List_Add.resx">
<DependentUpon>Mac_List_Add.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Mac_List_Edit.resx">
<DependentUpon>Mac_List_Edit.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\MarcCopySelect2.resx">
<DependentUpon>MarcCopySelect2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\MarcCopySelect.resx">
<DependentUpon>MarcCopySelect.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Marc.resx">
<DependentUpon>Marc.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\MarcEditorControl.resx">
<DependentUpon>MarcEditorControl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Marc_CopyForm.resx">
<DependentUpon>Marc_CopyForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Marc_FillBlank.resx">
<DependentUpon>Marc_FillBlank.cs</DependentUpon>
</EmbeddedResource>
@@ -1087,6 +1257,9 @@
<EmbeddedResource Include="마크\Mac_Stat_Stat.resx">
<DependentUpon>Mac_Stat_Stat.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Marc_mkList2.resx">
<DependentUpon>Marc_mkList2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Marc_mkList.resx">
<DependentUpon>Marc_mkList.cs</DependentUpon>
</EmbeddedResource>
@@ -1099,6 +1272,9 @@
<EmbeddedResource Include="마크\Marc_Plan_PrintLabel.resx">
<DependentUpon>Marc_Plan_PrintLabel.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\fMarc_Editor.resx">
<DependentUpon>fMarc_Editor.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Marc_Plan_Sub_MarcEdit.resx">
<DependentUpon>Marc_Plan_Sub_MarcEdit.cs</DependentUpon>
</EmbeddedResource>
@@ -1117,14 +1293,14 @@
<EmbeddedResource Include="마크\Make_Document.resx">
<DependentUpon>Make_Document.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Marc.resx">
<DependentUpon>Marc.cs</DependentUpon>
<EmbeddedResource Include="마크\Marc2.resx">
<DependentUpon>Marc2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Marc_memo.resx">
<DependentUpon>Marc_memo.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\Search_Infor_Sub.resx">
<DependentUpon>Search_Infor_Sub.cs</DependentUpon>
<EmbeddedResource Include="마크\Search_Infor2.resx">
<DependentUpon>Search_Infor2.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="마크\ShowDeleteMarc.resx">
<DependentUpon>ShowDeleteMarc.cs</DependentUpon>
@@ -1882,6 +2058,12 @@
<None Include="Connected Services\BaroService_TI\UniMarc.BaroService_TI.UpdateUserPWDResponse.datasource">
<DependentUpon>Reference.svcmap</DependentUpon>
</None>
<Content Include="Helper\sample_fullmarc.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Helper\sample_richtext.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="packages.config" />
<None Include="Properties\app.manifest" />
<None Include="Properties\Settings.settings">
@@ -2019,6 +2201,7 @@
<Content Include="Resources\3_2_1_목록.png" />
<Content Include="Resources\3_2_2_편목.png" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Selenium.WebDriver.4.34.0\build\Selenium.WebDriver.targets" Condition="Exists('..\packages\Selenium.WebDriver.4.34.0\build\Selenium.WebDriver.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View File

@@ -9,7 +9,7 @@
<ErrorReportUrlHistory />
<FallbackCulture>ko-KR</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
<ProjectView>ShowAllFiles</ProjectView>
<ProjectView>ProjectFiles</ProjectView>
</PropertyGroup>
<PropertyGroup>
<EnableSecurityDebugging>false</EnableSecurityDebugging>

Some files were not shown because too many files have changed in this diff Show More