기초단계/JSP&Servlet

2023.04.06 JSP

춘핑이 2023. 4. 6. 17:46

newlec JSP

40. JSP 시작하기 (Jasper를 이용한 서블릿 프로그래밍)

자바를 이용해서 웹개발을 할때 서블릿이라는 것을 이용해서 프로그램을 만들었는데 제스퍼라는 도움을 통해 서블릿을 좀 더 쉽게 개발하는 방법을 배우고자 한다.
이것이 바로 JSP프로그램이다.
간단한 문자열을 보내면 어렵지 않지만 HTML출력이 많은 결과 페이지는 어렵다. 이전처럼 한줄한줄 출력하면 매우 귀찮다.

재스퍼에게 일을 시킽려면 확장자만 jsp로 바꾸면된다. html코드들을 출력할 것으로 인식하고 출력하게 된다.
그런데 과연 이것들이 서블릿으로 언제 바꿔지나? jsp가 요구될때 만들어진다. url매핑은 jsp파일자체가 url이된다.

.jsp.java로 바뀌게 된다.

재스퍼를 사용하면 요청할때마다 다시 만들어준다.
서블릿에 변경이 있으면 그것을 다시 컴파일하기 위해 서버를 재시작했었는데 굳이 그럴필요가 없다.
우리가 컨트로 f11로 시작했을때 왼쪽에 보이는 webapp의 파일을 열어주는 것같지만 그것이아니다.
이것들은 개발할때 사용하는 개발디렉토리이고 톰캣의 홈디렉토리로 옮겨지게 된다.
사용하고있는게 실제 사용하는것과 섞이면 안되니 별도의 이클립스가 관리하는 별도의 운영을 위한 서비스 운영을 위한 사본을 만든다. 개발할때 사용하는 임시 개발디렉토리이다.
workspace.metadata.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\ROOT\org\apache\jsp
워크스페이스에가면 제스퍼가 만들어놓은 컴파일된 jsp파일을 볼 수 있다.

만약 int x = 3; int y = 4;처럼 변수를 선언하고싶은데 그냥 작성하면 출력표시가 들어간다.
그럼 이것들을 그대로 사용하고싶을때 사용되는게 바로 코드블록(스크립트릿)이다.

<%
int x = 3;
int y = 4;
%>

이런식으로 작성하면 출력할 것이아니라 서블릿안에 자바코드를 넣고싶은 것이라는 것을 나타내는것이다.
재스퍼가 만든것을 직접 건들면 안되고 재스퍼가 올바르게 일할 수 있도록 jsp파일만 만져야한다.

41. JSP의 코드블록

재스퍼로 서블릿코드를 간접적으로 만들었다.
문서를 출력할때 단순히 출력하는게아니라 방대한 HTML을 출력하는 것은 단순반복적이고 불편하기 때문에 재스퍼를 사용한것이다.

출력 문자 사이에 자바코드를 끼워넣는 방법은 많다.
코드블록을 작성하면 서비스 메소드 블록에 들어가게 된다.
실행되어야할 자바코드라면 그대로 넣어달라고 코드블록(스트립트릿)에 넣어야한다.

1.코드블록의 종류1 : 출력코드
환영합니다. -> out.write("환영합니다.");

2.코드블록의 종류2 : 코드블록
<% y =x+3; %> -> y =x+3;

3.코드블록의 종류3 : 코드블록2
y의값은: y 라고할때 출력하고자하는 것이 문자열 + 자바코드라면
y의 값은: <% out.print(y) %> 코드블럭을 만들고 값을 꺼내는 코드를 적어주면된다.

out.write("y의 값은: "); out.print(y);가 될것이다.
y의 값은: <%=y%> 이전 같은 내용이 추가가 된다.

단순히 출력만한다고 할때 out.wirte를 계속쓰면 불편하니 표현식을 쓰는게 좋다.

4.코드블록의 종류4 : 선언부(Declaration)

<%
  public int sum(int a, int b)
  {
  return a + b;
  }
%>

메소드를 만들고 싶을때 코드블록을 만들면 에러가 난다.
이 메소드가 서비스 메소드에 들어가면 메소드 안에 메소드를 정의할 수 없어서 구문 에러가 발생한다.
멤버메소드를 정의하고 싶다면 선언부를 사용하면된다.
<%! %> !를 추가해주면 멤버에 들어가게 된다.

