달력

42024  이전 다음

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

context root path

 

Servlet

절대경로

 

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

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

 

또는 

 

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

 

또는

 

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

 

또는

 

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

 


 

JAVA

 

절대경로

 

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

 

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

 

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

 

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

 

 

 

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

 

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

 


 

ClassLoader 사용법

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

Posted by 한설림
|

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

try {

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

  

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

throw ex;

} catch(Exception e) {

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

}
 

   

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

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



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

Posted by 한설림
|

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

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

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

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

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

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

일단 사전 조건은 

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


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

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

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

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

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

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

RefreshableSqlSessionFactoryBean.java

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


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

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

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


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

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

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


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


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



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

Posted by 한설림
|

SPRING @RestController, @RequestBody, @ResponseBody, ResponseEntity, @PathVariable



@RestController : 

- @RestController 어노테이션은 각 메소드에 @ResponseBody 어노테이션을 추가 할 필요 없이, @Controller와 @ResponseBody의 조합으로 기능한다.

- Spring version 4부터 새로운 @RestController 어노테이션을 사용할 수 있다.



@RequestBody : 

- 메소드 매개 변수에 @RequestBody가 어노테이션 된 경우, Spring은 들어오는 HTTP request body를 해당 매개 변수에 바인드한다.

- 이를 수행하는 동안 Spring은 HTTP Message converter를 사용하여 요청에 있는 ACCEPT 또는 Content-Type 헤더를 기반으로 HTTP request body를 도메인 객체로 변환한다.



@ResponseBody : 

- 메소드가 @ResponseBody로 어노테이션 된 경우, Spring은 반환 값을 나가는 HTTP response body에 바인딩한다.

- 이를 수행하는 동안 Spring은 요청 메시지의 HTTP 헤더에 있는 Content-Type을 기반으로 HTTP Message converter를 사용하여 반환 값을 HTTP response body로 변환한다.



ResponseEntity : 

- 전체 HTTP 응답을 나타낸다. 

- 상태 코드, 헤더 및 body를 지정할 수 있다. 

- HTTP Response에서 보내려는 정보를 전달하는 여러 생성자가 제공된다.



@PathVariable :

- PathVariable 어노테이션은 메소드 매개 변수가 URI 템플릿 변수에 바인드 되어야 함을 나타낸다.



REF

http://websystique.com/spring-boot/spring-boot-rest-api-example/


Posted by 한설림
|

File

하드디스크 정보를 얻을 수 있다.

 

 

함수

listRoots() : 파일 시스템 루트의 리스트를 반환한다. (C:\, D:\ ......)

getTotalSpace() : 하드디스크 총 용량

getUsableSpace() : 하드디스크 사용 공간

getFreeSpace() : 남은 용량 

     - 남은 용량이 사용 공간과 자꾸 똑같이 나와 그냥 총 용량에서 사용공간을 빼버린 값으로 사용했다..ㅠㅠ

 

 

 

소스코드  

String  drive;

double  totalSize, freeSize, useSize;        

 

File[] roots = File.listRoots();

 

for (File root : roots) {

        

drive = root.getAbsolutePath();

            

totalSize = root.getTotalSpace() / Math.pow(1024, 3);

useSize = root.getUsableSpace() / Math.pow(1024, 3);

freeSize = totalSize - useSize;

 

System.out.println("\n하드 디스크 이름 : " + drive + "\n");

System.out.println("전체 디스크 용량 : " + totalSize + " GB \n");

System.out.println("디스크 사용 용량 : " + freeSize + " GB \n");

System.out.println("디스크 남은 용량 : " + useSize + " GB \n");

}

 

 

결과 

하드 디스크 이름 : C:\

전체 디스크 용량 : 299.99999618530273 GB 

디스크 사용 용량 : 36.1625862121582 GB 

디스크 남은 용량 : 263.83740997314453 GB 

 

하드 디스크 이름 : D:\

전체 디스크 용량 : 165.66210556030273 GB 

디스크 사용 용량 : 2.611347198486328 GB 

디스크 남은 용량 : 163.0507583618164 GB 

 

하드 디스크 이름 : E:\

전체 디스크 용량 : 0.0 GB 

디스크 사용 용량 : 0.0 GB 

디스크 남은 용량 : 0.0 GB 

 

하드 디스크 이름 : F:\

전체 디스크 용량 : 0.0 GB 

디스크 사용 용량 : 0.0 GB 

디스크 남은 용량 : 0.0 GB 


Posted by 한설림
|


request.getContextPath(); 
request.getRequestURI(); 
request.getHeader("REFERER"); 
request.getRealPath("/")


