기초단계/JSP&Servlet

2023.04.03 JSP

춘핑이 2023. 4. 3. 18:31

JSP 쇼핑몰 만들기

6. 서블릿 이해

모델2는 기본적인 문법이 아니라 패턴을 배우게 되는 것이다.
어떻게 적용하느냐를 알아야한다.
이전에 만든 게시판을 model2로 만들어보자.

클라이언트가 서버에 접속을 하며 요청을 하게 된다.
요청을 모델1에서는 jsp가 처리했다. 모델2에서는 컨트롤러(서블릿 자바파일)가 이를 처리하게 된다.
이것이 모델 (DAO)를 통해서 DB에서 값을 가져오게 된다.
이 처리결과를 다시 서블릿에 넘긴다.
서블릿이 Request Dispatcher객체를 사용해서 VIEW(JSP)에 데이터를 넘겨주고 EL등을 사용해서 표현하게 된다.

jsp가 계속해서 바뀌는데 자바코드가 중간에 있으면 매우 헷갈려서 관리가 어려워진다.
그래서 mvc모델에서 나누어서 하는 장점이 있다.
스프링도 마찬가지로 MVC패턴을 사용한다.

서블릿 작성방법 2가지가 있다.
1.이클립스에서 서블릿코드 생성
2.서블릿 코드 작성
3.어노테이션으로 URL과 서블릿매핑하기(중요!!) / WEB.XML에서 매핑 하기
4.실행 후 웹브라우저에서 결과 확인

WEB.XML보다는 전자가 최근 방법이다.
자주 변경을 해야한다면 WEB.XML을 설정하는것이 좋다.
서블릿이 많이 있고 변경을 자주하려면 WEB.XML이 좋을 수도 잇다.
이런것은 알아서 판단해서 작성하는게 필요하다.

최신버전 서블릿에서만 어노테이션사용이 가능하다.

7. 서블릿 활용

실제 서블릿을 활용해보자. HELLO WORLD을 서블릿으로 찍어보자
request가 오면 서블릿으로 오고 이것을 jsp로 전달해주는 연습을 해보자.

의존관계 설정 등을 오버라이딩해서 인터페이스 사용하는데 이런것은 스프링에선 AOP로처리한다.
그때가서 공부하자.

jsp쪽으로 데이터를 request에 붙여서 넘겨주고
서블릿에서 jsp를 호출하면서 데이터를 같이 넘겨주는 객체를 선언해야한다.

http://localhost:8090/JSP1/HelloWorld
url에 맞추어서 매핑된 서블릿의 값이 jsp로 데이터가 넘어가서 출력되게 된다.
jsp:forward액션태그에서 사용햇을때 요청은 하나로 이루어지는 것이었다.
그런점에서 주소는 바뀌지 않고 처리 결과만 해당 jsp가 나오는 것처럼 보엿엇는데
이것도 서블릿이 처리를 하고 foward해서 jsp의 출력결과가 출력되는 것이라고 보면된다.

