달력

42024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30


-- STEP 1 테스트 테이블 생성
CREATE TABLE TEST_A (
TEST_CN VARCHAR2(100)
);
-- STEP 2 테스트 데이터 생성
INSERT INTO TEST_A ( TEST_CN ) VALUES ('AAA');
-- STEP 3 테이블 및 데이터 생성 확인
SELECT * FROM  TEST_A;
-- STEP 4 프로시저 생성 
CREATE OR REPLACE PROCEDURE TEST_AA (
IN_TABEL_NM IN VARCHAR2
)
IS
  V_STR VARCHAR2(500);
  V_RESULT  VARCHAR2(500);
BEGIN 

FOR  REC  IN  (
  SELECT OBJECT_NAME
   FROM   SYS.ALL_OBJECTS
   WHERE  OBJECT_TYPE = 'TABLE'
     AND  OBJECT_NAME = IN_TABEL_NM
   )LOOP
    
    V_STR := 'SELECT TEST_CN FROM '|| REC.OBJECT_NAME ;
EXECUTE IMMEDIATE V_STR INTO V_RESULT;

DBMS_OUTPUT.PUT_LINE('TABLE 명 : ' || REC.OBJECT_NAME || ', ' || V_RESULT );
    
    V_STR := 'DELETE FROM ' || REC.OBJECT_NAME;
    EXECUTE IMMEDIATE V_STR;


END LOOP;
END;


-- STEP 5 프로시저 실행.
   EXEC TEST_AA('TEST_A');

 

-- STEP 6 테스트 데이터 삭제 확인.
   SELECT * FROM  TEST_A;

 

-- STEP 7 테스트 테이블 삭제    
   DROP TABLE TEST_A;

Posted by 한설림
|

context root path

 

Servlet

절대경로

 

getServletContext().getRealPath("/")); // 웹서버의 Document Root

ex) getServletContext().getRealPath("/WEB-INF/web.xml")); 

 

또는 

 

config.getServletContext().getRealPath("/");

 

또는

 

getServletConfig().getServletContext().getRealPath("/");

 

또는

 

request.getSession().getServletContext().getRealPath("/");

 


 

JAVA

 

절대경로

 

this.getClass().getResource("").getPath(); // 현재 자신의 절대 경로

 

this.getClass().getResource("/").getPath(); // classes 폴더의 최상위 경로

 

this.getClass().getResource("/com/test/config/config.properties").getPath(); // classes 폴더에서부터 시작하여 해당파일까지의 절대 경로

 

this.getClass().getProtectionDomain().getCodeSource().getLocation(); // 자신의 파일명(*.class)이 포함된 절대경로

 

 

 

System.getProperty("user.home"); // 사용자 홈 디렉토리

 

System.getProperty("user.dir");  // 이클립스에서 실행시 이클립스 워크스페이스 (해당 프로젝트명 전까지)

 


 

ClassLoader 사용법

 

ClassLoader classLoader = (Thread.currentThread()).getContextClassLoader();

 

if(classLoader==null) classLoader = ClassLoader.getSystemClassLoader();

 

URL url = classLoader.getResource("struts.properties");

 

System.out.println(url.getPath());

 

WEB-INF/classes 에 있는 리소스만 참조합니다.

 

WEB-INF 와 같이 바로 아래에 있는 있는 리소스는 참조하지 못합니다.

 

getSystemClassLoader는 java application에서 사용되는 방법이고

 

(Thread.currentThread()).getContextClassLoader() 는 web에서 사용되는 방법입니다.

 

현재 클래스가 상속되는(부모) 클래스라면 클래스명.class.getResource 로 해야 합니다.

 

getClass()는 실행되는 현재 자신(자식클래스가 될 수 있습니다.)을 가리키기 때문입다.

 

WEB의 절대경로와는 다릅니다.

 

new File("").getAbsolutePath() : 절대경로

 

new File("").getCanonicalPath() : 상대경로

Posted by 한설림
|

프로젝트 진행중에 테스트 데이터를 마이그레이션 하는 동안

 

시퀀스는 초기화 시켜주지 않아서 매번 수동으로 시퀀스 값을 설정했었다.

 

한 두번도 아니고 일일이 수정하기에는 너무 손이 많이 가는 작업이라서

 

시퀀스를 새롭게 들어온 데이터에 맞춰서 새로 설정 해주는 방법을 찾아서 기록에 남기고자 한다.

 

