반응형

JSON 형식으로 서버에 로그를 남기고 있습니다. 

그런데 객체를 통으로 JSON으로 변환하다 보니 원하지 않거나 혹은 데이터를 변형해서 남기고 싶을 때가 있습니다.

여러가지 방법이 있지만 자유도 측면에서 custom filter 를 애용합니다.

 

아래 예제코드를 참조하시면 입맛에 맛게 마음대로 JSON 변환을 제어할 수 있습니다.

 

예제 코드

 

* FormatUtil.getSecurity 는 Masking 처리해주는 함수 입니다.

 

결과

 

 

반응형

'java' 카테고리의 다른 글

maven cache clear. 메이븐 캐시 클리어.  (0) 2018.07.31
spring boot 2.0 default connection pool  (2) 2018.07.25
fasterxml json parsing uppsercase  (0) 2018.07.24
spring resttemplate httpclient connection pool  (0) 2018.07.24
spring boot multi db and jndi in mybatis  (0) 2018.07.13
JNDI TEST  (0) 2018.07.09
fasterxml json camelcase  (2) 2018.06.18
spring jdbc sample  (0) 2018.06.04
반응형
Create Global Temporary Table 임시테이블명 (
  임시컬ㄹ럼 VARCHAR(100)
)
ON COMMIT PRESERVE ROWS; -- 세션 동안 데이터 살아있음
-- ON COMMIT DELETE ROWS; -- 트랜잭션 동안 데이터 살아있음. COMMIT과 동시에 지워짐.



오라클 임시 테이블 만드는 방법입니다.


저는 임시 테이블이라 테이블 자체가 사라질 줄 알았는데,  데이터만 사라지더군요. @@

반응형
반응형

jquery 를 이용해 ajax 통신할 때 다른 서버 URL 인 경우 IE 에서만 no transport 오류가 발생합니다.

 

 

 

해결책은 위 한줄을 상단에 넣어줍니다.

반응형
반응형

이 포스트는 Spring boot + Mybatis 를 전제하고 있습니다.


스프링부트를 이용하면서 다른 종류의 DB를 동시에 사용해야하는 경우가 종종 있습니다.


그런데 이번엔 JNDI 환경까지 겹치면서 1번 DB는 Tomcat (jdbc pool) Datasource 를 사용하고 2번 DB는 JNDI를 이용해야 하는 이런 상황이 되었습니다.


여기에 멈추지 않고 Local 개발환경에서 JNDI 를 사용하기는 또 부담스럽고 귀찮으니 Tomcat embedded JNDI 도 사용해봤습니다.


보너스로 @Profile 을 이용해서 마음대로 각 DB에서 설정에 따라 자유롭게 Datasource 를 골라 쓸 수 있게 해보았습니다.



 
import javax.naming.NamingException;
import javax.sql.DataSource;
 
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
 
@Configuration
@MapperScan(value = Constants.PACKAGE_BASE + ".dao", sqlSessionFactoryRef = "coreSqlSessionFactory")
public class CoreRepositoryConfig {
 
  @Bean
  @ConfigurationProperties(prefix = "spring.datasource.primary")
  public JndiPropertyHolder getJndiPropertyHolder() {
    return new JndiPropertyHolder();
  }
 
  @Primary
  @Bean("coreDatasource")
  @Profile("jndi")
  public DataSource jndiDatasource() throws IllegalArgumentException, NamingException {
    String jndiName = getJndiPropertyHolder().getJndiName();
    return (DataSource) new JndiDataSourceLookup().getDataSource(jndiName);
  }
 
  @Primary
  @Bean("coreDatasource")
  @Profile("!jndi")
  @ConfigurationProperties(prefix = "primary.spring.datasource")
  public org.apache.tomcat.jdbc.pool.DataSource coreDatasource() {
    return (org.apache.tomcat.jdbc.pool.DataSource) DataSourceBuilder.create()
        .type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
  }
 