@WebServlet("/HelloWorld") // /HelloWorld라고 url에 표시해줘야 이 서블릿 클래스가 실행됨
public class HelloWorld extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void reqPro(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String msg = "Hello World 안녕하세요";

        request.setAttribute("msg", msg);

        RequestDispatcher rd = request.getRequestDispatcher("HelloWorld.jsp");//jsp파일명
        rd.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>
    <h2> 결과보기</h2>
    <p> 인사말 : ${msg} </p>
</body>
</html>

8. 파라미터 사용

파라미터를 통해서 데이터를 받아와서 처리해보자.
직접 서블릿을 호출해서 데이터를 받았다.
회원가입처럼 input값을 서블릿이 처리하도록 할 수 있다.
usebean을 사용햇는데 이것은 서블릿이 사용할 수 없다.

bean클래스를 만들어서 jsp에 보내고 jsp에서 el로 읽어오면 편하다.

form에는 서블릿 매핑이름을 넣어주면된다.

8.1 회원가입 페이지

<div align="center">
    <h2>회원 가입</h2>
    <form action="MemberJoinProc.jsp">
        <table width="500" border="1">
            <tr height="50">
                <td width="150" align="center">아이디</td>
                <td width="350" align="center">
                    <input type="text" name="id" size="40" placeholder="id를 넣으세요">
                </td>
            </tr>

            <tr height="50">
                <td width="150" align="center">패스워드</td>
                <td width="350" align="center">
                    <input type="password" name="pass1" size="40" placeholder="비밀번호는 숫자와 영어만 넣어주세요">
                </td>
            </tr>

            <tr height="50">
                <td width="150" align="center">이메일</td>
                <td width="350" align="center">
                    <input type="email" name="email" size="40">
                </td>
            </tr>

            <tr height="50">
                <td width="150" align="center">전화 번호</td>
                <td width="350" align="center">
                    <input type="tel" name="tel" size="40">
                </td>
            </tr>

            <tr height="50">
                <td width="150" align="center">주소</td>
                <td width="350" align="center">
                    <input type="text" name="address" size="40">
                </td>
            </tr>

            <tr height="50">
                <td align="center" colspan=2><input type="submit" value="회원가입"/></td>
            </tr>
        </table>
    </form>
</div>

8.2 서블릿

하나씩 파라미터를 받는건 쉽다. 그런데 jsp에 떠넘기려면 bean으로 담아서 보내는게 편하다.
그래서 bean을 만들어주자.

public class MemberBean2 {
    private String id;
    private String password;
    private String email;
    private String tel;
    private String address;
    //getter setter
}

jsp때는 usebean이 있었는데 어떻게 사용할까
doGet doPost는 request와 reposonse밖에 받지 못한다.
그래서 bean클래스 객체를 생성하고 사용해야한다.
그리고 view에서는 EL을 통해서 프로퍼티를 꺼내서 읽으면된다.

@WebServlet("/MProc2")
public class MemberJoinProc2 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    //doget이든 do post던 아래 reqPro메소드가 실행되게 해주기
    protected void reqPro(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        MemberBean2 bean = new MemberBean2();
        bean.setId(request.getParameter("id"));
        bean.setPassword(request.getParameter("password"));
        bean.setEmail(request.getParameter("email"));
        bean.setTel(request.getParameter("tel"));
        bean.setAddress(request.getParameter("address"));

        //request객체에 bena클래스 넘기기
        request.setAttribute("bean", bean);

        RequestDispatcher ds = request.getRequestDispatcher("MemberView.jsp");
        ds.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>
    당신의 아이디는 ${bean.id}
    당신의 패스워드는 ${bean.password}
</body>
</html>

9. MVC패턴 연습 1 (회원가입)

db와 연동해서 완전한 패턴을 사용해 보자.
모델1을 모델2로 변경해보는 것이다.

커넥션풀을 사용해야한다. server.xml에 또 설정을 해주자.

<Context docBase="JSP1" path="/JSP1" reloadable="true" source="org.eclipse.jst.jee.server:JSP1">
    <Resource auth="Container" driverClassName="com.mysql.cj.jdbc.Driver" loginTimeout="10" maxWait="5000" name="jdbc/pool" password="1234" type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/jspshop" username="chun"/>
</Context>

스프링은 하나의 컨트롤러만되는데 스프링은 메소드자체가 어노테이션이된다.
이 메소드만 처리해줘가 된다.

각각의 서블릿이 만들어지고 구분자로 분류를 해야한다.
1에의한 메소드 2에의한메소드 등등 도 가능하지만 이번에는 각각을 호출하도록 하자.

@WebServlet("/proc.do")
public class MemberJoinProc extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void reqPro(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");

        MemberBean bean = new MemberBean();
        bean.setId(request.getParameter("id"));
        bean.setPass1(request.getParameter("pass1"));
        bean.setPass2(request.getParameter("pass1"));
        bean.setEmail(request.getParameter("email"));
        bean.setTel(request.getParameter("tel"));
        String[] hobbies = request.getParameterValues("hobby");
        String hobby = "";
        for (String s : hobbies) {
            hobby += s + " "; //하나의 스트링으로 데이터 연결
        }
        bean.setHobby(hobby);
        bean.setJob(request.getParameter("job"));
        bean.setAge(request.getParameter("age"));
        bean.setInfo(request.getParameter("info"));

        //DB베이스 객체 선언한 후 저장
        //다음시간부터
    }
}

10. MVC패턴 연습 2 (회원가입)

Bean클래스에 담은것을 db에 저장을 해야한다.
DAO의 insertMember()를 실행시키기전에 비밀번호를 검사해줘야한다.
pass1과 pass2가 같다면 실행 이후 MemberList.jsp가 나오도록 처리해주고
비밀번호가 다르다면 로그인 에러페이지가 나오도록 해주자.

//패스워드가 같을 경우에만 데이터베이스에 저장
if (pass1.equals(pass2)){
    //DB베이스 객체 선언한 후 저장
    MemberDAO3 mdao = new MemberDAO3();
    mdao.insertMember(bean);

    RequestDispatcher dis = request.getRequestDispatcher("MemberList.jsp");
    dis.forward(request, response);
} else {
    request.setAttribute("msg", "패스워드가 일치하지 않습니다.");
    RequestDispatcher dis = request.getRequestDispatcher("LoginError.jsp");
    dis.forward(request, response);

//회원 한사람 저장 메소드
public void insertMember(MemberBean bean) {
    getCon();

    try {
        String sql = "INSERT INTO MEMBER VALUES(?,?,?,?,?,?,?,?)";
        pstmt = con.prepareStatement(sql);
        pstmt.setString(1, bean.getId());
        pstmt.setString(2, bean.getPass1());
        pstmt.setString(3, bean.getEmail());
        pstmt.setString(4, bean.getTel());
        pstmt.setString(5, bean.getHobby());
        pstmt.setString(6, bean.getJob());
        pstmt.setString(7, bean.getAge());
        pstmt.setString(8, bean.getInfo());

        pstmt.executeUpdate();

        con.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

11. MVC패턴 연습 3 (회원보기)

memberlist를 바로 호출하면안되고 리스트 처리해주는 서블릿을 만들어줘야한다.
컨트롤러에서 또다른 컨트롤러를 호출해줘야한다.

// 모든 회원 정보 리턴하는 메소드 작성
public List<MemberBean> getAllMember() {
    List<MemberBean> list = new ArrayList<>();

    getCon();

    try {
        String sql = "SELECT * FROM MEMBER";
        pstmt = con.prepareStatement(sql);
        rs = pstmt.executeQuery();

        while (rs.next()) {
            MemberBean bean = new MemberBean();
            bean.setId(rs.getString(1));
            bean.setPass1(rs.getString(2));
            bean.setEmail(rs.getString(3));
            bean.setTel(rs.getString(4));
            bean.setHobby(rs.getString(5));
            bean.setJob(rs.getString(6));
            bean.setAge(rs.getString(7));
            bean.setInfo(rs.getString(8));
            list.add(bean);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return list;
}

@WebServlet("/MemberListCon.do")
public class MemberListCon extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void reqPro(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //db에 연결하여 회원의 모든 정보 리턴
        MemberDAO3 mdao = new MemberDAO3();
        List<MemberBean> list = mdao.getAllMember();

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

view에서는 JSTL을 사용해서 반복문을 사용해서 출력해주면된다.
ITEM을 가져올때 attribute를 꺼내와야하니 여기서도 EL을 작성해줘야하는 것을 잊지말자

<div align="center">
    <h2>모든회원보기</h2>
    <table border="1">
        <tr height="40">
            <td align="center" width="50"> 아이디 </td>
            <td align="center" width="200"> 이메일 </td>
            <td align="center" width="150"> 전화번호</td>
            <td align="center" width="150"> 취미 </td>
            <td align="center" width="150"> 직업 </td>
            <td align="center" width="100"> 나이 </td>
        </tr>

        <c:forEach var="bean" items="${list}">
            <tr height="50">
                <td align="center" width="50"> ${bean.id } </td>
                <td align="center" width="200"> <a href="#">${bean.email }</a> </td>
                <td align="center" width="150"> ${bean.tel }</td>
                <td align="center" width="150"> ${bean.hobby } </td>
                <td align="center" width="150"> ${bean.job } </td>
                <td align="center" width="100"> ${bean.age } </td>
            </tr>
        </c:forEach>
    </table>
</div>

12. 모델2 게시판 - 게시글 보기

모델2 게시판을 JSP로 만들어보자.
글쓰기 - 전체글보기 - 글삭제 -글읽기 글수정 - 전체글보기
컨트롤러가 가장먼저 나오자.

전체글보기부터 만들자. 이전에는 jsp로 만들었는데 서블릿 컨트롤러를 하고
전체글 dao와 연결해서 db를 가져오자. 그 이후 서블릿이 jsp에 넘겨서 글보기를 해주자.
카운터링 한 알고리즘까지 활용하자.

있는 것을 가져다 쓰되 수정을 하자.
1.커넥션 풀 설정
2.DAO
3.Bean클래스
4.서블릿클래스

12.1 DAO클래스

public class BoardDAO2 {
    // 커넥션 설정
    Connection con;
    PreparedStatement pstmt;
    ResultSet rs;

    // 데이터 베이스의 커넥션풀을 사용하도록 설정하는 메소드
    public void getCon() {
        try {
            Context initctx = new InitialContext();
            Context envctx = (Context) initctx.lookup("java:comp/env");
            DataSource ds = (DataSource) envctx.lookup("jdbc/pool");
            con = ds.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

12.2 Bean클래스

public class BoardBean {
    private int num;
    private String writer;
    private String email;
    private String subject;
    private String password;
    private String reg_date;
    private int ref;
    private int re_step;
    private int re_level;
    private int readcount;
    private String content;
    //setter getter들
}

12.3 서블릿클래스

@WebServlet("/BoardListCon.do")
public class BoardListCon extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        reqPro(request, response);
    }

    protected void reqPro(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    }
}

13. 모델2 게시판 - 게시글 보기 2

서블릿을 설정해줘야하는데 카운터링 처리를 위해서 페이징처리를 그대로 작성해준다.

protected void reqPro(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    //화면에 보여질 게시글의 개수를 지정
    int pageSize = 10;
    //현재 보여지는 페이지의 넘버값
    String pageNum = request.getParameter("pageNum");
    //처음 처리시 값없으니 null 처리 해주기
    if (pageNum ==null){
        pageNum = "1";
    }
    //전체글의 개수
    int count = 0;
    //jsp페이지 내에서 보여질 넘버링
    int number = 0; 

    //현재 보여지는 페이지 문자를 숫자로 형변환
    int currentPage = Integer.parseInt(pageNum);

    //전체 게시글 내용 가져오기
    BoardDAO2 bdao = new BoardDAO2();

    //전체 게시글의 개수 읽어오는 메소드 호출
    count = bdao.getAllCount();

    //현재 보여질 페이지 시작번호 1 11 21 31
    int startRow = (currentPage -1) * pageSize + 1;
    //int endRow = currentPage * pageSize; 10 20 30 40
    //mysql은 10으로 고정 값 넣어주면된다.
    int endRow = pageSize;

    //전체 게시글을 리턴 받아주는 소스
    List<BoardBean> list = bdao.getAllBoard(startRow, endRow); 

    //테이블에 표시할 번호를 지정
    number = count - (currentPage - 1) * pageSize;
}

// 모든 화면에 보여질 데이터를 10개씩 추출해서 리턴하는 메소드
public List<BoardBean> getAllBoard(int start, int end) {
    // 리턴할 객체 선언
    List<BoardBean> list = Collections.synchronizedList(new ArrayList<>());

    getCon();

    try {
        String sql = "SELECT * FROM BOARD ORDER BY REF DESC, RE_STEP ASC limit ?, ?";

        pstmt = con.prepareStatement(sql);
        pstmt.setInt(1, start - 1);
        pstmt.setInt(2, end);
        rs = pstmt.executeQuery();
        while (rs.next()) {
            BoardBean bean = new BoardBean();
            bean.setNum(rs.getInt(1));
            bean.setWriter(rs.getString(2));
            bean.setEmail(rs.getString(3));
            bean.setSubject(rs.getString(4));
            bean.setPassword(rs.getString(5));
            bean.setReg_date(rs.getDate(6).toString());
            bean.setRef(rs.getInt(7));
            bean.setRe_step(rs.getInt(8));
            bean.setRe_level(rs.getInt(9));
            bean.setReadcount(rs.getInt(10));
            bean.setContent(rs.getString(11));
            list.add(bean);
        }
        con.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return list;
}