1.  먼저 시퀀스를 설정할 프로시저를 하나 생성하고 매개변수로 3가지를 받는다.

 1-1 시퀀스명 

 1-2 시퀀스 대상 테이블명

 1-3 시퀀스 대상 컬럼명 

 

원리는 이렇다. 

현재의 데이터를 기준으로 시퀀스 값을 읽어 들이고 

그에 맞춰서 시퀀스 값을 변경해준다. 

 

CREATE OR REPLACE PROCEDURE P_REBUILD_SP_SEQUANCE
(
  I_SEQ_NAME IN VARCHAR2 /* 시퀀스 이름 */
  ,I_TB_NAME IN VARCHAR2 /* 시퀀스 대상 테이블 */
  ,I_TB_KEY IN VARCHAR2  /* 시퀀스 대상 컬럼 */
)
IS
  I_SEQNO1 NUMBER;
  I_SEQNO2 NUMBER;

BEGIN 
  /* 시퀀스 증가값을 1로 설정 */

   EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || I_SEQ_NAME || ' INCREMENT BY 1';  

   /* 현재 시퀀스 값 */   

   EXECUTE IMMEDIATE 'SELECT ' || I_SEQ_NAME || ' .NEXTVAL FROM DUAL' INTO I_SEQNO1;  

   /* 업무 테이블 시퀀스값 확인 */  

   EXECUTE IMMEDIATE 'SELECT NVL(MAX(TO_NUMBER('||I_TB_KEY||')),1) +10 FROM '||I_TB_NAME INTO I_SEQNO2;

   
   dbms_output.put_line(I_SEQNO2 - I_SEQNO1);

   /* 업무 테이블 시퀀스 값과 현재 시퀀스 설정값을 비교하여 시퀀스 증가값을 설정 */
   EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || I_SEQ_NAME || ' INCREMENT BY ' || (I_SEQNO2 - I_SEQNO1);
   /* 시퀀스 실행 */

   EXECUTE IMMEDIATE 'SELECT  ' || I_SEQ_NAME || ' .NEXTVAL FROM DUAL' INTO I_SEQNO1;
   dbms_output.put_line(I_SEQNO1);

   /* 시퀀스 증가값을 다시 1로 변경 */
   EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || I_SEQ_NAME || ' INCREMENT BY 1';
END;

 

이렇게 시퀀스를 새롭게 설정할 프로시저를  만들고

 

시퀀스를 가지고 있는 테이블 목록을 가지고 있는

 

프로시저를 하나 더 생성하였다.

 

CREATE OR REPLACE PROCEDURE P_RESET_SP_SEQUANCE
AS
BEGIN
/* 매개변수의 순서를 시퀀스명 , 테이블명 , 컬럼명 순임 */
P_REBUILD_SP_SEQUANCE('DOC_MASTER_SEQ','DOC_MASTER_INFO','DOC_ID'); /* 문서 정보 */ 
P_REBUILD_SP_SEQUANCE('DOC_ATTACH_FILE_SEQ','DOC_ATTACH_FILE_INFO','FILE_ID'); /* 파일 정보 */ 
P_REBUILD_SP_SEQUANCE('DOC_PRINT_HIST_SEQ','DOC_PRINT_HIST','PRINT_ID'); /* 인쇄 히스토리 정보 */ 
P_REBUILD_SP_SEQUANCE('DOC_PRINT_RSN_SEQ','DOC_PRINT_RSN','REQ_ID'); /* 인쇄 재요청 테이블 */ 
P_REBUILD_SP_SEQUANCE('DOC_STAMP_SEQ','DOC_STAMP_HIST','STAMP_ID'); /* 인쇄 시 직인 사용 히스토리 */

 

END; 

 

이렇게 해두면 새롭게 데이터마이그레이션이 진행되어도 

 

EXCUTE P_RESET_SP_SEQUANCE

 

SQL에서 한번의 명령어로 시퀀스값을 마이그레이션 데이터 기준으로 설정이 가능하다. 

Posted by 한설림
|

[MyBatis] Parameter NULL 처리방법

 

[MyBatis] Parameter NULL 처리방법

 

 

 

 

NULL이 들어갈 수 있는 값에 대해 처리를 해주지 않으면 위와같은 ERROR가 뜬다.

 

방법1. Mapper.xml에서 타입명시

 

NULL로 세팅 되는 값에 jdbdType

을 명시해준다.

 

~~~~  #{board_viewcount, jdbcType=INTEGER}, #{board_content, jdbcType=VARCHAR}, ~~~~

 

=> NULL이 될 수 있는 타입에 모두 명시를 해줘야한다.

 

