TIL - 12주차 코드

 
  • 프로젝트 개발 : 우리가 만들 프로젝트는 서버측에서 스프링부트를 이용하여 데이터를 RESTful API로 전송하기만 하고 클라이언트측에서 이러한 데이터를 받아서 클라이언트 측에서 전반적인 웹 개발(대부분의 업무 로직)을 진행한다.**


  • 이클립스 자동완성 : option + space


1. Servlet, JSP : 230213


1) 웹 서버 프로그래밍

  • ‘동적이다’라는 의미 : 클라이언트가 요청하거나 서버를 실행할 때, 문서가 만들어 진다.
  • 현재 코드의 문제점 : 데이터를 출력하는 코드와 입력하는 코드가 섞여 있다.
  • I/O 작업과 메모리 작업이 매우 다르다. 메모리 작업이 빨라서 먼저 처리하고 나중에 출력해주는 것이 빠르다.


  • View : 출력하는 부분, Controller : 사용자가 입력을 하면 수반되는 코드, Model : 사용자가 입력하면 전달하는 데이터.
    • ListController2.java, ListView.java 이용하기.


  • 데이터를 전달하는 방법(2가지) 차이점? : Redirection, Forwarding


  • Redirection :
    • response 도구에 포함되어있다. 이거는 출력 도구인데 출력 도구인데 redirect를 해준다.
    • 2번째 서블릿을 호출하는 것이 아니라 직접 호출하는 것이 아니다.
    • 응답은 하긴 했지만 다른 곳에서 그 요청을 가져다 준다.
    • list2는 클라이언트가 요청했고 응답을 했는데 다시 redirect로 그 응답을 해서 listview를 찾아간다. 이러한 방법이 redirection이다.
    • 정리** : 현재 작업하는 것과 상관없이 새로운 요청을 하게 된다, 저장소의 데이터에는 없어진다.


  • Forwarding :
    • 서버에서 서버를 요청해준다! 즉, 내가 요청한 도구이다.
    • 기다리는 동안에는 현재 2개의 서블릿이 살아 있고 입력값이 공유된다.
    • Dispatcher : ListController2에서 요청을 하면 이어서 너도 연결받아라. 일단, 일을 기다리고 forward를 통해 ListView에서도 req, resp를 공유한다.
    • 정리** : 현재 작업하는 내용을 계속 이어 갈 수 있도록 공유한다, 저장소의 데이터도 공유한다.


  • 실습코드 :


  • 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는 인터페이스라서 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 같이 객체에 콜렉션을 넣자!
				
				// 오토박싱 : Wrapper 클래스!!
//				menus.add(3);
//				Object obj = 3;  // 콜렉션에 '3'은 직접 대입되지 않는다.
											// 박씽과 언박씽을 해주는 것이 오토 박싱/ 오토 언박싱이다.
				
				// 자바에서는 Integer 클래스가 다 있어서 박싱이 다 되어 있어서 Wrapper 클래스라고 부른다. 
				// 박싱을 해주는 클래스이다. 자바스크립트에서만 기본 자료형이 Wrapper 클래스 였다. 
				// Object n = new Integer(3);
				
				// 그래서 콜렉션을 Object형태 뿐만 아니라 사용 방식에 따른 범용 콜렉션이 필요하다!
				// 그리하여, 제너릭을 이용한 템플릿으로 새로운 객체를 만든다 . 
				
				
			}
			
			con.close();
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		// resp.sendRedirect("listview");	// redirect 데이터를 넘겨주는 친구?
		
		req.setAttribute("menus", menus); // forwarding이 될때만 값이 전달된다. redirect일 경우는 안 된다. 
		
		req
		.getRequestDispatcher("listview")
		.forward(req, resp);
		
		
		
		
		
		// 데이터를 마련하는 부분
		
		// ================================
		
		// 데이터를 출력하는 부분 
		
//		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>");	
	
		}

}

  • 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();
		// 데이터를 마련하는 부분
		
		List<Menu> menus = (List<Menu>) req.getAttribute("menus");
		
		// ================================
		
		// 데이터를 출력하는 부분 
		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[] 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) 4대 저장소(암기) :

  • Page 저장소 : PageContext
  • Request 저장소 : HttpServletRequest
  • Session 저장소 : HttpSession, 한 사용자가 같으면 같은 사용자는 같은 공간을 이용한다.
  • Application 저장소 : ServletContext, 모든 유저가 이용할 수 있는 공간.

  • 정리 : 2개 사이의 서블릿에서 데이터를 공유하고 싶을 때, 위의 4가지 저장소를 사용한다. 또한, 이럴 때 forward를 이용한다.



2. JSP : 230214

1) Jasper

  • 확장자에서 jsp파일을 만들어서 jsp라는 요청을 주면 Jasper라는 알바가 서블릿 코드를 만들어 준다.

  • 톰캣의 프로젝트명은 Catalina이고 제품명이 Tomcat이다.

  • Jasper를 동작시키기 위해서는 jsp파일에서 서버를 켜야 Jasper가 일을 할 수 있다.

  • jsp가 만들어준 java 파일은 고쳐주면 안 된다. 우리는 jsp 파일만 수정할 수 있다.



