Spring MyBatis 환경에서 아래와 같은 메시지가 나오면서 트랜잭션 정상적으로 작동 안 하는 상황이 있다.


was not registered for synchronization because synchronization is not active

will not be managed by Spring 


TestCase로 Service 계층에서부터 테스트 하면 정상적으로 처리 되는 모습을 보였고, Controller 부분 부터 테스트 하면 실패하는 모습을 보였다.


우선 정상 로그와 비교해보았을때 아래와 같았고, Servlet MVC 부분에 문제로 보여 살펴보았는데 눈에 잘 띄지 않아.. 삽질 하다.. 찾음;;


문제는 <context:component-scan base-package="pe.kr.ddakker">부분에서 하위에 Controller이 아닌 Service 계층이 포함되면 문제가 생기는것이였다.

그리하여 해상 설정에서 Controller 이 아닌 Annotation들을 exclude-filter 해주거나, base-package 부분을 명확하게 구분되게 해주면 되겠다.



[servlet-mvc.xml]


	
	

	
	


[Log]

-- 비 정상
[DEBUG] org.mybatis.spring.SqlSessionUtils[getSqlSession:140] - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4c1c68d3] was not registered for synchronization because synchronization is not active 
[DEBUG] org.mybatis.spring.transaction.SpringManagedTransaction[openConnection:86] - JDBC Connection [jdbc:oracle:thin:@ip:1521:sid, UserName=id, Oracle JDBC driver] will not be managed by Spring 

-- 정상
[DEBUG] org.mybatis.spring.SqlSessionUtils[getSqlSession:120] - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@49ffa050] 
[DEBUG] org.mybatis.spring.transaction.SpringManagedTransaction[openConnection:86] - JDBC Connection [jdbc:oracle:thin:@ip:1521:test, UserName=STAT, Oracle JDBC driver] will be managed by Spring 

Tomcat Multi Instance로 설정 하려면, 기동관련을 위해서 Shell도 만져야 하고, server.xml 도 만져야 한다.


그것을 Script에서만 하면 좋을것 같아서 고민 중, Tomcat에 적용해 보았다.


[env.sh]

#!/bin/sh

DATE=`date +%Y%m%d_%H%M%S`

export JAVA_HOME=/usr/local/java8
export PATH=$PATH:$JAVA_HOME/bin

# Apache Balance Workers 값(WAS별 유니크)
HTTPD_LB_WORKER_NM=testcluster
HTTPD_WORKER_NM=$HTTPD_LB_WORKER_NM'11'
PROJECT_NM_PREPIX=
PROJECT_NM=test-cluster
WAR_PATH=/usr/local/tomcat/webroot/$PROJECT_NM_PREPIX$PROJECT_NM
WEB_ROOT=$WAR_PATH/webapp

export HTTPD_WORKER_NM
export PROJECT_NM
export WAR_PATH
export WEB_ROOT

# 동일 머신에서 중복되지 않게(01~99: 최대 90개)
export PORT_OFFSET=1

let SHUTDOWN_PORT=9100+$PORT_OFFSET
let HTTP_PORT=9200+$PORT_OFFSET
let HTTPS_PORT=9300+$PORT_OFFSET
let AJP_PORT=9400+$PORT_OFFSET

export SHUTDOWN_PORT
export HTTP_PORT
export HTTPS_PORT
export AJP_PORT


export CATALINA_HOME=/usr/local/tomcat/apache-tomcat
export CATALINA_BASE=/usr/local/tomcat/domains/$HTTPD_LB_WORKER_NM

# JVM Options : Server
export JAVA_OPTS="-server $JAVA_OPTS"

# JVM Options : Memory
export JAVA_OPTS="$JAVA_OPTS -Xms2048m -Xmx2048m -Xss256k"
# jdk7 이하
#export JAVA_OPTS="$JAVA_OPTS -XX:PermSize=256m -XX:MaxPermSize=256m"

export JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCTimeStamps "
export JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails "
export JAVA_OPTS="$JAVA_OPTS -Xloggc:$CATALINA_BASE/logs/gc_$DATE.log "
export JAVA_OPTS="$JAVA_OPTS -XX:+UseParallelGC "
export JAVA_OPTS="$JAVA_OPTS -XX:+UseParallelOldGC "

export JAVA_OPTS="$JAVA_OPTS -XX:+ExplicitGCInvokesConcurrent "
export JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError "
export JAVA_OPTS="$JAVA_OPTS -XX:HeapDumpPath=$CATALINA_BASE/logs/heapDump-$DATE.hprof "

export JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"
export JAVA_OPTS="$JAVA_OPTS -Dsun.rmi.dgc.client.gcInterval=0x7FFFFFFFFFFFFFFE"
export JAVA_OPTS="$JAVA_OPTS -Dsun.rmi.dgc.server.gcInterval=0x7FFFFFFFFFFFFFFE"
export JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true"



export JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"
export JAVA_OPTS="$JAVA_OPTS -DjvmRoute=$HTTPD_WORKER_NM"
export JAVA_OPTS="$JAVA_OPTS -Dtomcat.web.root=$WEB_ROOT"
export JAVA_OPTS="$JAVA_OPTS -Dtomcat.port.shutdown=$SHUTDOWN_PORT"
export JAVA_OPTS="$JAVA_OPTS -Dtomcat.port.http=$HTTP_PORT"
export JAVA_OPTS="$JAVA_OPTS -Dtomcat.port.https=$HTTPS_PORT"
export JAVA_OPTS="$JAVA_OPTS -Dtomcat.port.ajp=$AJP_PORT"

# WEB JK_MOD 정보
export HTTPD_HOSTS=( "192.0.0.100" )
export LB_WORKER=$HTTPD_LB_WORKER_NM
export WORKER=$HTTPD_WORKER_NM

#HTTPD_HOSTS_STR=""
for i in "${HTTPD_HOSTS[@]}"
do
        HTTPD_HOSTS_STR="${HTTPD_HOSTS_STR}${i},"
done

echo "============================================================="
echo "   Apache Tomcat 8.x                     ddakker@naver.com   "
echo "-------------------------------------------------------------"
$CATALINA_HOME/bin/./version.sh
echo "-------------------------------------------------------------"
echo "PROJECT_NM=$PROJECT_NM"
echo "WORKER_NM=$HTTPD_WORKER_NM"
echo "WEB_ROOT=$WEB_ROOT"
echo "SHUTDOWN_PORT=$SHUTDOWN_PORT"
echo "HTTP_PORT=$HTTP_PORT"
echo "HTTPS_PORT=$HTTPS_PORT"
echo "AJP_PORT=$AJP_PORT"
echo "HTTPD_HOSTS=$HTTPD_HOSTS_STR"
echo "============================================================="


[start.sh]

#!/bin/sh


. ./env.sh

