<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
<%!
public Integer toInt(String x){
int a = 0;
try{
a = Integer.parseInt(x);
}catch(Exception e){}
return a;
}
%>
<%
int pageno = toInt(request.getParameter("pageno"));
if(pageno<1){//현재 페이지
pageno = 1;
}
int total_record = 754;    //총 레코드 수
int page_per_record_cnt = 10;  //페이지 당 레코드 수
int group_per_page_cnt =5;     //페이지 당 보여줄 번호 수[1],[2],[3],[4],[5]
//      [6],[7],[8],[9],[10]

int record_end_no = pageno*page_per_record_cnt;
int record_start_no = record_end_no-(page_per_record_cnt-1);
if(record_end_no>total_record){
record_end_no = total_record;
}
   
   
int total_page = total_record / page_per_record_cnt + (total_record % page_per_record_cnt>0 ? 1 : 0);
if(pageno>total_page){
pageno = total_page;
}


//  현재 페이지(정수) / 한페이지 당 보여줄 페지 번호 수(정수) + (그룹 번호는 현제 페이지(정수) % 한페이지 당 보여줄 페지 번호 수(정수)>0 ? 1 : 0)
int group_no = pageno/group_per_page_cnt+( pageno%group_per_page_cnt>0 ? 1:0);
// 현재 그룹번호 = 현재페이지 / 페이지당 보여줄 번호수 (현재 페이지 % 페이지당 보여줄 번호 수 >0 ? 1:0)
// ex)  14 = 13(몫) =  (66 / 5) 1 (1(나머지) =66 % 5)   
int page_eno = group_no*group_per_page_cnt;
// 현재 그룹 끝 번호 = 현재 그룹번호 * 페이지당 보여줄 번호 
// ex)  70 = 14 * 5
int page_sno = page_eno-(group_per_page_cnt-1);
//  현재 그룹 시작 번호 = 현재 그룹 끝 번호 - (페이지당 보여줄 번호 수 -1)
// ex)  66 = 70 -  4 (5 -1)
if(page_eno>total_page){
//    현재 그룹 끝 번호가 전체페이지 수 보다 클 경우
page_eno=total_page;
//    현재 그룹 끝 번호와 = 전체페이지 수를 같게
}
int prev_pageno = page_sno-group_per_page_cnt;  // <<  *[이전]* [21],[22],[23]... [30] [다음]  >>
// 이전 페이지 번호 = 현재 그룹 시작 번호 - 페이지당 보여줄 번호수
// ex) 46 = 51 - 5
int next_pageno = page_sno+group_per_page_cnt; // <<  [이전] [21],[22],[23]... [30] *[다음]*  >>
// 다음 페이지 번호 = 현재 그룹 시작 번호 + 페이지당 보여줄 번호수
// ex) 56 = 51 - 5
if(prev_pageno<1){
// 이전 페이지 번호가 1보다 작을 경우
prev_pageno=1;
// 이전 페이지를 1로
}
if(next_pageno>total_page){
// 다음 페이지보다 전체페이지 수보가 클경우
next_pageno=total_page/group_per_page_cnt*group_per_page_cnt+1;
// next_pageno=total_page
// 다음 페이지 = 전체페이지수 / 페이지당 보여줄 번호수 * 페이지당 보여줄 번호수 + 1 
// ex)    =  76 / 5 * 5 + 1 ???????? 
}
// [1][2][3].[10]
// [11][12]
%>
현재 페이지   (pageno)   : <%=pageno%><br />
전체 데이터 수   (total_record) : <%=total_record %><br />
한페이지 당 레코드 수   (page_per_record_cnt) : <%=page_per_record_cnt %><br />
한페이지 당 보여줄 페지 번호 수   (group_per_page_cnt) : <%=group_per_page_cnt %><br />

<hr />
레코드 시작 번호  (record_start_no) : <%=record_start_no%><br />
레코드 끝 번호    (record_end_no) : <%=record_end_no %><br />
전체페이지 수     (total_page)  : <%=total_page %><br />
<hr />
현재 그룹번호 [1] (group_no):  <%=group_no %><br />
현재 그룹 시작 번호(page_sno): <%= page_sno%><br />
현재 그룹 끝 번호  (page_eno): <%= page_eno%><br />
이전 페이지 번호   (prev_pageno) <%=prev_pageno%><br />
다음 페이지 번호   (next_pageno) <%=next_pageno%><br />
<hr />


<a href="pase.jsp?pageno=1">[맨앞으로]</a>
<a href="pase.jsp?pageno=<%=prev_pageno%>">[이전]</a> 
<%for(int i =page_sno;i<=page_eno;i++){%>
<a href="pase.jsp?pageno=<%=i %>">
<%if(pageno == i){ %>
[<%=i %>]
<%}else{ %>
<%=i %>
<%} %>
</a> 
<%-- 콤마  --%>
<%if(i<page_eno){ %>
,
<%} %>
<%} %>
 