[지원하는 jdbcType 종류]

 

 

방법2. mybatis-config.xml에서 처리

 

방법1과 같은 방법은 하나하나 다 명시를 해줘야하고 다른 쿼리를 추가하게 되면 또 추가를 해야 하지만 이 방법은 mybatis-config.xml에 한 번 적어두기만 하면 된다.

 

<configuration> 

   <settings>            <!-- <settings>이 없으면 만들어줍니다. -->

     <setting name="jdbcTypeForNull" value="NULL" />

   <settings>

<configuration>

 

=> <settings> 태그를 <typeAliases> 아래에 두면 <configuration> 태그에 빨간줄(ERROR)이 생긴다. 그러니 위에 두자.

 

아래와 같이 설정하면 된다.

 

mybatis-config.xml

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration

  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<!-- catcheEnabled =>  default값은 true이다. 아래와 같이 false 설정을 하면 모든 mapper xml의 cache 선언이 무효화가 됨 -->

    <settings>

        <setting name="cacheEnabled" value="false" />

        <setting name="jdbcTypeForNull" value="NULL" />

    </settings>

    

  <typeAliases>

    <package name="com.example.test"/>    

  </typeAliases>

 

</configuration>

Colored by Color Scripter

cs

 

 

'Programing' 카테고리의 다른 글

git, github 이용하기#1  (0) 2016.12.29
Posted by 한설림
|

Android를 개발하다 보면 code에서 Exception이 의심되는 부분에 예외처리를 해주게 되는데, 이 때 예외 발생의 처리부분을 테스트 하기 위해 해당 Exception이 발생되는 상황을 만들 수도 있겠지만 직접 Exception을 throw 해서 발생 시킬 수도 있다. Code는 다음과 같이 상당히 간단하다.

try {

/// 강제로 예외 발생
throw new Exception();
} catch(Exception e) {
/// 예외 발생시 처리 부분
}

  

try {
/// 강제로 예외 발생
Exception ex = new Exception();

throw ex;

} catch(Exception e) {

/// 예외 발생시 처리 부분

}
 

   

대부분의 경우는 예외 처리 부분에 Error code를 printout 하는 경우가 많지만 예외 발생시 특정 동작을 해야 하는 경우도 있을 것이다. 이런 경우 어렵게 상황을 만들기 보다는 해당 Exception을 강제로 발생시켜 처리부의 code를 검증해 보는 것이 좋을 것이다.

Exception은 catch() 부분에 따라 발생 시키면 된다.(예. throw new RuntimeException()…)



출처: https://withwani.tistory.com/154 [박투(搏鬪)]

Posted by 한설림
|

$('.부모 이름').on('click', '.걸고 싶은 대상', function() {

넣을 소스;

});



출처: https://cordinghouse.tistory.com/55 [코딩집]

'Programing > JQUERY' 카테고리의 다른 글

특정 영역(DIV) 여닫기 기능 Toggle  (0) 2017.11.23
DatePicker 기본 설정  (0) 2017.05.25
Posted by 한설림
|

input 자동완성 끄기 HTML

2019. 4. 29. 09:27

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

톰캣(Tomcat) 버전별 차이

 

Apache

Tomcat

Version

Latest

Released

Version

 Supported

Java

Versions

Servelet

Spec

JSP

Spec

EL

Spec 

WebSocket

Spec 

JASPIC

Spec 

 

9.0.x

 

9.0.13

8 and later

4.0

2.3

3.0

1.1

1.1

8.5.x

8.5.35

7 and later

3.1

2.3

3.0

1.1

1.1

8.0.x

(superseded)

8.0.53

(superseded)

7 and later

3.1

2.3

3.0

1.1

 -

7.0.x

7.0.92

(archived)

6 and later

(7 and later for

WebSocket)

3.0

2.2

2.2

1.1

6.0.x

(archived)

6.0.53

(archived)

5 and later

2.5

2.1

2.1

 -

 -

5.5.x

(archived)

5.5.36

(archived)

1.4 and later

2.4

2.0

 -

 -

4.1.x

(archived)

4.1.40

(archived)

1.3 and later

2.3

1.1

 -

 -

 -

3.3.x

(archived)

3.3.2

(archived)

1.1 and later

2.2

1.1

 -

 -

 

위 표와 같이 Tomcat 버전별로 지원하는 Java 버전, 서블릿 스펙 등이 다릅니다.

개발하는 환경에 따라 Spec을 확인하여 톰캣을 정해주면 됩니다.

 

 



