Scope란?

Scope란 프로그래밍 할 때 가장 중요한 개념이라고 생각된다.

Scope란 변수 혹은 객체가 존재가능한 유효 범위를 의미한다.

이번 포스팅에서는 Spring에서의 Bean 객체의 scope에 대해 알아볼 것이다.

Bean의 범위

우선 Bean의 Scope는 bean 속성값에 따라서 다르다.

속성설명
singleton(Default) 하나의 bean 정의가 DI 컨테이너마다 하나의 객체를 유지한다.
prototype하나의 bean 정의가 다수의 객체 인스턴스 범위를 가진다.
request하나의 bean 정의가 하나의 HTTP 요청이 들어올때 생성되고 완료시 소멸된다.
session하나의 bean 정의가 HTTP session의 라이프 사이클의 범위를 가지며, ApplicationContext의 컨텍스트에서만 유효하다.
global session하나의 빈 정의가 전역적인 HTTP session의 라이프 사이클의 범위를 가진다. ApplicationContext의 컨텍스트에서만 유효하다.

이번 포스팅에서는 singleton과 prototype에 대해서만 다뤄보고자 한다.

singleton

scope 속성을 지정하지 않으면 기본적으로 singleton 범위가 적용된다.

<bean id="person" class="com.bbo.example.Person">
    <constructor-arg>
        <value>bbo</value>
    </constructor-arg>
    <constructor-arg>
        <value>23</value>
    </constructor-arg>
</bean>

아래 예제는 singleton의 범위를 가지는 person이라는 빈 객체를 가져와서 수정 전과 수정 후의 값을 비교해본다.

public static void main(String[] args) {
    AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX.xml");
 
    Person person1 = ctx.getBean("person", Person.class);
    System.out.println(person1.getName());
    System.out.println(person1.getAge());
 
    Person person2 = ctx.getBean("person", Person.class);
    person2.setName("john");
    person2.setAge(22);
 
  // TEST 부분 - person2를 수정했는데 person1이 수정이 될까? 말까?
 
  System.out.println(person1.getName());
    System.out.println(person1.getAge());
}

결론적으로는 하나의 인스턴스만 유지하기 때문에 person1과 person2는 같은 객체이기 때문에 값이 변경된다.

prototype

scope를 prototype으로 값을 지정해보자.

<bean id="person" class="com.bbo.example.Person" scope="prototype">
    <constructor-arg>
        <value>bbo</value>
    </constructor-arg>
    <constructor-arg>
        <value>23</value>
    </constructor-arg>
</bean>

결론적으로는 singleton에서의 예제와는 달리 person1과 person2는 다른 객체이기 때문에 수정이 되지 않는다.

정리

bean의 범위는 scope 속성 값에 따라 달라진다. 이번 포스팅에서는 간략하게 singleton과 prototype 만을 다루었는데, request와 session에 대해서도 다루어보길 바란다.

참고 자료

Outsider's Dev story

AOP란?

AOP는 관점 지향 프로그래밍이다. 이 관점이라는 것에 대해 설명해보겠다.

OOP는 핵심단위를 클래스로 보아 객체로써 모듈화를 시키지만, AOP는 다양한 타입 혹은 객체에 걸친 트랜젝션을 모아서 관심으로 모듈화 시킨다.

AOP를 이용하면 공통 기능과 핵심 기능을 분리하여 공통된 처리를 제거할 수 있다.

즉, AOP란 핵심 코드를 바라본다라는 패러다임으로 이해하면 될 것 같다.

AOP는 언제 사용하는가?

우선 실제 업무 처리에는 사용하는 것은 좋지 않다. 가동적이 현저히 떨어지기 때문이다.

AOP로 분리해도 되는 처리는 로그 출력이나 트랜잭션 처리 등 공통화 할 수 있는 처리에 사용된다.

AOP의 용어 정리

이름설명
관점(Aspect)여러 클래스에 걸친 관심사의 모듈이다. 즉 공통 기능으로 볼 수 있다.
조인 포인트(Join Point)프로그램이 실행되는 중의 특정 지점이다.(특정 지점은 메서드의 실행 혹은 예외처리 부분이라 생각하면 된다. 즉, 핵심 기능 하나하나를 의미한다.)
어드바이스(Advice)Aspect의 기능으로(공통 기능) 특정 조인포인트에서 관점이 취하는 행동을 나타낸다.
포인트컷(Point cut)Join Point의 부분으로 실제 Advice가 적용되는 부분이다. (Advice는 point cut의 expression과 매칭되고, point cut이 매칭한 join point에서 실행된다.)
AOP Proxy클라이언트의 요청을 받아주어 처리한다.(target에 접근하는 방법을 제어할 때 사용된다.)
WeavingAdvice를 핵심 기능(point cut)에 적용하는 행위이다.

