■ 서블릿 생명주기 메소드 종류 



init()

- 딱 한 번만 호출됩니다.

- 서블릿 컨테이너가 서블릿 객체를 생성한 후 호출합니다.

- 서블릿이 작업하는데 필요한 자원을 준비시키는 코드를 넣습니다.


destroy()

- 딱 한 번만 호출됩니다.

- 웹 어플리케이션의 실행이 멈출 때,

  서블릿이 사용한 자원을 초기화시킬 수 있도록 이 메서드를 호출합니다.

- 서블릿이 사용한 자원을 초기화 시키는 코드를 넣습니다.


service()

- 해당 서블릿에 대해 요청이 들어올 때마다 호출됩니다.

- 클라이언트가 요청한 작업을 처리하는 코드를 넣습니다.



──━━━

# 참고! : servlet-api 설정하기


▶ servlet-api 라이브러리는 서블릿 컨테이너에 포함되어 있습니다.

    따라서 $tmp/wtpwebapps/웹프로젝트명/WEB-INF/lib 폴더에 배치할 필요가 

    없습니다. 단지 서블릿을 만들 때 컴파일 단계에서만 사용하면 됩니다.



만약 특정 라이브러리 정보를 배치에서 제외하고 싶다면?


▶ build.gradle 파일의 dependencies {} 블록에 라이브러리 정보를 등록할 때, 

    'complie' 명령 대신 'providedCompile' 명령을 사용하면 됩니다.




ex) providedCompile 예제!


dependencies {

//complie: 빌드할 때도 사용하고, 배치에도 포함시킨다.

compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'

compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.42'


//providedCompile: 빌드할 때만 사용한다. 배치에는 제외시킨다.

providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'

}




■ javax.servlet.Servlet 인터페이스, Servlet이란?



▶ 서블릿 컨테이너가 클라이언트 요청을 처리하기 위해 

    객체에 대해 호출하는 메서드의 규칙!


▶ 클라이언트 요청을 처리하는 클래슬르 만들 때는

    반드시 이 규칙에 따라 만들어야 합니다. 


▶ 이 규칙에 따라 만든 클래스를 '서블릿(Servlet)'이라고 부릅니다.

블로그 이미지

필로그래머

,

켓의 디렉토리 구조


─────



 > bin
- 톰캣 서버 실행과 관련된 쉘 스크립트 파일 (.sh, bat 등)을 모아둔 곳입니다.

 > conf
- 톰캣 서버를 실행할 때 참조할 설정 파일을 모아둔 곳입니다.

 > lib
- 톰캣 서버를 구성하는 자바 클래스(classs) 라이브러리들을 모아둔 곳입니다.
 
  > logs
- 톰캣 서버를 실행하는 동안 실행 정보와 오류 정보를 기록한 파일을 모아둔 곳입니다.
  client로부터 get 요청이 들어왔는지 post 요청이 들어왔는지도 알 수 있고 
  마지막으로 요청한 정보가 무엇인지, ip address는 어떻게 되는지 등도 
  알 수 있습니다.

  > temp

- 톰캣 서버가 실행하는 동안 임시 데이터를 보관하는 디렉토리입니다.


  > work

- 톰캣 서버가 JSP를 실행할 때 그 중간 파일을 보관하는 곳입니다.


  > webapps

- 웹 애플리케이션을 모아둔 곳입니다.