<a href="pase.jsp?pageno=<%=next_pageno%>" >[다음]</a>
<a href="pase.jsp?pageno=<%=total_page %>">[맨뒤로]</a>

'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
Posted by 사라링

Problems warning 를 제거 하자.

 | JSP
2012. 10. 23. 13:14






@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' 카테고리의 다른 글

페이징 처리. 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
Posted by 사라링

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;
}
%>

JQuery 이용해서 Excel 파일로 저장하기. javascript  ASP

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가 자주 변경되면 그것 또한 짜증이였다.

 

 <%
 Response.Buffer = true
 Response.AddHeader "Content-Disposition","attachment;filename=each_week_data.xls"
 Response.ContentType = "application/vnd.ms-excel"
 Response.CacheControl = "public"
%>

해서. 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()" /> <!--엑셀 저장 버튼-->

<!--엑셀로 저장-->
<form action="a_e.asp" method="post" target="_blank" onsubmit='$("#excel_val").val($("#excel_view").html())' id="exe">
 <input type="hidden" name="excel_val" id="excel_val" />
</form>
<script type="text/javascript">
    function excel_save(){
    $("#exe").submit();
    }
</script>
<!--엑셀로 저장 끝-->


 

a_e.asp

 

<%
 Response.Buffer = true
 Response.AddHeader "Content-Disposition","attachment;filename=each_week_data.xls"
 Response.ContentType = "application/vnd.ms-excel"
 Response.CacheControl = "public"
%>

<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">

<head>
<style type="text/css">
body {font-family:tahoma;font-size: 12px}
table {padding:2px;border-spacing:0px;font-family:tahoma;font-size: 12px;border-collapse: collapse}
input,textarea,Select {font-family:tahoma;font-size: 12px;border-collapse: collapse;}
.bgc {background-color:#dddddd}
.bgct {background-color:#FAF082}
td {text-align:center}
br {mso-data-placement:same-cell;}

</head>
<body>
<%=request("excel_val")%>
</body>

 


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> 을 리턴하므로 원하는 결과를 얻을 수 있다.


다음은 서버쪽의 코드를 Jsp의 예로 보면 다음과 같다.


<%
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' 카테고리의 다른 글

페이징 처리. 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
Posted by 사라링

정규표현식  연산자, 기호 등을 가지고 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]?$\







'JSP' 카테고리의 다른 글

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
Posted by 사라링

기본JDBC 만들기

 | JSP
2012. 5. 8. 18:18

ojdbc.jpg  WEB-INF/lib 폴더 안에 ojdbc14.jar 파일을 넣는다. libraries/Web App Libraries 폴더 안에서 확인 가능

 

memberlist.jsp

 

<?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){}
%>

 

memberview.jsp

<?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){}
%>

이 글은 스프링노트에서 작성되었습니다.


'JSP' 카테고리의 다른 글

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
Posted by 사라링

Tiles(레이아웃처리)

 | JSP
2012. 5. 8. 18:18

컴포지트 뷰(Composite View) 패턴을 구현한 라이브러리 중에서 현재 널리 사용되고 있는 라이브러리는 Tiles 2로서,

http://tiles.apache.org/download.html 사이트에서 최신버전을 다운로드 받을 수 있다. 현재 최신버전은 2.2.2이고 자바 5 또는 그 이상 버전에서 동작한다.

  1. 필요한 jar 파일을 WEB-INF/lib 디렉터리에 복사한다.
  2. web.xml에 초기화 코드 추가
  3. Tile 2 설정파일 작성
  4. 레이아웃 템플릿 JSP 파일 작성
  5. 템플릿을 사용하는 JSP 파일 작성

미니 코드

gate.jsp

1
2
3
<%@ page contentType="text/html; charset=euc-kr" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<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" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<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>

 

이 글은 스프링노트에서 작성되었습니다.


'JSP' 카테고리의 다른 글

정규표현식 공식 및 응용 .  (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
Posted by 사라링

Propertise 한글 사용

 | JSP
2012. 5. 8. 18:17

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로 설정한다.

 

# \uc804\uc5ed \ub85c\uae45 \uc124\uc815
log4j.rootLogger=ERROR, stdout, file
# MyBatis \ub85c\uae45 \uc124\uc815...
#log4j.logger.org.apache.ibatis=DEBUG
#log4j.logger.java.sql.Connection=DEBUG
#log4j.logger.java.sql.Statement=DEBUG
#log4j.logger.java.sql.PreparedStatement=DEBUG
#log4j.logger.java.sql.ResultSet=DEBUG
# Console \ucd9c\ub825...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
# file \uc774\ub984\uc758 appender \uc124\uc815
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.Threshold=INFO
log4j.appender.file.File=C:/MyTest.log
log4j.appender.file.DatePattern='.'yyyy-MM-dd
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%-5p %d{ISO8601} %l] %m%n

