1. OracleDB, 서브쿼리, join : 230206
1) 서브쿼리
- 기존 sql문은 에러가 발생한다. ORDER BY 의 순서가 중요하다!
SELECT * FROM MEMBER ORDER BY REG_DATE DESC
WHERE ROWNUM BETWEEN 1 AND 10;
- 먼저 실행될 것이 있다면, 서브쿼리를 사용한다!
SELECT * FROM (
SELECT * FROM MEMBER ORDER BY REG_DATE DESC
) WHERE ROWNUM BETWEEN 1 AND 10;
- 문제점 : 하지만, 2page가 나오지 않는다! ROWNUM을 이용하고 서브쿼리를 여러 번 이용하여 수정하기!
- ROWNUM은 WHERE절이 나오고 SELECT 절이 나오면 등장하기 때문에 가장 마지막에 ROWNUM이 등장한다.
- 따라서, ROWNUM과 ORDER BY는 따로 따로 진행해야하기 때문에 서브쿼리를 2번에 나눠서 사용한다. ORDER BY부터 서브쿼리를 진행하고 ROWNUM는 두번째로 서브쿼리를 진행한다.
SELECT * FROM MEMBER ORDER BY REG_DATE DESC
- 여기에서 새로 생긴 결과집합은 정렬되었기 때문에 원본 ‘MEMBER’가 아니고 그 새로 생긴 결과 집합에서 별칭을 붙여 ‘M’으로 이용한다.
-- table에 별칭을 쓰는 방법은 결과집합을 괄호로 묶어 괄호 뒤에 별칭을 써준다.
SELECT * FROM (
SELECT ROWNUM NUM, M.* FROM (
SELECT * FROM MEMBER ORDER BY REG_DATE DESC
)M
)WHERE NUM BETWEEN 11 AND 20;
-- 별칭을 또 쓰고 싶다면, 이것도 가능
SELECT X.* FROM (
SELECT ROWNUM NUM, M.* FROM (
SELECT * FROM MEMBER ORDER BY REG_DATE DESC
)M
)X WHERE NUM BETWEEN 11 AND 20;
- 새로운 문제 : 조회수가 가장 많은 회원의 정보를 출력해라!
SELECT * FROM MEMBER WHERE MEMBER.ID =(
SELECT N.WRITER_ID FROM(
SELECT WRITER_ID, COUNT(ID) COUNT FROM NOTICE GROUP BY WRITER_ID ORDER BY COUNT DESC
)N
WHERE ROWNUM = 1);
2) (), ALL, ANY 서브쿼리 연산자?
- 문제 1: 성별 평균 나이를 조회하시오?
SELECT GENDER, AVG(AGE) AGE FROM MEMBER GROUP BY GENDER;
- 문제 2: 성별 평균나이를 상회하는 나이를 가지는 회원 정보를 출력 (ALL, ANY를 이용한다!)
- 격자형은 비교가 안된다!
- 단일값은 단일값과 비교해줘야한다. 하지만 여기서는 단일값과 2개값을 비교한다!!
- 하나의 단일값으로 만들어주는 도구가 필요하다!
- ALL을 이용할 때는 모든 것들과 비교했을 때, 등호를 쓰면 이상하다. 이길 때만 고민해야하므로 등호를 넣어줘서 비교해준다!
- ALL : 보통은 모든 것들보다 작은 것을 출력하고 할 때, 이용한다. (‘<’을 이용)
SELECT * FROM MEMBER WHERE AGE < ALL(SELECT AVG(AGE) FROM MEMBER GROUP BY GENDER);
- ANY : ()값이 어떤 것도 이길 수 있는 나이를 뽑아내라(‘>’ 이용)
SELECT * FROM MEMBER WHERE AGE > ANY(SELECT AVG(AGE) FROM MEMBER GROUP BY GENDER);
- 정리 : ALL, ANY는 서브쿼리에서만 사용가능하다!
3) Join(조인)
- Join(조인) 개념
- 2개 이상의 테이블을 참조하여 조회하기!
- 데이터 베이스(DB)는 데이터를 한 곳에 모아 놓고 사용하는데 이용한다! 그리고, 무결성을 위해서 사용한다. 무결성은 데이터 중복에 의해서 사용한다.
- 하지만, 데이터 중복을 없애기 위해서 쪼개서 데이터를 테이블에 저장했는데 이렇게 쪼개진 데이터를 묶어서 사용해야 한다.
- 참조키 개념 :
- NOTICE의 테이블에서 WRITER_ID는 사용자 정보를 가져오기 위해서 사용하는 참조키이다.
4) INNER JOIN
- INNER JOIN 개념 :
- 칼럼을 늘리는 결합이다.
- 조인은 주인공에서 만들어진다. 자식 테이블이 주인공이 된다. 참조하는 녀석이 자식이고 참조키를 가지고 있는 것이 자식 테이블이다. 참조키가 먼저 있어야 하므로 먼저 만들어 진다.
- 주인공인 자식 테이블이 움직여서 부모 테이블에 붙여진다.
- 참조하는 수만큼 부모가 복제된다. 복제는 파일에서 하는 것이 아니라 메모리에서 한다. 하지만, 데이터베이스는 통으로 저장하지 않고 부분적으로 가져오기 때문에 더 속도 측면에서 유리하다.
- JOIN의 장점 : 성능도 좋게하고 데이터의 결함을 없애준다. 하지만 개발측에서는 어렵다.
- 핵심!! : 참조하는 키가 무엇인지 파악하고 어떤 키와 연결되는지 파악하자!!
- INNER JOIN 실습 코드 :
-- 자식이 참조하고 있는 부모의 레코드만 불러온다!
SELECT *
FROM MEMBER
INNER JOIN NOTICE
ON MEMBER.ID = NOTICE.WRITER_ID;
- 하지만, INNER JOIN을 하면 NOTICE의 레코드 수 중에서 하나가 빠진다.
- 하나가 빠진 이유는 부모 레코드의 ID로 자식 레코드에 없는 경우가 빠진다. 이러한 것을 JOIN 관계에서 같이 결합되지 않은 OUTER가 존재한다. 라고 말한다.
- 2개의 테이블을 사용하면, 애매해서 별칭 써주기!, 또한, 의미를 분명하게 해주기 위해서 칼럼에도 별칭을 붙여준다!
- 기준(주인공)이 자식 테이블이므로 NOTICE가 기준이 된다.(중요!!)
SELECT M.ID MEMBER_ID, M.NAME MEMBER_NAME, N.ID, N.TITLE
FROM MEMBER M
INNER JOIN NOTICE N
ON M.ID = N.WRITER_ID;
5) OUTER JOIN :
- OUTER JOIN 개념 :
- OUTER 조인은 LEFT OUTER, RIGHT OUTER, FULL OUTER의 경우에는 OUTER를 생략할 수 있다.
- NOTICE에서 아까 빠진 레코드가 있었어서 오른쪽에서 빠진 녀석이었므로 RIGHT OUTER JOIN을 해주자! 그 빠진 레코드를 채워주는 격이다.
- 자식은 무조건 다 나오게 하고 부모는 그것과 관련된 것에 대해 출력함을 의미한다.
- 실습 코드 :
SELECT M.ID MEMBER_ID, M.NAME MEMBER_NAME, N.ID, N.TITLE
FROM MEMBER M
RIGHT OUTER JOIN NOTICE N
ON M.ID = N.WRITER_ID;
2. OracleDB, join : 230207
1) Outer Join
- 문제 1 : 회원별 작성한 게시글 수 조회
-- 집계
SELECT M.ID, M.NAME, M.NICNAME, M.PWD, COUNT(N.ID)
FROM MEMBER M LEFT JOIN NOTICE N
ON M.ID = N.WRITER_ID
GROUP BY M.ID, M.NAME, M.NICNAME, M.PWD;
- 우리는 Outer를 더 많이 사용한다. 그 이유는? Outer는 ‘주인공’인쪽에서 비워져 있는 레코드를 다 채워주기 때문이다.
- 멤버 목록을 뽑고자 하는데 Count가 껴져 있는 형태이다.
- 글을 안 쓴 회원도 다 나오게 해야 한다.
2) 테이블 3개 JOIN
- 하지만, 테이블을 추가해줄 때 , 테이블 명이 예약어 일경우 더블코테이션을 사용한다!
- 부모것을 가져오려면 그냥 가져오면 된다!(ex) M.NAME)
-
CONTENT는 GROUP BY에 묶을 수 없다. 목록에서 내용을 쓸 이유가 없기 때문에!
- 실습 코드(쌤) :
-- 쌤 정답 :
-- 주인공이 누구인지? 나를 기준으로 주인공이 어디있는지 그 방향을 붙여준다.
-- 데이터가 복제되는 부분을 생각해보자!!
SELECT N.ID, N.TITLE, N.WRITER_ID, N.REGDATE, M.NAME, COUNT(C.ID) CMT_COUNT
FROM NOTICE N
LEFT JOIN MEMBER M ON M.ID = N.WRITER_ID
LEFT JOIN "COMMENT"C ON N.ID = C.NOTICE_ID
GROUP BY N.ID, N.TITLE, N.WRITER_ID, N.REGDATE, M.NAME;
- 실습 코드(내가) :
-- 내가 푼 것의 정답 :
-- 주인공이 누구인지? 나를 기준으로 주인공이 어디있는지 그 방향을 붙여준다.
-- 데이터가 복제되는 부분을 생각해보자!!
SELECT N.TITLE, N.WRITER_ID, M.NAME, M.NICNAME, COUNT(C.ID) CMT_COUNT
FROM MEMBER M
RIGHT OUTER JOIN NOTICE N ON M.ID = N.WRITER_ID
LEFT OUTER JOIN "COMMENT" C ON N.ID = C.NOTICE_ID
GROUP BY N.TITLE, N.WRITER_ID, M.NAME, M.NICNAME;
- 답변 1 정리!!(아래 SQL문) :
- NOTICE가 주인공이지만 MEMBER를 기준으로 설명해서 복잡해진다!!
SELECT N.TITLE, N.WRITER_ID, M.NAME, M.NICNAME, COUNT(C.ID) CMT_COUNT
의 MEMBER 위치에서 NOTICE를 조회하면 오른쪽에 OUTER가 붙는다!- 모든 MEMBER들이 게시글을 등록하지 않기 때문에 게시글을 등록하지 않은 MEMBER도 조회되어야 하므로 오른쪽에 OUTER로 생긴다.
- 모든 MEMBER들이 게시글을 등록하지 않기 때문에 게시글을 등록하지 않은 MEMBER도 조회되어야 하므로 오른쪽에 OUTER로 생긴다.
SELECT N.TITLE, N.WRITER_ID, M.NAME, M.NICNAME, COUNT(C.ID) CMT_COUNT
의 MEMBER 위치에서 COMMENT를 조회하면 왼쪽에 OUTER가 붙는다!- 모든 MEMBER들이 댓글을 등록하지 않기 때문에 댓글을 등록하지 않은 MEMBER도 조회되어야 하므로 왼쪽에 OUTER로 생긴다.
- 즉, 여기서 DB 조회 순서를 NOTICE < MEMBER, MEMBER > COMMENT로 보았다.
- NOTICE가 주인공이지만 MEMBER를 기준으로 설명해서 복잡해진다!!
SELECT N.TITLE, N.WRITER_ID, M.NAME, M.NICNAME, COUNT(C.ID) CMT_COUNT
FROM MEMBER M
RIGHT OUTER JOIN NOTICE N ON M.ID = N.WRITER_ID
LEFT OUTER JOIN "COMMENT" C ON N.ID = C.NOTICE_ID
GROUP BY N.TITLE, N.WRITER_ID, M.NAME, M.NICNAME;
- 문제 1 변형 :
- 위의 SQL문 조회하는 순서 다시 바꿔보기!!
- 아래 코드는 모두 출력되지만 우리가 원하는 방식대로 출력되지 않는다!
-- 변형 1
SELECT M.NAME, M.NICNAME, N.TITLE, N.WRITER_ID, COUNT(C.ID) CMT_COUNT
FROM MEMBER M
LEFT OUTER JOIN NOTICE N ON M.ID = N.WRITER_ID
LEFT OUTER JOIN "COMMENT" C ON N.ID = C.NOTICE_ID
GROUP BY M.NAME, M.NICNAME, N.TITLE, N.WRITER_ID;
-- 변형 2
SELECT M.NAME, M.NICNAME, N.TITLE, N.WRITER_ID, COUNT(C.ID) CMT_COUNT
FROM MEMBER M
RIGHT OUTER JOIN NOTICE N ON M.ID = N.WRITER_ID
LEFT OUTER JOIN "COMMENT" C ON N.ID = C.NOTICE_ID
GROUP BY M.NAME, M.NICNAME, N.TITLE, N.WRITER_ID;
-
답변 2 정리 :
- 주인공이 누구인지?
- 데이터가 복제되는 부분을 생각해보자!!
- 부모 것을 가져오려면, 그냥 가져오면 된다! (ex) M.NAME)
- 중요! : FROM NOTICE이라서 NOTICE 기준이고 NOTICE가 주인공이라서 LEFT OUTER로 일치한다! MEMBER와 NOTICE에서는 MEMBER에서 OUTER가 생기고 NOTICE와 COMMENT 사이에서는 NOTICE에 OUTER가 생긴다.
- 즉, 여기서 DB 조회 순서를 MEMBER > NOTICE > COMMENT로 보았다.
SELECT N.ID, N.TITLE, N.WRITER_ID, N.REGDATE, M.NAME, COUNT(C.ID) CMT_COUNT
FROM NOTICE N
LEFT JOIN MEMBER M ON M.ID = N.WRITER_ID
LEFT JOIN "COMMENT"C ON N.ID = C.NOTICE_ID
GROUP BY N.ID, N.TITLE, N.WRITER_ID, N.REGDATE, M.NAME;
- CONTENT는 GROUP BY에 묶을 수 없다. 목록에서 내용을 쓸 이유가 없기 때문에!
3) Self Join :
- 데이터가 서로 포함 관계를 가지는 경우 : 조원과 조장을 구별
- 문제 : 조원들 중의 조장이 누구인지!! 조회 가능!
- 자기가 자기를 뽑아낸다. 테이블은 1개이다.
- 부모의 이름을 불러내서 JOIN을 한다.
- 이너 조인과 같은 형태이다.
- 문제 : 자기의 조장이 누구인지 나 자신을 조회해서 조장의 ID를 조회?
- 실습 코드 :
SELECT M.ID, M.NAME, B.BOSS_ID, B.NAME
FROM MEMBER M
LEFT JOIN MEMBER B ON M.BOSS_ID = B.ID;
- 정리 :
- 멤버가 주인공(대부분의 데이터를 조회하여 출력하는 부분)이라서 이게 핵심이다!
- 보스가 없는 사람도 같이 출력해줘야한다. LEFT OUTER를 해주어야 한다. LEFT OUTER는 왼쪽에 OUTER가 생긴다.
- 중요! : ON 뒤에는 관계 조건이 나와야 하는데 참조키를 이용한 조건이 나와야 한다. 하지만, Self Join에서 그 참조키가 자기 테이블에서 참조가 되기 때문에 서로 크로스되어 참조된다. 자기 본연 그대로 사용하면 참조하는 의미가 사라진다.
ON M.ID = B.BOSS_ID;
이렇게 쓰면 자기 테이블에서 자기 자신을 참조하므로 참조키의 의미가 없다.ON M.BOSS_ID = B.ID;
따라서, 크로스하여 사용하는 것이 참조키의 의미가 있다.
- Self Join 사용하는 곳 :
- 참조가 참조를 하고, 댓글이 댓글을, 사원이 사원을 참조할 때 사용한다!
- 대댓글을 구현할 때, 이렇게 가능하다.
- 카테고리도 구현할 때, 사용한다. 그 범주가 그 안에 있다.
4) Cross join
- 테이블과 테이블을 곱하여 조회할 때, 사용한다. 아래 SQL문은 멤버 테이블과 코멘트 테이블의 곱이다.
SELECT * FROM MEMBER CROSS JOIN "COMMENT";
5) UNION
- UNION은 칼럼이 늘어나지 않고 레코드가 늘어난다!
- 이것은 통합 검색에서 쓰인다. 게시글, 과정 등 2개를 통합해서 검색할 때, 이용한다!
- 하지만, 이것을 이용하기 위해서는 칼럼 수를 맞추어줘야 한다.
- 문제 : 게시글 제목에서 재영의 ‘재’를 검색하면 검색되는 것
SELECT * FROM NOTICE WHERE TITLE LIKE '%안%';
- 칼럼 수 맞춰 주기, 상수를 붙여주기!(어디서 데이터를 가져오는지 몰라서!) : ‘~’ TYPE
SELECT 'NOTICE' TYPE, ID, TITLE FROM NOTICE WHERE TITLE LIKE '%재%'
UNION
SELECT 'COMMENT' TYPE, ID, CONTENT FROM "COMMENT" WHERE CONTENT LIKE '%재%';
- 하지만, 레코드의 값들이 다 같다면, 중복된 값은 생략된다.
6) UNION ALL
- 또한, 중복된 값을 같이 출력해주고 싶다면, ~~을 이용해서 가능하다.
SELECT 'NOTICE' TYPE, ID, TITLE FROM NOTICE WHERE TITLE LIKE '%재%'
UNION ALL
SELECT 'COMMENT' TYPE, ID, CONTENT FROM "COMMENT" WHERE CONTENT LIKE '%재%';
- 하지만, 보통, UNION을 쓸 때는 TYPE을 써주기 때문에 겹치는 경우가 적다.
7) MINUS : 공통된 부분을 빼고 나머지 부분을 조회한다.(차집합)
SELECT ID, TITLE FROM NOTICE WHERE TITLE LIKE '%재%'
MINUS
SELECT ID, CONTENT FROM "COMMENT" WHERE CONTENT LIKE '%재%'
8) INTERSECT : 공통된 부분을 조회한다.(교집합)
SELECT ID, TITLE FROM NOTICE WHERE TITLE LIKE '%재%'
INTERSECT
SELECT ID, CONTENT FROM "COMMENT" WHERE CONTENT LIKE '%재%';
9) VIEW**
- DB : 각자 가져가지말고 같이 쓰자! 동시성, 중복을 제거하기 위해서 나눠놨다.
- 이렇게 잘게 나눠 놓은 것을 다시 합치는 작업을 한다!
CREATE VIEW NOTICE_VIEW11 // VIEW 생성!
AS
SELECT N.ID, N.TITLE, N.WRITER_ID, N.REGDATE, M.NAME, COUNT(C.ID) CMT_COUNT
FROM NOTICE N
LEFT JOIN MEMBER M ON M.ID = N.WRITER_ID
LEFT JOIN "COMMENT"C ON N.ID = C.NOTICE_ID
GROUP BY N.ID, N.TITLE, N.WRITER_ID, N.REGDATE, M.NAME;
SELECT * FROM NOTICE_VIEW; // VIEW 조회!
- VIEW는 결합 쿼리문만 있어야한다. 즉, ORDER BY절이나 WHERE절이나 GROUP BY가 없어야 한다!
- 1개의 테이블을 사용할 때, 1개의 테이블에서 가리고 싶은 칼럼이 있을 경우, VIEW를 따로 만들어 사용한다.
- 이것은 사용자 별로 허락된 테이블을 보여주고 싶을 때!!(관리자, 일반 사용자별 )
10) 데이터 딕셔너리
-
관리할 목적의 데이터 : 인증 같은 것을 위한 사용자 정보가 필요하다!
-
SQL에서는 이것을 ‘마스터 DB’라고 한다. MySQL에서는 ‘시스템 DB’라고 한다. 오라클 DB에서는 ‘데이터 딕셔너리’라고 한다.
-
오라클에서는 실제 TABLE을 가질 수 없고 VIEW만 제공한다.(DBA용, USER용: 현재 사용자용, 모든 이용자용)
-
예전의 도스창에서 썼었다! 그래서 지금은 안쓰고 GUI에서 DB를 사용한다.
SELECT * FROM USER_TABLES; // 내가 만든 모든 테이블 조회가능
SELECT * FROM USER_TAB_COLUMNS; // 내가 만든 모든 테이블의 칼럼 조회 가능
SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME='COMMENT';
3. 백엔드 시작(서블릿, JSP) : 230207
1) DB의 CRUD, 라이브러리 제작
- 요즘에는 DB에서 반복적이고 중복을 최대한 적게 해서 설계한다. 즉, 테이블을 하나씩 가져와서 AJAX를 이용하기 때문에 이러한 것들이 가능하다!
2) 서블릿 레이어 나누기 :
a. 레이어 나누는 방법 :
- mvc - service - dao - dto
- 보통, 사용자 요청하는 곳에서는 DB를 쿼리하지 않는다.
- 사용자 입출력과 업무 로직과 DB쿼리 사용하는 부분을 레이어로 나누기
b. 레이어를 나누는 이유?
- 레이어를 하지 않으면, 협업이 안 된다. 그래서 협업을 위해서 나눠서 코드를 작성한다!
- ex) 사용자 입출력을 잘하는 사람, 업무를 잘하는 사람 : 결제 모듈을 잘 알고 있는 사람, DB를 잘 작성하는 사람.
- 메뉴 데이터를 가져오는 것이 여러 군데라면 집중화가 필요하다! 메뉴 데이터를
- 따라서 데이터 서비스를 나눠서 만든다!
c. 실습 코드 :
- ListController.java
package com.newlecture.web.controller.menu;
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/menu/list")
public class ListController extends HttpServlet{
@Override // doGet 뿐만 아니라 doDelete, doPut, doPost, doHead 등이 있다.
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 서블릿은 메인함수 직접 작성하지 않고입출력 도구가 달라짐!
PrintWriter out = resp.getWriter();
out.print("hello");
}
}
- MenuService.java
package com.newlecture.web.service;
public class MenuService {
}
4. 자바 웹 개발 : 230208
- 자바 : 다형성, 인터페이스, 람다식,
- 서블릿, jdbc
1) 자바 다형성 :
2) 람다식(Lambda) :
- 개념 :
- 별도의 클래스 추가하는 것 말고 쉽게 인터페이스를 구현하여 연결할 수 있는 부분?
- ‘Banner’라는 클래스를 구현하는 것이 목적이 아니라 한 번만 쓸 것이다. 그래서 람다식을 사용한다.
- 익명 클래스 : 함수 안에서 클래스를 만드는 부분이 가능하다!(중첩 메서드 클래스)
- 람다식(=람다 함수) :
- 인터페이스의 메서드 추상 메서드가 존재하는 함수형 인터페이스이다.
- 람다식은 메서드와 동등한 것이 아니라 익명클래스의 객체와 동등하다.**
- 함수형 인터페이스의 추상 메서드를 참조하므로 매개변수의 타입을 작성하지 않아도 됩니다.**
- 클래스를 구현할 필요가 없습니다.**
- 함수형 인터페이스에는 오직 하나의 추상 메서드만 정의되어 있어야 한다. 그래야 람다식과 인터페이스가 1:1로 연결되기 때문이다. 반면 static 메서드와 default 메서드의 개수에는 제약이 없다.
- 람다식 참고 사이트 1, 람다식 참고 사이트 2
-
실습 코드 :
-
program.java
package com.newlecture.web.poly;
import java.util.List;
import java.util.ArrayList;
import java.util.Comparator;
public class Program{
public static void main(String[] args) {
//
// 3. jdk 1.8에서 등장! 람다 표현식을 사용하는 방법(+콜렉션) :
List list = new ArrayList();
// list.add("3");
// list.add("15");
// list.add("2");
// list.add("6");
list.add(new Exam(1,3,2)); // Exam에서 getter, setter, 생성자 다 만들어주기!
list.add(new Exam(10,20,30));
list.add(new Exam(70,80,90));
list.add(new Exam(11,33,22));
// new Comparator<T>()라는 객체를 아래와 같이 람다표현식으로 간단하게 표현이 가능하다.
// list.add(new Comparator<T>() {
//
// @Overide
// public int compare(T o1, T o2) {
//
// };
// })
// 4. 따라서, 람다식이 배열에서도 많이 사용된다.
list.sort((x,y)->((Exam)x).getKor()-((Exam)y).getKor());
// 형변환도 가능하다. 첫번째 add와 두번째 add를 비교하고 앞에게 더 큰지 뒤에게 더큰지 알려준다.
list.sort((x,y)->((Exam)y).getKor()-((Exam)x).getKor());
// 얘는 x-y이면 오름차순 정렬이 되고 y-x이면 내림차순 정렬이다.
// 얘는 compare이라서 양수인지 음수인지 0인지만 알려주면 정렬이 된다!
// 데이터 분석하는 것에 요구할 때, 이런 식으로 많이 쓰기 때문에 람다 표현식을 사용한다!
// 이것은 함수 단위의 인터페이스이다, 하지만 객체 단위의 람다식도 많이 쓰인다.
// list.sort(null); // list 콜렉션에서는 add가 이렇게 되면 뭘 기준으로 정렬 해야하지?
System.out.println(list); // 문자, 숫자 등 어떤 것들을 비교할 수 있다.(compare 메서드 이용! )
// 그래서 주의할 것 !
// 문자열 비교는 첫 글자만 비교한다. 따라서, "15"를 넣으면 "2", "3", "4"에서 "15", "2", "3", "4"로 정렬된다.
// 인터페이스 사용하는 방법 :
// 1) 함수의 인자를 넘겨주는 방법 :
// 2) 객체로 넘겨주는 방법 :
Banner banner = new ICTBanner(); // 참조하는 녀석만 구현할 수 있다.
Exam.printIntro(banner);
// 1. jdk 1.2에서 "메서드 중첩 클래스"라고 부른다.
// 위의 코드와 같은 형태이다.
class AAA implements Banner{
@Override
public void print() {
// 전체적인 아키텍쳐 구현을 위해 사용하는 것이 아니라 인터페이스 구현 목적에만 사용한다.
System.out.println("내부 클래스 ICT 교육센터");
}
}
Exam.printIntro(new AAA());
// AAA에게 인터페이스를 넘겨 줘야하는데 구현할 공간이 없어서 클래스를 만들어 줘야 한다.
// 하지만 자바에서 클래스를 만들기 위해서 클래스 파일을 생성해야 하는데
// 전체적이 파일구조를 망가트려서 바로 꽂을 수 있도록 함수 안에서 클래스를 만들 수 있게 가능했다.
// 2. jdk 1.5에서 "익명클래스"라고 부른다!
// 인터페이스는 구현하지도 않고 new할 수도 없다.
// 익명클래스는 클래스를 거론할 수 없다.(클래스 이름이 없다.)
Banner banner1 = new Banner() { // 즉각적으로 클래스명을 만들 필요없이 바로 생성해서 만들 수 있다.
// 클래스긴 하지만 클래스 이름이 없다. 이것을 익명 클래스라고 부르고
@Override
public void print() {
System.out.println("익명 클래스 ICT 교육센터");
}
} ;
Exam.printIntro(banner1);
// 3. jdk 1.8에서 등장!! 람다식!!
// 람다식!!!? 인터페이스를 구현하는데 쉬운 도구가 없을까 ?
// 그냥 바로 만들면 비대해져서 다 지워버린다!(compare 메서드 생각!)
// '화살표 함수'와 같은 모습이다.
// Exam.printIntro(new Banner() {
//
// @Override
// public void print() {
// System.out.println("Lambda 익명 클래스 ICT 교육센터");
//
// }
// });
Exam.printIntro(() -> {
System.out.println("Lambda 익명 클래스 ICT 교육센터");
});
// 함수에 return을 쓴다면 더 간략하게 쓸 수 있다.
// Exam.printIntro(()->{
// return 3+4;
// });
// return마저도 생략한다.
// Exam.printIntro(()->3+4
// );
// 람다 표현식은 인터페이스에서 구현하는 것이 한개만 있을때, 가능하다.
}
}
- Banner.java
package com.newlecture.web.poly;
public interface Banner {
// Banner를 가지고 있는 어떠한 객체도 꽂을 수 있게끔 한다.(스펙(=print)만 부여해준다.)
// 그래서 상위 개념인 인터페이스에서 정해주고 약속 기반이다!
// 추상 클래스가 아니라 약속의 개념이라서 인터페이스이다.
// 여기에는 어떠한 것도 구현할 수 없다. jdk 버전이 올라가면 구현할 수 있다.(default 타입 같은 것 )
void print(); // '메서드 인터페이스'라고 부른다!
}
- ICTBanner.java
package com.newlecture.web.poly;
public class ICTBanner implements Banner{
public void print() {
System.out.println(" ICT 교육센터 ");
}
}
- Exam.java
package com.newlecture.web.poly;
public class Exam {
// ICTBanner가 아니라 Banner에서 불러온다. 이것이 강의에서 배운 set이고 연결시켜준다.
// 사용하는 쪽(Exam)에서 약속을 정의(Banner banner)를 해주는 것이다.
// static void printIntro(Banner banner) {
// System.out.println("┌───────────────────────┐");
//
// // 이 부분을 쉽게 바꿔 끼움으로서 하나만 만들어도 다른 회사에서도 팔 수 있게 끔 바꿔 끼우는 성질이다.
// // 특정 교육센터 이름이 들어간 부분을 분리하자!
// // System.out.println(" 뉴렉체 교육 프로그램 ");
//
// banner.print(); // 이게 약속을 꽂아 넣는 작업이다!
// // 특정 구역을 언급하지 않았으면 어디에서든 꽂아서 구현할 수 있다.
//
// System.out.println("메인 메뉴 항목들...");
//
// }
// 생성자, 오버로드생성자, getter, setter, 전부 만들기!
private int kor;
private int math;
private int eng;
public Exam() {
}
public Exam(int kor, int math, int eng) {
this.kor = kor;
this.math = math;
this.eng = eng;
}
public int getKor() {
return kor;
}
public void setKor(int kor) {
this.kor = kor;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEng() {
return eng;
}
public void setEng(int eng) {
this.eng = eng;
}
@Override
public String toString() {
return "Exam [kor=" + kor + ", math=" + math + ", eng=" + eng + "]";
}
}
- MenuService.java
package com.newlecture.web.service;
// MenuService는 listController가 사용할 부품(인터페이스)이 된다.
public interface MenuService {
}
3) 라이브러리 파일 설정, 서블릿 필터링
- 라이브러리 파일 저장 방법 :
- 서블릿에서 한글 필터링 방법 :
- 실습 코드 :
package com.newlecture.web.controller.menu;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.newlecture.web.service.MenuService;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
// 앞으로는 모든 함수를 람다식으로 다 쓰기!! 최종 자바 버전인 람다식으로 쓰기!! **
// 익명함수는 제일 나중에 쓰기!! 버전이 낮으면!!
@WebServlet("/menu/list")
public class ListController extends HttpServlet{
// 인터페이스명인 MenuService는 아무렇게 짓고 service로 불러오면 된다!
private MenuService service; // 목록에 대한 데이터서비스를 얘한테 부탁한다!!
@Override // doGet 뿐만 아니라 doDelete, doPut, doPost, doHead 등이 있다.
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 서블릿은 메인함수 직접 작성하지 않고 입출력 도구가 달라짐!
// 데이터를 받으면 글씨가 깨지는 이유? :
// 인코딩이 문제가 아니라 데이터를 받는 사람의 해석의 문제이다.
// 데이터를 넘겨 주면 쟤도 데이터를 인식해야 한다.
// 브라우저가 데이터를 EUC-KR로 읽어서 문제가 발생한다. 우리는 UTF-8
// 응답헤더에 EUC-KR이 아니라 UTF-8로 읽으라고 알려줘야한다.
// 이것은 내가하는 인코딩 방식이다. 요즘에는 기본으로 UTF-8로 인코딩이 된다.
// resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
// resp.setContentType("text/txt; charset=utf-8");
// 내가 인코딩을 하는 것이 아니라 브라우저가 이런 방식으로 읽으라고 설정해준다.
PrintWriter out = resp.getWriter();
out.print("hello");
// 인젝션 sql 때문에 수정함.
String query = "";
String sql = String.format("select * from member where nicname like '%s'", "%"+query+"%") ;
try {
// 하지만, OracleDriver가 없다고 에러가 발생한다!
// 왜 그럴까? 기존에 우리가 ojdbc8 파일을 빌드패스 했었다.
// 현재 쓰고 있는 폴더 국한에서는 ojdbc가 동작한다.
// 실제로 동작할 때는 해당 폴더의 자바 파일이 톰캣이 있는 위치로 메타데이터 형태로 배포가 된다.
// 다른 컴퓨터로 옮길 때, 문제가 발생해서 프로젝트와 함께 라이브러리를 같이 가져가야 한다.
// 따라서, WEB-INF 안의 lib 폴더안에 ojdbc8 파일을 넣어주어야 한다.
// 이것은 다른 컴퓨터에서 사용해도 가능하게 내가 별도로 포장해서 가져야하는 라이브러리이다.
// webapp 폴더에서 프로그램을 두어야 한다.
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@oracle.newlecture.com:1521/xepdb1";
Connection con = DriverManager.getConnection(url, "NEWLEC", "rland");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
// 필터링, 집계, 정렬
while(rs.next()) // 서버의 커서를 한칸 내리고 그 위치의 레코드를 옮겨 오는 것. -> 레코드 하나가 저장되는 공간은?
{
int id = rs.getInt("id");
String name = rs.getString("name");
String nicName = rs.getString("nicname");
String format = String.format("id:%d, name:%s, nicname:%s\n" , id, name, nicName);
//System.out.println(format);
out.println("<table>"); // html 코드에 java 코드를 사용하는 방법!!
out.println("<tr>");
out.println("format");
out.println("</tr>");
out.println("</table>");
}
con.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// // 서비스에게 맡겨도 된다!
// Menu[] list = service.getList();
// int count = service.count();
// Class.forName("oracle.jdbc.driver.OracleDriver"); // 스태틱 생성자와 같이 바로 불러낼 수 있다.
//
// // https://service/a/b/c와 같이 http라는 프로토콜에 service 객체에 a,b,c 순으로 파일이 이동된다.
// // thin 도 약속되어있는 명칭이다.
// String url = "jdbc:oracle:thin:@oracle.newlecture.com:1521/xepdb1"; // xepdb1는 SEED로부터 복제된 샘플(플러그된 것에서 복제 )이다.
// // 조작을 아무렇게 해도 된다!
//
// Connection con = DriverManager.getConnection(url, "NEWLEC", "rland");
//
// Statement st = con.createStatement();
// ResultSet rs = st.executeQuery("select * from member"); // select * from member where id > 100; 로 조건걸어주기!
//
// out.print("hello");
}
}
5. 콜렉션, 제너릭 : 230209
1) 자바에서 html 코드 쓰는 법
package com.newlecture.web.controller.menu;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.newlecture.web.service.MenuService;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
// 콜렉션과 제너릭 쓰기 전!!
// 앞으로는 모든 함수를 람다식으로 다 쓰기!! 최종 자바 버전인 람다식으로 쓰기!! **
// 익명함수는 제일 나중에 쓰기!! 버전이 낮으면!!
@WebServlet("/menu/list")
public class ListController extends HttpServlet{
// 인터페이스명인 MenuService는 아무렇게 짓고 service로 불러오면 된다!
// private MenuService service; // 목록에 대한 데이터서비스를 얘한테 부탁한다!!
@Override // doGet 뿐만 아니라 doDelete, doPut, doPost, doHead 등이 있다.
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 서블릿은 메인함수 직접 작성하지 않고 입출력 도구가 달라짐!
// 데이터를 받으면 글씨가 깨지는 이유? :
// 인코딩이 문제가 아니라 데이터를 받는 사람의 해석의 문제이다.
// 데이터를 넘겨 주면 쟤도 데이터를 인식해야 한다.
// 브라우저가 데이터를 EUC-KR로 읽어서 문제가 발생한다. 우리는 UTF-8
// 응답헤더에 EUC-KR이 아니라 UTF-8로 읽으라고 알려줘야한다.
// 이것은 내가하는 인코딩 방식이다. 요즘에는 기본으로 UTF-8로 인코딩이 된다.
// resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
// resp.setContentType("text/txt; charset=utf-8");
// 내가 인코딩을 하는 것이 아니라 브라우저가 이런 방식으로 읽으라고 설정해준다.
PrintWriter out = resp.getWriter();
out.print("hello");
// 인젝션 sql 때문에 수정함.
String query = "";
String sql = String.format("select * from member where nicname like '%s'", "%"+query+"%") ;
try {
// 하지만 OracleDriver가 없다고 에러가 발생한다!
// 왜 그럴까? 기존에 우리가 ojdbc8 파일을 빌드패스 했었다.
// 현재 쓰고 있는 폴더 국한에서는 ojdbc가 동작한다.
// 실제로 동작할 때는 해당 폴더의 자바 파일이 톰캣이 있는 위치로 메타데이터 형태로 배포가 된다.
// 다른 컴퓨터로 옮길 때, 문제가 발생해서 프로젝트와 함께 라이브러리를 같이 가져가야 한다.
// 따라서, WEB-INF 안의 lib 폴더안에 ojdbc8 파일을 넣어주어야 한다.
// 이것은 다른 컴퓨터에서 사용해도 가능하게 내가 별도로 포장해서 가져야하는 라이브러리이다.
// webapp 폴더에서 프로그램을 두어야 한다.
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@oracle.newlecture.com:1521/xepdb1";
Connection con = DriverManager.getConnection(url, "NEWLEC", "rland");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
out.write("<!DOCTYPE html>");
out.write("<html>");
out.write("<head>");
out.write("<meta charset=\"UTF-8\">");
out.write("<title>Insert title here</title>");
out.write("</head>");
out.write("<body>");
out.write(" <h1>메뉴 목록</h1>");
out.write(" <table>");
out.write(" <tr>");
out.write(" <td>번호</td>");
out.write(" <td>이름</td>");
out.write(" <td>가격</td> ");
out.write(" </tr>");
// 필터링, 집계, 정렬
while(rs.next()) // 서버의 커서를 한칸 내리고 그 위치의 레코드를 옮겨 오는 것. -> 레코드 하나가 저장되는 공간은?
{
int id = rs.getInt("id");
String name = rs.getString("name");
String nicName = rs.getString("nicname");
String format = String.format("id:%d, name:%s, nicname:%s\n" , id, name, nicName);
//System.out.println(format);
// out.println("<table>"); // html 코드에 java 코드를 사용하는 방법!!
// out.println("<tr>");
out.println("format");
// out.println("</tr>");
// out.println("</table>");
out.write("<tr>");
out.write(" <td>"+id+"</td>");
out.write(" <td>"+name+"</td>");
out.write(" <td>5000</td>");
out.write("</tr>");
}
con.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
out.write("</table>");
out.write("</body>");
out.write("</html>");
// // 서비스에게 맡겨도 된다!
// Menu[] list = service.getList();
// int count = service.count();
// Class.forName("oracle.jdbc.driver.OracleDriver"); // 스태틱 생성자와 같이 바로 불러낼 수 있다.
//
// // https://service/a/b/c와 같이 http라는 프로토콜에 service 객체에 a,b,c 순으로 파일이 이동된다.
// // thin 도 약속되어있는 명칭이다.
// String url = "jdbc:oracle:thin:@oracle.newlecture.com:1521/xepdb1"; // xepdb1는 SEED로부터 복제된 샘플(플러그된 것에서 복제 )이다.
// // 조작을 아무렇게 해도 된다!
//
// Connection con = DriverManager.getConnection(url, "NEWLEC", "rland");
//
// Statement st = con.createStatement();
// ResultSet rs = st.executeQuery("select * from member"); // select * from member where id > 100; 로 조건걸어주기!
//
// out.print("hello");
}
}
2) 콜렉션 이란?
- 데이터를 수집하고 관리해주는 객체
- 저장공간도 알아서 크게 늘려준다. 가변길이 배열.
a. Object 형식 :
- 모든 클래스를 집중 공통화 해주는 클래스가 Object이다. 참조해주는 친구.
- 원래는 사용하려고 상속해야 하는데 Object이기 때문에 부모 것을 상속 받아서 쓸 게 없다.
- 예시 :
Object[] list = new Object[10];
list[0] = 3;
list[0] = 4;
b. List 형식 :
-
모든 클래스를 집중 공통화 해주는 클래스가 Object이다. 참조해주는 친구.
-
원래는 사용하려고 상속해야 하는데 Object이기 때문에 부모 것을 상속 받아서 쓸 게 없다.
-
실습 코드 :
-
NList.java
package com.newlecture.web.entity;
public class NList {
private Object[] data;
private int index;
private int max; // max로 임의의 값 지정!! 공간을 계속 늘리기 위해서!
public NList() {
index = 0;
data = new Object[max];
}
public void add(Object n) {
// 공간이 부족하면
if(index==max) {
// 공간을 늘리기
Object[] temp = new Object[max+3]; // 여기서 3이라는 숫자를 변수로 입력 받을 수 도 있다.
for(int i=0; i<max; i++)
temp[i] = data[i];
data = temp;
max = max+3;
}
data[index] = n;
index++;
}
public Object get(int idx) {
return data[idx];
}
public int size() {
return index;
}
}
- ListController3.java(NList 이용)
package com.newlecture.web.controller.menu;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.newlecture.web.entity.GList;
import com.newlecture.web.entity.Menu;
import com.newlecture.web.entity.NList;
import com.newlecture.web.service.MenuService;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
// NList 사용!!**
// 서블릿 바꿔주기!!** 경로!!
@WebServlet("/menu/list3")
public class ListController3 extends HttpServlet{
@Override // doGet 뿐만 아니라 doDelete, doPut, doPost, doHead 등이 있다.
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 서블릿은 메인함수 직접 작성하지 않고 입출력 도구가 달라짐!
// 이렇게 제너릭을 이용하면 하면 형변환할 필요가 없다!!
NList menus = new NList(); // NList 객체 생성! 콜렉션이다.
resp.setContentType("text/html; charset=utf-8");
// resp.setContentType("text/txt; charset=utf-8");
// 내가 인코딩을 하는 것이 아니라 브라우저가 이런 방식으로 읽으라고 설정해준다.
PrintWriter out = resp.getWriter();
out.print("hello");
// 인젝션 sql 때문에 수정함.
String query = "";
String sql = String.format("select * from member where nicname like '%s'", "%"+query+"%") ;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@oracle.newlecture.com:1521/xepdb1";
Connection con = DriverManager.getConnection(url, "NEWLEC", "rland");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
// Menu[] menus = new Menu[100]; // 배열 하나 쓰기
// List<Menu> list = new ArrayList<>(); // 콜렉션 하나 쓰기 - 데이터를 수집하고 관리해주는 객체!
// 필터링, 집계, 정렬
while(rs.next()) // 서버의 커서를 한칸 내리고 그 위치의 레코드를 옮겨 오는 것. -> 레코드 하나가 저장되는 공간은?
{
int id = rs.getInt("id");
String name = rs.getString("name");
String nicName = rs.getString("nicname");
Menu menu = new Menu(id, name, 1000, "");
menus.add(menu); // List 같이 객체에 콜렉션을 넣자!
}
con.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// 윗부분은 데이터를 마련하는 부분!! **
// ================================
// 아랫 부분은 데이터를 출력하는 부분 나누기 !! **
out.write("<!DOCTYPE html>");
out.write("<html>");
out.write("<head>");
out.write("<meta charset=\"UTF-8\">");
out.write("<title>Insert title here</title>");
out.write("</head>");
out.write("<body>");
out.write(" <h1>메뉴 목록</h1>");
out.write(" <table>");
out.write(" <tr>");
out.write(" <td>번호</td>");
out.write(" <td>이름</td>");
out.write(" <td>가격</td> ");
out.write(" </tr>");
for(int i = 0; i<menus.size(); i++) {
Menu m = (Menu) menus.get(i); // 데이터를 출력하는 부분!
out.write("<tr>");
out.write(" <td>"+m.getId()+"</td>");
out.write(" <td>"+m.getName()+"</td>");
out.write(" <td>5000</td>");
out.write("</tr>");
}
out.write("</table>");
out.write("</body>");
out.write("</html>");
}
}
4) Wrapper 클래스
- 오토박싱 : Wrapper 클래스!!
menus.add(3);
Object obj = 3; // 콜렉션에 '3'은 직접 대입되지 않는다.
// 박씽과 언박씽을 해주는 것이 오토 박싱 / 오토 언박싱이다.
- 자바에서는 Integer 클래스가 다 있어서 박싱이 다 되어 있어서 Wrapper 클래스라고 부른다.
- 이것은 박싱을 해주는 클래스이다. 자바스크립트에서만 기본 자료형이 Wrapper 클래스 였다.
Object n = new Integer(3);
- 그래서 콜렉션을 Object형태 뿐만 아니라 사용 방식에 따른 범용 콜렉션이 필요하다!
- 그리하여, 제너릭을 이용한 템플릿으로 새로운 객체를 만든다 .
5) 제너릭
-
제너릭 클래스 : 타입이 무엇이든 될수 있다.
-
실제 제너릭 클래스를 직접 사용할 때는, 제너릭 클래스의 타입인 ‘재영’에 Menu가 들어가서 그 제너릭 클래스의 메서드를 이용한다!!
- 실습 코드 :
- 데이터 마련하는 부분과 출력하는 부분을 나눠서 작성한다.
- GList.java
package com.newlecture.web.entity;
// 제너릭 클래스 ! : (타입이 무엇이든 될수 있따.)
// '재영' 이라는 글씨를 컴파일러가 알아 먹지 못해서 타입을 변장 시켜준다.
public class GList<재영> {
private 재영[] data;
private int index;
private int max; // max로 임의의 값 지정!! 공간을 계속 늘리기 위해서!
public GList() {
index = 0;
max = 3;
data = (재영[]) new Object[max]; // '재영' 이라는 글씨를 컴파일러가 알아 먹지 못해서 타입을 변장 시켜준다.
}
public void add(재영 n) {
// 공간이 부족하면
if(index==max) {
// 공간을 늘리기
재영[] temp =(재영[]) new Object[max+3]; // 여기서 3이라는 숫자를 변수로 입력 받을 수 도 있다.
for(int i=0; i<max; i++)
temp[i] = data[i];
data = temp;
max = max+3;
}
data[index] = n;
index++;
}
public 재영 get(int idx) {
return data[idx];
}
public int size() {
return index;
}
}
- 제너릭 클래스를 이해했으며 이제는 List 인터페이스의 ArrayList 객체를 사용한다.
- ArrayList 객체도 제너릭 클래스를 이용하듯이 그 메서드를 사용한다!
- ListController2.java
package com.newlecture.web.controller.menu;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.newlecture.web.entity.GList;
import com.newlecture.web.entity.Menu;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
// GList 사용!!**
// 서블릿 바꿔주기!!** 경로!!
@WebServlet("/menu/list2")
public class ListController2 extends HttpServlet{
// 인터페이스명인 MenuService는 아무렇게 짓고 service로 불러오면 된다!
// private MenuService service; // 목록에 대한 데이터서비스를 얘한테 부탁한다!!
@Override // doGet 뿐만 아니라 doDelete, doPut, doPost, doHead 등이 있다.
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 서블릿은 메인함수 직접 작성하지 않고 입출력 도구가 달라짐!
// 이렇게 제너릭을 이용하면 하면 형변환할 필요가 없다!!(아래쪽 코드에 있다.)**
// 제너릭 클래스의 재영에 Menu가 들어가서 그 제너릭 클래스의 메서드를 이용한다!!
// GList<Menu> menus = new GList<Menu>(); // GList 객체 생성! 콜렉션이다.
// 제너릭 클래스를 이해했으며 이제는 List 인터페이스의 ArrayList 객체를 사용한다.
// ArrayList 객체도 제너릭 클래스를 이용하듯이 그 메서드를 사용한다!
// List는 인터페이스라서 new를 할 수 없다.
// 따라서, 자식 객체급의 ArrayList에서 new로 생성된다.(이 개념 추상화에서 했었다.)
List<Menu> menus = new ArrayList<Menu>(); // GList 객체 생성! 콜렉션이다.
// 이것은 내가하는 인코딩 방식이다. 요즘에는 기본으로 UTF-8로 인코딩이 된다.
// resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
// resp.setContentType("text/txt; charset=utf-8");
// 내가 인코딩을 하는 것이 아니라 브라우저가 이런 방식으로 읽으라고 설정해준다.
PrintWriter out = resp.getWriter();
out.print("hello");
// 인젝션 sql 때문에 수정함.
String query = "";
String sql = String.format("select * from member where nicname like '%s'", "%"+query+"%") ;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@oracle.newlecture.com:1521/xepdb1";
Connection con = DriverManager.getConnection(url, "NEWLEC", "rland");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
// Menu[] menus = new Menu[100]; // 배열 하나 쓰기
// List<Menu> list = new ArrayList<>(); // 콜렉션 하나 쓰기 - 데이터를 수집하고 관리해주는 객체!
// 이렇게 말고 제너릭을 쓰자!
// 필터링, 집계, 정렬
while(rs.next()) // 서버의 커서를 한칸 내리고 그 위치의 레코드를 옮겨 오는 것. -> 레코드 하나가 저장되는 공간은?
{
int id = rs.getInt("id");
String name = rs.getString("name");
String nicName = rs.getString("nicname");
Menu menu = new Menu(id, name, 1000, "");
menus.add(menu); // List 같이 객체에 콜렉션을 넣자!
}
con.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// 데이터를 마련하는 부분
// ================================
// 데이터를 출력하는 부분
// out.write("<!DOCTYPE html>");
// out.write("<html>");
// out.write("<head>");
// out.write("<meta charset=\"UTF-8\">");
// out.write("<title>Insert title here</title>");
// out.write("</head>");
// out.write("<body>");
// out.write(" <h1>메뉴 목록</h1>");
// out.write(" <table>");
// out.write(" <tr>");
// out.write(" <td>번호</td>");
// out.write(" <td>이름</td>");
// out.write(" <td>가격</td> ");
// out.write(" </tr>");
//
// for(int i = 0; i<menus.size(); i++) {
//
// // 제너릭을 사용하면, 이제는 형변환을 안 해줘도 된다.!!**
// Menu m = menus.get(i); // 데이터를 출력하는 부분!
//
// out.write("<tr>");
// out.write(" <td>"+m.getId()+"</td>");
// out.write(" <td>"+m.getName()+"</td>");
// out.write(" <td>5000</td>");
// out.write("</tr>");
// }
//
// out.write("</table>");
// out.write("</body>");
// out.write("</html>");
}
}
- Menu.java
package com.newlecture.web.entity;
public class Menu {
private int id;
private String name;
private int price;
private String img;
// 생성자(기본, 오버로드)
// Getters/ Setters
// toString();
// 스태틱 생성자!!는 무조건 실행된다.
// static { //이것이 ojdbc를 가져온다.
// System.out.println("아무것도... Menu전역 초기화 ");
// Menu.setName
//
// }
public Menu() {
}
public Menu(int id, String name, int price, String img) {
super();
this.id = id;
this.name = name;
this.price = price;
this.img = img;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
@Override
public String toString() {
return "Menu [id=" + id + ", name=" + name + ", price=" + price + ", img=" + img + "]";
}
}
6) JSP
- html코드에 java 코드를 사용할 수 있게 한다.
- 일단 기본 JSP 설정만 한다.
- html 파일확장자를 jsp 확장자로만 변경!
- 한글이 깨지는 현상 발생
- list.jsp
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>ë©ë´ 목ë¡</h1>
<table>
<tr>
<td>ë²í¸</td>
<td>ì´ë¦</td>
<td>ê°ê²©</td>
</tr>
<tr>
<td>1</td>
<td>ìë©ë¦¬ì¹´ë
¸</td>
<td>5000</td>
</tr>
<tr>
<td>2</td>
<td>ì¹´íë¼ë¼</td>
<td>5000</td>
</tr>
<tr>
<td>3</td>
<td>ì¹´í¸ì¹ë
¸</td>
<td>5000</td>
</tr>
</table>
</body>
</html>
- ListView.java
package com.newlecture.web.controller.menu;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.newlecture.web.entity.GList;
import com.newlecture.web.entity.Menu;
import com.newlecture.web.service.MenuService;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
// GList 사용!!**
// 서블릿 바꿔주기!!** 경로!!
@WebServlet("/menu/listview")
public class ListView extends HttpServlet{
// 인터페이스명인 MenuService는 아무렇게 짓고 service로 불러오면 된다!
private MenuService service; // 목록에 대한 데이터서비스를 얘한테 부탁한다!!
@Override // doGet 뿐만 아니라 doDelete, doPut, doPost, doHead 등이 있다.
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 이것은 내가하는 인코딩 방식이다. 요즘에는 기본으로 UTF-8로 인코딩이 된다.
// resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
// resp.setContentType("text/txt; charset=utf-8");
// 내가 인코딩을 하는 것이 아니라 브라우저가 이런 방식으로 읽으라고 설정해준다.
PrintWriter out = resp.getWriter();
// 데이터를 마련하는 부분
// ================================
// 데이터를 출력하는 부분
out.write("<!DOCTYPE html>");
out.write("<html>");
out.write("<head>");
out.write("<meta charset=\"UTF-8\">");
out.write("<title>Insert title here</title>");
out.write("</head>");
out.write("<body>");
out.write(" <h1>메뉴 목록</h1>");
out.write(" <table>");
out.write(" <tr>");
out.write(" <td>번호</td>");
out.write(" <td>이름</td>");
out.write(" <td>가격</td> ");
out.write(" </tr>");
// 조작하는 부분을 다른 것으로 올리기!!
// for(int i = 0; i<menus.size(); i++) {
// 제너릭을 사용하면, 이제는 형변환을 안 해줘도 된다.!!**
// Menu m = menus.get(i); // 데이터를 출력하는 부분!
out.write("<tr>");
// out.write(" <td>"+m.getId()+"</td>");
// out.write(" <td>"+m.getName()+"</td>");
out.write(" <td>5000</td>");
out.write("</tr>");
// }
out.write("</table>");
out.write("</body>");
out.write("</html>");
}
}
- MenuService.java
package com.newlecture.web.service;
// MenuService는 listController가 사용할 부품(인터페이스)이 된다.
public interface MenuService {
}
6. 피그마 : 230210
-
플러그인 사용 : 피그마에서 플러그인 중 ‘Figma to HTML’ 이용해보기(플러그인 사용 중 프레임 아무거나 클릭하면 HTML코드를 받을 수 있다.)
-
폰트 크기가 안 맞는 것 같다.
-
메뉴버튼 추가하는 것 다시보기, flex, grid 등