  @Bean(name = "coreSqlSessionFactory")
  @Primary
  public SqlSessionFactory coreSqlSessionFactory(@Qualifier("coreDatasource") DataSource coreDatasource,
      ApplicationContext applicationContext) throws Exception {
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(coreDatasource);
    sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/config.xml"));
    return sqlSessionFactoryBean.getObject();
  }
 
  @Bean(name = "coreSqlSessionTemplate")
  @Primary
  public SqlSessionTemplate coreSqlSessionTemplate(SqlSessionFactory coreSqlSessionFactory) throws Exception {
    return new SqlSessionTemplate(coreSqlSessionFactory);
  }
 
  class JndiPropertyHolder {
    private String jndiName;
 
    public String getJndiName() {
      return jndiName;
    }
 
    public void setJndiName(String jndiName) {
      this.jndiName = jndiName;
    }
  }
}


<CoreRepositoryConfig.java>


1번 DB의 Java Config 파일이라고 보시면 되겠습니다.


import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan(value = Constants.PACKAGE_BASE + ".secondary.dao", sqlSessionFactoryRef = "secondarySqlSessionFactory")
public class SecondaryRepositoryConfig {
  @Bean("secondaryDatasource")
  @ConfigurationProperties(prefix = "secondary.spring.datasource")
  public DataSource secondaryDatasource() {
    return (DataSource) DataSourceBuilder.create().type(DataSource.class).build();
  }
  @Bean(name = "secondarySqlSessionFactory")
  public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDatasource") DataSource secondaryDatasource,
      ApplicationContext applicationContext) throws Exception {
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(secondaryDatasource);
    sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:secondary/mybatis-config.xml"));
    return sqlSessionFactoryBean.getObject();
  }
  @Bean(name = "secondarySqlSessionTemplate")
  public SqlSessionTemplate secondarySqlSessionTemplate(SqlSessionFactory secondarySqlSessionFactory) throws Exception {
    return new SqlSessionTemplate(secondarySqlSessionFactory);
  }
}


<SecondaryRepositoryConfig.java>


SecondaryRepositoryConfig.java 는 2번 DB의 Java Config 입니다.


spring.profiles.active=local,jndi
 
spring.datasource.primary.jndi-name=MYJNDI
 
secondary.spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
secondary.spring.datasource.url=jdbc:oracle:thin:@IP:PORT:DB
secondary.spring.datasource.username=아뒤
secondary.spring.datasource.password=패쓰워드
secondary.spring.datasource.max-active=1
secondary.spring.datasource.max-idle=1
secondary.spring.datasource.min-idle=1
secondary.spring.datasource.max-wait=-1
secondary.spring.datasource.initial-size=1
secondary.spring.datasource.test-on-borrow=true
secondary.spring.datasource.test-while-idle=true
secondary.spring.datasource.validation-query=select 'SECONDARY' from dual
secondary.spring.datasource.time-between-eviction-runs-millis=300000


<application.properties>


이 녀석은 Spring Boot 의 설정파일인 application.properties 입니다.



CoreRepositoryConfig.java 에서만 JNDI 혹은 Tomcat Datasouce를 쓸건지 선택할 수 있도록 되어있는데 이부분은 application.properties 의 설정중에


spring.profiles.active 에 jndi가 포함되어 있느냐 없느냐를 @Profile("jndi") or @Profile("!jndi") 로 구분해서 선택적으로 Datasource를 제공하고 있습니다.


JNDI 의 이름은 @ConfigurationProperties(prefix = "spring.datasource.primary") 를 이용해  


application.properties 의 spring.datasource.primary.jndi-name=MYJNDI 에서 획득하고 있습니다.


만약 1번 DB에서 JNDI 를 사용하지 않으려면 spring.profiles.active에서 jndi 를 지우고 2번 DB 설정처럼 primary.spring.datasource 설정들을 지정하면 됩니다.


