기존에 Sun JDK 를 사용하려면 많이 불편했었지요. FreeBSD 에서도 OpenJDK 를 사용할 수 있습니다. 설치는 아래와 같이 간단합니다.
# pkg_add -r openjdk7
# mount -t fdescfs fdesc /dev/fd
# echo "fdesc   /dev/fd         fdescfs         rw      0       0" >> /etc/fstab
혹시라도 JAVA_HOME 을 잡아주어야 하는 상황이라면, 아래와 같이 잡아주시면 되겠습니다.
export JAVA_HOME="/usr/local/openjdk7"
이제 실행해보면:
# java -version
openjdk version "1.7.0"
OpenJDK Runtime Environment (build 1.7.0-root_2011_12_03_14_00-b00)
OpenJDK Client VM (build 21.0-b17, mixed mode)
어때요? FreeBSD 에서도 OpenJDK 덕분에 Java 환경을 쉽게 구성할 수 있어서 좋네요~


CentOS에서 JDK를 설치하려면, 내장 패키지인 OpenJDK 를 설치하면 아주 쉽게 된다. 물론 Oracle 에서 다운로드 받아서 해도 되지만, 쉬운 방법이 있으니 그냥 쉽게 하자. OpenJDK도 특별히 문제 없고, 대부분 리눅스 배포판에서도 지원하고 있으니, 맘 놓고 사용하면 될 것 같다.

  • OpenJDK 패키지 확인/설치
    # yum list all | grep jdk
    gnu-crypto-sasl-jdk1.4.i386               2.1.0-2jpp.1                base
    java-1.6.0-openjdk.i386                   1:1.6.0.0-1.16.b17.el5      updates
    java-1.6.0-openjdk-demo.i386              1:1.6.0.0-1.16.b17.el5      updates
    java-1.6.0-openjdk-devel.i386             1:1.6.0.0-1.16.b17.el5      updates
    java-1.6.0-openjdk-javadoc.i386           1:1.6.0.0-1.16.b17.el5      updates
    java-1.6.0-openjdk-src.i386               1:1.6.0.0-1.16.b17.el5      updates
    ldapjdk.i386                              4.18-2jpp.3.el5             base
    ldapjdk-javadoc.i386                      4.18-2jpp.3.el5             base
    mockobjects-alt-jdk1.4.i386               0.09-14jpp.3                base
    mockobjects-jdk1.4.i386                   0.09-14jpp.3                base
    
    # yum install java-1.6.0-openjdk java-1.6.0-openjdk-devel
    
  • Java 버전을 확인해본다.
    # javac -version
    javac 1.6.0_17
    # java -version
    java version "1.6.0_17"
    OpenJDK Runtime Environment (IcedTea6 1.7.5) (rhel-1.16.b17.el5-i386)
    OpenJDK Client VM (build 14.0-b16, mixed mode)
    

어제(2010년 1월 28일) Debian 에서 이것저것 설치/업데이트하고 재부팅을 한 뒤로 이상하게도 원격에서 톰캣으로 접속이 되지 않는 현상이 발견되었다.

netstat 로 확인을 해보면 8080이 열려있는 것도 확인할 수 있다.

w3m 으로 아래와 같이 접속을 해보니, localhost 로의 접속은 정상적으로 되는 것을 확인하였고, 공인 IP로의 접속은 실패하였다. 원격에서 telnet 으로 접속하여도 포트가 죽어있는 것처럼 접속이 되지 않았다.

도대체 이해가 안되는 현상이었다. 결국 원인을 찾긴했는데, 좀 당황스럽다. 이번 업데이트부터 IPv4,IPv6에 대한 정책이 바뀐것 같다. 원인은 IPv4와 IPv6가 동시에 설치된 경우, 일부 프로그램에서 IPv6에 우선권을 주고 IPv4는 사용하지 않는 듯 하다. 여기에서는 Java가 그렇다. 요즘 대부분의 OS가 그렇듯이 Debian 을 설치하면 IPv4 와 IPv6 프로토콜 스택이 함께 설치된다. ifconfig 를 쳐보면 아래처럼 lo 인터페이스에 IPv4, IPv6에 대한 로컬주소가 매핑되어 있는 것을 확인할 수 있다. 아직까지는 IPv4로 거의 모든 서비스를 하고 있는데, IPv6가 우선권이 있게끔 하는 것은 문제가 있지 않은가?