개발용 웹 애플리케이션 실행 환경

 $workspace/Servers/localhost.../*.xml


- 톰캣 서버의 설정 파일을 복사해 옵니다.
- $tomcat_home/conf 에서 설정파일을 복사해서 생성된 파일입니다.
- 여기서 편집한 설정 파일은 실행환경 임시폴더인 아래 폴더에 저장이 됩니다.

$workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0


또한 

 $workspace/.metadata/.plugins/org.eclipse.wst.server.core/ 폴더에는  
 이 실행환경에서만 사용할 폴더들이 생성이 됩니다.

>logs
>temp
>work
>webapps
>wtpwebapps > 생성한 웹프로젝트 폴더(ex : web01)


그리고 생성한 웹프로젝트 폴더(ex: web01)에는 $workspace/web01/src/WebContent/에 있는 모든 폴더와 파일이 복사가 되구요,  
> web01 > WEB-INF 폴더 안에는 $workspace/web01/src/WebContent/WEB-INF에 있는 모든 폴더와 파일이 복사가 됩니다.

$workspace/web01/bin/ 에는 $workspace/web01/src/에서 컴파일된 *.class 파일이
저장되고 *.properies *.xml 등의 파일이 복사되어 저장됩니다.




─────

톰캣의 디렉토리 구조와 이클립스 웹 프로젝트 폴더 구조





# .class 파일은 java 파일에서 블록 단위의 class {} 마다 생성이 됩니다.  

## 이클립스에는 버그가 있다. 이클립스는 톰캣 서버를 실행시키면 웹 애플리케이션
    프로젝트에서 실행환경 임시폴더(tmp0)로 파일들을 복사 -> 배치 (deploy)시키는데
    자꾸 이전 파일이 로딩되는 경우가 있는 것이다. 이럴 땐 Servers 창에서 서버를
    중단시키고 삭제하고 다시 추가하면 된다. 그러면 다시 실행환경 임시폴더가 생성될 것이다. 
    다시 프로젝트 폴더를 만드는 바보 같은 행동은 하지 말자!
    

 이클립스 웹 어플리케이션 프로젝트 폴더 구조


 이클립스에서 웹 프로젝트를 다룰 때의 폴더 구조입니다.
 IntelliJ 혹은 NetBeans 등 다른 IDE를 사용할 때는 폴더 구조가 다를 수 있습니다.

$workspace/web01
 > src
- 자바 소스 파일을 두는 곳입니다.
 > WebContent : HTML, CSS, JavaScript, GIT 등 정적 웹 자원(static resource)을 두는 곳입니다. JSP 파일도 이 폴더 안에 두는 것이 일반적입니다.
> WEB-INF : 웹 애플리케이션 정보 파일을 두는 곳입니다.
> classes : 자바 클래스 파일(.class)을 두는 곳입니다.
> lib : 자바 라이브러리 파일(.jar)을 두는 곳입니다.
> web.xml : 웹 애플리케이션 설정 파일입니다.



■ 웹 어플리케이션 배치 폴더구조

$deployment_dir : HTML, CSS, JavaScript, GIT 등 정적 웹 자원(static resource)을 두는 곳입니다. JSP 파일도 이 폴더 안에 두는 것이 일반적입니다.

 > WEB-INF : 웹 애플리케이션 정보 파일을 두는 곳입니다.

> classes : 자바 클래스 파일(.class)을 두는 곳입니다.
> lib : 자바 라이브러리 파일(.jar)을 두는 곳입니다.
> web.xml : 웹 애플리케이션 설정 파일입니다.





블로그 이미지

필로그래머

,

[Java] 자바 이클립스 - 톰캣(tomcat)  or 웹 어플리케이션 서버의 실행 환경을 구축해보자! 여기선 톰캣을 예로 들겠다.



이클립스에 톰캣 실행환경 구축하는 방법

 

1) tomcat.apache.org 사이트에 들어가 아래 버전(현재는 8.5.15 - 안정성이 높다)의 zip 파일을 로컬 디스크 (C:)에 다운 받고 압축을 푼다.




2) 톰캣 서버(or 웹 애플리케이션 서버)가 설치된 폴더를 등록한다


Eclipse 실행 - 메뉴창 

 > Window > Preferences > Server 노드 > Runtime Environments > add > Apache  > 다운받은 톰캣 버전을 선택!


 > Browse > apache-tomcat-8.5.15 > ok




3) 톰캣(or 웹 애플리케이션 서버) 실행 환경을 구축해본다

Window > show view> Servers > 창에서 오른쪽 클릭 > new > 다운받은 톰캣 버전 선택! > Finish

 * 웹 애플리케이션 서버 실행 환경은, 이클립스에 설정된 서버에 대해서만 실행

   환경을 구축할 수 잇다.



4) 웹 애플리케이션 서버 실행 환경 시작하기

Servers > 서버실행환경 선택 > start 클릭

 - 웹브라우저의 url 주소에 localhost:8080 을 치면 톰캣 서버가 실행되고 있는 것을

   알 수 있다. (404 error가 뜬다는 것은 서버가 '연결'되었다는 의미이다.)



5) 실행환경이 구축된 폴더 확인하기

workspace 폴더 (ex: c:/workspace)/.metadata/.plugins

/org.eclipse.wst.server.core/tmp0    -----> tmp0은 임시폴더이다!! 이클립스를 제외한

편집기에서 바꾸면 절대 안된다. 이클립스에서 tmp0/server.xml 파일의 포트 번호(port)를 변경할 수 있다.











블로그 이미지

필로그래머

,

[Java] 자바 이클립스 서블릿 (Servlet) 만들기


서블릿 만들기


 1) 서블릿을 만드는 데 필요한 라이브러리를 가져온다.

- mvnrepository.com 에서 'servlet-api'를 검색한다.

- 3.1.x 버전의 gradle 라이브러리 정보를 복사한다.



- 프로젝트 폴더에 있는 build.gradle 파일의 dependencies {} 블록에 추가한다.





- 터미널(명령창)에서 'gradle eclipse'를 실행하여 

  이클립스 설정 파일 (.classpath, .project)을 갱신한다.




- 이클립스 설정 파일을 갱신하였다면, 프로젝트를 'Refresh(F5)' 해야 한다.



2) javax.servlet.Servlet 규칙에 따라 클래스를 작성해본다.


임의의 HelloServlet 클래스 예제


import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class HelloServlet implements Servlet {
 
  public HelloServlet() {
    System.out.println("HelloServlet()");
  }
 
  @Override
  public void init(ServletConfig config) throws ServletException {
    System.out.println("init()");
  }
  @Override
  public ServletConfig getServletConfig() {
    System.out.println("getServletConfig()");
    return null;
  }
  @Override
  public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    System.out.println("service()");

res.setContentType("text/plain;charset=UTF-8");
    PrintWriter out = res.getWriter();
    out.println("Hello, world");
   
  }
  @Override
  public String getServletInfo() {
    System.out.println("getServletInfo()");
    return null;
  }
  @Override
  public void destroy() {
    System.out.println("destroy()");
   
  }
}




서블릿 배포하기


 1) 톰캣 서버에 웹 애플리케이션 폴더를 만든다.

=> $톰캣홈/webapps/만들고싶은폴더명/

 2) 클래스 파일을 배치한다.

=> $톰캣홈/webapps/만든폴더명/WEB-INF/classes/폴더명/HelloServlet.class

 3) 서블릿 정보를 DD 파일에 등록한다.

=> $톰캣홈/webapps/ROOT/WEB-INF/web.xml 파일을 복사한다.

=> $톰캣홈/webapps/만들었던폴더명/WEB-INF/ 아래에 위에서 복사한 파일을 옮긴 후 이클립스로 다음과 같이 파일을 편집한다.


----------------------------------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee

                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

  version="3.1"

  metadata-complete="true">


  <display-name>Welcome to Tomcat</display-name>

  <description>

     Welcome to Tomcat

  </description>

  

  <!-- 서블릿의 클래스 정보를 등록한다. -->

  <servlet>

    <servlet-name>hello</servlet-name> <!-- 서블릿 클래스 별명 -->

    <servlet-class>step24.HelloServlet</servlet-class> <!-- 서블렛 경로 설정 -->

  </servlet>

  

  <!-- HelloServlet에 URL을 부여한다. -->

  <servlet-mapping>

    <servlet-name>hello</servlet-name>

    <url-pattern>/hi</url-pattern> <!-- 반드시 /로 시작해야 한다. -->

  </servlet-mapping>

</web-app>       

----------------------------------------------------------------------------------------


  4) C:\apache-tomcat-8.5.11\bin 경로에서 startup.bat 파일을 실행시켜 톰캣을 켠다.

  5) 웹브라우저를 켜고 url 주소에 "http://www.localhost:8080/test/hi" 를 입력한다.
  6) 화면 창에 out.println("Hello, world"); 결과가 뜬 것을 확인한다.

 맥에서 설정 정보 바꿔주기
     bin./logs 
     > cat catalina.out            : 서블릿 생성자가 호출될 때 메서드를 실행시켜준다.
     > tail -f catalina.out    : 웹브라우저로부터의 요청 정보가 바뀔 때마다 
  위 메서드를 지속적으로 호출시켜줄 수 있도록 설정한다.







블로그 이미지

필로그래머

,

[Java] 자바 인터페이스 (interface)의 기본 문법과 꼭 지켜야 하는 규칙


인터페이스(interface)의 내부 규칙 I

 - 인터페이스는 호출 규칙을 정의하는 것이기 때문에 추상 메서드만 선언 가능하다.

 - 인터페이스는 인스턴스 변수를 가질 수 없다.

   즉 인터페이스에 선언된 모든 메서드는 public이고 abstract이다.

   또한 인터페이스에 선언된 모든 필드(영역)는 public이고 static이며 final이다.



인터페이스(interface) 예제 

public interface A {
  // 1) 규칙이기 때문에 무조건 공개 메서드이고 추상 메서드이다.
  public abstract void m1();
 
  // 2) public을 생략해도 내부적으로 public으로 간주한다.
  abstract void m2();
 
  // 3) abstract를 생략해도 내부적으로 abstract로 간주한다.
  void m3();
 
  // 4) 절대 구현 메서드를 가질 수 없다.
  // void m4() {} // 컴파일 오류!

  // [필드 선언 규칙]
  // 1) 규칙이기 때문에 무조건 공개 필드이고, 스태틱 필드이다
  //    그리고 값을 바꿀 수 없는 상수 필드이다.
 
  public static final int v1 = 200;
 
  // 2) public을 생략하면 내부적으로 public으로 간주한다.
  static final int v2 = 200;
 
  // 3) static을 새약하면 내부적으로 static으로 간주한다.
  final int v3 = 200;
 
  // 4) final을 생략하면 내부적으로 final로 간주한다.
  int v4 = 200;

}





인터페이스(interface)의 규칙 II

 - 인터페이스도 상속 받아 서브 인터페이스를 만들 수 있다.



A 인터페이스로부터 상속 받은 B 인터페이스의 예제


public interface B extends A {

  /*public static final*/ int v5 = 300;
  /*public abstract */ void m4();
}

