**데이터 베이스 연동 준비
=> 데이터베이스에 접속
=> 프로그래밍 언어와 연동에 필요한 드라이버 준비
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(PreparedStatement, 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를 로드
=> 한번만 수행 - 일반 Application에서는 하지 않아도 됨
- Class.forName(String driverClassName)
=> 데이터베이스 종류마다 다름
- MySQL : com.mysql.jdbc.Driver
- Oracle : oracle.jdbc.driver.OracleDriver
3) 데이터베이스 연결
=> 형식 : Connection 연결변수명 = DriverManager.getConnect(String url, String account, String password);
=> url은 데이터베이스 종류마다 다르게 설정
- MySQL : jdbc:mysql://HOST:PORT/DBNAME
- Oracle : jdbc:oracle:thin:@HOST:PORT:SID - Oracle 11g까지 기본
jdbc:oracle:thin:@HOST:PORT/SERVICENAME - Oracle 12g이후 기본
4) 데이터베이스 사용
=> Statement를 이용하여 SQL을 실행
=> int나 ResultSet으로 실행 결과를 받아서 사용
5) 사용한 자원을 반납 - close()
5. 샘플 데이터베이스 작성
-- item 테이블
-- code는 정수, 기본키, 자동증가하는 형식
-- title은 고정 문자열(50자 -한글 16자)
-- category는 가변 문자열(50자 -한글16자) - 오라클에서는 varchar2
-- description은 긴 문자열(오라클에서는 clob)
create table Item(
code int primary key auto_increment,
title char(50) not null,
category varchar(50),
description text
)engine=innodb default charset=utf8;
-- 샘플데이터 작성
insert into Item values(1, 'Java', 'language','오픈소스 라이브러리가 많은 범용 프로그래밍 언어');
insert into Item values(2, 'Eclipse', 'IDE', '프로그래밍을 편리하게 할 수 있도록 해주는 오픈 소스 프로그램');
insert into Item values(3, 'Tomcat', 'Web Application Server','apache web server를 이용하는 오픈 소스 프로그램');
insert into Item values(4, 'Oracle', 'DataBase', '대기업이나 공공기관이 주로 사용하는 관계형 DBMS');
insert into Item values(5, 'MySQL', 'DataBase', '오픈 소스 기반의 관계형 DBMS - Maria DB와 거의 동일');
insert into Item values(6, 'MongoDB', 'DataBase', '가장 많이 언급되는 NoSQL');
insert into Item values(7, 'DBeaver', 'DB Tool', '데이터베이스 사용을 쉽게 해주는 프로그램');
insert into Item values(8, 'Spring', 'Framework', '자바 프레임워크');
insert into Item values(9, 'Android', 'Mobile OS', 'OHA 컨소시엄이 만든 Linux 기반의 모바일 운영체제');
insert into Item values(10, 'Android Studio', 'IDE', 'Android 용 프로그램을 개발할 수 있도록 해주는 프로그램');
insert into Item values(11, 'iOS', 'Mobile OS', 'Apple이 만든 unix 기반의 모바일 운영체제');
insert into Item values(12, 'Xcode', 'IDE', 'iOS 및 Mac 용 프로그램을 개발할 수 있도록 해주는 프로그램');
commit;
select * from Item;
6. 데이터 베이스 드라이버를 프로젝트에 복사
=> WebContent/WEB-INF/lib 디렉토리에 복사
- jstl-1.2.jar, mysql-connector-java-5.1.22-bin.jar
7. 연동할 DB 테이블을 표현할 DTO 클래스 작성
=> domain.Item
package domain;
public class Item {
//클라이언트용 프로그램이면 속성 앞의 접근 지정자를 public으로 하고
//생성자만 만들고 접근자 메소드는 만들지 않아도 됨
private int code;
private String title;
private String category;
private String description;
public Item() {
super();
// TODO Auto-generated constructor stub
}
public Item(int code, String title, String category, String description) {
super();
this.code = code;
this.title = title;
this.category = category;
this.description = description;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Item [code=" + code + ", title=" + title + ", category=" + category + ", description=" + description
+ "]";
}
}
8. Item 테이블과 연동할 DAO 클래스 생성후, 필요 변수와 연결, 해제 메소드 생성 - 서버에서 사용시 싱글톤 패턴 사용
=> DAO
=> Connection, PreparedStatement, ResultSet이 필요
package dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class ItemDao {
//데이터베이스 연동에 필요한 변수
private Connection con;
private PreparedStatement pstmt;
private ResultSet rs;
private ItemDao() {
//드라이버 클래스 로드
try {
Class.forName("");
}catch (Exception e) {
System.err.println("드라이버 클래스 로드 실패");
System.out.println(e.getMessage());
e.printStackTrace();
}
}
private static ItemDao itemDao;
public static ItemDao sharedInstance() {
if(itemDao == null)
itemDao = new ItemDao();
return itemDao;
}
//연결 메소드와 해제 메소드
//연결과 해제는 모든 곳에서 사용되는 부분이므로
//중복하여 코딩하지 않기 위해 별도의 메소드로 생성
//이 메소드는 코드의 중복을 회피하기 위해 작성한 메소드이므로
//private로 생성하여 외부 호출 방지
private void connect() {
try {
con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=utf8",
"root", "123123");
}catch (Exception e) {
System.err.println("Connect 실패");
System.out.println(e.getMessage());
e.printStackTrace();
}
}
private void close() {
try {
if(rs != null)
rs.close();
if(pstmt != null)
pstmt.close();
if(con != null)
con.close();
}catch (Exception e) {
System.err.println("Close 실패");
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
9. Service 인터페이스와 ServiceImpl 구현
=> 사용자의 요청마다 호출되는 형태로 템플릿 메소드 패턴을 적용하고 사용자요청 1 : 메소드 1개씩 매핑 권장
1) Service 인터페이스 생성
=> service.ItemService
package service;
public interface ItemService {
}
2) ServiceImpl 클래스를 생성
=> service.ItemServiceImpl
=> Service 인터페이스를 implements
=> Dao 클래스를 주입받아야 함
package service;
import dao.ItemDao;
public class ItemServiceImpl implements ItemService {
private ItemDao itemDao;
private ItemServiceImpl() {
//Dao 인스턴스를 생성
itemDao = ItemDao.sharedInstance();
}
private static ItemService itemService;
public static ItemService sharedInstance() {
if(itemService == null)
itemService = new ItemServiceImpl();
return itemService;
}
}
10. Controller 클래스 생성
=> HttpServlet 으로 부터 상속
=> Service를 주입 받아야 함
=> 싱글톤을 설정하지 않아도 WAS가 싱글톤으로 처리
=> url 패턴을 설정해야 하는데 이전에는 확장자 패턴, 최근에는 디렉토리 패턴에 작업을 기재하는 형태로 작성
- iteminsert.do 같은 방식이었는데, item/insert 형태로 많이 작성
=> item 디렉토리 패턴을 사용
=> controller.ItemConte
package controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import service.ItemService;
import service.ItemServiceImpl;
@WebServlet({ "/", "/item/*" })
public class itemController extends HttpServlet {
private static final long serialVersionUID = 1L;
//서비스 인스턴스 참조 변수
private ItemService itemService;
public itemController() {
super();
itemService = ItemServiceImpl.sharedInstance();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//공통된 부분을 제거한 주소를 만듬
String contextPath = request.getContextPath();
String requestURI = request.getRequestURI();
String command = requestURI.substring(contextPath.length());
//전송방식 저장
String method = request.getMethod();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
Dao는 Service 안에, Service는 Controller안에 들어가야 함
11. 시작 페이지 출력 작업
1) WebContent 디렉토리에 index.jsp 파일로 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Item CRUD</title>
</head>
<body>
<h3>Item CRUD 작업</h3>
</body>
</html>
2) Controller 클래스의 doGet메소드에서 시작요청을 처리하는 코드 작성
=> 시작 요청이 오면 WebContent/index.jsp로 포워딩하도록 설정
=> 단순 페이지 이동은 포워딩으로 처리
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//공통된 부분을 제거한 주소를 만듬
String contextPath = request.getContextPath();
String requestURI = request.getRequestURI();
String command = requestURI.substring(contextPath.length());
//전송방식 저장
String method = request.getMethod();
//시작요청이 온 경우 index.jsp페이지로 포워딩
if(command.equals("/")) {
RequestDispatcher dispatcher = request.getRequestDispatcher("index.jsp");
dispatcher.forward(request, response);
}
}
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.jsp 파일에 요청을 생성
2) DAO 작업
=> 메소드 모양 : public List<Item> list();
=> sql 작성 : item 테이블의 전체 데이터를 가져오는 SQL
- 데이터 1개 : select * from item;
- 데이터가 2개 이상이면 order by를 이용하여 정렬(기본키 오름차순 출력이 default)
3) Service 작업
=> Service 인터페이스에 메소드 구현
public interface ItemService {
//Item 테이블의 모든 데이터를 읽어오는 메소드
public void list(HttpServletRequest request, HttpServletResponse response);
}
@Override
public void list(HttpServletRequest request, HttpServletResponse response) {
//1. 파라미터 읽기
//2. 파라미터 변환 작업이나 알고리즘 처리
//3. 호출할 Dao 메소드의 매개변수를 생성
//4. Dao의 메소드를 호출하여 결과를 저장
List<Item> list = itemDao.list();
//5. Dao 메소드 호출 결과를 View로 전달하기 위해 request나 session에 저장
// 포워딩 할 경우 : request, 리다이렉트 할 경우 : session
request.setAttribute("list", list);
}
4) Controller 작업
=> 요청에 필요한 Service 메소드를 호출하고 그 결과를 확인하여 필요한 View 페이지로 이동하도록 작성
=> 조회는 필요한 메소드를 호출하고 결과 페이지로 포워딩 시키면 됨
=> doGet 메소드에 추가
else if(command.equals("/item/list")) {
//전체 데이터를 가져오는 서비스 메소드를 호출
itemService.list(request, response);
//결과 페이지로 이동
//현재 요청이 /item/list이므로 ../view/list.jsp이면 WebContent/view/list.jsp가 됨
RequestDispatcher dispatcher = request.getRequestDispatcher("../view/list.jsp");
dispatcher.forward(request, response);
}
5) View 작업 - Designer가 있는 경우에는 데이터의 모양을 설명하고 이 작업을 동시에 진행
=> WebContent 디렉토리에 view 디렉토리를 생성하고 list.jsp를 만들어서 출력
6) 처리과정
=> index.jsp에서 전체 데이터 조회를 클릭하면 ItemController의 doGet 메소드로 가야함
- 여기서 출력이 안되면 URL을 확인
=> ItemController에서 ItemServiceImpl의 메소드를 호출
- 여기서 출려깅 안되면 메소드를 잘못 호출
=> ItemServiceImpl 클래스에서 ItemDao의 메소드를 호출
- 여기서 출력이 안되면 메소드를 잘못 호출
=> ItemDao 클래스의 마지막에서 리턴할 데이터를 출력
- 여기서 출력이 잘못되었을 경우 sql과 매개변수를 확인
- 매개변수가 잘못된 경우 ItemServiceImpl에서 잘못 넘겨주었을 수도 있음
=> ItemServiceImpl에서 ItemDao 메소드의 매개변수를 출력
=> ItemController의 doGet 메소드로 와서 결과페이지 이름과 출력페이지 이름이 정확한지 확인
- 이 부분이 잘못되면 404에러가 나던지 화면에 아무것도 보이지 않음
=> list.jsp 파일을 다시 확인
- ItemServiceImpl에서 저장한 attribute 이름과 출력 내용이 일치하는지 확인
13. 데이터 삽입
=> 과정 : 삽입 요청 -> 입력 페이지로 이동 -> 삽입요청 -> 실제 데이터 삽입요청 -> Controller -> 입력페이지로 이
동 및 사용자의 입력 -> Controller -> Service -> Dao -> Repository -> Dao -> ServiceImpl -> Controller -> 결
과 페이지
=> 기본키
- 기본키나 Unique 속성의 데이터를 입력하는 경우는 중복검사를 해주어야 함
- 기본키를 자동설정하는 경우 sequence나 auto)increment를 이용하는 경우는 삽입하는 SQL에서 처리
- 가장 큰 번호를 찾아 +1하는 경우 Dao에 메소드를 추가해야 함
=> 가장 큰 번호를 찾아서 +1하는 방식은 Oracle, MySQL이 동일하므로 데이터 베이스를 변경해도 그대로 둬도 됨
- 하나의 SQL구문을 별도로 실행해야 한다는 점은 단점
1) index.jsp 파일에 삽입 요청을 생성
- <li><a href="item/insert">데이터 삽입</a></li>
2) ItemController 클래스에 위의 요청을 처리하는 코드를 doGet에 삽입
else if(command.equals("/item/insert") && method.equals("GET")) {
//입력 페이지로 이동
RequestDispatcher dispatcher = request.getRequestDispatcher("../view/insert.jsp");
dispatcher.forward(request, response);
}
3) WebContent/view/insert.jsp 파일을 추가하고 화면 디자인
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>데이터 입력 화면</title>
</head>
<body>
<h3>아이템 입력</h3>
<!-- title, category, description을 입력 -->
<form method="post" id="itemform">
카테고리
<select name="category" id="category">
<option value="language">언어</option>
<option value="IDE">통합개발환경</option>
<option value="Database">데이터베이스</option>
<option value="etc">기타</option>
</select><br />
제목<input type="text" name="title" id="title"/>
<br/>
설명<textarea rows="10" cols="30"
name="description" id="description"></textarea>
<input type="submit" value="전송" />
<input type="button" value="메인" id="mainbtn"/>
</form>
</body>
<script>
document.getElementById("mainbtn")
.addEventListener("click", function(){
location.href = "../";
})
</script>
</html>
4) ItemDao 클래스에 가장 큰 code를 찾아오는 메소드와 데이터를 삽입하는 메소드를 생성
=> 가장 큰 code를 찾아오는 메소드 - select max(code) form item
//가장 큰 글번호를 찾아오는 메소드
public int maxCode() {
int result = 0;
connect();
try {
pstmt.getConnection().prepareStatement("select max(code) from item");
//SQL을 실행
rs = pstmt.executeQuery();
if(rs.next()) {
result = rs.getInt("max(code)");
}
}catch (Exception e) {
System.err.println("가장 큰 글번호 찾기 에러");
System.out.println(e.getMessage());
e.printStackTrace();
}
close();
return result;
}
=> 데이터를 삽입하는 메소드
- 데이터 삽입과 갱신은 DTO나 Map을 매개변수로 받고 정수를 리턴
- 데이터 삭제는 일반적으로 Primary Key를 매개변수로 받고 정수를 리턴
- insert into 테이블명(컬럼명 나열) values(?, ?....)
=> 고정된 값을 ?대신에 직접입력(오라클 오늘날짜: sysdate, 일련번호는 시퀀스명, MyASQL : Auto_increment 생략
public int insert(Item item) {
//-1로 초기화하여 -1이 리턴되면 작업 실패
int result = -1;
connect();
try {
pstmt = con.prepareStatement("insert into item(code, category, title, description) "
+ "values(?, ?, ?, ?)");
//?의 값을 바인딩
pstmt.setInt(1, item.getCode());
pstmt.setString(2, item.getCategory());
pstmt.setString(3, item.getTitle());
pstmt.setString(4, item.getDescription());
//SQL 실행
result = pstmt.executeUpdate();
}catch (Exception e) {
System.err.println("삽입 에러");
System.out.println(e.getMessage());
e.printStackTrace();
}
close();
return result;
}
5) ItemService 클래스에 데이터 삽입처리를 위한 메소드를 생성
=> ItemService 인터페이스에 데이터 삽입처리를 위한 메소드를 선언
//Item 테이블에 데이터를 저장하는 메소드
public void insert(HttpServletRequest request, HttpServletResponse response);
=> ItemServiceImpl 클래스에 삽입처리를 위한 메소드 구현
@Override
public void insert(HttpServletRequest request, HttpServletResponse response) {
//1. 파라미터 읽기
String category = request.getParameter("category");
String title = request.getParameter("title");
String description = request.getParameter("description");
//2. 파라미터를 가지고 필요한 작업 수행
//가장 큰 code를 찾고 +1하여 code에 대입
int code = itemDao.maxCode() +1;
//3. 호출할 Dao 메소드의 매개변수를 생성
Item item = new Item();
item.setCode(code);
item.setCategory(category);
item.setTitle(title);
item.setDescription(description);
//4. Dao의 메소드를 호출하여 결과를 저장
int result = itemDao.insert(item);
//5. 결과를 저장
request.getSession().setAttribute("result", result);
}
6) ItemItemController 클래스의 doGet 메소드에 삽입요청을 처리하는 코드를 추가
else if(command.equals("/item/insert") && method.equals("POST")) {
//삽입을 처리
itemService.insert(request, response);
//삽입하고 결과 페이지로 이동
//작업을 수행했으므로 목록보기로 리다이렉트
response.sendRedirect("list");
}
14. 상세보기(파라미터 이용하기)
=> 목록에서 제목을 클릭하여 세부내용을 확인하는 형태로 많이 구현 함
- 제목에 링크를 설정, 이 링크에 상세보기를 위한 기본키 값을 같이 전달해야 함
- 예전에는 파라미터 형태로 기본키 값을 넘겼는데 최근에는 URL에 포함하는 형태로 구현
1) 목록보기에서 제목부분에 링크를 설정
<td> <a href="item/detail?code=${item.code}">${item.title}</a></td>
=> 예전의 링크의 경우 파라미터를 이용해서 데이터를 전달 했는데 최근의 Web에서는 파라미터는 form의 데이터를
전송할 때 주로 사용하고 url에 데이터를 포함시켜 전송하는 경우가 많음
2) ItemDAO 클래스에 상세보기를 위한 메소드를 구현
//상세보기를 위한 메소드
public Item detail(int code) {
Item item = null;
connect();
try {
//sql 생성
pstmt = con.prepareStatement("select * from item where code = ?");
pstmt.setInt(1, code);
//SQL 실행
rs = pstmt.executeQuery();
//하나의 행이 나오는 쿼리 결과 처리
if(rs.next()) {
item = new Item();
item.setCode(rs.getInt("code"));
item.setTitle(rs.getString("title"));
item.setCategory(rs.getString("category"));
item.setDescription(rs.getString("description"));
}
}catch (Exception e) {
System.err.println("상세보기 에러");
System.out.println(e.getMessage());
e.printStackTrace();
}
close();
return item;
}
3) ItemService 인터페이스에 상세보기 처리를 위한 메소드를 선언
//상세보기 처리를 위한 메소드
public void detail(HttpServletRequest request, HttpServletResponse response);
4) ItemServiceImpl 클래스에 상세보기 처리를 위한 메소드를 구현
@Override
public void detail(HttpServletRequest request, HttpServletResponse response) {
//1. 파라미터 읽기
try {
request.setCharacterEncoding("utf-8");
}catch (Exception e) {
System.err.println("인코딩 에러");
System.out.println(e.getMessage());
e.printStackTrace();
}
String code = request.getParameter("code");
//2. 파라미터를 가지고 일반적인 처리
//3. DAO 메소드의 매개변수 만들기
int c = Integer.parseInt(code);
//4. DAO 메소드를 호출하여 결과를 저장
Item item = itemDao.detail(c);
//5. 이동방법에 따라 사용할 데이터를 저장
request.setAttribute("item", item);
}
5) ItemController에서 상세보기 처리를 위한 코드를 doGet에 작성
else if(command.equals("/item/detail")) {
//상세보기 처리
itemService.detail(request, response);
//겨로가 페이지로 이동
RequestDispatcher dispatcher = request.getRequestDispatcher("../view/detail.jsp");
dispatcher.forward(request, response);
}
6) WebContent/view/detail.jsp 파일을 만들어서 데이터 출력
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상세보기</title>
</head>
<body>
<table border="1" align="center">
<tr>
<td>제목</td>
<td>${item.title}</td>
</tr>
<tr>
<td>내용</td>
<td>${item.description}</td>
</tr>
<tr>
<td colspan="2" align="center">
<!-- 수정과 삭제는 기본키를 넘겨받아야 합니다. -->
<!-- 절대 경로로 링크를 생성 -->
<a href="${pageContext.request.contextPath}/item/update/${item.code}">수정</a>
<a href="${pageContext.request.contextPath}/item/delete/${item.code}">삭제</a>
<a href="${pageContext.request.contextPath}/item/list">목록</a>
</td>
</tr>
</table>
</body>
</html>
15. 데이터 수정
=> 기본키를 가지고 데이터를 찾아와서 출력한 후 수정한 내용을 데이터 베이스에 반영
1) ItemController 클래스에 데이터 수정을 GET방식으로 요청하면 처리하는 코드를 doGET 메소드에 작성
=> 상세보기랑 데이터 수정화면을 만드는 것은 처리 내용은 같은데 화면 출력 방법이 다름
else if(command.indexOf("/item/update") >= 0) {
//상세보기를 처리
itemService.detail(request, response);
//결과 페이지로 이동
//결과 페이지에 jsp 파일이 제대로 생성되었는지 확인
RequestDispatcher dispatcher =
request.getRequestDispatcher(
"../../view/update.jsp");
dispatcher.forward(request, response);
}
2) update.jsp 파일을 만들고 출력 - 데이터 출력 여부를 확인
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>데이터 수정</title>
</head>
<body>
<!-- action을 생략하면 이전과 동일한 요청 -->
<h3>데이터 수정</h3>
<form method="post">
코드<input type="text" value="${item.code}"
name="code" id="code" readonly="readonly" /><br/>
카테고리<input type="text" value="${item.category}"
name="category" id="category" readonly="readonly" /><br/>
이름<input type="text" value="${item.title}"
name="title" id="title" /><br/>
설명<textarea name="description" id="description"
rows="10" cols="30">
${item.description}</textarea><br/>
<input type="submit" value="수정" />
<input type="button" value="메인" id="mainbtn"/>
<input type="button" value="목록" id="listbtn"/>
</form>
</body>
<script>
document.getElementById("mainbtn")
.addEventListener("click", function(event){
location.href=
"${pageContext.request.contextPath}/";
});
document.getElementById("listbtn")
.addEventListener("click", function(event){
location.href=
"${pageContext.request.contextPath}/item/list";
});
</script>
</html>
3) ItemDao 클래스에 데이터 수정을 위한 메소드를 생성
=> public int update(Item item)모양
=> sql
- update 테이블 명
set 수정할 컬럼 = 값, 수정할 컬럼=값..
where 기본키 = 값;
- where가 생략되는 경우도 있음
public int update(Item item) {
//-1로 초기화해서 -1이 리턴되면 작업 실패
int result = -1;
connect();
try {
pstmt = con.prepareStatement("update item set title=?, description=? where code=?");
//?에 값을 바인딩
pstmt.setString(1, item.getTitle());
pstmt.setString(2, item.getDescription());
pstmt.setInt(3, item.getCode());
//SQL 실행
result = pstmt.executeUpdate();
}catch(Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
close();
return result;
}
4) ItemServie 인터페이스에 수정요청처리할 메소드를 선언
//수정 처리를 위한 메소드
public void update(HttpServletRequest request, HttpServletResponse response);
5) ItemServiceImpl 클래스에 수정 요청을 처리할 메소드를 구현
@Override
public void update(HttpServletRequest request, HttpServletResponse response) {
//1.파라미터를 읽기
try {
request.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String code = request.getParameter("code");
String title = request.getParameter("title");
String description = request.getParameter("description");
String category = request.getParameter("category");
//Dao 의 파라미터 만들기
Item item = new Item();
item.setCode(Integer.parseInt(code));
item.setTitle(title);
item.setDescription(description);
item.setCategory(category);
int result = itemDao.update(item);
//웹 사이트만 고려하면 저장할 필요가 없습니다.
request.getSession().setAttribute("result", result);
}
6) ItemController 클래스에 수정 요청을 처리하는 코드를 doGet 메소드에 작성
else if(command.indexOf("/item/update") >= 0 && method.equals("GET")) {
//상세보기를 처리
itemService.detail(request, response);
//결과 페이지로 이동
//결과 페이지에 jsp 파일이 제대로 생성되었는지 확인
RequestDispatcher dispatcher =
request.getRequestDispatcher(
"../../view/update.jsp");
dispatcher.forward(request, response);
}else if(command.indexOf("/item/update") >= 0
&& method.equals("POST")) {
//데이터 수정을 처리
itemService.update(request, response);
//결과 페이지로 이동
response.sendRedirect("..list");
}
16. 데이터 삭제
1) ItemDao 클래스에 데이터 삭제를 위한 메소드를 구현
=> public int delete(기본키) 의 형태
=> sql : delete from 테이블명 where 기본키=?;
//데이터 삭제를 위한 메소드
public int delete(int code) {
int result = -1;
connect();
try {
pstmt = con.prepareStatement(
"delete from item where code = ?");
pstmt.setInt(1, code);
result = pstmt.executeUpdate();
}catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
close();
return result;
}
2) Item 인터페이스에 데이터 삭제와 관련된 메소드를 생성
//삭제 처리를 위한 메소드
public void delete(HttpServletRequest request, HttpServletResponse response);
3) ItemServiceImpl 클레스에 데이터 삭제와 관련된 메소드를 구현
@Override
public void delete(HttpServletRequest request, HttpServletResponse response) {
//마지막 /뒤의 값 가져오기
String[] ar =request.getRequestURI().split("/");
String code = ar[ar.length-1];
int result = itemDao.delete(Integer.parseInt(code));
request.getSession().setAttribute("result", result);
}
4) ItemController 클래스의 doGet 메소드에서 삭제 요청을 처리하는 코드를 추가
else if(command.indexOf("/item/delete") >= 0) {
//데이터 삭제를 처리
itemService.delete(request, response);
//결과 페이지로 이동
response.sendRedirect("../list");
}
**Connection Pool
=> 데이터베이스 연동시마다 데이터베이스 연결을 만들어주고 연결을 해제하는 것은 자원의 낭비
- 미리 데이터베이스 연결 객체를 만들어 두고 필요시 만들어진 객체를 이용하여 사용, 불필요 시는 반납하는 방식으로 데이터베이스를 사용하는 것을 Connection Pool이라고 함
- 이전에는 Connection Pool을 개발자가 직접 구현했지만 최근에는 라이ㅡ러리 형태로 많이 제공
- 여러 종류의 DataBase Connection Pool 라이브러리가 존재(톰캣에서도 제공)
=> 데이터베이스 접속정보는 일반적으로 개발시와 운영시는 다름
- 이런 정보를 java 코드에 문자열로 만들어서 사용하는 것은 배포시 불필요한 오류 발생
- 처음 1회 사용되고 실행중에는 변경X, 배포시 변경되는 문자열이나 숫자데이터의 값은 별도의 파일이나 데이터베이스에 저장해두고 사용하는 것이 바람직
=> java web application에서는 META-INF 디렉토리
3.
**나누어서 읽기
=> 많은 데이터 출력시 화면 크기에 제약이 있어 일부분만 출력하고 필요시 나머지 부분을 출력하는 방식을 사용
- 이전에는 목록보기에서만 이런식의 구현이 사용되었는데 최근에는 상세보기에서도 이방식이 사용됨
1. 구현 방식
1) 전체 데이터를 읽어온 후 보기를 누르면 출력만 해주는 방식
=> 한번 가져오면 잘 변경되지 않는 경우
=> 업데이트 이벤트를 만들어 주어야 함
=> 이렇게 만들어진 대표적인 모바일 애플리케이션이 메일 앱
2) 페이지 단위로 데이터를 가져와서 출력하는 방식
=> 이 경우는 사용자가 많이 접근하는 형태로 반드시 정렬하여 가져와야 함
2. 데이터베이스에서 페이징
1) MySQL은 select 구문의 맨 마지막 limit 시작번호, 데이터 개수
=> 시작번호는 0부터 시작
2) Oracle은 inline view(from 절에 사용된 select 구문)이용
3) Mongo DB는 skip과 limit 함수를 이용
3. Html 이외의 출력
<%@ page language="java" contentType="text/html; charset=UTF-8 pageEncoding="UTF-8"%>
=> 위의 설정에서 contentType이 출력 형식
- contentType을 text/xml로 설정시, xml 형식으로 출력할 수 있고 text/json으로 설정시 json형식으로 출력 가능
- json은 기본적으로 제공이 안되므로 json라이브러리를 이용하여 출력
- JSONObject : Map
- JSONArray : 배열 - List
4. 모바일 서버를 만들때는 여기까지를 가지고 만듬
5. 웹 페이지에서의 구현
=> ajax나 webSocket의 개념을 알아야 함
=> 더보기 구현시 이전 출력 내용은 그대로 두고, 새로 받아온 내용을 전체화면 갱신없이 출력해야 함
- 이때 사용되는 기술이 ajax와 webSocket
- ajax는 한번 받아오면 연결을 끊음
- web Socket은 끊는다고 할 때 까지 연결을 끊지 않음
=> 요청하지 않아도 서버가 클라이언트에게 데이터를 전송(웹사이트 광고)할때, webPush(SSE, Notification)을 이용
=> ajax, web Socket, web Push를 합쳐서 web Communication api라고 함
=> 더보기나 페이징은 ajax를 이용해서 구현
- 최근의 웹에서 댓글 작성도 ajax를 이용
=> react, vue, angular를 기반으로 하는 SPA(Single Page Application)에서 ajax는 필수
=> ajax를 쉽게 사용할 수 있도록 해주는 자바스크립트 라이브러리 중 하나가 jquery
- bakcend 개발자들은 jquery를 ajax 사용을 쉽게 하기 위한 목적과 크로스 브라우징 때문에 이용
6. 전통적인 방식의 페이징 처리
=> 하단에 페이지 번호를 출력해두고 페이지 번호를 클릭하면 페이지 번호에 해당하는 데이터를 가져오는 방식
=> 필요한 데이터
- 현재 페이지 번호
- 페이지당 출력할 데이터 개수 : 최근 웹페이지에서 보면 출력 데이터 개수를 설정하는 경우가 있으므로 필요
(고정된 값일시 생략)
- 현재 페이지 번호에 해당하는 데이터를 찾아올수 있어야 함
- 데이터 하단에 출력할 페이지 번호를 찾아야 함
- 종료 페이지 번호를 구해야 하는데 이 번호는 현재 페이지 번호, 한 페이지에 출력할 페이지 번호의 개수로 계산
- 종료 페이지 번호에서 한 페이지에 출력할 페이지 번호의 개수 -1을 빼면 시작하는 페이지번호가 만들어짐
- 전체 데이터 개수와 페이지당 출력할 데이터 개수를 가지고 전체 페이지 개수를 구함
- 종료 페이지 번호가 전체 페이지 개수보다 크면 종료 페이지 번호를 전체 페이지 개수로 변환
- 시작 페이지 옆의 이전 페이지로 이동할 수 있는 링크의 생성 여부를 결정
(시작 페이지 번호가 1이면 없고, 1이 아니면 있어야 함)
- 종료 페이지 번호 옆의 다음페이지로 이동할 수 있는 링크의 생성여부를 결정
(종료 페이지 번호가 전체페이지 번호와 동일하면 없고, 그렇지 않으면 있어야 함)
- 페이지 번호를 출력하지 않고 더보기, 스크롤로 구현할 경우 시작페이지번호, 시작, 다음은 필요 없음
=> 올림 : Math.ceil, 반올림 : Math.round, 버림 : Math.floor
1) ItemDao 클래스에 전체 데이터 개수를 리턴하는 메소드를 생성
=> 전체 페이지 개수를 알아야 하기 때문
=> 페이징 뿐 아니라 더보기를 만들 때도 필요
//페이징과 더보기 구현을 위한 전체데이터 개수를 세는 메소드
public int getCount() {
//기본 데이터 개수는 0
int result = 0;
connect();
//SQL을 생성
try {
pstmt = con.prepareStatement("select count(*) from item");
//SQL을 실행
rs = pstmt.executeQuery();
if(rs.next()) {
//결과를 저장
result = rs.getInt(1);
}
}catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return result;
}
2) 페이지번호와 한 페이지에 출력할 데이터 개수를 매개변수로 받아서 페이지 번호에 해당하는 데이터만 리턴하는 함
수를 ItemDao에 생성
=> 페이지당 데이터 개수를 변경할 수 없다면 페이지당 데이터 개수는 매개변수로 설정하지 않아도 됨
=> 기존 메소드를 그냥 둔 상태에서 매개변수만 다르게 해서 구현시 Method Overloading이라고 함
//페이지 번호와 페이지당 데이터 개수를 입력받아서
//페이지 번호에 해당하는 데이터만 리턴해주는 메소드
public List<Item> list(int pageno, int perpagecnt){
List<Item> list = new ArrayList<Item>();
connect();
try {
pstmt = con.prepareStatement("select * from item limit ?,?");
//데이터 시작번호는 페이지번호 -1에 데이터 개수를 곱한 것
pstmt.setInt(1, (pageno-1)*perpagecnt);
//가져올 데이터 개수는 페이지당 출력할 데이터 개수
pstmt.setInt(2, perpagecnt);
rs = pstmt.executeQuery();
while(rs.next()) {
Item item = new Item();
item.setCode(rs.getInt("code"));
item.setCategory(rs.getString("category"));
item.setTitle(rs.getString("title"));
list.add(item);
}
}catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
close();
return list;
}
3) ItemServiceImpl 클래스의 데이터 목록을 가져오는 메소드를 수정
@Override
public void list(HttpServletRequest request, HttpServletResponse response) {
//1.파라미터 읽기
//페이지 번호와 페이지 당 데이터 개수를 저장할 변수를 생성
int pageno = 1;
int perpagecnt = 5;
//파라미터로 페이지 번호와 페이지 당 데이터개수가 넘어오면
//페이지 번호와 페이지당 데이터 개수 변경
String no = request.getParameter("no");
String pagecnt = request.getParameter("pagecnt");
if(no != null) {
pageno = Integer.parseInt(no);
}
if(pagecnt != null) {
perpagecnt = Integer.parseInt(pagecnt);
}
//2.파라미터 변환 작업이나 알고리즘 처리
//3.호출할 Dao 메소드의 매개변수를 생성
//4.Dao의 메소드를 호출해서 결과를 저장
List<Item> list = itemDao.list(pageno, perpagecnt);
//전체 데이터 개수를 가져오기
int totalCount = itemDao.getCount();
//데이터 출력화면에 표시할 마지막 페이지 번호와 시작 페이지 번호를
//생성
//하나의 페이지에 페이지 번호를 10개씩 출력
//종료 페이지 번호를 임시로 계산
//1 - 10, 2 - 10, 12 - 20, 21 - 30
int endPage = (int)(Math.ceil(pageno/10.0)*10.0);
int startPage = endPage - 9;
//전체 페이지 개수 구하기
int tempEndPage = (int)(Math.ceil(totalCount/(double)perpagecnt));
//끝나는 페이지 번호가 전체 페이지 개수보다 크면 끝나는 페이지 번호 수정
if(endPage > tempEndPage) {
endPage = tempEndPage;
}
//이전과 다음의 출력 여부 생성
boolean prev = startPage == 1 ? false : true;
boolean next = endPage * perpagecnt >= totalCount ? false : true;
//5.Dao 메소드 호출 결과를 View로 전달하기 위해서
//request 나 session 에 저장
//포워딩 할 거면 request
//리다이렉트 할 거면 session
request.setAttribute("list", list);
request.setAttribute("startpage", startPage);
request.setAttribute("endpage", endPage);
request.setAttribute("pageno", pageno);
request.setAttribute("prev", prev);
request.setAttribute("next", next);
//전체 데이터 개수를 출력하고자 하면 저장
request.setAttribute("totalcount", totalCount);
}
4) list.jsp 파일을 수정
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 제어문 사용을 위한 태그 라이브러리를 설정 -->
<%@ taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>목록보기</title>
</head>
<body>
<h3 align="center">데이터 목록 보기</h3>
<table align="center" border="1">
<tr>
<th>코드</th>
<th>카테고리</th>
<th>이름</th>
</tr>
<c:forEach var="item" items="${list}">
<tr>
<td> ${item.code}</td>
<td> ${item.category}</td>
<!-- 기본키의 값을 파라미터로 전송 -->
<!-- <td> <a href="detail?code=${item.code}">${item.title}</a></td> -->
<td> <a href="detail/${item.code}">
${item.title}</a></td>
</tr>
</c:forEach>
</table>
<div align = "center">
<c:if test="${prev == true}">
<a href="list?no=${startpage-1}">이전</a>
</c:if>
<c:forEach var="idx" begin="${startpage}" end="${endpage}">
<c:if test="${pageno == idx}">
${pageno}
</c:if>
<c:if test="${pageno != idx}">
<a href="list?no=${idx}">${idx}</a>
</c:if>
</c:forEach>
<c:if test="${next == true}">
<a href="list?no=${endpage+1}">다음</a>
</c:if>
</div>
</body>
</html>
**ajax와 REST API Server 구축 및 암호화
1. REST API
=> 디바이스나 화면 크기에 상관없이 동일한 콘텐츠를 사용하는 경우에는 하나의 URL을 이용
=> Web Browser, Android, iOS Application등이 동일콘텐츠 이용시, 동일URL을 이용해서 콘텐츠를 사용가능해야 함
=> 서버 입장에서 여러 디바이스의 요청을 서로 다른 URL을 이용해서 처리시 유지보수가 어렵고 서버 Application을
여러개 구현해야 할 가능성이 높아 관리가 어려워짐
=> 클라이언트 입장에서는 디바이스 별로 다른 URL을 요청하므로 클라이언트용 애플리케이션 개발이 어려워짐
=> 이 경우 선택한 데이터 포맷은 XML과 JSON
- XML : 태그형식으로 표현하기 때문에 개발자가 구조파악하기가 쉬움
- JSON : 자바스크립트 데이터 표현방법으로 표현되어 있고, XML이후에 나온 포맷
-> 단점 : 개발자의 구조 파악이 어려움, 나중에 나온 포맷이라 외부 라이브러리를 이용하여 쉽게 사용 가능
-> 장점 : XML보다 경량이고, 자바스크립트나 파이썬 같은 언어와 데이터 작성 방법이 동일하므로 파싱이 수월
=> Java Web Programming 만으로 가능하지만 Spring 같은 Framework 사용시 조금 더 쉽게 구현
=> Server가 View를 만들지 않고 데이터를 만들어서 전송하는 개념
2. ajax
=> 비동기 데이터 전송
=> REST API Server는 View가 아닌 데이터를 전송해주기 때문에 HTML파일에서 Server와 통신하기 위해서 이전에
사용하던 a태그나 자바스크립트의 페이지 이동 또는 iframe을 사용할 수 없음
=> REST API Server와 통신하기 위해서는 다른 기술을 이용해야하는 데 그 중의 하나가 ajax
=> ajax는 자신의 도메인 데이터가 가져올수 있도록 설계되어 있는데 서버측에서 CORS가 가능하도록 설계해주면
ajax로 다른 도메인의 데이터도 가져올수 있음
- 상대방 서버가 CORS가 가능하도록 설계되어 있지 않다면 proxy를 이용하여 ajax 요청을 자신의 서버에게 보내
고 서버용 프로그래밍언어를 이용하여 외부 데이터를 가져오고 다시 ajax에 전달하는 방식을 이용
3. 암호화
=> 평문을 그냥 알아볼수 없도록 만드는 것
=> 복호화 : 암호화된 문장을 평문으로 변경하는 것
1) 암호화 방식
=> 평문을 비문으로 만든 후 비문을 복호화할 수 없게하고, 평문과 비문을 비교할 수 있게 하는 방식(비밀번호)
=> 비문을 평문으로 복호화 할 수 있도록 만드는 방식
2) 암호화 알고리즘
=> MD5, sha-256, res등 여러가지 알고리즘이 있음
**더보기 구현
1. json 생성을 위한 라이브러리를 프로젝트에 복사
=> view에 데이터를 전달하기 위해서 수행
2. ServiceImpl 클래스에서 데이터 목록을 만들어주는 메소드를 수정
public void list(HttpServletRequest request, HttpServletResponse response) {
//1. 파라미터 읽기
//페이지 번호와 페이지당 데이터 개수를 저장할 변수를 생성
int pageno = 1;
int perpagecnt = 5;
//파라미터로 페이지 번호와 페이지당 데이터 개수가 넘어오면 페이지 번호와 페이지당 데이터 개수 변경
String no = request.getParameter("no");
String pagecnt = request.getParameter("pagecnt");
System.out.println("no : " + no);
System.out.println("pagecnt : " + pagecnt);
if(no != null) {
pageno = Integer.parseInt(no);
}
if(pagecnt != null) {
perpagecnt = Integer.parseInt(pagecnt);
}
//2. 파라미터 변환 작업이나 알고리즘 처리
//3. 호출할 Dao 메소드의 매개변수를 생성
//4. Dao의 메소드를 호출하여 결과를 저장
//JSON 출력을 위해서 JSON 데이터 형식으로 변환
//List, 배열 -> JsonArray
//DTO, Map -> JsonObject
List<Item> list = itemDao.list(pageno, perpagecnt);
JSONArray ar = new JSONArray();
for(Item item : list) {
JSONObject obj = new JSONObject();
obj.put("code", item.getCode());
obj.put("title", item.getTitle());
obj.put("category", item.getCategory());
obj.put("description", item.getDescription());
ar.put(obj);
}
//전체 데이터 개수 가져오기
int totalCount = itemDao.getCount();
//데이터 출력화면에 표시할 마지막 페이지 번호와 시작 페이지 번호를 생성
//하나의 페이지에 페이지 번호를 10개씩 출력
//종료 페이지 번호를 임시로 계산(1-10, 2-10, 12-20, 21-30)
int endPage = (int)(Math.ceil(pageno/10.0)*10.0);
//페이징에서는 뒤로 가는게 있어서 시작페이지 번호가 필요하지만 더보기 형태의 구현은 뒤로가는게 없어서 시작페이지 번호가 필요없음
//int startPage = endPage - 9;
//전체 페이지 개수 구하기
int tempEndPage = (int)(Math.ceil(totalCount)/(double)perpagecnt);
//끝나는 페이지 번호가 전체 페이지 개수보다 크면 끝나는 페이지 번호 수정
if(endPage > tempEndPage) {
endPage = tempEndPage;
}
//이전도 필요가 없음
//이전과 다음의 출력 여부 생성
//boolean prev = startPage == 1 ? false : true;
//다음데이터의 존재여부를 위해 있는 것이 좋음
boolean next = endPage*perpagecnt >= totalCount ? false : true;
//Dao의 매개변수를 확인
//5. Dao 메소드 호출 결과를 View로 전달하기 위해 request나 session에 저장
// 포워딩 할 경우 : request, 리다이렉트 할 경우 : session
// request.setAttribute("list", list);
// request.setAttribute("startpage", startPage);
// request.setAttribute("endpage", endPage);
// request.setAttribute("pageno", pageno);
// request.setAttribute("prev", prev);
// request.setAttribute("next", next);
//REST API 서버를 구현할 때는 JSONObject로 묶어서 1개만 저장
JSONObject result = new JSONObject();
//현재 페이지 번호, 종료 페이지 번호, 다음 존재여부, 출력할 데이터
result.put("pageno", pageno);
result.put("endpage", endPage);
result.put("next", next);
result.put("ar", ar);
//request에 저장
request.setAttribute("result", result);
}
2) Controller를 확인해서 list 요청시 list.jsp로 출력하는 것을 확인하고 list.jsp 파일을 만들어 앞에서 저장한 내용 출력
3) 테스트
=> POST방식은 테스트가 어렵지만 GET 방식은 브라우저를 이용해서 테스트가 가능
=> 서버를 실행히키고 브라우저 창에 item/list 를 추가하여 확인
=> 여기까지가 서버 구현에서는 끝
5. Web Client에서 데이터를 요청해서 출력하기
1) index.jsp 페이지에서 목록보기 요청을 수정
<li><a href="item/itemlist">전체 데이터 조회</a></li>
2) ItemController에서 itemlist요청이 온 경우 출력할 페이지로 포워딩하는 코드를 doGet메소드에 작성
else if(command.equals("/item/itemlist")) {
RequestDispatcher dispatcher = request.getRequestDispatcher("../view/itemlist.jsp");
dispatcher.forward(request, response);
}
3) doGet 메소드에서 삽입이나 수정, 삭제 이후에 이동하는 곳도 itemlist로 변경
4) itemlist.jsp 파일을 생성하고 출력
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>목록 보기</title>
</head>
<body>
<h2 align="center">목록 보기</h2>
<table align="center" border="1" id="table">
<tr>
<th>코드</th>
<th>카테고리</th>
<th>제목</th>
</tr>
</table>
</body>
<!-- jquery를 사용하기 위한 링크 설정
ajax를 편리하게 사용하기 위해서 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
//페이지 번호 변수
var pageno = 1;
//ajax 요청을 해서 table에 데이터를 출력해주는 함수
function adddata(){
$.ajax({
url:"list",
dataType:"json",
data:{"no":pageno},
success:function(data){
//더보기 버튼을 삭제
$('#add').remove();
//배열을 순회해서 하나의 객체를 한 줄로 출력
$.each(data.ar, function(index, item){
disp = "<tr><td>" + item.code + "</td>";
disp += "<td>" + item.category + "</td>";
disp += "<td>" + item.title + "</td></tr>";
$('#table').html($('#table').html() + disp);
});
//더보기 버튼 만들기
//현재 페이지가 종료 페이지보다 작을 때 만 생성
if(data.pageno < data.endpage){
//페이지 번호 하나 올리기
pageno = pageno + 1;
disp = "<tr id='add'>" +
"<td colspan='3' align='center'>" +
"더보기" + "</td></tr>";
$("#table").html($("#table").html() + disp);
//id 가 add 객체를 click 하면 adddata 라는 함수를 호출
document.getElementById("add")
.addEventListener("click", adddata);
}
}
});
};
//태그를 전부를 읽고 난 후 수행
window.addEventListener("load", function(e){
adddata();
})
</script>
</html>
'수업 정리' 카테고리의 다른 글
수업 외 정리 (0) | 2020.06.24 |
---|---|
55~58일차(회원가입과 로그인) (0) | 2020.06.24 |
52일차 수업 정리(HttpServlet, Model2 MVC 구조의 프로젝트 생성) (0) | 2020.06.19 |
51일차 수업 정리(예외 처리, EL, JSTL) (0) | 2020.06.18 |
50일차 수업 정리(요청과 결과 출력, Cookie, Session) (0) | 2020.06.17 |