web.xml 의 Filter 부분을 동적으로 처리해야 할 일이 생겼다.


Spring 3.1 이상을 사용하게 되면 org.springframework.web.WebApplicationInitializer 를 이용하게되면 더 심플하겠지만 현재 상황에서는 Spring 2.5 환경이여서 불가능!!


Servlet 3.x (javax.servlet.ServletContainerInitializer) 만으로 처리해보자.



유의할 점은 Tomcat 8.x 에서는 아래와 같이 그대로 해도 정상적으로 작동하지만 JBoss와 같이 Java EE 환경에서는 

jar cvf webxml.jar META-INF/services/javax.servlet.ServletContainerInitializer pe.kr.ddakker.WebXml.class

와 같이 jar 생성 후 WEB-INF/lib 하위에 위치 시켜야 정상 작동합니다.


build.gradle

dependencies {
	providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
}


WebXml.java

package pe.kr.ddakker;

import java.util.EnumSet;
import java.util.Set;

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

import pe.kr.ddakker.filter.TestFilter;

public class WebXml implements ServletContainerInitializer {

	@Override
	public void onStartup(Set> c, ServletContext servletContext) throws ServletException {
		System.out.println("ServletContainerInitializer");


		TestFilter testFilter = new TestFilter();
        FilterRegistration.Dynamic test = servletContext.addFilter("testFilter", testFilter);
        test.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

	}
}


TestFilter.java

package pe.kr.ddakker.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class TestFilter implements Filter {

    public TestFilter() {
    }

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// pass the request along the filter chain
		System.out.println("TestFilter S");
		chain.doFilter(request, response);
		System.out.println("TestFilter E");
	}

	public void init(FilterConfig fConfig) throws ServletException {
	}

}


classpath 하위 META-INF/services/javax.servlet.ServletContainerInitializer

pe.kr.ddakker.WebXml


[jUnit or Hamcrest 셈플]

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.emptyArray;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.hamcrest.Matchers.equalToIgnoringWhiteSpace;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hamcrest.Matchers;
import org.junit.Test;


public class 테스트케이스 {
	@Test
	public void 셈플() throws Exception{
		assertThat("0이 아니겠지?", 1, not(0));
		assertThat("앞에값이 크겠지?", 2000, greaterThan(1000));
		assertThat("앞에값이 크거나 같겠지?", 1000, greaterThanOrEqualTo(1000));
		assertThat("앞에값이 작겠지?", 2000, lessThan(5000));
		assertThat("앞에값이 작거나 같겠지?", 1000, lessThanOrEqualTo(1000));
		assertThat("앞뒤가 같겠지?", "하이", equalTo("하이"));
		assertThat("앞뒤가 대소문자 구분없이 같겠지?", "aabbcc", equalToIgnoringCase("AaBbCc"));
		assertThat("앞뒤 공백은 좀 바주고 같겠지?", "하이 ", equalToIgnoringWhiteSpace(" 하이"));
		assertThat("널이 아니겠지?", new String("널 아니다"), is(notNullValue()));
		assertThat("리스트가 비어있겠지?", new ArrayList<Object>(), empty());
		assertThat("배열이 비어있겠지?", new String[0], emptyArray());
		assertThat("문자열에 포함되어 있지?", "abc", containsString("b"));
		assertThat("시작하는 단어가 맞지?", "abc", startsWith("a"));
		assertThat("끝나는 단어가 맞지?", "abc", endsWith("c"));


		List<Map<String, String>> mapList = new ArrayList<Map<String, String>>();
		Map<String, String> map = new HashMap<String, String>();
		map.put("name", "ddakkerTest");
		map.put("age", "100");
		mapList.add(map);
		map = new HashMap<String, String>();
		map.put("name", "ddakker");
		map.put("age", "0");
		mapList.add(map);
		assertThat("배열중에서 특정 키의 값이 존재 하지?", mapList, Matchers.<Map<String, String>>hasItem(hasEntry("name", "ddakker")));
		assertThat("해쉬맵에서 해당 필드의 값이 동일하지?", map, hasEntry("name", "ddakker"));

		List<User> userList = new ArrayList<User>();
		User user = new User("ddakkerTest", 100);
		userList.add(user);
		user = new User("ddakker", 0);
		userList.add(user);
		assertThat("배열중에서 특정 필드의 값이 존재 하지?", userList, Matchers.<User>hasItem(hasProperty("name", is("ddakker"))));
		assertThat("빈에서 해당 필드의 값이 동일하지?", user,hasProperty("name", is("ddakker")));
	}
}
  • hamcrest-all-1.3.jar
  • junit-4.4.jar
    ex) Spring 2.5 에서는 junit-4.4 버전을 사용해야 문제가 없다고 함!!


