프로그래밍 기술/웹 검색 엔진 만들기

11. 웹 검색 응용 만들기

언제나휴일 2017. 12. 7. 14:27
반응형

11. 웹 검색 응용 만들기


 

 이제 최종 사용자가 사용하는 검색 응용인 EH와 관리자가 사용할 응용인 WSE Manager를 만듭시다.

 

11.1 검색 응용 만들기

 

 EH 검색 응용은 최종 사용자가 검색 서비스를 이용하는 Windows Form 응용입니다. 검색 질의문을 입력하여 검색 요청하면 검색 결과를 확인할 수 있고 검색 결과의 웹 페이지로 쉽게 이동할 수 있는  프로그램입니다.

[그림 11.1] EH 실행 화면

[그림 11.1] EH 실행 화면

 

 EH 응용의 실행 화면은 [그림 11.1]과 같습니다. [그림 11.1] 1은 검색 결과 목록을 보여주는 컨트롤이며 2는 검색 결과 하나를 보여주는 컨트롤입니다. 이 부분은 관리자가 사용하는 WSE Manager 응용에서도 사용할 것으로 사용자 정의 컨트롤로 만들 것입니다.

 

 개발 순서는 검색 결과를 보여줄 컨트롤을 먼저 만들고 나서 EH 응용을 만들기로 합시다.

 

11.1.1 검색 결과를 보여줄 컨트롤 만들기

 

 검색 결과를 보여줄 컨트롤을 만듭시다. Windows Form 컨트롤 라이브러리 템플릿의 프로젝트를 추가하세요. 여기에서는 RankedUrlControlLib라고 정할게요.

 

 이 프로젝트에서는 검색 결과 하나를 보여주는 RankedUrlControl과 검색 결과 목록을 보여주는 RUListControl을 만들어 봅시다.

 

 마법사에서 기본으로 제공하는 컨트롤의 이름을 RankedUrlControl로 변경합시다. 그리고 자식 컨트롤을 배치합니다.

 

 자식 컨트롤은 검색 결과 페이지의 타이틀과 주소를 보여주는 Label 컨트롤과 검색 사이트로 이동하는 Button 컨트롤, 검색 결과 페이지의 내용을 보여주는 TextBox 컨트롤, 평가 점수를 보여주는 Label 컨트롤을 배치합시다. 

 

[그림 11.2] RankedUrlControl 자식 컨트롤 배치

[그림 11.2] RankedUrlControl 자식 컨트롤 배치

 

번호

컨트롤 이름

컨트롤 유형

설명

1

lb_title

Label

타이틀

2

lb_addr

Label

사이트 주소

3

btn_go

Button

바로가기 버튼

4

tbox_content

TextBox

페이지 내용

5

lb_score

Label

평가 점수

[ 11.1] RankedUrlControl의 자식 컨트롤

 

 먼저 바로가기 버튼을 클릭했을 때 이벤트 처리를 위한 대리자와 인자 클래스를 정의합시다.

public delegate void RUrlClickEventHandler(object sender,RUrlClickEventArgs e);

public class RUrlClickEventArgs:EventArgs

{

}

 

 RUrlClickEventArgs 클래스에는 현재 결과를 보여주고 있는 순위화 한 페이지 개체를 가져오기 속성을 제공합니다.

public RankedUrl RUrl

{

    get;

    private set;

}

 

 페이지 주소 가져오기 속성도 제공합시다.

public string Url

{

    get

    {

        return RUrl.Url;

    }

}

 

 생성자 메서드는 컨트롤 라이브러 내부에서만 생성할 수 있게 접근성을 internal로 지정하고 입력 인자로 결과를 보여주고 있는 순위화 한 페이지 개체를 받습니다. 그리고 속성을 설정합니다.

internal RUrlClickEventArgs(RankedUrl rurl)

{

    RUrl = rurl;

}

 

 ToString 메서드를 재정의하여 페이지 주소를 반환하게 합시다.

public override string ToString()

{

    return Url;

}

 