request.getContextPath()는 프로젝트의 Context path명을 반환한다.

요청 : http://localhost:8080/example/test.jsp 

리턴값 : /example




request.getRequestURI()는 웹전체 경로(프로젝트명+ 파일 경로)까지 반환한다.

요청 : http://localhost:8080/example/test.jsp

리턴값 : /example/test.jsp 




request.getHeader("REFERER")는 요청을 한 부모요청의 URL주소를 반환한다.

현재 페이지:  http://localhost:8080/example/test1.do

요청 페이지 :  http://localhost:8080/example/test.do

리턴값 : http://localhost:8080/example/test.do




request.getRealPath("/")는 서버 또는 로컬의 웹애플리케애션 서버의 docBase 설정값을 반환한다.

요청 : http://localhost:8080/example/test.jsp

리턴값 : D:\Project\webapps\example\


Posted by 한설림
|
public class StringFinder {
    public static void main(String[] args) {

        String txt1 = "가나다라" ;
        String txt2 = "해당 내용은 테스트 입니다" ;
        String txt3 = "가격은 29,000원 입니다" ;

        // contains를 이용한 방법(true, false 반환)
        if(txt1.contains("나다"))
            System.out.println("문자열 있음!");
        else
            System.out.println("문자열 없음!");
         
         
        // indexOf를 이용한 방법
        if(txt2.indexOf("테스트") > -1)
            System.out.println("문자열 있음!");
        else
            System.out.println("문자열 없음!");
         
         
        // matches를 이용한 방법
        if(txt2.matches(".*테스트.*"))
            System.out.println("문자열 있음!");
        else
            System.out.println("문자열 없음!");
         
         
        // matches를 이용하여 정규 표현식으로 문자열에 숫자가 있는지 확인
        if(txt3.matches(".*[0-9].*"))
            System.out.println("숫자 있음!");
        else
            System.out.println("숫자 없음!");
    }
}

contains : 문자열에 검색하고자 하는 문자가 있는지 확인 : 포함 - true / 미포함 - false
indexOf 문자열에서 검색하는 문자의 위치를 반환 : 포함 - 문자 위치 / 미포함 - -1 )
matches 정규식을 이용하여 문자열을 검색한다, 특정 문자열을 검색할때 사용하기 보다는 한글, 숫자 등과 같이 해당 형태의 텍스트가 존재하는지 확인할때 사용하면 좋다 : 포함 - true / 미포함 - false

출처 : http://fruitdev.tistory.com/72


Posted by 한설림
|




DispatcherServlet : 클라이언트의 요청을 전달받음. 컨트롤러에게 클라이언트의 요청을 전달하고 컨트롤러가 리턴한 결과 값을 view에 전달하여 알맞은 응답을 생성하도록 한다.


HandlerMapping : 클라이언트의 요청 URL을 어떤 컨트롤러가 처리할 지를 결정

 - SimpleUrlHandlerMapping

 - BeanNameUrlHandlerMapping

 - ControllerClassNameHandlerMapping

 - DefaultAnnotationHandlerMapping


Controller : 클라이언트의 요청을 처리한 뒤, 그 결과를 DispatcherServlet에 알려줌.

 - Controller

 - AbstractController

 - AbstractCommandController

 - SimpleFormController

 - AbstractWizardFormController

 - ParameterizableViewController

 - UrlFilenameViewController

 - MultiActionController


ModelAndView : 컨트롤러가 처리한 결과 정보 및 뷰 선택에 필요한 정보를 담는다.


ViewResolver : 컨트롤러의 처리 결과를 생성할 뷰를 결정


View : 컨트롤러의 처리 결과 화면을 생성

Posted by 한설림
|

JSP 개발 디렉토리와 서비스 디렉토리의 구조의 차이


이클립스를 사용해서 개발을 하는 것은 기존 텍스트 에디터를 이용해서 작업하는 것과 많은 차이를 갖고 있다. 특히 웹 애플리케이션 개발에서는 더 많은 차이가 있게 되는데, 우선 언급해 볼 것이 서비스에 구성된 디렉토리와 개발에 사용되는 디렉토리의 차이점이다.

웹 애플리케이션은 서블릿 스펙에 따라서 디렉토리가 정해진 규칙을 갖고 있다. 