이것을 해결하기 위해서는 몇가지 방법이 있는데, 하나씩 알아보자.

  1. IPv6 스택 disable 시키기
    터미널에서 다음과 같이 실행하면 IPv6가 멈출 것이다. 이 설정을 /etc/sysctl.conf 에 넣어두면 재부팅되도 적용될 것이다.
    # sysctl net.ipv6.conf.all.disable_ipv6=1
    
  2. IPv6 only disable
    이번 문제의 주범으로 보이는 설정이다. 이것을 아래와 같이 0으로 변경해주면, 프로그램에서 IPv4와 IPv6를 동시에 사용한다. 프로그램이 설정값을 확인하고 IPv4를 사용할지 말지를 결정하는 것 같다.
    # sysctl net.ipv6.bindv6only=0
    
  3. tomcat 실행시 Java 옵션 변경
    /etc/init.d/tomcat6 파일을 열어서, JAVA_OPTS를 아래와 같이 변경해준다.
    JAVA_OPTS="-Djava.awt.headless=true -Xms512m -Xmx512m -Djava.net.preferIPv4Stack=true"
    

이 문제로 원인찾고 해결하는데 하루를 삽질하였군요. 혹시라도 같은 고민을 하고 있던 분들은 참고하세요.

WindowsXP 환경에서 설치하는 것으로 하였고, JDK는 1.6이 설치되어 있다고 가정합니다.
먼저 각 프로그램, 라이브러리들을 해당 사이트에서 다운로드 합니다.

  • Tomcat 6 : http://tomcat.apache.org/download-60.cgi 에서 Windows Service Installer 를 다운로드 합니다.
  • Struts 2 : http://struts.apache.org/download.cgi에서 2.0.14 버전을 다운로드 합니다.
  • iBATIS 2 : http://ibatis.apache.org/java.cgi에서 2.3.4 버전을 다운로드 합니다.
  • PostgreSQL 8.3 : http://www.postgresql.org/download/windows에서 One click installer를 다운로드 합니다.
  • PostgreSQL 8.3을 위한 JDBC 드라이버 : http://jdbc.postgresql.org/download.html에서 postgresql-8.3-605.jdbc3.jar를 다운로드 한다.

이제, Tocmat 6 와 PostgreSQL 8.3 을 설치한다. 어렵지 않게 설치가 될 것이다. Tomcat 6의 설치위치는 C:\Program Files\Apache Software Foundation\Tomcat 6.0 이며, PostgreSQL 8.3 의 설치위치는 C:\Program Files\PostgreSQL\8.3 가 될 것이다.

웹어플리케이션을 위한 디렉토리(C:\Workspace\Project)를 생성한다.
Project 디렉토리 밑에는 src, WebContent 디렉토리도 생성한다.
당연히도, WebContent 디렉토리 밑에는 WEB-INF 디렉토리도 생성한다.
최종 디렉토리,파일의 전체 모습은 다음과 같다.

C:\Workspace\Project
                    \src
                        struts.xml
                        SqlMapConfig.xml
                        SqlMap_Admin.xml
                        \com
                             \test
                                  \action
                                         ListAdmin.java
                                  \dao
                                      AdminDao.java
                                  \model
                                        Admin.java
                                  \util
                                       SqlMapLocator.java
                    \WebContent
                               helloWorld.jsp
                               \admin
                                     listAdmin.jsp
                               \WEB-INF
                                       web.xml
                                       \lib
                                           commons-logging-1.0.4.jar
                                           freemarker-2.3.8.jar
                                           ibatis-2.3.4.726.jar
                                           ognl-2.6.11.jar
                                           struts2-core-2.0.14.jar
                                           xwork-2.0.7.jar
                                       \classes
                                               struts.xml
                                               SqlMapConfig.xml
                                               SqlMap_Admin.xml
                                               \com
                                                   \test
                                                        \action
                                                               ListAdmin.class
                                                        \dao
                                                            AdminDao.class
                                                        \model
                                                              Admin.class
                                                        \util
                                                            SqlMapLocator.class