이렇게 보이는 properties 파일이

  1. 전역 로깅 설정
    log4j.rootLogger=ERROR, stdout, file
    # MyBatis 로깅 설정...
    #log4j.logger.org.apache.ibatis=DEBUG
    #log4j.logger.java.sql.Connection=DEBUG
    #log4j.logger.java.sql.Statement=DEBUG
    #log4j.logger.java.sql.PreparedStatement=DEBUG
    #log4j.logger.java.sql.ResultSet=DEBUG
    # Console 출력...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    # file 이름의 appender 설정
    log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.file.Threshold=INFO
    log4j.appender.file.File=C:/MyTest.log
    log4j.appender.file.DatePattern='.'yyyy-MM-dd
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=[%-5p %d{ISO8601} %l] %m%n
 

이렇게 보인다.

 

이 글은 스프링노트에서 작성되었습니다.


'JSP' 카테고리의 다른 글

기본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
Posted by 사라링

POI

 | JSP
2012. 5. 8. 18:17

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
language="java"
contentType="text/html;charset=euc-kr"
import="java.io.*,
 org.apache.poi.poifs.filesystem.POIFSFileSystem,
 org.apache.poi.hssf.record.*,
 org.apache.poi.hssf.model.*,
 org.apache.poi.hssf.usermodel.*,
 org.apache.poi.hssf.util.*" %>

<html>
<head><title>Read example</title></head>
<body>
<%

  String excelfile = "C:\\Tomcat 5.0\\webapps\\ROOT\\example.xls";

  try {
       POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(excelfile)); 


       //워크북을 생성!                       HSSFWorkbook workbook = new HSSFWorkbook(fs);       int sheetNum = workbook.getNumberOfSheets();

       for (int k = 0; k < sheetNum; k++) {            //시트 이름과 시트번호를 추출
%>
            <br><br>
            Sheet Number <%= k %> <br>
            Sheet Name <%= workbook.getSheetName(k) %><br>
<%
            HSSFSheet sheet = workbook.getSheetAt(k);
            int rows = sheet.getPhysicalNumberOfRows();


            for (int r = 0; r < rows; r++) {                // 시트에 대한 행을 하나씩 추출
                HSSFRow row   = sheet.getRow(r);
                if (row != null) { 
                     int cells = row.getPhysicalNumberOfCells();
%>
                     ROW  <%= row.getRowNum() %> <%=cells%></b><br>
<%

                     for (short c = 0; c < cells; c++) {                        // 행에대한 셀을 하나씩 추출하여 셀 타입에 따라 처리
                         HSSFCell cell  = row.getCell(c);
                         if (cell != null) { 
                              String value = null;

                              switch (cell.getCellType()) {

                                   case HSSFCell.CELL_TYPE_FORMULA :
                                       value = "FORMULA value=" + cell.getCellFormula();
                                        break;
                                   case HSSFCell.CELL_TYPE_NUMERIC :
                                       value = "NUMERIC value=" + cell.getNumericCellValue(); //double
                                       break;
                                  case HSSFCell.CELL_TYPE_STRING :
                                       value = "STRING value=" + cell.getStringCellValue(); //String
                                       break;
                                  case HSSFCell.CELL_TYPE_BLANK :
                                      value = null;
                                     break;
                                 case HSSFCell.CELL_TYPE_BOOLEAN :
                                     value = "BOOLEAN value=" + cell.getBooleanCellValue(); //boolean
                                    break;
                                case HSSFCell.CELL_TYPE_ERROR :
                                     value = "ERROR value=" + cell.getErrorCellValue(); // byte
                                     break;
                                default :
                             }
%>         
                          <%= "CELL col=" + cell.getCellNum() + " VALUE=" + value %> <br>
<%
                        } 
                    }
                }
            }
       }
   } catch (Exception e) {
%>
       Error occurred:  <%= e.getMessage() %>
<%   
       e.printStackTrace();
    }

%>


</body>
</html>


위 소스의 결과입니다.