2) JSP

  • 문자열을쓰기위한 out. write, 숫자나 문자를 출력하기 위한 out.print이다.


3) JSP 코드 블럭 종류

  • 일반적인 코드 블럭 : <% %>


  • 변수를 넣어 줄 수 있는 코드 블럭(out.print(i)를 대신 해준다.) : <%= i %>


  • 지역변수 말고 멤버로 넣을 수 있는(함수를 넣을 수 있는) 코드 블럭 : <%! %>
    • private int x=3;


  • 지시자 코드 블럭 (JSP 인코딩 방식을 위한 방법) :
    • response.setContentType이 안 된다. out 코드를 불러 오기 전에 써야하기 때문에 의미가 없다. 그래서 가장 처음에 실행해주기 위해서 처음에 지시해주기 위해서 앞에 써주자.
    • <%@ %>


  • Jasper의 내장된 객체가 있다. pageContext, request, session, application, page가 있고 이것은 예약어라서 이것과 같은 변수를 만들 수 없다.

  • this를 의미해주는 page가 있다.

  • @import : 새로 추가된 List나 Menu 객체들을 JSP 파일에 추가해주는 코드블럭.



4) view 파일을 숨기는 방법

  • view 부분은 클라이언트로부터 호출되어서는 안된다. 그래서, 클라이언트에게 WEB-INF 리소스를 배포해서 안되고 WEB-INF 리소스는 클라이언트에게 숨기는 파일들이다.

  • 중요 : WEB-INF 리소스는 서버 상에서만 요청할 수 있다.

  • /WEB-INF/view/menu/list.jsp : 지금은 상대경로보다는 절대경로가 편하다.



  • 실습 코드 :


  • 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;

// jsp파일을 변경해주면, 서블릿 경로도 바꿔줘야 한다. 
// 실행도 컨트롤러에서 실행을 시켜주어야 한다.
@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 {
		
		// List는 인터페이스라서 new를 할 수 없다. 
		// 따라서, 자식 객체급의 ArrayList에서 new로 생성된다.(이 개념 추상화에서 했었다.)
		List<Menu> menus = new ArrayList<Menu>();		// GList 객체 생성! 콜렉션이다. 
	
		
		
		resp.setContentType("text/html; 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);

			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();
		}
		
		// resp.sendRedirect("listview");	// redirect 데이터를 넘겨주는 친구?
		req.setAttribute("menus", menus); // forwarding이 될때만 값이 전달된다. redirect일 경우는 안 된다. 
		
		
		// url도 jsp파일과 같게 설정해주어야 한다. 실제 디렉토리 경로가 아니라 url 경로이다. 
	
		req
		.getRequestDispatcher("/WEB-INF/view/menu/list.jsp")	// 지금은 상대경로보다는 절대경로가 편하다.
		.forward(req, resp);
		
		
		
		
		
		// 데이터를 마련하는 부분
		
		// ================================
		
		// 데이터를 출력하는 부분 
		
//		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>");	
		

		
		}
	
	
}


  • list.jsp
<%@page import="com.newlecture.web.entity.Menu"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   
<!-- JSTL 사용하기! uri가 없으면 -->
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    
<!-- 위에는 지시자 코드블럭-->


 <% 
 	List<Menu> menus = (List) request.getAttribute("menus");
 %>
 
<!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>


<!-- 문자열을쓰기위한 out. write, 숫자나 문자를 출력하기 위한 out.print이다. -->		


	<c:forEach begin="1" end="5" step="1">					
			<tr>
				<td>1</td>
				<td>아이스 아메리카노</td>
				<td>5000원</td>
				<!-- 값이라서 세미콜론이 없다. -->
				<%-- <td><%= m.getId() %></td>
				<td><%= m.getName() %></td>
				<td>5000</td> --%>			
			</tr>
	</c:forEach>
	
	</table>
</body>
</html>


5) JSTL(JSP Standard Tag Library), EL 태그


a. JSTL

  • jsp에서 java 코드를 쓰지 않게 하기


  • Tag Handler API(많이 안 쓴다.) : Tag Library를 직접 만들 수도 있다.
    • WEB-INF 폴더에 ~.tld라는 파일이 존재한다.


  • JSTL : 보편적으로 쓰는 태그 라이브러리
    • JSTL 종류 : core, formating, functions를 쓴다.
    • core : 제어문 관련 태그(if문, for문 등)
    • formating : 숫자에 대한 함수와 날짜 등
    • function : substring, 소문자를 대문자로 바꿔준다.


  • core 태그 :
    • 반복문 : forEach, forTokens
    • 조건문 : if
    • 선택하는 구문 : choose, when이고 추가로 url



	<c:forEach begin="1" end="5" step="1">					
			<tr>
				<td>1</td>
				<td>아이스 아메리카노</td>
				<td>5000</td>
				<!-- 값이라서 세미콜론이 없다. -->
				<%-- <td><%= m.getId() %></td>
				<td><%= m.getName() %></td>
				<td>5000</td> --%>			
			</tr>
	</c:forEach>
	




