Web-app으로 Conversion

서현서현·2022년 5월 26일
0

서블릿 & JSP

목록 보기
16/26

Untitled

이전 ibatis 예제의 dao.service,vo,util 패키지를 src에 복붙

Untitled

res도 다이나믹 프로젝트에 복붙해주고, 폴더 형태로 붙여넣기 되니 아래 add폴더에서 선택해 소스폴더 형태로 전환해준다

Untitled

제너레이트 해주기 +> web.xml 생긴다!

Untitled

이거 쓰고...

request : HTML 폼 요소의선택 값 등 사용자의 입력정보를 읽으려고 사용한다.
getParameter(name) : 문자열 name과 이름이 같은 매개변수의 값을 가져온다.
setCharacterEncoding() : 현재 JSP로 전달되는 내용을 지정한 캐릭터셋으로 변환해준다.
response : 사용자 요청에 대한 응답을 처리하려고 사용한다.
setContentType(type) : 문자열 형태의 type에 지정된 MIME Type으로 contentType을 설정한다.
sendRedirect(url) : 클라이언트 요청을 다른 페이지로 보낸다.
session : 클라이언트의 세션 정보를 처리하려고 사용한다.
setAttribute(name, attr) : 문자열 name으로 java.lang.Object attr을 설정한다.
getAttribute(attr) : 문자열 attr로 설정된 세션 값을 java.lang.Object 형태로 반환한다.
out : 사용자에게 전달하기 위한 output 스트림을 처리하려고 사용한다.
println(content) : content의 내용을 newline과 함께 출력한다.
application : 웹 서버의 애플리케이션 처리와 관련된 정보를 참조하려고 사용한다.
getServerInfo() : JSP/서블릿 컨테이너의 이름과 버전을 반환한다.

회원 전체정보 조회

ListmemberController extends HttpServlet

import java.io.IOException;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.or.ddit.member.service.IMemberService;
import kr.or.ddit.member.service.MemberServiceImpl;
import kr.or.ddit.member.vo.MemberVO;

public class ListmemberController extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 1.서비스객체 생성하기
		IMemberService memService = MemberServiceImpl.getInstance();
		
		// 2. 회원정보 조회
		List<MemberVO> memList = memService.getAllMemberList();
		
		**req.setAttribute("memList", memList);**
		
		RequestDispatcher rd = req.getRequestDispatcher("/view/member/list.jsp"); // 포워드할 경로 정해주기 디스패처=보내다
		rd.forward(req, resp); //foward() : req, resp를 전달! 사용자입장에서 리퀘스트는 한번임. resp보는게 한번이니까... 안에서 포워드 백번하든말든...
		
		// 3. 
		
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}

}

원래는 메인에서 서비스를 호출해서 진행했었는데, 이번엔 메인이 없고 서블릿을 실행하니까,... doget 요청에 대해서 처리해 주는 것이다. 어떻게? 서비스클래스의 객체를 먼저 생성해놓고 이제 서비스클래스를 쓸 수 있게 함! 그리고 요청이 왔을때 우선 리스트를 띄워주기 위해서~

memList라는 리스트를 서비스 객체의 getAllMemberList()메소드의 리턴값으로 설정해준다.

그리고 request의 setAttribute()라는 메소드를 사용하는것. 이 메소드는 JSP에 값을 넘겨주기 위해서 memList를 memList라는 객체명으로 명명하는것같다.

원하는 경로의 jsp파일에 세팅한 memList를 보내기 위해서 getRequestDispatcher(경로)를 선언해준다. 그리고 객체.forward() 메소드를 통해 req와 resp를 보낸다. 이때 유의할점은 사용자의 요청은 단 한번이라는것! 포워드를 몇번하든 req는 단한번이다.

즉 위 코드를 통해 사용자로부터 get요청이 오면 설정한 경로의 jsp파일로 req를 보내는데, 이 req엔 서비스 객체를 통해 가져온 memList가 들어있다!

list.jsp

위 경로에 jsp파일 만들어준다.. 루트는 webcontent

<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="kr.or.ddit.member.vo.MemberVO"%>

<%
	List<MemberVO> memList = (List<MemberVO>)**request.getAttribute("memList");**
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원목록</title>
</head>
<body>
	<table border="1">
		<tr>
			<th>ID</th>
			<th>이름</th>
			<th>전화번호</th>
			<th>주소</th>
		</tr>
		
		<%
			int memSize = memList.size();
			if(memSize>0){
				for(int i = 0; i<memSize; i++) {
		%>
		
		<tr>
			<td><%out.print(memList.get(i).getMemId()); %></td>
			<td><%out.print(memList.get(i).getMemName()); %></td>
			<td><%out.print(memList.get(i).getMemTel()); %></td>
			<td><%out.print(memList.get(i).getMemAddr()); %></td>
		</tr>
		
		<%
				}
			} else{
		%>
		
			<tr>
				<td colspan = "4">회원정보가 없습니다.</td>
			</tr>
			
		<% } %>
		
	
	<tr align="center">
		<td colspan="4"><a href="#">[회원 등록]</a></td>
	</tr>

	</table>