RUrlClickEventArgs.cs

using System;

using WSE_Core;

 

namespace RankedUrlControlLib

{

    /// <summary>

    ///  RankedUrlControl 바로 가기 버튼 클릭 이벤트 핸들러

    /// </summary>

    /// <param name="sender">이벤트 전송자</param>

    /// <param name="e">이벤트 처리 인자</param>

    public delegate void RUrlClickEventHandler(object sender,RUrlClickEventArgs e);

 

    /// <summary>

    /// RUrlClickEventHandler 이벤트 처리 인자 클래스

    /// </summary>

    public class RUrlClickEventArgs:EventArgs

    {

 

        /// <summary>

        /// 순위화  페이지 - 가져오기

        /// </summary>

        public RankedUrl RUrl

        {

            get;

            private set;

        }

 

        /// <summary>

        ///  페이지 주소 - 가져오기

        /// </summary>

        public string Url

        {

            get

            {

                return RUrl.Url;

            }

        }

        internal RUrlClickEventArgs(RankedUrl rurl)

        {

            RUrl = rurl;

        }

        /// <summary>

        /// ToString 메서드 재정의

        /// </summary>

        /// <returns> 페이지 주소</returns>

        public override string ToString()

        {

            return Url;

        }

    }

}

  

 이제 순위화 한 페이지 정보를 보여주는 RankedUrlControl을 구현합시다.

public partial class RankedUrlControl : UserControl

{

}

 

 멤버로 순위화 한 페이지 개체를 참조하는 필드를 선언합시다.

RankedUrl rurl;

 

 그리고 바로가기 버튼의 클릭 이벤트를 멤버로 선언합니다.

public event RUrlClickEventHandler RUClick = null;

 

 생성자 메서드는 마법사에 의해 만들어진 상태를 변경하지 않습니다.

public RankedUrlControl()

{

    InitializeComponent();

}

 

 순위화 한 페이지 개체를 설정하는 메서드를 제공합시다. 메서드의 입력 인자로 순위화 한 페이지 개체를 전달받습니다. 메서드 내부에서는 멤버 필드를 설정하고 각 컨트롤의 속성을 설정하는 작업을 수행합니다.

public void SetRankedUrl(RankedUrl rurl)

{

    this.rurl = rurl;

    lb_title.Text = rurl.PUrl.Title;

    lb_addr.Text = rurl.Url;

    tbox_content.Text = rurl.PUrl.Content;

    lb_score.Text = rurl.Score.ToString();

}

 

 바로가기 버튼 클릭 이벤트 핸들러를 추가합니다.

private void btn_go_Click(object sender, EventArgs e)

 

 이벤트 핸들러에서는 클릭 이벤트 멤버가 null이 아니면 설정한 클릭 이벤트가 있는 것이므로 순위화 한 페이지 개체를 입력 인자로 전달하여 이벤트를 Invoke 시킵니다.

if (RUClick != null)

{

    RUClick  (thisnew RUrlClickEventArgs(rurl));

}

 

RankedUrlControl.cs

using System;

using System.Windows.Forms;

using WSE_Core;

 

namespace RankedUrlControlLib

{

    /// <summary>

    /// 순위화  페이지 정보 컨트롤

    /// </summary>

    public partial class RankedUrlControl : UserControl

    {

        RankedUrl rurl;

 

        /// <summary>

        /// 바로가기 버튼 클릭 이벤트

        /// </summary>

        public event RUrlClickEventHandler RUClick  = null;

 

        /// <summary>

        /// 생성자 메서드

        /// </summary>

        public RankedUrlControl()

        {

            InitializeComponent();

        }

 

        /// <summary>

        /// 순위화  페이지 설정 메서드

        /// </summary>

        /// <param name="rurl"></param>

        public void SetRankedUrl(RankedUrl rurl)

        {

            this.rurl = rurl;

            lb_title.Text = rurl.PUrl.Title;

            lb_addr.Text = rurl.Url;

            tbox_content.Text = rurl.PUrl.Content;

            lb_score.Text = rurl.Score.ToString();

        }

 