이제 다운로드한 iBATIS 와 Struts2 파일을 압축풀고, 필요한 파일을 C:\Workspace\Project\WebContent\WEB-INF\lib 에 복사한다. iBATIS 에서는 ibatis-2.3.4.726.jar 만 복사하면 되고, Struts2 에서는 commons-logging-1.0.4.jar, freemarker-2.3.8.jar, ognl-2.6.11.jar, struts2-core-2.0.14.jar, xwork-2.0.7.jar 을 복사한다. 그리고, PostgreSQL JDBC 드라이버는 C:\Program Files\Apache Software Foundation\Tomcat 6.0\lib 에 복사해둔다. 이로써 필요한 프로그램 설치는 완료되었다.

원활한 테스트를 위해서 도메인 설정을 하자. C:\WINDOWS\system32\drivers\etc\hosts 파일을 열어서 아래 내용을 추가한다. 앞으로 test.com 을 웹브라우저에 입력하며 테스트할 것이다.

127.0.0.1       test.com

Tomcat 6 의 server.xml 을 설정해보자. 이 파일은 C:\Program Files\Apache Software Foundation\Tomcat 6.0\conf 에 존재한다. 우선 67째 라인에 아래 내용을 찾아서 port를 8080에서 80으로 변경한다.

...
    <Connector port="80" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />
...

그리고, 맨 밑부분에 닫힌 Host 태그를 찾아서 그 밑에 아래와 같이 버추얼호스팅 설정을 입력한다.

...
      <!-- test.com -->
      <Host name="test.com" debug="0" appBase="" unpackWARs="true" autoDeploy="true">
        <Logger className="org.apache.catalina.logger.FileLogger" directory="logs" prefix="test.com_" suffix=".log" timestamp="true"/>
        <Context path="" docBase="C:\Wrokspace\Project\WebContent" debug="0">
          <Resources className="org.apache.naming.resources.FileDirContext" allowLinking="true" />
          <Resource name="jdbc/TestDB"
                    auth="Container"
                    type="javax.sql.DataSource"
                    driverClassName="org.postgresql.Driver"
                    loginTimeout="10"
                    maxWait="5000"
                    username="아이디"
                    password="비밀번호"
                    testOnBorrow="true"
                    url="jdbc:postgresql://127.0.0.1/디비이름" />
        </Context>
      </Host>
...

위의 내용중 아이디, 비밀번호, 디비이름은 PostgreSQL 에서 사용할 적당한 것으로 정하면 된다. 아직은 DB 생성도, 사용자 생성도 하지 않았으니 상관은 없다. 이제 C:\Wrokspace\Project\WebContent에 hellowWorld.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>Hello, World</title>
</head>
<body>
<h1>잘 보이십니까?</h1>
</body>
</html>

Tomcat6를 실행한후, 웹브라우저에서 http://test.com/ 을 입력해서 내용이 잘 보이면 성공!
이제, DB 생성, 사용자 생성, 테이블 생성을 해보겠습니다.
첫번째로 DB/사용자 생성을 합니다. 시작 → 프로그램 → PostgreSQL 8.3 → SQL Shell (psql) 메뉴를 선택하고 아래와 같이 입력합니다.

Server [localhost]:
Database [postgres]:
Port [5432]:
Username [postgres]:
postgres 사용자의 비밀번호: <설치시에 입력했던 비밀번호>
이것은 PostgreSQL의 대화식 터미널 psql 입니다. 버전: psql 8.3.8

사용법:  \copyright 저작권 정보
         \h SQL 명령어 도움말
         \? 내장 명령어 도움말
         \g 또는 명령 끝에 ; 쿼리 실행
         \q 마침

postgres=# create user garachi with password 'Rnadmsdlfndjwlsek';
CREATE ROLE
postgres=# create database garachidb with encoding='utf-8' owner garachi;
WARNING:  could not determine encoding for locale "Korean_Korea.949": codeset is
 "CP949"
상세정보:  Please report this to <pgsql-bugs@postgresql.org>.
CREATE DATABASE
postgres=# \q

아이디/비밀번호를 통해서 로그인할 수 있도록 하려면 별도로 설정을해야 합니다. C:\Program Files\PostgreSQL\8.3\data 디렉토리의 pg_hba.conf 파일을 열어서 아래와 같이 설정하고, PostgreSQL을 재시작 합니다.