public interface C extends A {
  /*public static final*/ int v6 = 300;
  /*public abstract */ void m5();
  /*public abstract */ void m6();
}




인터페이스(interface)의 규칙 III

 - 인터페이스는 다중 상속이 가능하다.

 - 어차피 구현되지 않은 메서드이기 때문이다.



B 인터페이스와 C 인터페이스로부터 다중 상속 받은 D 인터페이스 예제

public interface D extends B, C {
  // 어차피 인터페이스의 모든 메서드는 구현된 게 아니기 때문에,
  // 서브 인터페이스에서 수퍼 인터페이스의 메서드를 다시 선언하더라도 문제는 없다.
  // => 다만 부질 없는 짓이다.
  // void m3();
 
  // 다음과 같이 메서드를 추가하는 것은 안된다.
  // 이미 같은 이름을 가지고 파라미터의 타입도 일치하는 메서드가 있는데
  // 리턴 타입만 달리해서 메서드를 선언하면
  // 나중에 크래스에서 이 메서드를 구현할 때 구분할 수 없기 때문에 이것은 불가능하다.
  // int m3(); // 컴파일 오류!
 
  // 파라미터가 다르다면 오버로딩이 가능하기 때문에 괜찮다.
  void m3(int a);
 
  // 파라미터만 다르다면 당연히 오버로딩이 가능하기 때문에 괜찮다.
  int m3(int a, int b);
 