        private void btn_go_Click(object sender, EventArgs e)

        {

            if (RUClick != null)

            {

                RUClick  (thisnew RUrlClickEventArgs(rurl));

            }

        }

    }

}

 

 이번에는 검색 결과를 포함하는 컬렉션 컨트롤을 정의합시다. 새 항목 추가에서 사용자 정의 컨트롤을 추가하세요. 여기서는 RUListControl이라 정할게요.

 

 RUListControl에는 자식 컨트롤로 RankedUrlControl을 보여주기 위함이며 검색 결과를 이용하여 동적으로 추가하는 작업을 수행합니다. 기본적인 자식 컨트롤을 배치하는 부분은 없습니다.

public partial class RUListControl : UserControl

{

}

 

 결과 항목을 자식으로 두어야 하므로 RankedUrlControl을 보관하는 컬렉션을 멤버가 있어야 합니다.

List<RankedUrlControl> children = new List<RankedUrlControl>();

 

 자식 컨트롤의 바로가기 버튼을 클릭하였을 때의 클릭 이벤트를 멤버로 선언합시다. 이는 RUListControl을 소유한 곳에서 처리하기 위한 이벤트 핸들러를 설정할 멤버입니다.

public event RUrlClickEventHandler RUClick  = null;

 

 생성자 메서드는 마법사에서 제공하는 것에서 변경할 것이 없습니다.

public RUListControl()

{

    InitializeComponent();

}

 

 결과 목록을 지우는 메서드도 제공합시다. 여기에서는 자식 컨트롤을 Dispose한 이후에 컨트롤 목록을 지웁니다.

public void Clear()

{

    foreach (RankedUrlControl rucon in children)

    {

        rucon.Dispose();

    }

    children.Clear();

}

 

 

 결과 항목을 추가하는 메서드를 제공합시다. 입력 인자로는 검색 결과인 순위화 한 페이지 개체를 받습니다.

public void AddRankedUrl(RankedUrl rurl)

 

 결과 항목을 보여줄 RankedUrlControl 개체를 생성하여 순위화 한 페이지 개체를 입력 인자로 설정합니다.

RankedUrlControl rucon = new RankedUrlControl();

rucon.SetRankedUrl(rurl);

 

 화면에 생성한 컨트롤을 배치하는데 이는 현재 추가한 자식의 개수에 따라 위치를 계산하여 배치합니다. 수치는 여러분이 작성하는 것에 맞게 설정하세요.

int ruc_cnt = children.Count;

rucon.Location = new Point(0, ruc_cnt * 200 + 24);

rucon.Height = 200;

rucon.Width = this.Width - 24;

rucon.Parent = this;

children.Add(rucon);

 

 그리고 자식 컨트롤을 클릭했을 때의 이벤트 핸들러를 등록합니다.

rucon. RUClick  += new RUrlClickEventHandler(rucon_Click);

 

 이벤트 핸들러에서는 자신을 포함하고 있는 곳에서 클릭 이벤트 핸들러를 등록한 것이 있으면 전달받은 이벤트를 bypass 해줍니다.

void rucon_Click(object sender, RUrlClickEventArgs e)

{

    if (RUClick != null)

    {

        RUClick  (sender, e);

    }

} 

 

RUListControl.cs

using System.Collections.Generic;

using System.Drawing;

using System.Windows.Forms;

using WSE_Core;

 

namespace RankedUrlControlLib

{

    /// <summary>

    /// 결과 항목 컨트롤

    /// </summary>

    public partial class RUListControl : UserControl

    {

        List<RankedUrlControl> children = new List<RankedUrlControl>();

 

        /// <summary>

        /// 바로가기 버튼 클릭 이벤트

        /// </summary>

        public event RUrlClickEventHandler RUClick  = null;

 

        /// <summary>

        /// 생성자 메서드

        /// </summary>

        public RUListControl()

        {

            InitializeComponent();

        }

 

        /// <summary>