5.코드블록의 종류5 : 초기설정을 위한 Page 지시자
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding = "UTF-8" %>
일반적으로 페이지 지시자라고 한다. 키 =값 으로 작성되는데 페이지를 어떠한 형태의 인코딩 켄텐트 타입이 무엇인지를 지시하는 것이다.

이 지시블록이 필요한 이유는 서블릿에서 프로그램만들때 출력하는데 우리가 UTF-8로하고 이것을 인코딩하는 것을 브라우저에게 지시했던 기억이있다.
과거에는 우리가 작성했던 코드를 코드블록안에 넣어서 처리했엇다.

<%
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8");
%>

그런데 이런것이 문제가 없어야하는데 애석하게도 에러가 발생하게 된다.
이것들이 먼저 출력이 안되기때문에 이미 출력이 진행된다음 설정하는 것이 잘못된 것이다.
그래서 페이지 지시자는 어떠한 코드보다도 설정이 먼저 진행되기 때문에 이것을 사용해야 된다.

페이지에서 저런것들을 설정하게 지시하는 것이라고 할 수 있다.

42. JSP의 내장객체 간단히 알아보기

jsp페이지를 만들면서 int page = 3; 하면
Duplicate local variable page 에러가 발생한다. 로컬변수가 중복되었다는 뜻이다.

나는 이 변수를 사용해본적이 없는데 중복된다고 나온다? 왜일까?
간과하지 말아야할 것은 이 코드블록 외에 코드가 있다는 것이다.

재스퍼가 서비스함수를 만들며 자기가 필요해서 만든 변수가 있다.
객체 형식을 가지고있는 변수들이다. 이것들을 내장객체라고 한다.

이것들을 우리가 알고 JSP를 만들때 이것들을 활용할 수 있어야 한다.
대표적으로 request response같은 입력도구와 출력도구
application session 객체
페이지 내에서 어플리케이션 세션처럼 임시로 데이터를 저장할 수있는 pageContext 객체가있다.
config out page객체를 참조하는 것들이잇다.

42.1 내장객체 HttpServletRequest

HttpServletRequest는 입력도구를 많이 사용해왔다.
getParameter()등등이 있다.
사용자 전달한 파라미터 입력 등 쿠키얻기 메소드얻기 세션얻기 등등
사용자가 요청한 ip를 얻을때 getRemoteAddr()등도잇다. 헤더정보등도 얻을 수있다.

42.2 내장객체 HttpServletResponse

HttpServletResponse은 출력도구로 많이 사용했다.
redirect, 헤더 설정, 컨텍트 형식설정, url인코딩, 상태값 넣기 등이 있다.

42.3 내장객체 out javax.servlet.jsp.JspWriter

출력하거나 그럴때 사용하는데 재스퍼가 알아서 해주기때문에 직접 사용할일은 적다.

42.4 내장객체 session

getAttribute(attr) / setAttribute(name,attr)등 값을 설정하거나 얻어내기
저장되는 시간들을 허용하기
removeAttribute(name)을 사용해서 세션에 설정한 속성값을 삭제하는 것들은 중요하다.
등등의 기능이 있다.
필요하다면 사용할 수 있게 있다는 것을 기억해두자.

42.5 내장객체 applcation : ServletContext

서블릿들이 사용하고 있는 문맥(context) 서블릿들이 사용하는 것을 얻어낼 수 있는 기능이다.
값을 설정하거나 값을 얻기 등등의 역할을 한다.

43. JSP로 만드는 Hello 서블릿

jsp페이지에 일하는 방법을 배웠으니 초간단 페이지를 만들어보자.
처음 만들엇던 nana.java를 이용해서 만들어보자
nana.jsp를 만드는데 이것이 url이름으로 매핑되기때문에 소문자로 이름을 만들어주는 것이 좋다.

jsp라는 것이 html을 출력하는 것이기때문에 기본적인 틀은 알아서 추가가된다.

10번 반복해서 출력한다고 해보자.

<% for (int i = 0 ; i< 10 ; i++) {%>
안녕 Servlet!!<br >
<%}%>

전체를 담는게 아니라 줄을 나눠서 중괄호도 코드블록에 담아줘야한다.
재스퍼가 한문장을 만들지 두문장을 만들지 구분을 못하기 때문에 정리해야한다.