출처: https://hyunjin821.tistory.com/147 [개발블로그]

Posted by 한설림
|

<---------------------------------   HTML  -------------------------------------------------->

<link rel="stylesheet" href="${pageContext.request.contextPath }/resources/adminlte/bower_components/select2/dist/css/select2.min.css">

<script src="${pageContext.request.contextPath }/resources/adminlte/bower_components/select2/dist/js/select2.full.min.js"></script>


<select id="maz" name="maz" class="select2-selection-multiple" multiple="multiple">


</select>


<input type="hidden" name="maz2"  value="${maz}">


<---------------------------------   HTML  -------------------------------------------------->



<SCRIPT>


var data = [

{ id : 1 ,text : '수요계획' },

{ id : 2 ,text : 'RTF' },

{ id : 3 ,text : '과부족' },

{ id : 4 ,text : '생산계획' },

{ id : 5 ,text : '재고' },

{ id : 6 ,text : '재고율' },

{ id : 7 ,text : '생산요청량' }

];


// class 에 선언한 부분을 찾아서 select2 형태로 꾸며준다. 

$('.select2-selection-multiple').select2({

placeholder: "Select an option",    // 제일위에 보여질 타이틀 같은 옵션 

allowClear: true,

tags: true,

    tokenSeparators: [',', ' '],

    data : data ,      // 실제 Select Option에 들어갈 데이터 

});


// 서버에서 넘어온 값을 처리하는 로직 

var vMaz = $('input[name=maz2]').val();    

//ex) 복수의 값을 선택하면 1 , 3  같이 콤마를 경계로 한 String 값을

가진다

var vMaz2= vMaz.split(','); // 콤마를 기준으로 스플릿 해준다   [ 1 , 3 ] 

$('.select2-selection-multiple').val(vMaz2).trigger('change');  // 해당 value 의 값이 선택된다.

</SCRIPT>


'Programing > HTML' 카테고리의 다른 글

input 자동완성 끄기 HTML  (0) 2019.04.29
색상코드 , 컬러코드  (0) 2017.10.25
Posted by 한설림
|

요즘 ORM으로는 하이버네이트, JPA등 많이 사용하고 있으나, 역시 SI 쪽은 mybatis(ibatis)를 많이 사용된다.

문제는 mybatis는 xml로 sql을 관리하고 있는데 보통 조금 바꿀때 마다 서버를 재구동 시켜야 되는 문제가 된다.

시스템이 클 경우 재시작시 오랜 시간 걸리고 session 사용시 또 로그인을 해야 하는듯 개발의 흐름이 끊어지는 문제가 많이 발생한다.

예전에 ibatis를 사용 했을시에도 그런 부분이 많이 불편했었는데, 예전 대우정보시스템의 JCF 프레임워크에서 사용된다고 Refresh 되는 클래스 소스가 한번 공개 된적이 있었다. ( 몇년전인지 기억은 안나지만, 당시 인터넷 검색으로 찾았었다. )

그것이 버전이 문제인지 바로 사용이 안되어서 커스터마이징하고 사용을 잘사용 했었다.

그런데 지금 프로젝트가 mybatis로 진행하기 때문에 예전과 같은 불편함이 또 생기게 되었는데, 이 번에는 그 소스를 mybatis에 맞도로 커스터마이징 하기로 했다.  

일단 사전 조건은 

JDK 1.5 이상, Spring, mybatis, spring-mybatis 라이브러리가 설치되어 있는 환경에서만 된다.


일단 기존 Spring 에서 mybatis 설정을 보겠다.

보통 sqlSessionFactory를 이렇게 설정 한다. 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" p:mapperLocations="classpath*:패키지경로/**/mapper.xml" p:configLocation="classpath:/MapperConfig.xml" p:dataSource-ref="dataSource"/>

classpath*:패키지경로/**/mapper.xml  <-이부분이 재로딩 될 xml 파일경로 ( 자신의 프로젝트에 따라 변경 )

이부분에서 굵게 표시한 class 부분만 새로 만든 클래스로 바꾸면 모든게 해결된다.

<bean id="sqlSessionFactory" class="패키지경로.RefreshableSqlSessionFactoryBean" p:mapperLocations="classpath*:패키지경로/**/mapper.xml" p:configLocation="classpath:/MapperConfig.xml" p:dataSource-ref="dataSource" />