</body>
</html>

서블릿 3.0부터는 xml 뿐만아니라 어노테이션을 통해서도 등록이 가능하다.

doGet에서 설정한 memList를 쓰기 위해 MemberVo를 임포트 해주고,
setAttribute로 보낸건 getAttribute로 받아서 사용할것이다

<%%>를 통해서 반복문을 돌면서, memList에서 .get()으로 멤버를 특정하고 거기서 .getMemName()등의 메소드로 표를 채워준다 (out.print는 JSP문법인듯) (memList는 memberVO가 List형태로 들어가 있으니 이런 메소드가 가능한거 알지?)

ListmemberController extends HttpServlet

@WebServlet(value="/member/list.do")
@WebServlet("/member/list.do") //밸류 안써도 ㄱㅊ
public class ListmemberController extends HttpServlet{

// .do가 붙었다? 아 컨트롤러가 붙어서 처리해주는구나~ 하고 쉽게 알 수 있다
// 이제 서블릿으하는 경우에만 캐릭터 인코딩 처리를 할수 있다. 
// 필터처리할때 .do인 경우에만 url인코딩을 하도록 설정 할 수도 있다!

위 어노테이션을 추가함으로서 xml로 경로설정 해주지 않아도(<?) 링크를 설정해 줄수있다!

애플리케이션을 톰캣에 적재

Untitled

만약 실행 안되면 있던거 지우고 exam 넣기!

접속결과

http://localhost/ServletExam/member/list.do << 접속

Untitled

<td><%out.print(memList.get(i).getMemId()); %></td>
이거 너무 자주 쓰니까
<td><%=memList.get(i).getMemId() %></td>
이렇게 쓰기도 함!
<tr align="center">
		<!-- 현재 url 기준으로 상대경로로 표현 -->
		<td colspan="4">**<a href="insert.do">**[회원 등록]</a></td>
	</tr>

회원정보 등록

InsertMemberController extends HttpServlet

@WebServlet("/member/insert.do")
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InsertMemberController extends HttpServlet{

	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.getRequestDispatcher("/view/member/insertform.jsp").forward(req, resp);
	}
	
	
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doPost(req, resp);
	}
}

새로운 컨트롤러를 만든다! 이번엔 화면에 데베로 부터 끌어올 내용은 없으니까

그냥 req.getRequestDispatcher() 메소드를 이용해 jsp파일로 포워딩만 해준다

insertform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>신규회원 등록</title>
</head>
<body>
		<table>
			<tr>
				<td>I D:</td>
				<td><input type="text" name="memId" value=""></td>
			</tr>
			<tr>
				<td>이름:</td>
				<td><input type="text" name="memName" value=""></td>
			</tr>
			<tr>
				<td>전화번호:</td>
				<td><input type="text" name="memTel" value=""></td>
			</tr>
			<tr>
				<td>주소:</td>
				<td><textarea name="memAddr" ></textarea></td>
			</tr>
		</table>
		<input type="submit" value="회원 등록">
	</form>
</body>
</html>

접속

http://localhost/ServletExam/member/insert.do

get으로 접근하면 다음과같이뜬다

Untitled

근데 이제 이건 post방식으로 해결해야하는 내용!

따라서 insertform을 action으로 바꿔준다

Post방식으로 전환

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>신규회원 등록</title>
</head>
<body>
	**<form action="insert.do" method="post">**
		<table>
			<tr>
				<td>I D:</td>
				<td><input type="text" name="memId" value=""></td>
			</tr>
			<tr>
				<td>이름:</td>
				<td><input type="text" name="memName" value=""></td>
			</tr>
			<tr>
				<td>전화번호:</td>
				<td><input type="text" name="memTel" value=""></td>
			</tr>
			<tr>
				<td>주소:</td>
				<td><textarea name="memAddr" ></textarea></td>
			</tr>
		</table>
		<input type="submit" value="회원 등록">
	</form>
</body>
</html>

회원등록 누르면 insert.do로 작성완료한 데이터를 post방식을 통해 전달하게 했다

아하! req가 get방식으로와서 jsp파일을 열게 만들고, jsp에서 작성한 form이 자동으로 getPost로 가서 처리하도록 만든거구나!

다음 내용을 추가하고

@WebServlet("/member/insert.do")
public class InsertMemberController extends HttpServlet{

	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.getRequestDispatcher("/view/member/insertForm.jsp").forward(req, resp);
	}
	
	
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 1. 요청파라미터 정보 가져오기
		String memId = **req.getParameter("memId");**
		String memName= req.getParameter("memName");
		String memTel = req.getParameter("memTel");
		String memAddr = req.getParameter("memAddr");
		
		// 2. 서비스 객체 생성하기
		IMemberService memService = MemberServiceImpl.getInstance();
		
		// 3. 회원정보 등록
		MemberVO mv = new MemberVO();
		mv.setMemId(memId);
		mv.setMemName(memName);
		mv.setMemTel(memTel);
		mv.setMemAddr(memAddr);
		
		int cnt = memService.insertMember(mv);
		
		String msg = "";
		
		if(cnt>0) {
			msg = "성공";
		} else {
			msg="실패";
		}
		
		req.getRequestDispatcher("/member/list.do").forward(req, resp);
		
		
	}
}

