ASP.NET2011.10.15 00:44
오랜만에 불 붙었습니다.

저는 VB MVP입니다. 하지만 누구 덕분에 ASP.NET은 C#이랑 해야 한다는 어떤 정석(?)이 생겨서 VB로 할수가 없습니다. ㅠㅠ

이전에 MVC에 대해 설명을 했습니다.

저는 정말 아무도 모르는 아니, 누군가는 알겠지만 공유를 안해서 죽어라 삽질하게 만드는 이기적인 개발자들에 대해 감사하고 있습니다.

제 블로그 이전글을 보면 JAVA를 해야 하는 이유에 대한 글이 있습니다.

닷넷이 아닌 자바!!

개방을 하는 시스템을 따라갈 자는 없다고 봅니다. 특히 자바쪽은 오픈소스가 굉장히 많습니다.
물론 닷넷도 오픈소스를 많이 합니다. 하지만 자바에 비하면 아직 애기 수준이죠....

자바의 스프링, 하이버네이트, 아이바티스, 앤트

정말 훌륭합니다. CI도 정말 훌륭한 프러덕이 많습니다. 하지만 닷넷은 요즘은 많아 졌는데, 예전에 정말 없었습니다.

정정 : 이 부분에 있던 내용은 삭제 하였습니다. < 모 회사에 관련된 내용이라서 ^^;>

제가 자바에 대해 해봐야 한다고 한건, 오픈소스가 정말 잘되어 있습니다. 아직도 활발하게 진행이 되고 있으며 EJB를 무너뜨린 Spring은 벌써 3.0 입니다.

닷넷은 spring이랑 ibatis랑 붙이는데 솔직히 셋팅하는데 일주일 걸렸습니다. 그때는 정말 자료가 전혀 없었습니다. 혼자 삽질 하며 겨우 셋팅을 해 보니 구글에서 아무리 찾아도 없던 내용을 제가 등록했습니다. codeproject에 여기에 근데 Part1 밖에 없습니다.

개발자의 가장 큰 단점인 영어가 안되어서... ㅠㅠ 제가 이 아티클을 쓰려고 일주일간 사전찾고 하며 쓴 간단한 part1입니다.

part2를 2년 만에 쓰게될지도 몰라요 ㅋㅋ

나름 MS 패턴앤 프랙티스 문서 많이 보고, 엔터프라이즈 J2EE 라는 책을 보며 최적의 패턴을 찾아서 쓴 내용입니다.

현재 실무에 제가 설계한 내용이 이 방법이고, 작년에 세미나 진행했던 내용도 이 내용입니다. 어흠.....


사실 MVC2 까지는 자바와 비교하기에는 너무 부족해 보였습니다.

뭐가 부족하나요? 라고 하시면 사실 저도 자바를 전문으로 한게 아니라 잘 모르지만, 일단 해 보시면 압니다. 라고 말씀드릴수가 있습니다. 왜냐면 MVP는 MS대변인이 아니기 때문에 분명히 말씀드립니다.

MVC2까지는 이건 뭐지? 라는 생각이였습니다.

하지만 3에서 ViewEngine 인 Razor가 나오면서 상황은 달라졌습니다.
JAVA의 Custom Tag나, JSTL를 접해보신분들은 Razor를 보시면 뭐... 비슷하게 따라했네... 라고 하실수도 있을것 같아요.

그만큰 자바쪽은 이전부터 발달이 되어 있었는데, 닷넷은 MVC3가 되면서 비슷한 느낌이 되었습니다 라고 말씀드릴수가 있습니다.


현재 랭귀지들은 굉장히 발전 되어있습니다.

자바가 1.5를 5.0으로 바꾸면서 타이거 라고 했죠 아마?

3~4년 전에 나온 자바5.0이 제가 보기엔 닷넷 4.0 과 비슷해 보입니다. 아직 닷넷 4.5는 베타입니다.

MS 관계자분들은 얘 뭐하는 놈이야? 라고 할수 있는데, 여긴 제 개인 블로그 입니다.
물론 주관적이긴 하지만 제가 느낀 언어는 그대로 전달할수 있습니다.

자바든 닷넷이든...
좋아하는 언어를 선택하시면 됩니다.

저는 사실 언어를 못합니다. 특히 국어.... 굉장히 어려운것 같습니다.
하지만 JAVA, C#, VB 는 동시통역(?) 할수 있습니다.

그만큼 비슷하다는 이야기 이지요~ ^^;


그러면 제가 왜 MVC3가 좋은지에 대해 설명할 차례인것 같네요.

우선 웹폼 기반 개발하시는 분들이 봤을땐, MVC는 페이지 개념이 없습니다. 예전에 MS에서 자주 PT자료로 내 놓았던것 중 하나가 털남 남자는 디자이너고, 이쁜 여자는 개발자...

상호 협력을 잘할수 있다라는건데.. 국내 뿐만 아니라 해외에서도 개발자와 디자이너 사이에 문제가 좀 있나 봅니다. ㅋㅋ

MVC로 하면 View는 디자이너 또는 퍼블리셔가 주는 html 그대로 사용할수 있습니다.

xxxToolkit 다 버리십시오. 이런거 쓰지 말고, 퍼블리셔가 주는 화면 그대로 사용하면 됩니다.

특히 jQuery와 통합되었기 때문에 jQuery 문법 조금만 알면 스크립트는 금방 합니다.

문제는 한국에선 화면에 출력되는걸 중요시 힙니다. 이건 까칠한!!! 퍼블리셔 몫입니다.
개발자는 요청에 맞는 응답을 잘 처리해 주면됩니다.