  // B에도 m5()가 있고, C에도 m5()가 있다.
  // 그러나 어차피 구현한 메서드가 아니기 때문에 둘 중 어느 것을 가져와도 된다.
  // 그래서 인터페이스는 다중 상속을 허락한다.
 
  void m7();

}



정리!


B, C 인터페이스의 추상 메서드를 재정의 하는 MyClass 클래스 예제


public class MyClass implements B, C{

  // B와 C의 수퍼 인터페이스는 A의 메서드 구현
  public void m1() {}
  public void m2() {}
  public void m3() {}
 
  // B에 선언된 메서드 구현
  public void m4() {}
  public void m5() {}
 
  // C에 선언된 메서드 구현
  // public void m5() {} // 이미 위에서 m5()를 구현했기 때문에 다시 구현할 필요는 없다.
  public void m6() {}

}



*주의!

- 만약 'E'라는 새로운 인터페이스에서 int m5()를 선언했을 경우,

  MyClass가 E를 상속 받는다면 m5()는 리턴 타입이 다르기 

  때문에 public void m5()로는 B, C, E의 규칙을 충족시킬 수

  없다. 이 경우 컴파일 오류가 발생한다.

- 즉, 인터페이스의 메서드 리턴 타입은 모두 동일해야 한다.






블로그 이미지

