TIL - 11주차 코드

 

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로 생긴다.
    • 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로 보았다.

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 등