# 임시 파일 삭제
rm -Rf $CATALINA_BASE/temp/*
# 로그 파일 관리
rm -Rf $CATALINA_BASE/logs/catalina.out


if [ "`ps -eaf | grep java | grep "$CATALINA_BASE "`" != "" ]; then
        echo "Tomcat SERVER - $PROJECT_NM is already RUNNING..."
        exit;
fi

if [ ! -d "$WEB_ROOT" ];
then
        mkdir -p $WAR_PATH
                mkdir -p $WEB_ROOT
                mkdir -p $WAR_PATH/../logs/$HTTPD_LB_WORKER_NM
fi


cd $CATALINA_HOME/bin

./startup.sh


if [ -z "`ps -eaf | grep java | grep "$CATALINA_BASE "`" ]; then
        echo "Error!!! Cannot start tomcat server."
fi


IS_WAIT=$1
IS_JK_CTL=$2

if [ "$IS_WAIT" == "wait" ]; then
        while [ `netstat -an | grep :$HTTP_PORT | grep LISTEN | wc | awk '{print $1}'` != 1 ]; do
                echo -ne "."
                sleep 1
        done

        echo "Check WAS Context Ready http://localhost:$HTTP_PORT ..."

        until [ "`curl --silent -o --show-error --connect-timeout 1 -w "%{http_code}\n" http://localhost:$HTTP_PORT | egrep '200|301|302|500'`" != "" ];
        do
                echo -ne "."
                sleep 1
        done
fi



if [ "$IS_JK_CTL" == "update" ]; then
        for HTTPD_HOST in "${HTTPD_HOSTS[@]}"
        do
                echo "<<< Turn-ON Worker $WORKER in $LB_WORKER [$HTTPD_HOST]"
                if [ "`curl --silent --show-error --connect-timeout 1 -I \"http://$HTTPD_HOST/jkstatus/?cmd=update&w=$LB_WORKER&sw=$WORKER&vwa=0\" | egrep '404|500|503'`" != "" ]
                then
                        echo "<<< Error"
                else
                        echo "<<< Done"
                fi
        done
fi


[shutdown.sh]

#!/bin/sh
 
 . ./env.sh

IS_WAIT=$1
IS_JK_CTL=$2
JK_CTL_AFTER_DELAY=$3
PID=`ps -ef | grep java | grep "$CATALINA_BASE " | awk '{print $2}'`

if [ e$PID == "e" ]
then
        echo "NOT RUNNING!!!"
        exit;
fi

if [ "$JK_CTL_AFTER_DELAY" == "" ]; then
        JK_CTL_AFTER_DELAY=0
fi

if [ "$IS_JK_CTL" == "update" ]; then
        for HTTPD_HOST in "${HTTPD_HOSTS[@]}"
        do
                echo "<<< Turn-OFF Worker $WORKER in $LB_WORKER [$HTTPD_HOST]"
                #if [ "`curl --silent --show-error --connect-timeout 1 -I \"http://$HTTPD_HOST/jkstatus/?cmd=update&w=$LB_WORKER&sw=$WORKER&vwa=1\" | egrep '403|404|500|503'`" != "" ]
                if [ "`curl --silent --show-error --connect-timeout 1 -I \"http://$HTTPD_HOST/jkstatus/?cmd=update&w=$LB_WORKER&sw=$WORKER&vwa=2\" | egrep '403|404|500|503'`" != "" ]
                then
                        echo "<<< Error"
                else
                        echo "<<< Done"
                fi
        done

        echo "+sleep $JK_CTL_AFTER_DELAY"
        sleep $JK_CTL_AFTER_DELAY
fi


$CATALINA_HOME/bin/./shutdown.sh
 
 
if [ "$IS_WAIT" == "wait" ]; then
        I=0
        until [ "`ps -eaf | grep java | grep "$CATALINA_BASE "`" == "" ];
        do
                if [ $I == 120 ]; then
                        ps -ef | grep java | grep "$CATALINA_BASE " | awk {'print "kill -9 " $2'} | bash -x
                        break;
                fi
 
                let I=$I+1
 
                echo -ne "."
                sleep 1
        done
fi


echo "*** Tomcat process ($PID) received SHUTDOWN signal ***" >> $CATALINA_BASE/logs/catalina.out


[setting.sh]

#!/bin/sh

. ./env.sh

if [ ! -d "$WEB_ROOT" ];
then
        mkdir -p $WAR_PATH
                mkdir -p $WEB_ROOT
                mkdir -p $WAR_PATH/../logs/$HTTPD_LB_WORKER_NM
fi


cd $CATALINA_BASE
find ./ -type d -exec chmod 750 {} \;
find ./ -type f -exec chmod 740 {} \;

chmod -Rf 640 $CATALINA_BASE/logs/*

cd $WEB_ROOT
find ./ -type d -exec chmod 755 {} \;
find ./ -type f -exec chmod 640 {} \;


if [ ! -e "$WEB_ROOT/index.html" ];
then
        echo "Hello World" >> $WEB_ROOT/index.html
fi
if [ ! -e "$WEB_ROOT/info.jsp" ];
then
        echo "<%@ page language=\"java\" contentType=\"text/html; charset=EUC-KR\" pageEncoding=\"EUC-KR\"%><%@page import=\"java.net.InetAddress\"%><%String serverIP = \"\";try{serverIP = InetAddress.getLocalHost().getHostAddress();serverIP = serverIP.substring(serverIP.lastIndexOf(\".\")+1);}catch(Exception e){}String info = request.getServerName() + \", \" + serverIP + \", \" + System.getProperty(\"jvmRoute\");out.print(info);// test%>" >> $WEB_ROOT/info.jsp
fi

if [ $LANG = "ko_KR.eucKR" ]; then
        cd $CATALINA_BASE
        FILE_ENC=`file -i env.sh `

        UTF8_IDX=`awk -v a="$FILE_ENC" -v b="utf-8" 'BEGIN{print index(a,b)}' `

        if [ $UTF8_IDX -gt 0 ]; then
                cd $CATALINA_BASE
                echo "----- encoding convertor -----"
                find . -name '*.sh' -exec iconv -f utf-8 -t euc-kr {} -o {} \;
        fi


[top.sh]

#!/bin/sh


. ./env.sh

PID=`ps -ef | grep java | grep "$CATALINA_BASE " | awk '{print $2}'`

if [ e$PID == "e" ]
then
        echo "NOT RUNNING!!!"
        exit;
fi

$CATALINA_BASE/../monitor_agent/./jvmtop.sh $PID


[dump.sh]

#!/bin/sh

. ./env.sh

for count in 1 2 3 4 5; do
    echo "Thread Dump : $count"
    for i in `ps -ef | grep java | grep "base=$CATALINA_BASE " | awk '{print $2}'`;do
        date
        #echo "+kill -3 $i"
        echo "+jstack -l $i >> $CATALINA_BASE/logs/thread_dump.$i"
        #kill -3 $i
        jstack -l $i >> $CATALINA_BASE/logs/thread_dump.$i
        #echo "sleep 1 sec"
        #sleep 1
    done
    echo "done"
    sleep 3
done


[dump_cpu.sh]

#!/bin/sh

. ./env.sh

for count in 1 2 3 4 5; do
    echo "Thread Dump : $count"
    for i in `ps -ef | grep java | grep "base=$CATALINA_BASE " | awk '{print $2}'`;do
        top -H -b -n1 >> $CATALINA_BASE/logs/dump_high_cpu_$i.txt
        date
        #kill -3 $i
        echo "+jstack -l $i >> $CATALINA_BASE/logs/dump_high_cpu_$i.txt"
        jstack -l $i >> $CATALINA_BASE/logs/dump_high_cpu_$i.txt
        echo "cpu snapshot and thread dump done. #"
    done
    echo "done"
    sleep 3
done


[httpd.sh]

#!/bin/sh


. ./env.sh



if [ "$1" == "stop" ]; then
        for HTTPD_HOST in "${HTTPD_HOSTS[@]}"
        do
                echo "<<< Turn-OFF Worker $WORKER in $LB_WORKER [$HTTPD_HOST]"
                if [ "`curl --silent --show-error --connect-timeout 1 -I \"http://$HTTPD_HOST/jkstatus/?cmd=update&w=$LB_WORKER&sw=$WORKER&vwa=2\" | egrep '403|404|500|503'`" != "" ]
                then
                        echo "<<< Error"
                else
                        echo "<<< Done"
                fi
        done
fi

if [ "$1" == "start" ]; then
        for HTTPD_HOST in "${HTTPD_HOSTS[@]}"
        do
                echo "<<< Turn-ON Worker $WORKER in $LB_WORKER [$HTTPD_HOST]"
                if [ "`curl --silent --show-error --connect-timeout 1 -I \"http://$HTTPD_HOST/jkstatus/?cmd=update&w=$LB_WORKER&sw=$WORKER&vwa=0\" | egrep '404|500|503'`" != "" ]
                then
                        echo "<<< Error"
                else
                        echo "<<< Done"
                fi
        done
fi


[server.xml]



  
  
  
  
  
  
  
  
    
    
    
    
 
      
        
      
      
                
        

      
    
  


.properties 의 경우 ISO-8859-1 문자셋이기때문에 한글 사용에 문제가 있어, IDE Tool 을 사용하여 자동으로 변환하는 방법을 이용하곤 했다.

하지만 이 방법의 경우에도 서버상에 올라가있는 설정 파일을 확인 및 직접 수정할 경우 에로 사항이 발생한다.

또한 개개인별 .properties 를 ms949, euc-kr 등으로 변경 해 놓는 사태도 발생해버린다. OTL...


이러한 불편함을 해결 하기 위해 .xml 확장자를 이용하면 좋을것이다.



[applicationContext.xml]


	
	
        
            
                classpath:/properties/globals-properties.xml
            
        
    

	
		
			
				classpath:properties/messages-properties
			
		
	

	
	
		
			
		
	


[Sample.java]

@Controller
public class Sample {
	
	@Value("#{global['server.type']}") private String serverType;
	@Resource GlobalsProperties globalsProperties;

	@RequestMapping(value="/sample")
	public void test(ModelMap model) {
		// Properties Case 1
		System.out.println("serverType: " + serverType);

		// Properties Case 2
		System.out.println("server.type: " + globalsProperties.getProperty("server.type"));
			
		//MessageSource Case 1
		System.out.println("msg.test1: " + messageSource.getMessage("msg.test1", null, Locale.getDefault()));

		// MessageSource Case 2
		System.out.println("msg.test2: " + messageSource.getMessage("msg.test2", new String[]{"첫번째", "두번째"}, Locale.getDefault()));
	}
}


[sample.jsp]

	
	
	
	
		로컬임
	

	
	

	
	


globals-properties.xml




	globals-properties local
	local								

	result					
	message				


[messages-properties_ko.xml]




	messages-properties_ko


	ko 한글 정보는...
	ko 파라미터1 = {0}, 파라미터2 = {1}...


지금까지 Spring 설정파일이나 Web.xml 파일의 JavaConfig형태로 사용하는것에 대해서 큰 필요성을 느끼지 못해 굳이 사용하고 있지 않았었다.


그런데 최근 Filter를 운영환경에서만 추가로 설정해야 할 필요가 생겨났다.

Filter를 상속받아서 처리해도 되겠지만 생각난김에 web.xml을 Java Code로 변경해 보았다.


[WebXml.java]

package config;

import java.util.EnumSet;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.multipart.support.MultipartFilter;
import org.springframework.web.servlet.DispatcherServlet;

import pe.kr.ddakker.core.framework.web.GlobalsProperties;
import pe.kr.ddakker.core.support.util.StringUtils;

/**
 * /WEB-INF/Web.xml 설정
 * @author ddakker 2014. 10. 13.
 */