Sheet Number 0
Sheet Name 한글
ROW 0 4
CELL col=0 VALUE=STRING value=일반
CELL col=1 VALUE=NUMERIC value=123456.0
CELL col=2 VALUE=STRING value=사용자정의
CELL col=3 VALUE=NUMERIC value=38392.0
ROW 1 4
CELL col=0 VALUE=STRING value=숫자
CELL col=1 VALUE=NUMERIC value=123456.0
CELL col=2 VALUE=STRING value=날짜 (yy-m-d h:mm)
CELL col=3 VALUE=NUMERIC value=38393.0
ROW 2 4
CELL col=0 VALUE=STRING value=통화
CELL col=1 VALUE=NUMERIC value=123456.0
CELL col=2 VALUE=STRING value=날짜 (yy年 mm月 dd日)
CELL col=3 VALUE=NUMERIC value=38394.0
ROW 3 4
CELL col=0 VALUE=STRING value=텍스트
CELL col=1 VALUE=NUMERIC value=123456.0
CELL col=2 VALUE=STRING value=날짜 (yyyy년 mm월 dd일)
CELL col=3 VALUE=NUMERIC value=38395.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

 

이 글은 스프링노트에서 작성되었습니다.


'JSP' 카테고리의 다른 글

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
Posted by 사라링

PAGING(sql)

 | JSP
2012. 5. 8. 18:17

  -- 페이징 기법.  가정.
  --  총레코드 수: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>

 


첨부파일 내용 다운로드 :

 

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.


'JSP' 카테고리의 다른 글

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
Posted by 사라링

동적쿼리문

 | JSP
2012. 5. 8. 18:17

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>

@패키지명.클래스@메소드 요렇게 호출해야 되기 때문에 패키지나 클래스명은 간단하게 명명하면 좋을것 같다.

이 글은 스프링노트에서 작성되었습니다.


'JSP' 카테고리의 다른 글

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
Posted by 사라링

Multiple Parameter

 | JSP
2012. 5. 8. 18:17

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으로 잡습니다.

<select id="selectMachineAgentMap" parameterType="map" resultType="map">
 SELECT MACHINE_ID, AGENT_ID
 FROM M_MACHINE_AGENT_MAP_TBL
 WHERE MACHINE_ID = #{machineId} AND AGENT_ID = #{agentId}
  </select>



위 와 같이 하면 MyBatis는 맵 객체를 생성하고 거기에 @Param에 해당하는 이름으로 전달받은 인자를 저장합니다. 이후 프로세서에서는 #{}의 이름에 해당하는 key를 이용하여 데이터를 추출하고 컬럼의 메타데이터에 해당하는 타입으로 캐스팅하여 쿼리를 날리게 됩니다.

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

log4j구현환경제공.

 | JSP
2012. 5. 8. 18:17

log4j.jpg

그림과 과 같은 구조에 주의 하자.

res 라는 clasess  폴더 안의 패키지 kr.or.ddit.mybatis 안에 마이바티스팩토리와  config.xml  이 구조화 되어있다.

log4j.properties 라는 프로 퍼티스 파일을 res 즉 클래스시스 루트단에 생성 한후.

  1. 전역 로깅 설정
    log4j.rootLogger=DEBUG, stdout, file
    #log4j.rootLogger=ERROR, file
    # MyBatis 로깅 설정...
    #log4j.logger.org.apache.ibatis=DEBUG
    log4j.logger.java.sql.Connection=DEBUG
    #log4j.logger.java.sql.Statement=DEBUG
    log4j.logger.java.sql.PreparedStatement=DEBUG
    log4j.logger.java.sql.ResultSet=DEBUG
    # Console 출력...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    file 이름의 appender 설정
    log4j.appender.file=org.apache.log4j.DailyRollingFileAppender

    log4j.appender.file.Threshold=INFO
    log4j.appender.file.File=C:/MyTest.log
    log4j.appender.file.DatePattern='.'yyyy-MM-dd'.log'
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=[%-5p %d{ISO8601} %l] %m%n

 

의 내용을 적어 놓으면 . 자동으로 설정 된다. log4j 의 경우 마이바티스 에서 자동으로 리포팅 하여 설정 되는듯 하다.

내부의 자세한 내용은 JSP 단의 log4j  에서 확인 하자.

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

