** 데이터베이스 연동
1. Dynamic Web Project 생성
2. JDBC
3. JDBC를 사용하는 방법
4. 연동 방법
5. 샘플 데이터베이스 생성
6. 데이터베이스 드라이버를 프로젝트에 복사
7. 연동할 데이터베이스 테이블을 표현할 DTO 클래스를 생성
8. Cafe_User 테이블과 연동할 Dao 클래스를 생성하고 필요한 변수와 연결 메소드와 해제 메소드를 생성 - 서버에서 사용하려면 싱글톤 패턴으로 디자인
9. Service 인터페이스와 ServiceImpl 구현
10. Controller 클래스를 생성
11. 시작 페이지 출력 작업
12. 조회 작업
13. 전체 데이터 조회
14. 데이터 삽입
15. 상세보기
16. 데이터 수정
17. 데이터 삭제
** Connection Pool
1. 접속정보를 저장할 context.xml 파일을 META-INF에 생성하고 코드 작성
2. web.xml 파일에 설정 내용을 읽는 코드를 작성
3. CafeUserDao 클래스의 데이터베이스 연결 부분 수정
** 나누어서 읽기
1. 구현 방식
2. 데이터베이스에서 페이징
3. html 이외의 출력
4. 모바일 서버를 만들 때는 여기까지를 가지고 만든다.
5. 웹 페이지에서의 구현
6. 전통적인 방식의 페이징 처리
※ 데이터베이스 연동
- 데이터베이스에 접속
- 프로그래밍 언어와 연동에 필요한 드라이버
1. Dynamic Web Project 생성
- 프로젝트 설정 파일인 web.xml 파일이 포함되도록 생성한다.
- servlet-api.jar 파일과 jstl.jar 파일을 WebContent/WEB-INF/lib 디렉토리에 복사한다.
- servlet-api.jar : JDK SE버전을 설치한 상태에서 HttpServlet 클래스를 사용하기 위해 사용한다.
- jstl.jar : jsp 페이지에서 if나 for를 java 코드를 이용하지 않고 사용하기 위해서 사용한다.
2. JDBC
- Java를 이용해서 데이터베이스에 접속하는 방식을 말한다.
3. JDBC를 사용하는 방법
1) JDK가 제공하는 API를 이용하는 방법
- Connection, Statement(PreparedStatemant, CallableStatement), ResultSet을 이용한다.
2) 프레임워크를 이용하는 방법
- JPA(Hibernate - SI를 제외한 전 분야에서 이용), MyBatis(공공기관 SI에서 주로 이용)
- Spring의 JDBC 프레임워크(공부할 때만 이용)
4. 연동 방법
1) 데이터베이스 드라이버를 애플리케이션에 사용할 수 있도록 복사
- 일반 Application의 경우는 build path에 복사한다.
- web Application의 경우는 WebContent/WEB-INF/lib 디렉토리에 복사한다.
- maven의 경우는 pom.xml에 작성 : Spring 사용할 경우 사용한다.
- gradle의 경우는 json 파일에 작성 : Android 사용할 경우 사용한다.
2) Driver Class를 로드
- 한 번만 수행 - 일반 Java Application에서는 하지 않아도 된다.(우리의 경우 Web을 하기 때문에 해주어야 한다.)
Class.forName(String driverClassName)
- 데이터베이스 종류마다 다르다.
MySQL : com.mysql.jdbc.Driver
Oracle : oracle.jdbc.driver.OracleDriver
3) 데이터베이스 연결
Connection 연결 변수명 = DriverManager.getConnection(String url, String account, String password);
- url은 데이터베이스 종류마다 다르게 설정한다.
- MySQL : jdbc:mysql://HOST:PORT번호/DBNAME
- Oracle : jdbc:oracle:thin:@HOST:PORT번호:SID - Oracle 11g까지 기본
- Oracle : jdbc:oracle:thin:@HOST:PORT번호/SERVICENAME - Oracle 12g 이후 기본
4) 데이터베이스 사용
- Statement를 이용해서 SQL을 실행한다.
- int나 ResultSet으로 실행 결과를 받아서 사용한다.
5) 사용한 자원을 반납 - close()
5. 샘플 데이터베이스 생성
6. 데이터베이스 드라이버를 프로젝트에 복사
- WebContent/WEB-INF/lib 디렉토리에 복사
7. 연동할 데이터베이스 테이블을 표현할 DTO 클래스를 생성
- domain.Cafe_User
8. Cafe_User 테이블과 연동할 Dao 클래스를 생성하고 필요한 변수와 연결 메소드와 해제 메소드를 생성 - 서버에서 사용하려면 싱글톤 패턴으로 디자인
- 클래스 이름 : dao.Cafe_UserDao
- Connection, PreparedStatement, ResultSet을 기본적으로 사용한다.
9. Service 인터페이스와 ServiceImpl 구현
- 사용자의 요청마다 호출되는 형태라 템플릿 메소드 패턴을 적용하고 사용자의 요청 1개에 메소드가 1개씩 매핑되는 것이 좋다.
1) Service 인터페이스를 생성
- service.Cafe_UserService
2) ServiceImpl 클래스를 생성
- service.Cafe_UserServieImpl
- Service 인터페이스를 implements 해야 한다.
- Dao 클래스를 주입받아야 한다.
10. Controller 클래스를 생성
- HttpServlet으로부터 상속받아야 한다.
- Service를 주입받아야 한다.
- 싱글톤을 설정하지 않아도 WAS가 싱글톤으로 처리한다.
- url 패턴을 설정해야 하는데 이전에는 확장자 패턴을 많이 사용했고 최근에는 디렉토리 패턴에 작업을 기재하는 형태로 많이 작성한다.
- cafe_userinsert.do 이런 식이 었는데 최근에는 cafe_user/insert 형태로 많이 작성된다.
- 연습 시에는 cafe_user 디렉토리 패턴을 사용해 본다.
11. 시작 페이지 출력 작업
1) WebContent 디렉토리에 index.html 파일로 생성
2) Controller 클래스의 doGet 메소드에서 시작 요청을 처리하는 코드를 작성
- 시작 요청이 오면 WebContent/index.html로 포워딩하도록 설정
- 단순한 페이지 이동은 포워딩으로 처리
3) 404 에러가 난 경우
- Controller의 가장 상단에 어노테이션에서 처리하지 않는 요청이 아닌지 확인해야 한다.
- doGet 메소드 비교하는 문장에서 요청을 정확하게 처리하였는지 확인해야 한다.
- 포워딩할 주소와 실제 페이지의 위치가 같은지 확인해야 한다.
- 이클립스와 톰캣의 경우 가끔 html 페이지이면 못 읽고 jsp 페이지이면 읽어내는 경우가 발생한다.
12. 조회 작업
- 전체 데이터 조회를 한다던가 데이터 개수를 파악하는 일들을 할 대는 파라미터가 없다.
- 여러 데이터 중 하나의 데이터를 선택해서 조회하는 경우는 파라미터로 기본키의 값을 줘야 한다.
- 조건을 주고 데이터를 조회하는 경우는 파라미터로 조건과 값을 줘야 한다.
- 페이징 처리를 할 때는 현재 페이지 번호와 데이터 개수를 추가로 넘겨줘야 한다.
- 조회를 할 때 매개변수가 많은 경우는 4개(현재 페이지 번호, 페이지 당 데이터 개수, 검색에 사용할 필드명, 검색에 사용할 값)까지 된다.
- 리턴 타입은 4가지
- Scala Type : 데이터 개수를 찾아오는 경우, ID 나 Nickname 존재 여부
- Map이나 DTO : 기본키를 가지고 데이터 1개를 조회하는 경우(상세보기나 로그인)
- List<Scala> : id 목록을 가져오는 등의 경우
- List<Map이나 DTO> : 기본키가 아닌 항목을 가지고 데이터를 조회하는 경우
13. 전체 데이터 조회
1) 요청을 생성 - index.html에 요청을 생성
2) DAO 작업
- 메소드 모양 : public List<Cafe_User> list();
- sql 작성 : cafe_user 테이블의 전체 데이터를 가져오는 SQL문 - select * from cafe_user;
- 데이터가 2개 이상이면 order by를 이용해서 정렬하는 것이 좋은데 기본키로 오름차순 정렬해서 출력하고자 하는 경우는 order by를 사용할 필요가 없다.
- 관계형 데이터베이스는 order by가 없으면 기본키로 오름차순 정렬해서 가져온다.
3) Servier 작업
4) Controller 작업
- 요청에 필요한 Service 메소드를 호출하고 그 결과를 확인해서 필요한 View 페이지로 이동하도록 작성한다.
- 조회는 필요한 메소드를 호출하고 결과 페이지로 포워딩시키면 된다.
- doGet 메소드에 추가한다.
5) View 작업 - Designer가 있는 경우에는 데이터의 모양을 설정하고 이 작업을 동시에 진행한다.
- WebContent에 view 디렉토리를 생성하고 list.jsp를 생성한다.
6) 처리 과정
- index.html에서 전체 데이터 조회를 클릭하면 Cafe_UserController에 doGet 메소드로 가야 한다.
- 여기서 출력이 안되면 URL을 확인해야 한다.
- Cafe_UserController에서 Cafe_UserServiceImpl의 메소드를 호출한다.
- 여기서 출력이 안되면 메소드를 잘못 호출한 것이다.
- Cafe_UserServiceImpl 클래스에서 Cafe_UserDao의 메소드를 호출한다.
- 여기서 출력이 안되면 메소드를 잘못 호출한 것이다.
- Cafe_UserDao 클래스의 마지막에서 리턴할 데이터를 출력한다.
- 여기서 출력이 잘못됐으면 sql과 매개변수를 확인한다.
- 매개변수가 잘못된 경우 Cafe_UserServiceImpl에서 잘못 넘겨주었을 수 있다.
- Cafe_UserServiceImpl에서 Cafe_UserDao 메소드의 매개변수를 출력한다.
- Cafe_UserController의 doGet 메소드로 와서 결과 페이지 이름과 출력 페이지 이름이 정확한지 확인한다.
- 이 부분이 잘못되면 404 에러가 나던지 화면에 아무것도 보이지 않는다.
- list.jsp 파일을 다시 확인한다.
- Cafe_UserServiceImpl에서 저장한 attribute 이름과 출력 내용이 일치하는지 확인한다.
14. 데이터 삽입
- 과정 : 삽입 요청 -> 입력 페이지로 이동 -> 삽입 요청 -> 실제 데이터 삽입 요청 -> Controller -> 입력 페이지로 이동하고 사용자의 입력 -> Controller -> Service -> Dao -> Repository -> Dao -> ServiceImpl -> Controller -> 결과 페이지
- 최근에는 입력 페이지로 이동하고 처리하는 형태에 1개의 URL만 사용하고 입력 페이지로 이동할 때는 GET 방식을 이용하고 처리하는 부분은 POST 방식으로 처리한다.
- 기본키나 unique 속성의 데이터를 입력하는 경우는 중복검사를 해주어야 한다.
- 기본키를 자동 설정하는 경우는 sequence나 auto_increment를 이용하는 경우는 삽입하는 SQL에서 처리하고 가장 큰 번호를 찾아서 +1을 하는 경우에는 Dao에 메소드를 추가해야 한다.
- 가장 큰 번호를 찾아서 +1을 하는 방식은 Oracle이나 MySQL이나 동일하기 대문에 데이터베이스를 변경해도 그대로 두면 된다.
- 하나의 SQL 구문을 별도로 실행해야 한다는 점은 단점이다.
1) index.jsp 파일에 삽입 요청을 생성
<li><a href = "cafe_User/insert">데이터 삽입</a></li>
2) Cafe_UserController 클래스에 위의 요청을 처리하는 코드를 doGet에 삽입
3) WebContent/view/insert.jsp 파일을 추가하고 화면 디자인
4) Cafe_UserDao 클래스에 가장 큰 일련번호를 찾아오는 메소드와 데이터를 삽입하는 메소드를 생성
- 가장 큰 일련번호를 찾아오는 메소드 - select max(cafeusernum) from cafe_user;
public int maxCafeUserNum(){
}
- 데이터를 삽입하는 메소드
- 데이터 삽입과 갱신은 DTO나 Map을 매개변수로 받고 정수를 리턴
- 데이터 삭제는 일반적으로 Primary Key를 매개변수로 받고 정수를 리턴
insert into 테이블 이름(컬럼이름 나열) values(?, ?, ...)
- 고정된 값은 ? 대신에 직접 입력(오라클에서 오늘 날짜는 sysdate, 일련번호는 시퀀스이름.nextval 등, MySQL에서는 Auto_increment는 생략)
public int insert(Cafe_User cafe_User){
}
5) Cafe_UserService 클래스에 데이터 삽입 처리를 위한 메소드를 구현
- Cafe_UserService 인터페이스에 데이터 삽입 처리를 위한 메소드를 선언
- Cafe_UserServiceImpl 클래스에 데이터 삽입 처리를 위한 메소드를 구현
6) Cafe_UserController 클래스의 doGet 메소드에 삽입 요청을 처리하는 코드를 추가
15. 상세보기
- 목록에서 제목을 클릭해서 세부 내용을 확인하는 형태로 구현을 많이 한다.
- 제목에 링크를 설정하게 되고 이 링크에 상세보기를 위한 기본키 값을 같이 전달해야 한다.
- 예전에는 파라미터 형태로 기본키 값을 넘겼는데 최근에는 URL에 포함하는 형태로 많이 구현한다.
1) 목록보기에서 제목 부분에 링크를 설정
- 예전 : </li><td><a href = "detail?cafeusernum=${cafeUser.cafeUserNum}">${cafeUser.cafeUserNum}</a></td>
- 예전 링크의 경우 파라미터를 이용해서 데이터를 전달했는데 최근의 Web의 파라미터는 form의 데이터를 전송할 때 주로 사용하고 url에 데이터를 포함시켜 전송하는 경우가 많다.
- 최근 : </li><td><a href = "detail/${cafeUser.cafeUserNum}">${cafeUser.cafeUserNum}</a></td>
2) CafeUserDao 클래스에 상세보기를 위한 메소드를 구현
3) CafeUserService 인터페이스에 상세보기를 위한 메소드를 구현
4) CafeUserServiceImpl 클래스에 상세보기 처리를 위한 메소드를 구현
5) CafeUserController에서 상세보기 처리를 위한 코드를 doGet에 작성
6) WebContent/view/detail.jsp 파일을 만들어서 데이터 출력
16. 데이터 수정
- 기본키를 가지고 데이터를 찾아와서 출력한 후 수정한 내용을 데이터베이스에 반영
1) CafeUserController 클래스에 데이터 수정을 GET 방식으로 요청하면 처리하는 코드를 doGet 메소드에 작성
- 상세보기랑 데이터 수정화면을 만드는 것은 처리 내용은 같은데 화면 출력 방법이 다르다.
2) update.jsp 파일을 만들고 출력 - 데이터 출력 여부 확인
3) CafeUserDao 클래스에 데이터 수정을 위한 메소드를 생성
- public int update(CafeUser cafeUser) 모양
- sql문
update cafeUser
set userNickname = ?, cafeNickname = ?, cafeVisitDate = ?, cafeOrderHistory = ?
where 기본키 = 값;
where는 생략되는 경우가 있다.
4) CafeUserSevice 인터페이스에 수정 요청을 처리할 메소드를 선언
5) CafeUserServiceImpl 클래스에 수정 요청을 처리할 메소드를 선언
6) CafeUserController 클래스에 수정 요청을 처리하는 코드를 doGet 메소드에 작성
17. 데이터 삭제
1) CafeUserDao 클래스에 데이터 삭제를 위한 메소드를 구현
- java : public int delete(기본키)
- sql : delete from 테이블 이름 where 기본키 = ?
2) CafeUserService 인터페이스에 데이터 삭제와 관련된 메소드를 구현
3) CafeUserServiceImpl 클래스에 데이터 삭제와 관련된 메소드를 선언
4) CafeUserController 클래스의 doGet 메소드에서 삭제 요청을 처리하는 코드를 추가
※ Connnection Pool
- 데이터베이스 연동 시 마다 데이터베이스 연결을 만들어주고 연결을 해제하는 것은 자원의 낭비다. 때문에 미리 데이터베이스 연결 객체를 만들어두고 필요할 때 만들어진 객체를 이용해서 사용하고 필요가 없을 때는 반납하는 방식으로 데이터베이스를 사용하는 것을 말한다.
- 이전에는 Connection Pool을 개발자가 직접 구현했지만 최근에는 라이브러리 형태로 많이 제공된다.
- 여러 종류의 Database Connection Pool 라이브러리가 존재한다.(톰캣에서도 제공한다.)
- 데이터베이스 접속 정보는 일반적으로 개발할 때와 운영을 할 때 다르다.
- 이런 정보를 java코드에 문자열로 만들어서 사용하는 것은 배포를 할 때 불필요한 오류를 발생시킬 수 있다.
- 처음 한 번 사용되고 실행 중에는 변경되지 않고 배포할 때 변경되는 문자열이나 숫자 데이터의 값은 별도의 파일이나 데이터베이스에 저장해두고 사용하는 것이 바랍직하다.
- java web application에서는 META-INF 디렉토리에 context.xml 파일에 내용을 기록해 두고 실행할 때 web.xml이 읽어서 사용하는 방식을 제공한다.
1. 접속정보를 저장할 context.xml 파일을 META-INF에 생성하고 코드 작성
2. web.xml 파일에 위의 설정 내용을 읽는 코드를 작성
3. CafeUserDao 클래스의 데이터베이스 연결 부분 수정
※ 나누어서 읽기
- 데이터는 많은데 화면 크기에 제약이 있기 때문에 데이터를 출력할 때는 전체 데이터를 출력하는 경우 보다는 일부분만 출력하고 필요하면 나머지 부분을 출력하는 방식을 많이 사용한다.
- 이전에는 목록보기에서만 이런 식의 구현이 사용되었는데
1. 구현 방식
1) 전체 데이터를 읽어온 후 보기를 누르면 출력만 해주는 방식
- 한 번 가져오면 잘 변경되지 않는 경우
- 업데이트 이벤트를 만들어 주어야 한다.
- 이렇게 만들어진 대표적 모바일 애플리케이션이 메일 앱
2) 페이지 단위로 데이터를 가져와서 출력하는 방식
- 이 경우는 사용자가 많이 접근하는 형태로 반드시 정렬해서 가져와야 한다.
2. 데이터베이스에서 페이징
1) MySQL은 select 구문의 맨 마지막 limit 시작번호, 데이터개수
- 시작번호는 0부터 시작한다.
2) Oracle은 inline view(from 절에 사용된 select 구문을 말한다.)와 rownum을 이용
3) Mongo DB는 skip과 limit 함수를 이용
3. html 이외의 출력
<%@ page language = "java" contentType = "text/html; charset=UTF-8" pageEncoding = "UTF-8"%>
- 위의 설정에서 contentType이 출력 형식이다.
- cotentType을 text/xml 이라고 설정하면 xml 형식으로 출력할 수 있고 text/json으로 설정하면 json 형시으로 출력할 수 있다.
- json은 기본적으로 제공이 안되기 때문에 json 라이브러리를 이용해서 출력한다.
JSONObject : Map
JSONArray : 배열 - List
4. 모바일 서버를 만들 때는 여기까지를 가지고 만든다.
5. 웹 페이지에서의 구현
- ajax나 web socket의 개념을 알아야 한다.
- 더보기를 구현하면 이전 출력 내용은 그대로 두고 새로 받아온 내용을 전체 화면 갱신 없이 출력을 해야 한다.
- 이 때 사용되는 기술이 ajax와 web socket이다.
- ajax는 한 번 받아오면 연결을 끊는다.
- web socket은 끊는다고 할 때까지 연결을 끊지 않는다.
- 웹 사이트의 광고처럼 요청하지 않아도 서버가 클라이언트에게 데이터를 전송하고자 하면 이 때는 web push(SSE, Notification)를 이용한다.
- ajax, web socket, web push를 합쳐서 web communication api라고도 한다.
- 더보기나 페이징은 ajax를 이용해서 구현한다.
- 최근 웹에서 댓글 작성도 ajax를 이용한다.
- react, vue, angular를 기반으로 하는 SPA(Single Page Application)에서 ajax는 필수이다.
- ajax를 쉽게 사용할 수 있도록 해주는 자바스크립트 라이브러리 중 하나가 jquery이다.
- back end 개발자들은 jquery를 ajax 사용을 쉽게하기 위한 목적과 크로스 브라우징 때문에 이용한다.
6. 전통적인 방식의 페이징 처리
- 하단에 페이지 번호를 출력해두고 페이지 번호를 클릭하면 페이지 번호에 해당하는 데이터를 가져오는 방식
- 전체 페이지 개수를 알아야 한다.
- 전체 페이지 개수와 페이지 당 출력 개수를 알아야 한다.
- 하단에 출력할 시작 페이지 번호와 종료 페이지 번호도 알아야 한다.
- 현재 페이지 번호도 알아야 한다.
- 올림 : Math.ceil, 반올림 : Math.round, 내림 : Math.floor
1) CafeUserDao 클래스에 전체 데이터 개수를 리턴하는 메소드를 생성
- 전체 페이지 개수를 알아야하기 때문이다.
- 페이징 뿐 아니라 더보기를 만들 때도 필요하다.
2) 페이지 번호와 한 페이지에 출력할 데이터 개수를 매개변수로 받아서 페이지 번호에 해당하는 데이터만 리턴하는 함수를 CafeUserDao 생성
- 페이지 당 데이터 개수를 변경할 수 없다면 페이지 당 데이터 개수는 매개변수로 설정하지 않아도 된다.
- 기존 메소드를 그냥 둔 상태에서 매개변수만 다르게 해서 구현하면 Method Overloading이라고 한다.