필로그래머

,

[Java] 추상 클래스 (abstract class)와 추상 메서드(abstract method)의 개념


추상 클래스와 추상 메서드


 1) 추상 클래스

- 서브 클래스에게 공통 필드와 메서드를 상속해주는 용도로 사용한다.

- 그 자체로 인스턴스를 만들어 사용하지 않는 경우에

  "추상 클래스"로 선언한다.

- 예) Car 클래스는 Sedan, Truck, Bulldozer의 공통 기능을 모아둔 클래스이다.

 이 클래스를 직접 사용하려고 만든 것이 아니다.

 이와 같이 특히 generalization 과정에 생성된 수퍼 클래스인 경우

 주로 추상클래스로 선언한다.

      - 왜? 

        직접 사용하지 말라는 의미이다. 

        상속 받아 쓰라는 의미이다.

        단지 상속 해주는 역할을 한다는 의미이다.

- 실습

- Car 클래스와 Loader 클래스는 직접 사용하기 위해 만든 클래스가 이니다.

  서브 클래스의 공통 필드나 메서드를 관리하기 쉽도록 하기 위해 수퍼

  클래스로 정의한 것이다. 

  그래서 이 클래스들은 abstract로 선언하는 것이 마땅하다.



 2) 추상 메서드

- 서브 클래스 마다 기능을 다루는 방법이 다를 것 같으면

  굳이 수퍼 클래스에서 그 메서드를 정의하지 말라

- 또는 서브 클래스에게 특정 메서드를 반드시 구현하도록 강요(강제)하고 싶다면

  수퍼 클래스에서 그 메서드를 정의하지 말라!

- 이런 메서드인 경우,

   "추상 메서드"로 선언한다.

의미?

  - 서버 클래스를 만드는 개발자, 이 메서드를 반드시 구현하세요.

  - 서브 클래스를 만드는 개발자, 제가 이 메서드를 구현해 봐야 소용이 없을 것 같습니다.

  - 예) Car 클래스의 run() 메서드는 모든 서브 클래스에서 재정의 해야한다.

- 추상 메서드는 추상 클래스 만이 가질 수 있다.

  인스턴스가 생성되어 실제 동작되는 클래스는 추상 메서드를 가질 수 없다.




추상 클래스 Car와 추상 메서드 run()의 예제


public abstract class Car {
  protected String model;
  protected String maker;
  protected int cc;
  public Car() {
    super();
  }
 
  public Car(String model, String maker, int cc) {
    this.model = model;
    this.maker = maker;
    this.cc = cc;
  }
 
  // 이 메서드느 어차피 서브 클래스에서 무조건 재정의할 것이다.
  // 또는 재정의하도록 강제하고 싶다.
  // 그렇다면 여기서 코딩하지 말자
  // 단지 어떤 메서드인지 선언만 하라!
  // 추상 메서드는 구현할 수 없다.
  public abstract void run();
}


Car로부터 상속 받은 추상 클래스 Loader의 예제 
- 짐을 싣는 메서드를 구현


public abstract class Loader extends Car {
  Object storage;
  public Loader() {
    super();
  }
  public Loader(String model, String maker, int cc) {
    super(model, maker, cc);
  }
 
  // 서브 클래스에서도 그냥 사용할 수 없는 메서드라면,
  // 다음 메서드와 같이 수퍼 클래스에서 선언한다.
  public void load(Object obj) {
    this.storage = obj;
    System.out.printf("%s를 실었습니다.\n", obj);
  }

}


Loader로부터 상속 받은 일반 클래스 Sedan의 예제
- Car의 추상 메서드 run()을 오버라이딩한다. 


public class Sedan extends Loader {
  boolean auto;
  public Sedan(String model, String maker, int cc, boolean auto) {
    super(model, maker, cc);
    this.auto = auto;
  }
 
  // 상속 받은 메서드를 서브 클래스의 역할에 맞게끔 재정의하자! 오버라이딩
  public void run() {
    System.out.println("부웅~~ 부드럽게 달린다.");
  }
}



Loader로부터 상속 받은 일반 클래스 Truck의 예제
- Car의 추상메서드 run()과 Loader의 일반메서드 load()를 오버라이딩 한다.