3. JSP, EL : 230215

1) EL 태그 : core 이용

  • request가 교도보 역할을 해주고 이것은 원래 request.getAttrubute("title")로 값을 출력해야 한다. 하지만 EL 태그를 쓰면 더 간단히 표현할 수 있다.
    • ${menus}로 쓸 수 있다.


  • forEach 구문에 의해서 담아놓은 ${menu}를 꺼내서 쓸 때는 pageContext.getAttribute로 꺼내서 쓴다.
    • pageContext.getAttribute


  • pageContext.getAttribute은 객체라서 형변환((Menu))을 해주고 표현식은 꺼내 쓸 수 있게 getName()을 get도 지우고 ()도 지우고 name으로 바꿔서 사용한다.
    • ((Menu) pageContext.getAttribute("m")).getName()
    • 따라서, EL 태그를 이용해서 간단히 ${m.name}으로 사용한다.
    • 원래는 getter이지만, 속성을 이용하는 것과 같다.


  • EL은 4대 저장소에 들어가서 저장하기 때문에 저장소에 있는 것을 꺼내 사용한다.
    • List<Menu> menus = (List)request.getAttribute("menus"); %> 이제 이 지역 변수 부분은 없애도 된다. request라는 저장소에 들어 가게 된다.


2) EL 태그 : fmt 이용

  • pattern, value 이용

<fmt:formatDate pattern="yyyy-MM-dd HH:mm:ss" value="${m.regDate}" />


  • 원래는, List(menus)에서 객체(var)를 뽑아낸 것이다.
  • fmt 태그에서 var에 다시 넣어주면, pageContext에 들어가는 것과 같다. 그것을 다시 더 간단히 꺼내서 사용할 수 있다.
<c:forEach var="m" items="${menus}">		
	<fmt:formatNumber  var="price" pattern="#,###"  value="${m.price}"/>
	<fmt:formatDate var="regDate" pattern="yyyy-MM-dd HH:mm:ss" value="${m.regDate}" />
			
		<tr>
			<td>${m.id}</td>
			<td>${m.name}</td>
			<td>${price}원</td>
			<td>${regDate}</td>
		</tr>
</c:forEach>
			


  • forTokens 태그 : 각각의 파일들을 개별적으로 스타일링하는 방법
    • 스타일링이라서 원래는 view단에서 해주는 것이 맞다.
    • 구분자를 가지고 문자열을 쪼개주고 tokens 수만큼 나누어 하나의 요소로 구분시켜 줄 수 있다.
    • 구분자도 바꿔줄 수 있다.


  • 실습 :
    • entity에 images 추가해주기
	<td colspan="4">
		<c:forTokens var="img" items="${m.images}" delims=",">
			${img}
		</c:forTokens>
	</td>


3) EL 태그를 이용한 반복문의 조건 처리


  • varStatus :
    • 반복문의 조건 처리를 위해서 if문을 쓰고 꼭 상태값(varStatus)이 필요하다.
      • st.current : 현재 토큰이 출력.
      • st.begin, st.end : 특정 범위의 index를 출력해준다.


  • EL 표현식의 연산자 : ${} 안에서 연산자를 적어주는 것이 적용된다.
    • empty 연산자 : st.last != null and st.last != "" 2개의 연산을 한번에 처리해준다.(문자열 검사에서 사용)
      • empty st.last


  • not 연산자 : !st.last or not st.last
<tr>
	<!-- forTokens 이용! -->
	<td colspan="4">
		<c:forTokens var="img" items="${m.images}" delims="," varStatus="st">
			<!-- a태그로 감싸줘서 페이지 이동도 가능하다. -->
			<a href="upload/${img}">${img}</a>
			
			<!-- 구분자의 가장 마지막 구분자는 없애 줘야 한다. -->
			<c:if test="${!st.last}"> | </c:if>
			
		</c:forTokens>
		<br>
	</td>
</tr>


  • 하지만, if-else 구문에서 else 구문은 없어서 if 문으로만 사용해야 한다.


  • when, when-otherwise 구문도 있다.()


4) EL 태그의 변수 집중화 :


  • Context path를 바꾸면 톰캣의 서버도 지워주고 다시 실행해야 한다.


  • core의 set 태그

// 경로에서 쓰인다. var는 컨텍스트페이지에 담긴다.
<c:set var="path" value="/webprj" />


  • core의 url 태그
<%-- 경로에서 보통 쓰이는 방법 : -->
<c:url var="path" value="/upload"/>

<%-- context가 있으면, url 태그를 이용해서 컨텍스트명을 알아서 붙여준다. -->
<a href="${path}/${img}">${img}</a>


  • core의 fn 태그
    • 문자열 쪼개기 정도로만 쓰인다.


  • 서버의 주석 처리 : <%-- aa -->
  • 클라이언트의 주석 처리 : <!-- aa -->



  • 전체 실습 코드 :


  • list.jsp