그리고 2번 DB의 사용은 @ConfigurationProperties(prefix = "secondary.spring.datasource") 을 이용해 application.properties 에서 db설정 정보를 가져와 


Tomcat datasource를 사용하고 있습니다.


마지막으로 Local 환경에서도 JNDI 로 테스트하기 위해 Embedded Tomcat JNDI를 이용해 보겠습니다.



 
import javax.sql.DataSource;
 
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.ContextResource;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
 
@Configuration
@Profile({ "local""dev" })
public class TomcatEmbdded {
  @Bean
  public TomcatEmbeddedServletContainerFactory tomcatFactory() {
    return new TomcatEmbeddedServletContainerFactory() {
 
      @Override
      protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
        tomcat.enableNaming();
        return super.getTomcatEmbeddedServletContainer(tomcat);
      }
 
      @Override
      protected void postProcessContext(Context context) {
        ContextResource resource = new ContextResource();
        resource.setName("JNDI이름");
        resource.setType(DataSource.class.getName());
        resource.setProperty("driverClassName""oracle.jdbc.driver.OracleDriver");
        resource.setProperty("url""jdbc:oracle:thin:@IP:PORT:DB");
        resource.setProperty("username""아뒤");
        resource.setProperty("password""패쓔워드");
        resource.setProperty("factory""org.apache.tomcat.jdbc.pool.DataSourceFactory");
        resource.setProperty("type""javax.sql.DataSource");
 
        context.getNamingResources().addResource(resource);
      }
    };
  }
}


<TomcatEmbdded.java - 오타가 ..>


@Profile({ "local", "dev" }) 를 통해서 spring.profiles.active 에 local 이나 dev 가 포함되어 있다면 Embedded Tomcat JNDI 를 사용할 수 있게 됩니다.





maven dependency

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>


@ConfigurationProperties 를 사용하기 위해 필요합니다.


org.apache.tomcat.jdbc.pool.DataSourceFactory 를 사용하기 위해선 tomcat-jdbc 가 필요한데 

저같은 경우 mybatis-spring-boot-starter (mybatis-spring-boot-starter > spring-boot-starter-jdbc > tomcat-jdbc ) 에 포함된 걸 이용하고 있습니다.

반응형
반응형

DB에 패턴이 있는데 데이터들에 대해서 일괄적인 변경을 하고 싶을 경우 정규식을 이용해 UPDATE 할 수 있습니다.

 

아래 예제는 약관에 대한 일괄 변경입니다.

약관정보에 부분적으로 돋보이도록 태그를 덧 씌우는 작업을 정규식 치환을 통해 일괄 처리하였습니다.

처리 건수는 600건 정도 되었습니다. 정규식이 없었다면 @.@ OTL

 

 

 

<before>

 

<after>

 

 

 

그룹 치환 시 오라클은  \1 Mysql 은 \\1 이렇게 사용하고 나머지 기본 문법은 동일 합니다.

반응형
반응형
import javax.naming.NamingException;
 
import org.apache.commons.dbcp.BasicDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
 
public class JndiDatasourceCreator {
  private static final Logger LOGGER = LoggerFactory.getLogger(JndiDatasourceCreator.class);
 
  private static final String username = "userName";
  private static final String password = "password";
  private static final String jndiName = "DB_Name";
  private static final String driverClassName = "Driver Name";
  private static final String url = "jdbc://localhost:port/dbName";
  public static BasicDataSource dataSource;
 
  public static void create() throws Exception {
    try {
      final SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
      dataSource = new BasicDataSource();
      dataSource.setUsername(username);
      dataSource.setPassword(password);
      dataSource.setDriverClassName(driverClassName);
      dataSource.setUrl(url);
      builder.bind("java:comp/env/jdbc/" + jndiName, dataSource);
      builder.activate();
    } catch (NamingException ex) {
      LOGGER.info(ex.getMessage());
    }
  }
}



