multipart form parser - http file upload, database 저장 java class 연재2 이번글에서는 업로드된 파일을 저장할때 database에 record를 함께 insert 하는 기능에 대해서 설명하겠습니다. 설명하기 전에 이전 글에서 대용량 파일 업로드 기능에 대해서 다시 한번 review하고 다시 자세히 설명하겠습니다. 1. 대용량 파일 업로드 기능 (1G 이상 파일 업로드에도 문제가 없는 기능) 2. 파일 업로드시 upload 진행 상황을 Internet Explorer에서 볼수 있을것 (다음번 글에서 올리겠습니다.) WCPage.java : JSP page context와 request parameter를 저장하는 java class WCMultipartFormParser.java : http request stream을 parsing하는 java class WCMultipartFormElement.java : multipart form lement를 저장하는 java class // form html 일부분 시작 <form name="fParam" encType="multipart/form-data"> <input type="hidden" name="_cmd" value="file_data"> <input type="file" name="file"> </form> // form html 일부분 끝 form을 javascript에서 서버로 submit하면 아래와 같은 http request stream이 서버로 전달됩니다. // http request stream 시작 -----------------------------7d82efc203cc Content-Disposition: form-data; name="_cmd" uploadFile -----------------------------7d82efc203cc Content-Disposition: form-data; name="file"; filename="C:\test.txt" Content-Type: text/plain test -----------------------------7d82efc203cc-- // http request stream 끝 위의 request stream을 parsing하는 pseudo code 입니다. // pseudo code 시작 JSP page -> WCPage.initCtrl -> WCPage.initCtrl -> WCPage.isMultipart() -> WCMultipartFormParser.init() -> WCMultipartFormParserparseContent(oRequest) -> WCMultipartFormParserparseContentEx(oRequest) -> WCMultipartFormParserfindBoundary() : -----------------------------7d82efc203cc 이 부분을 parsing합니다. -> WCMultipartFormParserfindHeader() : Content-Disposition: form-data; name="_cmd" 이 부분을 parsing 합니다. -> WCMultipartFormElement.setHeader : header 정보를 element에 저장합니다. -> WCMultipartFormParser.procContent() : content body를 parsing 합니다. -> 임시파일에 파일 저장 : content type이 file인경우 -> parameter인경우 WCProperties m_rParam 에 parameter 이름과 value를 저장 -> WCMultipartFormParser.saveFile(sDir) -> WCMultipartFormElement.saveFile(sPathFile) // pseudo code 끝 대용량 파일을 서버에 업로드 하기 위해서는 업로드 되는 파일을 임시 directory에 임시 파일로 저장을 하고 다시 개발자가 원하는 디렉토리로 파일을 이동하는 방식을 사용합니다. (임시로 저장하는 이유는 memory에 파일을 모두 load하고 있을 수 없기 때문입니다.) 위의 코드에서 procContent에서 파일 내용을 임시 디렉토리에 저장합니다. WCMultipartFormParser.procContent 사용자가 파일을 임시 디렉토리에서 운영용 file directory로 이동하고자 하면 WCMultipartFormParser.saveFile(sDir) 을 호출합니다. 이 함수를 form에 있는 element들 중에서 file인 경우 이 파일을 사용자가 지정한 sDir로 이동을 합니다. // WCMultipartFormParser.saveFile code 시작 public void saveFile(String sDir) { try { Vector vElement = this.getElements(); int nCount = WCVector.size(vElement); for (int i=0;i<nCount;i++) { WCMultipartFormElement oElmt = (WCMultipartFormElement)WCVector.getObjAt(vElement,i); if (oElmt == null) { continue; } if (!oElmt.isFile()) { continue; } String sTempFileName = oElmt.getCloneFileName(); if (WCString.isEmpty(sTempFileName)) { continue; } String sUserDirectoryFile = WCString.buildFilePath(sDir,sTempFileName,"/"); oElmt.saveFile(sUserDirectoryFile); } } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.saveFile "+ex.toString()); } } // WCMultipartFormParser.saveFile code 끝 WCMultipartFormParser.saveFile 에서 WCMultipartFormElement.saveFile을 호출합니다. WCMultipartFormElement.saveFile 함수는 임시로 저장된 file을 사용자가 지정한 path의 file로 copy한 다음 임시 파일을 삭제하는 코드입니다. // WCMultipartFormElement.saveFile code 시작 public int saveFile(String sPathFile) { try { if (sPathFile == null) return -1; String sDir = WCString.getPath(sPathFile); WCSystem oSys = WCSystem.getInstance(); oSys.CreateDir(sDir); String sSaveFileName = sPathFile; setSaveFileName(sSaveFileName); File oSrcFile = new File(getTempFileName()); File oDestinationFile = new File(sSaveFileName); FileInputStream oFIS = null; FileOutputStream oFOS = null; try { oFIS = new FileInputStream(oSrcFile); oFOS = new FileOutputStream(oDestinationFile); byte[] oBuffer = new byte[1024 * 4]; int nRead = 0; while ((nRead = oFIS.read(oBuffer)) != -1) { oFOS.write(oBuffer, 0, nRead); } oFIS.close(); oFOS.close(); oFIS = null; oFOS = null; oSrcFile.delete(); } catch (Exception e) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.saveFile "+e.toString()); if (oFIS != null) { oFIS.close(); } if (oFOS != null) { oFOS.close(); } e.printStackTrace(); } } catch(IOException ioe) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.saveFile "+ioe.toString()); ioe.printStackTrace(); } return 0; } // WCMultipartFormElement.saveFile code 시작 파일을 사용자가 원하는 디렉토리로 복사를 하면서 file 관련 정보를 database에 insert하기 위해서는 WCMultipartFormParser 로 부터 상속받은 class를 정의합니다. 그리고 saveFile method를 재 정의합니다. 그리고 아래와 같이 함수를 정의합니다. // WCMultipartFormParser에서 상속받은 MyFormParser java class sample 시작 public class MyFormParser extends WCMultipartFormParser { public void saveFile(String sDir) { try { super.saveFile(sDir); Vector vElement = this.getElements(); int nCount = WCVector.size(vElement); for (int i=0;i<nCount;i++) { WCMultipartFormElement oElmt = (WCMultipartFormElement)WCVector.getObjAt(vElement,i); if (oElmt == null) { continue; } if (!oElmt.isFile()) { continue; } String sPhyFile = oElmt.getSaveFileName(); String sOrgName = oElmt.getName(); WCStmt oStmt = new WCStmt(); oStmt.executeUpdate("insert into tb_file (xxx) values(xxx,'"+sFile+"')",null,"WDLDatabasePool"); } } catch (Exception ex) { WCLog.getInstance().printLog("exception at MyFormParser.saveFile "+ex.toString()); } } } // WCMultipartFormParser에서 상속받은 MyFormParser java class sample 끝 물론 이와 같이 OOP의 inheritance와 overriding 기법을 사용하지 않고 // inheritance와 overriding 기법을 사용하지 않고 직접 호출방식으로 구현한 소스 일부분 시작 WCMultipartFormParser oFormParser = new WCMultipartFormParser(this); oFormParser.setDebug(true); oFormParser.init(); oFormParser.saveFile(sDir); Vector vElement = this.getElements(); int nCount = WCVector.size(vElement); for (int i=0;i<nCount;i++) { WCMultipartFormElement oElmt = (WCMultipartFormElement)WCVector.getObjAt(vElement,i); if (oElmt == null) continue; if (oElmt.isFile()) { String sName = oElmt.getName(); String sPhyFileName = oElmt.getSaveFileName(); WCStmt oStmt = new WCStmt(); oStmt.executeQuery("insert into table(xxx,xxx) values(xxx,'"+sPhyFileName+"')",null,sDsn); } } // inheritance와 overriding 기법을 사용하지 않고 직접 호출방식으로 구현한 소스 일부분 끝 이와 같이 직접 호출하는 방식을 사용해도 됩니다. 아래의 소스는 Web Development Library(http://www.webdevlib.net)에서 소스의 일부분만을 추출하여 재구성한 sample입니다. 첨부한 소스만으로도 어느정도 동작이 가능하지만 WCProperties,WCVector,WCLog,WCSystem,WCEnv 등의 파일은 http://www.webdevlib.net에서 다운받아 사용하십시요 소스의 일부분은 고의로 누락한 것은 아닙니다. 모든 소스를 설명하려니 너무 많기때문에 중요한 부분을 추출하여 sample로 구성하면서 최대한 이해가 쉽도록 재구성을 하였습니다. 제공하는 sample code는 3개의 파일로 구성됩니다 file_upload_progress1.jsp WCMultipartFormParser.java WCMultipartFormElement.java 아래의 sample에서 개발자는 WCMultipartFormParser.java 이부분에서 multipart form을 parsing하는 부분만을 참고하여 사용할 수도 있을 것입니다. 아무튼 개발자에게 유용한 코드가 되길 바랍니다. // file_upload_progress1.jsp 소스 시작 <%@ page language="java" import="wdl.*,java.util.*,java.sql.*,java.lang.*,java.io.*,java.io.File " contentType="text/html; charset=EUC-KR"%> <% WCPage oPage = new WCPage(); if (oPage.initCtrl(pageContext) > 0) { return; } %> <%@ include file="/wdl/src/java/WCMultipartFormParser.java"%> <%@ include file="/wdl/src/java/WCMultipartFormElement.java"%> <%! public class WCPage { public int initCtrl(javax.servlet.jsp.PageContext oPageContext) { return initCtrl( (javax.servlet.http.HttpServletRequest)oPageContext.getRequest() ,(javax.servlet.http.HttpServletResponse)oPageContext.getResponse() ,(javax.servlet.jsp.JspWriter)oPageContext.getOut() ,(javax.servlet.http.HttpSession)oPageContext.getSession() ,(javax.servlet.ServletContext)oPageContext.getServletContext() ,oPageContext ,(javax.servlet.ServletConfig)oPageContext.getServletConfig() ); } public int initCtrl( javax.servlet.http.HttpServletRequest oRequest ,javax.servlet.http.HttpServletResponse oResponse ,javax.servlet.jsp.JspWriter oOut ,javax.servlet.http.HttpSession oSession ,javax.servlet.ServletContext oApplication ,javax.servlet.jsp.PageContext oPageContext ,javax.servlet.ServletConfig oConfig) { try { m_request = oRequest; m_response = oResponse; m_out = oOut; m_session = oSession; m_application = oApplication; m_pageContext = oPageContext; m_config = oConfig; if (isMultipart()) { WCMultipartFormParser oFormParser = new WCMultipartFormParser(this); oFormParser.setDebug(true); oFormParser.init(); byte[] btDebugBuf = oFormParser.getDebugBuf(); String sDebug = new String(btDebugBuf); this.printOut("<pre>"); this.printOut(sDebug); this.printOut("</pre>"); WCProperties rParam = oFormParser.getParam(); this.printOut(rParam.serializeOut()); String sDir = "c:/tmp3"; oFormParser.saveFile(sDir); return 1; } } catch (Exception ex) { } return 0; } public javax.servlet.http.HttpServletRequest m_request = null; public javax.servlet.http.HttpServletResponse m_response = null; public javax.servlet.jsp.JspWriter m_out = null; public javax.servlet.http.HttpSession m_session = null; public javax.servlet.ServletContext m_application = null; public javax.servlet.jsp.PageContext m_pageContext = null; public javax.servlet.ServletConfig m_config = null; public javax.servlet.http.HttpSession getSession() { return m_session; } public javax.servlet.http.HttpServletRequest getRequest() { return m_request; } public javax.servlet.jsp.PageContext getPageContext() { return m_pageContext; } public boolean isMultipart() { HttpServletRequest oRequest = (javax.servlet.http.HttpServletRequest)m_request; String content_type = oRequest.getHeader("content-type"); if (WCString.indexOf(WCString.toUpper(content_type),"MULTIPART") == 0) { return true; } return false; } } %> <form name="fParam" encType="multipart/form-data"> <input type="hidden" name="_cmd" value="file_data"> <input type="file" name="file"> </form> <a href="javascript:uploadFile();">upload the file</a> <iframe id="ifrmAction" name="ifrmAction" width="0" height="0"></iframe> <script> function uploadFile() { var fParam = window.document.fParam; fParam._cmd.value = "uploadFile"; fParam.method = "post"; fParam.target = "_blank"; fParam.submit(); } </script> // file_upload_progress1.jsp 소스 끝 // WCMultipartFormParser.java 소스 시작 package wdl; import javax.servlet.*; import javax.servlet.http.*; import java.util.*; import java.io.*; public class WCMultipartFormParser { public String m_sCharset; private HttpServletResponse resp; private ServletContext m_oApp; public Vector m_vElement = null; public WCProperties m_rParam = null; public WCPage m_oPage = new WCPage(); public WCMultipartFormParser() { refresh(); } public WCMultipartFormParser(WCPage oPage) { refresh(); setPage(oPage); } public void init() { WCPage oPage = getPage(); if (oPage == null) return; HttpServletRequest oRequest = (javax.servlet.http.HttpServletRequest)oPage.getRequest(); parseContent(oRequest); } public void init(WCPage oPage) { setPage(oPage); init(); } public int m_nContentLength = 0; public byte[] m_btBuf = null; public int m_nBufIdx = 0; public int m_nBoundaryLen = 0; public byte m_btBoundary[] = null; public int m_nBufReadSize = 0; public int m_nBufAllocSize = 1024*64; public int m_nCurrentBuffer = 0; public int m_nBufferCount = 0; public int m_nAccumRead = 0; public InputStream m_oInputStream = null; public int m_nAccumBufIdx = 0; public String getEnvValue(String sProp) { WCEnv env = WCEnv.getInstance(); if (env != null) { WCProperties rcd = env.getProperties(); if (rcd != null) { String sVal = rcd.getStrValue(sProp); return sVal; } } return ""; } public void refresh() { m_vElement = new Vector(); m_rParam = new WCProperties(); String sSrcCharset = getEnvValue("charset"); if (WCString.isEmpty(sSrcCharset)) { sSrcCharset = "KSC5601"; } m_sCharset = sSrcCharset; m_nContentLength = 0; m_btBuf = null; m_nBufIdx = 0; m_nBoundaryLen = 0; m_btBoundary = null; m_nBufReadSize = 0; m_nBufAllocSize = 1024*64; m_nCurrentBuffer = 0; m_nAccumRead = 0; m_oInputStream = null; m_nAccumBufIdx = 0; m_nBufferCount = 0; m_nPrevAccumBufIdx = 0; } public byte[] setByte(byte btBuf[],int nIdx,byte btChar) { { int nSize = 0; if (btBuf != null) nSize = btBuf.length; if (nIdx >= nSize) { int nMax = nIdx+32; byte btNew[] = new byte[nMax]; for (int i=0;i<nMax;i++) { btNew[i] = 0; } for (int i=0;i<nSize;i++) { btNew[i] = btBuf[i]; } btNew[nIdx] = btChar; btBuf = btNew; } else { btBuf[nIdx] = btChar; } return btBuf; } } public byte[] m_btDebugBuf = null; public byte[] getDebugBuf() { return m_btDebugBuf; } public byte[] append(byte btBuf[],byte btAppend[],int nLen) { try { if (btAppend == null) return null; if (btBuf == null) { btBuf = new byte[nLen]; } int nSize = btBuf.length; int nNewSize = nSize+nLen; byte btNew[] = new byte[nNewSize]; for (int i=0;i<nNewSize;i++) { btNew[i] = 0; } for (int i=0;i<nSize;i++) { btNew[i] = btBuf[i]; } for (int i=0;i<nLen;i++) { btNew[i+nSize] = btAppend[i]; } btBuf = btNew; return btBuf; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.append "+ex.toString()); } return null; } public byte[] copyBytes(byte btSrc[],int nStartIdx,int nEndIdx) { try { int nLen = nEndIdx-nStartIdx; if (nLen <= 0) return null; int nAlloc = nLen; byte btNew[] = new byte[nAlloc]; for (int i=0;i<nAlloc;i++) { btNew[i] = 0; } for (int i=0;i<nLen;i++) { btNew[i] = btSrc[i+nStartIdx]; } return btNew; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.copyBytes "+ex.toString()); } return null; } public void parseContent(HttpServletRequest oRequest) { try { Vector vDataHeader = parseContentEx(oRequest); } catch(Exception crfe) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.parseContent "+crfe.toString()); crfe.printStackTrace(); } } public void setResponse(HttpServletResponse resp) { this.resp = resp; } public void setContext(ServletContext oApp) { this.m_oApp = oApp; } public boolean findBoundary() { try { m_btBoundary = null; m_nBoundaryLen = 0; int nLen = 0; m_btBoundary = setByte(m_btBoundary,nLen,(byte)13); nLen ++; m_btBoundary = setByte(m_btBoundary,nLen,(byte)10); nLen ++; boolean bBoundaryFound = false; while (isEof() != true) { byte btByte = getByte(); if (btByte == 13) { bBoundaryFound = true; m_nBoundaryLen = nLen; getByte(); break; } m_btBoundary = setByte(m_btBoundary,nLen,btByte); nLen ++; } if (bBoundaryFound == true) { m_btBoundary = copyBytes(m_btBoundary,0,nLen); return true; } } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.findBoundary "+ex.toString()); } return false; } public String findHeader() { try { int nLen = 0; byte btHeader[] = null; boolean bFound = false; byte btByte = 0; byte btByte2 = 0; while (isEof() != true) { btByte = getByte(); btByte2 = getByte(); btByte2 = getByte(); putBackByte(); putBackByte(); if (btByte == 13 && btByte2 == 13) { getByte(); getByte(); getByte(); bFound = true; break; } btHeader = setByte(btHeader,nLen,btByte); nLen ++; } btHeader = copyBytes(btHeader,0,nLen); String sDataHeader = new String(btHeader,m_sCharset); return sDataHeader; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.findHeader "+ex.toString()); } return null; } public boolean isBoundary() { try { int boundaryKeyPosition = 0; boundaryKeyPosition = 0; boolean binaryEndFound = false; binaryEndFound = false; byte btByte = (byte)0; int nLen = 0; while (isEof() != true) { btByte = getByte(); nLen ++; if (btByte == m_btBoundary[boundaryKeyPosition]) { if (boundaryKeyPosition == m_nBoundaryLen-1 ) { binaryEndFound = true; getByte(); getByte(); break; } boundaryKeyPosition++; } else { for (int i=0;i<nLen;i++) { putBackByte(); } break; } } return binaryEndFound; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.isBoundary "+ex.toString()); } return false; } public void putBackByte() { m_nBufIdx --; m_nAccumBufIdx --; if (m_nBufIdx < 0) { m_nCurrentBuffer --; if (m_nCurrentBuffer < 0) { } m_nBufIdx = (m_nBufAllocSize/2) - 1; } } public boolean m_bDebug = false; public void setDebug(boolean bDebug) { m_bDebug = bDebug; } public boolean isDebug() { return m_bDebug; } public boolean isEof() { if (m_nAccumBufIdx < m_nContentLength) { return false; } return true; } public byte getByte() throws Exception { byte btData = getByteEx(); setProgress(m_nAccumBufIdx); return btData; } public byte getByteEx() throws Exception { try { if (m_oInputStream == null) { m_oInputStream = m_oPage.getRequest().getInputStream(); } if (m_btBuf == null) { m_btBuf = new byte[m_nBufAllocSize+32]; if (m_btBuf == null) { return (byte)0; } for (int i=0;i<m_nBufAllocSize+32;i++) { m_btBuf[i] = (byte)0; } } if (m_nBufIdx >= m_nBufReadSize && m_nAccumRead < m_nContentLength && m_nBufferCount == m_nCurrentBuffer) { if (m_nBufReadSize == m_nBufAllocSize/2) { m_nBufReadSize = 0; m_nCurrentBuffer ++; m_nBufferCount ++; } int nMaxRead = m_nBufAllocSize/2 - m_nBufReadSize; if (nMaxRead > m_nContentLength-m_nAccumRead) { nMaxRead = m_nContentLength-m_nAccumRead; } int nRead = m_oInputStream.read(m_btBuf ,(m_nCurrentBuffer%2)*(m_nBufAllocSize/2) + m_nBufReadSize ,nMaxRead); if (this.isDebug()) { m_btDebugBuf = this.append(m_btDebugBuf,m_btBuf,nRead); } m_nBufReadSize += nRead; m_nAccumRead += nRead; if (m_nBufReadSize >= m_nBufAllocSize/2) { } m_nBufIdx = m_nBufIdx % (m_nBufAllocSize/2); } byte btByte = m_btBuf[(m_nCurrentBuffer%2)*(m_nBufAllocSize/2) + m_nBufIdx]; m_nBufIdx ++; if (m_nBufIdx == m_nBufAllocSize/2 && m_nCurrentBuffer < m_nBufferCount) { m_nCurrentBuffer ++; m_nBufIdx = 0; } m_nAccumBufIdx ++; return btByte; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.getByteEx "+ex.toString()); setProgress(m_nContentLength); Exception oEx = new Exception("exception at getByte"); throw oEx; } } public int procContent() { try { if (m_oCurElement.isFile()) { try { FileOutputStream oFileStream = m_oCurElement.createTempFile(); if (oFileStream == null) { return -1; } int nBufSize = 1024*4; byte[] btBuf = new byte[nBufSize]; int nLen = 0; byte btByte = 0; while (isEof() != true) { btByte = getByte(); if (btByte == (byte)13) { putBackByte(); if (isBoundary() == true) { break; } btByte = getByte(); } btBuf[nLen] = btByte; nLen ++; if (nLen >= nBufSize) { if (oFileStream != null) { oFileStream.write(btBuf,0,nBufSize); } nLen = 0; } } if (nLen > 0) { if (oFileStream != null) { oFileStream.write(btBuf,0,nLen); } } m_oCurElement.closeTempFile(); } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.procContent "+ex.toString()); m_oCurElement.closeTempFile(); m_oCurElement.deleteTempFile(); return -1; } } else { byte btContent[] = null; int nLen = 0; byte btByte = 0; while (isEof() != true) { if (isBoundary() == true) break; btByte = getByte(); btContent = setByte(btContent,nLen,btByte); nLen ++; } String sValue = null; if (nLen > 0) { btContent = copyBytes(btContent,0,nLen); sValue = new String(btContent,m_sCharset); } else { sValue = ""; } String sProp = m_oCurElement.getFieldName(); if (btContent != null) { } else { } if (m_rParam == null) { m_rParam = new WCProperties(); } m_rParam.addValue(sProp,sValue); m_oCurElement.setValue(sValue); } } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.procContent "+ex.toString()); return -1; } return 0; } public WCMultipartFormElement m_oCurElement = null; public Vector parseContentEx(HttpServletRequest oRequest) { int nLen = oRequest.getContentLength(); setContentLength(nLen); m_nBufIdx = 0; m_btBoundary = null; m_nBoundaryLen = 0; int nState = 0; try { m_nBufReadSize = 0; int nRead = 0; m_oInputStream = oRequest.getInputStream(); while (isEof() != true) { if (nState == 0) { findBoundary(); nState = 100; } else if (nState == 100) { String sHeader = findHeader(); if (sHeader != null) { nState = 200; m_oCurElement = new WCMultipartFormElement(this); m_oCurElement.setHeader(sHeader); if (m_vElement == null) m_vElement = new Vector(); m_vElement.addElement(m_oCurElement); } nState = 200; } else if (nState == 200) { int nRet = procContent(); if (nRet < 0) { } nState = 100; } } } catch(IOException ioe) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.parseContentEx "+ioe.toString()); ioe.printStackTrace(); } setProgress(m_nAccumBufIdx); return m_vElement; } public Vector getElements() { return m_vElement; } public String getFileName() { Vector vElement = getElements(); int nCount = WCVector.size(vElement); for (int i=0;i<nCount;i++) { WCMultipartFormElement oElmt = (WCMultipartFormElement)WCVector.getObjAt(vElement,i); if (oElmt == null) continue; if (oElmt.isFile()) { return oElmt.getName(); } } return null; } public void deleteTempFile() { Vector vElement = getElements(); int nCount = WCVector.size(vElement); for (int i=0;i<nCount;i++) { WCMultipartFormElement oElmt = (WCMultipartFormElement)WCVector.getObjAt(vElement,i); if (oElmt == null) continue; if (oElmt.isFile()) { oElmt.deleteTempFile(); } } } public String getPathName() { Vector vElement = getElements(); int nCount = WCVector.size(vElement); for (int i=0;i<nCount;i++) { WCMultipartFormElement oElmt = (WCMultipartFormElement)WCVector.getObjAt(vElement,i); if (oElmt == null) continue; if (oElmt.isFile()) { return oElmt.getPathName(); } } return null; } public int getFileCount() { try { int nRet = 0; Vector vElement = getElements(); int nCount = WCVector.size(vElement); for (int i=0;i<nCount;i++) { WCMultipartFormElement oElmt = (WCMultipartFormElement)WCVector.getObjAt(vElement,i); if (oElmt == null) continue; if (oElmt.isFile()) { nRet ++; } } return nRet; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.getFileCount "+ex.toString()); } return 0; } public void setCharset(String sCharset) { m_sCharset = sCharset; } public String getCharset() { return m_sCharset; } public WCProperties getParam() { if (m_rParam == null) m_rParam = new WCProperties(); return m_rParam; } public WCPage getPage() { return m_oPage; } public void setPage(WCPage oPage) { m_oPage = oPage; } public int getContentLength() { return m_nContentLength; } public int getRead() { return m_nAccumBufIdx; } public void setContentLength(int nLen) { m_nContentLength = nLen; if (m_oPage != null) { String sLen = new String(""+m_nContentLength); HttpSession oSession = m_oPage.getSession(); if (oSession != null) { oSession.putValue("wdl.WCMultipartFormParser.contentLength",sLen); } } } public int m_nPrevAccumBufIdx = 0; public void setProgress(int nParam) { int nRead = nParam; m_nAccumBufIdx = nRead; if (m_nAccumBufIdx - m_nPrevAccumBufIdx < 1024 && (m_nAccumBufIdx < m_nContentLength)) { return; } m_nPrevAccumBufIdx = m_nAccumBufIdx; if (m_oPage != null) { String sLen = new String(""+m_nAccumBufIdx); HttpSession oSession = m_oPage.getSession(); if (oSession != null) { oSession.putValue("wdl.WCMultipartFormParser.read",sLen); } } } public void saveFile(String sDir) { try { Vector vElement = this.getElements(); int nCount = WCVector.size(vElement); for (int i=0;i<nCount;i++) { WCMultipartFormElement oElmt = (WCMultipartFormElement)WCVector.getObjAt(vElement,i); if (oElmt == null) { continue; } if (!oElmt.isFile()) { continue; } String sTempFileName = oElmt.getCloneFileName(); if (WCString.isEmpty(sTempFileName)) { continue; } String sUserDirectoryFile = WCString.buildFilePath(sDir,sTempFileName,"/"); oElmt.saveFile(sUserDirectoryFile); } } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormParser.saveFile "+ex.toString()); } } } // WCMultipartFormParser.java 소스 끝 // WCMultipartFormElement.java 소스 시작 package wdl; import javax.servlet.*; import javax.servlet.http.*; import java.util.*; import java.io.*; public class WCMultipartFormElement { private boolean m_bFile = false; private String fieldName = null; private String fullPathName = null; private String m_sFileName = null; private String fileExtension = null; private String pathName = null; private String contentType = null; private String contentDisposition = null; private String mimeType = null; private String mimeSubType = null; private String m_sValue = null; public WCMultipartFormParser m_oParser; public WCMultipartFormElement(WCMultipartFormParser oParser) { setMultipartFormParser(oParser); m_sValue = null; m_rUserData = new WCProperties(); m_oFileOutputStream = null; } public void setMultipartFormParser(WCMultipartFormParser oParser) { m_oParser = oParser; } public WCMultipartFormParser getMultipartFormParser() { return m_oParser; } public FileOutputStream createTempFile() { try { String sSourceFileName = getFileName(); if (WCString.isEmpty(sSourceFileName)) { return null; } java.io.File oFile = null; m_sTempFileName = getTempFile(sSourceFileName); oFile = new java.io.File(m_sTempFileName); m_oFileOutputStream = new FileOutputStream(oFile); } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.createTempFile "+ex.toString()); } return m_oFileOutputStream; } public void closeTempFile() { try { if (m_oFileOutputStream != null) { m_oFileOutputStream.close(); } m_oFileOutputStream = null; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.closeTempFile "+ex.toString()); } } public FileOutputStream getTempFileOutputStream() { FileOutputStream oRet = null; oRet = m_oFileOutputStream; return oRet; } public void setHeader(String headerString) { try { if (headerString == null) return; this.m_bFile = headerString.indexOf("filename=\"") > 0; int startPosition = headerString.indexOf("name=\"") + "name=\"".length(); int endPosition = headerString.indexOf("\"", startPosition); if( (startPosition > 0) && (endPosition > 0) ) { this.fieldName = headerString.substring(startPosition, endPosition); } if (this.isFile()) { startPosition = headerString.indexOf("filename=\"") + "filename=\"".length(); endPosition = headerString.indexOf("\"", startPosition); if( (startPosition > 0) && (endPosition > 0) ) { this.fullPathName = headerString.substring(startPosition, endPosition); } startPosition = headerString.indexOf("Content-Type: ") + "Content-Type: ".length(); if( startPosition > 0 ) { this.contentType = headerString.substring(startPosition); } startPosition = headerString.indexOf("Content-Disposition: ") + "Content-Disposition: ".length(); endPosition = headerString.indexOf(";", startPosition); this.contentDisposition = headerString.substring(startPosition, endPosition); if ((startPosition = this.fullPathName.lastIndexOf(47)) > 0) { this.m_sFileName = this.fullPathName.substring(startPosition + 1); } else if((startPosition = this.fullPathName.lastIndexOf(92)) > 0) { this.m_sFileName = this.fullPathName.substring(startPosition + 1); } else { this.m_sFileName = this.fullPathName; } if((startPosition = this.m_sFileName.lastIndexOf(46)) > 0 ) { this.fileExtension = this.m_sFileName.substring(startPosition+1); } else { this.fileExtension = ""; } if((startPosition = this.contentType.indexOf("/")) > 0) { this.mimeType = this.contentType.substring(0,startPosition); this.mimeSubType = this.contentType.substring(startPosition+1); } else { this.mimeType = this.contentType; this.mimeSubType = this.contentType; } } } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.WCMultipartFormElement "+ex.toString()); } } public boolean isFile() { return this.m_bFile; } public boolean isValidFile() { if (this.m_bFile == true && !WCString.isEmpty(getName())) { return true; } return false; } public String getFieldName() { return this.fieldName; } public String getFullPathName() { return this.fullPathName; } public String getFileName() { return this.m_sFileName; } public String getName() { return getFileName(); } public String getPathName() { return this.pathName; } public String getFileExtension() { return this.fileExtension; } public String getContentType() { return this.contentType; } public String getContentDisposition() { return this.contentDisposition; } public String getMimeType() { return this.mimeType; } public String getMimeSubType() { return this.mimeSubType; } public void setValue(String sValue) { m_sValue = sValue; } public String getValue() { return m_sValue; } private int size = 0; private byte [] contents; public WCProperties m_rUserData = new WCProperties(); public String m_sTempDirectory = ""; public void setTempDirectory(String sVal) { m_sTempDirectory = sVal; } public String getTempDirectory() { if (WCString.isEmpty(m_sTempDirectory)) { m_sTempDirectory = WCString.nullCheck(getEnvValue("tempdir"),getEnvValue("wdl.tempdir")); if (WCString.isEmpty(m_sTempDirectory)) { String sPath = getHome(); m_sTempDirectory = WCString.buildFilePath(sPath,"wdl/tmp","/"); } } return m_sTempDirectory; } public String getHome() { String sHome = WCString.trim(getEnvValue("wdl.home")); if (WCString.isEmpty(sHome)) { sHome = WCString.left(WCEnv.getInstance().getEnvFile(),"/WEB-INF"); } return sHome; } public String getTempName() { try { java.util.Date dat = new java.util.Date(); java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat ("yyyy"); String sYear = formatter.format(dat); formatter = new java.text.SimpleDateFormat("MM"); String sMonth = formatter.format(dat); formatter = new java.text.SimpleDateFormat("dd"); String sDate = formatter.format(dat); formatter = new java.text.SimpleDateFormat("HH"); String sHour = formatter.format(dat); formatter = new java.text.SimpleDateFormat("mm"); String sMin = formatter.format(dat); formatter = new java.text.SimpleDateFormat("ss"); String sSec = formatter.format(dat); int nRand0 = (int)(Math.random()*10000); int nRand1 = (int)(Math.random()*10000); int nRand2 = (int)(Math.random()*10000); String sName = sYear+sMonth+sDate+sHour+sMin+sSec+"_"+nRand0+"_"+nRand1+"_"+nRand2; return sName; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.getTempName "+ex.toString()); } return ""; } public String getTempFile(String sSourceFileName) { try { String sExt = WCString.nullCheck(WCString.getFileExt(sSourceFileName),""); String sName = getTempName(); if (!WCString.isEmpty(sExt)) { sName += "."+sExt; } String sDir = getTempDirectory(); WCSystem oSys = WCSystem.getInstance(); oSys.CreateDir(sDir); String sRet = WCString.buildFilePath(sDir,sName,"/"); return sRet; } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.getTempFile "+ex.toString()); } return null; } public String getEnvValue(String sProp) { WCEnv env = WCEnv.getInstance(); if (env != null) { WCProperties rcd = env.getProperties(); if (rcd != null) { String sVal = rcd.getStrValue(sProp); return sVal; } } return ""; } public FileOutputStream m_oFileOutputStream = null; public String m_sTempFileName = null; public String getTempFileName() { return m_sTempFileName; } public int getSize() { return this.size; } public void setSize(int size) { this.size = size; } public byte [] getContents() { return this.contents; } public byte getContentByte(int index) { return this.contents[index]; } public void setContents(byte[] contents) { this.contents = contents; } public void setContentByte(int index, byte content) { this.contents[index] = content; } public String m_sSaveFileName = null; public String getSaveFileName() { return m_sSaveFileName; } public void setSaveFileName(String sFileName) { m_sSaveFileName = sFileName; } public int saveFile(String sPathFile) { try { if (sPathFile == null) return -1; String sDir = WCString.getPath(sPathFile); WCSystem oSys = WCSystem.getInstance(); oSys.CreateDir(sDir); String sSaveFileName = sPathFile; setSaveFileName(sSaveFileName); File oSrcFile = new File(getTempFileName()); File oDestinationFile = new File(sSaveFileName); FileInputStream oFIS = null; FileOutputStream oFOS = null; try { oFIS = new FileInputStream(oSrcFile); oFOS = new FileOutputStream(oDestinationFile); byte[] oBuffer = new byte[1024 * 4]; int nRead = 0; while ((nRead = oFIS.read(oBuffer)) != -1) { oFOS.write(oBuffer, 0, nRead); } oFIS.close(); oFOS.close(); oFIS = null; oFOS = null; oSrcFile.delete(); } catch (Exception e) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.saveFile "+e.toString()); if (oFIS != null) { oFIS.close(); } if (oFOS != null) { oFOS.close(); } e.printStackTrace(); } } catch(IOException ioe) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.saveFile "+ioe.toString()); ioe.printStackTrace(); } return 0; } public WCProperties getUserData() { return m_rUserData; } public void setUserData(String sProp,String sValue) { if (m_rUserData == null) m_rUserData = new WCProperties(); m_rUserData.setValue(sProp,sValue); } public void setUserData(String sProp,int nValue) { if (m_rUserData == null) m_rUserData = new WCProperties(); m_rUserData.setValue(sProp,nValue); } public void deleteTempFile() { try { File oFile = new File(m_sTempFileName); boolean bSucc = oFile.delete(); } catch (Exception ex) { WCLog.getInstance().printLog("exception at WCMultipartFormElement.deleteTempFile "+ex.toString()); } } public String getCloneFileName() { String sFullPathName = this.getFullPathName(); if (WCString.isEmpty(sFullPathName)) { return null; } String sExt = WCString.getFileExt(sFullPathName); String sTempName = this.getTempName(); String sTempFileName = sTempName+"."+sExt; return sTempFileName; } public long m_nFileSize = -1; public long getFileSize() { if (m_nFileSize > (long)0) return m_nFileSize; String sFileName = getSaveFileName(); try { File oFile = new File(sFileName); if (oFile != null) { m_nFileSize = oFile.length(); return m_nFileSize; } } catch (Exception ex) { } sFileName = m_sTempFileName; try { File oFile = new File(sFileName); if (oFile != null) { m_nFileSize = oFile.length(); return m_nFileSize; } } catch (Exception ex) { } return 0; } } // WCMultipartFormElement.java 소스 끝 첨부파일 : file_upload_progress1.zip file_upload_progress1.jsp WCMultipartFormParser.java WCMultipartFormElement.java 출처 : 고급 웹 UI 개발 라이브러리 Web Development Library 소스공개 : http://www.webdevlib.net | |||
|
'01.JAVA/Java'에 해당되는 글 199건
- 2009.06.16 multipart form parser - http file upload, database 저장 java class 연재2
- 2009.06.16 multipart form parser - http file upload 기능 java class 연재1
- 2009.06.16 java 디렉토리 만들기 예제
- 2009.06.13 Teach Your Self Java Programming In 21 Days
- 2009.06.13 Java Performance Tuning 2000
- 2009.06.13 beginning-jsp-jsf-and-tomcat-web-development-from-novice-to-professional
- 2009.06.08 Java에서 HTML 태그를 제거하는 정규식 적용 1
- 2009.06.07 java enum - enum의 메쏘드
- 2009.06.04 tomcat 사용 : java.lang.OutOfMemoryError: Java heap space 2
- 2009.06.04 java.lang.OutOfMemoryError
- 2009.06.04 emctl start dbconsole / 오라클 em 안될때
- 2009.05.30 JAVA basic(scjp 1[1].5)
- 2009.04.28 java 파일 저장할때.. 중복이름 체크 2
- 2009.04.28 CLOB+MULTI UPLOAD
- 2009.04.24 [JAVA] Timer를 이용하여 일정시간에 작업수행하기(Schedule)
- 2009.04.14 TCP 네트워크로부터 읽고 쓰기
- 2009.04.07 자바에서 C/C++ 사용하기
- 2009.04.07 [String 비교하기] .equals()와 ==은 다른가요?
- 2009.04.06 query를 수행하는 두가지 방법
- 2009.04.06 자바스크립트 옆에는 <noscript>를 넣자
- 2009.04.06 [java]File에 이어쓰기
- 2009.04.06 클래스 PrintWriter 1
- 2009.04.01 윈도우즈 RDP 포트 변경하기 1
- 2009.03.23 java
- 2009.03.23 여러글자로 된 문자열 변환
- 2009.03.23 문자열 내의 특정한 문자열을 모두 지정한 다른 문자열로 변경 1
- 2009.02.25 Web Java Class Decompiler 이용 방법
- 2009.02.23 [JAVA] java환경변수 & Tomcat환경변수 & Servlet 설정
- 2009.02.23 'Development/Java'
- 2009.02.23 java transaction 처리
출처 : http://www.javanuri.net/devforum/boardView.jsp?pg=4&menuId=12&Id=305711&gb=qna multipart form parser - http file upload 기능 java class 연재1 다음과 같은 기능의 file upload 프로그램을 java code를 소개하겠습니다. 1. 대용량 파일 업로그 기능 (1G 이상 파일 업로드에도 문제가 없는 기능) 2. 파일 업로드시 upload 진행 상황을 Internet Explorer에서 볼수 있을것 위의 기능 중에서 이번 글에서는 1번 기능에 대해서 설명을 하겠습니다. 2번 기능은 AJAX 기능을 이요하여 구현이 가능하며 이후 글에서 차차 설명하겠습니다. 첨부하는 소스코드는 실제 프로젝트에서 사용하는데 무리가 없는 소스입니다. (많은 시스템에서 실제 운영중인 코드 입니다.) ActiveX를 제외한 일반적인 파일 업로드 프로그램은 클라이언트에서 서버로 전달된 multipart form 형식의 input stream을 parsing하여 어떤 값이 파일이고 어떤 값이 form의 input 값인지를 결정하여 파일은 file system에 저장하는 방식입니다. 다음과 같은 html form을 submit하겠습니다. 선택한 파일은 c:\test.txt 파일입니다. <form name="fParam" encType="multipart/form-data"> <input type="hidden" name="_cmd" value="file_data"> <input type="file" name="file"> </form> 서버에 전달되는 stream은 다음과 같습니다. -----------------------------7d82efc203cc Content-Disposition: form-data; name="_cmd" uploadFile -----------------------------7d82efc203cc Content-Disposition: form-data; name="file"; filename="C:\test.txt" Content-Type: text/plain test -----------------------------7d82efc203cc-- 이와 같은 stream을 parsing하는 java class인 WCMultipartFormParser,WCMultipartFormElement를 소개합니다. 위와 같은 stream을 parsing하면 form element가 2개이고 하나는 parameter(_cmd)이고 하나는 파일(c:\test.txt)입니다. WCMultipartFormParser -> WCMultipartFormElement : _cmd=uploadFile -> WCMultipartFormElement : file c:\test.txt WCMultipartFormParser(parser라고 간략히 부르겠습니다.) WCMultipartFormElement(element라고 간략히 부르겠습니다.) 의 구조를 설명하겠습니다. 대용량 파일을 서버에 업로드 하려면 input stream으로 부터 전달된 file의 data를 memory에 모두 loading하면 안됩니다. 만약 5G file을 uploading한다면 이를 memory에 올릴 수가 없기때문입니다. 따라서 upload된 내용을 parsing하면서 임시 directory에 저장을 합니다. 다음과 같은 순서로 설명을 하겠습니다. 1. input stream을 buffering하는 방법 2. parser에서 호출되는 순서 3. file을 임시파일로 저장(다음번 글에서 설명) 4. 임시로 저장된 파일을 사용자가 정의하는 directory로 복사(다음번 글에서 설명) parser는 input stream으로부터 읽어들인 내용을 double buffering하여 관리합니다. double buffering에 대해서 간단히 설명드리겠습니다. 하나의 buffer를 반으로 나누고 한쪽 부분에 input stream에서 읽은 내용을 임시로 저장합니다. 그리고 이 내용을 parsing을 합니다. 한쪽 부분 buffer를 모두 parsing을 하면 buffer의 나머지 반쪽에 다시 input stream에서 읽은 내용을 임시로 저장합니다. 이렇게 double buffering을 하는 이유는 한쪽의 buffer를 parsing하다가 parsing이 잘못되어 rollback을 하는 경우 한쪽 buffer에서만 rollback해서 안되는 경우가 있습니다. 예를 들어 보이겠습니다. buffer size = 20이고 반으로 나눈 한쪽 버퍼는 10 size가 됩니다. 1234567890 1234567890 abcdefghij kl 아래와 같이 kl까지 parsing을 했는제 잘못 parsing을 해서 rollback 즉 gh부터 parsing을 다시 해야 하는 경우 double buffering 기법을 사용합니다. 그러면 buffer size를 크게 하면 되지않느냐 라고 질문 할 수 있습니다. 그렇지 않습니다. buffer size가 아무리 커도 rollback에 대한 여분을 충분히 확보할 수가 없습니다. 즉 이전에 사용하던 buffer를 지우지 말고 보유하고 있어야 충분한 rollback을 확보할 수 있습니다. 첨부한 source 코드에서 getByte는 하나의 input stream에서 1 byte 씩 읽어들입니다. getByte에서 호출하는 getByteEx에서 double buffering 처리를 합니다. public byte getByte() throws Exception input stream을 parsing 하는 부분에서는 이제 byte단위로 parsing하다가 문제가 있으면 rollback을 할 수 있습니다. 위에서 sample로 보여드린 form 즉 _cmd,file을 parsing하는 방법에 대해 설명하겠습니다. WCMultipartFormParser.init() -> parseContent(oRequest) -> parseContentEx(oRequest) -> findBoundary() : -----------------------------7d82efc203cc 이 부분을 parsing합니다. -> findHeader() : Content-Disposition: form-data; name="_cmd" 이 부분을 parsing 합니다. -> WCMultipartFormElement.setHeader : header 정보를 element에 저장합니다. -> procContent() : content body를 parsing 합니다. -> 임시파일에 파일 저장 : content type이 file인경우 -> parameter인경우 WCProperties m_rParam 에 parameter 이름과 value를 저장 위와 같은 구조로 form을 parsing합니다. <form name="fParam" encType="multipart/form-data"> <input type="hidden" name="_cmd" value="file_data"> <input type="file" name="file"> </form> 이 form을 submit할때 request parameter 값은 WCMultipartFormParser.getParam()을 호출하면 parsing되어 저장된 request parameter값을 얻어올 수 있습니다. 그리고 아래의 소스에서 WCMultipartFormParser.saveFile(sDir)을 호출하여 임시 저장된 file들을 개발자가 원하는 directory로 이동을 합니다. 다음번 글에서는 file을 저장하는 구조에 대해서 설명하겠습니다. 아래의 소스 코드는 JSP 에서 WCPage의 object를 생성하고 WCMultipartFormParser의 기능을 호출하여 multipart form을 parsing하고 파일을 저장하는 sample code입니다. WCPage.initCtrl -> WCPage.initCtrl -> WCPage.isMultipart : file을 submit한 겨우인지를 검사 -> WCMultipartFormParser.init() if (isMultipart()) { WCMultipartFormParser oFormParser = new WCMultipartFormParser(this); oFormParser.setDebug(true); oFormParser.init(); byte[] btDebugBuf = oFormParser.getDebugBuf(); String sDebug = new String(btDebugBuf); this.printOut("<pre>"); this.printOut(sDebug); this.printOut("</pre>"); WCProperties rParam = oFormParser.getParam(); this.printOut(rParam.serializeOut()); String sDir = "c:/tmp3"; oFormParser.saveFile(sDir); return 1; } 여기서 잠깐 WCPage에 대해서 설명하겠습니다. WCPage는 JSP 혹은 Servlet에 대한 정보를 저장하고 있는 Object입니다. WCMultipartFormParser 혹은 WCMultipartFormElement에서 request 혹은 response object를 access할때 WCPage를 통하여 access할 수 있습니다. WCPage.initCtrl에서 pageContext를 넘김으로 WCPage에서 JSP 관련 context를 모두 저장하고 또한 page로 전달된 parameter를 WCPage가 모두 저장하고 있습니다. 여기서 sample로 제공하는 WCPage java class는 WDL(Web Development Library)에서 제공하는 WCPage.java에서 필요한 부분만 추출하여 새로 구성한 sample입니다. (개발자들이 이해를 쉽게 하기 위해서 일부러 추출을 하였습니다. http://www.webdevlib.net 에서 모든 소스코드는 무료로 다운로드 받을 수 있습니다.) 첨부한 소스만으로도 어느정도 동작이 가능하지만 WCProperties,WCVector,WCLog,WCSystem,WCEnv 등의 파일은 http://www.webdevlib.net에서 다운받아 사용하십시요 소스의 일부분은 고의로 누락한 것은 아닙니다. 모든 소스를 설명하려니 너무 많기때문에 중요한 부분을 추출하여 sample로 구성하면서 최대한 이해가 쉽도록 재구성을 하였습니다. 첨부파일에는 3개의 파일이 zip으로 묶여있습니다. WCMultipartFormParser.java WCMultipartFormElement.java file_upload_progress1.jsp -- file_upload_progress1.jsp 소스 시작 <%@ page language="java" import="wdl.*,java.util.*,java.sql.*,java.lang.*,java.io.*,java.io.File " contentType="text/html; charset=EUC-KR"%> <% WCPage oPage = new WCPage(); if (oPage.initCtrl(pageContext) > 0) { return; } %> <%@ include file="/wdl/src/java/WCMultipartFormParser.java"%> <%@ include file="/wdl/src/java/WCMultipartFormElement.java"%> <%! public class WCPage { public int initCtrl(javax.servlet.jsp.PageContext oPageContext) { return initCtrl( (javax.servlet.http.HttpServletRequest)oPageContext.getRequest() ,(javax.servlet.http.HttpServletResponse)oPageContext.getResponse() ,(javax.servlet.jsp.JspWriter)oPageContext.getOut() ,(javax.servlet.http.HttpSession)oPageContext.getSession() ,(javax.servlet.ServletContext)oPageContext.getServletContext() ,oPageContext ,(javax.servlet.ServletConfig)oPageContext.getServletConfig() ); } public int initCtrl( javax.servlet.http.HttpServletRequest oRequest ,javax.servlet.http.HttpServletResponse oResponse ,javax.servlet.jsp.JspWriter oOut ,javax.servlet.http.HttpSession oSession ,javax.servlet.ServletContext oApplication ,javax.servlet.jsp.PageContext oPageContext ,javax.servlet.ServletConfig oConfig) { try { m_request = oRequest; m_response = oResponse; m_out = oOut; m_session = oSession; m_application = oApplication; m_pageContext = oPageContext; m_config = oConfig; if (isMultipart()) { WCMultipartFormParser oFormParser = new WCMultipartFormParser(this); oFormParser.setDebug(true); oFormParser.init(); byte[] btDebugBuf = oFormParser.getDebugBuf(); String sDebug = new String(btDebugBuf); this.printOut("<pre>"); this.printOut(sDebug); this.printOut("</pre>"); WCProperties rParam = oFormParser.getParam(); this.printOut(rParam.serializeOut()); String sDir = "c:/tmp3"; oFormParser.saveFile(sDir); return 1; } } catch (Exception ex) { } return 0; } public javax.servlet.http.HttpServletRequest m_request = null; public javax.servlet.http.HttpServletResponse m_response = null; public javax.servlet.jsp.JspWriter m_out = null; public javax.servlet.http.HttpSession m_session = null; public javax.servlet.ServletContext m_application = null; public javax.servlet.jsp.PageContext m_pageContext = null; public javax.servlet.ServletConfig m_config = null; public javax.servlet.http.HttpSession getSession() { return m_session; } public javax.servlet.http.HttpServletRequest getRequest() { return m_request; } public javax.servlet.jsp.PageContext getPageContext() { return m_pageContext; } public boolean isMultipart() { HttpServletRequest oRequest = (javax.servlet.http.HttpServletRequest)m_request; String content_type = oRequest.getHeader("content-type"); if (WCString.indexOf(WCString.toUpper(content_type),"MULTIPART") == 0) { return true; } return false; } } %> <form name="fParam" encType="multipart/form-data"> <input type="hidden" name="_cmd" value="file_data"> <input type="file" name="file"> </form> <a href="javascript:uploadFile();">upload the file</a> <iframe id="ifrmAction" name="ifrmAction" width="0" height="0"></iframe> <script> function uploadFile() { var fParam = window.document.fParam; fParam._cmd.value = "uploadFile"; fParam.method = "post"; fParam.target = "_blank"; fParam.submit(); } </script> -- file_upload_progress1.jsp 소스 끝 출처 : 고급 웹 UI 개발 라이브러리 Web Development Library 소스공개 : http://www.webdevlib.net 첨부파일 : multipart_form_parser1.zip | |||
|
mkdirs() 는 디렉토리 생성에 성공하면 true 를 반환하기에, 실패시 에러를 출력하려면 if문 속에서 느낌표를 붙여, 논리값을 반전시켜 주어야 합니다.
같은 이름의 디렉토리가 이미 있을 때나
디렉토리명에 허용되지 않는 문자(*, ? 등)가 있을 때
에는 아래 예제의 경우, "디렉토리 생성 실패"라는 메시지가 출력됩니다.
여러 개의 중첩된 폴더를 한꺼번에 생성하려면 슬래시(/) 기호로 패스를 구분해 줍니다.
mkdir() 이라는 단수형 이름의 메소드로도 디렉토리를 만들 수 있지만, 여러개를 한꺼번에 만들 수는 없습니다.
디렉토리 만들기 예제
소스 파일명: Example.java
public class Example {
public static void main(String[] args) {
// MY_TEST_DIR 이라는 하위 폴더 만들기
File f = new File("MY_TEST_DIR");
if (!f.mkdirs())
System.err.println("디렉토리 생성 실패");
// MY_TEST_DIR 이라는 하위 폴더 밑에
// 333 이라는 하위 폴더 또 만들기
// 즉, MY_TEST_DIR/333 이렇게 중첩된 폴더 한꺼번에 생성
f = new File("MY_TEST_DIR/333");
if (!f.mkdirs())
System.err.println("디렉토리 생성 실패");
}
}
위의 자바 코드를 실행하면, 현재 디렉토리에 MY_TEST_DIR 이라는 폴더가 생기고, 그 안에 333 이라는 폴더가 또 들어 있을 것입니다.
▶▶ Java/자바] 파일 지우기, 디렉토리 삭제 방법; Delete File, Erase Directory
▶▶ Java 자바, 현재 날짜로 디렉토리 생성 예제; Current Date Directory Name
☞ 자바 (Java)
Java에서 HTML 태그를 제거하는 정규식 적용
HTML 태그를 제거하고 순수하게 텍스트만 가져오는 부분이 필요해서 관련 자료를 검색하다가 나온 소스를 정리해봤습니다.
정규식에 대해서는 개념은 들어보셨을 겁니다.
나중에 기회가 되면 정규식에 대해서도 한번 정리해 보도록 하구요..
오늘은 간단하게 원하는 기능을 구현한 소스를 보여드리도록 하겠습니다.
- private String getText(String content) {
- Pattern SCRIPTS = Pattern.compile("<(no)?script[^>]*>.*?</(no)?script>",Pattern.DOTALL);
- Pattern STYLE = Pattern.compile("<style[^>]*>.*</style>",Pattern.DOTALL);
- Pattern TAGS = Pattern.compile("<(\"[^\"]*\"|\'[^\']*\'|[^\'\">])*>");
- Pattern nTAGS = Pattern.compile("<\\w+\\s+[^<]*\\s*>");
- Pattern ENTITY_REFS = Pattern.compile("&[^;]+;");
- Pattern WHITESPACE = Pattern.compile("\\s\\s+");
- Matcher m;
- m = SCRIPTS.matcher(content);
- content = m.replaceAll("");
- m = STYLE.matcher(content);
- content = m.replaceAll("");
- m = TAGS.matcher(content);
- content = m.replaceAll("");
- m = ENTITY_REFS.matcher(content);
- content = m.replaceAll("");
- m = WHITESPACE.matcher(content);
- content = m.replaceAll(" ");
- return content;
- }
각각 HTML의 스크립트 태그와 내용, 스타일 및 내용, 태그들, 엔터티, 공백문자들을 제거하는 정규식 표현입니다.
관심있는 분들은 한번씩 테스트 해보시기 바랍니다. ^^
아마도 곧 간단한 기능을 하는 것을 오픈해서 보여드릴건데요..
URL을 지정하면 해당 텍스트를 분석해서 자동으로 태깅 정보를 제공하는 겁니다.
마무리 단계이니 완료되는 대로 이 사이트를 통해서 보여드릴께요..
그럼.. 좋은 하루 되세요~~ from 미니(xmlmanager@gmail.com)
java enum - enum의 메쏘드
모든 예제는 지난 글에서 썼던 Gender를 그대로 사용합니다. 코드는 아래와 같습니다.
public enum Gender {
MALE, FEMAIL
}
Static Methods
기본으로 정의되는 static method는 모두 3가집니다.
1. valueOf(String arg)
String 으로 넘긴 값을 기준으로 enum의 원소를 가져 옵니다. 즉, Gender.MALE 과 Gender.valueOf("MALE")은 같습니다.
2. valueOf(Class<T> class, String arg)
클래스를 넘겨서 받습니다. 즉, Gender.MALE 와 Gender.valueOf(Gender.class, "MALE"); 는 같습니다. 사실 valueOf(String arg)는 내부적으로 이 메쏘드를 호출합니다.
3. values()
이건 지난 시간에 설명한 그대로 enum의 요소들을 enum 타입의 배열로 리턴합니다. Gender.values() 는
new Gender[]{Gender.MALE, Gender.FEMALE} 와 같은 값을 가집니다.
Static이 아닌 Method
1. name()
호출된 값의 이름을 리턴합니다.
Gender.MALE.name() 은 "MALE" 이라는 String 값을 가져옵니다.
2. ordinal()
정의된 순서를 리턴합니다. 0부터 시작합니다.
즉, Gender.MALE.ordinal() 은 0을 Gender.FEMALE.ordinal()은 1을 리턴합니다.
3. compareTo(E o)
E는 자기 자신입니다. 예제로 쓴 Gender의 경우는 Gender가 될 겁니다.
이는 ordinal()을 호출해서 비교합니다. 요소들 간에 어떤 순서가 있을 때 쓰면 됩니다.(요일이 좋은 예가 되겠습니다.)
모든 enum은 Comparable을 구현하고 있습니다. Comparable 인터페이스에는 정의된 compareTo 메쏘드를 구현한 것입니다. 더 자세한 것은 다음 글에서 다루겠습니다.
기타 다른 메쏘드들은 java.lang.Object에 정의된 메쏘드들이거나 java.lang.Class에서 따온 메쏘드들이므로 설명하지 않겠습니다.
enum의 확장
Gender 별로 웃음 소리를 저장하려고 합니다. Gender를 다음과 같이 변경시킵니다.
public enum Gender {
MALE("하하")
, FEMAIL("호호");
private String sound;
Gender(String arg){
this.sound = arg;
}
String getSound(){
return sound;
}
}
일반적인 class의 생성자나 메쏘드를 만들 듯이 만들면 됩니다.
위의 코드의 경우 Gender.MALE.getSound()는 "하하"를 리턴합니다
Tomcat을 사용하다가 java application 실행 시
java.lang.OutOfMemoryError: Java heap space 에러 생겼을 때 해결방법.
생기는 경우의 수가 많이 있을 것 같지만, 이번에 아래의 스크립트로 해겼되었으므로 적어놔야 겠다.
----
이번 경우는 Confluence Wiki 설치 중, 어느 부분에서 페이지가 넘어가지 못하고 먹통이 되었다가 결국 아래의 에러가 발생했다.
java.lang.OutOfMemoryError: Java heap space
Confluence Wiki와 같은 Java 어플리케이션은 JVM에서 구동된다. 따라서 시작 시 JVM에서 일정량의 메모리를 할당하여 어플리케이션에서 사용된다. 기본적으로 Java 가상머신은 서버에 얼마나 많은 물리적인 메모리가 설치되있더라도 오직 64MB의 메모리만을 할당된다고 한다.
따라서 Confluence Wiki같은 중간규모 이상의 어플리케이션은 늘리필요가 있다고 한다.
늘리는 방법을 찾느냐 조금 시간이 걸렸다.
Linux, Java, Tomcat에 능통한 사람이면 금방 찾을 수 있지만, 전혀 찾을 수 없었다.
그래서 여기저기 해결방법을 짜집기 하다가 힌트를 얻었고 스크립트를 작성하였다.
** tomcat 5.5 기준임 **
/usr/local/tomcat/bin 에 tomcat.sh를 하나 만들자. (/usr/local/ 는 사람마다 다를 수 있슴)
> vi tomcat5.sh
tomcat5.sh 파일내용
# file:tomcat.sh
CLASSPATH=/usr/java/jdk1.5.0_15/lib
JAVA_HOME=/usr/java/jdk1.5.0_15
CATALINA_OPTS="-Djava.awt.headless=true"
JAVA_OPTS="-Xms512m -Xmx512m"
export CLASSPATH
export JAVA_HOME
export CATALINA_OPTS
export JAVA_OPTS
case "$1" in
start)
echo "Starting tomcat5..."
/usr/local/tomcat/bin/startup.sh
;;
stop)
echo "Stopping tomcat5..."
/usr/local/tomcat/bin/shutdown.sh
;;
*)
echo "Usage tomcat.sh start/stop"
exit 1;;
esac
tomcat 시작
> tomcat.sh start
java.lang.OutOfMemoryError: PermGen space
요즘 들어 부쩍 java.lang.OutOfMemoryErorr로 인해 이클립스가 뻗어버리는 일이 많이 발생했었다. 하지만 Heap Monitor를 보면 200M 조차 사용하지 않는다. 이런 경우, 대부분은 PermGen 영역이 모자란 것이 원인일 수 있다.
{workspace}/.metadata/.log를 확인해보면 PermGen space라고 기록되어 있을 것이다.
Eclipse를 사용할 때는 JVM에 -Xmx 옵션은 대부분은 넣어서 사용하리라 생각한다. 하지만 Java는 메모리 영역을 사실상 두 부분으로 구분하여 사용한다. 일반 Java Heap space와 클래스와 같이 Permenant Generation 대상 데이터를 두기 위한 PermGen space이다.
대부분의 자바 애플리케이션에서는 기본 PermGen Size로 충분하겠지만 이클립스의 경우 클래스가 꽤 많아지면서 모자란 경우가 있는듯 하다. javanese의 경우 Callisto를 깔아놓고 JDT, CDT를 왔다갔다 하면서 사용하다보니 Heap은 별로 쓰지도 않는데 PermGen space가 종종 모자라는 경우가 있다. 아마 Web관련 Tool을 많이 사용하는 분도 같은 현상이 나타날 수 있을 것이다.
PermGen space는 -XX:MaxPermSize 옵션으로 설정할 수 있다.
eclipse -vm /usr/lib/jvm/java-1.5.0-sun/bin/java -vmargs -XX:MaxPermSize=128m -Xms128m -Xmx512m
OutOfMemory 에러가 발생한다면 -Xmx만 늘려주지말고 PermSize도 확인해보라.
--------------------------------------------------------------------------------------
java.lang.OutOfMemoryError
2005-05-31 송학렬 ㈜아이티플러스 기술지원부
이 문서는 기술지원 또는 개발 시 java.lang.OutOfMemoryError 를 만났을 때 원인 파악 및 해결방안 입니다.
java.lang.OutOfMemoryError 에는 크게 2가지 패턴이 있다고 볼 수 있습니다.(전적으로 개인적인 생각이지만..^^)
Java의 heap 메모리가 정말로 Full 되서 나는 종류가 있고 그렇지 않은데도 나는 종류가 있습니다.
그 둘 중에 어는 것 인지부터 가려내는 것이 가장 먼저 선행되어야 합니다.
Java 가상머신에는 메모리 구조가 여러단계로 나뉘어 져 있으므로 어느 영역에 의해 java.lang.OutOfMemoryError 가 나는지 알기 위해 JAVA OPTION으로 싸이트가 안정화 되기 전까진 –verbosegc 또는 -XX:+PrintGCDetails 옵션을 추가해 놓는 것이 java.lang.OutOfMemoryError 났을 때를 대비해 좋은 습관이라 할 수 있습니다.
-verbosegc 또는 -XX:+PrintGCDetails 옵션으로 로그에 남는 heap 메모리 정보를 본 후 java.lang.OutOfMemoryError 가 날 때 heap이 꽉 차서 나는 것인지 아닌지 부터 판단합니다.
1. Heap Memory가 Full 차지 않았을 때 1) Perm 영역이 full 되는 경우
Permanent generation is full…
increase MaxPermSize (current capacity is set to: 134217728 bytes)
[Full GC[Unloading class sun.reflect.GeneratedSerializationConstructorAccessor31282]
810207K->802132K(1013632K), 8.3480617 secs]
<GC: 2 4 2465625.831280 10348 0 31 113802808 105534632 286326784 0 0 35782656 715849728 715848840 715849728 134217720 134023296 134217728 8.348677 8.348677 >
Passwd Check =============
<2005. 5. 19. 오전 9시 32분 23초 KST> <Error> <HTTP> <BEA-101017> <[ServletContext(id=2536415,name=/,context-path=)] Root cause of ServletException.
java.lang.OutOfMemoryError
위와 같은 case 인 경우네는 Java 가상머신중에 Perm 영역이 full 차는 경우 입니다.
Perm 영역에는 class object 및 관련된 meta data가 로드되는 곳인데 싸이트가 매우 많은 수의 class를 사용하는 경우 늘려줘야 하는 case도 있습니다.
얼마가 적정한 사이즈란 정답이 없는 것 같고 max가 계속 늘어나지 않고 일정한 사이즈를 유지 하면 됩니다.
위 에러가 났을때는 -XX:MaxPermSize=256m 옵션으로 사이즈를 적당하게 늘려주는게 방
법이며 늘려주었는데도 불구하고 Full 차는 시간만 늘어날 뿐 계속 사이즈가 늘어난다면 이 영역은 일반 비즈니스 프로그램으로 핸들링 할 수 없는 영역이므로 WAS 제품의 버그 및 jdk 버그로 보는 것이 일반적입니다.
2) MAXDSIZ 사이즈 관련
- Exception in thread “CompileThread0″ java.lang.OutOfMemoryError: requested 32756 bytes for ChunkPool::allocate
Possible causes:
- not enough swap space left, or
- kernel parameter MAXDSIZ is very small.
- java.lang.OutOfMemoryError: unable to create new native thread
위 두 에러가 나는 이유는 Data 사이즈가 Full 차서 더 이상 메모리 할당을 할 수 없다는 java.lang.OutOfMemoryError 입니다.
Jdk도 내부적으로 c 라이브러리를 쓰고 jni를 통해서 c프로그램을 호출할 수 도 있는 환경에서 Data 영역이상으로 메모리 사용 시 위 에러를 만날 수 있습니다.
Heap 영역에는 java heap과 C heap이 있는데 C heap이 Data 메모리 영역에 영향을 미치는 것으로 보이며 보통 C의 전역 변수들이 잡히는 영역입니다.
위 현상을 만났을 때는 hp os의 MAXDSIZ가 너무 작게 잡혀있지 않은지 확인 후 적당한 크기로 늘려 줘야 합니다.
Glance 에서 shift+m 을 누른 후 jvm pid를 누르면 java가 사용하는 Data 사이즈를 모니터링 할 수 있습니다.
모니터링을 통해 적정한 사이즈로 MAXDSIZ를 늘려주어야 하며 만일 늘려 준게 에러 발생의 시간만 지연 시킬 뿐 계속 사용량이 늘어난다면 이는 사용하는 c라이브러리 쪽에 메모리 릭 버그가 있는 것이므로 c라이브러리를 체크 하셔야 합니다.
java.lang.OutOfMemoryError: unable to create new native thread
이 경우는 프로그램에서 Thread pool 프로그램 실수로 필요이상으로 쓰레드가 생성되는 경우도 과도하게 메모리를 사용할 수 있으므로 jvm 쓰레드 덤프를 통해 과도한 쓰레드가 생성되지 않았는지도 확인해 보셔야 합니다.
2. Heap이 Full 찾을 때
이 경우는 java가 사용하는 heap 영역이 Full 되서 java.lang.OutOfMemoryError 가 나는 경우 인데 두 가지 패턴이 있습니다.
순간적으로 대량의 데이터를 메모리에 올리는 프로그램이 실행되어 문제를 야기 할수 있으며 다른 한 가지는 조금씩 메모리 릭이 발생하여 점차적으로 메모리가 쌓여 가는 경우 입니다.
두 가지 중에 어느 것인지 구별하는 것이 중요하며 이를 위해서도 마찬가지로 -verbosegc 또는 -XX:+PrintGCDetails 로그를 통해 순간적으로 메모리가 차는 것인지 조금씩 메모리가 차는 것인지를 확인하셔야 합니다.
1) 특정 프로그램의 특정시점의 과도한 메모리 사용에 의한 경우
특정 프로그램이 과도하게 heap 메모리 이상 메모리를 사용하면서
java.lang.OutOfMemoryError가 발생하는 경우는 이 에러가 발생하는 시점의 쓰레드 덤프를 통해 어느 프로그램인지 쉽게 찾을 수 있습니다.
쓰레드 덤프에 메모리를 쓸만한 프로그램은 어느 정도의 자바프로그램 경험이 있으면 찾을 수 있습니다.
Ex)
“ExecuteThread: ‘36′ for queue: ‘default’” daemon prio=10 tid=0×0048e7b0 nid=48 lwp_id=4139729 runnable [0x23f32000..0x23f30500]
at java.net.SocketInputStream.socketRead(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at oracle.net.ns.Packet.receive(Unknown Source)
at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.jdbc.ttc7.MAREngine.unmarshalUB1(MAREngine.java:718)
at oracle.jdbc.ttc7.MAREngine.unmarshalSB1(MAREngine.java:690)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:373)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1405)
at oracle.jdbc.ttc7.TTC7Protocol.fetch(TTC7Protocol.java:889)
- locked <0×35e8e3b0> (a oracle.jdbc.ttc7.TTC7Protocol)
at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:242)
- locked <0×36f66c98> (a oracle.jdbc.driver.OracleResultSetImpl)
at weblogic.jdbc.pool.ResultSet.next(ResultSet.java:180)
at Dcard.AAA.ejb.monitor.member.wbbb.WACBean.getInfoList(WACBean.java:5789)
java.lang.OutOfMemoryError 가 날 상황에 쓰레드 덤프를 두 세번 떠서 같은 쓰레드 번호로 위 같은 로직이 오래 결려있다면 이는 프로그램에서 while(rs.next()) 를 오랜 기간 돌면서 메모리에 DB로부터 읽어서 올리고 있다는 것을 의미 합니다… 대량 데이터 조회가 일어나는 경우인 것 입니다.
이런 식으로 특정 프로그램의 특정 시점에 과도한 메모리 사용으로 인한 java.lang.OutOfMemoryError 에러는 쓰레드 덤프를 통해 찾을 수 있습니다.
– 물론 2번에서 설명 할 heap dump를 통해서도 찾을 수 있습니다.
2) 메모리 릭에 의해 조금씩 메모리가 쌓인 경우
JVM위 에서 실행중인 프로그램중에 어떤 것이 GC 대상에서 제외되는 영역에 data를 조금씩 쌓고 있다는 얘기입니다.
GC 대상에서 제외되는 영역은 다음과 같은 곳이 있습니다.
- Http Session에 넣는 데이터..(세션 타임아웃 또는 invilidate 씨 까지 제외됨)
- Static 변수
- 서블릿 또는 jsp의 멤버변수 ( WAS 기동 후 최초 호출 시 인스턴스 화 되어 WAS가 내려 갈 때 까지 사라지지 않음 )
- EJB의 멤버변수( pool안에서 객체가 존재하는 한 GC대상에서 제외)
위 같은 영역에 프로그램에서 data를 add 하는 구조를 메모리 릭 이라고 할 수 있습니다.
IBM 또는 SUN JDK 인 경우에는 heapdump를 통해서 분석하여 어느 데이터가 메모리를 많이 잡고 있는지를 알 수 있습니다.
Heapdump 사용법 및 분석 법은 다음을 참조 하시면 됩니다.
http://www.alphaworks.ibm.com/aw.nsf/FAQs/heaproots
http://www-1.ibm.com/support/docview.wss?uid=swg21190476
http://www.skywayradio.com/tech/WAS51/IBMHeapDump/
출처 : http://www.javaservice.net/~java/bbs/read.cgi?m=etc&b=jdk&c=r_p&n=1117521098&p=1&s=t#1117521098
var viewer_image_url = “http://blogimgs.naver.com/blog20/blog/layout_photo/viewer/”; var photo = new PhotoLayer(parent.parent.parent); photo.Initialized(); window.onunload = function() { photo.oPhotoFrame.doFrameMainClose(); }.bind(this);
Environment variable ORACLE_SID not defined. Please define it.
C:\Documents and Settings\Administrator>set ORACLE_SID=orcl
C:\Documents and Settings\Administrator>emctl start dbconsole
OC4J Configuration issue. C:\oracle\product\10.2.0\db_1/oc4j/j2ee/OC4J_DBConsole
_192.168.1.66_orcl not found.
C:\Documents and Settings\Administrator>emctl start dbconsole
EM Configuration issue. C:\oracle\product\10.2.0\db_1/192.168.1.66_orcl not foun
d.
C:\Documents and Settings\Administrator>emctl start dbconsole
Oracle Enterprise Manager 10g Database Control Release 10.2.0.1.0
Copyright (c) 1996, 2005 Oracle Corporation. All rights reserved.
http://ts:1158/em/console/aboutApplication
Starting Oracle Enterprise Manager 10g Database Control ...OracleDBConsoleorcl
서비스를 시작합니다..
OracleDBConsoleorcl 서비스를 시작할 수 없습니다.
시스템 오류가 발생했습니다.
시스템 오류 3이(가) 생겼습니다.
지정된 경로를 찾을 수 없습니다.
C:\Documents and Settings\Administrator>emctl start dbconsole
Oracle Enterprise Manager 10g Database Control Release 10.2.0.1.0
Copyright (c) 1996, 2005 Oracle Corporation. All rights reserved.
http://ts:1158/em/console/aboutApplication
Starting Oracle Enterprise Manager 10g Database Control ...OracleDBConsoleorcl
서비스를 시작합니다.................
OracleDBConsoleorcl 서비스가 잘 시작되었습니다.
C:\Documents and Settings\Administrator>
해결방법
C:\WINDOWS\system32\drivers\etc
의 host화일을 수정한다
현재 사용중인 pc 의 이름과 ip를 매칭시켜주면된다.
192.168.1.66 ts
이런식으로 추가하여준다.
package struts02.util;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import org.apache.struts.upload.FormFile;
public class BoardUtil {
public static String saveFile(FormFile uploadFile) {
String physicalFileName=null;
InputStream is;
try {
is = uploadFile.getInputStream();
String uploadFileName = uploadFile.getFileName();
physicalFileName = getPhysicalFileName( uploadFileName );
String filePath = "F:/Struts_And_iBatis/workspace/struts-board-02/WebContent/upload/";
OutputStream os = new FileOutputStream(filePath + physicalFileName);
int byteRead = 0;
byte[] buf = new byte[8192];
while ((byteRead = is.read(buf)) != -1) {
os.write(buf, 0, byteRead);
}
os.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return physicalFileName;
}//end saveFile()
private static String getPhysicalFileName(String uploadFileName) {
String systemTime=new Date().getTime()+"";//
if( uploadFileName.indexOf(".") == -1 ){ //파일이름에 .이 없으면
return uploadFileName+"_"+systemTime;
}else{
int index = uploadFileName.lastIndexOf(".");
//확장자를뺀파일명
String _tmpFileName = uploadFileName.substring(0, index);
// Extension
String _extName = uploadFileName.substring( index );
return _tmpFileName + "_"+systemTime+_extName;
}
}
}
일주일에 한번, 하루에 한번 작업을 수행하는 프로세스를 실행하고 싶을 때가 있을 껍니다.
한가한 시간에 자동으로 배치작업을 실행하는 등의 작업을 자바에서 수행할 수 있습니다.
Timer라는 클래스에다가 시작날짜, 시간을 설정한 뒤, TimerTask클래스를 상속받은 클래스에서 run메소드를 구현하게 되면 설정된 시간에 run메소드가 자동으로 수행되게 됩니다.
코드를 보도록 합시다.
package com.mudchobo.scheduler;
import java.util.TimerTask;
public class WeeklySearch extends TimerTask {
@Override
public void run() {
System.out.println("WeeklySearch!");
}
}
TimerTask를 상속받아서 run메소드를 구현했습니다. run메소드는 간단히 WeeklySearch라고 보여주는군요.
그럼 메인을 보도록 합시다.
package com.mudchobo.scheduler;
import java.util.Calendar;
import java.util.Timer;
public class Scheduler {
public static void main(String[] args) {
WeeklySearch weeklySearch = new WeeklySearch();
Timer timer = new Timer();
Calendar date = Calendar.getInstance();
date.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
date.set(Calendar.AM_PM, Calendar.PM);
date.set(Calendar.HOUR, 11);
date.set(Calendar.MINUTE, 29);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
timer.scheduleAtFixedRate(weeklySearch, date.getTime(),
1000 * 60 * 60 * 24 * 7);
}
}
Timer객체, Calendar객체를 선언합니다. Calendar객체에는 이 스케쥴이 시작될 시간을 설정해서 넣습니다. 그 뒤에 timer에 있는 scheduleAtFixedRate메소드에 첫번째 인자는 맨 위에서 생성한 TimerTask객체를 넣으면 되구요. 두번째는 이 스케쥴이 시작될 시간을 설정해서 넣으면 되구요. 3번째는 얼마만큼의 주기로 실행될 지 기간을 설정하게 됩니다.
밀리초여서 1000밀리초 * 60초 * 60분 * 24시간 * 7일 하게 되면 저것은 1주일에 한번 실행되게 됩니다.
이상입니다!
출처 : http://mudchobo.tomeii.com/tt/category/자바(Java)?page=5
자바에서는 파일을 복사하는 것은 그리 어렵지 않습니다.
자바에는 풍부한 I/O 클래스가 많기 때문에 유연성있게 사용할 I/O 객체가 많습니다.
만약 특정파일을 디스크에서 디스크로 복사하는 것이 아니라 네트워크를 이용해서 파일을
다른 컴퓨터로 복사하다면 어떨까요?
자바에서는 이 또한 그리 어렵지 않습니다.
TCP 네트워크 Socket 객체를 얻기만 한다면 Socket에서 InputStream, OutputStream을
얻을 수 있고, 자바 I/O 객체를 이용해서 InputStream에서 읽고 OutputStream으로 쓰기만
하면 네트워크에서 읽고 쓰기가 되는 것이니까요.
자바 I/O 객체를 이용해서 파일을 복사하는 경우할 때 복사할 원본 파일을 읽는 프로그램이
결국 대상 파일을 만듭니다. 파일을 읽는 것, 파일을 쓰는 것이 같은 버추얼 머신에 의해서
실행됩니다. 하지만 네트워크를 이용해서 복사를 하는 경우에는 파일을 읽어서
네트워크로 보내는 프로그램(클라이언트)과 네트워크로부터 데이터를 읽어서 파일에 쓰기를
하는 프로그램(서버)으로 나눌 수 있을 것입니다.
그럼 이와 같이 네트워크를 통해서 파일을 복사하는 프로그램을 만들어 보겠습니다.
TCP 네트워크 프로그램에서는 네트워크에 참여하는 참여자가 항상 둘인데 거의 대부분
클라이언트, 서버의 서비스 구조입니다.
package tcp;
import java.io.*;
import java.net.*;
/**
* 스트림 복사를 합니다.
*/
public interface Zerox {
/**
* InputStream로 부터 읽은 데이터를 OutputStream으로 보냅니다.
* @param is InputStream
* @param os OutputStream
* @exception IOException
*/
public void copy(InputStream is, OutputStream os)
throws IOException;
}
예제 11 - 3 Zerox.java
Zerox 인터페이스는 public void copy(InputStream, OutputStream) 메소드를 하나 선언
했는데, 그 이름에서 짐작하듯이 InputStream으로부터 데이터를 읽고,그 읽은 데이터를
OutputStream으로 씁니다. 복사의 기본이 읽은 것을 읽은 그대로 쓰는 것이기 때문입니다.
먼저 TCP 네트워크 서버를 살펴보겠습니다.
package tcp;
import java.io.*;
import java.net.*;
/**
* 스트림 복사를 합니다.
*/
public class CopyServer implements Zerox{
/**
* InputStream로 부터 읽은 데이터를 OutputStream으로 보냅니다.
* @param is InputStream
* @param os OutputStream
* @exception IOException
*/
public void copy(InputStream is, OutputStream os)
throws IOException {
int c = -1;
while((c = is.read()) != -1) {
os.write(c);
}
os.flush();
}
public static void main(String[] args) throws Exception {
/*
데이타 Copy를 위해서 네트워크 InputStream 생성
*/
ServerSocket ss = new ServerSocket(8989);
Socket s = ss.accept();
InputStream is = s.getInputStream();
/*
데이타 Copy를 위한 파일 OutputStream 생성
*/
OutputStream os = new FileOutputStream(new File(args[0]));
/*
데이타 Copy를 위한 Zerox 생성
*/
Zerox zerox = new CopyServer();
/*
데이타 Copy - InputStream 데이타를 OutputStream으로 복사
*/
zerox.copy(is,os);
/* 네트워크 자원 해제 */
os.close();
is.close();
s.close();
}
}
예제 11 - 4 CopyServer.java
CopyServer는 우선 Zerox 인터페이스를 구현했습니다.
CopyServer가 구현한 public void copy(InputStream, OutputStream)을 살펴보면
InputStread에서 한 바이트를 읽고 읽은 바이트를 그대로 OutputStream으로 쓰는데,
이러한 행동을 InputStream으로부터 더 이상 읽을 데이터가 없을 때 까지 계속 반복하고
있습니다. 즉 InputStream은 복사할 원래의 데이터소스로부터 만들어진 것이니,
InputStream의 마지막에 이를 때까지 읽고,쓰기를 반복하면 결국엔 OutputStream으로는
원래의 데이터소스에 있던 모든 데이터가 씌여지는 셈입니다.복사의 기본입니다.
InputStream으로부터 데이타를 모두 읽은후에는 버퍼에 있을지 모를 데이터를
flush() 메소드를 호출해서 강제적으로 OutputStream으로 씁니다.
CopyServer의 public static void main(String[])는 CopyServer가 TCP 서버로 동작하도록
환경을 설정합니다.
우선 TCP 8989포트로 ServerSocket을 만들고 있습니다. 그리고 클라이언트가 TCP 연결을
하기를 기다리고 있습니다. 클라이언트가 TCP 연결을 한다면 public Socket accept()
메소드가 Socket을 리턴합니다. CopyServer는 대부분의 삶을 public Socket accept()에서
머물러 있습니다. 일단 Socket이 만들어졌다는 것은 TCP 연결이 된 것입니다.
Socket으로부터 InputStream과 OutputStream을 얻습니다.
물론 이제부터는 자바의 I/O객체를 이용해서 마음껏 읽고 쓸수 있습니다.
CopyServer는 복사할 대상 파일의 OutputStream은 FileOutputStream으로 합니다.
InputStream과 OutputStream은 복사를 담당하는 Zerox의 copy(InputStream,OutputStream)
메소드의 인자로 쓰여집니다.
Zerox는 그 원래 만들어진 것이 오로지 InputStream으로 읽은 데이터를 OutputStream으로
쓰기만 하므로 , 결국 여기서는 네트워크 스트림으로부터 데이터를 읽어서 파일을 의미하는
OutputStream으로 쓰는 행동을 합니다.
CopyServer는 다 사용한 시스템자원(네트워크 자원)을 해제하는데,TCP 네트워크 연결과
같은 시스템 자원은 열린 자원(Open Resources)라고 해서 사용한 후에는 반드시 정리해
주는 습관을 같져야 합니다. 자바의 가비지 컬렉터(Garbage Collector)는 열린 자원에 대해
서는 청소를 하지 않기 때문입니다.
열린 자원은 프로그래머가 명시적으로 정리하지 않으면 시스템 자원이 물 새듯 새나가고,
언젠가는 큰 낭패를 당합니다.
이젠 TCP 네트워크 클라이언트를 살펴보겠습니다.
package tcp;
import java.io.*;
import java.net.*;
/**
* 스트림 복사를 합니다.
*/
public class CopyClient implements Zerox{
/**
* InputStream로 부터 읽은 데이터를 OutputStream으로 보냅니다.
* @param is InputStream
* @param os OutputStream
* @exception IOException
*/
public void copy(InputStream is, OutputStream os)
throws IOException {
int c = -1;
/*
InputStream is로 부터 EOF일때까지 데이타를 읽고,
읽은 데이타를 OutputStream os로 보냅니다.
*/
while((c = is.read()) != -1) {
os.write(c);
}
os.flush(); // OutputStream 버퍼에 있을 수 있는 데이타를 강제 출력
}
public static void main(String[] args) throws Exception {
/*
데이타 Copy를 위해서 파일 InputStream 생성
*/
InputStream is = new FileInputStream(new File(args[0]));
/*
데이타 Copy를 위해서 네트워크 OutputStream 생성
*/
Socket s = new Socket("localhost",8989);
OutputStream os = s.getOutputStream();
/*
데이타 Copy를 위한 Zerox 생성
*/
Zerox zerox = new CopyClient();
/*
데이타 Copy - InputStream 데이타를 OutputStream으로 복사
*/
zerox.copy(is,os);
/*
네트워크 자원 해제
*/
is.close();
os.close();
s.close();
}
}
예제 11 - 5 CopyClient.java
CopyClient 역시 CopyServer와 마찬가지로 TCP기반의 Socket 객체를 사용하고 있는터라
tcp 패키지에 속하게 했습니다.
CopyClient에서 눈여겨 볼 것은 Socket 객체의 생성자에 사용된 두개의 인자인 “localhost”
와 8989의 값입니다.
localhost는 TCP 네트워크 연결을 하고자한는 서버가 위치한 컴퓨터의 IP 주소를
말합니다. 8989는 서버가 서비스하는 포트를 의미합니다.
CopyClient가 서비스를 받으려하는 CopyServer는 TCP 8989로 서비스하고 있으므로
클라이언트는 TCP 포트 8989로 네트워크 연결을 해야합니다.
localhost는 “127.0.0.1”의 IP 주소에 대한 또 다른 이름이며, "127.0.0.1"은 Loopback
주소로 자기자신의 IP주소와 같다고 컴퓨터입니다.
예제 11 - 5의 CopyClient가 서버의 IP 주소를 "localhost"라고 한 것은 CopyServer가
CopyClient를 실행하는 컴퓨터에서 Listen하면서 서비스를 제공하고 있기 때문입니다.
CopyClient역시 Zerox이므로 Zerox의 public void copy(InputStream, OutputStream)를
이용합니다. FileInputStream에서 데이타를 읽어서 TCP 네트워크에서 만들어진
OutputStream으로 데이터를 쓰습니다. 여기서 TCP 트워크 반대쪽에서는 서버가 열심히
정보를 데이터를 읽고 있을 것입니다.
CopyClient 역시 사용한 시스템 자원을 정리하고 있습니다.
Zerox 인터페이스를 보면 마치 로컬에서 파일을 복사하는 형태를 가지지만
CopyServer, CopyClient는 가장 기본적인 TCP 네트워크로부터 읽고,쓰기를 보여줍니다.
그림 11 - 6은 TCP 네트워크 서버인 tcp.CopyServer를 실행시킨 모습입니다.
그리고 아래 그림 11 - 7은 tcp.CopyClient를 실행시킨 모습이구요.
src 폴더아래의 Zerox.java 를 현재 폴더 Zerox.copy로 복사하는 내용입니다.
출처 : http://sinuk.egloos.com/2676307
1. JNI (Java Native Interface) 란 ?
- 자바가 다른 언어로 만들어진 어플리케이션과 상호 작용할 수 있는 인터페이스를 제공한다.
- 자바가상머신(JVM)이 원시 메소드(native method)를 적재(locate)하고 수행(invoke)할 수 있도록 한다
- JNI가 자바가상머신내에 포함됨으로써, 자바가상머신이 호스트 운영체제상의 입출력, 그래픽스, 네트워킹, 그리고 스레드와 같은 기능들을 작동하기 위한 로컬시스템호출(local system calls)을 수행할 수 있도록 한다.
* 쉽게 말해 Java와 다른 언어를 연동하는 솔루션입니다.
[그림1] C로 만들어진 Library와 JAVA를 연결해주는 JNI
2. Why do you need JNI ?
자 바 네이티브 메쏘드(Java Native method, 이하 JNI)는 다른 언어로 작성된 코드를 자바에서 호출하도록 만들어진 규약이다. 현재는 C/C++에 대한 호출만을 정확하게 지원한다. 어떻게 보면 JNI는 자바가 만들어진 철학과 정반대되는 것이다.
그러나. Java에도 한계가 있다.
1. 속도 문제가 있는 계산 루틴
> 자바가 Native Code(플랫폼에 종속적인 기계어 코드)에 비해 느리다.
2. 자바에서 하드웨어 제어
3. 자바에서 지원되지 않은 특정 운영체제 서비스
> 자바의 클래스 라이브러리는 방대하고 다양한 서비스를 제공하지만, 특정 플랫폼에서 제공하는 고유의 서비스의 기능을 모두 포함할 수는 없다. 특히, 특수한 목적으로 제작된 하드웨어를 자바에서 제어해야 할 필요가 있다고 한다면, 자바만으로 해결하기는 힘들다.
4. 기존의 프로그램에서 자바가 제공하는 서비스를 이용
> 기존에 작성된 프로그램이나 기존의 시스템(legacy)과의 연계 문제
∴ JNI를 써서 해결해보자.
3. C를 이용한 JNI 예제
VC++을 이용해 C문법으로 작성되어 만들어진 DLL을 로딩하여 Java에서 사용해보겠습니다.
1단계 : Native Method를 선언하는 자바 클래스 작성
2단계 : 1단계에서 작성한 클래스 컴파일
3단계 : javah를 사용해서 Native Method가 사용할 헤더 파일 생성
4단계 : C언어로 Native Method 실제 구현
5단계 : C 코드와 헤더 파일을 컴파일
6단계 : 자바 프로그램 실행
1단계 : Native Method를 선언하는 자바 클래스 작성
Java 소스 파일 : HelloJni_Jsource.java
import java.util.*;
class HelloJniClass {
native void Hello();
static { System.loadLibrary("Hello_DLL"); }
public static void main(String args[]) {
HelloJniClass myJNI=new HelloJniClass();
myJNI.Hello();
}
}
// 아래는 좀 위의 내용 보충 그림
2단계 : 1단계에서 작성한 클래스 컴파일
* 컴파일시에는 일반 java 컴파일때와 마찬가지로 환경변수 셋팅이 되어 있어야 합니다.
-> Path가 JDK의 Javac.exe가 있는 폴더에 설정되어 있어야 합니다.
3단계 : javah를 사용해서 Native Method가 사용할 헤더 파일 생성
HelloJniClass.h을 열어보면
JNIEXPORT void JNICALL Java_HelloJniClass_Hello (JNIEnv *, jobject);
위의 함수를 Implement만 해서 DLL을 만들면 됩니다. (4단계)
4단계 : C언어로 Native Method 실제 구현(1)
1) VC++ 프로젝트 만들기 : Win32용 DLL 프로젝트로 만듭니다.
New - Projects : Win32 Dynamic-Link Library
2) Add Files Projects : HelloJniClass.h 파일 추가
3) Projects Setings(Alt+F7)
- Link탭에 Output file Name : 1단계의 2. 라이브러리 적재시 작성한 DLL파일명(Hello_DLL.dll)
- C/C++탭 Preprocessor 카테고리의 Additional Include directories
JDK의 Include폴더와 Include폴더 밑의 win32폴더
예) C:\Program Files\Java\jdk1.5.0_03\include\,
C:\Program Files\Java\jdk1.5.0_03\include\win32
4. 값의 전달과 리턴
1단계 : Java 소스 파일 StringPass_Jsource.java
* 일반 자바 메쏘드 선언과 동일합니다.
class JNI_Message {
native byte[] Message(String input);
// 라이브러리 적재(Load the library)
static {
System.loadLibrary("Msg_DLL");
}
public static void main(String args[]) {
byte buf[];
// 클래스 인스턴스 생성(Create class instance)
JNI_Message myJNI=new JNI_Message();
// 원시 메소드에 값을 주고 받음
buf = myJNI.Message("Apple");
System.out.print(buf); // 받은값 출력
}
}
2단계 : 컴파일
javac StringPass_Jsource.java
3단계 : header파일 생성
javah JNI_Message
4단계 : method구현 : StringJNIDLLSource.c
#include <stdio.h>
#include <jni.h>
#include <string.h>
#include "JNI_Message.h"
JNIEXPORT jbyteArray JNICALL Java_JNI_1Message_Message (JNIEnv * env, jobject jobj, jstring input)
{
jbyteArray jb;
jboolean iscopy;
char* buf;
static char outputbuf[20];
buf=(*env)->GetStringUTFChars(env, input, &iscopy); // 입력 String 읽어오는 함수
printf ("\nDLL receive Data from JAVA : %s\n",buf); // 입력받은 내용을 출력
strcpy(outputbuf,"Delicious !!\n");
jb=(*env)->NewStringUTF(env, outputbuf); // 출력할 내용의 java버퍼에 output버퍼값을 셋팅
return(jb); // java버퍼 리턴
}
(*env)->함수명 형태로, JAVA의 메쏘드를 C에서 이용할수 있습니다.
* JAVA는 C로 문자열을 넘겨줄때 UTF-8형태를 사용합니다.
5단계 : 실행
C:\test\C_JNI\Paramerter Pass>java JNI_Message
DLL receive Data from JAVA : Apple
Delicious !!
5. KVM ? KNI ?
KVM은 J2ME의 일부로서 작고 자원이 한정된 기계장치를 위해 설계된 소형 JVM.
JVM에서는 JNI가 KVM의 KNI가 있다.
6. 기타프로그래밍 이슈들
참고 URL :http://www.javastudy.co.kr/docs/jhan/javaadvance/jni.html
언어적 이슈(Language Issues)
메소드 호출(Calling Methods)
필드의 참조(Accessing Fields)
스레드와 동기화(Threads and Synchronization)
메모리 이슈(Memory Issues)
수행(Invocation)
스레드 연결(Attaching Threads)
- aString.equals(bString)
하지만 왜 String을 비교할 때만 이렇게 비교하는지 우리는 알고 코딩을 하고 있는 것일까? int, boolean, long 등은 == 로 비교를 하면서 String은 왜 다를까?
지금부터 String을 비교할 때 .equals()와 == 이 어떻게 다른지 알아보자.
일단 코드를 실행해보고 결과를 보면서 진행하겠습니다. 저는 백문이불여일견이라는 말을 좋아하거든요.^^- public class Test {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- new Test().testString();
- }
- public void testString() {
- String a = "TEST";
- String b = "TEST";
- String c = new String("TEST");
- String d = new String("TEST");
- System.out.println("1:"+System.identityHashCode(a));
- System.out.println("2:"+System.identityHashCode(b));
- System.out.println("3:"+System.identityHashCode(c));
- System.out.println("4:"+System.identityHashCode(d));
- System.out.println("5:"+(a == b));
- System.out.println("6:"+a.equals(b));
- System.out.println("7:"+(c == d));
- System.out.println("8:"+c.equals(d));
- }
- }
위 코드를 실행해 보면 결과는 다음과 같이 나옵니다.
결과를 보면 a,b는 hashcode값이 같지만 c,d는 값이 다른 것이 보입니다.
그럼 이번엔 비교한 결과를 볼까요? a,b는 equals()로 비교를 하거나 ==로 비교를 해도 결과는 항상 true 입니다. 하지만 c,d는 equals() 비교를 하면 트루지만 ==로 비교를 하면 false죠.
왜 이런 결과가 나올까요?
이런 결과가 나오는 이유는 equals()는 비교대상의 문자열 리터럴(값)을 비교하고 ==는 대상 객체를 비교하기 때문입니다. 또한 자바에서는 a,b처럼 같은 값을 가지면 하나의 메모리 주소를 참조하게 됩니다. 즉, a,b의 "TEST"라는 문자열 리터럴은 컴파일되면 String 객체가 되는데 a,b는 같은 메모리 주소를 가지게 됩니다. 하지만 c,d는 처음부터 별도의 String 객체로 생성되었기 때문에 동일한 "TEST"라는 문자열 리터럴을 가지지만 서로 다른 객체가 됩니다.무슨말인지 모르시겠다구요? 그럼 그림으로 한번 볼까요?
간단하게 정리하자면 a,b는 문자열 리터럴이 컴파일시에 자동으로 하나의 String 객체가 되고 b,c는 별도의 객체가되어서 문자열 리터럴(값)으로 비교를 하면 a,b,c,d 모두 같지만 객체로 비교를 하게 되면 (a,b),c,d의 3개의 객체가 되는 것입니다.
여기서 이어지는 또다른 의문점... 프리미티브 타입과 Wrapper 클래스의 비교는 어떻게 될까요?
아래 코드를 한번 돌려 보세요. 8번까지는 위 내용과 비슷하지만 9번 결과는 어떻게 나올까요?
다음에는 프리미티브 타입과 Wrapper 클래스, 자동 Boxing, 자동 UnBoxing에 대해서 알아 보도록 하겠습니다.
- package net.westzero;
- public class Test {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- new Test().testInteger();
- }
- public void testInteger() {
- int a = 1;
- int b = 1;
- Integer c = new Integer(1);
- Integer d = new Integer(1);
- System.out.println("1:"+System.identityHashCode(a));
- System.out.println("2:"+System.identityHashCode(b));
- System.out.println("3:"+System.identityHashCode(c));
- System.out.println("4:"+System.identityHashCode(d));
- System.out.println("5:"+(a == b));
- // System.out.println("6:"+a.equals(b));
- System.out.println("7:"+(c == d));
- System.out.println("8:"+c.equals(d));
- System.out.println("9:"+(a == c));
- }
- }
출처 : http://westzero.net/21?category=6
PreparedStatement 를 이용
<%@ page import = "java.sql.PreparedStatement" %>
<%
String query = "select ? from table_name where x = ?";
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setString(1, value_1);
pstmt.setString(2, value_2);
pstmt.close();
>%
Statement를 이용
<%@ page import = "java.sql.Statement" %>
<%
String query = "select ? from table_name where x = ?";
Statement stmt = conn.createStatement();
stmt.executeUpdate(query);
stmt.close();
%>
<noscript> 태그는 브라우저에서 <script> 태그가 작동하지 않을 때 대신 내보낼 내용을 담기 위해 쓰인다.
즉, 방문객이 브라우저에서 자바스크립트가 실행되도록 설정해 두었다면 자바스크립트는 실행되고 <noscript> 태그 안의 내용은 나오지 않는다. 하지만 자바스크립트 기능을 꺼두고 있다면 자바스크립트가 실행되지 않는 대신에 <noscript> 태그 안의 내용이 출력된다.
<script type="text/javascript">
document.write('안녕하십니까?')
</script>
<noscript><p>자바스크립트를 꺼두셨군요.</p></noscript>
위의 예에서, 보통은 자바스크립트가 실행되기 때문에 화면에는 다음 문장이 나올 것이다.
안녕하십니까?
하지만 자바스크립트가 실행되지 않는다면 화면에는 다음 문장이 나오게 된다.
자바스크립트를 꺼두셨군요.
브라우저에서 자바스크립트 기능을 꺼두고 쓰는 사람도 있기 때문에 자바스크립트를 쓴 곳에는 <noscript> 태그를 써서 자바스크립트가 필요하다는 걸 알려주는 게 좋다.
<p><a href="#" onclick="window.open('photo.html'; return false">사진 보기</a></p>
<noscript><p>사진 보기를 하려면 자바스크립트가 필요합니다.</p></noscript>
위 예에서는 자바스크립트를 써서 사진 보기 창을 뜨도록 하고 있으므로, 자바스크립트를 꺼두면 새 창을 뜨게 할 수 없기 때문에 사진을 볼 수 없다. 만약 <noscript> 태그를 쓰지 않는다면 모르는 사람은 왜 사진 보기가 안 되는 걸까 의아해 할지도 모른다. 하지만 <noscript> 태그를 써서, 위와 같이 사진을 보기 위해서는 자바스크립트가 필요하다는 걸 알려준다면 자바스크립트 기능을 꺼두었기 때문에 사진 보기가 안 된다는 걸 알고 사진을 보기 위해 자바스크립트 기능을 켜게 될 것이다.
위 코드의 결과는 다음과 같다. 브라우저에서 자바스크립트 기능을 꺼서 어떻게 보이는지 직접 확인해 보기 바란다.
참고로 photo.html 파일은 만들지 않았으므로 사진 보기를 눌러도 새 창은 뜨지 않을 것이며, <noscript> 태그 안의 글씨는 현재 이곳의 CSS 설정에 따라 크기나 색깔이 다르게 보일 수도 있다.
<noscript> 태그 안의 내용은 웹 문서의 내용과는 상관 없는 것이므로 웹 문서의 내용과는 다르게 보이도록 하는 게 좋다. 예를 들어, CSS에서 설정을 다음과 같이 해 두면 <noscript> 태그 안의 글씨는 돋움 글꼴에 본문 글씨보다 작게 녹색으로 보이게 되므로 웹 문서에 쓰인 글씨가 검은 색이면 서로 구별될 것이다.
noscript { font-family: 돋움, Dotum;
font-size: 75%;
color: green; }
끝으로 한 가지 주의사항은, <noscript> 태그는 <p> 태그를 감쌀 수 있지만 그 반대는 되지 않고, <noscript> 태그 안에 들어 있는 글씨를 <p> 같은 형님 태그로 감싸주지 않으면 웹 표준 검사에서 오류가 난다는 것이다.
String filePath = "D:/SQLException.log";
try {
PrintWriter pw= new PrintWriter(new FileWriter(filePath, true));
pw.write(getLogTime());
pw.write(" : SQLException");
pw.write("\n");
pw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
값이 true일 경우는 File이어쓰기
값이 false일 경우는 File새로쓰기File새로쓰기
File이 없는 경우 자동으로 생성도 해준다.
java.io
클래스 PrintWriter
java.lang.Object java.io.Writer java.io.PrintWriter
- 모든 구현된 인터페이스:
- Closeable , Flushable , Appendable
객체의 서식 첨부 표현을 텍스트 출력 스트림에 출력합니다. 이 클래스는,PrintStream
에 있는 print 메소드를 모두 구현합니다. 다만, raw 바이트를 기입하는 메소드는 포함되지 않습니다. raw 바이트에 대해서는, encode되어 있지 않은 바이트 스트림을 프로그램으로 사용해 주세요.
PrintStream
클래스와는 달라, 자동 플래시가 유효한 경우는, 개행 문자가 출력될 때는 아니고,println,printf,format 의 몇개의 메소드가 불려 갔을 때에 마셔 실행됩니다. 이러한 메소드는, 개행 문자는 아니고, 플랫폼에 고유의 행 단락의 표기를 사용합니다.
이 클래스의 메소드는, 생성자 의 일부를 제외해, 입출력 예외를 throw 할 것은 없습니다. 클라이언트는,checkError()
를 호출하는 것에 의해, 에러가 발생했는지의 여부를 조회할 수 있습니다.
- 도입된 버젼:
- JDK1. 1
필드의 개요 | |
---|---|
protected Writer |
out 이 PrintWriter 의 기본이 되는 문자 출력 스트림입니다. |
클래스 java.io. Writer 로부터 상속된 필드 |
---|
lock |
생성자 의 개요 | |
---|---|
PrintWriter (File file) 행의 자동 플래시는 실시하지 않고 , 지정된 파일로 새로운 PrintWriter 를 작성합니다. | |
PrintWriter (File file, String csn) 행의 자동 플래시는 실시하지 않고 , 지정된 파일과 캐릭터 세트로 새로운 PrintWriter 를 작성합니다. | |
PrintWriter (OutputStream out) 행의 자동 플래시는 실시하지 않고 , 기존의 OutputStream 로부터 새로운 PrintWriter 를 작성합니다. | |
PrintWriter (OutputStream out, boolean autoFlush) 기존의 OutputStream 로부터 새로운 PrintWriter 를 작성합니다. | |
PrintWriter (String fileName) 행의 자동 플래시는 실시하지 않고 , 지정된 파일명으로 새로운 PrintWriter 를 작성합니다. | |
PrintWriter (String fileName, String csn) 행의 자동 플래시는 실시하지 않고 , 지정된 파일명과 캐릭터 세트로 새로운 PrintWriter 를 작성합니다. | |
PrintWriter (Writer out) 행의 자동 플래시는 실시하지 않고 , 새로운 PrintWriter 를 작성합니다. | |
PrintWriter (Writer out, boolean autoFlush) 새로운 PrintWriter 를 작성합니다. |
메소드의 개요 | |
---|---|
PrintWriter |
append (char c) 지정된 문자를 이 라이터에 추가합니다. |
PrintWriter |
append (CharSequence csq) 지정된 문자 순서를 이 라이터에 추가합니다. |
PrintWriter |
append (CharSequence csq, int start, int end) 지정된 문자 순서의 서브 순서를 이 라이터에 추가합니다. |
boolean |
checkError () 스트림이 닫혀지지 않은 경우는, 그 스트림을 플래시 해, 에러 상태를 체크합니다. |
protected void |
clearError () 이 스트림의 에러 상태를 해제합니다. |
void |
close () 스트림을 닫아, 거기에 관련하는 모든 system resource를 해제합니다. |
void |
flush () 스트림을 플래시 합니다. |
PrintWriter |
format (Locale l, String format, Object ... args) 지정된 서식 캐릭터 라인 및 인수를 사용해, 서식 첨부 캐릭터 라인을 이 라이터에 기입합니다. |
PrintWriter |
format (String format, Object ... args) 지정된 서식 캐릭터 라인 및 인수를 사용해, 서식 첨부 캐릭터 라인을 이 라이터에 기입합니다. |
void |
print (boolean b) boolean 형의 값을 출력합니다. |
void |
print (char c) 문자를 출력합니다. |
void |
print (char[] s) 문자의 배열을 출력합니다. |
void |
print (double d) 배정밀도의 부동 소수점수(실수)를 출력합니다. |
void |
print (float f) 부동 소수점수(실수)를 출력합니다. |
void |
print (int i) 정수를 출력합니다. |
void |
print (long l) long 정수를 출력합니다. |
void |
print (Object obj) 객체를 출력합니다. |
void |
print (String s) 캐릭터 라인을 출력합니다. |
PrintWriter |
printf (Locale l, String format, Object ... args) 지정된 서식 캐릭터 라인 및 인수를 사용해, 서식 첨부 캐릭터 라인을 이 라이터에 기입하는 편리한 메소드입니다. |
PrintWriter |
printf (String format, Object ... args) 지정된 서식 캐릭터 라인 및 인수를 사용해, 서식 첨부 캐릭터 라인을 이 라이터에 기입하는 편리한 메소드입니다. |
void |
println () 행의 단락 캐릭터 라인을 기입하는 것으로, 현재의 행을 종료시킵니다. |
void |
println (boolean x) boolean 치를 출력해, 행을 종료시킵니다. |
void |
println (char x) 문자를 출력해, 행을 종료시킵니다. |
void |
println (char[] x) 문자의 배열을 출력해, 행을 종료시킵니다. |
void |
println (double x) 배정밀도 부동 소수점수(실수)를 출력해, 행을 종료시킵니다. |
void |
println (float x) 부동 소수점수(실수)를 출력해, 행을 종료시킵니다. |
void |
println (int x) 정수를 출력해, 행을 종료시킵니다. |
void |
println (long x) long 형의 정수치를 출력해, 행을 종료시킵니다. |
void |
println (Object x) Object 를 출력해, 행을 종료시킵니다. |
void |
println (String x) 캐릭터 라인을 출력해, 행을 종료시킵니다. |
protected void |
setError () 에러가 발생한 것을 나타냅니다. |
void |
write (char[] buf) 문자의 배열을 기입합니다. |
void |
write (char[] buf, int off, int len) 문자의 배열의 일부를 기입합니다. |
void |
write (int c) 단일의 문자를 기입합니다. |
void |
write (String s) 캐릭터 라인을 기입합니다. |
void |
write (String s, int off, int len) 캐릭터 라인의 일부를 기입합니다. |
클래스 java.lang. Object 로부터 상속된 메소드 |
---|
clone , equals , finalize , getClass , hashCode , notify , notifyAll , toString , wait , wait , wait |
필드의 상세 |
---|
out
protected Writer out
- 이
PrintWriter
의 기본이 되는 문자 출력 스트림입니다.- 도입된 버젼:
- 1.2
생성자 의 상세 |
---|
PrintWriter
public PrintWriter(Writer out)
- 행의 자동 플래시는 실시하지 않고 , 새로운 PrintWriter 를 작성합니다.
- 파라미터:
out
- 문자 출력 스트림
PrintWriter
public PrintWriter(Writer out, boolean autoFlush)
- 새로운 PrintWriter 를 작성합니다.
- 파라미터:
out
- 문자 출력 스트림autoFlush
- boolean 치. true 의 경우,println 메소드,printf 메소드, 또는 format 메소드는 출력 버퍼를 플래시 한다
PrintWriter
public PrintWriter(OutputStream out)
- 행의 자동 플래시는 실시하지 않고 , 기존의 OutputStream 로부터 새로운 PrintWriter 를 작성합니다. 이 간이 생성자 은, 필요한 중간의 OutputStreamWriter 를 작성합니다. 이것은, 디폴트의 문자 인코딩을 사용해 문자를 바이트로 변환합니다.
- 파라미터:
out
- 출력 스트림- 관련 항목:
OutputStreamWriter.OutputStreamWriter(java.io.OutputStream)
PrintWriter
public PrintWriter(OutputStream out, boolean autoFlush)
- 기존의 OutputStream 로부터 새로운 PrintWriter 를 작성합니다. 이 간이 생성자 은, 필요한 중간의 OutputStreamWriter 를 작성합니다. 이것은, 디폴트의 문자 인코딩을 사용해 문자를 바이트로 변환합니다.
- 파라미터:
out
- 출력 스트림autoFlush
- boolean 치. true 의 경우,println 메소드,printf 메소드, 또는 format 메소드는 출력 버퍼를 플래시 하는- 관련 항목:
OutputStreamWriter.OutputStreamWriter(java.io.OutputStream)
PrintWriter
public PrintWriter(String fileName) throws FileNotFoundException
- 행의 자동 플래시는 실시하지 않고 , 지정된 파일명으로 새로운 PrintWriter 를 작성합니다. 이 간이 생성자 은, 필요한 중간
OutputStreamWriter
를 작성합니다. 이것은, 이 Java 가상 머신 인스턴스의디폴트 캐릭터 세트를 사용해, 문자를 encode 합니다.- 파라미터:
fileName
- 이 라이터의 행선지로서 사용되는 파일의 이름. 파일이 존재하는 경우는, 사이즈 0 에 절약할 수 있다. 그렇지 않은 경우는, 신규 파일이 작성된다. 출력은 파일에 기입해져 버퍼에 넣어진다- 예외:
FileNotFoundException
- 지정된 캐릭터 라인이 기존의 파일을 나타내지 않는 경우, 기입해 가능한 일반적으로 파일 및 신규의 일반적으로 파일이 그 이름으로 작성할 수 없는 경우, 또는 파일의 오픈 또는 작성중에 그 외의 에러가 발생했을 경우SecurityException
- 시큐리티 매니저가 존재해,checkWrite(fileName)
가 파일에의 기입해 액세스를 거부했을 경우- 도입된 버젼:
- 1.5
PrintWriter
public PrintWriter(String fileName, String csn) throws FileNotFoundException , UnsupportedEncodingException
- 행의 자동 플래시는 실시하지 않고 , 지정된 파일명과 캐릭터 세트로 새로운 PrintWriter 를 작성합니다. 이 간이 생성자 은, 필요한 중간
OutputStreamWriter
를 작성합니다. 이것은, 제공된 캐릭터 세트를 사용해 문자를 encode 합니다.- 파라미터:
fileName
- 이 라이터의 행선지로서 사용되는 파일의 이름. 파일이 존재하는 경우는, 사이즈 0 에 절약할 수 있다. 그렇지 않은 경우는, 신규 파일이 작성된다. 출력은 파일에 기입해져 버퍼에 넣어지는csn
- 지원하는 charset 의 이름- 예외:
FileNotFoundException
- 지정된 캐릭터 라인이 기존의 파일을 나타내지 않는 경우, 기입해 가능한 일반적으로 파일 및 신규의 일반적으로 파일이 그 이름으로 작성할 수 없는 경우, 또는 파일의 오픈 또는 작성중에 그 외의 에러가 발생했을 경우SecurityException
- 시큐리티 매니저가 존재해,checkWrite(fileName)
가 파일에의 기입해 액세스를 거부했을 경우UnsupportedEncodingException
- 지정된 캐릭터 세트가 지원되어 있지 않은 경우- 도입된 버젼:
- 1.5
PrintWriter
public PrintWriter(File file) throws FileNotFoundException
- 행의 자동 플래시는 실시하지 않고 , 지정된 파일로 새로운 PrintWriter 를 작성합니다. 이 간이 생성자 은, 필요한 중간
OutputStreamWriter
를 작성합니다. 이것은, 이 Java 가상 머신 인스턴스의디폴트 캐릭터 세트를 사용해, 문자를 encode 합니다.- 파라미터:
file
- 이 라이터의 행선지로서 사용되는 파일. 파일이 존재하는 경우는, 사이즈 0 에 절약할 수 있다. 그렇지 않은 경우는, 신규 파일이 작성된다. 출력은 파일에 기입해져 버퍼에 넣어진다- 예외:
FileNotFoundException
- 지정된 파일 객체가 기존의 파일을 나타내지 않는 경우, 기입해 가능한 일반적으로의 파일 및 신규의 일반적으로 파일이 그 이름으로 작성할 수 없는 경우, 또는 파일의 오픈 또는 작성중에 그 외의 에러가 발생했을 경우SecurityException
- 시큐리티 매니저가 존재해,checkWrite(file.getPath())
가 파일에의 기입해 액세스를 거부했을 경우- 도입된 버젼:
- 1.5
PrintWriter
public PrintWriter(File file, String csn) throws FileNotFoundException , UnsupportedEncodingException
- 행의 자동 플래시는 실시하지 않고 , 지정된 파일과 캐릭터 세트로 새로운 PrintWriter 를 작성합니다. 이 간이 생성자 은, 필요한 중간
OutputStreamWriter
를 작성합니다. 이것은, 제공된 캐릭터 세트를 사용해 문자를 encode 합니다.- 파라미터:
file
- 이 라이터의 행선지로서 사용되는 파일. 파일이 존재하는 경우는, 사이즈 0 에 절약할 수 있다. 그렇지 않은 경우는, 신규 파일이 작성된다. 출력은 파일에 기입해져 버퍼에 넣어지는csn
- 지원하는 charset 의 이름- 예외:
FileNotFoundException
- 지정된 파일 객체가 기존의 파일을 나타내지 않는 경우, 기입해 가능한 일반적으로의 파일 및 신규의 일반적으로 파일이 그 이름으로 작성할 수 없는 경우, 또는 파일의 오픈 또는 작성중에 그 외의 에러가 발생했을 경우SecurityException
- 시큐리티 매니저가 존재해,checkWrite(file.getPath())
가 파일에의 기입해 액세스를 거부했을 경우UnsupportedEncodingException
- 지정된 캐릭터 세트가 지원되어 있지 않은 경우- 도입된 버젼:
- 1.5
메소드의 상세 |
---|
flush
public void flush()
- 스트림을 플래시 합니다.
- 관련 항목:
checkError()
close
public void close()
- 스트림을 닫아, 거기에 관련하는 모든 system resource를 해제합니다. 벌써 닫혀지고 있는 스트림을 닫아도, 무슨 영향도 없습니다.
- 관련 항목:
checkError()
checkError
public boolean checkError()
- 스트림이 닫혀지지 않은 경우는, 그 스트림을 플래시 해, 에러 상태를 체크합니다.
- 반환값:
- 기본이 되는 출력 스트림상 또는 형식 변환중에, 출력 스트림로 에러가 검출되었을 경우는
true
setError
protected void setError()
- 에러가 발생한 것을 나타냅니다.
이 메소드를 사용하면(자),
clearError()
가 불려 갈 때까지,checkError()
가 계속해 불려 가 true 가 돌려주어집니다.
clearError
protected void clearError()
- 이 스트림의 에러 상태를 해제합니다.
이 메소드를 사용하면(자), 다른 기입 처리가 실패해,
setError()
가 불려 갈 때까지,checkError()
가 계속해 불려 가 false 가 돌려주어집니다.- 도입된 버젼:
- 1.6
write
public void write(int c)
write
public void write(char[] buf, int off, int len)
- 문자의 배열의 일부를 기입합니다.
- 파라미터:
buf
- 문자의 배열off
- 문자의 기입 개시 오프셋(offset)len
- 기입하는 문자수
write
public void write(char[] buf)
- 문자의 배열을 기입합니다. 입출력 예외를 억제해야 하기 때문에, 이 메소드를 Writer 클래스로부터 상속할 수 없습니다.
- 파라미터:
buf
- 기입하는 문자의 배열
write
public void write(String s, int off, int len)
- 캐릭터 라인의 일부를 기입합니다.
- 파라미터:
s
- 캐릭터 라인off
- 문자의 기입 개시 오프셋(offset)len
- 기입하는 문자수
write
public void write(String s)
- 캐릭터 라인을 기입합니다. 입출력 예외를 억제해야 하기 때문에, 이 메소드를 Writer 클래스로부터 상속할 수 없습니다.
- 파라미터:
s
- 기입해지는 캐릭터 라인
public void print(boolean b)
- boolean 형의 값을 출력합니다.
에 의해 작성된 캐릭터 라인은, 플랫폼의 디폴트의 문자 인코딩에 따라 바이트에 변환되어 이러한 바이트는String.valueOf(boolean)
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
b
- 출력되는boolean
치
public void print(char c)
- 문자를 출력합니다. 문자는 플랫폼의 디폴트의 문자 인코딩에 따라 1 개 이상의 바이트에 변환되어 이러한 바이트는
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
c
- 출력되는char
치
public void print(int i)
- 정수를 출력합니다.
에 의해 작성된 캐릭터 라인은, 플랫폼의 디폴트의 문자 인코딩에 따라 바이트에 변환되어 이러한 바이트는String.valueOf(int)
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
i
- 출력되는int
치- 관련 항목:
Integer.toString(int)
public void print(long l)
- long 정수를 출력합니다.
에 의해 작성된 캐릭터 라인은, 플랫폼의 디폴트의 문자 인코딩에 따라 바이트에 변환되어 이러한 바이트는String.valueOf(long)
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
l
- 출력되는long
치- 관련 항목:
Long.toString(long)
public void print(float f)
- 부동 소수점수(실수)를 출력합니다.
에 의해 작성된 캐릭터 라인은, 플랫폼의 디폴트의 문자 인코딩에 따라 바이트에 변환되어 이러한 바이트는String.valueOf(float)
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
f
- 출력되는float
치- 관련 항목:
Float.toString(float)
public void print(double d)
- 배정밀도의 부동 소수점수(실수)를 출력합니다.
에 의해 작성된 캐릭터 라인은, 플랫폼의 디폴트의 문자 인코딩에 따라 바이트에 변환되어 이러한 바이트는String.valueOf(double)
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
d
- 출력되는double
치- 관련 항목:
Double.toString(double)
public void print(char[] s)
- 문자의 배열을 출력합니다. 문자는 플랫폼의 디폴트의 문자 인코딩에 따라 바이트에 변환되어 이러한 바이트는
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
s
- 출력되는 char 의 배열- 예외:
NullPointerException
-s
가null
의 경우
public void print(String s)
- 캐릭터 라인을 출력합니다. 인수가
null
의 경우는, 캐릭터 라인 「null
」가 출력됩니다. 그렇지 않은 경우, 캐릭터 라인의 문자는 플랫폼의 디폴트의 문자 인코딩에 따라 바이트에 변환되어 이러한 바이트는
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
s
- 출력되는String
치
public void print(Object obj)
- 객체를 출력합니다.
메소드에 의해 작성된 캐릭터 라인은, 플랫폼의 디폴트의 문자 인코딩에 따라 바이트에 변환되어 이러한 바이트는String.valueOf(Object)
메소드와 완전히 같은 방법으로 기입해집니다.write(int)
- 파라미터:
obj
- 출력되는Object
치- 관련 항목:
Object.toString()
println
public void println()
- 행의 단락 캐릭터 라인을 기입하는 것으로, 현재의 행을 종료시킵니다. 행의 단락 캐릭터 라인은, 시스템 프로퍼티
line.separator
로 정의되어 반드시 단일의 개행 문자 ('\n'
)이다고는 할 수 없습니다.
println
public void println(boolean x)
- boolean 치를 출력해, 행을 종료시킵니다. 이 메소드는,
를 호출하고 나서print(boolean)
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는boolean
치
println
public void println(char x)
- 문자를 출력해, 행을 종료시킵니다. 이 메소드는,
를 호출하고 나서print(char)
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는char
치
println
public void println(int x)
- 정수를 출력해, 행을 종료시킵니다. 이 메소드는,
를 호출하고 나서print(int)
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는int
치
println
public void println(long x)
- long 형의 정수치를 출력해, 행을 종료시킵니다. 이 메소드는,
를 호출하고 나서print(long)
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는long
치
println
public void println(float x)
- 부동 소수점수(실수)를 출력해, 행을 종료시킵니다. 이 메소드는,
를 호출하고 나서print(float)
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는float
치
println
public void println(double x)
- 배정밀도 부동 소수점수(실수)를 출력해, 행을 종료시킵니다. 이 메소드는,
를 호출하고 나서print(double)
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는double
치
println
public void println(char[] x)
- 문자의 배열을 출력해, 행을 종료시킵니다. 이 메소드는,
를 호출하고 나서print(char[])
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는char
치의 배열
println
public void println(String x)
- 캐릭터 라인을 출력해, 행을 종료시킵니다. 이 메소드는,
를 호출하고 나서print(String)
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는String
치
println
public void println(Object x)
- Object 를 출력해, 행을 종료시킵니다. 이 메소드는, 최초로 String.valueOf(x)를 호출해, 출력된 객체의 캐릭터 라인치를 가져옵니다. 다음에,
를 호출하고 나서print(String)
를 호출하는 것과 같이 동작합니다.println()
- 파라미터:
x
- 출력되는Object
치
printf
public PrintWriter printf(String format, Object ... args)
- 지정된 서식 캐릭터 라인 및 인수를 사용해, 서식 첨부 캐릭터 라인을 이 라이터에 기입하는 편리한 메소드입니다. 자동 플래시가 유효한 경우는, 이 메소드를 호출하면(자) 출력 버퍼가 플래시 됩니다.
이 메소드를 out.printf(format, args) 의 형식에서 호출하면(자), 다음의 호출과 같은 결과가 됩니다.
out.format(format, args)
- 파라미터:
format
- 「서식 캐릭터 라인의 구문」으로 설명한 서식 캐릭터 라인args
- 서식 캐릭터 라인내의 서식 지시자에 의해 참조되는 인수. 서식 지시자 이외에도 인수가 존재하는 경우, 여분의 인수는 무시된다. 인수의 수는 변동해, 제로의 경우도 있다. 인수의 최대수는,Java 가상 머신 스펙으로 정의된 Java 배열의 최대 사이즈의 제한을 받는다. 인수가 null 의 경우, 동작은변환에 응해 다르다- 반환값:
- 이 라이터
- 예외:
IllegalFormatException
- 서식 캐릭터 라인에 부정한 구문, 지정된 인수와 호환성이 없는 서식 지시자, 인수의 지정이 불충분한 서식 캐릭터 라인, 또는 다른 부정한 조건이 포함되는 경우. 가능성이 있는 서식 에러 모든 자세한 것은, Formatter 클래스 스펙의「상세」섹션을 참조NullPointerException
- format 가 null 의 경우- 도입된 버젼:
- 1.5
printf
public PrintWriter printf(Locale l, String format, Object ... args)
- 지정된 서식 캐릭터 라인 및 인수를 사용해, 서식 첨부 캐릭터 라인을 이 라이터에 기입하는 편리한 메소드입니다. 자동 플래시가 유효한 경우는, 이 메소드를 호출하면(자) 출력 버퍼가 플래시 됩니다.
이 메소드를 out.printf(l, format, args) 의 형식에서 호출하면(자), 다음의 호출과 같은 결과가 됩니다.
out.format(l, format, args)
- 파라미터:
l
- 서식 설정시에 적용하는로케일 . l 가 null 의 경우, 로컬라이제이션은 적용되지 않는format
- 「서식 캐릭터 라인의 구문」으로 설명한 서식 캐릭터 라인args
- 서식 캐릭터 라인내의 서식 지시자에 의해 참조되는 인수. 서식 지시자 이외에도 인수가 존재하는 경우, 여분의 인수는 무시된다. 인수의 수는 변동해, 제로의 경우도 있다. 인수의 최대수는,Java 가상 머신 스펙으로 정의된 Java 배열의 최대 사이즈의 제한을 받는다. 인수가 null 의 경우, 동작은변환에 응해 다르다- 반환값:
- 이 라이터
- 예외:
IllegalFormatException
- 서식 캐릭터 라인에 부정한 구문, 지정된 인수와 호환성이 없는 서식 지시자, 인수의 지정이 불충분한 서식 캐릭터 라인, 또는 다른 부정한 조건이 포함되는 경우. 가능성이 있는 서식 에러 모든 자세한 것은, Formatter 클래스 스펙의「상세」섹션을 참조NullPointerException
- format 가 null 의 경우- 도입된 버젼:
- 1.5
format
public PrintWriter format(String format, Object ... args)
- 지정된 서식 캐릭터 라인 및 인수를 사용해, 서식 첨부 캐릭터 라인을 이 라이터에 기입합니다. 자동 플래시가 유효한 경우는, 이 메소드를 호출하면(자) 출력 버퍼가 플래시 됩니다.
이 객체에 대해서 다른 서식 설정 메소드가 먼저 불려 가고 있었는지 어떠했는지에 관계없이,
Locale.getDefault()
에 의해 반환되는 로케일이 항상 사용됩니다.- 파라미터:
format
- 「서식 캐릭터 라인의 구문」으로 설명한 서식 캐릭터 라인args
- 서식 캐릭터 라인내의 서식 지시자에 의해 참조되는 인수. 서식 지시자 이외에도 인수가 존재하는 경우, 여분의 인수는 무시된다. 인수의 수는 변동해, 제로의 경우도 있다. 인수의 최대수는,Java 가상 머신 스펙으로 정의된 Java 배열의 최대 사이즈의 제한을 받는다. 인수가 null 의 경우, 동작은변환에 응해 다르다- 반환값:
- 이 라이터
- 예외:
IllegalFormatException
- 서식 캐릭터 라인에 부정한 구문, 지정된 인수와 호환성이 없는 서식 지시자, 인수의 지정이 불충분한 서식 캐릭터 라인, 또는 다른 부정한 조건이 포함되는 경우. 가능성이 있는 서식 에러 모든 자세한 것은, Formatter 클래스 스펙의「상세」섹션을 참조NullPointerException
- format 가 null 의 경우- 도입된 버젼:
- 1.5
format
public PrintWriter format(Locale l, String format, Object ... args)
- 지정된 서식 캐릭터 라인 및 인수를 사용해, 서식 첨부 캐릭터 라인을 이 라이터에 기입합니다. 자동 플래시가 유효한 경우는, 이 메소드를 호출하면(자) 출력 버퍼가 플래시 됩니다.
- 파라미터:
l
- 서식 설정시에 적용하는로케일 . l 가 null 의 경우, 로컬라이제이션은 적용되지 않는format
- 「서식 캐릭터 라인의 구문」으로 설명한 서식 캐릭터 라인args
- 서식 캐릭터 라인내의 서식 지시자에 의해 참조되는 인수. 서식 지시자 이외에도 인수가 존재하는 경우, 여분의 인수는 무시된다. 인수의 수는 변동해, 제로의 경우도 있다. 인수의 최대수는,Java 가상 머신 스펙으로 정의된 Java 배열의 최대 사이즈의 제한을 받는다. 인수가 null 의 경우, 동작은변환에 응해 다르다- 반환값:
- 이 라이터
- 예외:
IllegalFormatException
- 서식 캐릭터 라인에 부정한 구문, 지정된 인수와 호환성이 없는 서식 지시자, 인수의 지정이 불충분한 서식 캐릭터 라인, 또는 다른 부정한 조건이 포함되는 경우. 가능성이 있는 서식 에러 모든 자세한 것은, Formatter 클래스 스펙의「상세」섹션을 참조NullPointerException
- format 가 null 의 경우- 도입된 버젼:
- 1.5
append
public PrintWriter append(CharSequence csq)
- 지정된 문자 순서를 이 라이터에 추가합니다.
이 메소드를 out.append(csq) 의 형식에서 호출했을 경우, 다음의 호출과 같은 결과를 얻을 수 있습니다.
out.write(csq.toString())
문자 순서 csq 의 toString 의 스펙에 따라서는, 그 순서 전체가 추가되지 않을 가능성도 있습니다. 예를 들어, 문자 버퍼의 toString 메소드를 호출했을 경우, 그 버퍼의 위치와 리밋트에 의해 정해지는 내용을 가지는 서브 순서가 돌려주어집니다.
- 정의:
- 인터페이스
Appendable
내의append
- 오버라이드(override):
- 클래스
Writer
내의append
- 파라미터:
csq
- 추가되는 문자 순서. csq 가 null 의 경우는, 이 라이터에 「null」라고 하는 4 문자가 추가된다- 반환값:
- 이 라이터
- 도입된 버젼:
- 1.5
append
public PrintWriter append(CharSequence csq, int start, int end)
- 지정된 문자 순서의 서브 순서를 이 라이터에 추가합니다.
이 메소드를 out.append(csq, start, end) (csq 는 null 가 아니다)의 형식에서 호출했을 경우, 다음의 호출과 같은 결과를 얻을 수 있습니다.
out.write(csq.subSequence(start, end). toString())
- 정의:
- 인터페이스
Appendable
내의append
- 오버라이드(override):
- 클래스
Writer
내의append
- 파라미터:
csq
- 문자 서브 순서의 추가원이 되는 문자 순서. csq 가 null 의 경우,csq 에 「null」의 4 문자가 포함되는것 같이 문자가 추가되는start
- 문자 서브 순서의 최초의 문자의 인덱스end
- 문자 서브 순서의 마지막 문자에 계속되는 문자의 인덱스- 반환값:
- 이 라이터
- 예외:
IndexOutOfBoundsException
- start 또는 end 가 0 보다 작은 값의 경우,start 가 end 보다 큰 경우, 또는 end 가 csq.length() 보다 큰 경우- 도입된 버젼:
- 1.5
append
public PrintWriter append(char c)
- 지정된 문자를 이 라이터에 추가합니다.
이 메소드를 out.append(c) 의 형식에서 호출했을 경우, 다음의 호출과 같은 결과를 얻을 수 있습니다.
out.write(c)
- 정의:
- 인터페이스
Appendable
내의append
- 오버라이드(override):
- 클래스
Writer
내의append
- 파라미터:
c
- 추가하는 16 비트 문자- 반환값:
- 이 라이터
- 도입된 버젼:
- 1.5
윈도우즈 RDP 포트 변경하기
December 4, 2008 — Digital Angel MasterSource : http://blog.khaddar.net/814
지금까지 여러가지 원격 솔루션을 사용해 봤는데, 윈도우용으로는 LogMeIn이 제일 나은 듯 했으나, 역시 속도면에서는 "원격 데스크톱 연결"을 따라갈 수가 없다. Terminal Service 혹은 RDP라 불리는 이 서비스는 윈도우 XP Professional이상에는 기본으로 제공되며, 간혹 매우 유용하게 사용되는 경우가 많다.
그런데 이 RDP 서비스는 기본적으로 3389번 포트를 사용하는데, 이 포트가 막혀있는 경우가 많이 있다. 이럴 때 위에서 설명한 LogMeIn등을 사용해도 되지만, 터미널서비스의 포트 자체를 변경하는 것도 좋은 방법이 되는 경우가 많다.
포트를 변경하기 위해서는 regedit등의 레지스트리 에디터를 사용하여 다음 키들을 변경하면 된다.
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp\PortNumber
기본값: 0×00000d3d 변경값: 원하는 포트번호
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\PortNumber
기본값: 0×00000d3d 변경값: 원하는 포트번호
주1) 각 키값을 변경할 때 표시형식을 10진수로 변경하여 edit하면 보다 편리하게 값을 바꿀 수 있다.
주2) 키값을 변경한 후에는 재부팅을 하거나 서비스에서 Terminal Service를 재시작시켜주면 된다.
Leave a Reply
아래 문서의 소유권은 getJava에 있으며, 리포스팅에 대한 문의는 getJava로 하시기 바랍니다.
For Beginner ::::: |
Basic Lecture ::::: |
Deep Lecture ::::: |