public class WebXml implements WebApplicationInitializer {
	private static Logger log = LoggerFactory.getLogger(WebXml.class);

	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		// 스프링 설정
		XmlWebApplicationContext rootContext = new XmlWebApplicationContext();
        rootContext.setConfigLocations(new String[] { "classpath:config/spring/context-*.xml" });
        rootContext.refresh();
        rootContext.start();


        GlobalsProperties globalsProperties = rootContext.getBean("globalsProperties", GlobalsProperties.class);
        String serverType 	= StringUtils.defaultString(globalsProperties.getProperty("server.type"), "local")
        String domain		= GlobalsProperties.REAL.equals(serverType)?"board.ddakker.pe.kr":serverType + "-board.ddakker.pe.kr";
        log.debug("========== domain: {} ========== ", domain);
        log.debug("========== serverType: {} ========== ", serverType);


        // SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS Filter 영역 SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
        if (GlobalsProperties.STAGE.equals(serverType) || GlobalsProperties.REAL.equals(serverType)) {
			// 상황에 따른 필터 추가
        }

        // 인코딩 설정
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);
        FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("characterEncodingFilter", characterEncodingFilter);
        characterEncoding.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

        // 스프링 RestFull 설정
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        FilterRegistration.Dynamic hiddenHttpMethod = servletContext.addFilter("hiddenHttpMethodFilter", hiddenHttpMethodFilter);
        hiddenHttpMethod.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

        // 파일업로드 설정
        MultipartFilter multipartFilter = new MultipartFilter();
        FilterRegistration.Dynamic multipart = servletContext.addFilter("multipartFilter", multipartFilter);
        multipart.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

        // String Security 설정
        DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy();
        FilterRegistration.Dynamic springSecurity = servletContext.addFilter("springSecurityFilterChain", springSecurityFilterChain);
        springSecurity.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");



        // 사이트메쉬 설정
        SiteMeshFilter siteMeshFilter = new SiteMeshFilter();
        FilterRegistration.Dynamic siteMeshEncoding = servletContext.addFilter("siteMeshFilter", siteMeshFilter);
        siteMeshEncoding.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), true, "/*");
        // EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE Filter 영역 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE




        // SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS Listener 영역 SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
        // String Core 설정
        servletContext.addListener(new ContextLoaderListener(rootContext));

        // Spring Security 증복로그인 관련 처리 여부(resources/config/spring/context-security.xml session-management->concurrency-control 부분)
        //servletContext.addListener(new HttpSessionEventPublisher());
        // EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE Listener 영역 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE





        // SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS Servlet 영역 SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
        // 스프링 MVC 설정
        XmlWebApplicationContext xmlWebApplicationContext = new XmlWebApplicationContext();
        xmlWebApplicationContext.setConfigLocation("classpath:config/spring/servlet-mvc.xml");
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(xmlWebApplicationContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
        /* EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE Servlet 영역 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE */


	}
}