<%@page import="com.newlecture.web.entity.Menu"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   
<!-- JSTL 사용하기! uri가 없으면 가져오기-->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!-- EL은 4대 저장소에 들어가서 저장하기 때문에 저장소에 있는 것을 꺼내 사용한다.  -->
<%--  <% 
 	List<Menu> menus = (List) request.getAttribute("menus");
 %>
  --%>
  
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>메뉴 목록</h1>
	
	<!-- html 테이블 속성 추가 -->
	<table border="1">
		<tr>
			<td>번호</td>
			<td>이름</td>
			<td>가격</td>			
			<td>날짜</td>	
		</tr>


<!-- 문자열을쓰기위한 out. write, 숫자나 문자를 출력하기 위한 out.print이다. -->		


	<%-- <c:forEach begin="1" end="5" step="1">	 --%>
	<c:forEach var="m" items="${menus}">				
			<fmt:formatNumber  var="price" pattern="#,###"  value="${m.price}"/>
			<fmt:formatDate var="regDate" pattern="yyyy-MM-dd HH:mm:ss" value="${m.regDate}" />
			<tr>
				<td>${m.id}</td>
				<td>${m.name}</td>
				<td>${price}원</td>
				<td>${regDate}</td>	
			</tr>
			
			<tr>
				<!-- forTokens 이용! -->
				<td colspan="4">
					<c:forTokens var="img" items="${m.images}" delims="," varStatus="st">
						<!-- a태그로 감싸줘서 페이지 이동도 가능하다. -->
						<a href="upload/${img}">${img}</a>
						
						<!-- 구분자의 가장 마지막 구분자는 없애 줘야 한다. -->
						<c:if test="${!st.last}"> | </c:if>
						
					</c:forTokens>
					<br>
				</td>
			</tr>
	</c:forEach>
	
	</table>
</body>
</html>


  • 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.Date;
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;

// jsp파일을 변경해주면, 서블릿 경로도 바꿔줘야 한다. 
// 실행도 컨트롤러에서 실행을 시켜주어야 한다.
@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 {
		
		// List는 인터페이스라서 new를 할 수 없다. 
		// 따라서, 자식 객체급의 ArrayList에서 new로 생성된다.(이 개념 추상화에서 했었다.)
		List<Menu> menus = new ArrayList<Menu>();		// GList 객체 생성! 콜렉션이다. 
		
		resp.setContentType("text/html; 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);

			while(rs.next())	// 서버의 커서를 한칸 내리고 그 위치의 레코드를 옮겨 오는 것. -> 레코드 하나가 저장되는 공간은?
			{
				int id = rs.getInt("id");
				String name = rs.getString("name");
				String nicName = rs.getString("nicname");
				Date regDate = rs.getDate("reg_date");
				String images = "pic1.png, pic2.png, pic3.png";			// DB에 칼럼이 없어서 직접 입력하여 테스트하기 
				
				Menu menu = new Menu(id, name, 1000, "", regDate);
				menu.setImages(images);				// 직접 입력해주므로 setter로 List에 값을 넣어준다. 
				
				menus.add(menu); 		// List 같이 객체에 콜렉션을 넣자!
			
				
			}
			
			con.close();
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		// resp.sendRedirect("listview");	// redirect 데이터를 넘겨주는 친구?
		req.setAttribute("menus", menus); // forwarding이 될때만 값이 전달된다. redirect일 경우는 안 된다. 
		
		
		// url도 jsp파일과 같게 설정해주어야 한다. 실제 디렉토리 경로가 아니라 url 경로이다. 
	
		req
		.getRequestDispatcher("/WEB-INF/view/menu/list.jsp")	// 지금은 상대경로보다는 절대경로가 편하다.
		.forward(req, resp);
		
		
		
		
		
		// 데이터를 마련하는 부분
		
		// ================================
		
		// 데이터를 출력하는 부분 
		
//		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;

import java.util.Date;

public class Menu {
	
	private int id;
	private String name;
	private int price;
	private String img;
	private Date regDate;			// Date는 java.util로 임포트 해주기
	private String images;
	
	// 생성자(기본, 오버로드)
	// Getters/ Setters
	// toString();
	
// 스태틱 생성자!!는 무조건 실행된다. 
//	static {			//이것이 ojdbc를 가져온다.
//		System.out.println("아무것도... Menu전역 초기화 ");
//		Menu.setName
//		
//	}
	
	public Menu() {
	}
	

	public Menu(int id, String name, int price, String img, Date regDate) {
		this.id = id;
		this.name = name;
		this.price = price;
		this.img = img;
		this.regDate = regDate;
	}


	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;
	}


	public Date getRegDate() {
		return regDate;
	}


	public void setRegDate(Date regDate) {
		this.regDate = regDate;
	}

		
	public String getImages() {
		return images;
	}


	public void setImages(String images) {
		this.images = images;
	}


	@Override
	public String toString() {
		return "Menu [id=" + id + ", name=" + name + ", price=" + price + ", img=" + img + ", regDate=" + regDate
				+ ", images=" + images + "]";
	}
	
}




4. Spring 시작 : 230216


  • 레이어 나누기 :
    • 업무를 잘하는 사람? 은 DB와의 여러 문제까지 같이 충돌되는 현상을 처리하는 것까지 다 해결하는 사람이 업무를 잘하는 사람이다.


1) JAVA로 레이어 나누기

  • 실무에서 DB를 다루려면, 업무를 잘 알아야 한다.(ex) 여러 포인트 결제 시스템 - 취소했을 때, 발생하는 경우)
  • 인터페이스는 사용하는 쪽에서 정의한다.
  • 각 계층의 레이어들을 연결해줄 때, 인터페이스 구현체에 연결하는 것이 아니라 인터페이스에 연결해주어야 한다.