동적쿼리문  (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
Posted by 사라링

MyBatis (odbc프레임웍)

 | JSP
2012. 5. 8. 18:16

마이바티스

http://code.google.com/p/mybatis/downloads/detail?name=mybatis-3.1.1-bundle.zip&can=3&q=%22mybatis-3%22+-migrations

위의 링크로 들어가 jar 파일을 다운받은후 추가 하자.

신세계 마이바티스를 공부해 보자. (아이바 티스를 안보신분은 먼저 그것부터 보길 바란다 ) http://sararing.springnote.com/pages/10976942

MyBatis-3-User-Guide_ko.pdf  <== 마이바 티스 한글 유저 가이드 .

 

먼저 마이바티스란. odbc 프레임웍으로 웹페이지 에서 필요한 디비를 최대한 능동적으로 (빠른 접속시간및 코드의 효율 최상화)를 위해 사용 하게 된다.

먼저 우리가 기본적으로 생성하게 되는  MemberDaoOracleMpl.java 파일을 보자

findByPk 메서드를  중심으로 설명해 보겠다.

기존의_findByPk.jpg

rs 생성후 파라미터 연결 또 보드객체 생성 받고 rs psmt conn 닫고 ./ 여기서 이러한 코드들이 거의 의미 없이 무제한 적으로 사용 하게 되는것에 의문을 가질수 있다.

실제로 쿼리 문장은 매우 규칙적이고 심플 하기 때문에 이러한 의미 없는 코딩을 줄이고 풀링및 접속 환경 까지 제어 해주는것이 마이바티스 이다.

위와 같은 코드식을

변경후의_finByPK.jpg

이렇게 만들었다.  DAO 의 인터페이스인 IMDAO를 implement 했다.  이렇든 간단하게 형식에 맞추어 구현이 가능한 것이 마이바 티스 이다.

 

사용에 먼저 가장 먼저 할일은

res.jpg res 소스 폴더를 만든다 이후에 kr.or.ddit.mybatis 패키지를 생성후 패키지의 루트에  config.xml 파일을 생성 하자.

마이바티스 기본 설정 이다.   jar 파일은 이미 추가 했다는 전제 이다. 

config.jpg

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 문을 구현 하게 된다.

memberxmlfinbypk.jpg

위 사진은 member.xml 구현부 이다. 여기서 namespace 를 DAO 에 잡으며 반드시 select 문의 id 값은 DAO 에서 구현한 메서드의 이름과 같아야 자동 매칭이 가능하다.

구문 에서 parameterType="String" resultType="member"  메서드 실행시 파라미터 의 종류로 String 과 돌려주는 값이 member 임을 알수 있다.

      여기서 member는 위에서 알리아스(애칭)을 적용 한값을 사용 함을 알수 있다.

받은 값에 대하여 마치 파라미터를 받는것과 마찬 가지로 #{mem_id}  등의 형식으로 적어  member 객체로 받아     MemberDaoMyBatis.java 에서 구현 한다.

DAOmybatis.jpg

위의 사진에서 MemberDaoMyBatis.java  의 구현 사진이다. 실질적으로 MemberServiceIMpl.java 에서는 이 명령을 구현 하게 된다 . session factory 구현에 메퍼를 사용함을

주의 깊게 보자. openSession파라미터  true commit()을 의미 하니 셀렉트 문에는 구지 안넣어도 되나 db 값이 변화 하는 경우 반드시 추가 해야만 한다. 

board구현.png

위의 사진에서 보면 실질적으로 jsp 단에서 파일을 생성 구현 하는 부분은 두 부분이다. 먼저 직접적인 생성및 사용하게 되는 BoardServiceIMple 이 있다.이곳 에서 일차 적으로 jsp 에서 사용 하게 되며

service 에서는 두가지 선택이 가능 하다. BoardDaoOracle 과 BoardDaoMybatis 이다. 기본적인 factory 단을 이용 하여 구현 하는게 훨신 간단하게 소스구현을 할수 있다는것을 알수 있다.

추가로 member의 UML 도 확인하자.

member구현.png

 

 

소스

 

 

config.xml

 

<?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>

MyBatisFactory.java

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;
    }
   
}

member.xml (member 의 매핑 파일)|| 실제 sql문 구현

<?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>

board.xml (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>

 

 

BoardDaoMyBatise.java

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();
        }
    }

}

MemberDaoMyBatis.java

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();
        }
    }

}

 

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

MVC패턴

 | JSP
2012. 5. 8. 18:16


그림 1 MVC Pattern Diagram


<그림 1>에서는 일반적인 MVC 패턴을 다이어그램으로 표현하고 있습니다.

MVC 패턴은 Model, View, Controller 세 개의 컴포넌트로 구성되는데 각 컴포넌트에서 담당하는 책임은 다음과 같습니다.


  • ViewUI 요소를 그려줍니다.
  • ControllerUI의 사용자 액션에 응답하고 데이터 흐름을 제어합니다.
  • ModelMVP 패턴의 Model과 마찬가지로 데이터와 상태를 유지하며 데이터 처리 로직을 포함합니다.


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 설계" 포스트를 참조하세요.

Trackback 0 Comment 0

MVP(Model-View-Presenter) 패턴을 적용한 GUI Architecture 설계



MVP(Model-View-Presenter) 패턴을 적용한 GUI Architecture 설계

1. MVP 패턴 소개

 

사용자 삽입 이미지

 

그림 1 MVP Pattern Diagram