보통 개발환경에서는 JNDI 를 사용하지 않는데 JNDI를 테스할 경우에는 위의 코드를 이용해서 JNDI 환경에서 잘 동작하는지 테스트 할 수 있다.


    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.4</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>


<필요한 라이브러리>

반응형
반응형

리눅스에서 특정 포트가 리스닝 중인지 혹은 접속 중인지 확인하려면 다음과 같은 명령어를 실행하면된다.

 

 

 

아래는 해당 포트에 접속되어 있거나 접속하고 있는 커넥션 갯수를 확인할 수 있다.

 

 

 

 

위 동일한 명령어에 대해서 윈도우에서도 실행할 수 있다. 

아래 두 명령어를 참조하면 된다.

 

 

 

 

 

 

반응형
반응형


          ------------------------------------------------------------------------------------------------------------------------------------

          

          키움OpenAPI는 함수에서 리턴값으로 함수성공여부를 판단할 수 있는데 0이면 함수호출 성공, 0보다 작은 값은 에러를 나타냅니다.

          주요 에러코드는 -200번(시세과부하), -308번(주문전송 과부하)입니다.

          

          ------------------------------------------------------------------------------------------------------------------------------------

              0         // 정상처리                                                                      

            -10        // 실패                                                                          

          -100        // 사용자정보교환 실패                                                           

          -101        // 서버 접속 실패                                                                

          -102        // 버전처리 실패                                                                 

          -103        // 개인방화벽 실패                                                               

          -104        // 메모리 보호실패                                                               

          -105        // 함수입력값 오류                                                               

          -106        // 통신연결 종료                                                                 

                                                                                                    

          -200        // 시세조회 과부하                                                               

          -201        // 전문작성 초기화 실패.                                                         

          -202        // 전문작성 입력값 오류.                                                         

          -203        // 데이터 없음.                                                                  

          -204        // 조회가능한 종목수 초과. 한번에 조회 가능한 종목개수는 최대 100종목.           

          -205        // 데이터 수신 실패                                                              

          -206        // 조회가능한 FID수 초과. 한번에 조회 가능한 FID개수는 최대 100개.               

          -207        // 실시간 해제오류                                                               

                                                                                                    

          -300        // 입력값 오류                                                                   

          -301        // 계좌비밀번호 없음.                                                            

          -302        // 타인계좌 사용오류.                                                            

          -303        // 주문가격이 20억원을 초과.                                                     

          -304        // 주문가격이 50억원을 초과.                                                     

          -305        // 주문수량이 총발행주수의 1% 초과오류.                                          

          -306        // 주문수량은 총발행주수의 3% 초과오류.                                          

          -307        // 주문전송 실패                                                                 

          -308        // 주문전송 과부하                                                               

          -309        // 주문수량 300계약 초과.                                                        

          -310        // 주문수량 500계약 초과.                                                        

          -340        // 계좌정보 없음.                                                                

          -500        // 종목코드 없음.                                                                


          



반응형
반응형


          [KOA_Functions() 함수]

          

          KOA_Functions(

          BSTR sFunctionName,   // 함수이름 혹은 기능이름

          BSTR sParam   // 함수 매개변수

          ))

          

          KOA_Function() 함수는 OpenAPI기본 기능외에 기능을 사용하기 쉽도록 만든 함수이며 두 개 인자값을 사용합니다. 이 함수가 

          제공하는 기능과 필요한 인자값은 공지를 통해 제공할 예정입니다.

          

          ------------------------------------------------------------------------------------------------------------------------------------

          

          [KOA_Functions() 함수 사용예시]

          OpenAPI.KOA_Functions(_T("ShowAccountWindow"), _T(""));// 계좌비밀번호 설정을 출력한다.

          

          OpenAPI.KOA_Functions(_T("GetServerGubun"), _T(""));// 접속서버 구분을 알려준다. 1 : 모의투자 접속, 나머지 : 실서버 접속 

          

          ------------------------------------------------------------------------------------------------------------------------------------

          