그럼 Razor는 왜? 타이틀에 붙어 다니는가?
Razor는 제가 생각하기에 정말 최상의 ViewEngine입니다.

흔히 말하는 골뱅이(@) 하나로 끝납니다. ㅋㅋ

그 예제는 다음에 보여드리겠습니다. :)
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2011.10.15 00:08

ASP.NET MVC3로 프로젝트를 진행하고 있습니다.
MVC2에서 부족한 부분들을 3에서 많이 채워 주었습니다.

대표적인 예로 View Engine인 Razor 지원이 됩니다.

제가 실용적인 강좌가 많이 없다고 많은 분들께 이야기 하고 다녔습니다. 저 또한 실용적인 강좌를 만들지 못하고 있지만 정말 실무에서 필요한 내용이 무었인지 여러분들과 조금이나마 공유했으면 좋겠다는 생각에 지극히 개인적인(?) 아티클을 남겨 봅니다.

MVC(Model-View-Controller) 는 사실 명명이 잘못되었다고 생각합니다. CMV가 되어야 하는데, MVC죠...

이야기처럼 봐 주세요 ^^;

웹은 요청(Request)가 있어야 응답(Response)을 합니다.

요청을 받는 녀석은 Controller(C) 이죠. 요청을 받으면 요청한 내용을 보여주기 위해서 Model(M)에서 필요한 내용을 꺼냅니다. 그리고 View(V)를 통해서 보여주게 되는것이죠.

그럼 기존 WebForm기반이랑 뭐가 다른가요?

WebForm도 마찬가지입니다. 요청(Request)에 대해 응답(Response)를 하는데, 단지 Page기반의 처리방법이 MVC와 차이가 있는것입니다.

현재 우리 팀원이 자주 질문하는것이 새로운 요청일 경우 Controller를 어떻게 다르게 만들어야 하는지가 궁금한가 봅니다.

Controller는 단지 요청(Request)을 받아들이고 Model을 통해서 어떻게 View에게 보여줄것인가 하는 녀석이니까 작은 Doamin 으로 나눈다면 특정한 Business Logic에 대해서는 하나만 존재 하면 됩니다.

그러면 기존에 웹폼 기반에 수많은 페이지들은 어떻할것인가?

도메인 모델로 구분짓고 적절히 나누면 되는것입니다.
예를 들어 Twitter와 같은 시스템을 설계를 한다고 할때에는 TimeLine을 위한 Controller 하나, 팔로워, 팔로잉을 하는 사람들을 위한 Controller 하나, 그리고 쪽지와 같은 특수한 기능을 하는 기능적인 Controller하나, 마지막으로 설정에 관련된 Controller 하나, 이렇게 4개만 있으면 됩니다.

그럼 이렇게 의문을 가지시는 분들이 있을것 같습니다.
"그럼. 팔로워, 팔로잉 페이지를 따로 만들어야 하는데, 그걸 컨트롤러 하나로 만들면 어떻할껀데? 기존 웹폼은 전부 따로 만들어서 유저컨트롤로 쪼개어서 SP만 따로 호출하면 되는거 아니냐?"

그런분들은 그냥 웹폼으로 열심히 만드십시오. 라고 하겠습니다.

MVC의 장점은 M-V-C를 명확하게 나눌수 있는점입니다.

요즘에 퍼블리셔와 같이 일하지 않습니까? 퍼블리셔가 주는 페이지들은 View 입니다. Controller가 아닙니다.

??????

예... Controller는 요청(Request)을 받기 위한것이지 응답(Response)을 하기 위한것이 아닙니다.
그 페이지들을 View에 만드는겁니다.

그런데!!!
실용적인 강좌에 대해서 제가 서두에 언급을 했습니다. 실용적이란 이런걸 말씀드리는것입니다.

Controller는 도메인 모델에 대해 크게 나누어진것 이고, WebForm에서 MVC로 넘어오시려는 분들이 생각하시는 페이지는 View입니다.


"그래서 어쩌라고?" 하시는 분들...

자...

요청을 받았습니다. 응답을 위해 기존에 흔히 말하는 DAL을 통해서 페이지에 뿌려준다?

MVC에서는 그게 아닙니다.

MVC에서는 Controller로 받은 응답을 요청하기 위해서 View에 필요한 데이터를 Model에 요청해서 뽑아내고
ViewBag, ViewData 에 넣어서 단지 View로 넘겨주기만 하면 됩니다.

그러면 View에서 정말 멋진 Razor로 보여주면 되는것입니다.

뭐... 작업 하시다가 사파리에서 화면이 틀어진다? 망할놈의 IE6에서 깨진다? 그건 고귀한 퍼블리셔님들이 해야 할 몫입니다.

대략 어떤건지 감이 오시나요?

다음 강좌에 계속하겠습니다.



!!! 혹시나 제가 틀린 부분이 있으면 얼마든지 댓글남겨 주십시오. 정보 공유는 올바른 정보공유로 부터 시작이 됩니다.

감사합니다.
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2010.02.05 17:06

원문 : http://haacked.com/archive/2010/02/04/aspnetmvc2-rc2.aspx

오늘 오전에 ASP.NET MVC 2 RC 2 가 발표되었습니다.

가장 눈에 띄는점은 유효성 체크 입니다.