        /// 자식 항목 지우기 메서드

        /// </summary>

        public void Clear()

        {

            foreach (RankedUrlControl rucon in children)

            {

                rucon.Dispose();

            }

            children.Clear();

        }

 

        /// <summary>

        /// 결과 항목 추가 메서드

        /// </summary>

        /// <param name="rurl">순위화  페이지 개체</param>

        public void AddRankedUrl(RankedUrl rurl)

        {

            RankedUrlControl rucon = new RankedUrlControl();

            rucon.SetRankedUrl(rurl);

            int ruc_cnt = children.Count;

 

            rucon.Location = new Point(0, ruc_cnt * 200 + 24);

            rucon.Height = 200;

            rucon.Width = this.Width - 24;

            rucon.Parent = this;

            rucon. RUClick  += new RUrlClickEventHandler(rucon_Click);

            children.Add(rucon);

        }

 

 

        void rucon_Click(object sender, RUrlClickEventArgs e)

        {

            if (RUClick != null)

            {

                RUClick  (sender, e);

            }

        }

    }

}

 

11.1.2 EH 응용 만들기

 

 이제 EH 응응을 만듭시다.

 

 EH 응용의 메인 폼에는 검색 질의를 입력하는 TextBox 컨트롤과 검색 요청하는 버튼 컨트롤, 결과 목록을 보여줄 RUListControl을 배치합니다. 보다 효과적으로 배치하는 것을 원하시면 도구 상자의 컨테이너 탭에 있는 컨트롤을 이용하세요. 여기에서는 컨테이너 컨트롤을 이용하는 부분은 설명에서 과감히 생략합니다.

 

[그림 11.3] EH 메인 폼 자식 컨트롤 배치

[그림 11.3] EH 메인 폼 자식 컨트롤 배치

 

 

 

번호

컨트롤 이름

컨트롤 유형

설명

1

tbox_query

TextBox

질의 입력 창

2

btn_search

Button

바로가기 버튼

3

rlc_result

RUListControl

결과 항목 시각화

[ 11.2] RankedUrlControl의 자식 컨트롤

 

 검색은 앞에서 만든 검색 서비스를 이용하는 클라이언트입니다. 검색 서비스는 .NET 리모팅 기술을 사용하므로 System.Runtime.Remoting 어셈블리를 참조 추가하세요. 또한 검색 서비스에서 서버와 클라이언트가 공통으로 사용하려고 만든 GenericSearchLib 도 참조 추가합니다. 물론 WSE_Core 라이브러리도 참조 추가해야겠죠.

 

 검색을 위해 .NET 리모팅을 통해 GenericSearch 개체를 참조할 수 있어야 하므로 이를 참조할 멤버 필드를 선언합시다.

GenericSearch svc;

 

 메인 폼의 Load 이벤트 핸들러를 추가합니다.

private void MainForm_Load(object sender, EventArgs e)

 

 이벤트 핸들러에서는 검색 서비스를 이용하여 GenericSearch 개체를 참조합니다.

HttpChannel hc = new HttpChannel();

ChannelServices.RegisterChannel(hc, false);

 

svc = Activator.GetObject(

        typeof(GenericSearch),

        "http://[서비스 서버의 IP 주소]:10200/EHSearchSVC"as GenericSearch;

}

 

 

 검색 버튼의 클릭 이벤트 핸들러를 추가합니다. 이벤트 핸들러에서는 검색하여 검색 결과를 처리합니다. 이 부분은 별도의 메서드로 작성합시다.

private void btn_search_Click(object sender, EventArgs e)

{

    Search();

}

 

 검색을 시도하여 결과를 처리하는 Search 메서드를 작성합시다.

private void Search()

 

 먼저 결과 목록을 지워줍니다.

rlc_result.Clear();

 

 그리고 검색 질의를 입력 인자로 검색 요청합니다.

string query = tbox_query.Text;

ArrayList list = svc.Request(query);

 

 검색 결과 목록의 각 결과인 순위화 한 페이지 개체를 입력 인자로 결과 항목을 추가합니다.