JSP의 form에 작성했던 내용이 req로 넘어왔기 때문에 req.getParameter()를 통해 그 내용을 꺼내서 String 형태로 저장한다. 이후 서비스 객체를 생성해 insertMember() 메소드를 불러와서 입력 데이터를 VO에 담은것을 넣어줄거임. 그러고 마지막에 list로 되돌아가도록 포워딩해준다!

접속결과

실행해서 등록폼 작성하여 제출하면 다음과 같이 뜬다!

Untitled

Forward 대신 Redirect 이용하기

이번엔 포워드방식 말고 리다이렉트 해보자

위에서 사용했던 포워드는 읽어보면 알다시피 모든 정보를 req에서 가져왔는데,

리다이렉트는 resp에서 가져온다

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 1. 요청파라미터 정보 가져오기
		String memId = req.getParameter("memId");
		String memName= req.getParameter("memName");
		String memTel = req.getParameter("memTel");
		String memAddr = req.getParameter("memAddr");
		
		// 2. 서비스 객체 생성하기
		IMemberService memService = MemberServiceImpl.getInstance();
		
		// 3. 회원정보 등록
		MemberVO mv = new MemberVO();
		mv.setMemId(memId);
		mv.setMemName(memName);
		mv.setMemTel(memTel);
		mv.setMemAddr(memAddr);
		
		int cnt = memService.insertMember(mv);
		
		String msg = "";
		
		if(cnt>0) {
			msg = "성공";
		} else {
			msg="실패";
		}
		
		//req.getRequestDispatcher("/member/list.do").forward(req, resp);
		// 앞에 플젝네임을 만들어줄게 이거 안만들면 링크에서 안생겨서 404에러뜸
		**String redirectUrl = req.getContextPath()+"member/list.do";
		resp.sendRedirect(redirectUrl);**

엄청 느림주의 << 트랜잭션 처리 고쳐줘야됨

  • 트랜잭션 처리 스타트와 엔드사이에 커밋이 있는데 중간에 오류가 생기면 롤백시켜버린다(?) end를 기다려주던거라 느렸던거였음 timeout해서 반환한거라... 둘중하나로 처리해줘야됨
    @Override
    	public int insertMember(MemberVO mv) {
    		int cnt  = 0;
    		try {
    			smc.startTransaction();//트랜잭션 시작
    			cnt = memDAO.insertMember(smc, mv);
    			smc.commitTransaction(); // 커밋...
    			**smc.endTransaction(); // 트랜잭션 끝**
    		} catch (SQLException e) {
    			try {
    				smc.endTransaction(); //롤백
    			} catch (SQLException e1) {
    				e1.printStackTrace();
    			} 
    		} 
    		
    		return cnt;
    	}
    @Override
    	public int insertMember(MemberVO mv) {
    		int cnt  = 0;
    		try {
    			smc.startTransaction();//트랜잭션 시작
    			cnt = memDAO.insertMember(smc, mv);
    			smc.commitTransaction(); // 커밋...
    
    		} catch (SQLException e) {
    			try {
    				smc.endTransaction(); //롤백
    			} catch (SQLException e1) {
    				e1.printStackTrace();
    			} **finally {
    				try {
    					smc.endTransaction();
    				} catch (SQLException e1) {
    					e1.printStackTrace();// 트랜잭션 끝
    				}** 
    			}
    		} 
    		
    		return cnt;
    	}
    @Override
    	public int insertMember(MemberVO mv) {
    		int cnt  = 0;
    		try {
    			smc.startTransaction();//트랜잭션 시작
    			cnt = memDAO.insertMember(smc, mv);
    			smc.commitTransaction(); // 커밋...
    
    		} catch (SQLException e) {
    				e.printStackTrace();
    			} **finally {
    				try {
    					smc.endTransaction();
    				} catch (SQLException e1) {
    					e1.printStackTrace();// 트랜잭션 끝
    				}** 
    			}
    		return cnt;
    	}

Untitled

응답메세지 (statuscode)가 302인 경우, 즉 send resirect 한 경우 resp헤더의 location에서 경로 찾아서 브라우저가 다시 요청... 이 예제의 경우 /ServletExam/member/list.dao

그래서 f12켜서 네트워크보면 요청이 두번 날라감. insert.dao와 list.dao

Redirect vs Foward

  • 브라우저 입장에서는 요청이 두번가냐(리다이렉트) 한번가냐(포워드) 차이인것!

Foward - 클라와 상관 없음, 서버단에서 정보를 전달할때 사용하는게 포워드

즉 리스폰스 하기 전까지는 계속 포워드 (화면그리는건 JSP가! - 컨트롤러 보다는 뷰가 구현하는게 맞으니까 포워드를 통해 전달한것. )

