레이블이 java instance variable인 게시물을 표시합니다. 모든 게시물 표시
레이블이 java instance variable인 게시물을 표시합니다. 모든 게시물 표시

2013년 10월 11일 금요일

[야간,Spring3.x]스프링게시판,Spring DI설정을 annotation으로

스프링3.X 게시판 (DI설정을 애노테이션으로 변경), XML설정-->Annotation으로...
 
지금까지 구현한 게시판의 기본 기능은 다음과 같다.
 
스프링게시판 현재 1차 버전까지의 기능(게시판 리스트보기 + 게시물 본문내용 미리 보기 + 게시 글 상세보기 + 커멘트(댓글)기능 + 글쓰기 + 글 수정하기 + 글 삭제하기 + 답변 글)
(http://www.oraclejavanew.kr/bbs/board.php?bo_table=LecSpring&wr_id=261&page=2)
 
그리고 마지막으로 Controller를 @Controller, @RequestMapping을 이용하여 변경 하였다.
(http://www.oraclejavanew.kr/bbs/board.php?bo_table=LecSpring&wr_id=261&page=2)
 
이번 강좌에서는 이 소스를 기본으로 스프링 주입(DI)을 애노테이션으로 변경해 보자. Spring Framework XML설정 파일이 깔끔해 진다.
 
그리고 다음 강좌에서 진행될 DAO단 Spring AOP를 적용하여 로깅하기를 위해 미라 SqlProvider를 구현하자. (jdbcTemplate에서 실행 sql문을 받아 내기 위해)
 

1. BoardDAO.java
 
package onj.board.dao;
import java.util.List;
import onj.board.model.BoardDTO;
import onj.board.model.CommentDTO;
import org.springframework.dao.DataAccessException;

public interface BoardDAO {
 //게시물 리스트 보기
 public List<BoardDTO> boardList() throws DataAccessException;

 //게시물 본문 미리보기
 public String preView(String seq) throws DataAccessException;

 //게시물 본문 읽기
 public BoardDTO readContent(String seq) throws DataAccessException;

 //읽은 글의 조회수 1증가
 public int updateReadCount(String seq) throws DataAccessException;

 //Comment저장
 public int insertComment(CommentDTO commentDTO) throws DataAccessException ;

 //Comment조회
 public List<CommentDTO> commentList(String seq) throws DataAccessException;

 //게시글 입력
 public int insertBoard(BoardDTO board) throws DataAccessException;

 //글 수정
 public int updateBoard(BoardDTO board) throws DataAccessException;

 //글 삭제
 public int deleteBoard(String sid , String password) throws DataAccessException;

 //답글 달기
 public int replyBoard(BoardDTO board) throws DataAccessException;

 //SQL리턴용
 public String getSql();


 
}
 
 

2. onj.board.dao.SpringBoardDAO.java
 
package onj.board.dao;
 
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import onj.board.model.BoardDTO;
import onj.board.model.CommentDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlProvider;
import org.springframework.stereotype.Component;
 
//아래 SqlProvider는 jdbcTemplate이 실행될 때의 SQL문장을 받아내기 위하여 구현, getSql()
@Component("boardDAO")
public class SpringBoardDAO implements BoardDAO, SqlProvider {
 private JdbcTemplate jdbcTemplate = null;
 String sql = "";
 @Autowired
 private DataSource dataSource;
 
 public JdbcTemplate getTemplate() {
  if (jdbcTemplate == null) {
   this.jdbcTemplate = new JdbcTemplate(dataSource);
  }
  return jdbcTemplate;
 }
 
@Override
 public String getSql() {
  // TODO Auto-generated method stub
  return sql;
 }

 // /게시판 전체 리스트 보기(list.html)
 public List<BoardDTO> boardList() throws DataAccessException {
  List<BoardDTO> boardList = null;
  // String sql = "select * from board";
 
  sql = " select * from  (select seq, name , passwd, "
    + "                        title, content, filename, regdate, "
    + "                        readcount, reply, reply_step, "
    + "                        reply_level , rownum r "
    + "                   from board "
    + "                  order by reply desc , reply_step asc)";
  boardList = getTemplate().query(sql, new RowMapper() {
   public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
    BoardDTO board = new BoardDTO();
    board.setSeq(rs.getInt("seq"));
    board.setName(rs.getString("name"));
    board.setPasswd(rs.getString("passwd"));
    board.setTitle(rs.getString("title"));
    board.setContent(rs.getString("content"));
    board.setFileName(rs.getString("filename"));
    board.setRegDate(rs.getString("regdate"));
    board.setReadCount(rs.getInt("readcount"));
    board.setReply(rs.getInt("reply"));
    board.setReply_step(rs.getInt("reply_step"));
    board.setReply_level(rs.getInt("reply_level"));
    return board;
   }
  });
  return boardList;
 }
 // 게시물 본문내용 미리보기(/preView)
 public String preView(String seq) throws DataAccessException {
  sql = "select * from board where seq = ?";
  String preContent = (String) getTemplate().queryForObject(sql,
    new Object[] { seq }, new RowMapper() {
     public Object mapRow(ResultSet rs, int rowNum)
       throws SQLException {
      return rs.getString("content");
     }
    });
  return preContent;
 }
 // 게시판 상세보기, 게시글 읽기
 public BoardDTO readContent(String seq) throws DataAccessException {
  sql = "select * from board where seq = ?";
  BoardDTO boardDTO = (BoardDTO) getTemplate().queryForObject(sql,
    new Object[] { seq }, new RowMapper() {
     public Object mapRow(ResultSet rs, int rowNum)
       throws SQLException {
      BoardDTO board = new BoardDTO();
      board.setSeq(rs.getInt("seq"));
      board.setName(rs.getString("name"));
      board.setPasswd(rs.getString("passwd"));
      board.setTitle(rs.getString("title"));
      board.setContent(rs.getString("content"));
      board.setFileName(rs.getString("filename"));
      board.setRegDate(rs.getString("regdate"));
      board.setReadCount(rs.getInt("readcount"));
      board.setReply(rs.getInt("reply"));
      board.setReply_step(rs.getInt("reply_step"));
      board.setReply_level(rs.getInt("reply_level"));
      return board;
     }
    });
  // 글 조회수 1증가
  this.updateReadCount(new Integer(boardDTO.getSeq()).toString());
  return boardDTO;
 }
 // 읽은 글의 조회수를 1증가
 public int updateReadCount(String seq) throws DataAccessException {
  sql = "update board set readcount = nvl(readcount,0) + 1 where seq = ?";
  Object[] obj = { seq };
  return getTemplate().update(sql, obj);
 }
 // 커맨트 입력
 public int insertComment(CommentDTO commentDTO) throws DataAccessException {
  sql = "insert into comment_t(seq, name, comm) values (?, ?, ?)";
  Object[] obj = { commentDTO.getSeq(), // 게시글순번
    commentDTO.getName(), // 작성자
    commentDTO.getComment() }; // 커맨트
  return getTemplate().update(sql, obj);
 }
 // 커맨트 조회
 public List<CommentDTO> commentList(String seq) throws DataAccessException {
  sql = "select * from comment_t where seq = ?";
  List<CommentDTO> commentList = getTemplate().query(sql,
    new Object[] { seq }, new RowMapper() {
     public Object mapRow(ResultSet rs, int rowNum)
       throws SQLException {
      CommentDTO commentDTO = new CommentDTO();
      commentDTO.setName(rs.getString("name"));
      commentDTO.setComment(rs.getString("comm"));
      return commentDTO;
     }
    });
  return commentList;
 }
 // 글쓰기
 public int insertBoard(BoardDTO board) throws DataAccessException {
  sql = "insert into board values(board_seq.nextval , ? , ? , ? , ? , ? , sysdate , 0 , board_seq.currval , 0 , 0)";
  if (board.getFileName() == null) {
   Object[] obj = { board.getName(), board.getPasswd(),
     board.getTitle(), board.getContent(), "" };
   return getTemplate().update(sql, obj);
  } else {
   Object[] obj = { board.getName(), board.getPasswd(),
     board.getTitle(), board.getContent(), board.getFileName() };
   return getTemplate().update(sql, obj);
  }
 }
 // 게시글 수정
 public int updateBoard(BoardDTO board) throws DataAccessException {
  sql = "update board set  title = ? , content = ? where seq = ?";
  Object[] obj = { board.getTitle(), board.getContent(), board.getSeq() };
  return getTemplate().update(sql, obj);
 }
 // 게시글 삭제
 public int deleteBoard(String seq, String passwd)
   throws DataAccessException {
  int result = 0;
  String sql = "delete from board where seq = ? and passwd = ?";
  result = getTemplate().update(sql, new Object[] { seq, passwd });
  return result;
 }
 // 답글달기
 public int replyBoard(BoardDTO boardDTO) throws DataAccessException {
  int result = 0;
  String name = boardDTO.getName();
  String passwd = boardDTO.getPasswd();
  String title = boardDTO.getTitle();
  String content = boardDTO.getContent();
  String fileName = boardDTO.getFileName();
  int reply = boardDTO.getReply();
  int reply_step = boardDTO.getReply_step();
  int reply_level = boardDTO.getReply_level();
  // 현재 답변을 단 게시물 보다 더 높은 스텝의 게시물이 있다면 스텝을 하나씩 상승시킴
  sql = "update board set reply_step = reply_step + 1 "
    + "where reply = " + reply + " and reply_step > " + reply_step;
  getTemplate().update(sql);
  sql = "insert into board values(board_seq.nextval , ? , ? , ? , ? , ? , sysdate , 0 , ? , ? , ?)";
  // reply_step과 reply_level을 1씩 증가시킨 후 내용을 저장
  Object[] obj2 = { name, passwd, title, content, fileName, reply,
    reply_step + 1, reply_level + 1 };
  result = getTemplate().update(sql, obj2);
  return 0;
 }
}
 

3. BoardServiceImpl.java
 
package onj.board.service;
 
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import onj.board.dao.BoardDAO;
import onj.board.model.BoardDTO;
import onj.board.model.CommentDTO;
 
@Component("boardService")
public class BoardServiceImpl implements BoardService {
    @Autowired
    private BoardDAO boardDAO;

   
    //게시물 리스트 보기
    public List<BoardDTO> boardList() {
     return boardDAO.boardList();
    }
   
    //게시물 본문 내용 미리보기
    public String preView(String seq) {
     return boardDAO.preView(seq);
    }
    //게시글 읽기
 public BoardDTO readContent(String seq) {
  return boardDAO.readContent(seq);
 }
 //커맨트 입력
 public int insertComment(CommentDTO commentDTO) {
  return boardDAO.insertComment(commentDTO);
 }
 //커맨트 조회
 public List<CommentDTO> commentList(String seq) {
  return boardDAO.commentList(seq);
 }   

 //게시글 입력
 public int insertBoard(BoardDTO board) {
  return boardDAO.insertBoard(board);
 }

 //게시글 수정
 public int updateBoard(BoardDTO board) {
  return boardDAO.updateBoard(board);
 }

 //게시글 삭제
 public int deleteBoard(String seq, String passwd) {
  return boardDAO.deleteBoard(seq, passwd);
 }

 //답글 등록
 public int replyBoard(BoardDTO board){
  return boardDAO.replyBoard(board);
 }

}
 
 

4. /WEB-INF/boardConfig.xml
 <aop:aspectj-autoproxy/>
 <context:component-scan base-package="onj.board.dao"/>
 <context:component-scan base-package="onj.board.service"/> 

</beans> 

2013년 8월 8일 목요일

오라클자바커뮤니티 강좌, jQuery를 입력 양식 이벤트 change 이론및 실습입니다.

오라클자바커뮤니티 강좌, jQuery를 입력 양식 이벤트 change 이론및 실습입니다.


오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  



change : 상태가 변경 될 때 이벤트 발생

<html>
<head>
<meta charset="utf-8"/>
<script src="/ajaxjquery/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
 $(document).ready(function() {
  //ALL 체크박스가 변동되면,
  $("#mychk").change(function() {
   if (this.checked) {
    //check_item아래 전체 체크박스를 true
    $("#check_item").children().attr("checked",true);   
   } else {
    $("#check_item").children().attr("checked",false);
   }
  });
 });
</script>
<body>   
 <form id="myform">
  <input type="checkbox" id="mychk"/>
  <label>ALL</label><!-- 여기 체크하면 아래전무 체크되거나 해제됨 -->
  <div id="check_item">
   <input type="checkbox"/>
   <label>A</label>
   <input type="checkbox"/>
   <label>B</label>
   <input type="checkbox"/>
   <label>C</label>
  </div>
 </form>
</body>
</html>

 

[오라클자바커뮤니티, ORACLEJAVANEW.KRstruts file upload DynaValidatorForm

Struts  ActionForm에서 구현한 형태입니다. 


오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  


이번엔 DynaValidatorForm에서 구현한 형태입니다.


======================================================================
============== struts-config.xml ============================================================================================================



name="applicationForm"
type="org.apache.struts.validator.DynaValidatorForm">


name="file"
type="org.apache.struts.upload.FormFile"/>


=============================================================================================== file_upload.jsp ==============================
======================================================================






======================================================================
======================= FileUploadAction ==============================
======================================================================

action class (though it's not getting this far using IE):
FormFile file= (FormFile)dForm.get("file");

2013년 8월 6일 화요일

[오라클자바닷넷교육강좌]웹애플리케이션에서의 로깅 , Web Application Logging

웹애플리케이션에서의 로깅 

오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  



로그를 남겨 프로그램을 디버깅 하는 일은 대단히 중요한 일입니다. 웹 애플리케이션에서의 로깅은 크게 시스템 로깅과 애플리케이션 로깅으로 나누어 볼 수 있는데 시스템 로깅은 사용자의 데이터 보다 애플리케이션의 내부적인 동작에 대한 기록 입니다. 예를 들면 컨테이너가 시작했을 때의 시스템적인 오류 정보 등을 기록하는 것들이 해당 되며 애플리케이션의 로그는 사용자가 로그인을 하는 경우 인증을 한 정보 등을 기록하는 것이 해당 됩니다.

시스템의 오류는 error로 표현되는 반면에 애플리케이션의 에러는 info로 정의가 가능합니다.

--------------------------------------
서블릿 컨테이너를 이용한 로깅
--------------------------------------

서블릿의 스펙에서 개발자들이 컨테이너의 로그 파일에 이벤트 정보를 로깅 할 수 있도록 지원 합니다. 로그파일의 이름이나 위치는 어떤 컨테이너를 사용 하느냐에 따라 다르지만 기록이 된다는 것은 사실 입니다.

java.servlet.ServletContext는 로그를 남기기 위한 두개의 메소드를 제공 합니다.

ppublic void log(Stirng msg);
public void log(String msg, Throwable throwable);

아래는 이 메소드를 Struts의 Action에서 사용 한 예입니다.

[이전의 DB를 이용한 인증 예제의 LoginAction 입니다.]

//로그를 남기자.
                StringBuffer buf = new StringBuffer("LoginAction : User --> ");
                buf.append(id + " logged in session");
                servlet.log(buf.toString());

위의 소스 코딩에 위해 Tomcat의 Console창에 다음과 같은 기록이 남습니다…

정보: action: LoginAction : User --> jcleelogged in session



------------------------
필터사용
-----------------------

필터는 서블릿2.3에 새로 추가된 기능 입니다. 서블릿의 필터를 이용하면 HTTP요청과 응답객체의 Contents를 검사 할 수 있으며 정적인 Contents뿐 아니라 동적인 Contents에 대해서도 필터기능을 이용하는 것이 가능 합니다.

필터링 기능을 이용하여 아래와 같은 일들이 가능 합니다.

- 클라이언트의 요청이 도달하기 전에 웹 리소스에 대해 접근 가능 합니다.
- 클라이언트의 요청이 리소스에 도달하기 전 요청을 처리 할 수 있습니다.
- 요청헤더나 데이터에 대한 수정이 가능
- 응답헤더나 데이터에 대한 수정 가능
- 어떤 리소스를 수행 한 후 리소스에 대한 메소드 호출을 가로챌 수 있습니다.

이 필터 기능을 로깅만을 위해 쓰기에는 아까운 면도 있지만 시스템에서 사용자의 행위를 추적하기에는 적합한 기술 입니다. 필터를 이용해 암호화, URL 및 기타정보에 대한 캐시, 인증,XML Contents를 변환하기 위한 XSLT 변환 등 다양한 일들을 할 수 있습니다.

필터를 생성 하기 위해서는 세 단계를 거쳐야 합니다.

1.        javax.servlt.Filter 인터페이스를 구현하는 자바 클래스를 만듭니다.
2.        web.xml에 filter 요소를 선언 합니다.
3.        웹애플리케이션의 리소스와 함께 filter class를 packaging 합니다.

Javax.servlet.Filter 인터페이스를 구현하는 클래스에서 반드시 구현해야 하는 세가지 메소드는 다음과 같습니다.

public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
public void destroy( );

[필터 예]


import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletContext;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;

public class LoggingFilter implements Filter{
        public final static String LOG_FILE_PARAM = "Login.log";
        private FilterConfig filterConfig = null;
        private ServletContext servletContext = null;

        public void init( FilterConfig config ) throws        ServletException {
                // Initialize any neccessary resources here
                this.filterConfig = config;
                this.servletContext = config.getServletContext( );

                // You can get access to initialization parameters from        web.xml
                // although this example doesn't really use it
                String logFileName = config.getInitParameter( LOG_FILE_PARAM );

                // You can log messages to the servlet log like this
                log( "Logging to file " + logFileName );

                // Maybe initialize a third-party logging framework        like log4j
        }

        public void doFilter( ServletRequest request,ServletResponse response,FilterChain filterChain )       
                              throws IOException, ServletException {
                // Log a message here using the request data
                log( "doFilter called on LoggingFilter" );

                // All request and response headers are available to the filter
                log( "Request received from " +        request.getRemoteHost( ) );

                // Call the next filter in the chain
                filterChain.doFilter( request, response );
        }

        public void destroy( ){
                // Remove any resources to the logging framework here
                log( "LoggingFilter destroyed" );
        }

        protected void log( String message ) {
                getServletContext( ).log("LoggingFilter: " + message );
        }

        protected ServletContext getServletContext( ){
                return this.servletContext;
        }
}


[web.xml]

<filter>
                <filter-name>MyLoggingFilter</filter-name>
                <filter-class>LoggingFilter</filter-class>
                <init-param>
                        <param-name>log_file_name</param-name>
                        <param-value>log.out</param-value>
                </init-param>
        </filter>

        <filter-mapping>
                <filter-name>MyLoggingFilter</filter-name>
                <servlet-name>MyExampleServlet</servlet-name>
        </filter-mapping>

        <filter-mapping>
                <filter-name>MyLoggingFilter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>



다음은 필터 기능을 이용하여 스트럿츠에서 한글 문제를 해결 한 경우 입니다.

[SetCharacterEncodingFilter.java]

package filters;


import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;



public class SetCharacterEncodingFilter implements Filter {

    protected String encoding = null;

    protected FilterConfig filterConfig = null;


    /**
    * Should a character encoding specified by the client be ignored?
    */
    protected boolean ignore = true;


    public void destroy() {

        this.encoding = null;
        this.filterConfig = null;

    }


    public void doFilter(ServletRequest request, ServletResponse response,
                        FilterChain chain)
        throws IOException, ServletException {

        // Conditionally select and set the character encoding to be used
        if (ignore || (request.getCharacterEncoding() == null)) {
            String encoding = selectEncoding(request);
            if (encoding != null)
                request.setCharacterEncoding(encoding);
        }

        // Pass control on to the next filter
        chain.doFilter(request, response);

    }

    public void init(FilterConfig filterConfig) throws ServletException {

        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("ignore");
        if (value == null)
            this.ignore = true;
        else if (value.equalsIgnoreCase("true"))
            this.ignore = true;
        else if (value.equalsIgnoreCase("yes"))
            this.ignore = true;
        else
            this.ignore = false;

    }


    protected String selectEncoding(ServletRequest request) {

        return (this.encoding);

    }
}


[web.xml]

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>

<!-- Example filter to set character encoding on each request -->
<filter>
 <filter-name>Set Character Encoding</filter-name>
 <filter-class>filters.SetCharacterEncodingFilter</filter-class>
 <init-param>
  <param-name>encoding</param-name>
  <param-value>EUC-KR</param-value>
 </init-param>
</filter>

<!-- Define filter mappings for the defined filters -->
<filter-mapping>
 <filter-name>Set Character Encoding</filter-name>
 <servlet-name>action</servlet-name>
</filter-mapping>

    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
       
        <init-param>
            <param-name>config</param-name>
            <param-value>/WEB-INF/struts-config.xml</param-value>
        </init-param>
        <init-param>
            <param-name>debug</param-name>
            <param-value>3</param-value>
        </init-param>
        <init-param>
            <param-name>detail</param-name>
            <param-value>3</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
   
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
 
</web-app> 

2013년 8월 5일 월요일

(Struts Login Exam)스트럿츠 를 이용한 간단한 로그인 예제

Struts를 이용한 간단한 로그인 예제


오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의) 




이번엔 웹 개발의 전형적인 예로써 사용자의 ID와 Password를 입력 받아 이를 인증 후 결과 페이지로 Forward 시키는 것을 Struts Framework을 이용하여 만들어 보겠습니다.

구성요소들은  다음과 같습니다.

1.        로그인  HTML 페이지
2.        Controller&Model 역할을 하는 LoginAction
3.        ActionForm, 폼빈 역할을 하는 LoginForm
4.        로그인이 성공 이었을 때 분기하는 success.html
5.        로그인이 실패했을 경우 분기하는 fail.html

사용자는 HTML 웹페이지를 이용하여 ID/Password를 입력 후 로그인 버튼을 누릅니다. 이 요청을 Controller 와 Model의 역할을 동시에 수행 하는(이 예제에서…)LoginAction이 이를 받아 폼빈(LoginForm, 사용자가 HTML 폼에서 입력한 정보들이 들어 있다.)을 통해 사용자가 입력 한 정보를 추출 후 인증을 수행 합니다.

폼빈(LoginForm)이 존재 하므로 LoginAction에서는 요청 파라미터를 추출 하는 일은 없습니다. 최근에 발표된 RC2 버전인 경우 매번 폼빈을 생성 할 필요 없이 동적으로 파라미터를 추출 할 수 있도록 했는데 이를 동적 폼빈 이라고 하며 DynaActionForm 클래스를 이용 합니다.

주)이 예제를 이클립스에서 실행 하기 위해서 이전 강좌(Eclipse에서 Struts(HelloWorld))와 같이 struts-test 라는 Tomcat 프로젝트에서 작성을 합니다. 그리고 프로젝트에서 마우스 우측 버튼을 누른 후 속성 - Java Build Path - library - add jars를 하신 후 WEB-INF/lib 아래의 struts를 다운 받아서 푼 jar 파일들을 선택 해 주신 후 아래의 예제를 돌리셔야 합니다.

1.        로그인을 위한 login.jsp를 만듭니다. (struts-test 라는 프로젝트에서 마우스 우측버튼을 누른 후 new , file 한 후 만드세요)

<%@ page language="java" contentType="text/html;charset=euc-kr" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:form action="/login">
        ID : < html:text property="id"/><br>
        Password : <html:password property="pwd"/><br>
        <html:submit value="로긴"/>
</html:form>

2.        로그인이 성공 했을 때 분기할 페이지인 success.html을 만듭니다. (struts-test 라는 프로젝트에서 마우스 우측버튼을 누른 후 new , file 한 후 만드세요)
3.       

<html>
        <head><title>로그인 성공 화면</title></head>
        <body>
                로그인이 성공 되었습니다...
        </body>       
</html>

4.        로그인이 실패 했을 경우 분기 할 페이지인 fail.html을 만듭니다. (struts-test 라는 프로젝트에서 마우스 우측버튼을 누른 후 new , file 한 후 만드세요)

<html>
        <head><title>로그인 실패 화면</title></head>
        <body>
                로그인 실패!!
        </body>       
</html>

5.        사용자가 요청 시 넘기는 값들을 빈으로 저장 해 놓기 위해 Request Parameter와 같은 구조를 가지는 폼빈을 만듭니다. LoginForm.java (이클립스인 경우 WEB-INF/src에서 마우스 우측 버튼을 클릭 후 new, class 하신 후 만드세요)

이 클래스는 Form빈으로서 사용자가 입력 한 값을 적절한 변수(프로퍼티)로 설정 해 주는 역할을 합니다. getXXX, setXXX 메소드등을 이용하여 적절한 변수 값으로 설정 되는 것입니다.


package login;
import org.apache.struts.action.*;

public class LoginForm extends ActionForm {
        protected String id;
        protected String pwd;
       
        public String getId() {
                return id;
        }
       
        public String getPwd() {
                return pwd;
        }
       
        public void setId(String id) {
                this.id = id;
        }
       
        public void setPwd(String pwd) {
                this.pwd = pwd;
        }       
}

6.        이번에는 MVC 모델의 컨트롤러 및 모델의 역할을 동시에 수행하는 LoginAction.java 파일을 만듭니다. 아래 파일에서 AuthUser라는 모듈을 자바빈으로 빼 낸다면 이것이 모델에 해당 하게 될겁니다. 본예제에서는 편의상 컨트롤러와 모델의 기능을 통합 시켰습니다.

이 클래스는 사용자가 입력 한 파라미터(id, pwd)를 LoginForm(폼빈)으로부터 받아 이
값을 이용하여 인증을 한 후 적절한 View를 선택 하여 포워딩을 하는 것입니다.

예제의 간결함을 위해 본 예제에서는 AuthUser 메소드는 무조건 인증이 성공됨을 알
리는 true를 리턴 합니다. 이 부분을 Oracle과 같은 DB와 JDBC등을 이용한 적절한
인증을 구현 하시는 것은 여러분들의 몫으로 넘기겠습니다.


package login;

import org.apache.struts.action.*;
import javax.servlet.http.*;
import java.io.*;

public class LoginAction extends Action {
        public ActionForward execute(ActionMapping mapping, ActionForm form,
                                              HttpServletRequest req, HttpServletResponse res) {
                String id = ((LoginForm)form).getId();
                String pwd = ((LoginForm)form).getPwd();
               
                boolean isOK = authUser(id, pwd);
               
                if (isOK) {
                        return (mapping.findForward("success"));
                }
                else {
                        return (mapping.findForward("fail"));
                }               
        }
       
        public boolean authUser(String id, String pwd) {
                //이곳에서 디비에 접속해서 ID와 Password가 맞는지 확인 한다.
                //본 예제에서는 무조건 인증이 된것으로 true를 리턴 합니다
                return true;
        }
}


7.        이번에는 web.xml을 만듭니다. (WEB-INF에서 마우스 우측 버튼을 누른 후 new, file 하신 후 만드세요)

web.xml 파일에서 추가 한 내용은 URL창에 확장자가 .do인 요청이 들어 오면 ora.apache.struts.action.ActionServlet으로 요청을 보내도록 설정을 했습니다. 그런다음 스트럿츠의 설정 파일인 struts-config.xml의 위치를 알려주고 있습니다.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <display-name>Welcome to Tomcat</display-name>
  <description>
    Welcome to Tomcat
  </description>
        <!-- Struts Tag Library Descriptors -->
        <taglib>
            <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
        </taglib>   
       
        <!-- ActionServlet Congif =====================================-->
        <servlet>
                <servlet-name>action</servlet-name>
                <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
                <init-param>
                        <param-name>config</param-name>
                        <param-value>/WEB-INF/struts-config.xml</param-value>
                </init-param>
                <load-on-startup>1</load-on-startup>               
        </servlet>
       
       
        <!-- ActionServlet Mapping ====================================-->
        <servlet-mapping>
                <servlet-name>action</servlet-name>
                <url-pattern>*.do</url-pattern>
        </servlet-mapping>


</web-app>


8.        이번에는 struts 설정을 위한 struts-config.xml을 만듭니다. . (WEB-INF에서 마우스 우측 버튼을 누른 후 new, file 하신 후 만드세요)

이 파일에서는 프로그램에서 사용 할 폼빈을 LoginForm으로 설정 하고 프로그램에서 사용 할 포워딩 이름을 설정 하는데(물론 이 부분은 action 설정에서 할 수도 있지만 전역적으로 설정 하기 위해 global-forwards 로 설정을 했습니다.

그리고 실제 요청을 처리 할 action 부분을 설정 하는데 예제 에서는 URL에 “/login”이 포함되어 있는 경우에 처리하라고 지정 했는데 LoginAction이 그 일을 하는거죠… 또한 폼빈으로 LoginForm을 설정 했습니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
     
    <!-- ========== Form Bean Definitions ================================== -->
    <form-beans>
        <form-bean name="LoginForm" type="login.LoginForm">         
        </form-bean>       
    </form-beans>
   
 
    <!-- ========== Global Forward Definitions =============================== -->
    <global-forwards>
        <forward name="success" path="/success.html" />
        <forward name="fail" path="/fail.html" />
    </global-forwards>
   
    <!-- ========== Action Mapping Definitions =============================== -->
    <action-mappings>
        <action         
                path="/login"
                type="login.LoginAction"
            name="LoginForm"                       
            validate="false"
        >
        </action>       
    </action-mappings> 
</struts-config>

위에서 주석 만드실 때 주의하세요… <!—다음에 줄 두개짜립니다. “====” 만약 다음과 같이 하시면 Tomcat 시작시 오류 뜹니다.<!-------------- 

그리고 이클립스에서 만드시면 별도로 LoginForm.java나 LoginAction.java를 별도로 컴파일 하실 필요는 없습니다. 브라우저에서 다음과 같이 입력 하신면 로그인 화면이 나타나며 적절한 ID/PWD를 입력하시면 인증이 성공 했다는 success.html이 실행 될겁니다.

실행 후 화면을 보시면 주소창에 /login.do 라고 나타나 있을 것입니다. 이 같이 함으로써 사용자의 입장에서는 마지막 결과가 어느 페이지에서 나오는지를 알 수가 없습니다.(멋지죠^^) 당연히 직접 그 페이지로 접근 한다는 것은 불가능 합니다.

그러므로 success.jsp와 같은 결과 페이지를 만드는 사람과 Action등을 만드는 사람의 업무가 분리가 가능 하다는 이야기 입니다. 결국 이러한 장점이 MVC 모델의 장점이 되는거구요…

다음 강좌부터는 이 로그인 예제를 하나씩 기능을 추가해 가도록 하죠^^

건투를 빕니다, 오타 주의 하세요~~~

2013년 8월 2일 금요일

JAVA BufferedReader/BufferedWriter – 예제

import java.io.*;
public class BufferedWriterSample {
public static void main(String[] args) throws Exception {
File imsiFile = File.createTempFile("imsi",".tmp");
imsiFile.deleteOnExit();
FileWriter fw = new FileWriter(imsiFile);
BufferedWriter bw = new BufferedWriter(fw);
for(int i=0; i<args.length; i++) {
bw.write(args[i]);
bw.newLine();    }
bw.close();
System.out.println(imsiFile+" 에 썼습니다...");
FileReader fr = new FileReader(imsiFile);
BufferedReader br = new BufferedReader(fr);
System.out.println(imsiFile+"에서 읽습니다...");
for(String readLine;(readLine=br.readLine())!=null;) {
System.out.println(readLine);
}
br.close();
}
}

2013년 8월 1일 목요일

java.util.HashMap 클래스 – 예제

import java.util.*; 
public class HashMapTest { 
  public static void main(String args[]) { 
    Map map = new HashMap(); 
    Integer hana = new Integer(1); 
    for (int i=0, n = args.length; i<n; i++) { 
      String key = args[i]; 
      Integer freq = (Integer)map.get(key); 
      if (freq == null) { 
        freq = hana; 
      } 
    else { 
        int value = freq.intValue(); 
        freq = new Integer(value + 1); 
      } 
      map.put(key, freq); 
    } 
    System.out.println(map); 
    Map sortedMap = new TreeMap(map); 
    System.out.println(sortedMap); 
  } 


Java Collection Framework (자바 컬렉션 프레임워크)

java2에 새롭게 추가된 자료구조 클래스들의 모임
 Collection, Map, Set, List, StoredMap, StoredSet등의 6개의 인터페이스와 이동을 구성하는 클래스들로 Java Collection FrameWork을 구성한다.
 대량의 Data를 다룰때 일관된 I/F를 제공
 6개의 인터페이스와 10개의 클래스로 구성
  java.util.Collection : 순서/중복에 관계없는 객체들의 단순한 모임
  java.util.Set : 중복되지 않는 수학적인 의미의 객체모임(순서는없다), Collection을 상속
  java.util.List : 순차적 나열에 의한 순서 지정이 가능한 구조. Collection을 상속
  java.util.Map : Key와 Key에 대한 Value로 이루어진 구조
  java.util.SortedSet : 값들이 정렬된 Set, Set을 상속
  java.util.SortedMap : Key가 정열된 Map

(JAVA OBJECT Serialize,Object Serializing)자바 객체직렬화

객체는 클래스를 통해 팔요한 시기에  생성되며 프로그램이 종료하지 않더라도  소멸된다. 물론 프로그램이 종료하면 사라진다. 실행시간에 유지하고 있던 객체 내부의 정보와 객체 자신의 정보를 어디엔가 기록해 놓고 나중에 필요한 시기에 다시 볼수 있는 방법을 제공하는것이 객체직렬화 이다.
 정보를 연속된 바이트 단위로 기록하는데 이를 객체 직렬화라고 한다.
 직렬화의 과정은 인스턴스 변수의 값을 저장하는 일인데 만약 인스턴스 변수가 다른 객체를 참조하고 있는 참조형의 변수일 경우 그 변수가 가리키는 객체 또한 직렬화 되어야 한다. 이렇게 직렬화는 복잡한 Tree형태로 계속 진행된다.
 (만약 참조형 변수가 가리키는 객체가 Serializable, Externalizable을 구현 하지 않았다면 직렬화가 되지 않으므로 이경우에는 readObject 메소드및 writeObject를 적절히 프로그램 내부에 기록해 줌으로서 제한적이지만 가능한 방법을 제시한다.)
 Static 필드, transient로 명시적으로 직렬화 하지 말라고 선언된 변수등은 직렬화 되지 않는다.
 직렬화를 담당하는 클래스는 java.io.ObjectInputStream, java.io.ObjectOutputStream
 적절히 writeObject, readObejct 메소드를 구현한다.

 객체를 생성한후 그 인스턴스를 a.dat 파일에 쓰는 경우
  FileOutputStream fos = new FileOutputStream(“”a.dat);
  ObjectOutputStream oos = new ObjectOutputStream(fos);
  oos.writeObject(“MyString…”);
  oos.writeObject(new Date());
  oos.flush(); 
 복구하는 방법
  FileInputStream fis = new FileInputStream(“”a.dat);
  ObjectInputStream ois = new ObjectInputStream(fis);
  String myString = (String)ois.readObejct();
  //return형이 Object이므로 타입캐스팅이 필요
  Date d = (Date)ois.readObject();


 
// MySerializationWrite.java
import java.io.*;
public class MySerializationWrite extends MySuperClass implements Serializable {
int i;
public MySerializationWrite(int i) {
this.i = i;
j=i*2;
}
          public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("imsi.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(new MySerializationWrite(2000));
oos.close();
System.out.println("객체 쓰기 완료...");
}
}
class MySuperClass implements Serializable {
int j;
}




객체직렬화(Object Serializing) –예제(복원하기)

import java.io.*;

public class MySerializationRead implements Serializable{
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("imsi.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
MySerializationWrite m = (MySerializationWrite)ois.readObject();
ois.close();

System.out.println("읽은후 MySerializationWrite(i) :" + m.i);
System.out.println("읽은후 MySerializationWrite(j) :" + m.j);
}
}

(instance member, field, method)클래스멤버 - 인스턴스변수(필드)/인스턴스 메소드

인스턴스 필드(변수)
 static으로 선언되지 않은 모든 변수(필드)는 인스턴스필드
  public double r;
 클래스의 인스턴스와 연관, 생성된 모든 객체는 자신만의 
  복사본을 가진다.
 클래스 내부에서 이름하나만으로 지칭된다.
  public double r;
  public double area() {
      return PI * r * r;
  }
 클래스 외부에서는 클래스를 인스턴스화한 객체.변수명 형
  태로 사용한다. 인스턴스 필드(변수)의 값은 한객체를 다른
  객체와 구분한다.
  Circle c = new Circle();    c.r=2.0;
  Circle c1 = new Circle();  c1.r=5.0;


 인스턴스 메소드
 static으로 선언되지 않은 모든 메소드
  public double area();
 클래스의 인스턴스(객체)와 연관된다.
 static이든, 아니든 모든 클래스멤버 사용가능
 클래스 외부에서는 클래스를 인스턴스화한 객체.메소드명 형태로 사용한다. 
  인스턴스 필드(변수)의 값은 한객체를 다른객체와 구분한다.
  Circle c = new Circle();    c.r=2.0;
  double a = c.area(); //객체 c에는 이미 r 값이 setting됨

   


- 매개변수가 없는 c.area()가 어떤 데이터에 대해 수행될건지 어떻게 아는가? 사실 모든 인스턴스 메소드는 암시적인 this 매개변수를 가지고 실행된다. This는 메소드가 호출되는 객체(Circle)이다. This 매개변수는 항상 필요하지는 않기에 메소드 시그네쳐에 보이지 않는다.
메소드가 그자신의 필드(변수)등을 접근한다는것을 명시적으로 this를 이용하여 지정할수 있다.
  public double area() {
return Circle.PI * this.r * this.r;
  }


클래스 멤버예제(Circle1.java)
class Circle {
        //클래스 변수(필드), 상수정의
public static final double PI = 3.141592; 
//클래스 메소드
public static double radianToDegree(double rads) {
return rads * 180 / PI;
}
//인스턴스 필드(변수), 원의반지름
public double r;
//인스턴스 메소드, 원의 면적계산
public double area() {  return PI * r * r; }
//인스턴스 메소드,원주계산
public double circumference() {  return 2 * PI * r; } 
}


public class Circle1 {
  public static void main(String[] args) {
Circle c = new Circle();
c.r = 4.0;
//인스턴스 메소드 이용
System.out.println("반지름이 4인 원의 면적은 : " + c.area());
System.out.println("반지름이 4인 원의 원주는 : " + c.circumference());
        //클래스 메소드및 클래스변수(필드) 이용
System.out.println("2 * PI의 Degree는 : " +
                    Circle.radianToDegree(2.0*Circle.PI) + "도 입니다.");
}
}