MVP 패턴은 MVC(Model-View-Controller) 패턴에 기반을 둔 UI 프리젠테이션 패턴입니다.
MVP 패턴은 Model, View, View Interface, Presenter 네 개의 컴포넌트(구성요소)로 구성됩니다.
각 컴포넌트에서 담당하는 책임은 다음과 같습니다.

  • View
    View Interface의 Display 멤버(Properties, Display Methods)를 구현하여 실제적인 UI 요소를 그려줍니다.
  • View Interface
    Presenter에서 Concrete View를 직접 참조하지 않고 View Interface를 참조함으로써 Concrete View와의 커플링을 감소시키고 View의 실제 UI 요소가 어떻게 구현되는지 몰라도 데이터를 올바르게 표현할 수 있도록 합니다.
  • Presenter
    View와 Model간의 상호작용을 담당합니다. Model의 데이터를 View Interface를 통해 Concrete View에 출력(바인딩)해 주고 사용자의 이벤트를 View에서 구독하여(실제적인 이벤트 핸들러 구현) Model의 데이터를 갱신하는 역할을 수행합니다.
    Presenter를 통해 View와 Model간의 의존관계를 없앨 수 있습니다.
  • Model
    데이터와 상태를 유지하며 데이터 처리 로직을 포함합니다. 일반적으로 비즈니스 엔티티와 비즈니스 로직을 Model 컴포넌트로 간주합니다.

2. MVP 패턴 적용

위에서 소개한 MVP 패턴을 적용하여 샘플 어플리케이션을 만들어 보도록 하겠습니다.
샘플 어플리케이션의 Class Diagram은 다음과 같습니다.

 

사용자 삽입 이미지
그림 2 MVP Pattern이 적용된 샘플 어플리케이션의 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

}

표 1 DummyMember Class

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;
}

표 2 Member Class의 데이터 처리 메서드


다음으로 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;
}

표 3 IMemberView Interface

세 번째로 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
}

표 4 MemberView Form

주목할 부분은 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 적용하기

 

사용자 삽입 이미지


그림 3 MVP Pattern Diagram with C/S Application

일반적으로 비즈니스 레이어와 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; }
    }

표 5 직렬화 가능한 Member Entity

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);

표 6 MemberPresenter Class에서 Web Service 참조를 Model로 참조하기

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
}

표 7  DummyView Class

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);           

        }


    }
}

표 8 IMemberView와 MemberPresenter 단위 테스트 코드

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에서 컴파일된 어셈블리를 로드하여 테스트를 수행하면 다음과 같이 테스트가 통과한 것을 볼 수 있습니다.
 

사용자 삽입 이미지


그림 4 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

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

Login&Logout 기본패턴

 | JSP
2012. 5. 8. 18:16

index.jsp

<?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>

top.jsp(include)

<%@ 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>

login.jsp

<?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>

loginchecked.jsp

<?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>

 

 

 

 

 

logout.jsp

<?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>

 

 

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

log4j

 | JSP
2012. 5. 8. 18:16

첨부파일 : 압축해제후 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"
 import="org.apache.log4j.Logger" %>

<%!
 static Logger logger = Logger.getLogger("test.jsp");
%>

<%
logger.fatal("fatal!!");

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.*;
import javax.servlet.http.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class TestServlet extends HttpServlet {


    static Logger logger = Logger.getLogger(TestServlet.class);


    public void init(ServletConfig config) throws ServletException {
         super.init(config);
    }


    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

         try {
              ...
   
              logger.info("Hellow World~");

              ...

          } catch (Exception e) {
              logger.error("Error at TestServlet", e);
          }
     }
}



VII. LOG4J 설정


log4j 설정은 프로그램 내에서 할 수 있지만 설정파일을 사용함으로서 좀더 유연하게 log4j환경을 만들 수 있습니다.


프로그램에서 설정

<%@ page contentType="text/html;charset=MS949"
 import="org.apache.log4j.*,java.io.* "
%>

<%!
 static Logger logger = Logger.getLogger("log4j.jsp");
%>

<%
String layout = "%d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n";
String logfilename = "DailyLog.log";
String datePattern = ".yyyy-MM-dd ";

PatternLayout patternlayout = new PatternLayout(layout);
DailyRollingFileAppender appender = new DailyRollingFileAppender(patternlayout, logfilename, datePattern);
logger.addAppender(appender);
logger.setLevel(Level.INFO);
logger.fatal("fatal!!");
%>


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

=============================================

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

JSTL- 사용 하기

 | JSP
2012. 5. 8. 18:15

<%@ 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 값을 지정 하여 사용 할수 있다.

 

jstl_변경전(1).jpg

 

이러한 포문을

 

jstl_변경후(1).jpg

변경 되었다 request.setAttribute 에 list 를 "dragon" 이라는 key 값으로 주며

