import java.text.SimpleDateFormat; import java.util.Date; import java.util.GregorianCalendar; import com.ibm.icu.util.Calendar; public class DateUtil { /** * 월의 해당 주의 날짜 배열을 얻어온다. * @param yyyymm * @param weekSeq * @return */ public static int[] getRangeDateOfWeek(String yyyymm, int weekSeq) { int rangeDateOfWeek [] = new int[7]; int startDayOfWeek = dayOfWeek(yyyymm.substring(0, 4), yyyymm.substring(4, 6), "1"); if( startDayOfWeek == 0 || weekSeq > 1 ){ Calendar cal = converterDate(yyyymm+"01"); int lastDateOfMonth = getLastDateOfMonth(new SimpleDateFormat("yyyyMM").format(cal.getTime())); int startDate = 1 + ((weekSeq-1)*7) - startDayOfWeek; for( int i=0; i<7; i++ ){ if( startDate > lastDateOfMonth ){ startDate = 1; } rangeDateOfWeek[i] = startDate++; } }else{ Calendar cal = converterDate(yyyymm+"01"); cal.add(Calendar.MONTH, -1); int lastDateOfBeforeMonth = getLastDateOfMonth(new SimpleDateFormat("yyyyMM").format(cal.getTime())); int startDate = (lastDateOfBeforeMonth + 1) - startDayOfWeek; for( int i=0; i<7; i++ ){ if( startDate > lastDateOfBeforeMonth ){ startDate = 1; } rangeDateOfWeek[i] = startDate++; } } return rangeDateOfWeek; } /** * 특정날짜의 요일의 숫자를 리턴 * 0:일요일 ~ 6:토요일 * @return */ public static int dayOfWeek(String sYear, String sMonth, String sDay) { int iYear = Integer.parseInt(sYear); int iMonth = Integer.parseInt(sMonth) - 1; int isDay = Integer.parseInt(sDay); GregorianCalendar gc = new GregorianCalendar(iYear, iMonth, isDay); return gc.get(gc.DAY_OF_WEEK) - 1; } /** * String 형식의 날자를 Calendar 로 변환 해준다. * * @param yyyymmdd * @return */ public static Calendar converterDate(String yyyymmdd) { Calendar cal = Calendar.getInstance(); // 양력 달력 if (yyyymmdd == null) return cal; String date = yyyymmdd.trim(); if (date.length() != 8) { if (date.length() == 4) date = date + "0101"; else if (date.length() == 6) date = date + "01"; else if (date.length() > 8) date = date.substring(0, 8); else return cal; } cal.set(Calendar.YEAR, Integer.parseInt(date.substring(0, 4))); cal.set(Calendar.MONTH, Integer.parseInt(date.substring(4, 6)) - 1); cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(date.substring(6))); return cal; } /** * 해당 월의 마지막일을 구한다. * @return */ public static int getLastDateOfMonth() { return getLastDateOfMonth(new Date()); } public static int getLastDateOfMonth(Date date) { return getLastDateOfMonth(new SimpleDateFormat("yyyyMM").format(date)); } public static int getLastDateOfMonth(String yyyymm) { int year = Integer.parseInt(yyyymm.substring(0, 4)); int month = Integer.parseInt(yyyymm.substring(4, 6)) - 1; Calendar destDate = Calendar.getInstance(); destDate.set(year, month, 1); return destDate.getActualMaximum(Calendar.DATE); } }
JAVA/JSP
- 날짜(Date, Calendar), 한주의 시작~끝 날짜, 요일, 마지막일 2012.07.11
- Apache POI Excel xls, xlsx 2012.05.04
- Object -> XML String Apache commons Betwixt Example 2012.04.09 1
- 기호 특수문자 치환 2012.04.06
- Struts2 기존 Action 그대로 xml, json Result 생성, JSP Runtime Exception catch 2012.02.21
- Apache Solr 3.5.0 셋팅하기(db dataimport), Lucene, 한글형태소분석기 2012.02.13
- 오픈소스 검색엔진 패스트캣(FASTCAT), 루씬(Lucene) 비교 2012.02.07 1
- JEUS 6 DataSource 설정 (Spring) 2011.07.11
- AES 암호화 예제(128Bit) 2011.06.09
- java 압축 zip 만들기 2011.05.13
날짜(Date, Calendar), 한주의 시작~끝 날짜, 요일, 마지막일
Apache POI Excel xls, xlsx
import java.io.File; import java.io.FileInputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.FormulaEvaluator; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.xssf.usermodel.XSSFCell; /** * Excel Read 한다. xls, xlsx 가능 * ex) ExcelGenerator.excelToList(new File("path..xls,xlsx"); * ExcelGenerator.excelToList(new File("path..xls,xlsx", new Integer[]{x, y, width, height}); * ExcelGenerator.excelToList(new File("path..xls,xlsx", x, y, width, height); * java.awt.Rectangle(int x, int y, int width, int height) 와 같은 형태로 왼쪽 위 모서리 좌표와, 오른쪽 아래 모서리 좌표 정보 * @author ddakker * @version 1.0 * @date 2012.05.04 * */ public class ExcelGenerator { private static final Log logger = LogFactory.getLog(ExcelGenerator.class); public static Object[][] excelToList(File file ) throws Exception { return excelToList(file, 0, null); } /** * 엑셀 데이터를 Object[colunm][row] 형태로 변환한다. * @param file 엑셀 파일(xls, xlsx) * @param x 왼쪽 위 모서리 x * @param y 왼쪽 위 모서리 y * @param width 오른쪽 아래 모서리 x * @param height 오른쪽 아래 모서리 y * @return * @throws Exception */ public static Object[][] excelToList(File file, int x, int y, int width, int height) throws Exception { Integer [] colRow = {x, y, width, height}; return excelToList(file, 0, colRow); } /** * 엑셀 데이터를 Object[colunm][row] 형태로 변환한다. * @param file 엑셀 파일(xls, xlsx) * @param colRow 범위 지정 new Integer[]{왼쪽 위 모서리 x, 왼쪽 위 모서리 y, 오른쪽 아래 모서리 x, 오른쪽 아래 모서리 y} * @return * @throws Exception */ public static Object[][] excelToList(File file, Integer [] colRow) throws Exception { return excelToList(file, 0, colRow); } /** * 엑셀 데이터를 Object[colunm][row] 형태로 변환한다. * @param file 엑셀 파일(xls, xlsx) * @param sheetIndex 시트 번호 * @return * @throws Exception */ public static Object[][] excelToList(File file, int sheetIndex) throws Exception { return excelToList(file, sheetIndex, null); } /** * 엑셀 데이터를 Object[colunm][row] 형태로 변환한다. * @param file 엑셀 파일(xls, xlsx) * @param sheetIndex 시트 번호 * @param colRow 범위 지정 new Integer[]{왼쪽 위 모서리 x, 왼쪽 위 모서리 y, 오른쪽 아래 모서리 x, 오른쪽 아래 모서리 y} * @return */ public static Object[][] excelToList(File file, int sheetIndex, Integer [] colRow) throws Exception { Object [][] contentData = null; FileInputStream fis = null; Workbook workBook = null; Sheet sheet = null; try { if( colRow != null ){ if( colRow.length != 4 ) throw new Exception("colRow[] 무조껀 셋팅 해야 합니다. ex) new Integer[]{0,0,6,2}"); if( !(colRow[0] >= 0 && colRow[1] >= 0) ) throw new Exception("colRow[] 0 이상 입력 하시요. ex) new Integer[]{1,1,6,2}"); if( !(colRow[2] >= 0 && colRow[3] >= 0) ) throw new Exception("colRow[] 0 이상 입력 하시요. ex) new Integer[]{1,1,6,2}"); } fis = new FileInputStream(file); workBook = WorkbookFactory.create(fis); sheet = workBook.getSheetAt(sheetIndex); int minCol = colRow==null?0:colRow[0]; int maxCol = colRow==null?-1:colRow[2]+1; int minRow = colRow==null?0:colRow[1]; int maxRow = colRow==null?sheet.getPhysicalNumberOfRows():colRow[3]+1; FormulaEvaluator evaluator = workBook.getCreationHelper().createFormulaEvaluator(); for( int i=minRow; i<maxRow; i++ ) { Row row = sheet.getRow(i); if( i-minRow == 0 ){ if( maxCol == -1 ){ maxCol = row.getPhysicalNumberOfCells(); } contentData = new Object[maxRow-minRow][maxCol-minCol]; } for( int j=minCol; j<maxCol; j++ ) { Cell cell = row.getCell(j)==null?row.createCell(j):row.getCell(j); Object value = null; switch( cell.getCellType() ) { case XSSFCell.CELL_TYPE_FORMULA : if( !(cell.toString() == "") ){ if(evaluator.evaluateFormulaCell(cell)==XSSFCell.CELL_TYPE_NUMERIC){ //value = cell.getNumericCellValue(); value = String.valueOf(new Double(cell.getNumericCellValue()).intValue()); }else if(evaluator.evaluateFormulaCell(cell)==XSSFCell.CELL_TYPE_STRING){ value = cell.getStringCellValue(); }else if(evaluator.evaluateFormulaCell(cell)==XSSFCell.CELL_TYPE_BOOLEAN){ value = String.valueOf(cell.getBooleanCellValue()); } } break; case XSSFCell.CELL_TYPE_NUMERIC : //value = cell.getNumericCellValue(); value = String.valueOf(new Double(cell.getNumericCellValue()).intValue()); break; case XSSFCell.CELL_TYPE_STRING : value = cell.getStringCellValue()==null?new String(""):cell.getStringCellValue(); break; case XSSFCell.CELL_TYPE_BOOLEAN : value = Boolean.toString(cell.getBooleanCellValue()); //boolean break; default : } logger.debug("xlsx ["+i+"]["+j+"]=" + ((cell==null || value==null)?"":value)); contentData[i-minRow][j-minCol] = (value==null)?new String(""):value; } } } catch (Exception e) { logger.error(e); throw new Exception("POI Excel Read 중 오류가 발생하였습니다."); } finally { if( fis != null ) fis.close(); } return contentData; } /** * List
--------------
dom4j-1.6.1.jar
poi-3.6-20091214.jar
poi-ooxml-3.6-20091214.jar
poi-ooxml-schemas-3.6-20091214.jar
xmlbeans-2.3.0.jar
등
Object -> XML String Apache commons Betwixt Example
아주 간단하게 처리 된다.
import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.betwixt.io.BeanWriter; public class WriteExampleApp { public static final void main(String [] args) throws Exception { StringWriter outputWriter = new StringWriter(); outputWriter.write(""); BeanWriter beanWriter = new BeanWriter(outputWriter); // Bean 속성 으로 값 출력 여부 beanWriter.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(true); // 아이디 출력 여부 beanWriter.getBindingConfiguration().setMapIDs(false); // 정렬 beanWriter.enablePrettyPrint(); List list1 = new ArrayList(); list1.add(new PersonBean("hk", 20)); list1.add(new PersonBean("dk", 20)); Map map = null; List list2 = new ArrayList(); map = new HashMap(); map.put("name", "hk"); map.put("age", "20"); list2.add( map ); map = new HashMap(); map.put("name", "dk"); map.put("age", "20"); list2.add( map ); beanWriter.write("list1", list1); beanWriter.write("list2", list2); System.out.println(outputWriter.toString()); outputWriter.close(); } }
기호 특수문자 치환
public String convertorChar(String value) { // \(역슬레쉬) 맨 처음 치환 return value==null?"":value.replace("\\", "\\\\") .replace("+", "\\+") .replace("[", "\\[") .replace("]","\\]") .replace("(", "\\(") .replace(")", "\\)") .replace("{", "\\{") .replace("}", "\\}") .replace("\'", "\\\'") .replace("\"", "\\\""); }
Struts2 기존 Action 그대로 xml, json Result 생성, JSP Runtime Exception catch
환경 : Struts2 + Spring + Sitemesh 등
기존 개발된 환경에서 Source 는 그대로 유지하면서 MVC Action 단 Result View를 XML, JSON 등의 형태로 받고 싶었다.
아래 아키텍처를 보고 고민하던 중 Result 단을 좀 꺽으면 될듯 싶어 작업해 보았다.
우선 Default Result 인 org.apache.struts2.dispatcher.ServletDispatcherResult 를 상속받아서 doExecute 함수를 재정의 해서 호출확장자가 .action 일때는 기존과 그대로 처리 하고, action.xml, action.json 일때는 request.getAttributeNames() 배열에 있는 데이터를 xml, json 문자열로 만들어서 response.getWriter() 이용해서 출력하면 되겠네요.
(해당 정보를 파라미터로 해도 될듯하고, Request Header 정보를 활용해도 되겠습니닷.)
신경써야 할 점은 getAttribute 배열에 들어있는 불필요한 데이터는 무시합니다.
또한 Struts2 가 POJO 기반이여서 Action 단의 데이터들도 뽑아와야 하는데 파마리터 ActionInvocation 객체에 getAction() 함수를 통해서 얻을 수 있습니다.
(getAttribute에 "struts.valueStack" 에 OgnlValueStack 객체에도 Action 정보가 담겨 있습니다. OgnlValueStack 는 배열로서 해당 Action 객체 일때 필요한 getter 메소드 호출해서 사용하면 되겠습니다.
ActionInvocation 에서 뽑아 올 경우 getAttributeNames() 이용 시
"struts.valueStack" 정보는 제외 시켜야 합니다.)
필요에 따라 다른 ResultType 들도 수정하시면 되겠습니다.
수정 하시고, struts 설정파일 package 하위 result-type 에 등록하시면 되겠습니다.
또한 super.doExceute() 함수에 try ~ catch 거시면 JSP Runtime Exception 에 대한 처리도 할 수 있겠네요.
JSON, XML 변환은 아래 package를 사용했습니다.
ezmorph-1.0.4.jar
json-lib-2.2.1-jdk15.jar
xom-1.1.jar
* 위 jar 최신버전으로 하면 오류나네요...
* 또한 XML Element Name이 숫자로 생성되면 파싱 오류납니다.
Apache Solr 3.5.0 셋팅하기(db dataimport), Lucene, 한글형태소분석기
메뉴얼(http://wiki.apache.org/solr/DataImportHandler)이 있기는 하지만 직관적이지 않아 이리저리 검색도 해보고 문의해서 정리한다.
Window 7
Tomcat 5.5.35,
Apache Solr 3.5.0
Oracle 10g
톰켓 설치 경로
/conf/server.xml
<Connector port="8983" ..... URIEncoding="UTF-8" />
포트는 편하신것으로 하면 될듯하다.
Encoding 는 검색할때 Request 호출 시 한글 깨짐을 방지하기 위함이다.(해당 WAS에 따라서 또는 소스레벨에서 적절하게 하면 될듯하다.)
/bin/catalina.bat
set CATALINA_HOME=D:\apache-solr\tomcat
set JAVA_OPTS=%JAVA_OPTS% -Dsolr.solr.home=D:\apache-solr\solr ... 기존 옵션...
/common/lib/ojdbc14.jar 복사하자.(Oracle)
Solr 작동 소스 경로
D:\apache-solr\tomcat\webapps\solr
Apache-solr-3.5.0.zip 파일 하위 dist/apache-solr-3.5.0.war 파일을 solr.war 로 변경하여 복사한다.
Apache-solr-3.5.0.zip 파일 하위 dist/apache-solr-dataimporthandler-3.5.0.jar, apache-solr-dataimporthandler-extras-3.5.0.jar 두 파일을 WEB-INF/lib 하위에 복사한다.
(Solr 설정파일 colrconfig.xml <lib> 설정으로도 할 수 있지만 간편히 복사하자.
Solr 설정파일 경로
D:\apache-solr\solr
Apache-solr-3.5.0.zip 파일 하위 example/solr 폴더를 복사한다.
/conf/solrconfig.xml
추가 하자 data-config.xml 파일은 같은경로에 두자.
/conf/data-config.xml
한글형태소분석기는 http://cafe.naver.com/korlucene/462 를 참조하자.
이제 Tomcat 시작하고
http://localhost:8983/solr/dataimport?command=full-import 하면 인덱싱 된다.
http://localhost:8983/solr/admin 에서 *:* 모두 검색해보자.
오픈소스 검색엔진 패스트캣(FASTCAT), 루씬(Lucene) 비교
그래서 현재 2.x 로 개발된것과 Fastcat을 동일환경으로 약 13만건의 데이터로 테스트 해본 결과 Fastcat 이 인덱스속도 약 2배, 검색속도 약 100배의 속도차이가 보였다.
(사실 검색속도는 7ms 와 300ms 라서 큰 의미가 없지만, 인덱스속도는 40s와 2m의 차이라서 의미가 약간? 컷다. 로컬환경이라 신뢰도가 떨어질 수 있다.)
* 위 잘못 된비교로 정정, Lucene 3.5 으로 셈플링 한 결과 2.3 버전과 성능면은 크게 다르지 않았다.
* Solr 기반 테스트 시작...
우선 Fastcat 은 별도의 개발 없이 웹관리자의 셋팅만으로 검색환경 구축이 마무리 되었다.
약 10분이면 셋팅완료!!
Lucene 2.x 으로 개발된 환경이 유지보수로 몇년간 이어오면서 불필요한 오버헤드가 있을것도 감안 해야겠다.
또한 형태소 분석 알고리즘도 다르겠다.
시간 나면 Lucene 3.x 버전으로 셈플링해서 테스트 해봐야겠다.
ps. Lucene이나 Fastcat 모두 크롤링은 지원되지 않는다.
[결과]
데이터 건수 : 130,268건
패스트캣 indexer 소요시간 : 약 45초
루씬 2.3 indexer 소요시간 : 약 2분
패스트캣과 약 2배
루씬 3.5 indexer 소요시간 : 약
2.1분 패스트캣과 약 3배
Solr 3.5 indexer 소요시간 : 약 1.3분 패스트캣과 약 2배
패스트캣 sercher 소요시간 : 약 7밀리초
루씬 2.3
sercher 소요시간: 약 700밀리초 패스트캣과 약 100배
루씬 3.5
sercher 소요시간: 약 187밀리초 패스트캣과 약 26배
Solr 3.5 sercher 소요시간: 약 23밀리초 패스트캣과
약 8배
너무 작은 차이로 의미 없음
데이터 검수 : 529,188건
패스트캣 indexer 소요시간 : 1분 26초
Solr
3.5 indexer 소요시간 : 5분 30초
패스트캣 sercher 소요시간 : 48밀리초
패스트캣 배포/커뮤니티 사이트 - http://www.getfastcat.org/
JEUS 6 DataSource 설정 (Spring)
[JEUSMain.xml]
oracle jdbc/name_test oracle.jdbc.pool.OracleConnectionPoolDataSource ConnectionPoolDataSource oracle sid This is a sample for database setting. 아이디 아이디 1521 아이피 driverType java.lang.String thin true Warning 2 30 4 3600000 true 10000
[jeus-web-dd.xml]
jdbc/name_test jdbc/name_test
JEUSMain.xml
jdbc/name_test javax.sql.DataSource
[스프링 설정파일]
AES 암호화 예제(128Bit)
public class CipherUtil { private Log LOG = LogFactory.getLog(this.getClass()); /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub CipherUtil cu = new CipherUtil(); Calendar cal = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssss"); String key = sdf.format(cal.getTime()); System.out.println("key: " + key); String text = "가나다라마바사@★아&자@12!@#$%"; String encryptText = null; String decryptText = null; try { encryptText = cu.encryptAES(text, key); decryptText = cu.decryptAES(encryptText, key); } catch (Exception e) { e.printStackTrace(); } System.out.println("encryptText: " + encryptText); System.out.println("beforeText : " + text); System.out.println("decryptText: " + decryptText); // 2011051813190051 // abcdefgh01234567 } // key는 16바이트로 구성 되어야 한다. private String encryptAES(String s, String key) throws Exception { String encrypted = null; try { SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); encrypted = byteArrayToHex(cipher.doFinal(s.getBytes())); return encrypted; } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error(e.getMessage(), e); } throw e; } } // key는 16 바이트로 구성 되어야 한다. private String decryptAES(String s, String key) throws Exception { String decrypted = null; try { SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); decrypted = new String(cipher.doFinal(hexToByteArray(s))); return decrypted; } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error(e.getMessage(), e); } throw e; } } private byte[] hexToByteArray(String s) { byte[] retValue = null; if (s != null && s.length() != 0) { retValue = new byte[s.length() / 2]; for (int i = 0; i < retValue.length; i++) { retValue[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16); } } return retValue; } private String byteArrayToHex(byte buf[]) { StringBuffer strbuf = new StringBuffer(buf.length * 2); for (int i = 0; i < buf.length; i++) { if (((int) buf[i] & 0xff) < 0x10) { strbuf.append("0"); } strbuf.append(Long.toString((int) buf[i] & 0xff, 16)); } return strbuf.toString(); } }
java 압축 zip 만들기
private boolean createZIP(List list, String strOutputFileName) { byte[] buffer = new byte[2048]; try { ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(strOutputFileName)); String strFileName = ""; for (int i=0; i<list.size(); i++){ strFileName = (String) list.get(i); strFileName = strFileName.substring(12); File f = new File(uploadPath + File.separator + strFileName); FileInputStream fin = new FileInputStream(f); ZipEntry ze = new ZipEntry(f.getName()); ze.setTime( f.lastModified() ); zout.putNextEntry(ze); int nlen = 0; while( (nlen = fin.read(buffer) ) > 0) { zout.write(buffer, 0, nlen); } zout.closeEntry(); fin.close(); } zout.close(); return true; } catch (IOException e) { e.printStackTrace(); return false; } }