Redirect - 사용자로 하여금 새로운 요청으로 다시 요청하게함! 따라서 목적이 다른것. 요청 url의 변화.. 즉 요청이 두번감! (statusCode : 302) 라고 Http resp가 보내지고, http의 헤더부의 location을 찾아서 반환을 한다.

(insert에서 리다이렉트를 쓴건 사용자로 하여금 목록정보를 다시 요청하게끔 하고 싶어서 쓴거임. 나는 한번 요청했지만 실제론 두번 요청한것과 같은 상황. insert.do를 요청했는데 최종 화면 반환은 list.do가 된다. )

insert시 리다이렉트 한다면 302 찍히고 location으로 list.do 확인해서 그 정보를 url에 쓰고 엔터친것처럼 동작! 즉 인서트 했을뿐인데 두번 동작하는것처럼 동작

필터 - 인코딩

public class CharacterEncodingFilter implements Filter {	

	private String encoding; //인코딩정보
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("인코딩 설정 정보"+ encoding);
		req.setCharacterEncoding(encoding);
		resp.setCharacterEncoding(encoding);
		
		chain.doFilter(req, resp);
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		if(filterConfig.getInitParameter("encoding") == null) {
			this.encoding = "UTF-8";
		} else {
			this.encoding = filterConfig.getInitParameter("encoding");
		}
	}

}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>ServletExam</display-name>

	
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>kr.or.ddit.util.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>
</web-app>

Untitled

이제 인서트한 회원정보도 한글로 제대로 뜬다!

insert를 해봤으니 update, delete, 파일upload도 해보자

insert에 비해 update에서 달라지는점?

  • 처음 뷰에서 기존정보를 가져와서 보여줘야됨! 보고 수정할수있도록!

회원정보 수정

엇 근데 원래 코드에 getMember하는 메소드가 없어서 일단 추가

IMemberDAO

public interface IMemberDAO >> 메소드 추가!!
/**
	 * 주어진 회원ID 이용하여 회원정보 조회하는 메소드
	 * @param smc
	 * @param memId
	 * @return 조회된 회원정보를 담은 VO객체
	 */
	public MemberVO getMember(SqlMapClient smc, String memId);

MemberDaoImpl

MemberDaoImpl implements IMemberDAO >> 메소드 추가!!
@Override
	public MemberVO getMember(SqlMapClient smc, String memId) {
		
		MemberVO mv = null;
		
		try {
					
				mv = (MemberVO) smc.queryForObject("member.getMember",memId);

				} catch (SQLException ex) {
					ex.printStackTrace();
					throw new RuntimeException("회원정보 조회중 예외 발생!",ex);
				}
		
		return mv;
	}

IMemberService

public interface IMemberService >> 메소드 추가!!
@Override
/**
	 * 회원ID로 해당 회원 정보 조회
	 * @param memId
	 * @return
	 */
	public MemberVO getMember(String memId);

MemberServiceImpl

public class MemberServiceImpl implements IMemberService >> 메소드 추가!!
@Override
	public MemberVO getMember(String memId) {
		return memDAO.getMember(smc, memId);
	}

UpdateMemberController extends HttpServlet

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.or.ddit.member.service.IMemberService;
import kr.or.ddit.member.service.MemberServiceImpl;
import kr.or.ddit.member.vo.MemberVO;

@WebServlet("/member/update.do")
public class UpdateMemberController extends HttpServlet{

	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		String memId = req.getParameter("memId");
		
		// 1. 서비스 객체 생성하기
		IMemberService memService = MemberServiceImpl.getInstance();
		
		// 2. 회원정보 조회
		MemberVO mv = memService.getMember(memId);
		
		req.setAttribute("mv", mv);
		
		req.getRequestDispatcher("/view/member/updateForm.jsp").forward(req, resp);
		
	}

updateForm.jsp

<%@page import="kr.or.ddit.member.vo.MemberVO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	MemberVO mv = (MemberVO) request.getAttribute("mv"); 
//getPatameter()는 사용자가 던져준거니까 쓰면 안돼. 저장해둔 mv 쓰는거니까 getAttribute()
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원정보 변경</title>
</head>
<body>
	<form action="update.do" method="post">
	<input type="hidden" name="memId" value="<%=mv.getMemId() %>"> 
		**<!-- submit했을때 id도 form에 실려 같이갈수 있게 히든으로 input해준다 -->**
		<table>
			<tr>
				<td>I D:</td>
				<td><%=mv.getMemId() %></td>
			</tr>
			<tr>
				<td>이름:</td>
				<td><input type="text" name="memName" value="<%=mv.getMemName()%>"></td>
			</tr>
			<tr>
				<td>전화번호:</td>
				<td><input type="text" name="memTel" value="<%=mv.getMemTel()%>"></td>
			</tr>
			<tr>
				<td>주소:</td>
				<td><textarea name="memAddr" ><%=mv.getMemAddr()%></textarea></td>
			</tr>
		</table>
		<input type="submit" value="회원정보 수정">

	</form>
</body>
</html>