그것을 forEach 문에서 Items 로 사용함을 확인 하자.  <%%> 의 사용을 최대한 줄이자.

 

한가지 더

jstl_변경전_2(1).jpg

 

하단의 페이지 구문 이다. <%%> d이러한 것을 없에자.

request.setAttrivute 로 값을 셋팅 하고 있다.

jstl_변경후2_1(1).jpg

jstl_변경후2_2(1).jpg

이렇듯 바뀌었다. !!

 

참고로 주석은 되도록 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" />추가.jpg
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>

 

 

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

JSTL

 | JSP
2012. 5. 8. 18:15
하단 메뉴의 http://sararing.springnote.com/pages/11288712 사용 하기 를 반드시 읽을것

<%@ 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>

 

 

 

JSTL 기초, Part 1: Expression Language (한글)

JSP 애플리케이션용 MA 단순화하기

Mark A. Kolb, 소프트웨어 엔지니어

요약:  JSP Standard Tag Library (JSTL)은 일반적인 웹 애플리케이션 기능(반복(iteration)과 조건, 데이터 관리 포맷, XML 조작, 데이터베이스 액세스)을 구현하는 커스텀 태그 라이브러리 모음이다. 소프트웨어 엔지니어인 Mark Kolb은 JSTL 태그의 사용방법을 설명한다. 표현층(presentation layer)에서 소스 코드를 제거하여 소프트웨어 관리를 단순화시키는 방법도 설명한다. 이외에도 JSTL의 단순화된 Expression Language에 대한 설명도 포함되어 있다.

 

원문 게재일:  2003 년 11 월 18 일 (출판일: 2003 년 2 월 11 일)
난이도:  초급
페이지뷰:  19026 회
의견:   0 (보기 | 의견 추가 - 로그인)

평균 평가 등급 4 개 총 32표 평균 평가 등급 (32 투표수)
아티클 순위

 

 

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 작성자들이 스크립팅 엘리먼트에 대한 필요를 줄이고 관련된 관리 비용을 피할 수 있도록 한다.

이 기사의 다른 시리즈

Part 2, "core 분석" (2003년 3월)
Part 3, "보여지는 것도 중요하다!" (2007년 3월)
Part 4, "SQL과 XML 콘텐트에 액세스 하기" (2007년 4월)

JSTL 1.0

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 이상 스팩을 지원하는 모든 애플리케이션 서버에 통합될 수 있다.

Expression language

JSP 1.2에서 JSP 액션의 애트리뷰트는 정적 캐릭터 스트링이나 익스프레션을 사용하여 지정된다. 예를 들어 Listing 2의 경우 정적 값들은 <jsp:setProperty> 액션의 nameproperty 애트리뷰트를 위해 지정된다. 반면 익스프레션은 이것의 값 애트리뷰트를 지정하는데 사용된다. 이 액션은 요청 매개변수의 현재 값을 이름이 붙여진 빈 속성으로 할당하는 효과를 갖고 있다. 이러한 방식으로 사용된 익스프레션은 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}"/>

 

범위 변수(Scoped variables)

<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 라이브러리에서 정의된 많은 커스텀 태그들은 스스로 범위 변수로서 애트리뷰트 값을 설정할 수 있다.

내장 객체(Implicit objects)

11 개의 EL 내장 객체용 식별자는 표 1과 같다. JSP 내장 객체와 혼동하지 말것!

표 1. EL 내장 객체

 

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 전개 디스크립터 파일을 통해 정의된다.

접근자(Accessors)

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" 키와 관련된 값을 반입하는데 사용될 수 있는것과 같은 이치이다.

연산자(Operators)

식별자와 접근자를 사용하여 EL은 애플리케이션 데이터(범위 변수를 통해 노출) 또는 환경 관련 정보(EL 내장 객체를 통해 노출)를 포함하고 있는 객체 계층을 트래버스 할 수 있다. 그와 같은 데이터에 간단히 접근하는 것은 많은 JSP 애플리케이션에 필요한 표현 로직을 구현하는데 종종 부적합하다.

EL에는 EL 익스프레션으로 접근된 데이터를 조작 및 비교할 여러 연산자를 포함하고 있다. 이러한 연산자들을 표 2에 요약했다.

표 2. EL 연산자

 

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

리터럴(Literals)

숫자, 캐릭터 스트링, 부울, null은 EL 익스프레션에서 리터럴 값으로 지정될 수 있다. 캐릭터 스트링은 싱글 쿼트 또는 더블 쿼트로 범위가 지정된다. 부울 값은 truefalse로 계산된다.

Taglib 지시문

앞서 언급했지만 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 애트리뷰트는 변수가 될 값을 지정한다. 지정된 변수가 이미 존재하면 지시된 값으로 할당된다. 그렇지 않다면 새로운 범위 변수가 만들어지고 그 값으로 초기화된다.