public class Truck extends Loader {
  public Truck(String model, String maker, int cc) {
    super(model, maker, cc);
  }
  // 수퍼 클래스 Car의 run()을 오버라이딩 한다.
  public void run() {
    System.out.println("부왕~~ 힘차게 달린다.");
  }
  // 수퍼 클래스 Loader의 load()를 오버라이딩 한다.
  public void load(Object obj) {
    if (obj != null) {
      super.load(obj);
    } else {
      System.out.println("비었습니다.");
    }
  } 
  public void dump() {
    if (storage != null) {
      System.out.printf("%s를 내렸습니다.\n", this.storage);
      this.storage = null;
    } else {
      System.out.println("내릴 게 없습니다.");
    }
  }

}



* 결론!


- 추상 메서드는 추상 클래스 만이 가질 수 있다.

  인스턴스가 생성되어 실제 동작되는 클래스는 추상 메서드를 가질 수 없다.

- 추상 클래스는 어디까지나 유지보수를 하게 될 개발자에게 자식 클래스에서 

   메서드를 재정의하길 바라는 마음에서, 만들어진 문법이다.




블로그 이미지

필로그래머

,

[Java] 자바 이클립스 JDBC 5. Statement와 PreparedStatement 비교



Statement와 PreparedStatement의 차이

1) 보안

    Statement: 

    - 사용자가 입력한 값을 가지고 SQL문을 만들기 때문에 보안이 취약하다.

    - 즉 악의적으로 SQL의 일부를 포함하는 값을 입력할 수 있다.

    PreparedStatement

    - ?(in-parameter) 자리에 임의의 SQL문을 삽입할 수 없다.

    - 삽입해봐야 단순 문자열로 취급한다.

    - 그래서 보안 문제를 발생시키지 않는다.

2) 바이너리 데이터

    Statement

    - 문자열로 SQL문을 만들기 때문에 바이너리 데이터를 삽입할 수 없다.

    PreparedStatement

    - ?(in-parameter) 자리에 바이너리 데이터를 삽입할 수 있다.

3) 코드의 가독성

    Statement

    - + 연산자를 사용하여 컬럼의 값을 연결하는 식으로 문자열을 만들기 때문에,

      컬럼의 개수가 많으면 문자열을 붙이는 코드도 산만해지고 복잡해진다.

    PreparedStatement

    - setXxx()를 사용하여 값을 넣기 때문에 코드가 간결하다.

4) 실행속도

    서버에 SQL문을 전달하기 전에 서버에서 원하는 형식으로 변환하여 보낸다.

    단순히 SQL을 한 번만 실행한다면 Statement나 PreparedStatement 둘 다 속도가 같다.

    그러나 같은 SQL문을 값을 바꿔가면서 여러 번 실행할 경우,

    PreparedStatement는 SQL문을 컴파일한 후 값만 넣어서 보내기 때문에 속도가 빠르다.

   Statement는 executeXxx()를 실행할 때마다 SQL문을 매번 컴파일하기 때문에 속도가 느리다.

      



JDBC 프로그래밍: PreparedStatement 객체 사용 후

 - 더하기 연산자를 사용하여 SQL문을 만드는 대신,

   in-parameter '?' 를 사용하여 SQL 문을 만든다.