[web.xml]





	...
	
	
		contextConfigLocation
		classpath:config/spring/context-*.xml
	


	
		monitoring
		net.bull.javamelody.MonitoringFilter
	
	
		monitoring
		/*
	
	
		net.bull.javamelody.SessionListener
	
	
	
		encodingFilter
		org.springframework.web.filter.CharacterEncodingFilter
		
			encoding
			UTF-8
		
		
			forceEncoding
			true
		
	
	
		encodingFilter
		/*
	
	
		org.springframework.security.web.session.HttpSessionEventPublisher
	
	
		httpMethodFilter
		org.springframework.web.filter.HiddenHttpMethodFilter
	
	
		httpMethodFilter
		/*
	
	
		multipartFilter
		org.springframework.web.multipart.support.MultipartFilter
	
	
		multipartFilter
		/*
	
	
		springSecurityFilterChain
		org.springframework.web.filter.DelegatingFilterProxy
	
	
		springSecurityFilterChain
		/*
	
	
		sitemesh
		com.opensymphony.sitemesh.webapp.SiteMeshFilter
	
	
		sitemesh
		/*
		REQUEST
		FORWARD
	
	
		org.springframework.web.context.ContextLoaderListener
	
	
		action
		org.springframework.web.servlet.DispatcherServlet
		
			contextConfigLocation
			classpath:config/spring/servlet-mvc.xml
		
		1
	
	
		action
		/
	


2012-10-13 stable release 이후 버전에서 부터 디자인이 전체적으로 변경되면서 가로사이즈가 75em<--으로 고정되어졌음


변경 하려면 ../lib/tpl/dokuwiki/style.ini

__site_width__      = "75em" 부분을 __site_width__      = "100%" 와 같이 변경한다.




두번째로 IE9에서(다른 IE버전은 모르겠음..) 편집 버튼 폰트가 너무 작아 이상하게 보이는 문제는


../lib/tpl/dokuwiki/css/_edit.css 파일에서 .dokuwiki .secedit input.button 부분에서 font-size: 75%; 부분을 font-size: 11px; 와 같이 변경한다.



세번째로 font-size 가 우리 정서적으로 맞지않아.. 12px로 변경.. 


/lib/tpl/dokuwiki/css/basic.less 의 body 부분에서 font: normal 12px Arial, sans-serif; 와 같이 변경


네번째로 li의 간격 조절, 같은 파일의 li,dd 부분의 margin: 0 0 0 1.5em; 를 margin: 6px 0 0 1.5em; 와 같이 변경


그 외.. 이것..저것..



이 후 touch ../conf/local.php 해주면 적용된다.






2012-10-13 stable release 이전 버전도 style 수정이 필요 하다면 /lib/tpl/default/ 하위 css를 수정 후 local.php 파일을 touch 해주면 적용된다.


이전 디자인이 더 맘에 드는 이유는....

개발/운영 환경에 따라 설정파일관련 정보들이 빌드 시점에 동적으로 변경되어야 한다.

Maven에는 Profile이라는 기능을 통하여 처리하는 반면, Gradle의 경우 System Propertie와 비슷한 방법을 이용하여 처리한다.


[디렉토리 구조]



[build.gradle]

build 시작에 properties-dev 에 있는 내용을 properties 에 옮기고, logback.xml 파일은 class root에 위치 시키는 내용이다.

build 실행 시 target이라는 옵션을 주면 된다.

-Ptarget=dev build  // 주의할 점은 java VM -D가 아니라는 점임

...

sourceSets {
	def targetServer = project.hasProperty('target') ? project.getProperty('target') : 'local'
	println "targetServer: $targetServer"
	if( "$targetServer" != "local" ){
		copy {
			from("src/main/resources/properties-$targetServer"){
				exclude 'logback.xml'
			}
			into "src/main/resources/properties"
		}
		copy {
			from("src/main/resources/properties-$targetServer"){
				include 'logback.xml'
			}
			into("src/main/resources/")
		}
		delete file("src/main/resources/properties-dev")
		delete file("src/main/resources/properties-stage")
		delete file('src/main/resources/properties-real')
	}
}

...


Eclipse TestCase 실행 - 정상

Eclipse Gradle TestCase 실행 - 정상

Linux 64/Tomcat 7.x 배포 실행 후 서비스 - 정상


Linux 64/Jenkins Gradle test Task 실행 - 실패


TestMapper.java 일 경우 testMapper.xml 일때 위와 같은 정상/실패 케이스가 생긴다.


xml 파일명은 무조건 java파일명과 대소문자까지 일치 시켜주자!!

svn: POST of '': 404 Not Found 


Window -> Team -> SVN -> SVN Connector 탭 -> SVN Connector 셀렉트 -> SVNKit .... 선택

[참고] http://snippets.khromov.se/subversion-1-8-centos-6/



wget http://snippets.khromov.se/wp-content/uploads/2013/09/svninstall.sh_.txt
mv svninstall.sh_.txt svninstall.sh
chmod 755 svninstall.sh
sh svninstall.sh


svninstall.sh_.txt


[SampleDaoCase.java]

import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;

import java.util.List;

import javax.annotation.Resource;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:config/spring/context-*.xml"})
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleDaoCase {
	private Logger log = LoggerFactory.getLogger(SampleDaoCase.class);
	@Resource SampleDao sampleDao;

	private String name = "이름 테스트";

	@Test
	public void seq01_addSample_글_등록() {
		Sample sampleVo = new Sample();
		sampleVo.setName(name);
		sampleVo.setEmail("ddakkerABC@gmail.com");

		int insertCnt = sampleDao.addSample(sampleVo);
		log.debug("insertCnt: {}", insertCnt);

		assertThat("글 등록 갯수", 1, is(insertCnt));

	}

	@Test
	public void seq02_getSamplesXml_조회() {
		log.debug("sampleDao: " + sampleDao);
		Sample sampleVo = new Sample();
		sampleVo.setEmail("ddakker@gmail.com");

		List list = sampleDao.getSamplesXml(sampleVo);
		log.debug("list: {}", list);
		log.debug("seq: {}", list.get(0).getSeq());
		log.debug("name: {}", list.get(0).getName());
		if( list.get(0).getName() == null )	log.debug("name NULL");
		else								log.debug("name NOT NULL: {}", list.get(0).getName().length());

		assertThat("리스트 갯수 체크", 0, not(list.size()));
		assertThat("리스트 첫번째 배열의 네임값 체크", list.get(0).getName(), not(nullValue()));

		assertThat("리스트 첫번째 배열의 네임값 체크 다른 방법", list.get(0),hasProperty("name", not(nullValue())));

	}

	@Test
	public void seq03_getSamplesXml_조회_검색() {
		log.debug("sampleDao: " + sampleDao);
		Sample sampleVo = new Sample();
		sampleVo.setEmail("ddakker@gmail.com");
		sampleVo.setSeq(30);

		List list = sampleDao.getSamplesXml(sampleVo);
		log.debug("list: {}", list);
		log.debug("seq: {}", list.get(0).getSeq());
		log.debug("name: {}", list.get(0).getName());
		if( list.get(0).getName() == null )	log.debug("name NULL");
		else								log.debug("name NOT NULL: {}", list.get(0).getName().length());

		assertThat("리스트 갯수 체크", 0, not(list.size()));
		assertThat("리스트 첫번째 배열의 네임값 체크", list.get(0).getName(), not(nullValue()));
		assertThat("리스트 첫번째 배열의 네임값 체크 다른 방법", list.get(0),hasProperty("name", not(nullValue())));

	}

	@Test
	public void seq04_deleteSample_삭제() {
		Sample sampleVo = new Sample();
		sampleVo.setName(name);

		Sample sample = sampleDao.getSample(sampleVo);

		assertThat("글", sample, not(nullValue()));
		assertThat("글번호", sample.getSeq(), not(nullValue()));

		sampleVo = new Sample();
		sampleVo.setSeq(sample.getSeq());

		int deleteCnt = sampleDao.deleteSample(sampleVo);
		assertThat("글 삭제 갯수", 1, is(deleteCnt));
	}

}

[SampleControllerCase.java]

import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import pe.kr.ddakker.core.support.web.tags.pagination.Paging;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextHierarchy({
    @ContextConfiguration("classpath*:config/spring/context-*.xml"),
    @ContextConfiguration("file:webapp/WEB-INF/config/springmvc/name-servlet.xml")
})
public class SampleControllerCase {
	private Logger log = LoggerFactory.getLogger(SampleControllerCase.class);

	@Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
    	this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }


	@Test
	public void listCase_페이징_리스트() throws Exception{
		System.out.println("mockMvc1: " + mockMvc);
		MvcResult mvcResult = this.mockMvc.perform(get("/sample/list").param("a", "1"))
					.andDo(print())
					.andExpect(status().isOk())
					.andExpect(model().attributeExists("paging"))
					.andExpect(view().name("sample/list"))
					.andReturn();

		Paging samplePaging = (Paging) mvcResult.getModelAndView().getModelMap().get("paging");

		assertThat("게시물 정상 여부", samplePaging, not(nullValue()));
		assertThat("게시물 리스트 정상 여부", samplePaging.getList(), not(nullValue()));

		if( samplePaging.getList().size() > 0 ){
			log.debug("seq={}, name={}", samplePaging.getList().get(0).getSeq(), samplePaging.getList().get(0).getName());
			assertThat("리스트 첫번째 배열의 네임값 체크 다른 방법", samplePaging.getList().get(0),hasProperty("name", not(nullValue())));
		}
	}

	@Test
	public void listCase_페이징_리스트_JSON() throws Exception{
		System.out.println("mockMvc1: " + mockMvc);
		this.mockMvc.perform(get("/sample/list").accept(MediaType.APPLICATION_JSON))
					.andDo(print())
					.andExpect(status().isOk())
					.andExpect(jsonPath("$.result").value("0000"))
					;
	}

}


dependencies {
	compile 'org.mybatis:mybatis:3.2.7'
	compile 'org.mybatis:mybatis-spring:1.2.2'
	testCompile 'junit:junit:4.11'
	testCompile 'org.hamcrest:hamcrest-all:1.3'
	testCompile 'com.jayway.jsonpath:json-path-assert:0.9.1'
	testCompile 'org.springframework:spring-test:3.2.9.RELEASE'
}

+ Recent posts