원래대로라면 전부 다 작성해야하지만 out은 이미 재스퍼에서 사용하고 있고
utf-8로 변환하는 과정은 페이지 지시자에서 설정을 했기때문에 필요없다.
우리는 코드블록만 책임지면 되서 출력이 많은 경우 도움을 받을 수 잇다.

<%    
    String cnt_ = request.getParameter("cnt");
    int cnt = 100;
    if (cnt_ != null && !cnt_.equals("")) {
        cnt = Integer.parseInt(cnt_);
    }
    String[] result = new String[cnt];
    for (int i = 0 ; i< result.length ; i++) {
        result[i] = "안녕 Servlet!!";
    }
%> 

장점도 많지만 요즘 단점이 더많아진다.
요즘 경향은 jsp사용을 정말 출력에 필요한 템플릿페이지로만 사용한다.

44. 스파게티 코드를 만드는 JSP

JSP를 만드는 방법은 정말 다양해서 이를 단순하게 만들수도 복잡하게 만들 수 도있다.
복잡하게 만들면 스파게티 코드이다. 이게 문제가 되는 이유를 알아보도록하자.

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<%
String num_ = request.getParameter("n");
if(num_ != null && !num_.equals("")){
    num = Integer.parseInt(num_);
}
%>
<body>
    <%if(num%2 != 0){%> 
    홀수입니다.
    <%}
    else
    {%> 
    짝수입니다.
    <%}%>
</body>
</html>

코드를 만들었을때 자바코드들만 모아서 볼 수가 없다.
어떤블록이 어디서 오류가 낫는지 어떤 블록들이 단일화되있는지 알기 어렵다.
관심있는 코드와 관심없는 코드가 섞여있으면 작업하기 매우 힘들다.
스파게티 코드, 우리나라말로는 실타래 코드라고 한다.
이런 코드를 지양하고 바람직하게 만들어야하고 그럴라면 코드들이 모여있어야 한다.

45. JSP MVC model1

스파게티 코드가 만들어지면 작업을 할때 매우 힘들다.
잘못만들면 코드블록이 복잡해지는 문제가 발생하게 된다.
코드블록이 흩어져있는 것을 간단하게 하는것이 MVC model1방식이다.

블록을 최소화 시키는 것이다.
가능하면 코드들을 위에 몰아 넣고 밑에는 출력코드만 모아 놓는 것이다.
업무로직은 윗 코드에서 보고 출력을 고치려면 밑으로 내려가서 보완하는 것이다.

이러기 위해서는 추가적인 변수가 필요하다.
이런 변수를 모델이라고 한다.

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

    String num_ = request.getParameter("n");
    if(num_ != null && !num_.equals("")){
    num = Integer.parseInt(num_);
    }

    String result;

    if(num%2 != 0){
        result = "홀수";
    } else {
        result = "짝수";
    }
%> 
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>

<body>
    <%=result%>입니다.
</body>
</html>

if문들이 위로 올리고 출력하기 위한 것을 변수에 넣었다.
이전 조건문에서는 출력을 제어했다면 이 모델에서는 데이터를 제어하는 것이다.
출력할 데이터를 만들고 출력할때는 쉽게 꽃아 넣는게 만드는것이다.

이렇게하면 코드들이 한곳에 모일수있고 코드블록이 줄어들 수있다.
앞으로 프로그램을 만들때 모델1처럼 만드는게 좋다.
데이터를 제어하는 것이 중요하다.

입력과 제어를 담당 : Controler[자바코드]
출력을 담당 : View[html코드]
출력데이터 : Model
->이래서 MVC 모델1이다. 자바코드와 출력코드를 최대한 분리하고 Model변수를 적절히 사용하는 것이다.

코드를 조금 더 쉽게 유지보수 할 수 있다.

46. JSP MVC model1을 model2 방식으로

model1 : 컨트롤러와 뷰가 물리적으로 분리되지 않은 방식. jsp 페이지 1개에 작성을 했었다.
model2 : 컨트롤러와 뷰가 물리적으로 분리된 방식 View단만 jsp로만든다.
사용자 요청에따라 view단만 서블릿으로 만들어지니 서블릿으로 만드는게 분량이 훨씬 줄어든다.
그리고 컨트롤러들은 미리 컴파일해놔서 배치해놓기 때문에 더 개선되고 유지보수가 쉬워진다.

model2는 Dispatcher를 집중화 하기 전의 모델이다.
model2를 더발전시키면 다음과 같아진다.