ASP.NET MVC 가 처음 나왔을때 제가 느낀 불편한 점이 몇가지 있었는데요, 그 중에 유효성 체크도 있었습니다.
하지만, 이번 RC2 에서 가장 크게 바뀐 부분이고, 지금껏 많은 개발자들이 이부분에 대한 피드백을 주어서 반영된것 같습니다.

기존에는 유효성 검사를 하기위해서는 HttpVerbs.Post 동사 부분에서 If 문으로 처리를 하였죠?
다음처럼 말이죠...
'
' POST: /Product/Create

<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude:="Id")> ByVal productToCreate As Product) As ActionResult
    ' Validation logic
    If productToCreate.Name.Trim().Length = 0 Then
	    ModelState.AddModelError("Name", "Name is required.")
    End If
    If productToCreate.Description.Trim().Length = 0 Then
	    ModelState.AddModelError("Description", "Description is required.")
    End If
    If productToCreate.UnitsInStock < 0 Then
	    ModelState.AddModelError("UnitsInStock", "Units in stock cannot be less than zero.")
    End If
    If (Not ModelState.IsValid) Then
	    Return View()
    End If

    ' Database logic
    Try
	    _entities.AddToProductSet(productToCreate)
	    _entities.SaveChanges()
	    Return RedirectToAction("Index")
    Catch
	    Return View()
    End Try
End Function

ref : http://www.asp.net/learn/mvc/tutorial-36-vb.aspx

하지만, 이번 RC2 에서는 이 부분이 단순하게 다음처럼 바뀌어버립니다.
'
' POST: /Product/Create

<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude:="Id")> ByVal productToCreate As Product) As ActionResult
    ' Validation logic
    If ModelState.IsValid Then
	    Return View()
    End If

    ' Database logic
    Try
	    _entities.AddToProductSet(productToCreate)
	    _entities.SaveChanges()
	    Return RedirectToAction("Index")
    Catch
	    Return View()
    End Try
End Function


윗부분에 필드별 조건문은 모두 없어졌습니다.

핵심은 Models 영역의 <Required()> 어노테이션 선언 덕분입니다.
Input Validation vs. Model Validation in ASP.NET MVC

이제 좀 쓸만하겠는데요?

하지만 아직 URL Rewrite, Routing 부분은 좀더 개선이 필요해 보입니다.
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2009.10.20 15:47

MVC 패턴에서 AJAX을 쓰기가 꽤 까다롭습니다.


위 그림과 같이 페이지 요청을 하면 라우팅 테이블(또는 룰)을 거쳐 Controller->Model->View 의 흐름을 거치게 됩니다.

기존 WebForm 에서는 간단히 처리가 되는데, MVC 모델에서는 간단하지가 않죠.

일전에 자바 프로젝트를 하면서 MVC 2 모델에 Spring 위에서 AJAX을 구현해야 하는 경우가 생겼습니다. 이때는 Return Type이 XML 문서로써, AJAX 요청에 대해서 MultiActionController 를 상속받아서 처리한 경우가 있었습니다. 이건 Spring 프레임웍에서 지원하는거라 별 어려움없이 xml 설정과 액션 우회 방식으로 처리 되어 실제 흐름은 위 그림과 비교 해 보면 실존하는 페이지 View 가 없고, Document 객체를 메모리에 Writing 시키는 방식으로 처리 했습니다.

제가 MS 제품을 좋아 하는 이유가 쓰기 편하게 설계가 되어 있다는 점 입니다. 마침 Walkthrough: Adding ASP.NET AJAX Scripting to an MVC Project 문서를 발견하여 간단히 따라 할수 있도록 정리 해 봤습니다.

  • 준비물
    • Microsoft Visual Studio 2008
    • ASP.NET MVC 2 - Download

1. 프로젝트 시작하기


위 두가지가 설치되었으면 Visual Studio 를 실행하고, 그림과 같이 프로젝트 템플릿을 ASP.NET MVC 2 Web Application 을 선택하고, 프로젝트명을 MVCAjaxApplication 이라고 입력한 후 확인을 누릅니다.



2. ASP.NET AJAX 스크립트 라이브러리를 스크립트 참조

솔루션 탐색기에서 /Views/Shared/Site.Master 를 선택하고, 소스보기를 한후 아래 코드를 head 에 추가합니다.



3. HomeController 클래스에 액션 메서드 추가