Listing 9. <c:set> 액션 신택스

<c:set var="name" scope="scope" value="expression"/>

 

scope 애트리뷰트는 선택적이며 page로 기본 설정되어 있다.

<c:set>의 두 예제는 Lisitng 10에 설명되어 있다. 첫 번째 예제에서 세션 범위 변수는 String 값으로 설정된다. 두 번째에서는 익스프레션은 숫자 값을 설정하는데 사용된다. square라는 페이지 범위 변수는 x 라는 요청 매개변수 값을 배가시킨 결과로 할당된다.


Listing 10. <c:set> 액션 예제

<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).


Listing 12. <c:remove> 액션 예제

<c:remove var="timezone" scope="session"/>

 

아웃풋

<c:set> 액션은 익스프레션의 결과가 범위 변수로 할당될 수 있도록 하는 반면 개발자들은 익스프레션 값을 저장하는 대신 간단히 디스플레이하기를 원한다. 이는 JSTL의 <c:out> 커스텀 태그의 몫이다. (Listing 13). 이 태그는 value 애트리뷰트에서 지정된 익스프레션을 계산한다. 그런다음 결과를 프린트한다. 선택적 default 애트리뷰트가 지정되면 value 애트리뷰트의 익스프레션이 null 또는 비어있는 String으로 계산될 때 <c:out> 액션은 값을 프린트한다.


Listing 13. <c:out> 액션 신택스

<c:out value="expression" default="expression" escapeXml="boolean"/>

 

escapeXml 애트리뷰트 또한 선택사항이다. "<", ">", "&" 같은 캐릭터가 <c:out> 태그에 의해 아웃풋 될 때 종료되는지의 여부를 제어한다. escapeXml이 true로 설정되어 있다면 이 캐릭터들은 상응하는 XML 인터티(<, >, &)로 바뀐다.

예를 들어, user라는 세션 범위 변수가 있다고 가정해보자. 이것은 사용자에 대한 usernamecompany라는 두 개의 속성들을 정의하는 클래스의 인스턴스이다. 이 객체는 사용자가 사이트에 접근할 때마다 세션에 할당된다. 하지만 이 두 개의 속성들은 사용자가 실제로 로그인하기 전까지 설정되지 않는다. (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라는 것은 놀라운 일이 아니다.


Listing 15. <c:out> 액션 예제)

<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 애트리뷰트를 계산한 결과를 아웃풋한다.

 

참고자료

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

JSP 에러코드 모음

 | JSP
2012. 5. 8. 18:15

 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

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

include

 | JSP
2012. 5. 8. 18:15

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="파일경로" -->

 

사용방법 1 :프로그램적 사용.

인크루드대상파일.jpg

 

이렇게 파일을 생성 // list 메서드. 변수 등의 자주 사용 하는 것을 파일로 생성 한다. 첫단에 붙일 경우 prelude ,마지막 단에 붙일 경우 coda 로 사용 하면 됨.

web.xml 파일의 수정

webxml_추가.jpg

이렇듯 web.xml 에 추가 시키면 메서드 이름및 변수 이름을 직접 사용 바로 사용 하여 사용가능 하다.

바로사용.jpg

 

사용방법2:디자인적 사용(자주사용 하는 부분 메뉴&보조메뉴&FOOTER)

먼저 top.jsp 를 생성. 

top.jpg

이후 ./ 메인jsp 에 인크루드 하여야 한다.

메인안의top.jpg

여기서 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"); %> 를 해줘야 한다.

 

 

 

 

이 글은 스프링노트에서 작성되었습니다.

'JSP' 카테고리의 다른 글

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
Posted by 사라링

BLOG main image
.. by 사라링

카테고리

사라링님의 노트 (301)
JSP (31)
J-Query (41)
JAVA (24)
VM-WARE (0)
디자인패턴 (1)
스크랩 (0)
스트러츠 (3)
안드로이드 (11)
오라클 (45)
우분투-오라클 (1)
이클립스메뉴얼 (6)
스프링3.0 (23)
자바스크립트 (10)
HTML5.0 (17)
정보처리기사 (1)
기타(컴퓨터 관련) (1)
문제점 해결 (3)
프로젝트 (2)
AJAX (4)
하이버네이트 (3)
트러스트폼 (11)
Jeus (2)
재무관리(회계) (5)
정규식 (5)
아이바티스 (8)
취미 (2)
소프트웨어 보안 관련모음 (0)
정보보안기사 (6)
C언어 베이직 및 프로그램 (3)
보안 관련 용어 정리 (2)
넥사크로 (6)
Total :
Today : Yesterday :