컨트롤단에서 뷰를 연결하기 위해 포워딩하는 방법이 사용된다.
둘다 서블릿 서블릿에서 서블릿으로 연결하도록 이어지는게 포워딩이라는 것이다. 이 포워딩을 Dispatcher로한다.
페이지가 추가가되면 컨트롤러-뷰가 하나씩 추가되고 이것들이 각각 Dispatcher로 포워딩하게 되면
Dispatcher이 여러개 있는 것이 중복되는 것이므로 어떻게보면 비효율적으로 보인다.
그래서 뷰와 소통하는 서블릿은 Dispatcher를 하나만두고
일반적인 업무로직인 Controller들은 별도의 POJO클래스로 일반클래스로 만들어서 사용자 요청이 들어오면 Dispatcher가 적절한 컨트롤러를 호출하도록 해준다.

이번에는 물리적으로 분리만 해보도록한다.
request.setAttribute("result", result);
redirect
현재작업과 관련없는 새로운요청
forward
현재작업한 내용을 이어갈수있도록 공유하는 것
RequestDispatcher dispatcher = request.getRequestDispatcher("spag.jsp");
dispatcher.forward(request, response);

현재작업햇던 내용들을 담고있다면 jsp 서블릿에 이어지면 jsp에서 사용하는 request와 response가 이 서블릿의 것이다.
jsp에서 꺼내서 사용할수도있고 이용하면 포워드 새로요청하면 리디렉트
둘사이에 포워드하는 것은 request를 사용한다.

실행은 무조건 컨트롤러에서 한다.
데이터를 컨트롤러가 만들기때문이다. 뷰는 그냥 껍데기일뿐이다.
코드가 완전히 물리적으로 분리되었다는 것을 이해해야한다.

@WebServlet("/spag")
public class Spag extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        int num = 0;

        String num_ = request.getParameter("n");
        if (num_ != null && !num_.equals("")) {
            num = Integer.parseInt(num_);
        }

        String result = "";

        if (num % 2 != 0) {
            result = "홀수";
        } else {
            result = "짝수";
        }

        request.setAttribute("result", result);
        RequestDispatcher dis = request.getRequestDispatcher("spag.jsp");
        dis.forward(request, response);
    }
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>

<body>
    <%=request.getAttribute("result")%>입니다.
</body>
</html>

47. EL(Expression Language)

JSP를 MVC를 만들려고할때 중요한 표기언어이다.
Controller단: request.setAttribute("cnt",30); -> View단: request.getAttribute("cnt")

View에서는 자바코드를 사용하지 않는게 MVC구현하는데 가장 좋은 방법이다.
이 값을 EL이라는 저장소에 담을 수 있다.

${cnt} 그 값을 꺼내서 출력까지 해준다.
저장소에서 값을 꺼내기 위해 복잡한 로직 사용할 필요가 없어진다.
$ { } 에 넣으면된다.

<%=request.getAttribute("result")%>입니다.

${result}입니다.

같은 역할을 하게 된다.

좀 더 복잡한 것을 심는다고 해보자.

List list = new ArrayList(){"1", "test"};
request.setAttribute("list", list);
((List))request.getAttrilibute("list")).get(0)
무조건 객체로 뽑아주기때문에 get을 못쓴다. 그래서 List로 강제 타입변환도 해줘야한다.

EL을 사용하면 ${list[0]} 배열처럼 꺼내면된다.

Map n = new HashMap("title", "제목");
request.setAttribute("n", n);
-> ((Map) request.getAttribute("n")).get("title")
-> ${n.title}

48. EL의 데이터 저장소

#{cnt} request라는 저장소에 담겨잇다. 사실 여기서만 검색하는 것은 아니다.
1.pageContext 2.request 3.session 4.application에서 4개의 영역에서 꺼내 사용할 수 있다.

request는 포워드를 통해 두개의 서블릿이 값을 공유할때 사용하는 저장소이다.
pageContext는 JSP내에서 재스퍼가 만들어낸 객체 중 pageContext 페이지내에서 사용할 수 잇는 서블릿객체들을 모아놓은것이다.
이런애들이 페이지단위로 저장소 역할이 필요하면 저장소 역할을 할 수있는 객체이다.

<%
pageContext.setAttribute("aa","hello");
%>

이것을 또 el을 사용해서 읽을 수 있다.
4개의 객체에다가 우연치않게 같은 이름으로 넣엇을 경우 좁은 순서부터 가져오게 된다.
pageContext->request->session->appication순서이다.