AOP 적용 방법

AOP 적용 방법에는 Bean 파일을 이용한 방법과 어토네이션을 이용한 방법이 있다. 이번 포스팅에서는 Bean 파일을 이용한 방법을 다루겠다.

아래 예제는 LogAop라는 클래스에서 로깅을 다룬다. 우선 bean 파일에 LogAop 클래스의 객체를 생성해준다.

// applicationCTX.xml
 
<bean id="logAop" class="com.bbo.ex.LogAop" />

다음 부분은 aop를 적용한다.

pointcut 을 적용하기 위해 expression을 지정해준다. 아래 예제는 com.bbo.ex 에 있는 모든 클래스의 함수 호출에 적용하겠다라는 것을 의미한다.

만약 특정 클래스로 한정 짓고 싶다면 expression의 범위를 수정하면 된다.

// applicationCTX.xml
 
<aop:config>
    <aop:aspect id="logger" ref="logAop">
        <aop:pointcut id="publicM" expression="within(com.bbo.ex.*)"  />
 
      <!-- advice 설정 부분 -->
        <aop:around pointcut-ref="publicM" method="loggerAop" />
    </aop:aspect>
</aop:config>

위의 코드중 다음 코드는 advice와 pointcut을 연결하는 과정이다.

pointcut-ref를 이용해 pointcut으로 설정한 id를 참조하고 method 속성을 이용해 advice의 메소드를 LogAop의 loggerAop라는 함수로 지정한다.

<!-- advice 설정 부분 -->
<aop:around pointcut-ref="publicM" method="loggerAop" />

마지막으로 AOP를 적용할 클래스를 생성한다.

중요한 부분은 Advice method의 첫 파라미터는 반드시 ProceedingJoinPoint 타입이어야 한다. ProceedingJoinPoint의 proceed()를 호출하면 기반하는 메소드를 호출한다.

//LogAop.java
 
public class LogAop {
 
    public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable {
 
        try {
            Object obj = joinpoint.proceed();
            return obj;
        }
 
    }
 
}

정리

bean 파일을 이용한 AOP의 적용방법에 대해 알아보았다. 실제 적용할 때는 LogAop 클래스에 Log를 찍어볼 수 있다. 예를 들어 Person이라는 클래스를 만들고 내부적으로 멤버 함수를 호출할 때 pointcut의 expression 의 범위에 해당하는 클래스라면 AOP가 적용되어 loggerAop라는 함수를 거치게 될 것이다.

그리고 proceed() 함수 호출을 통해 기반하는 메소드가 호출될 것이다.

추가적으로 advice 타입에 대해 간략히 정리한다. 자세한 내용은 검색을 통해 알아보면 좋을 것 같다.

속성내용
aop:before메소드 실행 전(Join point 이전) advice를 실행
aop:after메소드 실행 중 exception이 발생 하여도 advice를 실행
aop:after-returning메소드가 정상적으로 실행 된 후에 advice를 실행
aop:around메서드 실행 전, 후, 예외 발생 등 모든 시점에서 advice를 실행
aop:after-throwing메소드가 실행 중 exception이 발생 시 advice 실행

참고 자료

I's Story

Outsider's Dev Story

Spring 4 입문(한빛미디어)

인프런 강좌(신입 프로그래머를 위한 자바 스프링 프레임워크 강좌)

Environment 객체란?

외부 설정 파일들을 가져와서 프로퍼티를 추가하거나 추출하는 역할을 한다.

Environment 객체를 사용하는 이유?

Environment를 이용하는 경우를 생각해보자. DB 이전을 할 경우 해당 정보는 자바 코드 상에 없을 때, 외부 파일에 정보를 담아 관리를 해야 할 경우이다.

Environment 사용 방법

ConfigurableApplicationContext 객체는 AbstractApplicationContext 클래스의 상위 클래스이다.

ConfigurableApplicationContext 객체에 GenericXmlApplicationContext() 를 생성 후 getEnvironment()로 Environment 객체를 얻어올 수 있다.

아래 예시는 resources 폴더에 user.properties 라는 파일을 읽어와 user.id와 user.pw 라는 속성 값을 출력한 결과다.

// MainClass.java
 
