레이블이 자바개발인 게시물을 표시합니다. 모든 게시물 표시
레이블이 자바개발인 게시물을 표시합니다. 모든 게시물 표시

2013년 11월 3일 일요일

스프링,아이바티스트랜잭션예제[Spring Framework3.X,Transaction,iBATIS, @Transactional]

스프링,아이바티스트랜잭션예제[Spring Framework3.X,Transaction,iBATIS, @Transactional]
 
스프링의 트랜잭션 관리 방법중 @Transactional 애노테이션을 이용하여 iBATIS와 연동하는 간단 예제이다.(오라클 emp 테이블에 Data 1건 insert..)

먼저 Spring MVC 프로젝트 하나 생성하자.
 
1. pom.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.mungchung</groupId>
 <artifactId>sample</artifactId>
 <name>abc</name>
 <packaging>war</packaging>
 <version>1.0.0-BUILD-SNAPSHOT</version>
 <properties>
  <java-version>1.6</java-version>
  <org.springframework-version>3.0.6.RELEASE</org.springframework-version>
  <org.aspectj-version>1.6.9</org.aspectj-version>
  <org.slf4j-version>1.5.10</org.slf4j-version>
 </properties>
 <dependencies>
 
  <!-- Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${org.springframework-version}</version>
   <exclusions>
    <!-- Exclude Commons Logging in favor of SLF4j -->
    <exclusion>
     <groupId>commons-logging</groupId>
     <artifactId>commons-logging</artifactId>
    </exclusion>
   </exclusions>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${org.springframework-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-tx</artifactId>
   <version>${org.springframework-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>${org.springframework-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>${org.springframework-version}</version>
  </dependency>
  <dependency>
   <groupId>org.apache.ibatis</groupId>
   <artifactId>ibatis-sqlmap</artifactId>
   <version>2.3.4.726</version>
  </dependency>
  <dependency>
   <groupId>commons-dbcp</groupId>
   <artifactId>commons-dbcp</artifactId>
   <version>1.2.2</version>
  </dependency>
  <dependency>
   <groupId>xerces</groupId>
   <artifactId>xercesImpl</artifactId>
   <version>2.9.1</version>
  </dependency>
  <dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib</artifactId>
   <version>2.2</version>
   <type>jar</type>
   <scope>compile</scope>
  </dependency>
  <!-- AspectJ -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>${org.aspectj-version}</version>
  </dependency>
  <!-- Logging -->
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>${org.slf4j-version}</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>jcl-over-slf4j</artifactId>
   <version>${org.slf4j-version}</version>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>${org.slf4j-version}</version>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.16</version>
   <exclusions>
    <exclusion>
     <groupId>javax.mail</groupId>
     <artifactId>mail</artifactId>
    </exclusion>
    <exclusion>
     <groupId>javax.jms</groupId>
     <artifactId>jms</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jdmk</groupId>
     <artifactId>jmxtools</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jmx</groupId>
     <artifactId>jmxri</artifactId>
    </exclusion>
   </exclusions>
   <scope>runtime</scope>
  </dependency>
  <!-- @Inject -->
  <dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
  </dependency>
  <!-- Servlet -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>
  <!-- Test -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>${java-version}</source>
     <target>${java-version}</target>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
     <warName>abc</warName>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
     <execution>
      <id>install</id>
      <phase>install</phase>
      <goals>
       <goal>sources</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.5</version>
    <configuration>
     <encoding>UTF-8</encoding>
    </configuration>
   </plugin>
  </plugins>
 </build>
</project>
 

2. 컨트롤러
 
package onj.edu.transaction;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HomeController {
 @Autowired
 private TransactionMain transactionMain;

 @RequestMapping(value = "/hello", method = RequestMethod.GET)
 public String home(Locale locale, Model model) {
  String msg = "";
  try {
   msg = transactionMain.insert();
  } catch (Throwable e) {
   msg = "Transaction 오류";
   e.printStackTrace();
  }
  model.addAttribute("msg", msg );
  return "onj";
 }
}
 
3. 트랜잭션 메인 클래스
 
package onj.edu.transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class TransactionMain {
 @Autowired
 private Tran1 tr1;

 @Transactional(propagation = Propagation.REQUIRED)
 public String insert() throws Throwable {
  tr1.insertTest();
 
  return "Transaction Success!!";
 }
}

4. 트랜잭션 처리 클래스(간단히 EMP 테이블에 한건 인서트)

package onj.edu.transaction;
import java.util.HashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class Tran1 {
 @Autowired
 private SqlMapClientTemplate sqlMapClientTemplate;

 @Transactional(propagation = Propagation.REQUIRED)
 public void insertTest() {
  HashMap<String, String> hashMap = new HashMap<String, String>();
  hashMap.put("empno", "101");
  hashMap.put("ename", "오엔제이");
  sqlMapClientTemplate.insert("sql.empinsert1", hashMap);
 }
}
 
5. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/spring/root-context.xml</param-value>
 </context-param>


 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <servlet>
  <servlet-name>onjServlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/spring/onjServlet-context.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>onjServlet</servlet-name>
  <url-pattern>*.html</url-pattern>
 </servlet-mapping>
</web-app>
 
6. /spring/root-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

 <tx:annotation-driven proxy-target-class="true"/>

 <context:component-scan base-package="onj.edu.transaction">
  <context:exclude-filter type="annotation" __EXPRESSION__="org.springframework.stereotype.Controller" />
 </context:component-scan>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
  destroy-method="close">
  <property name="driverClassName">
   <value>oracle.jdbc.driver.OracleDriver</value>
  </property>
  <property name="url">
   <value>jdbc:oracle:thin:@192.168.0.7:1521:onj</value>
  </property>
  <property name="username">
   <value>scott</value>
  </property>
  <property name="password">
   <value>tiger</value>
  </property>
 </bean>
   
    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation" value="classpath:/sql-map-config.xml"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>
   
    <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
        <property name="sqlMapClient" ref="sqlMapClient"/>
    </bean>
 <bean id="transactionManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
 </bean>
 <bean id="tr1" class="onj.edu.transaction.Tran1"/>
 <bean id="trMain" class="onj.edu.transaction.TransactionMain"/>
</beans>

7. /spring/onjServlet-context.xml

 <!-- Enables the Spring MVC @Controller programming model -->
 <annotation-driven/>
 <tx:annotation-driven proxy-target-class="true"/>
 <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
 <resources mapping="/resources/**" location="/resources/" />
 <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
 <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <beans:property name="prefix" value="/views/" />
  <beans:property name="suffix" value=".jsp" />
 </beans:bean>

 <context:component-scan base-package="onj.edu.transaction"/>

</beans:beans>
 
8. src/main/resources/sql-map-config.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>
    <settings useStatementNamespaces="true"/>   
    <sqlMap resource="sqlmap/sql.xml"/>
</sqlMapConfig>

9.  SLQ매퍼, src/main/resources/sqlmap/sql.xml
 
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com/DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap namespace="sql">
 <insert id="empinsert1" parameterClass="hashMap">
  INSERT INTO emp (empno, ename) VALUES (#empno#, #ename#)
 </insert>
</sqlMap>

10.마지막으로 view 역할을 하는 jsp(/views/onj.jsp)
 
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<head>
 <title>Home</title>
</head>
<body>
//트랜잭션처리결과 출력
<P> ${msg} </P>
</body>
</html>

2013년 10월 31일 목요일

[자바강좌]JAVA Method Overring(자바 메소드 재정의) 상위 클래스의 인스턴스 메소드를 새로 구현함으로써 ...

 [자바강좌]JAVA Method Overring(자바 메소드 재정의)
 
상위 클래스의 인스턴스 메소드를 새로 구현함으로써 외부에 다른 반응양식을 보일 수 있다
메쏘드 재정의를 하기위해서 메쏘드 이름, 매개변수개수, 타입, 리턴형이 같아야 한다.
객체의 타입과 관계없이 참조값(reference)이 가리키는 실제 객체 자료형의 메쏘드가 선택되어 런타입중 실행
실제 자료형에 메쏘드가 없으면 가장 가까운 상위 클래스의 메쏘드가 실행된다.
상위 클래스보다 접근 제어를 강화할 수 없다
상위 클래스에 public으로 되어있는 함수를 하위 클래스에서 private으로 할 수 없다.
 

[예제]
 
package onj;
class A1 {
 public void m(int i) {
  System.out.println("A1의  m(int)");
 }
 public void m(double f) {
  System.out.println("A1의  m(double)");
 }
}
class B1 extends A1 {
 //A1의 m(int i) 재정의
 public void m(int i) {
  System.out.println("B1의 m(int)");
 }
 //method overloading(매개변수의 개수를 변화줌)
 public void m() {
  System.out.println("B1의 m()");
 }
}
class Override {
 public static void main(String[] args) {
  A1 a = new A1();
  a.m(1); // A1의 m(int)가 호출됨
  B1 b = new B1();
  b.m(1);     // B1의 m(int)가 호출됨
  b.m(1.0);   // B1에는 m(double d)이  없다, 상위클래스 A1의 b.m(double d) 호출
  
  A1 c = new B1();
  c.m(1);   // 마지막으로 재정의된 메쏘드 B의 m(int)가 호출됨
  //c.m(); // 컴파일오류: 자료형 A1에는 메쏘드 m()이 정의되어 있지 않음.
 
 }
}
 
[결과]
 
A1의  m(int)
B1의 m(int)
A1의  m(double)
B1의 m(int)

2013년 10월 29일 화요일

Java Colection,AbstractCollection 인터페이스 1. Collection 객체의 모임이며

Java Colection,AbstractCollection 인터페이스

1. Collection
 
객체의 모임이며, 직접 구현 안하며 Set이나 List중 하나를 구현한다.
크기 정보 추출
int size()
boolean isEmpty()
검색, 비교, 복사
boolean contains(Object o)
boolean containsAll(Collection c)
Iterator iterator()
Object[] toArray() : Collection 내의 객체의 배열을 반환
Object[] toArray(Object[] a)
객체 추가, 제거
boolean add(Object o)
boolean addAll(Collection c)
boolean remove(Object o)
boolean removeAll(Collection c) : c를 모두 제거
boolean retainAll(Collection c) : c를 제외한 객체 제거
clear()
특징
구성원 객체의 수가 변경되었으면 true를 반환
허용하지 않는 메쏘드는 UnsupportedOperationException 발생
add, addAll 메쏘드는 ClassCastException 발생 가능
null을 허용하지 않을 경우 NullPointerException 발생 가능
조건에 맞지 않을 경우 IllegalArgumentException 발생 가능
 
2. AbstractCollection
 
Collection 인터페이스 구현한 추상클래스
중복 허용
실제 저장 구조와 관계된 함수는 미구현
변경 불가능한 하위 Collection 구현 시 iterator(), size() 만 구현
변경 가능한 하위 Collection 구현 시
add() 구현하지 않으면  UnsupporedOperationException 발생
String toString()은 각 구성원 객체의 toString() 값을 출력한다.
 
 
[예제]

package onj;
 
//AbstractCollection을 상속한 사용자 정의 컬렉션
import java.util.*;
public class MyCollection extends AbstractCollection {
 private int size = 0;
 private Object[] arr = new Object[10];
 public int size() {
  return size;
 }
 public boolean add(Object o) {
  arr[size++] = o;
  return true;
 }
 public Iterator iterator() {
  return new Iterator() {
   private int current = -1;
   public boolean hasNext() {
    return current + 1 < size;
   }
   public Object next() {
    current++;
    if (size <= current)
     throw new NoSuchElementException();
    return arr[current];
   }
   public void remove() {
    if (current == -1 || size <= current) throw new NoSuchElementException();
    for (int i = current + 1; i < size; i++)
     arr[i - 1] = arr[i];
    current--;
    size--;
   }
  };
 }
 public static void main(String[] args) {
  MyCollection col = new MyCollection();
  col.add("OnJ1");
  col.add("OnJ2");
  System.out.println("size(): " + col.size());
  System.out.println("contains(): " + col.contains("second"));
  System.out.println("toString(): " + col);
  System.out.print("iterator: ");
  // 반복자
  Iterator iter = col.iterator();
  while (iter.hasNext()) {
   System.out.print(iter.next() + ", ");
  }
  System.out.println();
  System.out.print("toArray(): ");
  Object[] array = col.toArray();
  for (int i = 0; i < array.length; i++)
   System.out.print(array[i] + ", ");
  System.out.println();
  col.remove("first");
  System.out.println("remove(): " + col);
  MyCollection col2 = new MyCollection();
  col2.add("OnJ3");
  col2.add("OnJ4");
  System.out.println("containsAll(): " + col.containsAll(col2));
  col.addAll(col2);
  System.out.println("addAll(): " + col);
  col.removeAll(col2);
  System.out.println("removeAll(): " + col);
  col.clear();
  System.out.println("col.size() : " + col.size());
  System.out.println("clear(): " + col);
 }
}
 

[결과]
 
size(): 2
contains(): false
toString(): [OnJ1, OnJ2]
iterator: OnJ1, OnJ2,
toArray(): OnJ1, OnJ2,
remove(): [OnJ1, OnJ2]
containsAll(): false
addAll(): [OnJ1, OnJ2, OnJ3, OnJ4]
removeAll(): [OnJ1, OnJ2]
col.size() : 0
clear(): []

2013년 10월 24일 목요일

[JAVA TIP]java.util.Arrays.sort를 이용한 배열정렬(Array Sort)

[JAVA TIP]java.util.Arrays.sort를 이용한 배열정렬(Array Sort)
 
예제를 보시면 이해가 되리라 생각 합니다.
참고하시구요, 열공 하세요.
 
//
//  @Java Tip
//  @author 오라클자바커뮤니티, 오엔제이프로그래밍
//  @Desc : java.util.Arrays 클래스의 sort메소드를 이용한 정렬
// 
package onj;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;

public class ArraySortExam {
 public static void main(String[] args) {
  String[] myArray = { "c", "a", "b" };
  // 일단 그냥 출력 해보자. c, a, b 순으로 출력
  for (String s : myArray) {
   System.out.println(s);
  }
  // Ascending Sort, 오름차순 정렬
  Arrays.sort(myArray);
  // a, b, c로 출력
  for (String s : myArray) {
   System.out.println(s);
  }
  // 이번에는 내림차순(Descending) 졍렬
  Arrays.sort(myArray, Collections.reverseOrder());
  // c, b, a로 출력
  for (String s : myArray) {
   System.out.println(s);
  } 

2013년 10월 19일 토요일

JAVA JNDI를 이용한 DNS 서비스 구현 JNDI란 자바로 만들어진 프로그램이 Naming 및 Directory 서비스에 접근할 수 있도록 제공되는 API 입니다.

JAVA JNDI를 이용한 DNS 서비스 구현

 JNDI란 자바로 만들어진 프로그램이 Naming 및 Directory 서비스에 접근할 수 있도록 제공되는 API 입니다.
 
즉 자바 응용 프로그램이 어느 위치에 있든지 필요한 자바 객체들을 검색할 수 있는 것입니다. EJB 환경에서는 JNDI를 이용해 EJB Home 객체를 얻어낸 후 이를 이용해 Java Beans 객체를 생성하거나 접근하게 됩니다.
 
JNDI는 DNS(Domain Name System), COS(Common Object Services) 등의 네이밍 서비스 표준과 LDAP(Lightweight Directory Access Protocol), NDS(NetWare Directory Service), NIS(Netware Information System) 등 API를 제공 합니다.
 
참고로 JDK1.4 부터는 JNDI 서비스 프로바이더에 DNS Service Provoder를 제공하여 DNS 서비스를 통해 네이밍 서비스를 받을 수 있도록 지원 했는데 아래는 그 예제 입니다.
 
아래예제는 www.onjprogramming.co.kr에 대한 DNS 서비스를 받아 오는 예제 입니다.
 

import java.util.Hashtable;
import javax.naming.directory.*;
import javax.naming.NamingEnumeration;
public class JNDIExample {
 public static void main(String[] args) {
  Hashtable h = new Hashtable();
  h.put("java.naming.factory.initial","com.sun.jndi.dns.DnsContextFactory");
  h.put("java.naming.provider.url","dns://ns.dacom.co.kr");
  
  try {
   //DirContext 초기화
   DirContext context = new InitialDirContext(h);
   
   //DNS질의 결과를 받아 오자...
   Attributes attribute = context.getAttributes("www.onjprogramming.co.kr");
   
   //질의 결과 출력
   NamingEnumeration ne = attribute.getAll();
   System.out.println("www.onjprogramming.co.kr --> ");
   while(ne.hasMoreElements()) {
    System.out.println(ne.next());
   }
  }
  catch(Exception e) {
   e.printStackTrace();
  }
  
 }
}
 
[결과]
java.sun.com --> 
A: 209.249.116.141

2013년 8월 8일 목요일

[프리랜서] 자바, 스프링, xplatform 중급 이상 개발자 모집

[프리랜서] 중급 이상 개발자 모집


㈜오엔제이시스템즈에서 공공기관 SI프로젝트 중급이상 개발자 모집하고 있습니다.

경력 : 중급이상(KOSA기준)

위치 : 서울 강남

투입일시 : 8월중

기간 : 7 or 8개월(연장될 수 있으니 참고하세요)

필수조건 : Xplatform

우대조건 : Proframe, 회계업무경험자

경력기술서(skill inventory)를 아래의 이메일로 보내주시면 전화드리겠습니다.

manager@onjprogramming.co.kr


역량있는 개발자분들의 많은 지원 바랍니다.