이럴때 사용하는게 pageScope, requestScope, sessionScope, applicationScope으로 특정 저장소에서만 꺼내올 수있다.
각 영역에 들어잇는 attribute를 저장하는 Map이다.
${sessionScope.cnt} 이건 객체가 아니라 그냥 한정사로 사용할 수 있다

.

el표기는 4대 저장소 이외에도 사용할 수 있는 객체가 잇다.
${param.cnt} ${header.host} ${header["host"]} 등등이 있다.
보통 파라미터를 컨트롤러에서 얻는데 때에 따라 파라미터를 간단하게 뷰단에서 얻을때 사용하는 것이다.
attribute의 이름에 -같은게 들어가거나 띄어쓰기 같은 변수이름을 그냥 만들 수 없는 것이 있다면 그냥 불러올수 없어서 []에 담아야한다.

header는 개발자도구 켜서 보기 accept는 브라우저 할때 내가 읽을 수있는 페이지타입등을 보여준다.
pageContext 페이지 단위의 컨텍스트 저장소
<%=pageContext.getRequest().getMethod()%>
${pageContext.request.method}
객체를 사용하지만 메소드가 아닌것처럼 사용할 수 있다.

49. EL의 연산자

[] .
()
not ! empty
* / div % mod
+ -
< > <= >= lt(less than) gt(greater than) le ge
== != eq ne
&& and
|| or
? :
굳이 연산자를 lt gt이런걸 사용해야할까? html이 기본적으로 꺽은쇠를 가지고 있어서 안에다가 꺽은쇠를 사용하는 것은 오류를 유발할 수 있다.
html과 같은 환경에서는 왠만하면 영어로 된 키워드 연산자를 사용하는게 좋다.

${empty param.n} null이든 빈문자열이든 true로온다.
${param.n == null || param.n == ""}와 같은 의미이다.

${empty param.n? '값이비어있습니다.':param.n} 3항연산자로 필요하면 값 나타낼 수 있다. 자바에서의 삼항연산자와 기능이 같다.
${param.n/2}
1.5 문자열/2했는데 정수/ 정수 로해서 실수값으로 나온다.
산술연산에서는 알아서 정수로 변환되고 계산이 된다. 정수로 변환이 안될 경우 예외가 발생한다.

50. JSP 수업용 프로젝트 준비하기

사용자홈페이지
관리자페이지
회원가입 공지사항등록 공지사항조회
공지관리에 대한 기본적인 방식 배우기
db를 사용할것이다.

51. JSP를 이용한 자바 웹프로그래밍 시작하기

JSP로 웹프로그래밍을 만들기 위해서는 다음 두가지를 알아야한다.
1.JSP로 만드는 이유 2. JSP이용하는 방법

1.JSP로 만드는 이유
출력내용이 정적인내용을 OUT.WRITE로 직접 작성해줘야한다. 비효율적이니 재스퍼로 사용해서 필요한 코드만 하는게 좋다.
JSP파일에 코드블록을 적절하게 넣어서 잘 사용할 수 있느냐가 JSP이용하는 방법이다.
확장자는 JSP지만 결국만드는것은 서블릿이다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
한글을 사용할 경우 페이지 지시자를 안넣으면 깨진다.
페이지 지시자 꼭넣어주고 db로 데이터를 가져올 것이다.

알트 엔터 눌러서 인코딩방식을 바꿔줘야한다.
out.write할때도 한글이 깨지지 않도록 설정을 해줘야한다.
utf-8로 설정을 안해서 그렇다. 그래서 페이지 지시자를 넣어주면 되는 것이다.

자바코드를 적절하게 넣어서 반복문을 사용하려면 다음처럼 넣을 수 있다.

<% for(int i = 0 ; i <10; i++){    
    pageContext.setAttribute("i", i);
%>

<tr>
    <td>${i+1}</td>
    <td class="title indent text-align-left"><a href="detail.html">스프링 8강까지의 예제 코드</a></td>
    <td>newlec</td>
    <td>
        2019-08-18        
    </td>
    <td>146</td>
</tr>
<%
}
%>

2023.04.06 후기

이미햇엇던 JSP를 MYSQL과 따로 공부한 내용을 조금씩 커스텀해보며 체험해보려고한다
아무리 사용을 안해도 한번은 마무리하고 가보고 싶다.