JDBC SQL에서 PreparedStatement의 사용 예제


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class Test05_2 {
  public static void main(String[] args) throws Exception {
    // 원래는 값을 JVM 아규먼트나 프로그램 아규먼트 등 외부로부터 받아야 하지만,
    // 테스트를 원활하게 하기 위해서 변수에 값을 담아 놓자!
   
    String jdbcDriver = "com.mysql.jdbc.Driver";
    String jdbcUrl = "jdbc:mysql://localhost:3306/데이터베이스명";
    String jdbcUsername = "유저명";
    String jdbcPassword = "1111";
   
    String name = "홍길동102";
    String email = "hong102@test.com";
    String tel = "1111-1111";
    String password = "1111";
    try {
      Class.forName(jdbcDriver);
    } catch (Exception e) {
      e.printStackTrace();
    }
   
    try (
      Connection con = DriverManager.getConnection(jdbcUrl, jdbcUsername,jdbcPassword);
       
      // SQL 문을 미리 작성해둔다. 값(문자, 숫자 상관없이)이 들어갈 자리는 ?을 사용하여 비워둔다.
      // 이때 ?를 in-parameter라 부른다.
      // preparedStatement()의 리턴 값은 java.sql.PreparedStatement의 구현체이다.
    PreparedStatement stmt = con.prepareStatement("insert into memb(name, tel, email, pwd) values(?,?,?,password(?))");
    ) {
     
    // SQL문을 서버에 보내기 전에 in-parameter 자리에 값을 채운다.
    // 컬럼의 타입에 따라 호출하는 메서드가 다르다.
    // => setXxx(컬럼인덱스, 값)
    // => 컬럼 인덱스는 1부터 시작한다.
    // 빈자리(in-parameter)에 값을 넣을 때 컬럼의 순서를 지킬 필요는 없다.
    // 그렇다고 굳이 임의 순서대로 넣는 것은 코드의 이해도를 떨어뜨린다.
    stmt.setString(1, name);
    stmt.setString(2,  tel);
    stmt.setString(3, email);
    stmt. setString(4, password);
    // 이렇게 setXxx()를 호출하여 SQL 문을 완성하면,
    // + 연산자를 사용하여 SQL문을 완성하는 방법보다 편리하고 가독성이 좋다.
   
    // 위에서 SQL문을 준비하고 값을 채웠기 때문에 여기에서는 그냥 실행만 하면 된다.
   
    int count = stmt.executeUpdate("insert into memb(name, tel, email, pwd) values('" +
      name + "', '"+
      tel + "', '"+
      email + "', password('" +
      password + "'))");
     
    System.out.println(count);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}



블로그 이미지

필로그래머

,

[Java] 자바 이클립스 JDBC 4. 특정 DBMS에 종속되는 것을 막기


JDBC 프로그래밍 : 특정 DBMS에 종속되는 것을 막기

 - 기존 코드에서는 java.sql.Driver 구현체(이 규칙에 따라 만든 클래스)의

   인스턴스를 만들기 위해 직접 클래스 명을 언급하였다.

   예) com.mysql.jdbc.Driver. driver = new com.mysql.jdbc.Driver();

 - 이렇게 하면 코드가 특정 DBMS에 종속되는 문제가 발생한다.

   즉 다른 DBMS

 - 해결 방법?

    - java.sql.Driver 구현체의 이름을 변수로 받아서 처리한다.


 - 명령창에서 실행하는 법

   > java -cp bin:xxx.jar -Djdbc.driver=com.mysql.jdbc.Driver step20.Test04_1

 - 이클립스에서 실행하는 법

   1) 일단 그냥 실행한다. 그러면 실행 정보가 이클립스에 기록된다.

    Run > Run Configurations... > "Java Application / Test04_1" 선택 >arguments > -Djdbc.driver=com.mysql.jdbc.Driver step20.Test04_1




System.getProperty("...")로 드라이버를 등록하고, 

Class.forName(...)에 드라이버 이름을 주는 예제 ->


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Test04_2 {
  public static void main(String[] args) {
    try {
      // JVM 아규먼트로 java.sql.Driver 구현체의 이름을 받는다.
      String driverClassName = System.getProperty("jdbc.driver");

  // 아규먼트로 넘겨준 문자열로 지정된 클래스를 찾아 로딩한다.
  // => Class.forName("com.mysql.jdbc.Driver")라면,
  //    com.mysql.jdbc.Driver 클래스를 찾아서 로딩한다.
      // => 객체를 만들어서 DriverManager에 등록하지 않아도 자동으로 인식한다.
Class.forName(driverClassName);
./* 참고! 
  * 클래스가 로딩되는 경우, (조건: 클래스가 로딩되어 있지 않을 때)
 1) 인스턴스를 만들 때 - new 연산자
 2) 스태틱 멤버(변수나 메서드)를 사용할 때 - Student.a;
 3) Class.forName()을 호출할 때.
*/
    } catch (Exception e) {
      e.printStackTrace();
      return;
    }
   
    try ( // 이 괄호 안에 선언하는 변수는 오직 java.lang.AutoCloseable 구현체 만이 가능하다.
      Connection con = DriverManager.getConnection(
        "jdbc:mysql://localhost:3306/webappdb",
        "webapp",
        "1111");
   
      Statement stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery("select mno, name, tel, email from memb");
    ) {
      while (rs.next()) {
        System.out.printf("%d, %s, %s, %s\n",
            rs.getInt("mno"),
            rs.getString("name"),
            rs.getString("tel"),
            rs.getString("email"));
      }
     
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}



블로그 이미지

필로그래머

,