2) SOLID 원칙

  • 객체지향 디자인 원칙 : SRP, OCP, LSP, ISP, DIP 법칙

  • 예시 :


  • SRP : 책임을 하나만 사용해야 한다. 역할 분배를 잘해라


  • OCP : 객체가 수정에는 닫혀 있고 확장에는 열려 있어야 한다.
    • 모듈을 서로 배분하고 사용하는 것 npm 사이트가 있는데 JS로 이용하는 수많은 라이브러리가 있다.
    • npm 레포지토리에서 모듈이 유명한데, 모든 모듈을 사용할 수 없었다. 어떤 사람이 역대급으로 함수 이름을 바꿔 버림..
    • 그래서, 그 유명한 모듈을 사용할 수 없다.
    • 하지만, 확장을 하면 코드는 무거워지지만 전체 버전을 업그레이드 해야 한다.


  • LSP : 하위 객체는 치환해도 문제가 없어야 한다.


  • ISP: 너무 많은 것을 한번에 약속(인터페이스)을 정하지 마라. 클라이언트가 필요하지 않은 인터페이스는 없애고 만들어라.


  • DIP : 종속성 역전 원칙? 사용하는 객체 이름이 ‘A’라고 하면, 우리는 객체를 쓸 때, ‘A’라는 부품 객체 이름을 쓰지 말고 부모의 이름을 사용해서 써라!
    • 조금 더 범용화된 참조형을 써야 한다. 왜냐하면, 메서드 추가할 떄, 그 객체를 이용하여 사용한다.


3) Layered Architecture


1) DAO

  • 테이블의 데이터를 가져와서 자바스럽게 사용할 수 있게 해주는 변환 객체이다. SQL문을 몰라도 순수하게 자바코드로만 데이터를 다룰 수 있다.
  • ex) MemberDao, NoticeDao, MenuDao로 사용한다.
  • DAO는 메서드를 보통 find(), insert(), delete(), update()라는 이름을 이용한다.


2) 인터페이스 심화 개념

  • 참조하는 것을 자식형인 구현체화된 이름을 써주는 것이 아니라 부모형을 써줘야 한다.
  • 결론 : 인터페이스만 일치하면, 바꿔치기 하는데 문제가 없다,


3) 외부파일에서 객체 생성하는 방법

  • 그래서 객체 생성을 외부에서 생성해줄 수 도 있다.
  • 생성해야할 객체 생성 방법을 외부 파일에 둔다. XML과 Annotation 방식이 있다.
  • 객체를 생성하는 일이 내가 코딩하는 부분에 있다면, 그 코드를 수정할 때, 그 소스코드 내부에서 수정해줘야 한다.
  • 그래서, 이러한 객체를 생성해주고 연결해주는 코드를 Spring 프레임워크가 대신 해준다.


4) 스프링이 해주는 일

  • 객체를 텍스트에 저장해두면, 텍스트 문자열 부분을 원래는 Class.forName으로 직접 만들어주어야하지만 텍스트로서 저장만 해두면 객체 생성을 스프링이 만들어 줄 것이다.(getBean())


4) 자바로 만든 Layered Architecture의 실습 코드

ListController4.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.Date;
import java.util.List;

import com.newlecture.web.entity.GList;
import com.newlecture.web.entity.Menu;
import com.newlecture.web.service.DefaultMenuService;
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/list4")
public class ListController4 extends HttpServlet{

	private MenuService service;		// 목록에 대한 데이터서비스를 얘한테 부탁한다!!
	
	 public ListController4() {
		 // 컨트롤러 객체와 구현된 서비스 객체를 강한 결합으로 연결 
		 service = new DefaultMenuService();
	}
	
	 
	@Override						// doGet 뿐만 아니라 doDelete, doPut, doPost, doHead 등이 있다.
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html; charset=utf-8");	
		
		PrintWriter out = resp.getWriter();
		
		List<Menu> menus = service.getList(); 	//  이젠 service에서 List를 받아온다. 