전에 잠깐 눈으로만 알고 있었는데, 한번 셈플링 해보았다.

자세한것은 모르지만 Selenium 과 WebDriver 의 장점을 살려서 Selenium 2 로 탄생했단다.


우선 편리한 레코딩을 위해서 Firefox와 Firefox Plugin으로 Selenium IDE를 설치한다.

http://docs.seleniumhq.org/download/


아래 IDE로 자동 레코딩된 소스를 조금 수정해서 돌려보았다.


Firefox 이외의 브라우저에서는 alert 클릭이 부분이 정상적으로 되지 않았다...


추 후에 연구해봐야 할듯...(단순하게 WebDriver만 바꾸는게 아닌건가...)


또한 IDE로 레코딩 할때에 frameset 기반의 홈페이지는 레코딩이 잘 되지 않았고, javascript로 레이어로 펼쳐서 클릭하는 메뉴의 경우에도 Firefox를 제외하고는 정상적으로 되지 않았다.


[LoginTest.java]

import static org.junit.Assert.fail;

import java.io.File;
import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.remote.DesiredCapabilities;

public class LoginTest {
	private WebDriver driver;
	private String baseUrl;
	private boolean acceptNextAlert = false;
	private StringBuffer verificationErrors = new StringBuffer();
	private int browser = 1;
	
	@Test
	public void loginTest() throws Exception {
		baseUrl = "http://localhost:8080/";
		driver.get(baseUrl + "/login");
		driver.findElement(By.name("j_username")).clear();
		driver.findElement(By.name("j_username")).sendKeys("1");
		driver.findElement(By.name("j_password")).clear();
		driver.findElement(By.name("j_password")).sendKeys("2");
		driver.findElement(By.name("submit")).click();
		driver.findElement(By.cssSelector("button")).click();
		Assert.assertEquals("이구용", closeAlertAndGetItsText());
	}
	
	@Before
	public void setUp() throws Exception {
		DesiredCapabilities caps = null;
		File f = null;
		
		if( browser == 0 ){
			driver = new HtmlUnitDriver(true);
		}else if( browser == 1 ){
			driver = new FirefoxDriver();
		}else if( browser == 2 ){
			f = new File("E:\\webdriver\\IEDriverServer32\\IEDriverServer.exe");
			System.setProperty("webdriver.ie.driver", f.getAbsolutePath());
			
			caps = DesiredCapabilities.internetExplorer();
			caps.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);
			driver = new InternetExplorerDriver(caps);
		}else if( browser == 3 ){
			f = new File("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe");
			System.setProperty("webdriver.chrome.driver", f.getAbsolutePath());
			
			driver = new ChromeDriver();
		}
		
		
		driver.manage().timeouts().implicitlyWait(300, TimeUnit.SECONDS);
	}
	
	@After
	public void tearDown() throws Exception {
		System.out.println("@After");
		driver.quit();
		String verificationErrorString = verificationErrors.toString();
		if (!"".equals(verificationErrorString)) {
			fail(verificationErrorString);
		}
	}

	private String closeAlertAndGetItsText() {
		try {
			Alert alert = driver.switchTo().alert();
			String alertText = alert.getText();
			if (acceptNextAlert) {
				alert.accept();
			} else {
				alert.dismiss();
			}
			return alertText;
		} finally {
			acceptNextAlert = true;
		}
	}
}



[build.gradle]

apply plugin: 'java'
apply plugin: 'eclipse'