RefreshableSqlSessionFactoryBean.java

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.io.Resource;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* mybatis mapper 자동 감지 후 자동으로 서버 재시작이 필요 없이 반영
*
* @author sbcoba
*/
public class RefreshableSqlSessionFactoryBean extends SqlSessionFactoryBean implements DisposableBean {
private static final Log log = LogFactory.getLog(RefreshableSqlSessionFactoryBean.class);
private SqlSessionFactory proxy;
private int interval = 500;
private Timer timer;
private TimerTask task;
private Resource[] mapperLocations;
/**
* 파일 감시 쓰레드가 실행중인지 여부.
*/
private boolean running = false;
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public void setMapperLocations(Resource[] mapperLocations) {
super.setMapperLocations(mapperLocations);
this.mapperLocations = mapperLocations;
}
public void setInterval(int interval) {
this.interval = interval;
}
/**
* @throws Exception
*/
public void refresh() throws Exception {
if (log.isInfoEnabled()) {
log.info("refreshing sqlMapClient.");
}
w.lock();
try {
super.afterPropertiesSet();
} finally {
w.unlock();
}
}
/**
* 싱글톤 멤버로 SqlMapClient 원본 대신 프록시로 설정하도록 오버라이드.
*/
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
setRefreshable();
}
private void setRefreshable() {
proxy = (SqlSessionFactory) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSessionFactory.class},
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// log.debug("method.getName() : " + method.getName());
return method.invoke(getParentObject(), args);
}
});
task = new TimerTask() {
private Map<Resource, Long> map = new HashMap<Resource, Long>();
public void run() {
if (isModified()) {
try {
refresh();
} catch (Exception e) {
log.error("caught exception", e);
}
}
}
private boolean isModified() {
boolean retVal = false;
if (mapperLocations != null) {
for (int i = 0; i < mapperLocations.length; i++) {
Resource mappingLocation = mapperLocations[i];
retVal |= findModifiedResource(mappingLocation);
}
}
return retVal;
}
private boolean findModifiedResource(Resource resource) {
boolean retVal = false;
List<String> modifiedResources = new ArrayList<String>();
try {
long modified = resource.lastModified();
if (map.containsKey(resource)) {
long lastModified = ((Long) map.get(resource))
.longValue();
if (lastModified != modified) {
map.put(resource, new Long(modified));
modifiedResources.add(resource.getDescription());
retVal = true;
}
} else {
map.put(resource, new Long(modified));
}
} catch (IOException e) {
log.error("caught exception", e);
}
if (retVal) {
if (log.isInfoEnabled()) {
log.info("modified files : " + modifiedResources);
}
}
return retVal;
}
};
timer = new Timer(true);
resetInterval();
}
private Object getParentObject() throws Exception {
r.lock();
try {
return super.getObject();
} finally {
r.unlock();
}
}
public SqlSessionFactory getObject() {
return this.proxy;
}
public Class<? extends SqlSessionFactory> getObjectType() {
return (this.proxy != null ? this.proxy.getClass()
: SqlSessionFactory.class);
}
public boolean isSingleton() {
return true;
}
public void setCheckInterval(int ms) {
interval = ms;
if (timer != null) {
resetInterval();
}
}
private void resetInterval() {
if (running) {
timer.cancel();
running = false;
}
if (interval > 0) {
timer.schedule(task, 0, interval);
running = true;
}
}
public void destroy() throws Exception {
timer.cancel();
}
}


만약에 재로딩 되는 시간을 바꾸고 싶으면 

<bean id="sqlSessionFactory" class="패키지경로.RefreshableSqlSessionFactoryBean" p:mapperLocations="classpath*:패키지경로/**/mapper.xml" :configLocation="classpath:/MapperConfig.xml" p:dataSource-ref="dataSource" p:interval="1000" />

 p:interval="1000" 이부분을 수치를 정해주면된다. ( 디폴트는 500, 단위 ms )


이제 설정을 서버를 시작해서 위에 로케이션 해당하는 mapper.xml ( sql이 있는 xml , 설정에 따라 다름)에서

sql을 바꿔 보자 그리고 클라이언트에서 바뀐지 확인해보자

큰 문제가 없다면 반영될것이라고 생각된다. 


아 단 운영 시스템에 사용은 보장 못합니다~ 개발시에서만 사용하세요~


이 소스는 예전에 인터넷에서 나돌던 RefreshableSqlMapClientFactoryBean 소스를 커스터마이징한 소스인데 문제가 있다면 연락주시길바랍니다



출처: http://sbcoba.tistory.com/16 [홍이의 개발 노트]

Posted by 한설림
|