public class MainClass {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = new GenericXmlApplicationContext();
        ConfigurableEnvironment env = ctx.getEnvironment();
 
        MutablePropertySources propertySources = env.getPropertySources();
 
        try {
            propertySources.addLast(new ResourcePropertySource("classpath:user.properties"));
 
            System.out.println(env.getProperty("user.id"));
            System.out.println(env.getProperty("user.pw"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

'=' 를 기준으로 key, value를 구분한다. '=' 이외에도 ':'으로도 테스트를 해보니 가능함을 알 수 있다.

// user.properties
 
user.id=konan
user.pw=12345

bean 객체 생성후 Environment 값을 전달하기

ctx는 ConfigurableApplicationContext 형이고, 이는 GenericXmlApplicationContext의 상위 클래스이므로 형변환이 가능하다.

생명주기에 따라 gCtx 객체는 해당 bean 파일을 로드하고 refresh()를 해줘야 설정값이 적용된다.

// MainClass.java
 
...
 
GenericXmlApplicationContext gCtx = (GenericXmlApplicationContext) ctx;
 
gCtx.load("applicationCTX.xml");
gCtx.refresh();
 
AdminConnection adminConnection = gCtx.getBean("adminConnection", AdminConnection.class);

AdminConnection 이라는 객체를 BeanFactory로부터 가져오기 위해 다음과 같이 설정을 하여 객체를 DI Container에서 생성한다.

// applicationCTX.xml
 
<bean name="adminConnection" class="com.bbo.example.AdminConnection">
 
</bean>

이제 Environment 값을 adminConnection 객체에 전달해야 한다. AdminConnection 클래스에 EnvironmentAware 인터페이스를 추가후 setEnvironment(Environment env) 함수를 재정의한다.

흐름을 다시 생각해보면, ctx에는 기존의 Environment 객체 값을 가지고 있고 이 ctx를 GenericXmlApplicationContext 타입으로 gCtx라는 객체로 형변환하였다. gCtx로부터 BeanFactory에 대한 정보를 가지고 있는 applicationCTX.xml 를 load하여 refresh()를 호출하여 적용시켰다. 적용 후에 applicationCTX.xml 내에 adminConnection이라는 객체를 생성된다.

즉, 객체 생성시 이미 Environment에 대한 정보를 가지고 있으니 전달이 가능하다는 이론이다.

// AdminConnection.java
 
public class AdminConnection implements EnvironmentAware {
    private Environment env;
    private String adminId;
    private String adminPw;
 
    @Override
    public void setEnvironment(Environment env) {
        // TODO Auto-generated method stub
        setEnv(env);
    }
 
  public void setEnv(Environment env) {
        this.env = env;
    }
}

env로부터 값을 가져올 때는 getProperty(key)를 통해 value를 가져올 수 있다. 다음 예시는 InitializingBean을 통해 bean 객체 생성시 각 멤버변수에 대해 초기화한다.

// AdminConnection.java
 
public class AdminConnection implements EnvironmentAware, InitializingBean, DisposableBean {
    private Environment env;
    private String adminId;
    private String adminPw;
 
    @Override
    public void setEnvironment(Environment env) {
        // TODO Auto-generated method stub
        setEnv(env);
    }
 
  ...
 
  @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
        setAdminId(env.getProperty("user.id"));
        setAdminPw(env.getProperty("user.pw"));
    }
 
    @Override
    public void destroy() throws Exception {
        // TODO Auto-generated method stub
 
    }
}

정리

이번 포스팅에서는 Environment 객체가 무엇인지, 언제 사용되는지, 어떻게 사용하는지에 대해 간략하게 알아보았다.

이렇게 외부 파일을 이용한 bean 객체 설정 방법은 Environment 외에도 프로퍼티 파일을 이용한 방법과 java 코드에 어노테이션을 이용한 방법, 그리고 프로파일 속성을 이용한 설정도 있다.

관련 강의는 검색을 통해 알아보거나 추후 포스팅하도록 하겠다.

DI란 무엇인가?

DI란 말 그대로 Dependency Injection으로 의존성을 주입시킨다는 뜻이다.

의존성 주입을 설명할 가장 간단한 예를 들 수 있다. 아래와 같이 객체에서 new 연산자를 사용하여 포함시킬 수 있다.

//A객체
B b = new B();
C c = new C();

하지만 스프링에서 객체를 포함시키는 방법은 코드 내부에서가 아닌 외부에서 객체를 얻어오는 방식이다.

AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX.xml");
 
PersonService personService = ctx.getBean("personService", PersonService.class);

추후 설명하겠지만 외부 파일(xml)에서 생성된 객체를 가져오는 방식이다.

DI 방식의 이점은 무엇인가?

간단하게 말하겠다. 코드 상에서 변경이 아니므로 쉽게 설정파일만을 수정하여 부품(각 기능을 담당하는 클래스)들을 생성 및 조립이 가능하다.


DI 적용 방법

우선 세가지의 방식이 있다.

  1. 어노테이션 이용한 방식

  2. Bean 파일을 이용한 방식

  3. JavaConfig 파일을 이용한 방식


가장 많이 사용되는 2번 방식만을 이번 포스팅에서 다루려고 한다. 각 방법마다 장점과 단점이 있으니 추후 포스팅할 기회가 있다면 하겠다.

먼저 BeanFactory를 알자

DI 컨테이너의 핵심은 BeanFactory이다. BeanFactory는 실행 시 건네지는 Bean 정의 파일(기본적으로 applicationCTX.xml로 명명)을 바탕으로 인스턴스를 생성하고 인스턴스의 인젝션을 처리한다.


DI 컨테이너로부터 인스턴스를 얻는 다는 말은 BeanFactory 로부터 인스턴스를 얻는 다는 것을 의미한다.

전체 구조

예제를 위한 전체 구조는 아래 사진과 같다.


중간에 구현클래스와 인터페이스를 구분하였는데 DI를 이용할 때는 원칙적으로 인터페이스에 의존하고 구현 클래스에서는 의존하면 안된다. 이를 인터페이스 기반의 컴포넌트화라고 하는데 PersonService와 PersonDao는 인터페이스화 시키고 그 구현 클래스들은 인터페이스 클래스 이름에 Impl를 덧붙였다.

PersonDaoImpl은 PersonServiceImpl을 인젝션함을 알 수 있다. 이는 내부적으로 PersonServiceImpl가 PersonDao를 포함하고 있고, 이를 bean 파일에 정의함으로써 설정을 해야 한다.(곧 배운다.)

Bean 파일 정의

src/main/resources에서 오른쪽 마우스를 클릭하여 New -> Other 에서 Spring Bean Configuration File을 클릭하여 생성한다.(applicationCTX.xml로 생성)


bean 태그에는 여러가지가 있지만 이번 포스팅에서 사용할 주요 태그는 아래와 같다.

속성의미
id오브젝트를 유일하게 구분하는 값
name오브젝트명을 의미
classid의 실체로 패키지명 + 클래스명 으로 구성
autowireno, byName, byType, constructor 값을 통해 인젝션 방법 설정

personService 인스턴스는 내부적으로 personDao를 포함하는데 autowire 의 byType이라는 속성을 통해 프로퍼티형과 일치하는 Bean이 인젝션된다.

// applicationCTX.xml
 
<bean id="personDao" class="com.bbo.example.PersonDaoImpl"/>
 
<bean id="personService" class="com.bbo.example.PersonServiceImpl"
    autowire="byType"/>

단, 인젝션을 위해서는 personService 내에서 personDao에 대한 setter 함수가 꼭!! 필요하다.

// PersonServiceImpl.java
 
private PersonDao personDao;
 
public void setPersonDao(PersonDao personDao)
{
    this.personDao = personDao;
}

생성된 객체를 Bean 으로부터 가져오기

bean 파일에 대한 path를 통해 생성된 bean 파일에서 생성한 id를 통해 personService를 가져온다.

// PersonSampleRun.java
 
AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX.xml");
 
PersonService personService = ctx.getBean("personService", PersonService.class);

personService는 DI 컨테이너에 의해 만들어진 PersonServiceImpl 클래스이기에 멤버함수를 호출하여 사용할 수 있다.

// PersonSampleRun.java
 
Person person = new Person("bbo", 22);
 
personService.addPerson(person);
 
System.out.println(person.getName());
 
Person loaded_person = personService.findByPerson("bbo");
 
System.out.println(loaded_person.getName());

전체 소스

// Person.java
 
public class Person {
    private String name;
    private int age;
 
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}
// PersonDao.java
 
public interface PersonDao {
    public void addPerson(Person person);
    public Person findByPerson(String name);
}
// PersonDaoImpl.java
 
package com.bbo.example;
 
import java.util.HashMap;
import java.util.Map;
 
public class PersonDaoImpl implements PersonDao{
 
    private Map<String, Person> storage = new HashMap<String, Person>();
 
    @Override
    public void addPerson(Person person) {
        // TODO Auto-generated method stub
        storage.put(person.getName(), person);
    }
 
    @Override
    public Person findByPerson(String name) {
        // TODO Auto-generated method stub
        return storage.get(name);
    }
 
}
// PersonService.java
 
public interface PersonService {
    void addPerson(Person person);
    Person findByPerson(String name);
}
// PersonServiceImpl.java
 
public class PersonServiceImpl implements PersonService{
 
    private PersonDao personDao;
 
 
    public void setPersonDao(PersonDao personDao) {
        this.personDao = personDao;
    }
 
    @Override
    public void addPerson(Person person) {
        // TODO Auto-generated method stub
        personDao.addPerson(person);
    }
 
    @Override
    public Person findByPerson(String name) {
        // TODO Auto-generated method stub
        return personDao.findByPerson(name);
    }
 
}
// PersonSampleRun.java
 
package com.bbo.example;
 
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
 
import ex00.MyCalculator;
 
public class PersonSampleRun {
    public static void main(String[] args) {
        AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationCTX.xml");
 
        PersonService personService = ctx.getBean("personService", PersonService.class);
 
        Person person = new Person("bbo", 22);
 
        personService.addPerson(person);
 
        System.out.println(person.getName());
 
        Person loaded_person = personService.findByPerson("bbo");
 
        System.out.println(loaded_person.getName());
 
        ctx.close();
    }
}

정리

Bean파일을 이용한 DI 방법에 대해 알아보았다. bean 파일을 이용하여 의존성 주입하는 방법에는 setter 방식외에도 생성자를 이용한 방식도 있다.

setter 이용시에는 <property> 태그를 이용하지만 생성자를 이용한 방식에는 <constructor-arg> 태그를 이용한다. 이 방식에 대해서는 자료가 많으니 찾아보면 좋을 것 같다.

DI 가 정말 중요한 개념인만큼 프로젝트 진행시 여러 방법에 대해 탐구해보며 공부해봐야 할 것 같고 느낀점에 대해 계속 포스팅해야겠다.

참고서적

Spring 4 입문(한빛미디어)

인프런 강좌(신입 프로그래머를 위한 자바 스프링 프레임워크 강좌)

[Lint Code] Split String

문제 : 문자열이 주어졌을 때 한 개의 문자 혹은 두 개의 문자로 구성된 문자열들로 구성할 수 있는 전체 경우를 구하시오

[예시]

Input -> "123"
 
Output -> [["1", "2", "3"], ["12", "3"], ["1", "23"]]

[풀이]

이 문제는 [start:start+1]과 [start:start+2]의 경우를 DFS를 이용하여 모든 경우의 수를 탐색하여 풀면 된다.

[코드]

class Solution:
    """
    @param: : a string to be split
    @return: all possible split string array
    """
 
    def func(self, s, start, end, row, matrix):
        # 기저사례: end가 문자열 s의 길이면 matrix 배열에 추가 후 종료
        if(end == len(s)):
            matrix.append([])
            for i in range(len(row)):
                matrix[len(matrix)-1].append(row[i])
            return
 
        # end+1이 len(s) 보다 작다면 : case one character
        if end+1 <= len(s):
            # s[end:end+1]를 row에 추가후 재귀호출
            row.append(s[end:end+1])
            self.func(s, end, end+1, row, matrix)
            # s[end:end+1]에 값을 row 배열에서 pop
            row.pop(len(row)-1)
 
        # end+2이 len(s) 보다 작다면 : case two character
        if end+2 <= len(s):
            # s[end:end+2]를 row에 추가후 재귀호출
            row.append(s[end:end+2])
            self.func(s, end, end+2, row, matrix)
 
    def splitString(self, s):
        # write your code here
 
        matrix = []
 
        row = []
 
        # s의 문자열의 길이가 1개이상일 경우 s[0]번째를 row에 넣고 재귀함수 호출 시작
        if len(s) >= 1:
            row.append(s[0:1])
            self.func(s, 0, 1, row, matrix)
 
        # s의 문자열의 길이가 2개이상일 경우 s[0]과 s[1]이 합쳐진 문자열을 row에 넣고 재귀함수 호출 시작
        if len(s) >= 2:
            row = []
            row.append(s[0:2])
            self.func(s, 0, 2, row, matrix)
 
        return matrix
 


'Language > Python' 카테고리의 다른 글

리스트  (0) 2017.11.20

list 클래스

파이썬에서 연속적인 데이터를 저장하기 위해 사용하는 클래스이다.

클래스 생성 방법으로는 아래와 같다.

  1. list1 = list()

  2. list1 = []

  3. list2 = list([2,3,4,])

  4. list2 = [2,3,4]와 동일

  5. list3 = list(["red", "green", "blue"])

  6. list3 = ["red", "green", "blue"]

  7. list4 = list(range(3, 6))

  8. list5 = list("abcd")

list 슬라이싱 [start: end: step]

list 슬라이싱을 이용하여 문자열 추출을 쉽게 할 수 있다.

list1 = [4,2,9,1,32]
 
list1[1:4] // [2, 9, 1]

연결 연산자, 반복 연산자, in/not in

>>> list1 = [4,2,9,1,32]
 
>>> list2 = [3, 3]
 
>>> list1 + list2 // [4, 2, 9, 1, 32, 3, 3]
 
>>> list2 * 3 // [3, 3, 3, 3, 3, 3]
 
>>> 4 in list2 // False
 
>>> 3 not in list2 // False
 
>>> 1 in list1 // True

리스트 복사

파이썬에서 아래와 방식으로 리스트를 복사하게 되면 참조가 된다.

list1 = [1,2]
 
list2 = list1
 
list1[0] = 3
 
//list1과 list2 모두 [0] 번재 원소가 3으로 변경된다.
print(list1, list2)

따라서 리스트를 복사할 때는 아래의 2가지 방법을 이용할 수 있다.

익명 배열에다가 원소를 넣어서 대입하므로 참조가 일어나지 않는다.

list2 = [x for x in list1]
 
list2 = [] + list1

아래의 예시를 보면서 참조에 대한 이해를 해보자

def main():
    x = 1 # x는 int 변수이다.
    y = [1, 2, 3] # y는 리스트이다.
 
    m(x, y) # x, y 인자를 사용하여 m을 호출한다.
 
    print("x is", x) // 1
    print("y[0] is", y[0]) // 5555
 
def m(number, numbers):
    number = 1001
 
    numbers[0] = 5555
 
main()

number와 같은 일반 변수는 참조가 일어나지 않지만 리스트는 참조가 일어남을 확인할 수 있다.

'Language > Python' 카테고리의 다른 글

[Lint Code] Split String  (0) 2017.12.24

Atom Remote-FTP 패키지를 이용해 서버와 파일 전송하기

서버에 작업하였던 파일들을 로컬 디렉토리로 옮기고 싶을 때가 있다. 로컬에서 서버로 ssh 접속하였지만 반대로 서버측에서 로컬 컴퓨터로 접속하여 파일을 보내고 싶을 때는 로컬 컴퓨터에서 ftp 혹은 관련 프로토콜을 서비스 할 수 있어야 한다.

그런데 atom의 Remote-FTP 패키지를 이용하면 FileZila 처럼 원하는 remote path를 지정하여 파일을 가져오거나 업로딩 할 수 있다.

  1. 패키지 설치 후 프로젝트를 연다.

  2. Package -> Remote-FTP -> Toggle 을 클릭한다.

  3. Package -> Remote-FTP -> Create (s)FTP config file을 클릭하여 config file을 프로젝트에 추가한다.(.ftpignore 파일이 생성된다.)

  4. 메뉴의 connect, disconnect를 이용하여 연결 후 upload, download를 통해 파일 업로딩 및 다운로드를 할 수 있다.

.ftpignore 파일은 아래와 같이 remote path와 host, user, pass의 정보를 입력하면 된다.

{
    "protocol": "sftp",
    "host": "xxx.xxx.xxx.xxx",
    "port": 22,
    "user": "userName",
    "pass": "password",
    "promptForPass": false,
    "remote": "/var/lib/tomcat7/webapps/ROOT/file",
    "local": "",
    "agent": "",
    "privatekey": "",
    "passphrase": "",
    "hosthash": "",
    "ignorehost": true,
    "connTimeout": 10000,
    "keepalive": 10000,
    "keyboardInteractive": false,
    "keyboardInteractiveForPass": false,
    "remoteCommand": "",
    "remoteShell": "",
    "watch": [],
    "watchTimeout": 500
}
 


'IT > BackEnd' 카테고리의 다른 글

Mysql UDF 작성  (0) 2019.03.20
Crawling을 위한 Selenium, Chrome Driver 설치  (0) 2018.07.15
SSL 인증서 발급 및 Nginx 적용. 그리고 체인 이슈 해결하기  (1) 2018.02.28
JWT  (0) 2017.09.27

+ Recent posts