/WEB-INF/ 브라우저를 통해서 접근이 불가능한 웹 애플리케이션 핵심정보들을 포함하고 있는 디렉토리
/WEB-INF/classes/ 패키지에 따른 디렉토리별 class파일과 properties 파일이 위치하는 곳
/WEB-INF/lib/ 웹 애플리케이션에서 사용되는 jar 파일이 존재하는 곳
/META-INF/context.xml 톰캣에서 사용되는 manager를 통한 배포용 웹 애플리케이션 Context정보 파일
브라우저를 통해서 접근 가능한 리소스들은 그 외의 디렉토리에 놓으면 된다.
특히 브라우저의 JVM 위에서 돌아가는 애플릿 class와 관련 jar 들은 /WEB-INF/ 밖에 위치해야 한다.
이 디렉토리들을 묶어서 Context 라고 얘기한다.

서비스와 관련된 디렉토리 구조가 위와 같고, 개발용 디렉토리 구조는 java 파일이라는 특징 때문에 다음과 같이 구성한다.

/src 패키지에 따른 디렉토리별 java 파일과 properties 파일이 존재하는 곳
/WebContent/ 앞에 언급한 브라우저를 통해서 접근 가능한 리소스들. 웹 애플리케이션의 컨텍스트 루트 디렉토리에 해당.
/WebContent/WEB-INF/ 앞에 언급했던 /WEB-INF/ 디렉토리와 같은 성격
/build/classes  /src 하위 자바파일의 컴파일된 class 들이 놓이는 곳. properties 파일은 자동 복사되는 곳.


개발 디렉토리와 WAS의 서비스되는 디렉토리의 매핑 즉 자연스런 연결은 빌드 툴인 ant를 통하거나 Eclipse같은 IDE에서 자동으로 해준다.

이클립스의 경우 Servers 라는 프로젝트가 웹 프로젝트와 별개로 생성이 된다. 여기에서 설정되는 서버의 세팅은 기본적으로 설치된 세팅과 별도로 운영된다. 즉 톰캣이 설치된 디렉토리의 conf 에 있는 설정과는 별개로 Servers하위의 서버별 server.xml 의 파일에 설정된 내용으로 동작이 된다는 뜻이다.
<%= request.getRealPath("/") %> 를 통해서 확인해 보면 이클립스에서 운영하는 디렉토리가 완전히 엉뚱한 곳에 존재함을 알 수 있다. 웹 프로젝트에서 파일을 변경하면 자동으로 파일이 해당 위치로 복사된다.


Posted by 한설림
|

import java.io.*;
import java.net.URLEncoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

 

@Controller
public class Test {

 @RequestMapping("/fileView.do")
 public void fileDownLoad(HttpServletRequest request ,HttpServletResponse response) throws IOException {

  System.out.println(request.getParameter("file_id"));
  String getfile = "C:/DATA001/attachFiles/201610/Koala[20161018010740425].jpg";
  //String path = "C:/DATA001/attachFiles/201610/"; //paramMap.get("filePath"); //full경로
     //String fileName =  "Koala[20161018010740425].jpg"; //paramMap.get("fileName"); //파일명
     File f = new File("C:/DATA001/attachFiles/201610/Koala[20161018010740425].jpg");
     String path = f.getParent().toString();
     String fileName = f.getName();
     System.out.println("파일크기 ?" + f.length());
     FilenameUtils.getExtension(getfile);
     System.out.println("path : " + path);
     System.out.println("fileName : " + fileName);
     File file = new File(path+"/"+fileName);
     FileInputStream fileInputStream = null;
     ServletOutputStream servletOutputStream = null;

     try{
         String downName = null;
         String browser = request.getHeader("User-Agent");
         //파일 인코딩
         if(browser.contains("MSIE") || browser.contains("Trident") || browser.contains("Chrome")){//브라우저 확인 파일명 encode

             downName = URLEncoder.encode(fileName,"UTF-8").replaceAll("\\+", "%20");

         }else{

             downName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");

         }

         response.setHeader("Content-Disposition","attachment;filename=\"" + downName+"\"");
         response.setContentType("application/octer-stream");
         response.setHeader("Content-Transfer-Encoding", "binary;");

         fileInputStream = new FileInputStream(file);
         servletOutputStream = response.getOutputStream();

         byte b [] = new byte[1024];
         int data = 0;

         while((data=(fileInputStream.read(b, 0, b.length))) != -1){

             servletOutputStream.write(b, 0, data);

         }

         servletOutputStream.flush();//출력

     }catch (Exception e) {
         e.printStackTrace();
     }finally{
         if(servletOutputStream!=null){
             try{
                 servletOutputStream.close();
             }catch (IOException e){
                 e.printStackTrace();
             }
         }
         if(fileInputStream!=null){
             try{
                 fileInputStream.close();
             }catch (IOException e){
                 e.printStackTrace();
             }
         }
     }
 }
}

 

Posted by 한설림
|