		// resp.sendRedirect("listview");			// redirect 데이터를 넘겨주는 친구?
		req.setAttribute("menus", menus); 		// forwarding이 될때만 값이 전달된다. redirect일 경우는 안 된다. 
		
		// url도 jsp파일과 같게 설정해주어야 한다. 실제 디렉토리 경로가 아니라 url 경로이다. 
		req
		.getRequestDispatcher("/WEB-INF/view/menu/list.jsp")	// 지금은 상대경로보다는 절대경로가 편하다.
		.forward(req, resp);
		
		}	
	
}


MenuService.java
package com.newlecture.web.service;

import java.util.List;

import com.newlecture.web.entity.Menu;

// MenuService는 listController가 사용할 부품(인터페이스)이 된다. 
public interface MenuService {
	List<Menu> getList();
}


DefaultMenuService.java
package com.newlecture.web.service;

import java.util.List;

import com.newlecture.web.entity.Menu;
import com.newlecture.web.repository.MenuDao;
import com.newlecture.web.repository.jdbc.JdbcMenuDao;

// 다양한 업무를 처리하기 위한 상관 관계를 잘 아는 사람이 데이터를 조작하도록 한다.
// 단, 데이터를 조작하기 위한 방법은 몰라도 되도록 하는 것이 어떨지...
// 다음과 같은것들을 모르고도 자바 지식만으로 업무를 처리할 수 있게 하는 것이 좋지 않을까?

// - 어떤 DB를 사용해야하는지.. 
// - 쿼리를 어떻게 작성해야 하는지...
// - 데이터 소스가 다양한데 그것이 어떤 것들을 사용해야 하는지...

// - 데이터 베이스가 달라지면? SQL과 연결 문자열과 드라이브 등이 달라지는데... 그럼 모든 업무로직 코드를 수정해야 한다. 

// **지금은 코드가 간단하지만, 원래는 서비스 로직에서는 2개 이상의 업무를 처리하는 객체가 있어야 한다. 

// 중요!!
 
// 서비스 객체의 메서드는 사용자 요청이 함수화 된다. 
	// getList(), likeUp() : 사용자가 요구하는 내용이 메서드의 이름이 된다.
//DAO 객체의 메서드는 SQL 명령어를 함수화한다. 
	// 데이터를 조작하는 객체에 메서드 이름은 서비스와 달라야 하는 것이 맞다.

public class DefaultMenuService implements MenuService {
	private MenuDao menuDao;
	
	 public DefaultMenuService() {
		 // 컨트롤러 객체와 구현된 서비스 객체를 강한 결합으로 연결 
		 menuDao = new JdbcMenuDao();
	}
	
	@Override
	public List<Menu> getList() {
		List<Menu> list = menuDao.findAll();
		return list;
	}
	
}


MenuDao.java
package com.newlecture.web.repository;

import java.util.List;

import com.newlecture.web.entity.Menu;

public interface MenuDao {
	List<Menu> findAll();
}


JdbcMenuDao.java
package com.newlecture.web.repository.jdbc;

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.Date;
import java.util.List;

import com.newlecture.web.entity.Menu;
import com.newlecture.web.repository.MenuDao;

public class JdbcMenuDao implements MenuDao {

	@Override
	public List<Menu> findAll() {
		List<Menu> menus = new ArrayList<>();
		
		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);

			while(rs.next())	// 서버의 커서를 한칸 내리고 그 위치의 레코드를 옮겨 오는 것. -> 레코드 하나가 저장되는 공간은?
			{
				int id = rs.getInt("id");
				String name = rs.getString("name");
				String nicName = rs.getString("nicname");
				Date regDate = rs.getDate("reg_date");
				String images = "pic1.png, pic2.png, pic3.png";			// DB에 칼럼이 없어서 직접 입력하여 테스트하기 
				
				Menu menu = new Menu(id, name, 1000, "", regDate);
				menu.setImages(images);				// 직접 입력해주므로 setter로 List에 값을 넣어준다. 
				
				menus.add(menu); 		// List 같이 객체에 콜렉션을 넣자!	
			}			
			con.close();
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return menus;
	}

}


Menu.java
package com.newlecture.web.entity;

import java.util.Date;

public class Menu {
	
	private int id;
	private String name;
	private int price;
	private String img;
	private Date regDate;			// Date는 java.util로 임포트 해주기
	private String images;
	
	// 생성자(기본, 오버로드)
	// Getters/ Setters
	// toString();
	
// 스태틱 생성자!!는 무조건 실행된다. 
//	static {			//이것이 ojdbc를 가져온다.
//		System.out.println("아무것도... Menu전역 초기화 ");
//		Menu.setName
//		
//	}
	
	public Menu() {
	}
	