UpdateMemberController extends HttpServlet

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 1. 요청파라미터 정보 가져오기
		String memId = req.getParameter("memId");
		String memName= req.getParameter("memName");
		String memTel = req.getParameter("memTel");
		String memAddr = req.getParameter("memAddr");
		
		// 2. 서비스 객체 생성하기
		IMemberService memService = MemberServiceImpl.getInstance();
		
		// 3. 회원정보 변경
		MemberVO mv = new MemberVO();
		mv.setMemId(memId);
		mv.setMemName(memName);
		mv.setMemTel(memTel);
		mv.setMemAddr(memAddr);
		
		int cnt = memService.updateMember(mv);
		
		String msg = "";
		
		if(cnt>0) {
			msg = "성공";
		} else {
			msg="실패";
		}
		
		//req.getRequestDispatcher("/member/list.do").forward(req, resp);
		// 앞에 플젝네임을 만들어줄게 이거 안만들면 링크에 플젝네임이 안생겨서 404에러뜸..
		String redirectUrl = req.getContextPath()+"/member/list.do";
		resp.sendRedirect(redirectUrl);
		
		
	}
}

http://localhost/ServletExam/member/update.do?memId=a001 << ID포함하여 접속

Untitled

Untitled

업데이트 잘된다!

회원정보 삭제

상세보기를 한다 = 회원 아이디를 제공받는다 = 회원정보를 던져줬다고 가정하고 진행

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.or.ddit.member.service.IMemberService;
import kr.or.ddit.member.service.MemberServiceImpl;
import kr.or.ddit.member.vo.MemberVO;

@WebServlet("/member/detail.do")
public class DetailMemberController extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		String memId = req.getParameter("memId");
		
		// 1. 서비스 객체 생성하기
		IMemberService memService = MemberServiceImpl.getInstance();
		
		// 2. 회원정보 조회
		MemberVO mv = memService.getMember(memId);
		
		req.setAttribute("mv", mv);
		
		req.getRequestDispatcher("/view/member/detail.jsp").forward(req, resp);
		
		
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp); //상세는 겟이나 포스트나,... 비슷하니까 겟에 해볼게
	} 

}

detail.jsp

<%@page import="kr.or.ddit.member.vo.MemberVO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	MemberVO mv = (MemberVO) request.getAttribute("mv");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 정보 상세</title>
</head>
<body>
	<table border="1">
		<tr>
			<td>I D:</td>
			<td><%=mv.getMemId() %></td>
		</tr>
		<tr>
			<td>이름:</td>
			<td><%=mv.getMemName() %></td>
		</tr>
		<tr>
			<td>전화번호:</td>
			<td><%=mv.getMemTel() %></td>
		</tr>
		<tr>
			<td>주소:</td>
			<td><%=mv.getMemAddr() %></td>
		</tr>
		<tr>
			<td colspan="2">
			<a href="list.do">[목록]</a>
			<a href="update.do?memId=<%=mv.getMemId() %>">[회원정보 수정]</a>
			<a href="delete.do?memId=<%=mv.getMemId() %>">[회원정보 삭제]</a>
			</td>
		</tr>
	</table>
</body>
</html>

list.jsp

list.jsp에서 링크를 걸어 바로 삭제 들갈 수 있게도 할수있다!
	<tr>
		<td><%=memList.get(i).getMemId() %></td>
		<td><a href="detail.do?memId=<%=memList.get(i).getMemId() %>"><%=memList.get(i).getMemName() %></a></td>
		<td><%=memList.get(i).getMemTel() %></td>
		<td><%=memList.get(i).getMemAddr() %></td>
	</tr>

DeleteMemberController extends HttpServlet

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.or.ddit.member.service.IMemberService;
import kr.or.ddit.member.service.MemberServiceImpl;

@WebServlet("/member/delete.do")
public class DeleteMemberController extends HttpServlet {
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		String memId = req.getParameter("memId");
		
		// 1.서비스객체 생성
		IMemberService memService = MemberServiceImpl.getInstance();
		
		// 2.삭제
		int cnt = memService.deleteMember(memId);
		
		String msg = "";
		
		if(cnt>0) {
			msg = "성공";
		} else {
			msg="실패";
		}
		
		req.setAttribute("msg", msg);
		
		String redirectUrl = req.getContextPath()+"/member/list.do";
		resp.sendRedirect(redirectUrl);
	}
	
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
	}

}

Untitled

Untitled

알림띄우기 - req라고 다 같은 객체는 아니다

동적인 페이지를 만들어보자! JSP 만져서 알림 띄워보자고

💡 JSP에서 자바로 뚝딱대는건 백엔드상, 즉 톰캣상에서 돌아가고 있는거임! resp를 타고 올라가야 브라우저상에서 뜨는것임을 잊지 말자

list JSP

<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="kr.or.ddit.member.vo.MemberVO"%>

