'JSP' 카테고리의 다른 글
Problems warning 를 제거 하자. (1) | 2012.10.23 |
---|---|
html excel 추출 하기.& Jquery excel 추출 하기. (0) | 2012.06.16 |
정규표현식 공식 및 응용 . (0) | 2012.05.08 |
기본JDBC 만들기 (0) | 2012.05.08 |
Tiles(레이아웃처리) (0) | 2012.05.08 |
Problems warning 를 제거 하자. (1) | 2012.10.23 |
---|---|
html excel 추출 하기.& Jquery excel 추출 하기. (0) | 2012.06.16 |
정규표현식 공식 및 응용 . (0) | 2012.05.08 |
기본JDBC 만들기 (0) | 2012.05.08 |
Tiles(레이아웃처리) (0) | 2012.05.08 |
@SuppressWarnings({"rawtypes","unchecked"})
현재 자바에서 노란색으로 뜨는 현상이 나타나는 경우 위의 Warnings을 Class 및 문법 등등 사용할수 있다..
이 문제는 위에서 같이 16229 개의 문제를 도출 하고 있다. 대부분의 경우
ArrayLisst 의 제너릭 타입을 지정 하지 않아 문제가 있다고 나온다. 이는 자바 1.5 버전 이상에서 도출 된다.
다른 문제로 전역또는 지역 변수 값이 if 문이나 for 문에서 사용 하여 (실제로 사용 한다는 말) 컴파일시에 다른경로로 인식 하여 사용 안되는 문제라고 나오는 경우 이다.
우선 Class 위에 @SuppressWarnings({"rawtypes","unchecked"})
사용 후 그래도 나타나신다면, 사용안하는 변수나 Map이 있을 경우가 있으실테니 주석 처리를 하거나 삭제 해주시면 됨.
또한 for문이나 if문 안에 들어가서 Warnings이 일어나는 경우 그 문법 위에 @SuppressWarnings({"unused"})를 사용하면 됨.
함께 사용 하는 경우 @SuppressWarnings({"rawtypes","unchecked","unused"}) 를 클래스 테임 위에 추가 하면 된다.
단. 적용(대상이)이 없는경우 unchecked 나 unused 자체가 problems 가 나오게 되니 주의 하자.
페이징 처리. JSP 설명까지 포함 (2) | 2012.11.01 |
---|---|
html excel 추출 하기.& Jquery excel 추출 하기. (0) | 2012.06.16 |
정규표현식 공식 및 응용 . (0) | 2012.05.08 |
기본JDBC 만들기 (0) | 2012.05.08 |
Tiles(레이아웃처리) (0) | 2012.05.08 |
PHP는
<?
header("Content-Type: application/vnd.ms-excel");
?>
JSP는
<%@ page contentType="application/vnd.ms-excel; name='My_Excel'" %>
<%
response.setHeader("Content-Disposition", "inline; filename=myfile.xls");
response.setHeader("Content-Description", "JSP Generated Data");
%>
저 부분을 <HTML> 태그 앞에 넣으면 끝나지요.
저 페이지가 호출이 되면 오피스가 깔려있는 사용자들은 저장할것인지 그냥 열것인지를 물어보구여, 안깔려 있는 사용자들은 파일을 다운받을수 있게 되지요.
그럼 워드 파일은
<?
header("Content-Type: application/msword");
?>
파워포인트 역시 같은 방법으로
<?
header("Content-Type: application/vnd.ms-powerpoint");
?>
그럼 마지막으로 ASP에서는
<%
Response.Buffer = TRUE
Response.ContentType = "application/vnd.ms-excel"
%>
다음은 header 내용을 변경해서 excel로 바꾸어 주는 구문입니다.
* excel.php
<?php
header("Content-type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=test.xls");
header("Content-Description: PHP4 Generated Data");
?>
<html>
<body>
<table>
<tr>
<td>테스트1</td>
<td>테스트1</td>
<td>테스트1</td>
<td>테스트1</td>
</tr>
<tr>
<td>테스트2</td>
<td>테스트2</td>
<td>테스트2</td>
<td>테스트2</td>
</tr>
</table>
</body>
</html>
실행시켜보세요. 어떻게 되죠? test.xls 이름으로 excel 화일이 다운로드 되죠.
혹 DB내용을 excel형태로 출력해야될 때 유용할거 같습니다
[JSP] 쿼리결과를 엑셀로 추출
<%@ page contentType="application/vnd.ms-excel;charset=euc-kr" import="java.sql.*,java.text.*"%><%
response.setHeader("Content-Disposition", "inline; filename=myfile.xls"); // 파일 이름 지정
response.setHeader("Content-Description", "JSP Generated Data");
Connection con = null ;
Statement st = null ;
ResultSet rs = null ;
try{
con = ## 컨넥션 얻기 ##
st = con.createStatement();
rs = st.executeQuery("## 쿼리 ##");
ResultSetMetaData rsmd = rs.getMetaData();
%><html>
<body bgcolor=white>
<table border=1>
<tr bgcolor="#CACACA">
<% for ( int i = 1 ; i <= rsmd.getColumnCount() ; i ++ ) { %>
<th><%=rsmd.getColumnName(i)%></th>
<% } %>
</tr>
<%
while(rs.next()) {
%>
<tr>
<% for ( int i = 1 ; i <= rsmd.getColumnCount() ; i ++ ) { %>
<td><%
if ( rs.getString(rsmd.getColumnName(i)) == null ) {
out.print("");
} else {
out.print(rs.getString(rsmd.getColumnName(i)));
}
%></td>
<% } %>
</tr>
<% } %>
</table>
</body>
</html>
<%
} catch (Exception eee) {}
finally {
if ( rs != null ) rs.close();
if ( st != null ) st.close();
if (con != null ) con.close;
}
%>
2011/06/15 09:59
http://blog.naver.com/hogini/10111306100
기존에는 a.asp가 있고 그것을 excel로 저장하기 위해선 같은 a.asp 파일을 복사하여 a_e.asp를 만들고
a_e.asp의 상단 부분에 다음과 같은 구분을 삽입했다.
이럴경우 a.asp의 버튼이나 잡다한 것 까지 죄다 excel로 저장되어 지저분해지고. a_e.asp만 따로 해서 편집하자니
a.asp가 자주 변경되면 그것 또한 짜증이였다.
<% |
해서. JQuery를 사용해보니 훨씬 간편하고 아주 좋았다!
<form>에서 아래와 같이 onsubmit부분에 $("#excel_val")이라는 id, 즉 post로 넘겨줄 hidden값에 원하는구역에 <div>감싸고 그 id값.html()로
해당 <div> 아래의 모든 태그를 가지고 온다.
그리고 submit으로 a_e.asp로 날려주면 끝.
a_e.asp에선 request로 받아주면 된다.
또 하나 맘에 드는점은 jquery로 각종 스타일을 주고 excel 저장했던 기존방법은 html에선 잘되는데 엑셀로 저장하면 스타일이 안먹는 경우가
많았지만 jquery로 하니 현재 보이는 html상태를 excel에서 거의 그대로 저장하니 아주 만족!!
a.asp
<div id="excel_view"> <table> ... </table> </div> <input type="button" value="Excel" onclick="excel_save()" /> <!--엑셀 저장 버튼--> <!--엑셀로 저장--> |
a_e.asp
<% <html xmlns:o="urn:schemas-microsoft-com:office:office" <head> </head>
|
JSP
jQuery 를 이용해서 HTML 테이블을 엑셀로 저장하는 간단한 방법입니다.
다음은 HTML 코드입니다.
<form action="/SaveToExcel.jsp" method="post" target="_blank"
onsubmit='$("#dataToDisplay").val( $("<div>").append( $("#ReportTable").eq(0).clone() ).html() )'>
<pre><input type="image" src="/images/icons/save_excel.png"></pre>
<pre><input type="hidden" id="dataToDisplay" name="dataToDisplay" />
<table id="ReportTable">
... 중략
</table>
</form>
설명
reportTable - 저장하기 원하는 테이블 ID
dataToDisplay - 서버로 POST될 베이블을 위한 hidden변수
폼의 onSubmit시에 저장할 HTML 테이블을 jQuery 메서드로 쉽게 처리할수 있다.
<table>을 포함한 HTML코드를 가져오는 부분의 처리가 중요하다.
jQuery.html() 메서드는 innerHTML만 가져오므로 table id를 기준으로 실행하면 <table> 태그가 빠지게 된다.
그래서 <div> 안에 전체 <table> 을 append하면 <div> <table>...</table> </div> 가 되고
여기서 .html() 을 실행하면 <table>...</table> 을 리턴하므로 원하는 결과를 얻을 수 있다.
<%
response.setContentType("application/vnd.ms-excel; name='excel'");
response.setContentDisposition("filename=export.xls");
// Fix for crappy IE bug in download.
response.setHeader("Pragma","");
response.setHeader("Cache-Control","");
%>
<html>
<head></head>
<body>
${param.dataToDisplay}
</body>
</html>
페이징 처리. JSP 설명까지 포함 (2) | 2012.11.01 |
---|---|
Problems warning 를 제거 하자. (1) | 2012.10.23 |
정규표현식 공식 및 응용 . (0) | 2012.05.08 |
기본JDBC 만들기 (0) | 2012.05.08 |
Tiles(레이아웃처리) (0) | 2012.05.08 |
정규표현식 연산자, 기호 등을 가지고 AS-PATH에 대한 Filtering
서버에서도 많이 사용
연산자/기호의 종류 1. ^ : 시작을 의미
예) ^1 : 나의 neighbor의 AS가 준 정보, AS-PATH가 1로 시작하는 모든 정보
2. $ : 끝을 의미
예) 3$ : AS 3번이 만든 정보, AS-PATH가 3으로 끝나는 모든 정보
3. | : or을 의미
예) ^1|2 : 1로 시작하거나 2로 시작하는 정보
4. [] : 포함
예) [12345] 또는 [1-5] : 1 또는 2 또는 3 또는 4 또는 5를 포함하는 정보
5. _ : 시작(^), 끝($), 공백을 의미하지만 문자는 올 수 없음
예) _2_ : 2로 시작하거나 2로 끝나거나 2를 포함하는 정보
6. () : 분배
예) ^(2|3)_100 = ^2_100|^3_100 : 2로 시작하고 100을 포함하는 정보
7. . : 어떠한 문자가와도 상관이 없다
예) [1-5]. : 1부터 5를 포함하고 1~5에서 표기되는 모든 AS-PATH(11,22,33 등)를 포함
8. \ : 특수문자를 표시하기 위한 기호
예) \/24 : /24
9. * : AS뒤에 쓰여서 AS가 하나도 없거나 또는 무수히 많은 경우
예) ^[0-9]+_([0-9])+$ : AS번호가 2개 달린 경로의 일반화
10. + : AS뒤에 쓰여서 AS가 하나 있거나 또는 무수히 많은 경우
11. ? : AS뒤에 쓰여서 AS가 하나도 없거나 또는 하나인 경우
일반적 표현
예) ^$ : AS가 하나도 없는 경로, IBGP로 받은 정보
예) .* : 모든 경로
정규표현식 Configure
(config)# router bgp {AS번호} (config-router)# neighbor {Next-hop IP} filter-list {ACL num} (config)# ip as-path access-list {num} {permit|deny} {정규표현식} 또는
(config-router)#neighbor {next-hop IP} route-map {name} in (config)# route-map {name} (config-route-map)# match as-path {num} (config-route-map)# set ________________ (config)#ip as-path access-list {num} {permit|deny} {정규표현식}
예제
1. R1에서 R2로 들어올때 AS3 정보만 permit : 3$ or ^2_3$
2. R1에서 R4로 들어올때 AS6 정보만 permit : 6$ or ^4_5_6$ or ^[0-9]+[0-9]+[0-9]?$\
Problems warning 를 제거 하자. (1) | 2012.10.23 |
---|---|
html excel 추출 하기.& Jquery excel 추출 하기. (0) | 2012.06.16 |
기본JDBC 만들기 (0) | 2012.05.08 |
Tiles(레이아웃처리) (0) | 2012.05.08 |
Propertise 한글 사용 (0) | 2012.05.08 |
WEB-INF/lib 폴더 안에 ojdbc14.jar 파일을 넣는다. libraries/Web App Libraries 폴더 안에서 확인 가능
<?xml version="1.0" encoding="UTF-8" ?>
<%@page import="java.sql.SQLException"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>10/memberList.jsp</title>
</head>
<body>
<%
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
// 실행중에 해당 클래스를 로딩(문자열로) 하겠다.
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe","hun","java");
// member 라는 테이블이 생성 되어 있다는 전제 조건 하에 !
psmt=conn.prepareStatement("select * from member");
rs=psmt.executeQuery();
%>
<h4 align="center">회원 목록</h4>
<table align="center" border="1">
<thead>
<tr>
<th bgcolor="pink">ID</th>
<th bgcolor="pink">성명</th>
<th bgcolor="pink">직업</th>
<th bgcolor="pink">e-mail</th>
<th bgcolor="pink">hp</th>
</tr>
</thead>
<tbody>
<%
while(rs.next()){
%>
<tr>
<td><%=rs.getString("mem_id") %></td>
<td><%=rs.getString("mem_name") %></td>
<td><%=rs.getString("mem_job") %></td>
<td><%=rs.getString("mem_mail") %></td>
<td><%=rs.getString("mem_hp") %></td>
</tr>
<%} %>
</tbody>
</table>
</body>
</html>
<%
if(rs!=null)try{rs.close();}catch(SQLException e){}
if(psmt!=null)try{psmt.close();}catch(SQLException e){}
if(conn!=null)try{conn.close();}catch(SQLException e){}
%>
<?xml version="1.0" encoding="UTF-8" ?>
<%@page import="java.sql.SQLException"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="<%=request.getContextPath() %>/css/main.css" />
<title>11/memberview.jsp</title>
</head>
<body>
<div id="form">
<%
// 실제 회원아이디는 센션에서 꺼내야 합니다.
String id=request.getParameter("mem_id");
if(id==null || id.equals("")){
response.sendRedirect(request.getContextPath()+"/index.jsp");
return;
}
// 만약에 id 가 null 이라면
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
// 실행중에 해당 클래스를 로딩(문자열로) 하겠다.
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe","hun","java");
psmt=conn.prepareStatement("select * from member where mem_id = ?");
psmt.setString(1, id);
rs=psmt.executeQuery();
%>
<h4 align="center">회원 상세 보기</h4>
<table align="center" border="1">
<tbody>
<%
if(rs.next()){
%>
<tr>
<th>ID</th>
<td><%=rs.getString("mem_id") %></td>
</tr>
<tr>
<th>성명</th>
<td><%=rs.getString("mem_name") %></td>
</tr>
<tr>
<th>주민번호</th>
<td><%=rs.getString("mem_regno1") %>-<%=rs.getString("mem_regno2") %></td>
</tr>
<tr>
<th>생일</th>
<td><%=rs.getString("mem_bir") %></td>
</tr>
<tr>
<th>주소</th>
<td><%=rs.getString("mem_zip") %><br />
<%=rs.getString("mem_add1") %>
<%=rs.getString("mem_add2") %>
</td>
</tr>
<tr>
<th>집전화</th>
<td><%=rs.getString("mem_hometel") %></td>
</tr>
<tr>
<th>직장전화</th>
<td><%=rs.getString("mem_comtel") %></td>
</tr>
<tr>
<th>HP</th>
<td><%=rs.getString("mem_hp") %></td>
</tr>
<tr>
<th>e-mail</th>
<td><%=rs.getString("mem_mail") %></td>
</tr>
<tr>
<th>직업</th>
<td><%=rs.getString("mem_job") %></td>
</tr>
<tr>
<th>취미</th>
<td><%=rs.getString("mem_like") %></td>
</tr>
<tr>
<th>기념일</th>
<td><%=rs.getString("mem_memorial") %></td>
</tr>
<tr>
<th>마일리지</th>
<td><%=rs.getString("mem_mileage") %></td>
</tr>
<tr>
<th>탈퇴여부</th>
<td><%=rs.getString("mem_delete") %></td>
</tr>
<%}
else {
%>
<tr>
<td>
<span class="warning">
해당 회원이 존재 하지 않습니다.
</span>
</td>
</tr>
<%
}%>
</tbody>
</table>
</div>
</body>
</html>
<%
if(rs!=null)try{rs.close();}catch(SQLException e){}
if(psmt!=null)try{psmt.close();}catch(SQLException e){}
if(conn!=null)try{conn.close();}catch(SQLException e){}
%>
이 글은 스프링노트에서 작성되었습니다.
html excel 추출 하기.& Jquery excel 추출 하기. (0) | 2012.06.16 |
---|---|
정규표현식 공식 및 응용 . (0) | 2012.05.08 |
Tiles(레이아웃처리) (0) | 2012.05.08 |
Propertise 한글 사용 (0) | 2012.05.08 |
POI (0) | 2012.05.08 |
컴포지트 뷰(Composite View) 패턴을 구현한 라이브러리 중에서 현재 널리 사용되고 있는 라이브러리는 Tiles 2로서,
http://tiles.apache.org/download.html 사이트에서 최신버전을 다운로드 받을 수 있다. 현재 최신버전은 2.2.2이고 자바 5 또는 그 이상 버전에서 동작한다.
미니 코드
gate.jsp
1
2
3
|
<%@ page contentType= "text/html; charset=euc-kr" %> <tiles:insertDefinition name= "test" /> |
tiles-test.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?xml version= "1.0" encoding= "euc-kr" ?> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN" <tiles-definitions> <definition name= "test" template= "/container.jsp" > <put-attribute name= "title" value= "Hello" /> <put-attribute name= "header" value= "/header.jsp" /> <put-attribute name= "menu" value= "/side.jsp" /> <put-attribute name= "content" value= "/content.jsp" /> </definition> </tiles-definitions> |
web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
... <servlet> <servlet-name>tiles</servlet-name> <servlet-class>org.apache.tiles.web.startup.TilesServlet</servlet-class> <init-param> <param-name> org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG </param-name> <param-value> /WEB-INF/tiles-test.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> ... </web-app> |
container.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<%@ page contentType= "text/html; charset=euc-kr" %> <html> <head> <title><tiles:getAsString name= "title" /></title> </head> <body> <table width= "100%" border= "1" cellpadding= "0" cellspacing= "0" > <tr> <td colspan= "2" ><tiles:insertAttribute name= "header" /></td> </tr> <tr> <td valign= "top" ><tiles:insertAttribute name= "menu" /></td> <td valign= "top" ><tiles:insertAttribute name= "content" /></td> </tr> </table> </body> </html> |
TilesDispatchServlet을 사용하면 웹 요청 URI와 동일한 이름을 같는 Definition을 바로 클라이언트에 출력할 수 있다. TilesDispatchServlet을 사용하려면 <servlet>태그를 이용해서 TilesDispatchServlet을 web.xml 파일에 등록하고, <servlet-mapping>을 이용해서 TilesDispatchServlet이 처리할 확장자를 설정하면 된다.
web.xml
1
2
3
4
5
6
7
8
9
10
|
<servlet> <servlet-name>TilesDispatchServlet</servlet-name> <servlet-class> org.apache.tiles.web.util.TilesDispatchServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>TilesDispatchServlet</servlet-name> <url-pattern>*.tiles</url-pattern> </servlet-mapping> |
이 글은 스프링노트에서 작성되었습니다.
정규표현식 공식 및 응용 . (0) | 2012.05.08 |
---|---|
기본JDBC 만들기 (0) | 2012.05.08 |
Propertise 한글 사용 (0) | 2012.05.08 |
POI (0) | 2012.05.08 |
PAGING(sql) (0) | 2012.05.08 |
properties 파일의 유니코드로 표현 되는 한글을 인식 시켜 보자. !
이클립스의 기본 Properties Editor는 한글로 바로 표현이 안되고 유니코드로 표현되므로 유니코드를 한글로 인식시킬수있는 플러그인이 필요합니다.
테스트는 이클립스 3.7.2에서 했으며 이전에 사용하던 3.4, 3.5에서도 이상없이 동작 했습니다.
1. 이클립스 메뉴의 Help->Install New Software 클릭
2. 상단의 Add버튼 클릭후 Name에는 아무이름이나 정하고 Location에는 http://propedit.sourceforge.jp/eclipse/updates 입력하고 OK 클릭
3. 목록에 Pending이라는 글이 뜨고 잠시 기다리면 저장소에서 검색된 목록이 뜨는데
목록중 가장하단의 PropertiesEditor에 체크하고 next누르고 다음단계에서도 Next누르면서 설치.
4. 만약 이클립스 3.6이상을 사용중이라면 이클립스 marketplace를 이용하면 더 편하게 설치 할 수 있는데
방법은 이 블로그의 http://kdarkdev.tistory.com/36에서 find항목의 검색어만 변경하면 되는데 검색어는 properties editor 이고 세번째에 있는 'Pe' 라는 로고를 가진 플러그인을 선택하면 된다.
*** 설치후 이클립스 재시작 후 에도 Properties Editor가 설정 안될경우 ***
이클립스 메뉴의 window-preferences-general-Editors-File Associations의 *.properties 찾아서 하단의 Associated editors에 PropertiesEditor를 default로 설정한다.
이렇게 보이는 properties 파일이
이렇게 보인다.
이 글은 스프링노트에서 작성되었습니다.
기본JDBC 만들기 (0) | 2012.05.08 |
---|---|
Tiles(레이아웃처리) (0) | 2012.05.08 |
POI (0) | 2012.05.08 |
PAGING(sql) (0) | 2012.05.08 |
동적쿼리문 (0) | 2012.05.08 |
Jakarta POI
I. POI 란?
일반적으로 POI가 엑셀파일을 쓰는 컴퍼넌트로 알려져 있으나 POI는 프로젝트 이름입니다.
즉 POI는 Microsoft Format File을 액세스 할 수 있는 API를 제공합니다. (한마디로 자바에서 MS파일을 읽고 쓸수있도록 지원합니다.)
POI안에는 여러 컴퍼넌트들이 있습니다.
① POIFS Microsoft의 OLE2 포맷 형식의 문서를 자바로 읽고 쓸수 있는 컴퍼넌트입니다
기본적으로 POI의 모든 컴퍼넌트들이 POIFS를 사용합니다.
② HSSFMicrosoft의 엑셀파일을 읽고 쓸수 있도록 지원하는 컴퍼넌트입니다.
③ HWPFMicrosoft의 워드파일을 읽고 쓸수 있도록 지원하는 컴퍼넌트입니다.
이 컴퍼넌트는 디자인 초기단계입니다.
④ HPSFMicrosoft의 OLE2 포맷 형식의 문서 속성을 어플리케이션에서 사용 할수 있도록 지원하는 컴퍼넌트입니다.
현재 읽기 기능만 제공합니다
워드파일을 핸들링 하는 HWPF는 초기단계라 사용을 못하지만 기대는 되는군요 ^^
II. 다운로드 및 설치
http://poi.apache.org/download.html 드라이버 를 다운 받아 보자.
다운로드 받으러 갑시다~!
<실제 구현 POI> 구현 POI
현재 2.5.1버젼입니다.
다운받은 파일을 압축을 풀면 *.jar 파일들이 있을겁니다 이 파일들을 자신의 어플리케이션 /lib/에 복사합시다
POI API http://jakarta.apache.org/poi/apidocs/index.html
Quick Guidehttp://jakarta.apache.org/poi/hssf/quick-guide.html
III. Formula(수식) 지원에 관해..
엑셀을 읽고 쓸때 수식을 지원합니다.
org.apache.poi.hssf.usermodel.HSSFCell의 setCellFormula("formulaString") 메쏘드는 스프레드시트에 수식을 추가하는데 사용되며 getCellFormula() 메소드는 수식을 대표하는 문자열을 해석하는데 사용됩니다. 하지만 엑셀에서 사용하는 수식을 모두 사용 할 수는 없습니다.
① 지원되는 부분
-. 셀 참조, 시트참조, 지역참조
-. 상대적 혹은 절대적 참조
-. 수연산 및 논리연산
-. 시트 혹은 매크로 함수
-. 수식 결과값 반환
② 부분적 지원
문자열을 포함하는 수식을 해석할 수는 있지만 문자열값을 반환하는 수식은 아직 지원하지 않습니다.
③ 지원되지 않는 부분
-. 배열 수식
-. 1진법 수식
-. 3D 참조
-. 에러 값 (cells containing #REF's or #VALUE's)
IV. 기본객체
가장 기본이되는 객체가 다음 4가지 입니다
이름에서 무엇을 뜻하는지 대강 짐작 할 수 있겠죵?
① HSSFWorkbook - 엑셀 워크북을 말합니다.
② HSSFSheet - 엑셀 쉬트를 나타냅니다.
③ HSSFRow - 엑셀에서 특정 행입니다.
④ HSSFCell - 엑셀에서 특정 행에대한 특정 셀입니다
위 4가지 객체는 앞으로 계속 나올겁니다. 눈여겨 미리 봐 둡시다. @.@
V. 엑셀 읽기 예제
① POSFS을 이용하여 엑셀 워크북을 생성합니다.
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream("excelfile.xls"));
HSSFWorkbook workbook = new HSSFWorkbook(fs);
② 생성된 워크북을 이용하여 시트 수만큼 돌면서 엑셀 시트 하나씩을 생성합니다.
int sheetNum = workbook.getNumberOfSheets();
for (int k = 0; k < sheetNum; k++) {
System.out.println("Sheet Number : "+k);
System.out.println(Sheet Name : " + workbook.getSheetName(k));
HSSFSheet sheet = workbook.getSheetAt(k);
}
③ 생성된 시트를 이용하여 그 행의 수만큼 돌면서 행을 하나씩 생성합니다.
int rows = sheet.getPhysicalNumberOfRows();
for (int r = 0; r < rows; r++) {
HSSFRow row = sheet.getRow(r);
System.out.println("Row : "+row.getRowNum());
}
④ 역시나 생성된 행을 이용하여 그 셀의 수만큼 돌면서 셀을 하나씩 생성합니다.
int cells = row.getPhysicalNumberOfCells();
for (short c = 0; c < cells; c++) { <--!! short 형입니다. 255개가 max!
HSSFCell cell = row.getCell(c);
int celltype = cell.getCellType();
...
}
셀을 생성하여 셀 타입에 따라 처리를 해주면 끝~
⑤ 주의사항
만약 엑셀에서 A열에 아무런 값이 없으면 그 행은 읽지 못합니다.
행을 읽지 못하니 셀또한 처리 할 수 없습니다
VI. 엑셀읽기 샘플소스
샘플 데이터
A열은 B열에 대한 셀 타입을 나타내며 C열은 D열에대한 셀 타입을 나타냅니다.즉 B:1 의 123456의 셀 타입은 A:1 일반 이라는 것이며 마찬가지로 D:1의 2005-02-09의 셀타입은 C:1 사용자정의로 세팅하였다는 겁니다
이 엑셀의 데이터를 다음 소스로 읽어 보겠습니다.
<%@ page <html> String excelfile = "C:\\Tomcat 5.0\\webapps\\ROOT\\example.xls"; try { //워크북을 생성! HSSFWorkbook workbook = new HSSFWorkbook(fs); int sheetNum = workbook.getNumberOfSheets(); for (int k = 0; k < sheetNum; k++) { //시트 이름과 시트번호를 추출
for (short c = 0; c < cells; c++) { // 행에대한 셀을 하나씩 추출하여 셀 타입에 따라 처리 switch (cell.getCellType()) { case HSSFCell.CELL_TYPE_FORMULA : %>
|
위 소스의 결과입니다.
Sheet Number 0 |
결과를 보니 사용자가 지정한 셀 타입에 관계없이 숫자관련 셀은 POI에서 모두 숫자 타입으로 인식해 버렸습니다. 날짜 역시 지정한 셀 타입에 관계없이 모두 숫자 타입으로 인식해 버리는군요!
그럼 어떻게 날짜를 제대로 표현할까요?
날짜 타입을 제대로 나타내기 위해서는 날짜 Cell에는 getDateCellValue()를 사용하면정상적으로 처리 할 수 있습니다.
SimpleDateformat sdf = new SimpleDateformat("yyyy-MM-dd hh:mm");
String date = sdf.format(cell.getDateCellValue());
등을 이용하면 나타내고자 하는 알짜를 표현 하기 더 쉽겠지요
나머지 수식을 가져 올때도 마찬가지입니다. 이런 사항을 도표로 나타내보았습니다.
org.apache.poi.hssf.usermodel.HSSFCell 에는 모두 6가지의 Cell Type이 있는데, cell.getCellType()을 하면 그 셀의 반환값을 알 수 있으며 그에 상응하는 static 필드타입은 다음과 같습니다.
셀타입 | 필드타입 |
함수 |
함수반환값 |
0 | CELL_TYPE_NUMERIC |
getNumericCellValue() -> 숫자 타입일때 getDateCellValue() -> 날짜 타입일때 |
double Date |
1 | CELL_TYPE_STRING |
getStringCellValue() |
String |
2 | CELL_TYPE_FORMULA |
getCellFormula() -> 수식자체를 가져올때 getNumericCellValue() -> 수식 반환값이 숫자일때 getStringCellValue() -> 수식 반환값이 문자일때 |
String double String |
3 | CELL_TYPE_BLANK |
|
|
4 | CELL_TYPE_BOOLEAN |
getBooleanCellValue() |
boolean |
5 | CELL_TYPE_ERROR |
getErrorCellvalue() |
byte |
이 글은 스프링노트에서 작성되었습니다.
Tiles(레이아웃처리) (0) | 2012.05.08 |
---|---|
Propertise 한글 사용 (0) | 2012.05.08 |
PAGING(sql) (0) | 2012.05.08 |
동적쿼리문 (0) | 2012.05.08 |
Multiple Parameter (0) | 2012.05.08 |
-- 페이징 기법. 가정.
-- 총레코드 수:33 int totalRowCount = 33
-- 목록수:30 int size = 10
-- 총 페이지수 :(총레코드수 -1)/목록수 +1 int totalPageCount = (totalRowCount-1)/listSize+1
-- 현제 페이지 :3 int curPage = 3
-- 시작행 : (페이지 -1)
psmt=conn.prepareStatement(sb.toString());
int startRow = 1;
int endRow = 10;
if(paramMap.containsKey("startRow")){
startRow=(Integer)paramMap.get("startRow");
}
if(paramMap.containsKey("endRow")){
endRow=(Integer)paramMap.get("endRow");
}
psmt.setInt(1,endRow);
psmt.setInt(2,startRow);
rs=psmt.executeQuery();
select *
from (select rownum rn,a.*
from (select *
from board
order by bo_no desc
)a
where rownum <=?
)
where rn >=? ;
1, 시작 페이지 넘버
2. 마지막 페이지 넘버
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!-- 페이징 처리 수행 페이지 -->
<%--
/*
Input Parameter :
이미지 파라미터
1. firstPageImg : 처음으로 버튼 이미지
2. prevPageImg : 이전 X 페이지로 이동 버튼 이미지
3. nextPageImg : 다음 X 페이지로 이동 버튼 이미지
4. lastpageImg : 마지막 페이지로 이동 버튼 이미지
페이지 관련 이미지
5. totalRowCount : 총 데이터 로우의 개수
6. rowNumPerPage : 한페이지당 리스트할 로의 개수
7. pageCount : 한 화면에 보여질 페이지 개수 1 ~ 10, 11 ~ 20
8. pageNo : 페이지 번호
9. target : 페이징을 구분할 타겟 정보
사용법
a. 페이지 인클루드
<jsp:include flush="true" page="./paging.jsp">
<jsp:param name="firstPageImg" value="./images/firstImg.jpg"/>
<jsp:param name="prevPageImg" value="./images/prevImg.jpg"/>
<jsp:param name="nextPageImg" value="./images/nextImg.jpg"/>
<jsp:param name="lastPageImg" value="./images/lastImg.jpg"/>
<jsp:param name="totalRowCount" value="105"/>
<jsp:param name="rowNumPerPage" value="10"/>
<jsp:param name="pageCount" value="10"/>
<jsp:param name="pageNo" value="3"/>
<jsp:param name="target" value="TEST_PAGE"/>
</jsp:include>
b. 자바 스크립트 작성
<script type="text/javascript">
<!--
function searchByTarget(pageNo, target)
{
// TODO
}
//-->
</script>
*/
--%>
<%
int totalRowCount = 1; // 전체 로 개수
int rowNumPerPage = 5; // 페이지당 로의 개수
int pageCount = 10; // 한 화면에 보여질 페이지 번호 개수
int pageNo = 1; // 현재 선택된 페이지 번호
String firstPageImg = "/blog/images/bl_nv_start.gif"; // 처음 페이지 이동 이미지
String prevPageImg = "/blog/images/bl_nv_prev.gif"; // 이전 X 페이지 이동 이미지
String nextPageImg = "/blog/images/bl_nv_next.gif"; // 다음 X 페이지 이동 이미지
String lastPageImg = "/blog/images/bl_nv_last.gif"; // 마지막 페이지 이동 이미지
firstPageImg = request.getParameter("firstPageImg")== null ? firstPageImg : request.getParameter("firstPageImg");
prevPageImg = request.getParameter("prevPageImg") == null ? prevPageImg : request.getParameter("prevPageImg");
nextPageImg = request.getParameter("nextPageImg") == null ? nextPageImg : request.getParameter("nextPageImg");
lastPageImg = request.getParameter("lastPageImg") == null ? lastPageImg : request.getParameter("lastPageImg");
String target = request.getParameter("target"); // 페이징 구분 타겟 코드(한번에 페이징이 여러개인경우 구분해주는 기능)
try {
totalRowCount = Integer.parseInt(request.getParameter("totalRowCount"));
} catch (NumberFormatException e) {
}
try {
rowNumPerPage = Integer.parseInt(request.getParameter("rowNumPerPage"));
} catch (NumberFormatException e) {
}
try {
pageCount = Integer.parseInt(request.getParameter("pageCount"));
} catch (NumberFormatException e) {
}
try {
pageNo = Integer.parseInt(request.getParameter("pageNo"));
} catch (NumberFormatException e) {
}
int lastPageNum = (totalRowCount - 1) / rowNumPerPage + 1; // 전체 페이지 개수
int startPageNum = ((pageNo - 1) / pageCount) * pageCount + 1; // 화면에 보여질 시작 페이지 번호
int endPageNum = startPageNum + pageCount - 1; // 화면에 보여질 종료 페이지 번호
if(endPageNum > lastPageNum) endPageNum = lastPageNum; // 종료 페이지 범위 처리
int prevPageGroup = 1;
int nextPageGroup = lastPageNum;
if(startPageNum - pageCount < 1) {
prevPageGroup = 1;
}
else {
prevPageGroup = startPageNum - endPageNum;
if(prevPageGroup <= 0) {prevPageGroup = 1;}
}
if(endPageNum + 1 > lastPageNum) {
nextPageGroup = lastPageNum;
}
else {
nextPageGroup = endPageNum + 1;
}
%>
<!-- 처음 페이지로 이동-->
<a href="javascript:searchByTarget('1', '<%=target %>');">
<img src="<%=firstPageImg %>" border="0" alt="처음 페이지" align="absmiddle">
</a>
<!-- 이전 X 페이지 이동 -->
<a href="javascript:searchByTarget('<%=prevPageGroup %>', '<%=target %>');">
<img src="<%=prevPageImg %>" border="0" alt="이전 <%=pageCount %>페이지" align="absmiddle">
</a>
<!-- 페이지 번호 표시 -->
<%
for (int i = startPageNum; i <= endPageNum; i++) {
if (i == pageNo) {
%>
<font color="RED"><b><%=i %></b></font> |
<%
}
else {
%>
<a href="javascript:searchByTarget('<%=i %>', '<%=target %>');">
<font color="NAVY"><%=i %></font>
</a>|
<%
}
}
%>
<!-- 다음 X 페이지 이동 -->
<a href="javascript:searchByTarget('<%=nextPageGroup %>', '<%=target %>');">
<img src="<%=nextPageImg %>" border="0" alt="다음 <%=pageCount %>페이지" align="absmiddle">
</a>
<!-- 마지막 페이지 이동 -->
<a href="javascript:searchByTarget('<%=lastPageNum %>', '<%=target %>');">
<img src="<%=lastPageImg %>" border="0" alt="마지막 페이지" align="absmiddle">
</a>
첨부파일 내용 다운로드 :
이 글은 스프링노트에서 작성되었습니다.
Propertise 한글 사용 (0) | 2012.05.08 |
---|---|
POI (0) | 2012.05.08 |
동적쿼리문 (0) | 2012.05.08 |
Multiple Parameter (0) | 2012.05.08 |
log4j구현환경제공. (0) | 2012.05.08 |
iBatis 에서 mybatis 로 바뀌면서 바뀐것들 중에 하나가 동적쿼리문에서 쓰는 태그들이다.
iBatis 에 있던 <isEqual/> <isNotEqual/> 요런 것들이
mybatis 에서는 <if test="xxx == 'a'"></if> <if test="xxx != 'a'"></if> 요렇게 대체할 수 있어서 쫌더 간결해 진것 같다.
그런데 test="" 요기에서 쓸수 있는 비교연산자들 중에는 null 인지 빈 공백인지 판단하던 <isEmpty/>, <isNotEmpty/> 를 대체할만한 비교연산자가 없었다.
null 인지 공백인지 mybatis 에서 판단하기 위해서는
1
|
< if test = "xxx == null or xxx == ''" ></ if > |
어째 다른 방법이 없나 쭉 찾아보니까~ 신기하게도 조건문에서 자바 클래스의 메소드를 호출해서 하는 방법이 있었다.
클래스를 하나 맨들고 거기에다 boolean 을 리턴해주는 static 메소드들을 뽓 맨들고 고것을 호출하는 방식이다.
내가 작성해본 클래스는 요렇다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package stove99.tistory.com; import java.lang.reflect.Array; import java.util.List; import java.util.Map; public class MyComparator { public static boolean isEmpty(Object obj){ if ( obj instanceof String ) return obj== null || "" .equals(obj.toString().trim()); else if ( obj instanceof List ) return obj== null || ((List)obj).isEmpty(); else if ( obj instanceof Map ) return obj== null || ((Map)obj).isEmpty(); else if ( obj instanceof Object[] ) return obj== null || Array.getLength(obj)== 0 ; else return obj== null ; } public static boolean isNotEmpty(String s){ return !isEmpty(s); } } |
죠렇게 맨든 클래스를 땡겨다 쓰는 mabatis sql xml 예제는 요렇다.
1
2
3
4
5
6
7
8
9
|
< select id = "testSQL" parameterType = "map" resultType = "hashmap" > SELECT * FROM TB_TEST WHERE 1=1 <!-- @패키지.클래스명@호출할메소드(파라메터) --> < if test = "@stove99.tistory.com.MyComparator@isEmpty(keyword)" > AND KEYWORD = #{keyword} </ if > </ select > |
@패키지명.클래스@메소드 요렇게 호출해야 되기 때문에 패키지나 클래스명은 간단하게 명명하면 좋을것 같다.
이 글은 스프링노트에서 작성되었습니다.
POI (0) | 2012.05.08 |
---|---|
PAGING(sql) (0) | 2012.05.08 |
Multiple Parameter (0) | 2012.05.08 |
log4j구현환경제공. (0) | 2012.05.08 |
MyBatis (odbc프레임웍) (0) | 2012.05.08 |
MyBatis 3.0의 예제를 보면 파라미터를 하나 던지는 예제만 줄줄 있습니다.
그 타입이 primitive 이던, POJO 형태든지 말이죠.
여러 개의 파라미터를 던지려면 @Param 어노테이션을 사용하고, map으로 xml 파일에 정의해 주면 됩니다.
1. 먼저 Mapper Interface에 메소드를 정의합니다.
public Map selectMachineAgentMap(@Param("machineId") int machineId, @Param("agentId") int agentId);
2. mapper.xml 파일에 paramterType을 map으로 잡습니다.
위 와 같이 하면 MyBatis는 맵 객체를 생성하고 거기에 @Param에 해당하는 이름으로 전달받은 인자를 저장합니다. 이후 프로세서에서는 #{}의 이름에 해당하는 key를 이용하여 데이터를 추출하고 컬럼의 메타데이터에 해당하는 타입으로 캐스팅하여 쿼리를 날리게 됩니다.
이 글은 스프링노트에서 작성되었습니다.
PAGING(sql) (0) | 2012.05.08 |
---|---|
동적쿼리문 (0) | 2012.05.08 |
log4j구현환경제공. (0) | 2012.05.08 |
MyBatis (odbc프레임웍) (0) | 2012.05.08 |
MVC패턴 (0) | 2012.05.08 |
그림과 과 같은 구조에 주의 하자.
res 라는 clasess 폴더 안의 패키지 kr.or.ddit.mybatis 안에 마이바티스팩토리와 config.xml 이 구조화 되어있다.
log4j.properties 라는 프로 퍼티스 파일을 res 즉 클래스시스 루트단에 생성 한후.
의 내용을 적어 놓으면 . 자동으로 설정 된다. log4j 의 경우 마이바티스 에서 자동으로 리포팅 하여 설정 되는듯 하다.
내부의 자세한 내용은 JSP 단의 log4j 에서 확인 하자.
이 글은 스프링노트에서 작성되었습니다.
동적쿼리문 (0) | 2012.05.08 |
---|---|
Multiple Parameter (0) | 2012.05.08 |
MyBatis (odbc프레임웍) (0) | 2012.05.08 |
MVC패턴 (0) | 2012.05.08 |
Login&Logout 기본패턴 (0) | 2012.05.08 |
마이바티스
위의 링크로 들어가 jar 파일을 다운받은후 추가 하자.
신세계 마이바티스를 공부해 보자. (아이바 티스를 안보신분은 먼저 그것부터 보길 바란다 ) http://sararing.springnote.com/pages/10976942
MyBatis-3-User-Guide_ko.pdf <== 마이바 티스 한글 유저 가이드 .
먼저 마이바티스란. odbc 프레임웍으로 웹페이지 에서 필요한 디비를 최대한 능동적으로 (빠른 접속시간및 코드의 효율 최상화)를 위해 사용 하게 된다.
먼저 우리가 기본적으로 생성하게 되는 MemberDaoOracleMpl.java 파일을 보자
findByPk 메서드를 중심으로 설명해 보겠다.
rs 생성후 파라미터 연결 또 보드객체 생성 받고 rs psmt conn 닫고 ./ 여기서 이러한 코드들이 거의 의미 없이 무제한 적으로 사용 하게 되는것에 의문을 가질수 있다.
실제로 쿼리 문장은 매우 규칙적이고 심플 하기 때문에 이러한 의미 없는 코딩을 줄이고 풀링및 접속 환경 까지 제어 해주는것이 마이바티스 이다.
위와 같은 코드식을
이렇게 만들었다. DAO 의 인터페이스인 IMDAO를 implement 했다. 이렇든 간단하게 형식에 맞추어 구현이 가능한 것이 마이바 티스 이다.
사용에 먼저 가장 먼저 할일은
res 소스 폴더를 만든다 이후에 kr.or.ddit.mybatis 패키지를 생성후 패키지의 루트에 config.xml 파일을 생성 하자.
마이바티스 기본 설정 이다. jar 파일은 이미 추가 했다는 전제 이다.
config.xml 의 소스 내용 이다. 중요한 부분으로는 typeAliases 를 볼수 있다 . 위 소스를 보면 MemberBean 및 BoardBean 과 같은 bean 파일을 type 으로 지정 하여
애칭을 주며. 차후에 factory 등에서 쉽게 kr.or.ddit.member.vo.MemberBean 를 member 라고 적어 구현 할수 있다.
여기서 중간 내용을 적용 하여 dataSource pooled 에서 드라이브및 url username password 등을 적어 구현 한다.
밑단에 보면 mappers 를 확인해 보자. 이하 매핑 이라고 하면 mappers 라고 알고 있자
mapper 의 리소스에는 mapping 에 각기 member.xml board.xml 이 있다 이이곳에서 실질적인 데이터베이스에 필요한 sql 문을 구현 하게 된다.
위 사진은 member.xml 구현부 이다. 여기서 namespace 를 DAO 에 잡으며 반드시 select 문의 id 값은 DAO 에서 구현한 메서드의 이름과 같아야 자동 매칭이 가능하다.
구문 에서 parameterType="String" resultType="member" 메서드 실행시 파라미터 의 종류로 String 과 돌려주는 값이 member 임을 알수 있다.
여기서 member는 위에서 알리아스(애칭)을 적용 한값을 사용 함을 알수 있다.
받은 값에 대하여 마치 파라미터를 받는것과 마찬 가지로 #{mem_id} 등의 형식으로 적어 member 객체로 받아 MemberDaoMyBatis.java 에서 구현 한다.
위의 사진에서 MemberDaoMyBatis.java 의 구현 사진이다. 실질적으로 MemberServiceIMpl.java 에서는 이 명령을 구현 하게 된다 . session factory 구현에 메퍼를 사용함을
주의 깊게 보자. openSession파라미터 true commit()을 의미 하니 셀렉트 문에는 구지 안넣어도 되나 db 값이 변화 하는 경우 반드시 추가 해야만 한다.
위의 사진에서 보면 실질적으로 jsp 단에서 파일을 생성 구현 하는 부분은 두 부분이다. 먼저 직접적인 생성및 사용하게 되는 BoardServiceIMple 이 있다.이곳 에서 일차 적으로 jsp 에서 사용 하게 되며
service 에서는 두가지 선택이 가능 하다. BoardDaoOracle 과 BoardDaoMybatis 이다. 기본적인 factory 단을 이용 하여 구현 하는게 훨신 간단하게 소스구현을 할수 있다는것을 알수 있다.
추가로 member의 UML 도 확인하자.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias alias="member" type="kr.or.ddit.member.vo.MemberBean"/>
<typeAlias alias="board" type="kr.or.ddit.board.vo.BoardBean"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/>
<property name="username" value="hun"/>
<property name="password" value="java"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="kr/or/ddit/mapping/member.xml"/>
<mapper resource="kr/or/ddit/mapping/board.xml"/>
</mappers>
</configuration>
package kr.or.ddit.mybatis;
import java.io.IOException;
import java.io.Reader;
import javax.management.RuntimeErrorException;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.io.Resources;
public class MyBatisFactory {
private static SqlSessionFactory sqlMapper;
static{
try {
String resource = "kr/or/ddit/mybatis/config.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlMapper = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
public static SqlSessionFactory getSqlMapper() {
return sqlMapper;
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.board.dao.IBoardDao">
<cache eviction="LRU" flushInterval="600000" size="512" readOnly="true" />
<select id="findAllByPage" parameterType="map" resultType="board">
select *
from (select rownum rn,a.*
from (select *
from board
order by bo_no desc
)a
where <![CDATA[ rownum <= #{endRow}]]>
)
where <![CDATA[rn >= #{startRow}]]>
</select>
<select id="findByPk" parameterType="int" resultType="board">
select * from BOARD where bo_no=#{bo_no}
</select>
<select id="getBoardCount" resultType="int" parameterType="map">
select count(*) from board
</select>
<insert id="insertBoard" parameterType="board" >
INSERT INTO board (bo_no,bo_title,bo_writer,bo_passwd,bo_email,bo_ip,
bo_content,bo_hit,bo_date)
VALUES(board_seq.nextval,#{bo_title}, #{bo_writer}, #{bo_passwd}, #{bo_email}, #{bo_ip},
#{bo_content}, 0, sysdate)
</insert>
<update id="hitCount" parameterType="board">
update board set
BO_HIT =#{bo_hit}
where BO_NO=#{bo_no}
</update>
<update id="updateBoard" parameterType="board">
update board set
BO_TITLE =#{bo_title},
BO_WRITER =#{bo_writer},
BO_EMAIL =#{bo_email} ,
BO_IP =#{bo_ip} ,
BO_CONTENT =#{bo_content}
where BO_NO=#{bo_no}
</update>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.member.dao.IMemberDao">
<select id="findByPk" parameterType="String" resultType="member">
select * from member where mem_id= #{mem_id}
</select>
<select id="findByAll" resultType="member">
select * from member
</select>
<insert id="insertMember" parameterType="member">
INSERT INTO MEMBER
(MEM_ID,MEM_PASS, MEM_NAME,MEM_REGNO1,MEM_REGNO2,MEM_BIR,
MEM_ZIP, MEM_ADD1, MEM_ADD2, MEM_HOMETEL, MEM_COMTEL, MEM_HP,
MEM_MAIL, MEM_JOB, MEM_LIKE, MEM_MEMORIAL,MEM_MEMORIALDAY,
MEM_MILEAGE, MEM_DELETE)
VALUES
(#{mem_id},#{mem_pass}, #{mem_name},#{mem_regno1},#{mem_regno2},#{mem_bir},
#{mem_zip}, #{mem_add1}, #{mem_add2}, #{mem_hometel}, #{mem_comtel}, #{mem_hp},
#{mem_mail}, #{mem_job}, #{mem_like}, #{mem_memorial},#{mem_memorialday},0,'N' )
</insert>
<update id="updateMember" parameterType="member">
update MEMBER set
MEM_NAME =#{mem_name},
MEM_REGNO1 =#{mem_regno1},
MEM_REGNO2 =#{mem_regno2},
MEM_BIR =#{mem_bir},
MEM_ZIP =#{mem_zip},
MEM_ADD1 =#{mem_add1},
MEM_ADD2 =#{mem_add2},
MEM_HOMETEL =#{mem_hometel},
MEM_COMTEL =#{mem_comtel},
MEM_HP =#{mem_hp},
MEM_MAIL =#{mem_mail},
MEM_JOB =#{mem_job},
MEM_LIKE =#{mem_like},
MEM_MEMORIAL =#{mem_memorial},
MEM_MEMORIALDAY =#{mem_memorialday},
MEM_MILEAGE =#{mem_mileage},
MEM_DELETE =#{mem_delete}
where MEM_ID =#{mem_id}
</update>
<select id="findByJob" resultType="member">
select * from member
<where>
<if test="array !=null">
<foreach collection="array" item="item" open=" mem_jop in(" close=")" separator=",">
#{item}
</foreach>
</if>
</where>
</select>
</mapper>
package kr.or.ddit.board.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import kr.or.ddit.board.vo.BoardBean;
import kr.or.ddit.mybatis.MyBatisFactory;
public class BoardDaoMyBatis implements IBoardDao {
private SqlSessionFactory factory = MyBatisFactory.getSqlMapper();
@Override
public int insertBoard(BoardBean board) {
SqlSession session = factory.openSession(true);
try {
IBoardDao boardDao = session.getMapper(IBoardDao.class);
return boardDao.insertBoard(board);
} finally{
session.close();
}
}
@Override
public int updateBoard(BoardBean board) {
SqlSession session = factory.openSession(true);
try {
IBoardDao boardDao = session.getMapper(IBoardDao.class);
return boardDao.updateBoard(board);
} finally{
session.close();
}
}
@Override
public int deleteBoard(BoardBean board) {
SqlSession session = factory.openSession();
try {
IBoardDao boardDao = session.getMapper(IBoardDao.class);
return boardDao.deleteBoard(board);
} finally{
session.close();
}
}
@Override
public int getBoardCount(Map<String, Object> paramMap) {
SqlSession session = factory.openSession();
try {
IBoardDao boardDao = session.getMapper(IBoardDao.class);
return boardDao.getBoardCount(paramMap);
} finally{
session.close();
}
}
@Override
public List<BoardBean> findAllByPage(Map<String, Object> paramMap) {
SqlSession session = factory.openSession();
try {
IBoardDao boardDao = session.getMapper(IBoardDao.class);
return boardDao.findAllByPage(paramMap);
} finally{
session.close();
}
}
@Override
public BoardBean findByPk(int bo_no) {
SqlSession session = factory.openSession();
try {
IBoardDao boardDao = session.getMapper(IBoardDao.class);
return boardDao.findByPk(bo_no);
} finally{
session.close();
}
}
@Override
public int hitCount(BoardBean board) {
SqlSession session = factory.openSession(true);
try {
IBoardDao boardDao = session.getMapper(IBoardDao.class);
return boardDao.hitCount(board);
} finally{
session.close();
}
}
}
package kr.or.ddit.member.dao;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import kr.or.ddit.member.vo.MemberBean;
import kr.or.ddit.mybatis.MyBatisFactory;
public class MemberDaoMyBatis implements IMemberDao {
private SqlSessionFactory factory = MyBatisFactory.getSqlMapper();
@Override
public int insertMember(MemberBean member) {
// factory.openSession(true); 오토코밋 가능
SqlSession session = factory.openSession(true);
try {
//return session.insert("kr.or.ddit.member.dao.IMemberDao.insertMember",member);
// 위에엇을 밑에 것으로 변환 해서 사용.
IMemberDao dao = session.getMapper(IMemberDao.class);
return dao.insertMember(member);
} finally {
session.close();
// session 을 close 하면서 dao를 null로 돌려 주므로 IMemberDao 를 전역 변수로 사용 하지 않아도 된다..
}
}
@Override
public int updateMember(MemberBean member) {
// factory.openSession(true); 오토코밋 가능
SqlSession session = factory.openSession(true);
try {
IMemberDao dao = session.getMapper(IMemberDao.class);
return dao.updateMember(member);
//return session.update("kr.or.ddit.member.dao.IMemberDao.updateMember",member);
} finally {
session.close();
}
}
@Override
public int deleteMember(String mem_id) {
// TODO Auto-generated method stub
return 0;
}
@Override
public List<MemberBean> findByAll() {
SqlSession session = factory.openSession();
try {
//return session.selectList("kr.or.ddit.member.dao.IMemberDao.findByAll");
IMemberDao dao = session.getMapper(IMemberDao.class);
return dao.findByAll();
} finally {
session.close();
}
}
@Override
public MemberBean findByPk(String mem_id) {
SqlSession session = factory.openSession(true);
try {
IMemberDao dao = session.getMapper(IMemberDao.class);
return dao.findByPk(mem_id);
} finally {
session.close();
}
}
}
이 글은 스프링노트에서 작성되었습니다.
Multiple Parameter (0) | 2012.05.08 |
---|---|
log4j구현환경제공. (0) | 2012.05.08 |
MVC패턴 (0) | 2012.05.08 |
Login&Logout 기본패턴 (0) | 2012.05.08 |
log4j (0) | 2012.05.08 |
그림 1 MVC Pattern Diagram
<그림 1>에서는 일반적인 MVC 패턴을 다이어그램으로 표현하고 있습니다.
MVC 패턴은 Model, View, Controller 세 개의 컴포넌트로 구성되는데 각 컴포넌트에서 담당하는 책임은 다음과 같습니다.
MVC 패턴이 MVP패턴과 다른 점은 Presenter 컴포넌트 대신 Controller 컴포넌트가 존재하는 것이죠. Controller는 사용자의 액션 - 예를 들면 버튼 컨트롤을 클릭하거나 키보드를 통해 텍스트를 입력 받는 행위들 - 에 반응하여 적절한 행동을 하는 코드를 포함합니다. 즉, 사용자의 액션에 반응하여 Model의 데이터를 변경하는 역할을 수행합니다.
MVC 패턴이 적용된 대표적인 사례는 MFC(CDocument <-> CView), ASP.NET(ASPX <-> Code Behind), WinForm.NET(Form & Control Design.cs<-> Form & Control .cs <-> Entity or Business Logic .cs) , JSP등이 있겠습니다. 특히 JSP에서는 (자바진영) View와 Controller가 합쳐진 Model 1과 View와 Controller를 명확히 구분하고 View와 Model 사이에 상호작용을 전담하는 역할로서 Controller를 정의합니다.
그림 2 JSP Model 1 architecture
그림 3 JSP Model 2 architecture
Model 1에서는 JSP에서 사용자 Request(Controller)와 Response(View)를 담당하고 Data source의 접근 처리는 JavaBean(Model)에서 담당하게 됩니다.
Model 2에서는 사용자 Request를 Servlet(Controller)에서 담당하고 Response는 JSP(View), Data source의 접근 처리는 JavaBean(Model)에서 담당하게 되죠.
이와 비슷한 모델로 최근 ASP.NET 3.5에서 발표될 MVC Framework를 들 수 있겠습니다. Request URL을 Controller가 분석해서 Model에 데이터를 쿼리(조회, 갱신)하고 적합한 View를 선택해서 Rendering하는 방식입니다.
문제는 View와 모델을 완전히 분리할 수 없다는 것이죠.
JSP의 Model2를 보셔도 JSP와 JavaBean과의 상호작용은 피할 수 없습니다. 역시 ASP.NET의 MVC Framework에서도 Controller에서 Model에 쿼리를 수행한 다음 반환된는 Entity(or Entity List)를 View에 바인딩할 때 Entity 자체를 넘겨주게 되므로 View에서 Model을 의존하게 되는 상황이 발생하게 되죠.
또한 MVC 패턴에서 Model에 연결된 View가 여럿일 경우 Model과 View간(또는 Model을 대신해서 Controller) Observer패턴을 적용하여 Model(or Controller)에서 View로 Notify하는 (Active Model) 방식이 사용되거나 반대로 View에서 Model을 polling(Passive Model)하는 방식이 수행됩니다.
그림 4 MVC passive model
그림 5 MVC active model
그림 6 Using observer pattern to decouple the model from view in the active model
이 프로세스를 살펴봐도 역시 View와 Model의 커플링은 제거하기 힘들어 보이는 군요.
(이런 논의도 있습니다. http://kldp.org/node/70219 )
애초에 MVC패턴이 나온 이유가 뭘까요?
바로 View와 Model의 분리입니다. 쉽게 말해 표현계층과 데이터( + 데이터 처리 로직)를 분리하여 데이터 처리 로직이 중복 코딩되는 것을 막고 로직과 엔티티(데이터)를 재 사용하는데 그 목적이 있습니다. 또한 GUI의 단위 테스트 코드를 작성할 수 있을지에 대한 기대감도 포함합니다.
하지만 MVC패턴에서는 View와 Model간의 의존성을 완벽히 분리할 수 없는데다 패턴의 모호함때문에 해석이 제각각 달라지며 여러가지 변형이 생기게 되었습니다.
그런 와중에 MVP패턴이 마틴 파울러에 의해서 발표되었는데 이 패턴에서는 View와 Model의 완벽한 분리가 이뤄지는 특징이 있습니다.
MVP 패턴에 대해서는 "MVP(Model-View-Presenter)패턴을 적용한 GUI Architecture 설계" 포스트를 참조하세요.
MVP(Model-View-Presenter) 패턴을 적용한 GUI Architecture 설계
1. MVP 패턴 소개
MVP 패턴은 MVC(Model-View-Controller) 패턴에 기반을 둔 UI 프리젠테이션 패턴입니다.
MVP 패턴은 Model, View, View Interface, Presenter 네 개의 컴포넌트(구성요소)로 구성됩니다.
각 컴포넌트에서 담당하는 책임은 다음과 같습니다.
2. MVP 패턴 적용
위에서 소개한 MVP 패턴을 적용하여 샘플 어플리케이션을 만들어 보도록 하겠습니다.
샘플 어플리케이션의 Class Diagram은 다음과 같습니다.
Model 컴포넌트는 Member Class이며 Member Entity와 데이터 처리 로직을 포함하고 있습니다.
Presenter 컴포넌트는 MemberPresenter Class이며 View와 Model을 참조합니다. 그리고 View의 이벤트 핸들러를 구현합니다.
View Interface 컴포넌트는 IMemberView Interface이며 View의 속성과 이벤트를 정의합니다.
Concrete View 컴포넌트는 MemberView Form이며 IMemberView를 구현하며 UI요소를 렌더링합니다.
먼저 Model 컴포넌트인 Member Class를 만들도록 합니다.
Member Class는 실제 데이터 소스에 접근하여 데이터를 검색하거나 갱신하는 로직을 포함합니다. 또한 Member의 Age, Name 속성을 갖는 Entity Class의 역할도 수행합니다.
데이터 소스는 실제 데이터베이스가 아닌 <표 1>과 같이 더미 데이터를 임시로 구현하여 사용합니다.
static class DummyMember
{
#region 회원 더미 데이터 생성
public static List<Models.Member> List = new List<Models.Member>();
static DummyMember()
{
List.Add(new Models.Member("홍길동", 20));
List.Add(new Models.Member("김갑수", 10));
}
#endregion
}
public int SaveMember(){
#region 저장
if (id == null)
{
// 추가
Data.DummyMember.List.Add(new Member(this.name, this.age));
id = Data.DummyMember.List.Count - 1; }
else
{
// 수정
Data.DummyMember.List[id.Value].Name = name;
Data.DummyMember.List[id.Value].Age = age; }
#endregion
return 0;
}
public bool LoadMember(int id){
if (id >= Data.DummyMember.List.Count || id < 0)
{
this.id = null;
return false;
}
this.id = id;
name = Data.DummyMember.List[id].Name;
age = Data.DummyMember.List[id].Age;
return true;
}
다음으로 IMemberView Interface를 정의합니다.
IMemberView Interface는 Concrete View에서 구현해야할 UI 요소와 표현 메서드를 정의합니다. 일반적으로 UI요소는 Property로 정의하며 Concrete View의 UI 요소에서 이벤트가 발생했을 때 이를 Presenter에서 처리할 수 있도록 이벤트를 정의합니다.
interface IMemberView
{
int ID { get; set; }
string Name { get; set; }
int Age { get; set; }
event EventHandler LoadMember;
event EventHandler SaveMember;
}
세 번째로 UI 요소를 출력하는 MemberView Form을 생성합니다.MemberView Form은 System.Windows.Forms.Form Class를 상속하는 WinForm Class입니다. 닷넷의 WinForm Control이 UI 요소가 됩니다.
또한 IMemberView Interface를 구현하여 Presenter에서 UI 요소에 데이터를 채우거나 이벤트 핸들러를 구현하여 View를 제어할 수 있도록 합니다.
public partial class MemberView : Form, IMemberView{
MemberPresenter presenter;
public MemberView()
{
InitializeComponent();
presenter = new MemberPresenter(this); }
#region IMemberView 멤버
int IMemberView.ID
{
get { return (int)numericUpDown1.Value; }
set { numericUpDown1.Value = value; }
}
string IMemberView.Name
{
get { return textBox1.Text; }
set { textBox1.Text = value; }
}
int IMemberView.Age
{
get { return (int)numericUpDown2.Value; }
set { numericUpDown2.Value = value; }
}
event EventHandler IMemberView.SaveMember
{
add { button1.Click += value; }
remove { button1.Click -= value; } }
event EventHandler IMemberView.LoadMember
{
add { button2.Click += value; }
remove { button2.Click -= value; } }
#endregion
}
주목할 부분은 SaveMember, LoadMember 이벤트를 구현한 부분입니다. button1.Click과 button2.Click의 실제 이벤트 핸들러는 Presenter에서 구현하는데, 이 곳에서 Model의 데이터를 검색하고 갱신하는 코드를 작성하게 됩니다.
마지막으로 View와 Model의 상호작용을 처리하는 MemberPresenter Class를 구현합니다. MemberPresenter Class는 Concrete View의 UI 요소(WinForm Control)의 실제 이벤트 핸들러를 구현하며 Member Class의 데이터 처리 메소드를 호출해 데이터를 검색하거나 갱신하는 코드를 구현합니다. 또한 IMemberView 인터페이스를 통해 Concrete View인 MemberView Form의 UI 요소(WinForm Controls)에 데이터를 출력하는 코드도 구현하고 있습니다.
class MemberPresenter
{
IMemberView view;
Models.Member model;
public MemberPresenter(IMemberView view)
{
this.view = view;
this.view.SaveMember += new EventHandler(view_SaveMember);
this.view.LoadMember += new EventHandler(view_LoadMember);
this.model = new SingleLayerMVP.Models.Member(); }
// 회원정보 불러오기
void view_LoadMember(object sender, EventArgs e)
{
int id = view.ID;
if (model.LoadMember(id))
{
view.Name = model.Name;
view.Age = model.Age;
}
else
{
MessageBox.Show("존재하지 않는 회원입니다.");
view.Name = string.Empty;
view.Age = 0;
}
}
// 회원정보 저장하기
void view_SaveMember(object sender, EventArgs e)
{
model.Name = view.Name;
model.Age = view.Age;
if (model.SaveMember() == 0)
{
MessageBox.Show("성공");
}
else
{
MessageBox.Show("실패");
}
}
}
MemberPresenter Class는 IMemberView와 Member의 참조를 모두 갖게 되며 view와 model간의 상호작용을 담당하는 코드를 실제 구현하게 됩니다. 이 로써 View와 Model간의 커플링을 없앰과 동시에 View와의 상호작용을 IMemberView Interface를 통해 처리함으로써 실제 Concrete View인 MemberView Form과의 커플링도 없앨 수 있게 되는 것입니다.
3. Multi Layer Application Architecture 에서 MVP Pattern 적용하기
일반적으로 비즈니스 레이어와 Presentation Layer가 분리 되어 있는 어플리케이션에서 MVP Pattern의 적용은 <그림 3>과 같은 구조를 적용하면 됩니다. Model의 Business Entity는 직렬화가 가능하도록 [Serializable] 어트리뷰트를 추가하여 개발하고 Client Application에서는 Web Service참조를 Model로 간주하여 Presenter에 구현하면 됩니다.
[Serializable]public class Member
{
int? id = null;
public int? Id
{
get { return id; }
set { id = value; }
}
…
class MemberPresenter
{
IMemberView view;
WebService.Service1 model;
public MemberPresenter(IMemberView view)
{
this.view = view;
this.view.SaveMember += new EventHandler(view_SaveMember);
this.view.LoadMember += new EventHandler(view_LoadMember);
this.model = new Client.WebService.Service1(); }
// 회원정보 불러오기
void view_LoadMember(object sender, EventArgs e)
{
int id = view.ID;
WebService.Member member = model.wpLoadMember(id);…
4. View를 위한 단위 테스트 코드 작성
우선 단위 테스트 코드는 NUnit Framework를 사용하도록 합니다.
NUnit Framework의 다운로드와 설치는 다음 링크를 참조하세요.
http://www.nunit.org
일반적으로 GUI에 대한 테스트는 사용자 액션(이벤트 발생)을 시뮬레이션하기 어렵기 때문에 자동화하기가 어렵습니다. 그래서 마우스와 키보드 동작을 레코드하여 매크로 동작으로 테스트하는 상용화된 테스팅 툴을 사용하게 됩니다.
하 지만 MVP 패턴을 적용하게 되면 IMemberView 인터페이스를 사용해서 View만을 위한 단위 테스트 코드를 작성할 수 있습니다. 이것이 의미하는 것은 GUI 개발을 테스트 지향적(TDD, 테스트 코드 먼저구현->실제 코드 구현)으로 개발할 수 있다는 것이기도 합니다.
단위 테스트 코드를 작성하기 위해 먼저 IMemberView Interface를 구현하는 DummyView Class를 생성합니다.
public class DummyView : IMemberView{
int id;
int age;
string name;
event EventHandler loadMember;
event EventHandler saveMember;
#region IMemberView 멤버
…
#endregion
#region 테스트용 인터페이스
public void TestLoadMember()
{
loadMember(this, null);
}
public void TestSaveMember()
{
saveMember(this, null);
}
#endregion
}
DummyView Class에서 IMemberView Interface를 구현한 것과 테스트용 메서드인 TestLoadMember()와 TestSaveMember() 메서드를 추가한 것입니다. 실제 View의 UI 요소를 제어하는 코드가 있는 Class는 MemberPresenter이기 때문에 IMemberView와 MemberPresenter를 모두 테스트하는 코드라고 볼 수 있습니다.
using NUnit.Framework;
namespace SingleLayerMVP.Tests
{
[TestFixture]
public class MemberViewTest
{
IMemberView view;
MemberPresenter presenter;
[SetUp]
public void SetUp()
{
view = new DummyView();
presenter = new MemberPresenter(view);
}
[TearDown]
public void TearDown()
{
// null
}
/// <summary>
/// Test LoadMember()
/// </summary>
[Test]
public void TestLoadMember()
{
view.ID = 0;
(view as DummyView).TestLoadMember();
Assert.AreEqual(view.Name, "홍길동");
Assert.AreEqual(view.Age, 20); }
/// <summary>
/// Test SaveMember()
/// </summary>
[Test]
public void TestSaveMember()
{
view.ID = 0;
view.Name = "홍길삼";
view.Age = 21;
(view as DummyView).TestSaveMember();
Assert.AreEqual(view.Name, "홍길삼");
Assert.AreEqual(view.Age, 21);
}
}
}
NUnit Framework를 사용해서 테스트 코드를 작성하는 방법은 http://www.nunit.org 사이트를 참조하세요.
TestLoadMember() 테스트 메서드와 TestSaveMember() 테스트 메서드를 보면 실제 GUI의 동작을 시뮬레이션하는 코드가 구현되어 있는 것을 볼 수 있습니다.
TestLoadMember() 메서드를 자세히 살펴보죠.
view.ID = 0; 이라는 코드에서 사용자가 ID UI 요소에 0이란 값을 입력한 것을 의미하고,
(view as DummyView).TestLoadMember(); 코드에서는 “불러오기” 버튼을 클릭(또는 유사한 동작)한 것을 의미합니다.
Assert.AreEqual() 구문에 의해서 DummyMember.List[]의 첫 번째 데이터인 {‘홍길동’, 20}이 정상적으로 View에 출력되었는지 확인하게 됩니다.
NUnit에서 컴파일된 어셈블리를 로드하여 테스트를 수행하면 다음과 같이 테스트가 통과한 것을 볼 수 있습니다.
물론 MemberView 폼을 대상으로 테스트를 수행하지 않은 것은 아쉬운 점입니다. 특히 View의 입력 요소에 값이 입력될 때 유효성 체크하는 코드를 작성할 수 없다는 것도 역시 아쉬운 점입니다. 이 두 항목을 포함하여 본 문서에서 미흡하게 다뤘거나 또는 건너 뛴 부분(MVC 패턴, MVC와 MVP 패턴의 차이점과 장단점…)들은 참조문헌에 있는 링크를 참조하세요.
이상으로 MVP 패턴을 적용한 Gui Archicecture 설계를 마치도록 하겠습니다.
5. 참조문헌
5.1. MSDN Magazine, Model View Presenter :
http://msdn.microsoft.com/msdnmag/issues/06/08/DesignPatterns/
5.2. MVC or MVP Pattern – What’s the difference :
http://blogs.infragistics.com/blogs/tsnyder/archive/2007/10/17/mvc-or-mvp-pattern-whats-the-difference.aspx
5.3. Martin Fowler’s GUI Architectures :
http://www.martinfowler.com/eaaDev/uiArchs.html
5.4. MSDN, Model View Controller
http://msdn2.microsoft.com/en-us/library/ms978748.aspx
5.5. MSDN, Implementing Model-View-Controller in ASP.NET
http://msdn2.microsoft.com/en-us/library/ms998540.aspx
5.6. MSDN, Page Controller
http://msdn2.microsoft.com/en-us/library/ms978764.aspx
5.7. MSDN, Front Controller
http://msdn2.microsoft.com/en-us/library/ms978723.aspx
5.8. KLDP, M-V-C가 서로의 영역을 전혀 침범하지 않고 개발하는 것이 과연 가능한가?
http://kldp.org/node/70219
5.9. Javaworld, JSP의 MVC 모델1과 모델2
http://www.javaworld.com/javaworld/jw-12-1999/jw-12-ssj-jspmvc.html
이 글은 스프링노트에서 작성되었습니다.
log4j구현환경제공. (0) | 2012.05.08 |
---|---|
MyBatis (odbc프레임웍) (0) | 2012.05.08 |
Login&Logout 기본패턴 (0) | 2012.05.08 |
log4j (0) | 2012.05.08 |
JSTL- 사용 하기 (0) | 2012.05.08 |
<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>방가 방가 ~~/index.jsp</title>
</head>
<body >
<link rel="stylesheet" type="text/css" href="<%=request.getContextPath() %>/css/main.css" />
<div id="topMenu">
<jsp:include page="/include/top.jsp" />
</div>
<h3>이쁜 선희의 웹페이지</h3>
<img src="<%=request.getContextPath() %>/img/5985.jpg" alt="절대경로 3" width="100px" /><br />
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%--
request.setCharacterEncoding("utf-8");--%>
<%-- // incloude/top.jsp --%>
<ul>
<li>HOME</li>
<li>회원관리</li>
<li>게시판</li>
<li>사이트맵</li>
<%-- <li>msg=<%=request.getParameter("msg") %></li>
--%>
<%
String id = (String)session.getAttribute("USER_ID");
if(id==null){
%>
<li><a href="<%=request.getContextPath()%>/07/login.jsp">로그인</a>
</li>
<%
}else {
%>
<li><%=id %>님 방가 방가 ^^
<a href="<%=request.getContextPath()%>/07/logout.jsp">로그아웃</a>
</li>
<%
}
%>
</ul>
<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>로그인 07/ login.jsp</title>
<%
String id="";
String checked="checked='checked'";
// 쿠키 배열을 읽어서 이름중에 "user_id" 가 있다면
// 그 값을 id에 넣고 ,checked변수에는 "";
Cookie cookie[] =request.getCookies();
for(int i =0;i<cookie.length;i++){
if(cookie[i].getName().equals("user_id")){
id=cookie[i].getValue();
checked="";
break;
}
}
%>
</head>
<body>
<h4>로그인</h4>
<form action="logincheck.jsp" method="post">
<label>아이디
<input type="text" name="user_id" value="<%=id %>" />
</label>
<label>패스워드
<input type="password" name="user_pw" />
</label>
<label>
<input type="checkbox" <%=checked %> name="id_save" value="Y"/>
ID 기억
</label>
<button type="submit">로그인</button>
</form>
</body>
</html>
<?xml version="1.0" encoding="UTF-8" ?>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%!static Map memberMap;
static {
memberMap = new HashMap();
memberMap.put("hwang", "java");
memberMap.put("malja", "1004");
memberMap.put("sunhee", "pretty");
memberMap.put("sararing", "1234");
}%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>07 /logincheck.jsp</title>
</head>
<body>
<%
//사용자가 입력한 파라미터 user_id user_pass 를 받아서
// 등록된 것과 비교를 해야함.
//맞으면 세션에 "USER_ID" 키로 해당 user_id 저장
// / index.jsp로 다이렉트 하고
// 틀리면 자바 스크립트로 메시지 창을 보여 주고 login.jsp로 이동
String id = request.getParameter("user_id");
String pw = request.getParameter("user_pw");
String checked = request.getParameter("id_save");
if (id != null) {
if (memberMap.containsKey(id)) {
String dbPass = (String) memberMap.get(id);
if (dbPass.equals(pw)) {
session.setAttribute("USER_ID", id);
//sendRedirect 는 헤더에 3xx 대 상태 코드로 설정 하고
// Location 헤더에 다시 들어올 경로를 알려 주는데
// 클라이언트가 다시 와야하므로 웹경로를 포함 시켜야 한다.
if(checked!=null){
/* "user_id",id, 한달,루트로 저장
*/
Cookie cookie =new Cookie("user_id",id);
cookie.setMaxAge(60*60*24*30);
cookie.setPath("/ddit");
response.addCookie(cookie);
}else {
Cookie cookie =new Cookie("user_id","");
cookie.setMaxAge(0);
cookie.setPath("/ddit");
response.addCookie(cookie);
}
response.sendRedirect(request.getContextPath()+"/index.jsp");
return;
}else {
// 패스워드가 틀릴때
// 자바 스크립트로 경고 메시지 출력후 login.jsp로 점프
%>
<script type="text/javascript">
<!--
alert("d야 패스워드가 틀려");
location.href="login.jsp";
//-->
</script>
<%
return;
}
}
}
// id가 null 이거나 memberMap 에 없는 경우
%>
<script type="text/javascript">
<!--
alert("아이디를 입력해주세요");
location.href="login.jsp";
//-->
</script>
</body>
</html>
<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>07/logout.jsp</title>
</head>
<body>
<%
//세션중 임의 키만 제거 은 밑
//session.removeAttribute("USER_ID");
// 기존세션 무효화,새로운 세션키 활당
session.invalidate();
response.sendRedirect(request.getContextPath()+"/index.jsp");
%>
</body>
</html>
이 글은 스프링노트에서 작성되었습니다.
MyBatis (odbc프레임웍) (0) | 2012.05.08 |
---|---|
MVC패턴 (0) | 2012.05.08 |
log4j (0) | 2012.05.08 |
JSTL- 사용 하기 (0) | 2012.05.08 |
JSTL (0) | 2012.05.08 |
첨부파일 : 압축해제후 log4j-1.2.14.jar 파일을
JDK설치된 폴더의 lib/ext 디렉토리에 카피후
프로젝트 properties 의 Java Build Path >
Library > Add External Jars ... 에서 추가시킴
LOG4J
I. 들어가면서.. 그리고 log4j
log4j는 자바 어플리케이션에서 빠르고 효과적으로 로깅 할 수 있도록 도와주는 오픈 소스 프로젝트입니다.
로깅(logging)은 코드의 가독성을 떨어뜨리는 단점이 있지만 애플리케이션에 문제가 있을 때 개발자가 자세한 상황을 파악할 수 있도록 해 주며 테스팅시 빠질 수 없는 요소입니다.
아마도 여러분들은 여러 어플리케이션이 추가되면서 각 개발자들만의 독특한 로깅방식이 서로 썩이고 얽혀서 화면에 나타나는것을 많이 봤을겁니다 -_-;
즉 로깅방법을 통일할 필요가 있는것이죠. 모든 개발자가 특정 포맷에 맞추어서 로깅 한다면 한결 로깅하기도 편하겠지요
오픈 소스 프로젝트인 Log4j는 개발자들이 매우 손쉽고 다양한 형태로 로깅을 할 수 있도록 도와줍니다. 성능또한 우수해 더이상 System.out.println을 사용할 필요가 없습니다.
II. 다운로드
다운로드 http://logging.apache.org/log4j/docs/download.html
매뉴얼 http://logging.apache.org/log4j/docs/documentation.html
API spec http://logging.apache.org/log4j/docs/api/index.html
III. LOG4J 구조
일단 log4j를 잘 모르지만 그 구조만 살짝 살펴보고 넘어갑시다
log4j는 크게 3가지 요소로 구성되며 그 구조는 다음과 같습니다
① Logger(Category) : 로깅 메세지를 Appender에 전달합니다.
② Appender : 전달된 로깅 메세지를 파일에다 기록할 것인지, 콘솔에 출력할 것인지
아니면 DB에 저장할 것인지 매개체 역활을 합니다.
③ Layout : Appender가 어디에 출력할 것인지 결정했다면 어떤 형식으로 출력할 것이지
출력 layout을 결졍합니다.
쉽죠?
IV. LOG4J 로깅 레벨
log4j는 다양한 로깅레벨을 지원합니다.
① FATAL : 가장 크리티컬한 에러가 일어 났을 때 사용합니다.
② ERROR : 일반 에러가 일어 났을 때 사용합니다.
③ WARN : 에러는 아니지만 주의할 필요가 있을 때 사용합니다.
④ INFO : 일반 정보를 나타낼 때 사용합니다.
⑤ DEBUG : 일반 정보를 상세히 나타낼 때 사용합니다.
만약 로깅 레벨을 WARN 으로 설정하였다면 그 이상 레벨만 로깅하게 됩니다.
즉 WARN, ERROR, FATAL 의 로깅이 됩니다.
V. 샘플코드 1
jsp에서 사용하는 예제가 없어 만들어 봤습니다.
test.jsp <%@ page contentType="text/html;charset=MS949" <%! <% logger.fatal("fatal2!!", new NullPointerException("널입니다요")); logger.error("error!", new NumberFormatException()); logger.error("error!2"); logger.warn("warn"); logger.info("info"); logger.debug("debug"); |
결과 콘솔화면
① static Logger logger = Logger.getLogger("test.jsp");
static 메소드 getLogger를 통해 logger 인스턴스를 가져옵니다.
getLogger에는 파라미터로 스트링 혹은 클래스를 사용하는데 jsp에서는 클래스를 파라미터로 주기에는 좀 애매합니다. 그냥 스트링으로 주도록 하지요
② logger.fatal("fatal!!");
logger.fatal("fatal2!!", new NullPointerException("널입니다요"));
logger에 fatal 레벨의 메세지를 전달합니다. 다음 두가지 메소드를 지원하는군요
fatal(Object message)
fatal(Object message, Throwable t)
각 레벨마다 위처럼 두가지 메소드를 지원합니다.
지원 메쏘드 | |
logger.fatal(Object message) | logger.fatal(Object message, Throwable t) |
logger.error(Object message) | logger.error(Object message, Throwable t) |
logger.warn(Object message) | logger.warn(Object message, Throwable t) |
logger.info(Object message) | logger.info(Object message, Throwable t) |
logger.debug(Object message) | logger.debug(Object message, Throwable t) |
VI. 샘플코드 2
서블릿의 경우 다음과 같이 코딩하면 되겠군요
TestServlet.java import javax.servlet.*; public class TestServlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { ... } catch (Exception e) { |
VII. LOG4J 설정
log4j 설정은 프로그램 내에서 할 수 있지만 설정파일을 사용함으로서 좀더 유연하게 log4j환경을 만들 수 있습니다.
① 프로그램에서 설정
<%@ page contentType="text/html;charset=MS949" import="org.apache.log4j.*,java.io.* " %> <%! <% PatternLayout patternlayout = new PatternLayout(layout); |
② property 파일에 설정
log4j.properties를 만들어 /WEB-INF/classes 밑에 놓으세요
log4j.rootLogger=INFO, stdout, rolling log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender log4j.appender.rolling.File=output.log log4j.appender.rolling.Append=true log4j.appender.rolling.MaxFileSize=500KB log4j.appender.rolling.DatePattern='.'yyyy-MM-dd log4j.appender.rolling.layout=org.apache.log4j.PatternLayout log4j.appender.rolling.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n |
#최상위 카테고리에 INFO로 레벨 설정 및 appender로 stdout, rolling을 정의
log4j.rootLogger=INFO, stdout, rolling
#stdout 어펜더는 콘솔에 뿌리겠다는 정의
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#stdout 어펜더는 patternlayout을 사용하겠다는 정의
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#페턴은 다음과 같이 포맷팅 하겠다는 것을 정의
log4j.appender.stdout.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n
#역시나 rolling 어펜더는 파일로 처리한다라고 정의
log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender
#로그 파일 이름은 output.log
log4j.appender.rolling.File=output.log
#true면 톰캣을 내렸다 올려도 파일이 리셋되지 않습니다.
log4j.appender.rolling.Append=true
#파일 최대 사이즈는 500KB로 설정
log4j.appender.rolling.MaxFileSize=500KB
#파일 포맷은 output.log.2005-03-10 으로 관리하겠다고 정의
log4j.appender.rolling.DatePattern='.'yyyy-MM-dd
#역시나 rolling 어펜더는 패턴 레이아웃을 사용하겠다고 정의
log4j.appender.rolling.layout=org.apache.log4j.PatternLayout
#rolling 어펜더는 패턴 레이아웃 포맷
log4j.appender.rolling.layout.ConversionPattern=%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n
VIII. 설정 포맷
① 로그파일명 포맷 (DatePattern)
로그파일명 포맷입니다. 날짜, 시간 및 분단위로까지 로그 파일을 분리할 수 있습니다.
형식 | 설명 |
'.'yyyy-MM | 매달 첫번째날에 로그파일을 변경합니다 |
'.'yyyy-ww | 매주의 시작시 로그파일을 변경합니다. |
'.'yyyy-MM-dd | 매일 자정에 로그파일을 변경합니다. |
'.'yyyy-MM-dd-a | 자정과 정오에 로그파일을 변경합니다. |
'.'yyyy-MM-dd-HH | 매 시간의 시작마다 로그파일을 변경합니다. |
'.'yyyy-MM-dd-HH-mm | 매분마다 로그파일을 변경합니다. |
② PatternLayout 포맷
로그자체를 어떤 포맷으로 남길지 결정합니다.
layout에는 HTMLLayout, PatternLayout, SimpleLayout, XMLLayout등이 있으며 PatternLayout이 일반적으로 가장 많이 쓰입니다.
형식 | 설명 |
%p | debug, info, warn, error, fatal 등의 priority 가 출력된다. |
%m | 로그내용이 출력됩니다 |
%d | 로깅 이벤트가 발생한 시간을 기록합니다. 포맷은 %d{HH:mm:ss, SSS}, %d{yyyy MMM dd HH:mm:ss, SSS}같은 형태로 사용하며 SimpleDateFormat에 따른 포맷팅을 하면 된다 |
%t | 로그이벤트가 발생된 쓰레드의 이름을 출력합니다. |
%% | % 표시를 출력하기 위해 사용한다. |
%n | 플랫폼 종속적인 개행문자가 출력된다. \r\n 또는 \n 일것이다. |
%c | 카테고리를 표시합니다 예) 카테고리가 a.b.c 처럼 되어있다면 %c{2}는 b.c가 출력됩니다. |
%C | 클래스명을 포시합니다. 예) 클래스구조가 org.apache.xyz.SomeClass 처럼 되어있다면 %C{2}는 xyz.SomeClass 가 출력됩니다 |
%F | 로깅이 발생한 프로그램 파일명을 나타냅니다. |
%l | 로깅이 발생한 caller의 정보를 나타냅니다 |
%L | 로깅이 발생한 caller의 라인수를 나타냅니다 |
%M | 로깅이 발생한 method 이름을 나타냅니다. |
%r | 어플리케이션 시작 이후 부터 로깅이 발생한 시점의 시간(milliseconds) |
%x | 로깅이 발생한 thread와 관련된 NDC(nested diagnostic context)를 출력합니다. |
%X | 로깅이 발생한 thread와 관련된 MDC(mapped diagnostic context)를 출력합니다. |
예시) (같은 색끼리 보시면 됩니다)
위의 test.jsp를 다음 포맷으로 출력해본다면
[%c] [%C] [%d] [%F] [%l] [%L] [%m] [%M] [%n] [%p] [%r] [%t] [%x] [%X]는 다음과 같다
[test.jsp] [org.apache.jsp.test_jsp] [2005-03-10 12:37:23,561] [test_jsp.java] [org.apache.jsp.test_jsp._jspService(test_jsp.java:64)] [64] [fatal!!] [_jspService] [개행] [FATAL] [765567] [http-8080-Processor25] [] []
=============================================
본문서는 자유롭게 배포/복사 할수 있지만
이문서의 저자에 대한 언급을 삭제하시면 안됩니다
저자 : GoodBug (unicorn@jakartaproject.com)
최초 : http://www.jakartaproject.com
=============================================
이 글은 스프링노트에서 작성되었습니다.
MVC패턴 (0) | 2012.05.08 |
---|---|
Login&Logout 기본패턴 (0) | 2012.05.08 |
JSTL- 사용 하기 (0) | 2012.05.08 |
JSTL (0) | 2012.05.08 |
JSP 에러코드 모음 (0) | 2012.05.08 |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
테그 라이브러리를 맨 위 임포트 페이지 쪽에 정의 하자. core는 c 로 fmt 는 fmt(포멧) 으로 사용하는게 정신건강에 이로우며
<fmt:bundle basename="kr.or.ddit.res.board"
prefix="BOARD.">
이런식의 응용도 가능 하다.
먼저 board.properties 를 만들어야 한다.
BOARD.TITLE=Sunhee mom's Doodle
BOARD.NEW=new
BOARD.LIST.NO=no
BOARD.LIST.TITLE=title
BOARD.LIST.WRITER=writer
BOARD.LIST.HIT=hit
BOARD.LIST.DATE=date
BOARD.LIST.TIP={0} is write, {1} hit ,{2} haha
BOARD.LIST.PREV=Previous
BOARD.LIST.NEXT=Next
이는 소스의 내용이다. 이것을 이용 하여
<thead>
<tr>
<th><fmt:message key="LIST.NO"/></th>
<th><fmt:message key="LIST.TITLE"/></th>
<th><fmt:message key="LIST.WRITER"/></th>
<th><fmt:message key="LIST.HIT"/></th>
<th><fmt:message key="LIST.DATE"/></th>
</tr>
이런식의 key 값을 지정 하여 사용 할수 있다.
이러한 포문을
변경 되었다 request.setAttribute 에 list 를 "dragon" 이라는 key 값으로 주며
그것을 forEach 문에서 Items 로 사용함을 확인 하자. <%%> 의 사용을 최대한 줄이자.
한가지 더
하단의 페이지 구문 이다. <%%> d이러한 것을 없에자.
request.setAttrivute 로 값을 셋팅 하고 있다.
이렇듯 바뀌었다. !!
참고로 주석은 되도록 jsp 에서는 <%-- --%> 라고 사용 하자.
<c:set var="msg">황-지혜,유-지혜,오-선희</c:set>
<c:forTokens items="${msg}" delims="," var="tk">
${tk} <br/>
</c:forTokens>
<?xml version="1.0" encoding="UTF-8" ?>
<%@page import="kr.or.ddit.board.vo.BoardBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<% request.setCharacterEncoding("UTF-8"); %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>19/core_3.jsp</title>
</head>
<body>
<c:set var="board" value="<%=new kr.or.ddit.board.vo.BoardBean()%>"></c:set>
<c:set target="${board}" property="bo_title" value="수요일에는 빨간 장미를 .. " />
1.${board.bo_title}<br>
<c:remove var="board" />
2.${board.bo_title}<br>
</hr>
<c:set var="msg">황-지혜,유-지혜,오-선희</c:set>
<c:forTokens items="${msg}" delims="," var="tk">
${tk} <br/>
</c:forTokens>
<hr/>
<!-- 아래 데이터를 데이터베이스에서 가져왔다고 가정 하자. -->
<c:set var="hee">
<b>오선희</b>그녀는 누구인가.. 근데.. ? ,
<font color="red">유지혜</font>,유씨엄마
</c:set>
${hee}
<hr/>
<c:out value="${hee}" default="기본값" escapeXml="true"/>
<hr/>
-- excapeXml="false" 옵션시
<c:catch var="ex">
<%
String a =request.getParameter("dragon");
out.println(a.toUpperCase());
%>
</c:catch>
<c:if test="${not empty ex}">
아 에러 났네 . .. ${ex.message}<br/>
</c:if>
<!--
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
-->
<c:set var="msg2">Hwang,황엄마, you 유지혜 </c:set>
기억자 : ${fn:length(msg2) }</br>
대문자 : ${fn:toUpperCase(msg2)}<br/>
일행문자 : ${fn:substring(msg2,0,6) }
지혜로끈나니? : ${fn:endsWith(msg2,"지혜") }<br/>
<c:set var="arr2" value="${fn:split(msg2,',') }"/>
<c:forEach items="${arr2 }" varStatus="st">
${st.count}, ${st.current} <br/>
</c:forEach>
</body>
</html>
이 글은 스프링노트에서 작성되었습니다.
Login&Logout 기본패턴 (0) | 2012.05.08 |
---|---|
log4j (0) | 2012.05.08 |
JSTL (0) | 2012.05.08 |
JSP 에러코드 모음 (0) | 2012.05.08 |
include (0) | 2012.05.08 |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
request.setCharacterEncoding("UTF-8");
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>19/ core_2.jsp</title>
</head>
<body>
<%-- <%
request.setAttribute("jumsu", "97");
%> --%>
<c:set var ="jumsu" value="86" scope="request"/>
<c:if test="${jumsu>90}">수</c:if>
<c:if test="${jumsu gt 80 and jumsu<=90}">우</c:if>
<c:if test="${jumsu>70 && jumsu le 80}">미</c:if>
<c:if test="${jumsu<=60}">나가 죽어 </c:if>
<hr />
<!--
밑에 스위치문
--><c:choose>
<c:when test="${jumsu>90}">참 잘했어요</c:when>
<c:when test="${jumsu>80}">잘했어요</c:when>
<c:when test="${jumsu>70}">분발 하세요. </c:when>
<c:when test="${jumsu>60}">너 낳고 미역국을 먹은 내가 잘못 </c:when>
</c:choose>
<c:set var = "sum" value="0"/>
<c:forEach begin="1" end="100" var="i" step="2">
<c:set var="sum" value="${sum+i}"/>
</c:forEach>
1부터 100까지의 홀수의 합 =${sum}
<br/>
<hr />
<c:set var="dan" value="5" />
<c:forEach begin="1" end="9" var="i" step="1">
${dan} * ${i}=${dan*i} <br>
</c:forEach>
</body>
</html>
JSP 애플리케이션용 MA 단순화하기
요약: JSP Standard Tag Library (JSTL)은 일반적인 웹 애플리케이션 기능(반복(iteration)과 조건, 데이터 관리 포맷, XML 조작, 데이터베이스 액세스)을 구현하는 커스텀 태그 라이브러리 모음이다. 소프트웨어 엔지니어인 Mark Kolb은 JSTL 태그의 사용방법을 설명한다. 표현층(presentation layer)에서 소스 코드를 제거하여 소프트웨어 관리를 단순화시키는 방법도 설명한다. 이외에도 JSTL의 단순화된 Expression Language에 대한 설명도 포함되어 있다.
이 기사에 태그: j2ee_(java_2_enterprise_edition), jsp, jstl, 웹_서비스
JavaServer Pages (JSP)는 J2EE 플랫폼을 위한 표준 표현 레이어(presentation-layer) 이다. JSP는 페이지 콘텐트를 동적으로 생성할 수 있는 전산을 수행 할 수 있는 스크립팅 엘리먼트와 액션을 제공한다. 스크립팅 엘리먼트는 프로그램 소스 코드가 JSP 코드에 포함될 수 있도록 한다. 페이지가 사용자 요청에 대한 응답으로 렌더링 될 때 실행할 목적이다. 액션(actions)은 전산 작동을 JSP 페이지의 템플릿 텍스트를 구성하고 있는 HTML 이나 XML과 거의 흡사하게하는 태그로 인캡슐한다. JSP 스팩에 표준으로 정의된 몇 가지의 액션들이 있다. 하지만 JSP 1.1 부터 개발자들은 커스텀 태그 라이브러리 형태로 자신만의 액션들을 만들 수 있다.
JSP Standard Tag Library (JSTL)는 JSP 1.2 커스텀 태그 라이브러리 모음으로서 광범위한 서버측 자바 애플리케이션에 일반적으로 쓰이는 기본 기능들을 구현한다. JSTL은 데이터 포맷, 반복 콘텐트 또는 조건 콘텐트 같은 전형적인 표현 레이어를 위한 표준 구현을 제공하기 때문에, JSP 작성자들이 애플리케이션 개발에 집중하는데 도움이 된다.
물론, 스크립틀릿, 익스프레션, 선언 같은 JSP 스크립팅 엘리먼트를 사용하는 태스크를 구현할 수 있다. 예를 들어 조건 콘텐트(conditional content)는 세 개의 스크립틀릿(Listing 1의 하이라이트 부분)을 사용하여 구현될 수 있다. 페이지 내에 프로그램 소스 코드를 임베딩하는 것에 의존하기 때문에 스크립팅 엘리먼트가 소프트웨어 관리 태스크를 매우 복잡하게 하는 경향이있더라도 JSP 페이지는 그들을 사용한다. Listing 1의 스크립틀릿 예제는 브레이스들의 적절한 매칭에 매우 의존한다. 조건화된 콘텐트 내에 추가 스크립틀릿을 중첩하는 것은 신택스 에러가 갑자기 일어났다면 페이지가 JSP 콘테이너에 의해 컴파일 될 때 결과 에러 메시지를 합리화하는 것은 도전이 될 수 있다.
Listing 1. 스크립틀릿을 통해 조건 콘텐트 구현하기
<% if (user.getRole() == "member")) { %> <p>Welcome, member!</p> <% } else { %> <p>Welcome, guest!</p> <% } %> |
그와 같은 프로그램을 해결하는데에는 프로그래밍 경험이 많이 필요하다. JSP 페이지의 마크업이 페이지 레이아웃과 그래픽 디자인에 익숙한 디자이너에 의해 개발 및 관리되는데 반해 그와 같은 페이지 내의 스크립팅 엘리먼트는 문제가 생길 때 프로그래머가 개입해야한다. 하나의 파일안에 있는 코드에 대한 책임을 공유하는 것은 JSP 페이지의 개발, 디버깅, 향상을 성가신일로 만든다. JSTL은 일반적인 기능을 커스텀 태그 라이브러리의 표준 세트로 패키징했기 때문에 JSP 작성자들이 스크립팅 엘리먼트에 대한 필요를 줄이고 관련된 관리 비용을 피할 수 있도록 한다.
02년 6월에 릴리스된 JSTL 1.0은 네 개의 커스텀 태그 라이브러리(core
, format
, xml
, sql
)와 두 개의 범용 태그 라이브러리 밸리데이터(ScriptFreeTLV
& PermittedTaglibsTLV
)로 구성되어 있다. core
태그 라이브러리는 커스텀 액션을 제공하여 범위 변수를 통해 데이터를 관리할 수 있도록하며 페이지 콘텐트의 반복과 조건화를 수행할 수 있도록 한다. 또한 URL에서 생성 및 작동할 수 있는 태그도 제공한다. format
태그 라이브러리는 이름이 시사하는 바와 같이 데이터 특히 숫자와 날짜를 포맷하는 액션을 정의한다. 국지화 된 리소스 번들을 사용하여 JSP 페이지의 국제화도 지원한다. xml
라이브러리에는 XML을 통해 표현된 데이터를 조작할 수 있는 테그가 포함되어 있다. sql
라이브러리는 관계형 데이터베이스를 쿼리하는 액션을 정의한다.
두 개의 JSTL 태그 라이브러리 밸리데이터는 개발자들이 JSP 애플리케이션 내에서 표준을 코딩하도록 한다. ScriptFreeTLV
밸리데이터를 설정하여 JSP 페이지 내에 있는 다양한 스크립팅 엘리먼트(스크립틀릿, 표현, 선언)의 다양한 유형을 사용하는 것을 막는다. 이와 비슷하게 PermittedTaglibsTLV
밸리데이터는 애플리케이션의 JSP 페이지들에 의해 액세스된 커스텀 태그 라이브러리(JSTL 태그 라이브러리 포함)을 제한한다.
JSTL은 J2EE 플랫폼에 필요한 컴포넌트가 될 것이지만 적은 수의 애플리케이션 서버들만이 이를 포함하고 있는 것이 현실이다. JSTL 1.0의 레퍼런스 구현은 Apache Software Foundation의 Jakarta Taglibs 프로젝트의 일부로서 사용할 수 있다. (참고자료). 레퍼런스 구현에 있는 커스텀 태그 라이브러리는 JSTL 지원을 추가하기 위해 JSP 1.2와 Servlet 2.3 이상 스팩을 지원하는 모든 애플리케이션 서버에 통합될 수 있다.
JSP 1.2에서 JSP 액션의 애트리뷰트는 정적 캐릭터 스트링이나 익스프레션을 사용하여 지정된다. 예를 들어 Listing 2의 경우 정적 값들은 <jsp:setProperty>
액션의 name
과 property
애트리뷰트를 위해 지정된다. 반면 익스프레션은 이것의 값 애트리뷰트를 지정하는데 사용된다. 이 액션은 요청 매개변수의 현재 값을 이름이 붙여진 빈 속성으로 할당하는 효과를 갖고 있다. 이러한 방식으로 사용된 익스프레션은 request-time attribute values이라 일컬어지며 애트리뷰트 값을 동적으로 지정하기위한 JSP 스팩에 내장된 유일한 메커니즘이다.
Listing 2. request-time attribute value을 결합하는 JSP 액션
<jsp:setProperty name="user" property="timezonePref" value='<%= request.getParameter("timezone") %>'/> |
request-time attribute values가 익스프레션을 사용하여 지정되기 때문에 다른 스크립팅 엘리먼트와 같은 소프트웨어 관리 문제가 일어날 수 있다. 이런 이유로 인해 JSTL 커스텀 태그는 동적 애트리뷰트 값을 지정하기 위한 대안 메커니즘을 지원한다. JSP 익스프레션을 사용하는 것 보다 JSTL 액션용 애트리뷰트 값이 단순화 된 expression language (EL)를 사용하여 지정될 수 있다. EL은 JSP 컨테이너에 있는 데이터를 검색 및 조작할 식별자, 접근자, 연산자를 제공한다. EL은 EcmaScript(참고자료)와 XML Path Language (XPath)에 약간 의존하기 때문에 신택스는 페이지 디자이너와 프로그래머 모두 에게 익숙하다. EL은 객체와 속성들을 검색하면서 간단한 작동을 수행한다. 이것은 프로그래밍 언어도 스크립팅 언어도 아니다. JSTL 태그와 결합하면 간단하고 편리한 표기를 사용하여 복잡한 작동이 표현될 수 있다. EL 익스프레션은 달러 표시($)와 중괄호 ({})를 앞에 붙여 사용하여 범위를 정한다.(Listing 3)
Listing 3. JSTL 액션: EL 익스프레션 범위 지정
<c:out value="${user.firstName}"/> |
여러개의 익스프레션들과 정적 텍스트를 결합하여 스트링 연결을 통해 동적 애트리뷰트 값을 만들 수 있다.(Listing 4). 개별 익스프레션들은 식별자, 접근자, 리터럴, 연산자로 구성되어 있다. 식별자는 데이터 센터에 저장된 데이터 객체를 참조하는데 사용된다. EL은 11 개의 식별자를 보유하고 있다. 11 개의 EL 내장 객체에 상응하는 것들이다. 다른 모든 식별자들은 범위 변수를 참조하는 것으로 간주된다. 접근자는 객체의 속성 또는 컬렉션의 엘리먼트를 검색하는데 사용된다. 리터럴은 고정된 값들(숫자, 문자, 스트링, 부울, null)을 나타낸다. 연산자는 데이터와 리터럴이 결합 및 비교될 수 있도록 한다.
Listing 4. 정적 텍스트와 여러 EL 익스프레션을 결합하여 동적 애트리뷰트 값 지정하기
<c:out value="Hello ${user.firstName} ${user.lastName}"/> |
<jsp:useBean>
액션을 통한 JSP 에이피아이는 데이터가 저장될 수 있도록 하며 JSP 컨테이너 내에 네 개의 다른 범위에서 데이터가 검색될 수 있도록 한다. JSTL은 이러한 범위 내에 객체를 할당하고 제거할 추가 액션을 제공한다. 더욱이, EL은 범위 변수 같은 객체들을 검색하는 빌트인 지원을 제공한다. 특히 EL의 내장 객체 중 하나라도 상응하지 않는 EL 익스프레션에 있는 식별자는 네 개의 JSP 스콥 중 하나에 저장된 객체를 참조하는 것으로 자동 간주된다:
페이지 범위에 저장된 객체들은 특정 요청에 대한 페이지가 프로세스 되는 동안 검색될 수 있다. 요청 범위 내에 저장된 객체들은 요청 프로세스에 참여한 모든 페이지들이 프로세스 하는 동안 검색될 수 있다. 객체가 세션 범위에 저장되어있다면 웹 애플리케이션과의 단일 인터랙트브 세션 동안 사용자가 액세스 한 페이지로 검색될 수 있다. 웹 애플리케이션이 언로드(unload) 될 때 까지 애플리케이션 범위에 저장된 객체는 모든 페이지에서 접근가능하며 모든 사용자들이 접근할 수 있다.
캐릭터 스트링을 희망하는 범위에 있는 객체로 매핑하여 범위안에 객체를 저장할 수 있다. 이러한 경우에는 같은 캐릭터 스트링을 제공하여 범위에서 객체를 검색할 수도 있다. 스트링은 범위 매핑 중 검색되고 매핑된 객체는 리턴된다. Servlet API 내에서 그와 같은 객체들은 상응하는 범위의 애트리뷰트로서 언급된다. EL의 경우 애트리뷰트와 관련된 캐릭터 스트링은 변수 이름으로 간주될 수도 있다.
EL에서 내장 객체들과 관련이 없는 식별자들은 JSP 범위에 저장된 객체들을 명명하는 것으로 간주된다. 그와 같은 식별자는 페이지 범위를 검사하고 그 다음에는 요청 범위, 세션 범위, 애플리케이션 범위 순으로 검사한다. 식별자의 이름이 그 범위에 저장된 객체 이름과 매칭되는지의 여부가 테스트된다. 첫 번째 매치는 EL 식별자의 값으로 리턴된다. EL 식별자는 범위 변수를 참조하는 것으로 간주될 수 있다.
기술적인 관점에서 보면 내장 객체로 매핑하지 않는 식별자는 PageContext
인스턴스의 findAttribute()
메소드를 사용하여 평가되면서 현재 핸들되는 요청에 대해 익스프레션이 발생하는 페이지의 프로세싱을 나타낸다. 식별자의 이름은 이 메소드에 대한 인자로서 전달된다. 이것은 같은 이름을 가진 애트리뷰트에 대한 네 개의 범위를 검색한다. 발견된 첫 번째 매치는 findAttribute()
메소드 값으로 리턴된다. 그와 같은 애트리뷰트가 네 개의 범위 중에 없으면 null
이 리턴된다.
궁극적으로 범위 변수는 네 개의 EL 식별자로서 사용될 수 있는 이름을 가진 JSP 범위의 에트리뷰트라고 할 수 있다. 영숫자 이름으로 할당되는 한 범위 변수는 JSP 에 존재하는 모든 메커니즘으로 만들어져 애트리뷰트를 설정할 수 있다. 여기에는 빌트인 <jsp:useBean>
액션은 물론 setAttribute()
메소드가 포함된다. 게다가 네 개의 JSTL 라이브러리에서 정의된 많은 커스텀 태그들은 스스로 범위 변수로서 애트리뷰트 값을 설정할 수 있다.
11 개의 EL 내장 객체용 식별자는 표 1과 같다. JSP 내장 객체와 혼동하지 말것!
Category | 식별자 | 설명 |
JSP | pageContext |
현재 페이지의 프로세싱과 상응하는 PageContext 인스턴스 |
범위 | pageScope |
페이지 범위 애트리뷰트 이름과 값과 관련된 Map |
requestScope |
요청 범위 애트리뷰트 이름과 값과 관련된 Map |
|
sessionScope |
세션 범위 애트리뷰트 이름과 값과 관련된 Map |
|
applicationScope |
애플리케이션 범위 애트리뷰트 이름과 값과 관련된 Map |
|
요청 매개변수 | param |
요청 매개변수의 기본 값을 이름으로 저장하는 Map |
paramValues |
요청 매개변수의 모든 값을 String 어레이로서 저장하는 Map |
|
요청 헤더 | header |
요청 헤더의 기본 값을 이름으로 저장하는 Map |
headerValues |
요청 헤더의 모든 값을 String 어레이로서 저장하는 Map |
|
쿠키 | cookie |
요청에 수반되는 쿠키들을 이름으로 저장하는 Map |
초기화 매개변수 | initParam |
웹 애플리케이션의 콘텍스트 초기화 매개변수를 이릉으로 저장하는 Map |
JSP와 EL 내장 객체가 일반적인 하나의 객체를 갖는 반면(pageContext
) 다른 JSP 내장 객체는 EL에서 접근 가능하다. 페이지콘텍스트가 다른 8 개의 JSP 내장 객체 모두에 액세스 할 수 있는 속성을 갖고 있기 때문이다.
남아있는 모든 EL 내장 객체들은 맵(map)이다. 이름에 상응하는 객체들을 탐색한다. 첫 번째 네 개의 맵은 이전에 언급한 다양한 애트리뷰트 범위를 나타낸다. 특정 범위 내의 식별자들을 검색하는데 사용될 수 있다. EL이 기본적으로 사용하는 순차적인 탐색 프로세스에 의존하지 않는다.
다음 네 개의 맵은 요청 매개변수와 헤더의 값을 반입하는 용도이다. HPPT 프로토콜이 요청 매개변수와 헤더가 다중 값을 가질 수 있도록 하기 때문에 각각 한 쌍의 맵이 있다. 각 쌍 중에서 첫 번째 맵은 요청 매개변수 또는 헤더에 대한 기본 값을 리턴한다. 실제 요청 시 첫 번째로 지정된 값이 무엇이든 상관없다. 두 번째 맵은 매개변수나 헤더의 값 모두 검색될 수 있도록 한다. 이 맵의 핵심은 매개변수 또는 헤더의 이름이다. 값들은 String
객체의 어레이이다.
쿠키 내장 객체는 요청으로 설정된 쿠키에 대한 접근을 제공한다. 이 객체는 요청과 관련된 모든 쿠키들의 이름을 Cookie
객체들로 매핑하면서 쿠키들의 속성을 나타낸다.
마지막 EL 내장 객체인 initParam
은 웹 애플리케이션과 관련된 모든 콘텍스트 초기와 매개변수의 이름과 값을 저장하는 맵이다. 초기화 매개변수들은애플리케이션의 WEB-INF
디렉토리에 있는 web.xml
전개 디스크립터 파일을 통해 정의된다.
EL 식별자는 내장 객체 또는 범위 변수로서 설명될 수 있기 때문에 자바 객체로 평가해야한다. EL은 상응하는 자바 클래스에서 프리머티브를 래핑/언래핑한다. 하지만 대부분의 경우 식별자들은 자바 객체에 대한 포인터가 된다.
결과적으로 이러한 객체들의 속성이나, 어레이와 컬렉션의 경우 그들의 엘리먼트에 액세스하는 것이 바람직하다. 이를 위해 EL은 두 개의 다른 접근자를 제공한다. 닷(dot) 오퍼레이터(.
)와 브래킷 오퍼레이터([]
)이다. 이들은 속성과 엘리먼트들이 EL을 통해 연산될 수 있도록 한다.
닷 연산자는 객체의 프로퍼티에 접근하는데 사용된다. ${user.firstName}
익스프레션에서 닷 연산자는 user
식별자에 의해 참조된 객체 중 firstName
이라는 이름을 가진 속성에 액세스 한다. EL은 자바 빈 규정을 사용하여 객체 속성에 접근하기 때문에 이 속성에 대한 게터(일반적으로 getFirstName()
)는 이 익스프레션이 정확히 계산하기 위해서 반드시 정의되어야 한다. 액세스되는 속성이 객체일 때 닷 연산자는 재귀적으로 적용될 수 있다. 예를 들어 가상의 user
객체가 자바 객체로서 구현된 address
속성을 갖고 있다면 닷 연산자는 이 객체의 속성에 액세스 하기 위해 사용될 수도 있다. ${user.address.city}
익스프레션은 이 address 객체 중 중첩된 city
속성을 리턴한다.
브래킷 연산자는 어레이와 컬렉션의 엘리먼트를 검색하는데 사용된다. 어레이와 컬렉션(java.util.List
를 구현하는 컬렉션)의 경우 검색될 엘리먼트 인덱스는 브래킷 안에 나타난다. 예를 들어 ${urls[3]}
익스프레션은 이 urls
식별자에 의해 참조된 어레이 또는 컬렉션의 네 번째 엘리먼트를 리턴한다.
java.util.Map
인터페이스를 구현하는 컬렉션의 경우 브래킷 연산자는 관련 키를 사용하여 맵에 저장된 값을 찾는다. 이 키는 브래킷 내에서 지정되고 상응하는 값은 익스프레션 값으로 리턴된다. 예를 들어 ${commands["dir"]}
익스프레션은 commands
식별자에 의해 참조된 Map
의 "dir"
키와 관련된 값을 리턴한다.
익스프레션이 브래킷안에 나타날 수 있다. 중첩된 익스프레션의 계산 결과는 컬렉션이나 어레이의 적절한 엘리먼트를 검색하는 인덱스 또는 키로 작용한다. 닷 연산자가 true라면, 브래킷 연산자도 재귀적으로 적용될 수 있다. 이는 EL이 다차원 어레이, 중첩 컬렉션, 또는 둘의 결합에서 엘리먼트를 검색 할 수 있도록 한다. 더욱이 닷 연산자와 브래킷 연산자는 상호운용성이 있다. 예를들어 한 어레이의 엘리먼트가 객체라면 브래킷 연산자는 그 어레이의 엘리먼트를 검색하는데 사용될 수 있고 닷 연산자와 결합하여 엘리먼트 속성 중 하나를 검색할 수 있다. (예를 들어 ${urls[3].protocol}
).
EL이 동적 애트리뷰트 값을 정의하는 간한한 언어로서 작용한다고 볼 때, 자바 접근자와는 다른 EL 접근자의 재미있는 특성 중 하나는 null
에 적용될 때 예외를 던지지 않는다는 점이다. EL 접근자가 적용되는 객체(예를 들어 ${foo.bar}
와 ${foo["bar"]}
의 foo
식별자)가 null
이면 접근자 적용 결과 역시 null
이다. 이는 대부분의 경우, 도움이 되는 일이다.
마지막으로 닷 연산자와 브래킷 연산자는 상호 교환될 수 있다. 예를 들어 ${user["firstName"]}
은 user
객체의 firstName
속성을 검색하는데 사용될 수 있다. ${commands.dir}
가 commands
맵에서 "dir"
키와 관련된 값을 반입하는데 사용될 수 있는것과 같은 이치이다.
식별자와 접근자를 사용하여 EL은 애플리케이션 데이터(범위 변수를 통해 노출) 또는 환경 관련 정보(EL 내장 객체를 통해 노출)를 포함하고 있는 객체 계층을 트래버스 할 수 있다. 그와 같은 데이터에 간단히 접근하는 것은 많은 JSP 애플리케이션에 필요한 표현 로직을 구현하는데 종종 부적합하다.
EL에는 EL 익스프레션으로 접근된 데이터를 조작 및 비교할 여러 연산자를 포함하고 있다. 이러한 연산자들을 표 2에 요약했다.
Category | 연산자 |
산술 | + , - , * , / (or div ), % (or mod ) |
관계형 | == (or eq ), != (or ne ), < (or lt ), > (or gt ), <= (or le ), >= (or ge ) |
논리 | && (or and ), || (or or ), ! (or not ) |
타당성검사 | empty |
산술 연산자는 더하기, 빼기, 나누기를 지원한다. 다른 연산자들도 제공된다. 나누기와 나머지 연산자들은 비 상징 이름들이라는 대안을 갖고 있다. 산술 연산자의 사용법을 설명하는 예제 익스프레션은 Listing 5에 설명되어 있다. 산술 연산자를 한 쌍의 EL 익스프레션에 적용한 결과는 그러한 익스프레션에 의해 리턴된 숫자 값에 대한 연산자에 적용한 결과이다.
Listing 5. 산술 연산자를 사용하는 EL 익스프레션
${item.price * (1 + taxRate[user.address.zipcode])} |
관계형 연산자는 숫자 또는 텍스트 데이터를 비교할 수 있도록 한다. 비교 결과는 부울 값으로서 리턴된다. 논리적 연산자는 부울 값이 결합될 수 있도록 하며 새로운 부울 값을 리턴한다. EL 논리적 연산자는 중첩된 관계형 연산자 또는 논리적 연산자의 결과에 적용될 수 있다. (Listing 6).
Listing 6. 관계형 연산자 및 논리적 연산자를 사용하는 EL 익스프레션
${(x >= min) && (x <= max)} |
EL 연산자는 empty
이다. 데이터의 타당성 검사에 특히 유용하다. empty
연산자는 하나의 익스프레션을 인자로 취한다.(${empty input}
). 그리고 익스프레션이 empty
값으로 계산했는지의 여부를 나타내는 부울 값을 리턴한다. null
로 계산한 익스프레션은 empty
로 간주된다. 어떤 엘리먼트도 없는 컬렉션이나 어레이와 같다. empty
연산자는 인자가 길이가 0인 String
으로 계산했다면 true
로 리턴한다.
EL 연산자의 우선순위는 표 3에 정리되어 있다. Listing 5와 6에 제안된 것 처럼 괄호는 그룹 익스프레션에 사용되고 일반적인 우선순위를 따른다.
표 3. EL 연산자 우선순위 (위->아래, 왼쪽->오른쪽)
[] , . |
() |
unary - , not , ! , empty |
* , / , div , % , mod |
+ , binary - |
() < , > , <= , >= , lt , gt , le , ge |
== , != , eq , ne |
&& , and |
|| , or |
숫자, 캐릭터 스트링, 부울, null
은 EL 익스프레션에서 리터럴 값으로 지정될 수 있다. 캐릭터 스트링은 싱글 쿼트 또는 더블 쿼트로 범위가 지정된다. 부울 값은 true
와 false
로 계산된다.
앞서 언급했지만 JSTL 1.0에는 네 개의 커스텀 태그 라이브러리가 포함되어 있다. 익스프레션 언어로 JSTL 태그의 인터랙션을 설명하기 위해 JSTL core
라이브러리에서 여러 태그들을 검토할 것이다. 모든 JSP 커스텀 태그 라이브러리로 true가 된다면 taglib
지시문은 이 라이브러리 태그를 사용할 수 있는 페이지에 포함되어야한다. 이 특정 라이브러리에 대한 지시문은 Listing 7에 나타나있다.
Listing 7. JSTL core 라이브러리의 EL 버전용 테그립 지시문
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> |
실제로 JSTL core
라이브러리에 상응하는 두 개의 Taglib
지시문이 있다. JSTL텐에서 EL은 옵션이기 때문이다. JSTL 1.0 의 네 개의 커스텀 태그 라이브러리들은 동적 애트리뷰트 값을 지정할 때 EL 대신 JSP 익스프레션을 사용하는 대안 버전을 갖고있다. 이러한 대안 라이브러리는 JSP의 전통적인 요청시간 애트리뷰트 값에 의존하기 때문에 RT 라이브러리로 일컬어진다. 반면 익스프레션 언어를 사용하는 것은 EL 라이브러리라고 한다. 개발자들은 대안 Taglib
지시문을 사용하는 각각의 라이브러리의 버전들을 구별한다. RT 버전의 코어 라이브러리를 사용하기 위한 지시문은 Listing 8에 나와있다. 하지만 지금은 EL에 집중해야 하기 때문에 지금 필요한 것은 이 지시문들 중 첫 번째 것이다.
Listing 8. RT 버전의 JSTL core 라이브러리용 태그립 지시문
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %> |
첫 번째 JSTL 커스텀 태그는 <c:set>
액션이다. 이미 언급했듯이 범위 변수는 JSTL에서 핵심적인 역할을 하고 <c:set>
액션은 태그 기반의 매커니즘을 제공하여 범위 변수의 생성 및 설정에 쓰인다. 이 액션의 신택스는 Listing 9와 같다. var
애트리뷰트는 범위 변수 이름을 정하고 scope
애트리뷰트는 변수가 머물게 될 범위를 나타내고, value
애트리뷰트는 변수가 될 값을 지정한다. 지정된 변수가 이미 존재하면 지시된 값으로 할당된다. 그렇지 않다면 새로운 범위 변수가 만들어지고 그 값으로 초기화된다.
<c:set var="name" scope="scope" value="expression"/> |
scope
애트리뷰트는 선택적이며 page
로 기본 설정되어 있다.
<c:set>
의 두 예제는 Lisitng 10에 설명되어 있다. 첫 번째 예제에서 세션 범위 변수는 String
값으로 설정된다. 두 번째에서는 익스프레션은 숫자 값을 설정하는데 사용된다. square
라는 페이지 범위 변수는 x
라는 요청 매개변수 값을 배가시킨 결과로 할당된다.
<c:set var="timezone" scope="session" value="CST"/> <c:set var="square" value="${param['x'] * param['x']}"/> |
애트리뷰트를 사용하는 대신 범위 변수용 값을 <c:set>
액션의 바디 콘텐트로 설정할 수 있다. 이러한 접근방식을 사용하여 Listing 10의 첫 번째 예제를 Listing 11과 같이 재작성할 수 있다. 더욱이 <c:set>
태그의 바디 콘텐트가 커스텀 태그를 적용하는 것도 가능하다. <c:set>
의 바디 안에서 만들어진 모든 콘텐트는 String
값 같이 지정된 변수에 할당된다..
Listing 11. 바디 콘텐트를 통해 <c:set> 액션용 값 지정하기
<c:set var="timezone" scope="session">CST</c:set> |
JSTL core 라이브러리에는 범위 변수를 관리하는 두 번째 태그(<c:remove>
)가 포함되어 있다. 이름에서 시사되는 바와 같이 <c:remove>
액션은 범위 변수를 지우는데 사용되고 두 개의 애트리뷰트를 취한다. var
애트리뷰트는 제거될 변수를 명명하고 선택적인 scope
애트리뷰트는 제거되어야 할 범위를 나타낸다. (Listing 12).
<c:remove var="timezone" scope="session"/> |
<c:set>
액션은 익스프레션의 결과가 범위 변수로 할당될 수 있도록 하는 반면 개발자들은 익스프레션 값을 저장하는 대신 간단히 디스플레이하기를 원한다. 이는 JSTL의 <c:out>
커스텀 태그의 몫이다. (Listing 13). 이 태그는 value
애트리뷰트에서 지정된 익스프레션을 계산한다. 그런다음 결과를 프린트한다. 선택적 default
애트리뷰트가 지정되면 value
애트리뷰트의 익스프레션이 null
또는 비어있는 String
으로 계산될 때 <c:out>
액션은 값을 프린트한다.
<c:out value="expression" default="expression" escapeXml="boolean"/> |
escapeXml
애트리뷰트 또한 선택사항이다. "<", ">", "&" 같은 캐릭터가 <c:out>
태그에 의해 아웃풋 될 때 종료되는지의 여부를 제어한다. escapeXml
이 true로 설정되어 있다면 이 캐릭터들은 상응하는 XML 인터티(<
, >
, &
)로 바뀐다.
예를 들어, user
라는 세션 범위 변수가 있다고 가정해보자. 이것은 사용자에 대한 username
과 company
라는 두 개의 속성들을 정의하는 클래스의 인스턴스이다. 이 객체는 사용자가 사이트에 접근할 때마다 세션에 할당된다. 하지만 이 두 개의 속성들은 사용자가 실제로 로그인하기 전까지 설정되지 않는다. (Listing 14). 일단 사용자가 로그인하면 "Hello"가 디스플레이 되고 뒤따라서 사용자 이름과 감탄부호가 나온다. 사용자가 로그인하기 전에 여기에서 생긴 콘텐트는 "Hello Guest!" 라는 구(phrase)가 된다. 이 경우 username
속성이 초기화되지 않았기 때문에 <c:out>
태그는 default
애트리뷰트 값을 프린트한다.
Listing 14. <c:out> 액션 예제 (디폴트 콘텐트)
Hello <c:out value="${user.username}" default=="Guest"/>! |
<c:out>
태그의 escapeXml
애트리뷰트를 사용하는 Listing 15를 보자. company
속성이 자바 String
값인 "Flynn & Sons"
으로 설정되었다면 이 액션에서 생긴 콘텐트는 Flynn & Sons
이 된다. 이 액션이 HTML 또는 XML 콘텐트를 만드는 JSP 페이지의 일부라면 이 캐릭터의 스트링 중간에 있는 앰퍼샌트 부호는 HTML 또는 XML이 문자를 제어하고 이 콘텐트의 렌더링 또는 파싱을 방해하는것으로 해석하고 끝난다. escapeXml
애트리뷰트의 값이 true
로 설정되면 생성된 콘텐트는 Flynn & Sons
이 된다. 이 콘텐트를 만나는 브라우저 또는 파서는 인터프리테이션에 아무 문제가 없다. HTML과 XML이 JSP 애플리케이션에서 가장 일반적인 콘텐트 유형이라면 escapeXml
애트리뷰트의 디폴트 값이 true
라는 것은 놀라운 일이 아니다.
<c:out value="${user.company}" escapeXml=="false"/> |
동적 데이터를 단순하게 하는 것 외에도 디폴트 값을 지정하는 <c:out>
의 기능은 <c:set>
을 통해 변수 값을 설정할 때에도 유용하다. 범위 변수에 할당된 값이 <c:set>
태그의 바디 콘텐트로 지정될수 있고 value 애트리뷰트로서도 가능하다. <c:out>
액션을 <c:set>
태그의 바디 콘텐트에 중첩하여 변수 할당은 이것의 디폴트 값을 이용할 수 있다. (Listing 11).
이러한 접근 방식은 Listing 16에도 설명되어 있다. 외부 <c:set>
태그의 작동은 단순하다.
Listing 16. <c:set>과 <c:out> 결합: 디폴트 변수 값 제공
<c:set var="timezone" scope=="session"> <c:out value="${cookie['tzPref'].value}" default=="CST"/> </c:set> |
요청에 제공된 tzPref
라는 이름의 쿠키가 없다. 내장 객체를 사용한 검색은 null
이 된다는 것을 의미한다. 익스프레션은 전체적으로 null
을 리턴한다. value
애트리뷰트를 계산한 값이 null
이기 때문에 <c:out>
태그는 default
애트리뷰트를 계산한 결과를 아웃풋한다.
이 글은 스프링노트에서 작성되었습니다.
log4j (0) | 2012.05.08 |
---|---|
JSTL- 사용 하기 (0) | 2012.05.08 |
JSP 에러코드 모음 (0) | 2012.05.08 |
include (0) | 2012.05.08 |
IBatis (0) | 2012.05.08 |
JSP 각종 에러코드 번호입니다. 에러 발생시 참고하세요.
빈번하게 자주 발생하는 에러코드는 200, 404, 500 입니다.
참고로 한말씀을 드리자면 에러를 많이 봐야 프로그램 코딩 실력이 늡니다.
100 Continue
101 Switching Protocols
200 OK (에러 없이 전송 성공)
202 Accepted - 서버가 클라이언트의 명령을 받음
203 Non-authoritative Information - 서버가 클라이언트 요구 중 일부만 전송함
204 Non Content - 클라이언트 요구를 처리했으나 전송할 데이터가 없음
205 Reset Content
206 Partial Content
300 Multiple Choices - 최근에 옮겨진 데이터를 요청함
301 Moved Permanently - 요구한 데이터를 변경된 임시 URL 에서 찾음
302 Move Permanently - 요구한 데이터가 변경된 URL 에 있음을 명시함
303 See Other - 요구한 데이터를 변경하지 않았기 때문에 문제가 있음
304 Non modified
305 Use Proxy
400 Bad Request, 요청실패 - 문법상 오류가 있어서 서버가 요청 사항을 이해하지 못함
401.1 Unauthorized, 권한없음 - 접속 실패. 서버에 로그온 하려는 요청 사항이 서버에
들어있는 권한과 비교했을 시 맞지 않을 경우 발생
(접근 권한을 받기 위해 서버 운영자에게 요청해야 함)
401.2 Unauthorized, 권한없음 - 서버 설정으로 인한 접속 실패. 서버에 로그온 하려는
요청 사항이 서버에 들어있는 권한과 비교했을 시 맞지
않을 경우 발생
(www-authenicate head field 를 전송하지 않아서 발생)
401.4 Unauthorized, 권한없음 - 필터에 의한 권한 부여 실패. 서버에서 서버에 접속하는
사용자들을 확인하기 위해 설치된 필터 프로그램이 있음을
의미함.
(서버 접속에 이용되는 인증 과정이 필터 프로그램에 의해
거부된 것)
402 Payment Required, 예약됨
402.3 Unauthorized, 권한없음 - 자원에 대한 ACL 에 기인한 권한 없음.
클라이언트가 특정 자원에 접근할 수 없을 때 발생
페이지가 될 수도 있고, 클라이언트의 주소 입력란에
명기된 파일일 수도 있고, 클라이언트가 해당 주소로
접속할 때 이용되는 또 다른 파일일 수도 있다.
(접근할 주소를 확인해보고 서버 운영자에게 자신의 접근
권한 유무 확인)
403.1 Forbidden, 금지 - 수행 접근 금지. CGI 나 ISA-PI, 혹은 수행시키지 못하도록 되어
있는 디렉토리 내의 실행 파일을 수행시키려고 했을 때 발생
403.2 Forbidden, 금지 - 읽기 접근 금지. 브라우저가 접근한 디렉토리에 가용한 디폴트
페이지가 없을 경우에 발생함.
403.4 Forbidden, 금지 - SSL 필요. 접근하려는 페이지가 SSL 로 보안 유지되고 있는 것일
때 발생함
403.5 Forbidden, 금지 - SSL 128 필요. 접근하려는 페이지가 SSL로 보안 유지되고 있을
때 발생, 브라우저가 128 bit 의 SSL 을 지원하는지를 확인해야함
403.6 Forbidden, 금지 - IP 주소 거부됨. 서버가 사이트에 접근이 허용되지 않는 IP 주소로
사용자가 접근하려 했을 때 발생
403.7 Forbidden, 금지 - 클라이언트 확인 필요. 접근하려는 자원이 서버가 인식하기 위해
브라우저에게 클라이언트 SSL을 요청하는 경우 발생. 자원을 이용
할 수 있는 사용자임을 입증하는데 사용됨
403.8 Forbidden, 금지 - 사이트 접근 거부. 웹 서버가 요청사항을 수행하고 있지 않았거나,
해당 사이트에 접근하는 것을 허락하지 않았을 경우에 발생함
403.9 Forbidden, 접근금지 - 연결된 사용자수 과다. 웹 서버가 busy한 상태에 있어서
요청을 수행할 수 없을 경우 발생
403.10 Forbidden, 접근금지 - 설정이 활실하지 않음. 웹 서버의 설정 부분에 문제가 있을
경우 발생
403.11 Forbidden, 접근 금지 - 패스워드 변경. 사용자 인증 단계에서 잘못된 패스워드를 입력
했을 경우 발생
403.12 Forbidden, 접근 금지 - Mapper 접근 금지. 클라이언트 인증용 맵(map)이 해당 웹
사이트에 접근하는 것을 거부할 경우에 발생함
404 Not Found, 문서를 찾을 수 없음 - 클라이언트가 요청한 문서를 찾지 못한 경우에 발생.
404.5 Unauthorized, 권한없음 - ISA PI/CGI 어플리케이션에 의한 권한 부여 실패.
서버의 어드레스에 ISA PI 나 CGI 프로그램이 설치되어
있어 사용자의 권한을 검증함. 서버 접속에 이용되는 인증
과정이 프로그램에 의해 거부됨.
405 Method not allowed, 메소드 허용 안 됨 - Request 라인에 명시된 메소드를 수행
하기 위한 해당 자원의 이용이 허용되지
않았을 경우 발생
406 Not Acceptable, 받아들일 수 없음 - 요청 사항에 필요한 자원은 요청 사항으로 전달
된 Accept header 에 따라
"Not Acceptable" 내용을 가진 사항이 있
을 경우에 발생
407 Proxy Authenication Required, Proxy 인증이 필요함
- 해당 요청이 수행되도록 Proxy 서버에게 이증을 받아야 할 경우 발생
408 Request timeout, 요청 시간이 지남
409 Conflict
410 Gone, 영구적으로 사용할 수 없음.
411 Length Required
412 Precondition Failed, 선결조건 실패 - Request-header Field 에 하나 이상에
선결조건에 대한 값이 서버에서 테스트 결과
false 로 나왔을 경우 발생
413 Request entity too large
414 Request-URI too long, 요청한 URI 가 너무 김 - 요청한 URI 의 길이가 너무 길어
서 서버가 요청 사항의 이행을
거부했을 경우 발생
415 Unsupported media type
500 Internal Server Error, 서버 내부 오류 - 웹 서버가 요청사항을 수행할
수 없을 경우에 발생.
(코딩 실수가 대부분)
501 Not Implemented, 적용 안 됨 - 웹 서버가 요청사항을 수행하는데 필요한 기능을
지원하지 않는 경우에 발생
502 Bad geteway, 게이트웨이 상태 나쁨 - 게이트웨이 상태가 나쁘거나 서버의 과부하
상태일 때 발생
503 Service Unavailable, 서비스 불가능 - 서비스가 현재 멈춘 상태 또는 현재 일시적인
과부하 또는 관리 상황일 때 발생될 수 있다.
504 Geteway timeout
505 HTTP Version Not Supported
이 글은 스프링노트에서 작성되었습니다.
JSTL- 사용 하기 (0) | 2012.05.08 |
---|---|
JSTL (0) | 2012.05.08 |
include (0) | 2012.05.08 |
IBatis (0) | 2012.05.08 |
Filter(유저를 this 시켜 보자 ) (0) | 2012.05.08 |
JSP - include //
<%@ include file="파일경로.jsp" %>
JSP로 작업하였을 경우 웹상에서 한글이 깨져 보일때
<html>위에 (즉, 페이지 맨 위)
<%@ page contentType="text/html; charset=EUC-KR"%>
or
<%@ page contentType="text/html; charset=euc-kr" language="java" import="java.sql.*" errorPage="" %>
을 넣어준다
------------------------------------------------------------------------------------------------------
JSP에서 인크루드 시킬때는
<% @include file="../inc/top_menu.jsp" %>
삽입한다
------------------------------------------------------------------------------------------------------
* 참고로 HTML에서 인크루드 삽입할때는
<!--#include file="파일경로" -->
이렇게 파일을 생성 // list 메서드. 변수 등의 자주 사용 하는 것을 파일로 생성 한다. 첫단에 붙일 경우 prelude ,마지막 단에 붙일 경우 coda 로 사용 하면 됨.
web.xml 파일의 수정
이렇듯 web.xml 에 추가 시키면 메서드 이름및 변수 이름을 직접 사용 바로 사용 하여 사용가능 하다.
먼저 top.jsp 를 생성.
이후 ./ 메인jsp 에 인크루드 하여야 한다.
여기서 div의 아이디는 css 에서 내부 설정을 위해 필요 한 부분 이며 DIV 의 id 를 통해 css 로 설정한 경우 내부의 ul li 도 설정 이 가능 하다는것을 알수 있다.
중간 <jsp:param value="<%=msg %>" name="msg"/> 경우 초기 생성시 에 이 div 에 대한 부분에 대한 권한을 top.jsp 로 넘겨 주면서 msg변수의 값을
파라미터 형식으로 보내 줄수 있다. 여기서. 보내 줄때 기본적으로 로마 기호를 따름으로. top.jsp 에서는 euc-kr 로 인코딩 하여도
ex)<%request.setCharacterEncoding("utf-8"); %> -- 하더라도 보내주는 값이 로마xx 에 따름으로 한글이 깨져 출력 된다 따라서 코딩 상단에.
path.jsp 에서 .// <%request.setCharacterEncoding("utf-8"); %> 를 해줘야 한다.
이 글은 스프링노트에서 작성되었습니다.
JSTL (0) | 2012.05.08 |
---|---|
JSP 에러코드 모음 (0) | 2012.05.08 |
IBatis (0) | 2012.05.08 |
Filter(유저를 this 시켜 보자 ) (0) | 2012.05.08 |
FileUploadRequestWrapper (0) | 2012.05.08 |