솔루션 탐색기에서 /Controllers/HomeController.vb 를 선택 하고, 다음과 같이 액션 메서드를 추가 해 줍니다.
    Public Function GetStatus() As String
        Return "Status OK at " + DateTime.Now.ToLongTimeString()
    End Function

    Public Function UpdateForm(ByVal textBox1 As String) As String
        If textBox1 <> "Enter text" Then
            Return "You entered: """ + textBox1.ToString() + """ at " + DateTime.Now.ToLongTimeString()
        End If

        Return [String].Empty
    End Function


4. Index 페이지 재 정의

지금까지 한 작업들을 보여주는 View 페이지(/Views/Home/Index.aspx)에서 <asp:Content> 부분을 다음과 같이 수정합니다.


5. 테스트

지금까지 작업한 내용을 확인하기 위해 "실행" 을 해 봅니다.
그러면 다음과 같이 잘 나옵니다.(혹시 index.aspx 에 포커스를 두고 실행하면 라우팅 오류가 날수 있으므로, 컴파일 후 Default.aspx 페이지에서 실행 하시기 바랍니다.)


이렇게 간단하게 ASP.NET MVC 에서 AJAX을 구현 할수 있습니다.
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2009.06.10 09:25
Visual Studio 2010 에 ASP.NET MVC 탑재 한다고 했는데, 베타버전에 탑재 하지 않은채 발표 하였습니다. 2010에서 MVC 개발을 할수 없었던건 아니지만, 꽁수를 부려야 했죠.

2008에서 생성한 프로젝트를 열고, 오류가 났을때 특정 GUID를 제거 하는 방법으로 돌렸는데, 어제(2009.06.09)부로 설치판이 발표 되었습니다.

Phil Haack 의 블로그(http://haacked.com/archive/2009/06/09/aspnetmvc-vs10beta1-roadmap.aspx)에서 로드맵을 제시 해 줍니다.

요약을 하자면.
http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=28527 에서

AspNetMVC1.1_VS2010.exe을 설치하고, ASP.NET MVC Snippets for VS2010 Beta 1를 다운받아서
C:\Users\<username>\Documents\Visual Studio 10\Code Snippets\Visual Web Developer\My HTML Snippets 에 압축을 풀면 됩니다.

그러면 다음 그림처럼 정상적으로 ASP.NET MVC를 VS2010에서 개발 가능합니다.
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2009.06.01 10:22
처음에 언급한것과 같이 테스트 해 보면서, 연재 하다 보니 오랜시간이 걸렸습니다. 지난 강좌에서 말씀드린 수정, 삭제를 구현하는부분에서 애매한 부분이 생겼는데, 억지로 라우팅을 변경하다보니 헤깔리는 부분이 많았습니다. 결론적으로, ASP.NET MVC에서는 라우팅 테이블이라는것이 존재하므로, 보통 웹 개발을 할때, 하나의 ASPX를 글쓰기, 수정하기 기능을 같이 넣는데, 이렇게 하는것은 좋지 않다는 결론을 내었습니다. 또한 validate 가 그리 녹녹하지는 않네요 ^^;

자 그럼 마지막 연재를 끝내보도록 하겠습니다.
구현해야 할 내용이 수정, 삭제 이고, 수정은 글쓰기의 view,  삭제는 view없이 이루어집니다.
그러면 글 읽기 화면에 수정, 삭제 기능을 추가해야 하므로, Detail.aspx 를 다음과 같이 수정합니다.
상단에 자바스크립트로, 1차적인 유효성 체크를 하고, 실제 post 액션이 발생했을때 맞는 패스워드 인지 또다시 체크를 하게 구현 하였습니다. post액션 발생시켜서 유효성 체크를 하는것이 구쓰리님의 ASP.NET MVC 책에 나오는 정석입니다.

상단에 Html.ValidationSummary("You must specify a password") 라는 메서드는 컨트롤러단에서 유효성 체크를 해서 ModelState.AddModelError() 메서드를 통해 값을 넣게 되면 나타나는 것인데, 랜더링이 되면 레이블 형태를 취합니다.

하단에 보면 약간 지저분해 보이는 코드가 있습니다. Html.Hidden(), Html.ValidationMessage() 메서드가 있는데, Html.Hidden() 메서드는 억지로 MVC 라우팅을 무시하고, POST 액션을 취하기 위한 방법인데, 앞으로는 수정 화면을 따로 View를 가져가도록 코드를 짜는것이 맞을것 같습니다. 그리고, Html.ValidationMessage()는 좀전에 얘기한 ModelState.AddModelError("pwd", "message") 라고 컨트롤러에서 오류값을 넣으면 Html.ValidationMessage("pwd")로 반환 받을 수 있습니다.

자... 그러면, 여기서 Modify, Delete 컨트롤러를 구현해야 합니다. BoardController.vb에 다음과 같이 구현하도록 합니다.


억지로 구현하다보니 컨트롤러가 좀 지저분해 졌습니다.
우선 HttpVerbs.Post 동작을 하는 Modify 메서드를 보면, ASPX에서 Hidden필드로 seq, password 필드로 pwd를 가져오기 위해 FormCollection을 받아옵니다.

우선 password가 유효한지 검사해서 유효하지 않으면 DetailController에 오류를 담아서 보내고, 유효하다면, 해당 seq로 게시물이 있는지 찾아서 게시물을 VO에 셋팅 합니다.

여기서 자세히 보면

이 구문이 write컨트롤러와 modify컨트롤러를 같이 쓰게될때 들어가게 되는 지저분한 코드 입니다.

만약 복잡한 화면에 코드가 많이 들어가야할 어쩔 수 없는 경우라면 이런 방법으로 하는것도 그리 나쁘진 않을것이지만, 유지보수 차원에서 그리 추천하는 코드는 아닙니다.

Delete 메서드를 보면 Modify 와 비슷합니다. 단지 Delete는 View가 없기 때문에 아래처럼 심플하게 구현되어 집니다.


자... 그러면, Modify, Delete 메서드에서 새롭게 추가된 Facade 객체의 메서드는 다음과 같이 3가지가 추가 되었습니다.
Me.sbFacade.getValidPwd(formValues)
Me.sbFacade.updateBoard(boardDetail, formValues)
Me.sbFacade.deleteBoard(id)

그러면, 이번에는 지금까지 했던 코딩 방식과는 다르게 반대로 코딩을 해 보겠습니다. 목적지 부터 해 봅니다.
(이렇게 하는것이 더 편하더라구요 ^^;)

Board.xml 을 다음과 같이 마지막에 3가지 statements를 추가 하도록 합니다.


그리고, 인터페이스 BoardListDAO.vb 를 다음처럼 코드를 추가 합니다.



SqlMapBoardListDAO.vb 클래스를 다음처럼 코드 추가 합니다.



getValidPwd 메서드는 FormCollection 을 받아서 해당게시물의 작성자 비밀번호가 맞는지 값을 Integer 타입으로 돌려주는것입니다. 맞으면 1, 틀리면 0

updateBoard 서브프로시져는 가져온 보드에 폼값을 받아서 업데이트 처리 해 줍니다. update이므로 반환값이 없습니다. 더욱 정교하게 설계를 한다면 반환값을 True, False으로 업데이트 성공유무를 오류메시지와 함께 표현해 주는것도 좋은 방법입니다.

deleteBoard 서브프로시져 마찬가지로 삭제 하고 받을 필요가 없습니다. 향상된 UI 에서는 "xx개 행에 적용되었습니다." 라는 메시지를 뿌려주곤 하는데, 이때도 마찬가지로 affectedRows 값을 받아와서 표현해 줄 수 있습니다.

아... 참고로, VB.NET 에서는 인터페이스에 메서드를 추가 하면, 구현하는 클래스는 Implements 인터페이스 부분에 파란 밑줄이 표시되는데, 이 파란 밑줄 젤 끝에서 엔터를 치면 자동으로 구현받는 메서드가 생성이 됩니다.

이제는 SpringBoardFacade.vb 인터페이스에 메서드를 추가할 차례입니다. 다음처럼 추가 합니다.


마지막으로 SpringBoardImpl.vb 클래스에서 인터페이스에 선언된 메서드를 구현 해야 합니다. 다음처럼 코드를 추가 하도록 하겠습니다.


 
여기까지가 ASP.NET MVC + SPRING.NET + iBATIS.NET 모두 합쳐서 만들어본 간단한 게시판의 하나의 LifeCycle 입니다. 제 생각에 Log On, About 클릭 하면 오류가 날건데요, BoardController 를 참조하여 해당 컨트롤러의 contructor injection을 objects.xml 에 구현해 주어도 됩니다. ^^;

원래는 이런거 안해줘도 잘 돌아가는데 왜 해주냐고요? 
음... 오픈소스 프레임웍이 모든걸 다 해주지는 못합니다. 훌륭한 닷넷 프레임웍 을 도울뿐이죠... 그러기 위해서는 약간의 수고가 따르는것 같네요.

단, iBATIS.NET은 정말 훌륭한것 같습니다. 서비스를 운영중에 어떤 쿼리가 변경되어야 한다고 할때 예전에 RDO 가 뜰때 sp기반의 어플리케이션을 작성할때 쿼리가 수정이 될때 sp만 수정하면 되었습니다. 하지만, 모두 sp로 때려넣다 보니, DB부하가 커지게 되죠.. 그러면 간단한 부분은 inline 쿼리로 처리 하게 되는데, inline쿼리로 구현했던 부분이 수정이 된다고 하면?
재배포 해야 합니다. 

하지만, iBATIS.NET을 붙이면 해당 xml 파일의 쿼리만 수정해 주면, Dynamic Loading 을 합니다. 트랜잭션관리 또한 우수합니다. SqlMapxxxxxDAO.vb 에서 메서드에서 Mapper.Instance().QueryForObject("blabla", vo) 부분 기억나실꺼에요..
이 매퍼를 통한 쿼리 호출시에 같은 메서드 안에서는 트랜잭션 처리가 됩니다.
예로, 첫번째 줄에 삭제, 두번째줄에 업데이트, 세번째 줄에 조회 라고 한다면, 하나라도 오류가 생기면 자동으로 롤백 처리가 됩니다.

오픈소스 프레임웍이 이처럼 좋긴 하나 모든걸 해결해 주지는 못합니다.

실생활에 비유를 하자면 제 생각엔 오픈소스 프레임웍은 망치 이고, 사람은 닷넷 프레임웍이라고 생각합니다.
사람은 손으로 컴퓨터도 다루고, 밥도 먹고, 운전도 할 수 있습니다. 하지만 특정한 도구 없이는 못을 박기에는 힘듭니다. 쉽게 해 주는것이 망치 이죠.. 단 벌레 한마리 잡는데 망치를 사용하는것이 맞는것일까요?

망치 매니아 라면 그러셔도 좋습니다.!! 단 유리에 붙어 있는 벌레를 잡으러 망치를 들다간 큰일 나겠죠? :)

지금까지 한 소스코드를 첨부 합니다. :)


 
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2009.04.27 13:10
간단한 게시판 하나 만드는데 연재가 길어지고 있습니다. 셋팅과 부연설명등이 잇따라 나오면서 이렇게 되어버렸습니다. ㅡㅡ;
이번 포스트는 글 읽기 입니다. 처음 부터 열심히 따라 하셨다면 쉽게 구현 할수 있을것 입니다.
전체적인 패러다임은 글쓰기 화면과 바슷합니다.

우선 목차 페이지 부터 시작하겠습니다.
글읽기를 위해서 목차의 제목에 링크를 달아야 합니다.

그림과 같이 링크를 달려고 하는데, 어떤 부분을 고쳐야 하는지 한번 봅시다.

처음에 셋팅할때 보았던, Global.asax 의 라우팅을 보면 {controller}/{action}/{id} 라고 해석이 되어집니다.
즉, 예전에는 Detail.aspx?seq=4 라는 표현이 /Board/Detail/4 라고 표현이 됩니다.

그러면 리스트 페이지에서 title을 나타내는 부분에 링크를 걸어주면 됩니다.

기존코드에서 약간 변경이 되었습니다. 기존에 비해 a 태그와 Html.Encode 메서드가 추가 되었습니다. a 메서드의 링크값은 위에서 설명한것과 같이 표현 방식이고, Html.Encode() 메서드는 헬퍼 메서드 입니다. 데이터를 입력하고, 웹페이지에서 다시 보여줄때, encode를 해 주는것이 매우 중요합니다. 왜냐면 악의를 품고 javascript injection 공격에 대한 대비책이 될수 있으니깐요.. 해커들이 개인정보를 빼낼때 주로 인젝션을 사용하는데, 이때 encode 시키면 결과값을 쉽게 알아볼수 없기 때문에 텍스트 데이터에 대해 display 할때는 가급적 Html.Encode() 메서드를 사용하기를 권장합니다.

그럼 상세 내용 보는 페이지(view)를 Detail.aspx 라고 한다면 BoardController 에서 라우팅 메서드를 하나 만들어야 합니다.
기존 코드와 함께 추가된 Detail() 메서드를 추가해 봅시다. BoardController.vb

여기서 주의해야 할 부분은 받는 파라메타의 변수값은 무조건!! id 라야 합니다. 지금은 이유를 모르겠지만, 내부적인 매핑이 별도로 이루어지는 모양입니다.

이렇게 했으면, boardDetail = Me.sbFacade.getBoardDetail(id) 부분에 파란줄이 생길것입니다. 파사드에 메서드가 없기 때문이죠.. 그럼 파사드에 추가해 보도록 하겠습니다.

우선 SpringBoardFacade.vb 인터페이스에 getBoardDetail() 메서드를 추가 해 봅시다.


그리고, SpringBoardImpl.vb 클래스에 구현을 합니다.


마찬가지로, BoardListDAO.vb 인터페이스에도 추가해 줍니다.


그다음은????? SqlMapBoardListDAO.vb 클래스에 구현합니다.


실제 구현 부를 보면 정말 심플합니다.
Mapper.Instance().Update("updateReadCount", seq) 는 현재 게시물의 조회수 1 증가 시키는 명령입니다. update 문이겠죠? 그리고 다음줄에 getBoardDetail 은 게시물의 내용을 가져오는 부분입니다. 이게 딸랑 두줄만에 끝나죠 ^^*

그럼 이제 Board.xml 에서 쿼리를 추가해 줘야 합니다.


간단히 쿼리 두개가 statement id 값을 가지며 추가가 되었습니다.
그러면 다시 컨트롤러(BoardController)로 돌아와 보면 View가 빠져있는걸 알수 있습니다.
그럼 Detail.aspx 라는 뷰를 추가 해 봅시다. 코드 하이라이트가 asp.net 코드는 인식이 안되므로 캡춰 했습니다. 참고로 Write.aspx 와 비슷하니 참조해서 코딩 하시면 됩니다. (이런 무책임함... ㅡㅡ; 죄송합니다. )

여기까지 코딩 했으면 이제 실행해 봅시다. 두번째 글을 클릭하면 다음과 같이 글 보기 화면이 잘 나올것 입니다.

짠~ 근데 날짜 형식도 이상하고.. 많이 허접해 보입니다. 어쩔수 없습니다. 최소한의 디자인으로 이정도면 훌륭하다고 판단이 됩니다. 죄송합니다. ㅠㅠ

이렇게 글 보기 화면까지 훌륭하게 잘 만들어 봤습니다.
남은건 수정, 삭제 입니다. 요것 까지 해서 하나의 게시판 Life Cycle 를 만들어 본 후에 대망의 제 2탄!!!

지금 생각하는건, 똑같은 게시판이지만, AJAX와 jQuery 까지 붙이고.. 욕심이 생기는 부분은 아예 View를 silverlight 로 만들어 버릴까? 하는 생각도 있습니다. 의견을 주시면 적극 반영하여, 2탄 강좌에서는 태요님과 같이 깔끔한 연재가 되도록 할께요 ^^;

앗... 혹시나 하는 생각에 hoons.kr 에서 찾아보니 훈쓰님이 다음과 같은 답변을 달았네요...


참고 해야 겠습니다.

그럼 좋은 하루 되세요~
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2009.04.24 20:30
이번에는 글 쓰기 페이지를 개발할 차례입니다. 물론 유효성 체크나 기타 유용한 기능은 게시판 개발의 한 라이프 사이클이 지난 후에 일명 "고도화 작업" 을 하면서 더 깊이 다뤄 보고, 지금 이 게시판은 오픈소스 프레임웍과 ASP.NET MVC 와의 유연성과 확정성을 알아보기 위한 테스트 게시판입니다. 똑같이 따라했는데 오류가 나신다고요? 죄송합니다. 중간중간 빠뜨린게 많나봅니다. ㅡㅡ; 중간중간에 올리는 소스를 참고 하시어 빠진부분을 체크 해 보아요~

자... 서두가 길었는데, Write 페이지를 만들기 위해서 이전에 했던 부분을 약간 수정해야 하는 부분이 있는데 그것부터 하고 넘어 가겠습니다.

지난시간에 했던, List.aspx 에서 버튼 링크를 잘못 넣었습니다. 아래와 같이 onclick 부분을 수정해 주세요 ^^;
<input type="button" value="글쓰기" onclick="location.href='/Board/Write'" />

그리고, /Views/Board/Write.aspx 를 추가 합니다. 그리고 캡춰된 이미지와 같이 코딩합니다.

이렇게 코딩 하고 나면 이처럼 허접한 화면이 됩니다. ^^;

지금 우리에게 중요한건 디자인이 아닙니다. ㅡㅡ; 죄송합니다. ㅠㅠ

흠... 그리고 저장버튼을 눌렀을때 HomeController의 Write 액션을 취합니다. 물론 이때 Http의 Post 동사를 취하게 됩니다.(보통 사람들이 이렇게 어렵게 말 하는데, 그냥 어트리뷰트 추가해 주면되니 걱정 하지 마시기 바랍니다.)

자... 그럼 이제 어떻게 받는지 확인해 보죠.
BoardController.vb 를 다음과 같이 Write메서드를 오버로드 해서 하나 더 만들어 봅니다.


이렇게 만들면 Me.sbFacade.setBoard(formValues) 요기 파란죽이 쫙~ 갑니다. SpringBoardFacade에 없기 때문이죠.
그럼 이번에는 파사드에 추가 해 줍니다. SpringBoardFacade.vb


그리고, SpringBoardImpl.vb 클래스도 메서드 구현해 줍니다.


잘 보시면 파라메타로 FormCollection 이란걸 가지고 다닙니다. 보통은 컨트롤러에서 받아서 VO에 셋팅하고 VO를 가지고 다니지만, 완전한 로직 분리를 위해 폼컬렉션 자체를 가지고 다니기로 했습니다.

역시나 파란줄이 쭉쭉 갑니다~ DAO 에도 메서드를 선언해 줘야 하죠. 우선 BoardListDAO 인터페이스를 다음처럼 메서드 하나 추가 해 줍니다.


마찬가지로 구현을 해야 하니 SqlMapBoardListDAO.vb 클래스를 다음과 같이 변경합니다.


여기서 눈여겨 보셔야 할 부분이 getNewThread 메서드와 FormCollection 에서 폼 컬렉션을 VO 에 셋팅 하는 부분입니다.
우선 getNewThread 메서드는 태요님의 강좌에서 thread를 마지막 thread 번호보다 1000을 크게 하는것인데, 이것을 태요님은 프로시져로 처리 하셨지만, 저는 우선 select 해서 insert 하기로 하고, select를 해 보는것입니다. 중요한게 아니니 패쓰~

자...  여기까지 했다면 마지막으로 쿼리를 짜야 합니다. Board.xml 파일에 우리가 위에서 호출하는 getNewThread와 setBoard 를 추가해 봅시다.


여기까지 했으면 다 된것입니다.

그럼 실행 해 볼까요? 오류없이 잘 뜰것입니다. 글쓰기 화면에서 다음처럼 입력해 보겠습니다.

그리고 저장 버튼을 팍~ 누르는 순간..... 다음과 같은 화면이 잘 나옵니다.~

여기까지 해서 목차화면, 글쓰기 화면 까지 만들어 봤습니다.

다음강좌에는 글 읽기, 글 수정 부분을 하겠습니다.
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2009.04.22 10:10
이번 강좌의 목표는 list 페이지에 출력 해 보는것입니다. 물론 페이징이나 링크 등이 안먹지만 리스트 화면으로 출력 해 보겠습니다. 지난 강좌에 이어 설정파일 수정 부터 하겠습니다.

우선 objects.xml 을 다음과 같이 변경합니다.


마찬가지로 BoardController도 Facade 패턴을 적용하기 위해 생성자 주입을 시킵니다.
다시한번 왜 Facade를 사용하는지 간단히 설명드리자면 Facade 패턴은 복잡한 서브 시스템에 통일된 인터페이스를 두어 복잡한 API를 단순화 시켜 줍니다. 각각의 모듈을 서브 시스템 단위로 쪼개어 구성하는 것은 시스템의 복잡도를 낮춰 주지만 반대로는 각 서브시스템간의 결합도가 증가 하게 됩니다. 이러한 서브시스템 간의 의존도를 낮추고 서브 시스템의 사용자 입장에서 사용하기 편한 인터페이스를 제공하고자 하는것이 Facade 객체 라 합니다. 
Facade객체는 실생활에 따져봤을때 호텔의 인포메이션 센터와 같다고 할수 있습니다. 각 요청을 한곳으로 집중시키는 방식을 말 합니다. MVC 모델에서 요청은 항상 Controller가 받는데, 이 요청을 받을때 Facade 가 중앙 집중식으로 관리 해 주기 때문에 MVC 모델의 패턴에 적합하다고 판단이 되어 채택하게 되었습니다. ^^*

그럼 이제 BoardController 클래스를 다음과 같이 코딩합니다.


여기서도 마찬가지로 Facade 를 통해 게시물 리스트를 가져옵니다. 아주 간격하지 않나요? ^^;

그럼 이 쿼리는 Board.xml 에서 처리 되기 때문에 다음과 같이 변경합니다.


잘 보시면, resultMap과 select 가 1:1 로 매핑됩니다. 사실 이 부분이 좀 애매한 부분인데, 자바 버전에서는  하나만 선언 해 놔도 문제가 없었지만, iBATIS.NET에서는 select하는 필드 수 보다 resultMap에 선언된 property 가 많으니깐 IndexOutOfBoundsException 이 나더라구요.. 왜 그런지는 못찾았습니다. 하다보면 다른곳에서 또 나타나면 그때 다시 개선 방안을 모색해야 할듯 합니다. ㅡㅡ;
아.. 참고로, iBATIS의 가장 단점은 디버깅이 어렵습니다. 엉뚱한 오류가 나는경우가 허다합니다. 그러니 조심조심 해야하죠.
디비가 Oracle 일때 쿼리문의 마지막에 세미콜론(;)이 찍혀있으면 정말 황당한 오류가 나죠.. 참고 하시기 바랍니다. =ㅁ=;

이제 View를 만들어야 합니다. BoardController 에서 보내는 것이니, /Views/Board/List.aspx 를 만듭니다.
제가 쓰는 코드 하이라이트 헬퍼가 asp.net을 지원하지 않아 aspx 코드는 매번 이렇게 캡춰를 받아서 올리네요 ㅡㅡ;

여기서 중요한건, SpringBoard.Models.Vo를 Import 해야지만 m.Title 과 같이 인텔리센스가 동작하고, TBoard 를 사용할수 있습니다. 코드 그대로 간결합니다. ㅡㅡ;

여기까지 하고, 실행 해 봅시다. 실행하여 Board 메뉴를 클릭하면 다음과 같이 리스트가 잘 출력이 됩니다.

처음에 하나의 row만 넣었으니 몇개 더 넣어보고 새로고침 해 봅시다.

INSERT INTO ThreadBoard (thread, depth, writer, pwd, title, mode, content)
Values (2000, 0, 'admin', 'pwd', '두번 째 글입니다', 1, '본문 내용입니다')


INSERT INTO ThreadBoard (thread, depth, writer, pwd, title, mode, content)
Values (3000, 0, 'admin', 'pwd', '세번 째 글입니다', 1, '본문 내용입니다')

이렇게 데이터를 넣고 새로고침 해 봅시다. 다음과 같이 잘 나오나요?

잘 따라 오셨는데 잘 안되시는 분들을 위해 친절하게 지금까지의 소스를 첨부 합니다. 단, sqlMap.config 파일에서 connectinString 을 자신의 디비환경에 맞게 입력 해 주세요.
connectionString="Data Source=(local);Initial Catalog=디비명;User ID=아이디;Password=패스워드"


그럼 다음에는 글쓰기 화면 Write 부분을 해 봅시다.











저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower
ASP.NET2009.04.20 12:36
지난 포스팅에서 ASP.NET MVC + SPRING.NET + iBATIS.NET의 세팅을 모두 끝내고, 테스트 까지 성공 하였다. 이번에는 게시판 리스트 페이지를 만들어 본다.

우선은 HomeController 대신에 BoardController쪽으로 라우팅 되도록 Board컨트롤러를 추가 시키고, 처음부터 리스트 페이지로 이동해도 되지만, 기존에 존재하는 Master페이지에서 Home, About 메뉴에다가 Board 메뉴를 추가 시키고, Board메뉴를 선택했을때 BoardController로 가도록 한다.

위 화면 처럼, Home, About, Board 가 되도록 Board 아이템을 하나 추가한다.
그러기 위해서는 Views/Shared/Site.Master 페이지에 메뉴 항목을 다음과 같이 Board 컨트롤러를 추가한다.
Html.ActionLink 의 파라메타는 linkText, ActionName, ControllerName 으로 구성된다. 즉, 파라메타 상으로, BoardController 에 List 메서드 쪽으로 보낸다는 말이니깐, 컨트롤러와 메서드를 만들어 보자.
우선 컨트롤러 폴더에서 마우스 오른쪽 클릭 하고, 추가->Controller 를 선택하면 Add Controller 다이얼로그가 뜨는데, 선택된 부분을  Board로 바꾸어 최종적으로 이름이 BoardController가 되도록 하고, Add버튼을 클릭한다.



여기서 곧장 Controller 를 수정할 것이 아니라, 처음 부터 계속 말 했던 Facade를 태우기 위해 우선 DAO단에 코드를 추가 하도록 한다. 게시판 리스트 화면이므로, getBoardList로 하도록 하자.

SqlMapBoardListDAO.vb 에 getBoardList를 추가한다.


코드를 보면 굉장힌 간결한걸 알수 있다. 쿼리는 iBATIS.NET 을 통하여 Board.xml에서 구현된다. ^^

이 클래스의 인터페이스인 BoardListDAO에도 다음과 같이 인터페이스(메서드)를 추가한다.


그리고 Facade의 구현 클래스인 SpringBoardImpl.vb의 코드는 다음과 같이 추가 되어진다.


코드에서 보는것과 같이 간결하게 이루어 진다. 이 모든것들이 SPRING.NET 과 iBATIS.NET 프레임웍 덕분이다.
하지만, 단점처럼 보이는것이 왜 자꾸 Facade를 통하려고, 비슷한 코드를 반복적으로 넣는지... 이것은 Spring in Action 이라는 책과 Core J2EE Pattern 이라는 책에서 이 방식이 좋다고 한다. ㅡㅡ; 약간 황당하게 들릴수는 있으나, 실제로 이렇게 개발을 해 보았더니 아주 확장성이 좋았다. Facade 패턴에 관한것은 나중에 다시 언급하기로 하겠다.

그러면 이제 SpringBoardFacade.vb 인터페이스에도 getBoardList 를 선언한다.


이렇게 추가하고 나면 코드단의 작업은 모두 끝났다.
다음작업은? 설정파일들을 수정하는 작업이 남았다.

설정파일 수정, 리스트 페이지 디자인, Board.xml 의 getBoardList statement 는 다음 포스트에서...

아침에 출근해서 한시간동안 하려고 하니 너무 시간이 부족한것 같다.. 일이 계속 밀리네 ㅡㅡ;


저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by dotnetpower

티스토리 툴바