foreach (RankedUrl rurl in list)

{

    rlc_result.AddRankedUrl(rurl);

}

 

 마지막으로 바로가기 버튼 클릭했을 때 이벤트 핸들러를 추가합니다.

private void rlc_result_Click(object sender, RUrlClickEventArgs e)

 

 이벤트 핸들러에서는 검색 결과인 순위화 한 페이지 개체를 인자로 브라우저를 생성하여 보여줍니다. EHBrowser는 별도의 폼으로 작성합시다.

RankedUrl rurl = e.RUrl;

EHBrowser eb = new EHBrowser(rurl);

eb.Show();

 

MainForm.cs

using System;

using System.Windows.Forms;

using System.Runtime.Remoting.Channels.Http;

using System.Runtime.Remoting.Channels;

using GenericSearchLib;

using System.Collections;

using WSE_Core;

using RankedUrlControlLib;

 

namespace EH

{

    public partial class MainForm : Form

    {

        GenericSearch svc;

 

        public MainForm()

        {

            InitializeComponent();

        }

 

        private void MainForm_Load(object sender, EventArgs e)

        {

            HttpChannel hc = new HttpChannel();

            ChannelServices.RegisterChannel(hc, false);

 

            svc = Activator.GetObject(

                typeof(GenericSearch),

                "http:// [서비스 서버의 IP 주소]:10200/EHSearchSVC"as GenericSearch;

        }

 

        private void btn_search_Click(object sender, EventArgs e)

        {

            Search();

        }

 

        private void Search()

        {            

            rlc_result.Clear();

 

            string query = tbox_query.Text;

            ArrayList list = svc.Request(query);

            foreach (RankedUrl rurl in list)

            {

                rlc_result.AddRankedUrl(rurl);

            }

        }

 

        private void rlc_result_Click(object sender, RUrlClickEventArgs e)

        {

            RankedUrl rurl = e.RUrl;

            EHBrowser eb = new EHBrowser(rurl);

            eb.Show();

        }

    }

}

  

 Windows Form 추가 메뉴를 통해 EHBrowser 폼을 추가합시다.

 

 EHBrowser 폼에는 자식 컨트롤로 페이지 제목과 주소 및 페이지 내용을 보여주는 자식 컨트롤을 배치합니다.

 

[그림 11.4] EHBrowser폼 자식 컨트롤 배치

[그림 11.4] EHBrowser폼 자식 컨트롤 배치

 

번호

컨트롤 이름

컨트롤 유형

설명

1

lb_title_info

Label

정보 표시

2

lb_title

Label

타이틀

3

lb_addr_info

Label

정보 표시

4

lb_addr

Label

사이트 주소

5

wb

WebBrowser

페이지 정보 표시

[ 11.3] RankedUrlControl의 자식 컨트롤

 

 EHBrowser 컨트롤의 생성자는 순위화 한 페이지 개체를 입력 인자로 받는 것으로 변경하세요.

public EHBrowser(RankedUrl rurl)

 

 생성자 메서드에서는 마법사에 의해 작성한 InitializeComponent 메서드 호출로 초기 자식 컨트롤 배치 등을 마친 후에 입력 인자로 받은 순위화 한 페이지 개체의 속성으로 자식 컨트롤의 Text속성을 설정합니다. 그리고 페이지 주소를 입력 인자로 WebBrowser 컨트롤인 wb Navigate 메서드를 호출합니다.

 

EHBrowser.cs

using System.Windows.Forms;

using WSE_Core;

 

namespace EH

{

    public partial class EHBrowser : Form

    {

        public EHBrowser(RankedUrl rurl)

        {

            InitializeComponent();

            lb_addr.Text = rurl.Url;

            lb_title.Text = rurl.PUrl.Title;

            wb.Navigate(rurl.Url);

        }

    }

}

 

 검색 서비스를 가동한 후에 EH 응용이 잘 동작하는지 테스트를 해 보세요.

 

반응형