<%
	List<MemberVO> memList = (List<MemberVO>)request.getAttribute("memList");

	String msg = request.getAttribute("msg")==null ? "" : (String) request.getAttribute("msg");
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원목록</title>
</head>
<body>
	<table border="1">
		<tr>
			<th>ID</th>
			<th>이름</th>
			<th>전화번호</th>
			<th>주소</th>
		</tr>
		
		<%
			int memSize = memList.size();
			if(memSize>0){
				for(int i = 0; i<memSize; i++) {
		%>
		
		<tr>
			<td><%=memList.get(i).getMemId() %></td>
			<td><a href="detail.do?memId=<%=memList.get(i).getMemId() %>"><%=memList.get(i).getMemName() %></a></td>
			<td><%=memList.get(i).getMemTel() %></td>
			<td><%=memList.get(i).getMemAddr() %></td>
		</tr>
		
		<%
				}
			} else{
		%>
		
			<tr>
				<td colspan = "4">회원정보가 없습니다.</td>
			</tr>
			
		<% } %>
		
	<tr align="center">
		<!-- 상대경로로 표현 -->
		<td colspan="4"><a href="insert.do">[회원 등록]</a></td>
	</tr>

	</table>

**<% if(msg.equals("성공")) { %>
	<script>
		alert('정상적으로 처리되었습니다');
	</script>
<% } %>**
</body>
</html>

but 알람 안뜨고 html에도 스크립트가 안보임

Untitled

⇒ 서블릿에서의 req와 getAttribute의 req는 list.do를 요청했을때 만들어진 새로운 req객체임. 따라서 성공이 아니라 알람이 안뜨는것이다

따라서 세션을 이용해서 처리해준다!

DeleteMemberController extends HttpServlet - 세션 이용하기

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import kr.or.ddit.member.service.IMemberService;
import kr.or.ddit.member.service.MemberServiceImpl;

@WebServlet("/member/delete.do")
public class DeleteMemberController extends HttpServlet {
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		String memId = req.getParameter("memId");
		
		// 1.서비스객체 생성
		IMemberService memService = MemberServiceImpl.getInstance();
		
		// 2.삭제
		int cnt = memService.deleteMember(memId);
		
		String msg = "";
		
		if(cnt>0) {
			msg = "성공";
		} else {
			msg="실패";
		}
		
		//req.setAttribute("msg", msg);
		// 세션은 연결끝날때까지 유지
		**HttpSession session = req.getSession();
		session.setAttribute("msg", msg);**
		
		String redirectUrl = req.getContextPath()+"/member/list.do";
		resp.sendRedirect(redirectUrl);
	}

JSP

<%
	List<MemberVO> memList = (List<MemberVO>)request.getAttribute("memList");

	**String msg = session.getAttribute("msg")==null ? "" : (String) session.getAttribute("msg");**
%>

<!DOCTYPE html>

Untitled

근데이제 list.do에 접속만 해도 자꾸 정상적으로 처리됐다고 뜸!

⇒ 세션이니까 한번 만들면 계속있는거,.. 그래서 꺼낸다음에 없애줄거임

JSP

<%
	List<MemberVO> memList = (List<MemberVO>)request.getAttribute("memList");

	String msg = session.getAttribute("msg")==null ? "" : (String) session.getAttribute("msg");
	
	**session.removeAttribute("msg"); //꺼내온 메세지 속성 제거하기**
%>

이렇게 처리해주면 된다

Redirect에서 주의하자 서로다른 req객체를 쓰고 그 둘을 공유할 수없다!

파일업로드 기능 만들어보기

두가지 방법이 있다.

  • 아파치 파일업로드 모듈
  • 서블릿3.0이상에서 업로드 기능 제공

Untitled

commons 두개랑 jsp파일 추가해두고

http://localhost/ServletExam/upload.jsp << 접속

Untitled

지금은 파일을 업로드해 전송하면 404에러가 뜬다 >> 서블릿처리를 해주자!

JSP파일

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

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>File Upload 예제</title>
</head>

<body>
   <h3>아파치 자카르타 프로젝트의 fileupload 모듈을 이용한 파일업로드</h3>
    <form method="post" action="upload2" enctype="multipart/form-data">
        파일선택: <input type="file" name="uploadFile" multiple="multiple"/>
        전송자: <input type="text" name="sender">
        <input type="submit" value="Upload"/>

    </form>
    
    <hr>
    
    <h3>서블릿3부터 지원하는 Part 인터페이스를 이용한 파일업로드</h3>
    <form method="post" action="upload3" enctype="multipart/form-data">
        파일선택: <input type="file" name="multiPartServlet"/>
        전송자: <input type="text" name="sender">
        <input type="submit" value="Upload"/>
    </form>