반응형
반응형


          [GetCodeListByMarket() 함수]

          

          GetCodeListByMarket(

          BSTR sMarket    // 시장구분값

          )

          

          국내 주식 시장별 종목코드를 ';'로 구분해서 전달합니다. 만일 시장구분값이 NULL이면 전체 시장코드를 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          

          [시장구분값]

          0 : 장내

          10 : 코스닥

          3 : ELW

          8 : ETF

          50 : KONEX

          4 :  뮤추얼펀드

          5 : 신주인수권

          6 : 리츠

          9 : 하이얼펀드

          30 : K-OTC

          

          



          [GetMasterCodeName() 함수]

          

          GetMasterCodeName(

          BSTR strCode    // 종목코드

          )

          

          종목코드에 해당하는 종목명을 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          



          [GetMasterListedStockCnt() 함수]

          

          GetMasterListedStockCnt(

          BSTR strCode  // 종목코드

          )

          

          입력한 종목코드에 해당하는 종목 상장주식수를 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          



          [GetMasterConstruction() 함수]

          

          GetMasterConstruction(

          BSTR strCode  // 종목코드

          }

          

          입력한 종목코드에 해당하는 종목의 감리구분(정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목)을 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          



          [GetMasterListedStockDate() 함수]

          

          GetMasterListedStockDate(

          BSTR strCode    // 종목코드

          )

          

          입력한 종목의 상장일을 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          

          



          [GetMasterLastPrice() 함수]

          

          GetMasterLastPrice(

          BSTR strCode    // 종목코드

          )

          

          입력한 종목의 전일가를 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          



          [GetMasterStockState() 함수]

          

          GetMasterStockState(

          BSTR strCode  // 종목코드

          )

          

          입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자융의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          



          [GetFutureList() 함수]

          

          지수선물 종목코드 리스트를 ';'로 구분해서 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          



          [GetActPriceList() 함수]

          

          지수옵션 행사가에 100을 곱해서 소수점이 없는 값을 ';'로 구분해서 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          

          ------------------------------------------------------------------------------------------------------------------------------------

          

          [지수옵션 행사가 사용예시]

          CString strActPriceList(OpenAPI.GetActPriceList());

          "19000;19250;19500;19750;20000;20250;20500;20750;21000;21250;21500;21750;..."

          

          ------------------------------------------------------------------------------------------------------------------------------------

          



          [GetMonthList() 함수]

          

          지수옵션 월물정보를 ';'로 구분해서 전달하는데 순서는 콜 11월물 ~ 콜 최근월물 풋 최근월물 ~ 풋 최근월물가 됩니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          

          ------------------------------------------------------------------------------------------------------------------------------------

          

          [지수옵션 월물조회 사용예시]

          CString strMonthList(OpenAPI.GetMonthList());

          "201812;201806;201712;201706;201703;201612;201611;201610;201609;201608;201607;..."

          

          ------------------------------------------------------------------------------------------------------------------------------------

          



          [GetOptionCode() 함수]

          

          GetOptionCode(

          BSTR strActPrice,   // 소수점을 포함한 행사가

          int nCp,    // 콜풋구분값, 콜:2, 풋:3

          BSTR strMonth   // 6자리 월물

          )

          

          인자로 지정한 지수옵션 코드를 전달합니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          

          ------------------------------------------------------------------------------------------------------------------------------------

          

          [지수옵션 코드 사용예시]

          

          CString strOptCode = OpenAPI.GetOptionCode(_T("247.50"), 2, _T("201607"));

          

          ------------------------------------------------------------------------------------------------------------------------------------

          



          [GetOptionATM() 함수]

          

          지수옵션 소수점을 제거한 ATM값을 전달합니다. 예를들어 ATM값이 247.50 인 경우 24750이 전달됩니다.

          로그인 한 후에 사용할 수 있는 함수입니다.

          



반응형

+ Recent posts