host    all         all         0.0.0.0           0.0.0.0           password
local   all         postgres                                        trust
local   all         all                                             password

다시 SQL Shell (psql)을 실행하여 아래와 같이 입력하여 테스트용 테이블을 생성한다.

Server [localhost]:
Database [postgres]: <디비이름>
Port [5432]:
Username [postgres]: <아이디>
아이디 사용자의 비밀번호: <비밀번호>
이것은 PostgreSQL의 대화식 터미널 psql 입니다. 버전: psql 8.3.8

사용법:  \copyright 저작권 정보
         \h SQL 명령어 도움말
         \? 내장 명령어 도움말
         \g 또는 명령 끝에 ; 쿼리 실행
         \q 마침

garachidb=> 
CREATE TABLE tb_admin
(
  id serial NOT NULL,
  "login" character varying(20) NOT NULL,
  passwd character varying(20) NOT NULL,
  "name" character varying(20) NOT NULL,
  register_date date NOT NULL,
  login_datetime timestamp without time zone,
  status_code character varying(4),
  email character varying(40),
  mobile_phone character varying(20),
  CONSTRAINT tb_admin_pkey PRIMARY KEY (id),
  CONSTRAINT tb_admin_login_key UNIQUE (login)
)
WITH (
  OIDS=FALSE
);

insert into tb_admin(login, passwd, name, register_date, status_code, email, mobile_phone)
values('yahoo', 'yahoo123', 'YAHOO...', '2009-11-11', '0000', 'yahoo@yahoo.com', '010-1111-2222');

insert into tb_admin(login, passwd, name, register_date, status_code, email, mobile_phone)
values('google', 'google123', 'GOOGLE...', '2009-11-11', '0000', 'google@gmail.com', '010-3333-4444');

해당 웹어플리케이션에서 스트럿츠를 사용할 수 있도록 web.xml 을 아래와 같이 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>TEST</display-name>
 
  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>
      org.apache.struts2.dispatcher.FilterDispatcher
    </filter-class>
  </filter>
 
  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
 
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

struts.xml 을 아래와 같이 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
 
<struts>
  <package name="Test" extends="struts-default" namespace="/admin">
    <action name="ListAdmin" class="com.test.action.ListAdmin">
      <result name="success">/admin/listAdmin.jsp</result>
    </action>
  </package>
</struts>

이것은 웹브라우저에서 http://test.com/admin/ListAdmin.action 를 입력하면 /admin/listAdmin.jsp 를 보여주겠다는 의미를 가지고 있다.
Admin.java 를 아래와 같이 작성한다. 위에서 생성한 tb_admin 테이블에 대한 모델 클래스이다.

package com.test.model;
 
import java.util.Date;
 