</body>
</html>
  • 파일업로드에서 메소드방식은 무조건 POST
  • enctype에다가 인코딩설정 필요하다! 무조건 “multipart/form-data” (필드데이터나 첨부값이 전부 body에 들어가서 헷갈리고 어려움,(HTTP는 리퀘스트라인 - 헤더 - 엠티라인 - 바디로 나뉜다) 그래서 파트별로 나눠버렸음 → multipart/form-data 라고 부른다!
  • 멀티파트로 보냈다고 가정하고, 서블릿에서 그걸 이해하고 잘라서 파싱해야함 근데 셀프로 하긴 어렵다 ⇒ 아파치에서 모듈 만들어줬음! 얘끼 파싱해서 원하는 데이터를 뽑아올수있게 해준다

Untitled

아래가 서블릿 자체제공인듯? 위에거 쓸거임

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@WebServlet("/fileupload.do")
public class FileUploadServlet extends HttpServlet{
	
	private static final String UPLOAD_DIR = "upload_files";
	// 메모리 임계크기 (이 크기가 넘어가면 래파지토리 위치에 임시파일로 저장됨)
	private static final int MEMORYTHRESHOLD = 1024*1024*3;
	// 파일한개당 최대크기
	private static final long MAX_FILE_SIZE = 1024*1024*40; //40MB
	// 요청파일 최대크기
	private static final long MAX_REQUEST_SIZE = 1024*1024*50;
	
	// doget은 만들 가치도없음ㅋ
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		// 멀티파트 파싱 전 파라미터값 가져와보기 - sender는 html에서 전송자 id로 준값
		System.out.println("파싱 전 => "+req.getParameter("sender"));
		
		if(ServletFileUpload.isMultipartContent(req)) { // 멀티파트여부 체크
			
			Map<String,String> formFieldMap = new HashMap<String, String>(); // 폼 필드값 저장용
			
			DiskFileItemFactory factory = new DiskFileItemFactory();
			factory.setSizeThreshold(MEMORYTHRESHOLD);
			factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
			System.out.println("java.io.tmpdir => " + System.getProperty("java.io.tmpdir"));
			
			ServletFileUpload upload = new ServletFileUpload(factory);
			upload.setFileSizeMax(MAX_FILE_SIZE);
			upload.setSizeMax(MAX_REQUEST_SIZE);
			
			// 웹애플리케이션 루트 디렉토리 기준 업로드 경로 설정하기
			
			String uploadPath = req.getServletContext().getRealPath("/")
									+ File.separator + UPLOAD_DIR;
			File uploadDir = new File(uploadPath);
			
			if(!uploadDir.exists()) {
				uploadDir.mkdir();
			}
			// 멀티파트를 하나하나 파싱 시작
			try {
				List<FileItem> formItems = upload.parseRequest(req);
				
				if(formItems != null && formItems.size() > 0) {
					for(FileItem item : formItems) {
						if(!item.isFormField()) { //파일인경우
							String fileName = item.getName();
							String filePath = uploadPath + File.separator + fileName;
							File storeFile = new File(filePath);
							item.write(storeFile); //업로드 파일 저장
							System.out.println("업로드 완료됨. 파일명 : "+fileName);
						}else { // 폼필드인 경우
							//폼필드의 값이 한글인 경우에는 해당 문자열을 적절히 변환해주어야한다
							formFieldMap.put(item.getFieldName(), item.getString("UTF-8"));
						}
					}
				}
				
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			for(Entry<String, String> entry: formFieldMap.entrySet()) {
				System.out.println("파라미터명: "+entry.getKey());
				System.out.println("파라미터값: "+entry.getValue());
			}
		}
		resp.setContentType("text/html");
		resp.getWriter().print("업로드 완료");
	}

	
}

톰캣입장에서 서버 메모리는 무한하지 않음, 따라서 어느정도 이상이면 다른 프로그램이 쓸 메모리가 없어지므로 임시파일로 떨궈놔야 된다.. 그래서 임계크기 MEMORYTHRESHOLD를 만들었다

파일 업로드를 여러개 할 수도 있다. 그럼 하나의 req에 최대 몇개를 수용하는 사이즈를 할지...

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

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>File Upload 예제</title>
</head>

<body>
   <h3>아파치 자카르타 프로젝트의 fileupload 모듈을 이용한 파일업로드</h3>
    **<form method="post" action="<%=request.getContextPath() %>/fileupload.do" enctype="multipart/form-data">**
<!--     action 설정시 action="/ServletExam/fileupload.do" 밀고 위경로로 할수있으면 좋음! -->
        파일선택: <input type="file" name="uploadFile" multiple="multiple"/>
        전송자: <input type="text" name="sender">
        <input type="submit" value="Upload"/>

    </form>
    

    <hr>
    
    

    <h3>서블릿3부터 지원하는 Part 인터페이스를 이용한 파일업로드</h3>
    <form method="post" action="upload3" enctype="multipart/form-data">
        파일선택: <input type="file" name="multiPartServlet"/>
        전송자: <input type="text" name="sender">
        <input type="submit" value="Upload"/>
    </form>
</body>
</html>

http://localhost/ServletExam/upload.jsp << 에서 첨부하고 제출!

Untitled

Untitled

Untitled

멀티파트!

컴파일 결과가 배포되는 위치는

Untitled

경로로 가보면

Untitled

이렇게 파일이 업로도 되고 있음을 확인 할 수 있다.

파일도 들어갈 수 있고 필드값도 들어갈 수 있으니까 body 에서 구분자를 정해 서로 구분 할 수 있도록 한다! = multipart/form-data


dopost 써놓은거 주석처리 후 다음 코드 삽입

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("===================================");
		BufferedReader br = new BufferedReader(
				// 문자를 하나하나 읽어
				new InputStreamReader(req.getInputStream()));
				
		String readLine = "";
		
		// req의 body를 읽어보자
		while((readLine = br.readLine())!=null) {
			System.out.println(readLine);
		}
		System.out.println("===================================");

서버 실행해 파일 여러개 첨부해서 다시실행하면

읽어오면 헤더 / 공백 / 바디가 오는걸 확인 할 수 있다

form필드와 file 보낼때 차이점 : 헤더가 다름... 첨부파일 드갈땐 filename이 붙고 filename이 없으면 sender 즉 필드명이 붙는다

만약 파일 안보내고 이름만 작성해 보내면 filename=”” (empty String) 바디는 비어있다.


파일 업로드 모듈말고 part 인터페이스 이용해서 해보자

서블릿 3.0 이상에서 지원해주는 part!

서블릿3 부터 지원하는 Part인터페이스를 이용한 파일업로드 예제

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

public class FileloadServlet2 extends HttpServlet{
	
	private static final String UPLOAD_DIR = "upload_files";
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		String uploadPath = getServletContext().getRealPath("/")
							+ File.separator + UPLOAD_DIR;
		
		File uploadDir = new File(uploadPath);
		
		if(! uploadDir.exists()) { //업로드 경로 존재하지 않으면
			uploadDir.mkdir();
		}
		
		try {
			String fileName = "";
			
			for(Part part : req.getParts()) {
				System.out.println(part.getHeader("content-disposition"));
				
				fileName = getFileName(part);
				if(fileName != null && fileName.equals("")) {
					// 폼필드가 아니거나 파일이 첨부된경우
					
					// 파일 저장
					part.write(uploadPath + File.separator + fileName);
					System.out.println("파일명 : "+fileName+"업로드 완료");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("파라미터값 : "+req.getParameter("sender"));
		
		resp.setContentType("text/html");
		resp.setCharacterEncoding("utf-8");
		resp.getWriter().print("업로드완료");
	}

}

이제 getFileName메소드를 추가해보자!

getFileName(Part part)

Content-Disposotion에 대하여

1. 응답헤더에 사용되는 경우 (ex.파일 다운로드)
- Content-Disposition: inline (default)
- Content-Disposition: attachment // 파일다운로드
- Content-Disposition: attachment; filename = "a.jpg" // a.jpg이름으로 다운로드
1. multipart body를 위한 헤더정보로 사용되는 경우 ex) 파일업로드
- Content-Disposition : form-data
- Content-Disposition : form=data; name="fieldName"
- Content-Disposition : form-data; name="fieldName"; filename="a.jpg"
import java.io.File;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

/**
 * 서블릿3 부터 지원하는 Part인터페이스를 이용한 파일업로드 예제
 * @author 306-02
 *
 */

@MultipartConfig(fileSizeThreshold = 1024*1024*3, maxFileSize=1024*1024_40, 
maxRequestSize=1024*1024*50) 
// -> 이거 없으면 java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided 오류!
@WebServlet("/fileupload2.do")
public class FileUploadServlet2 extends HttpServlet{
	
	private static final String UPLOAD_DIR = "upload_files";
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		String uploadPath = getServletContext().getRealPath("/")
							+ File.separator + UPLOAD_DIR;
		
		File uploadDir = new File(uploadPath);
		
		if(! uploadDir.exists()) { //업로드 경로 존재하지 않으면
			uploadDir.mkdir();
		}
		
		try {
			String fileName = "";
			
			for(Part part : req.getParts()) {
				System.out.println(part.getHeader("content-disposition"));
				
				fileName = getFileName(part);
				if(fileName != null && !fileName.equals("")) {
					// 폼필드가 아니거나 파일이 첨부된경우
					
					// 파일 저장
					part.write(uploadPath + File.separator + fileName);
					System.out.println("파일명 : "+fileName+"업로드 완료");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("파라미터값 : "+req.getParameter("sender"));
		
		resp.setContentType("text/html");
		resp.setCharacterEncoding("utf-8");
		resp.getWriter().print("업로드완료");
	}

	/**
	 * 객체를 파싱하여 파일이름 추출하기
	 * @param part
	 * @return 파일명 : 파일명이 존재하지 않으면 널값 리턴함(폼필드인 경우)
	 */
	private String getFileName(Part part) {

		
		for(String content : part.getHeader("Content-Disposition").split(";")) {
			if(content.trim().startsWith("filename")) {
				return content.substring(content.indexOf("=")+1).trim().replace("\"", "");
			}
		}
		
		return null;
	}

}
<h3>서블릿3부터 지원하는 Part 인터페이스를 이용한 파일업로드</h3>
    <form method="post" action="<%=request.getContextPath() %>/fileupload2.do" enctype="multipart/form-data">
        파일선택: <input type="file" name="multiPartServlet"/>
        전송자: <input type="text" name="sender">
        <input type="submit" value="Upload"/>
    </form>

Untitled

얏호

0개의 댓글