	public Menu(int id, String name, int price, String img, Date regDate) {
		this.id = id;
		this.name = name;
		this.price = price;
		this.img = img;
		this.regDate = regDate;
	}


	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;
	}


	public Date getRegDate() {
		return regDate;
	}


	public void setRegDate(Date regDate) {
		this.regDate = regDate;
	}

	
	
		
	public String getImages() {
		return images;
	}


	public void setImages(String images) {
		this.images = images;
	}


	@Override
	public String toString() {
		return "Menu [id=" + id + ", name=" + name + ", price=" + price + ", img=" + img + ", regDate=" + regDate
				+ ", images=" + images + "]";
	}

}




5. Spring 도입부 : 230217


1) 이전 복습 :


  • 서비스 객체 :
    • 업무 : 사용자가 요구하는 기능


  • 컨트롤러 객체 :
    • 사용자 요청을 서비스 객체에 전달하고 View단에 사용자에게 보여줄 출력을 담당하는 친구


  • DAO 객체 :
    • 업무자가 자바코드 말고 안쓰게 하려고
    • 결국 자바 객체만 사용한다.
    • DAO 코드를 수정할 때는 새로운 확장되어서 바꿔치기 해야 한다.(소스코드를 직접 바꾸면 코드 수정 시, 사용자가 사용하지 못한다.)


  • 객체를 생성해주는 라이브러리는 스프링이 해줄 것이다.
  • DAO에서 데이터를 가져오는 부분도 라이브러리를 이용할 것이다. Mybatis, JPA을 이용한다.


2) 웹 에러 정리

  • 인증이 안되었거나 권한이 없어서 이 요청을 처리할 수 없는 경우 우리는 어떤 상태 코드를 전달해야 할까? 사용자에게 : 403 에러
  • 매개변수 인지가 일치하지 않는 경우 : 400에러
  • POST 요청에 응답할 수 있는 메소드 처리함수가 없을 경우의 오류 상태 코드는? 405 에러


3) front-controller 개념

  • 서블릿(톰캣)처럼 특화된 것에만 종속되어 있다. 이렇게 특화된 방식으로 입력을 처리한다.
  • 입력 받는 코드가 너무 반복적이고 불편하다.
  • 출력을 위한 Distpatcher forward가 매번 똑같은 코드로 반복된다.

  • 해결 방법 :
    • 그래서, Front Controller가 모든 응답을 담당한다.
    • 요청도 입력하고 문서도 출력한다.
    • 요청과 출력 그리고 URL도 얘가 처리한다.
    • 기존 컨트롤러는 자바스럽게 전달한다. 매개변수만 존재한다.


4) 사용자 입력 받는 방법

1) 쿼리 스트링을 이용한 입력 :

  • 쿼리(질의) : 사용자가 문서를 달라고 하는 것 + 추가적으로 제공하게 되는 옵션 값을 쿼리 스트링이라고 한다.
  • 웹이 기본적으로 요청할 때 옵션 값이다.
  • 하지만, 이것은 서버가 기본적으로 이러한 옵션을 제공해주어야 사용이 가능하다.
  • 예시 : 페이지, 검색어, 레코드 개수, 기간, ….
  • 전달된 내용은 무조건 String 형이다. 바로 문자열을 사용할 수 없어서 정수로 쓰기 위해서는 형변환을 해주어야 한다.

response.setContentType("text/html; charset=utf-8");	

String page = request.getParameter("p");
String query  = request.getParameter("q");
String size = request.getParameter("s");
		


  • 그럼 요청 방법은?

PrintWriter out = response.getWriter();
out.printf("%s %s %s ", page, query, size);

// s는 size이다. 웹의 주소는 100자 내외의 길이 제한했던 부분이 있다.


2) form을 이용한 입력

  • 사실 쿼리 스트링은 사용자가 전달하는 값이라기 보다 페이지를 제공하는 쪽에서 정해진 값을 선택하게 하는 방식입니다
  • 예를 들어서 쿼리스트링은 사용자가 URI창을 직접 편집하는 것이 아니라 다음처럼 링크에 있는 경우가 일반적입니다.
<a href="/input?p=2&q=hello&s=15“>2</a> 
<a href=”/input?p=3&q=hello&s=15“>1</a>


  • 위와 같이 이미 정해진 값들 중에 하나의 링크를 선택함으로써 입력을 요청하게 됩니다.


  • 반면에 사용자가 값을 직접 입력하게 하고 싶다면 어떻게 할까? 그 때는 form을 제공함으로써 입력을 하게 합니다.

out.write (String.format ("page:%s, query:%s, size:%s<br>", page, query, size));

out.write("<form action=\"/webprj2/input\" method=\"get\">"); 
out.write(" <label>page:</label>");
out.write(" <input type=\"text\" name=\"p\"><br>");
out.write(" <label>검색어 : </label>") ;
out.write(" <input type=\"text\" name=\"q\"><br>");
out.write(" <label>size:</label>");
out.write(" <input type=\"text\" name=\"s\"><br>");
out.write(" <input type=\"submit\" value=\"제출\">");
out.write("</form>");

request.setAttribute("page", page);
request.setAttribute("query", query);
request.setAttribute("size", size);