sourceCompatibility = 1.5
version = '1.0'
jar {
    manifest {
        attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
    testCompile group: 'junit', name: 'junit', version: '4.+'
    //testCompile 'org.seleniumhq.selenium:selenium-java:2.28.0'
	//testCompile 'org.seleniumhq.selenium:selenium-firefox-driver:2.39.0'
	//testCompile 'org.seleniumhq.selenium:selenium-server:2.39.0'
	//testCompile 'org.seleniumhq.selenium:selenium-server-standalone:2.39.0'
	testCompile 'org.seleniumhq.selenium:selenium-java:2.39.0'
	testCompile 'org.seleniumhq.selenium:selenium-firefox-driver:2.39.0'
	testCompile 'org.seleniumhq.selenium:selenium-chrome-driver:2.39.0'
	testCompile 'org.seleniumhq.selenium:selenium-IE-driver:2.39.0'
	testCompile 'org.seleniumhq.selenium:selenium-HtmlUnit-driver:2.39.0'
}




 menuCd

 highMenuCd

 menuNm

 orderNo

 

 1001

 0

 고객

 1

 1002

 1001

 고객리스트

 2
 1003 1002 대기리스트 3
 1004 0 게시판 4
 1005 1004 자유게시판 5
 1006 1004 유머게시판 6


위와 같은 형식의 데이터를 DB에서 뽑아 냈을때 오른쪽과 같이 화면에 표현하고 싶었다.


우선 Tree는 jQuery기반의 드래그앤랍이 기능이 되는 "jquery.dynatree.js" 를 선택했다.


이제 위 2차원 배열형태의 데이터를 dynatree가 요구하는 데이터형태로 변환을 해야 한다.

요구하는 데이터형태는 트리형식으로 아래와 같은 스타일로 만들어주면 된다.


[

{"isFolder":"true","title":"고객","children":[

{"isFolder":"true","title":"고객리스트" }

...

    ]

....

]


위와 같은 형태로 만들려고 삽질 좀 하다가 javascript 기반으로 잘 만들어져있는 소스를 구글링을통해 발견하여 그것을 java기반으로 수정 하였습니다.

(http://programmingsummaries.tistory.com/250)






import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * JSON관련 가공에 필요한 함수들
 * @auther ddakker 2013. 12. 12.
 */
public class JsonUtil {
	private static final Log log = LogFactory.getLog(JsonUtil.class);
	/**
	 * 2차원 배열의 부모/자식 관계의 데이터를 트리형식으로 재나열 한다.
	 * @param list			2차원 배열
	 * @param rootId		최상위 id
	 * @param idKey			유니크한 키(id가 될 필드명)
	 * @param pIdKey		부모키(pId가 될 필드명)
	 * @param titleKey		메뉴명이 표시될 필드명
	 * @return
	 * @auther ddakker 2013. 12. 12.
	 */
	public static List<Map<String, Object>> convertorTreeMap(final List<Map<String, Object>> list, String rootId, final String idKey, final String pIdKey, final String titleKey){
		return convertorTreeMap(list, rootId, idKey, pIdKey, titleKey, null);
	}
	/**
	 * 2차원 배열의 부모/자식 관계의 데이터를 트리형식으로 재나열 한다.
	 * @param list			2차원 배열
	 * @param rootId		최상위 id
	 * @param idKey			유니크한 키(id가 될 필드명)
	 * @param pIdKey		부모키(pId가 될 필드명)
	 * @param titleKey		메뉴명이 표시될 필드명
	 * @param orderKey		정렬이 필요한경우 정령 필드명
	 * @return
	 * @auther ddakker 2013. 12. 12.
	 */
	public static List<Map<String, Object>> convertorTreeMap(List inList, String rootId, final String idKey, final String pIdKey, final String titleKey, final String orderKey){
		List<Map<String, Object>> treeList = new ArrayList<Map<String,Object>>();	// 최종 트리
		
		if( inList == null || inList.size() == 0 ) 	throw new RuntimeException("List<Map> 데이터가 없습니다.");
		if( inList.get(0) == null ) 				throw new RuntimeException("Map 데이터가 없습니다.");
		
		final List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();	// 원본데이터(Bean일경우 Map으로 변환)
		Iterator iter;
		for( iter=inList.iterator(); iter.hasNext(); ) {
			try{
				Object obj = iter.next();
				if( obj instanceof Map ) {
					list.add((Map<String, Object>) obj);
				}else{
					list.add((Map<String, Object>) BeanUtils.describe(obj));
				}
			}catch (Exception e) {
				throw new RuntimeException("Collection -> List<Map> 으로 변환 중 실패: " + e);
			}
		}
		
		
		int listLength = list.size();
		int loopLength = 0;
		final int[] treeLength = new int[] { 0 };
		
		while ( treeLength[0] != listLength && listLength != loopLength++ ) {
			for ( int i=0; i<list.size(); i++ ) {
				Map<String, Object> item = list.get(i);
				if ( rootId.equals((String)item.get(pIdKey)) ) {
					Map<String, Object> view = new HashMap<String, Object>(item);
					view.put("title", item.get(titleKey));
					view.put("children", new ArrayList<Map<String,Object>>());
					
					treeList.add(view);
					list.remove(i);
					
					treeLength[0]++;
					
					
					if( orderKey != null ){
						Collections.sort(treeList, new Comparator<Map<String, Object>>(){
							public int compare(Map<String, Object> arg0, Map<String, Object> arg1) {
								// TODO Auto-generated method stub
								return ((String)arg0.get(orderKey)).compareTo((String)arg1.get(orderKey));
							}
						});
					}
					view.put("isFolder", "true");
					
					break;
				}else{
					new InnerClass(){
			            public void getParentNode(List<Map<String, Object>> children, Map<String, Object> item ) {
			            	for ( int i=0; i<children.size(); i++ ) {
			    				Map<String, Object> child = children.get(i);
			    				if ( child.get(idKey).equals(item.get(pIdKey)) ) {
			    					Map<String, Object> view = new HashMap<String, Object>(item);
			    					view.put("title", item.get(titleKey));
			    					view.put("children", new ArrayList<Map<String,Object>>());
			    					((List<Map<String,Object>>) child.get("children")).add(view);
			    					
			    					treeLength[0]++;
			    					
			    					list.remove(list.indexOf(item));
			    					view.put("isFolder", "true");
			    					
			    					if( orderKey != null ){
				    					Collections.sort(((List<Map<String,Object>>) child.get("children")), new Comparator<Map<String, Object>>(){
				    						public int compare(Map<String, Object> arg0, Map<String, Object> arg1) {
				    							// TODO Auto-generated method stub
				    							return ((String)arg0.get(orderKey)).compareTo((String)arg1.get(orderKey));
				    						}
				    					});
			    					}
			    					break;
			    				}else{
			    					if( ((List<Map<String,Object>>) child.get("children")).size() > 0 ){
			    						getParentNode((List<Map<String,Object>>) child.get("children"), item);
			    					}
			    				}
			            	}
			            }
			        }.getParentNode(treeList, item);
				}
			}
		}
		return treeList;
	}
	
	public interface InnerClass {
		public void getParentNode(List<Map<String, Object>> list, Map<String, Object> item );
    }
	
}
import java.io.FileOutputStream;
import java.io.StringReader;

import org.junit.Test;

import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.html.simpleparser.HTMLWorker;
import com.itextpdf.text.html.simpleparser.StyleSheet;
import com.itextpdf.text.pdf.PdfWriter;


public class TestCreatePDF {

	@Test
	public void htmlCreate() throws Exception {
		// TODO Auto-generated method stub
		String fontname = "d:\\GulimChe.ttf";
		String filename = "d:\\filename.pdf";
		
		FontFactory.register(fontname);
		StringBuffer sBuff = new StringBuffer("<html>");
		sBuff.append("<head></head>");
		sBuff.append("<body>");
		sBuff.append("<table border=1>");
		sBuff.append("<tr><td>Test worker <b>한글</b> 테스트</td><td>11<b>1</b>11</td></tr>");
		sBuff.append("</table>");
		sBuff.append("</body>");
		sBuff.append("</html>");
		StringReader stringReader = new StringReader(sBuff.toString());

		Document document = new Document();
		StyleSheet st = new StyleSheet();
		st.loadTagStyle("body", "face", "굴림체"); 
		st.loadTagStyle("body", "encoding", "Identity-H"); 
		st.loadTagStyle("body", "leading", "12,0"); 
		HTMLWorker worker = new HTMLWorker(document);
		PdfWriter.getInstance(document, new FileOutputStream(filename));
		document.open();
		java.util.List<Element> p = HTMLWorker.parseToList(stringReader, st);
		for (int k = 0; k < p.size(); ++k)
		    document.add((Element)p.get(k));
		document.close();
	}

}

GulimChe.ttf

itextpdf-5.4.0.jar


[출처] http://blog.wooriaru.com/131163646


oscache-2.3.2.jar 가 기존에 포함되어 있길래 재대로 활용해보았다.


하지만 운영서버에서 서버가 버벅되다 죽는것이 확인되었다.


이유를 못 찾는 와중에 WAS 시스템 엔지니어로 부터 OSCache문제라는 통보를 받았다 ㅠ


구글링도 해보았지만 해결책을 쉽게 찾지 못 하였다.


캐쉬 최대 갯수도 늘려보아도 소용이 없던 찰라에 oscache 버전을 최신으로 교체해보았다.


결론은.. 원활하게 운영중이다..


이런. ㅠㅠ


현재 oscache-2.4.1.jar 버전으로 정상 가동중이다.


+ Recent posts