public class Admin {
 private int  id;
 private String  login;
 private String  passwd;
 private String  name;
 private Date  register_date;
 private Date  login_datetime;
 private String  status_code;
 private String  email;
 private String  mobile_phone;
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getLogin() {
  return login;
 }
 public void setLogin(String login) {
  this.login = login;
 }
 public String getPasswd() {
  return passwd;
 }
 public void setPasswd(String passwd) {
  this.passwd = passwd;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public Date getRegister_date() {
  return register_date;
 }
 public void setRegister_date(Date registerDate) {
  register_date = registerDate;
 }
 public Date getLogin_datetime() {
  return login_datetime;
 }
 public void setLogin_datetime(Date loginDatetime) {
  login_datetime = loginDatetime;
 }
 public String getStatus_code() {
  return status_code;
 }
 public void setStatus_code(String statusCode) {
  status_code = statusCode;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
 public String getMobile_phone() {
  return mobile_phone;
 }
 public void setMobile_phone(String mobilePhone) {
  mobile_phone = mobilePhone;
 }
}

iBATIS는 라이브러리파일과, SqlMapConfig.xml, SqlMap.xml 로 구성이 되며, 라이브러리 파일은 위에서 lib 에 복사를 해두었다. 여기에서는 SqlMapConfig.xml 파일을 읽어서 SQL Map 을 얻어오는 클래스를 작성하게 된다.

SqlMapLocator.java 를 아래와 같이 작성한다.

package com.test.util;
 
import java.io.IOException;
import java.io.Reader;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
 
public class SqlMapLocator {
 public static SqlMapClient getMapper() {
  SqlMapClient sqlMapper;
  try {
   Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
   sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader);
   reader.close();
  }catch(IOException e) {
   // Fail fast.
   throw new RuntimeException("Something bad happend while building the SqlMapClient instance." + e, e);
  }
 
  return sqlMapper;
 }
}

SqlMapConfig.xml 을 아래와 같이 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig
 PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
 "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
 
<sqlMapConfig>
  <transactionManager type="JDBC" commitRequired="false">
    <dataSource type="JNDI">
      <property name="DataSource" value="java:/comp/env/jdbc/TestDB"/>
    </dataSource>
  </transactionManager>
  <sqlMap resource="SqlMap_Admin.xml" />
</sqlMapConfig>

그리고, SqlMap_Admin.xml 을 아래와 같이 작성한다. 테스트를 위한 tb_admin 테이블의 모든 레코드를 Select 하는 문장만 있다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
 PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
 "http://ibatis.apache.org/dtd/sql-map-2.dtd">
 
<sqlMap>
  <typeAlias alias="Admin" type="com.test.model.Admin"/>
  <select id="AdminList" resultClass="Admin">
    SELECT id, login, passwd, name, register_date, login_datetime, status_code, email, mobile_phone
    FROM tb_admin
  </select>
</sqlMap>
</xml>

AdminDao.java 를 아래와 같이 작성한다.

package com.test.dao;
 
import java.sql.SQLException;
import java.util.List;
 
import com.test.model.Admin;
import com.test.util.SqlMapLocator;
 
public class AdminDao {
 private static AdminDao singleton;
 
 private AdminDao() {}
 
 public static AdminDao getInstance() {
  if(singleton == null)
   singleton = new AdminDao();
  return singleton;
 }
 
 @SuppressWarnings("unchecked")
 public List<Admin> list() throws SQLException {
  List<Admin> list = (List<Admin>)SqlMapLocator.getMapper().queryForList("AdminList");
  return list;
 }
}

ListAdmin.java 를 아래와 같이 작성한다.

package com.test.action;
 
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
 
import com.test.dao.AdminDao;
import com.test.model.Admin;
import com.opensymphony.xwork2.ActionSupport;
 
public class ListAdmin extends ActionSupport {
 private static final long serialVersionUID = 1L;
 private String message = "Hello~!";
 private AdminDao dao;
 private List<Admin> list = new ArrayList<Admin>();
 
 public String getMessage() {
  return message;
 }
 
 public void setMessage(String message) {
  this.message = message;
 }
 
 public ListAdmin() throws IOException {
  dao = AdminDao.getInstance();
 }
 
 public String execute() throws Exception {
  list = dao.list();
  return SUCCESS;
 }
 
 public List<Admin> getList() {
  return list;
 }
 
 public void setList(List<Admin> list) {
  this.list = list;
 }
}

마지막으로, listAdmin.jsp 를 아래와 같이 작성한다.

<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!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>관리자</title>
</head>
<body>
<s:if test="list.size() <= 0"> 데이터가 없네요. ^^;</s:if>
<h1>관리자 목록</h1>
<table border="1" width="100%">
<tr>
  <th>번호</th>
  <th>아이디</th>
  <th>비밀번호</th>
  <th>이름</th>
  <th>등록일자</th>
  <th>로그인일시</th>
  <th>상태코드</th>
  <th>이메일</th>
  <th>핸드폰</th>
</tr>
<s:iterator value="list">
<tr>
  <td><s:property value="id"/></td> 
  <td><s:property value="login"/></td>
  <td><s:property value="passwd"/></td>
  <td><s:property value="name"/></td>
  <td><s:property value="register_date"/></td>
  <td><s:property value="login_datetime"/></td>
  <td><s:property value="status_code"/></td>
  <td><s:property value="email"/></td>
  <td><s:property value="mobile_phone"/></td>
</tr>
</s:iterator>
</table>
</body>
</html>

드디어 웹브라우저에서 http://test.com/admin/ListAdmin.action 을 입력하면 테이블에 입력되었던 데이터를 볼 수 있을 것이다.

+ Recent posts