3) 우선순위 설정 및 param 이용

  • 4대 저장소에서 데이터가 저장된다.

  • page-request-session-application 순서로 EL 태그를 찾는다.

  • model이 있을 때, tag library로 변수가 생성되어 값이 저장되어 있으면, 우선 순위가 밀린다.

  • 그때 model에 우선순위를 주기 위해서 Scope를 사용해서 콕 집어 준다. (requestScope)

  • 추가로 쿠키나 세션을 객체 생성하지 않고 그냥 사용할 때, 그냥 param에서 꺼내서 사용할 수 있다.**
    • 우선순위 : requestScope 이용
  • input.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>   
<c:set var="site" value=""/>
 
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<a href="/webprj2/input?p=2&q=hello&s=15">2</a> 
	<br>
	<a href="/webprj2/input?p=3&q=hello&s=15">3</a> 
	<br>
	<a href="/webprj2/input?p=4&q=hello&s=15">4</a> 
	<br>
	
	<div>
		page : ${page} , query : ${query} , size : ${requestScope.size}
	</div>
		
	<form action="/webprj2/input" method="get"> 
		 <label>page:</label>
		 <input type="text" name="p"><br>
		 <label>검색어 : </label>
		 <input type="text" name="q"><br>
		 <label>size:</label>
		 <input type="text" name="s"><br>
 		<input type="submit" value="제출">
	</form>

</body>
</html>


  • inputController.java
package com.newlecture.web;

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("/input")
public class InputController extends HttpServlet {
		
	@Override
		protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		
		// 1. 쿼리 스트링을 이용한 입력 
		// 쿼리(질의) : 사용자가 문서를 달라고 하는 것 + 추가적으로 제공하게 되는 옵션 값을 쿼리 스트링이라고 한다.  
		// 웹이 기본적으로 요청할 때 옵션 값이다. 
		// 하지만, 이것은 서버가 기본적으로 이러한 옵션을 제공해주어야 사용이 가능하다.

		// 예시 : 페이지, 검색어, 레코드 개수, 기간, .... 
		// 전달된 내용은 무조건 String 형이다. 바로 문자열을 사용할 수 없어서 정수로 쓰기 위해서는 형변환을 해주어야 한다.		
		response.setContentType("text/html; charset=utf-8");	
		
		
		String page = request.getParameter("p");
		String query  = request.getParameter("q");
		String size = request.getParameter("s");
		
		
		// 그럼 요청 방법은?
		PrintWriter out = response.getWriter();
		// out.printf("%s %s %s ", page, query, size);
		
		// s는 size이다. 웹의 주소는 100자 내외의 길이 제한했던 부분이 있다.
		
		
		
		// 2. form을 이용한 입력
		// 사실 쿼리 스트링은 사용자가 전달하는 값이라기 보다 페이지를 제공하는 쪽에서 정해진 값을 선택하게 하는 방식입니다 
		// 예를 들어서 쿼리스트링은 사용자가 URI창을 직접 편집하는 것이 아니라 다음처럼 링크에 있는 경우가 일반적입니다.
		// <a href="/input?p=2&q=hello&s=15“>2</a> 
		// <a href=”/input?p=3&q=hello&s=15“>1</a>
		
		// 위와 같이 이미 정해진 값들 중에 하나의 링크를 선택함으로써 입력을 요청하게 됩니다 .
		// 반면에 사용자가 값을 직접 입력하게 하고 싶다면 어떻게 할까? 그 때는 form을 제공함으로써 입력을 하게 합니다.
		
		out.write (String.format ("page:%s, query:%s, size:%s<br>", page, query, size));
		
		out.write("<form action=\"/webprj2/input\" method=\"get\">"); 
		out.write(" <label>page:</label>");
		out.write(" <input type=\"text\" name=\"p\"><br>");
		out.write(" <label>검색어 : </label>") ;
		out.write(" <input type=\"text\" name=\"q\"><br>");
		out.write(" <label>size:</label>");
		out.write(" <input type=\"text\" name=\"s\"><br>");
		out.write(" <input type=\"submit\" value=\"제출\">");
		out.write("</form>");
	
		
		request.setAttribute("page", page);
		request.setAttribute("query", query);
		request.setAttribute("size", size);
		
		
		// [EL 저장소]
		// 4대 저장소에서 데이터가 저장된다. 
		// page-request-session-application 순서로 EL 태그를 찾는다.
		
		// model이 있을 때, tag library로 변수가 생성되어 값이 저장되어 있으면, 우선 순위가 밀린다.
		// 그때 model에 우선순위를 주기 위해서 Scope를 사용해서 콕 집어 준다. (requestScope)
 		
		
		
		
		// 3. 쿠키 입력 
		
		
		// 4. Header 입력 
		
		
		
		// 3. hidden 필드  입력 
		
		
		
		
	
		
		request.getRequestDispatcher("WEB-INF/view/input.jsp").forward(request, response);
		
		
	}
}



0. css 정리
  • reset.css :

  • utils.css :

  • style.css :

  • component.css :

  • button.css :