JSP

부트캠프50일차(Model2 : mail , id pw search , password수정 , pictureForm)

동곤일상 2025. 4. 14. 17:09
반응형

 

1) mailForm

2)mailSend를 위한작업

3)비밀번호수정 password

4)아이디찾기 비밀번호찾기 id , pw

5) 사진등록 picutreForm

 


1) mailForm

<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>

layout.jsp에 head부분script에 넣어줬음 ( 메일폼을 위해)

 

webapp\view\member\mailForm.jsp

(그냥구글비번이 아닌 앱비밀번호(2차인증)으로 로그인하자!!!!)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript">
function inputchk(f) {
	if(f.googleid.value==""){
		alert("구글아이디입력바람");
		f.googleid.focus();
		return false;
	}	
	if(f.googlepw.value==""){
	alert("구글비번을 입력하세요")
	f.googlepw.focus();
	return false;
	}
	return true;
}
</script>

<title>메일작성</title>
</head>
<body>
<div class="container"></div>
<h2 id="center">메일보내기</h2>
<form action="mailSend" method="post" name="form1" onsubmit="return inputchk(this)">
<table class="table">
<tr><td>보내는사람</td>
<td>본인구글ID:<input type="text" name="googleid" class="form-control" value="ddkk8525">
	본인구글PW:<input type="password" name="googlepw" class="form-control" value="muefnfldrbqlbfez"></td>
</tr>
<tr><td>받는사람</td>
	<td><input type="text" name="recipient" class="form-control" 
value="<c:forEach items="${list}" var="m">${m.name} &lt;${m.email}&gt;</c:forEach>">
<%-- name <email> 의 형태로 check된member가 나열될거임 --%>
	</td></tr>
<tr><td>제목</td>
	<td><input type="text" name=title class="form-control"></td>
</tr>
<tr><td>메시지형식</td>
	<td><select name="mtype" class="form-control">
		<option value="text/html;charset=UTF-8">HTML
		<option value="text/plain;charset=UTF-8">TEXT
	<!-- plane : 순수한 text파일이라는뜻(태그인식X) -->
	</select></td>
</tr>
<tr><td colspan="2">
내용:<textarea name="content" rows="10" cols="40" class="form-control"></textarea></td></tr>
<tr><td colspan="2" id="center">
	<button type="submit" class="btn btn-primary">전송</button></td></tr>
</table>
</form>

</body>
</html>

 

 

 

MemberDto 에 emailList 메서드

public List<Member> emailList(String[] ids) {
		//ids : 선택한 아이디목록 "[test1 test2]"
		Connection conn = DBConnection.getConnection();
		PreparedStatement psmt = null;
		ResultSet rs = null;
		ArrayList<Member> list = new ArrayList<Member>();
		StringBuilder sb = new StringBuilder();
		
		for (int i = 0; i < ids.length; i++) {
			sb.append("'"+ids[i]+((i<ids.length -1)?"',":"'"));
            //마지막인덱스라면 , 를안찍음(sql에넣기위함)
		}//sb = 'test1','test2'....
		String sql = "select * from member where id in("+ sb.toString()+")";
							//sb를 String으로변경 id in('id1' , 'id2'..)
		try {
			psmt = conn.prepareStatement(sql);
			rs = psmt.executeQuery();
			while(rs.next()) {
				Member m = new Member();
				m.setId(rs.getString("id"));
				m.setName(rs.getString("name"));
				m.setPass(rs.getString("pass"));
				m.setGender(rs.getInt("gender"));
				m.setEmail(rs.getString("email"));
				m.setTel(rs.getString("tel"));
				m.setPicture(rs.getString("picture"));
				list.add(m);
			}
			return list;
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			DBConnection.close(conn, psmt, rs);
		}
		return null;
	}

MemberController 의 mailForm매핑(선택된 아이디의 객체를 속성으로지정해준후 mailForm이동)

@RequestMapping("mailForm")
@MSLogin("loginAdminCheck") //관리자만가능
	public String  mailForm(HttpServletRequest request, HttpServletResponse response) {
		//관리자로 로그인시에만 실행
		String[] ids = request.getParameterValues("idchk");//해당파라미터의 값들을 배열로리턴
		System.out.println(Arrays.toString(ids));
		List<Member> list = dto.emailList(ids); 
		System.out.println(list);
		request.setAttribute("list", list); 
		return "member/mailForm"; 
	}


2) mailSend를 위한 작업들

 

구글 smtp서버 이용해 메일전송하기

 1.구글계정에 접속해 2단계 로그인설정하기

2.앱비밀번호 생성

3.생성된 앱 비번을 메모장을 이용해저장하기

 4. mail.properties 파일 /web-inf/에 만들기

5. 라이브러리 가져오기

 

 

gmail로 보내놨음 폰메모장에도있음


mail-1.4.7.jar
0.50MB
activation-1.1.1.jar
0.07MB
web-inf / lib 에 넣자

 

 

/webapp\WEB-INF\mail.properties

# gmail !!!
#smtp : 이메일을 주고받기 위해 사용되는 인터넷 표준 프로토콜 
mail.smtp.host=smtp.gmail.com
mail.smtp.starttls.enable=true
mail.debug=true
mail.smtp.auth=true
mail.smtp.port=587
mail.smtp.ssl.protocols=TLSv1.2

공백조심해!!!!

 

 

Cotroller에 MyAtuthenticator 생성 (id pw를 이용한 사용자인증 이라고생각해두자)

//사용자 이름과 비밀번호를 저장하고, Session 객체가 이를 활용하여 
	//안전하게 이메일 서버에 연결할 수 있도록 합니다
	public final class MyAuthenticator extends Authenticator{
		private String id;
		private String pw;
		public MyAuthenticator(String id, String pw) {
			this.id = id;
			this.pw = pw;
		}
		protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
			return new javax.mail.PasswordAuthentication(id, pw);
		}
	}

 

Controller의 mailSend 메서드

 ( mail부분에서 가장중요하다고보면 됨) 주석을 하나하나 다 읽어보자

@RequestMapping("mailSend")
	@MSLogin("loginAdminCheck") //관리자만가능
	public String  mailSend(HttpServletRequest request, HttpServletResponse response) {
		String sender = request.getParameter("googleid") + "@gmail.com";
        //작성자의아이디에 @gmail.com을붙임
		//앱비밀번호
		String passwd = request.getParameter("googlepw");
         //recipient : mem.name , mem.email 형식의 String
         //(선택한 아이디의 이름과 이메일만 들어있음)
		String recipient = request.getParameter("recipient");
		String title = request.getParameter("title");
		String mtype = request.getParameter("mtype");
		String result="메일전송실패";
		String content = request.getParameter("content");
		Properties prop = new Properties();//이메일전송위한 환경설정값
		try {
			String path = request.getServletContext().getRealPath("/") //내프로젝트의절대경로
					+"WEB-INF/mail.properties"; //해당파일사용
			FileInputStream fis = new FileInputStream(path); //파일을읽어
			prop.load(fis);//fis가 참조하는 파일의내용을 Properties객체의요소로저장
			prop.put("mail.smtp.user", sender);//전송하는 사람의 이메일주소
		}
		catch (Exception e) {
			e.printStackTrace();

		}
		//메일전송을 위한 사용자인증(연결)객체 
		MyAuthenticator auth = new MyAuthenticator(sender, passwd);
		//prop : 메일전송을위한 시스템환경설정 (mail.properties)
		//auth : 인증객체
		Session mailSession = Session.getInstance(prop,auth);

		//msg : 메일로전송되는 데이터객체
		MimeMessage msg = new MimeMessage(mailSession);
		//이메일주소들을 담을수있는 리스트
		ArrayList<InternetAddress> addrs = new ArrayList<InternetAddress>();
		try {
			//recipient는 name,email,name2,email2 형식의 String임.
			String[] emails = recipient.split(",");
			for (String email : emails) { //email : 이름 or email 
				try {
		//email.getBytes("UTF-8") : byte배열
		//8859_1 : 웹의 기본인코딩방식
   //addrs에는 이메일형식만 들어갈거야(이름은들어가지않음)
				addrs.add(new InternetAddress(
					new String(email.getBytes("UTF-8"),"8859_1")));
				}
				catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}
			InternetAddress[] address =  new InternetAddress[emails.length];
			for (int i = 0; i < addrs.size(); i++) {
            //setRecipients는 List를 받지못하고 배열만 받기때문!!
            //mail API는 오래되서그렇다!
				address[i] = addrs.get(i);
			}
			InternetAddress from = new InternetAddress(sender);
			msg.setFrom(from); //보내는사람의 이메일주소
            //address의 이메일에게 메일 보낸단 뜻
			msg.setRecipients(Message.RecipientType.TO, address);
			msg.setSubject(title);
			msg.setSentDate(new Date());
			msg.setText(content);
			//multipart : 내용,첨부파일1,.....
			MimeMultipart multipart = new MimeMultipart();
			MimeBodyPart body = new MimeBodyPart();
			body.setContent(content,mtype); //내용
			multipart.addBodyPart(body);
			msg.setContent(multipart);
			Transport.send(msg); //메일전송
			result = "메일전송완료";
		}
		catch (MessagingException e) {
			e.printStackTrace();
		}
		request.setAttribute("msg", result);
		request.setAttribute("url", "list");
		return "alert"; 
	}

 

테스트

(pw는 아까 발급받은 앱비밀번호16자리를 공백없이 해보자!)

 

HTML전송

 

 

3) 비밀번호수정 (info에서 시작됨)

 

/view/member/passwordForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>비번수정폼</title>
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
</head>
<body>
<h3>비밀번호변경</h3>
<form action="password" method="post" name="f" onsubmit="return input_check(this)">
<table class="table">
<tr><th>현재 비밀번호</th>
	<td><input type="password" name="pass" class="form-control"></td></tr>
<tr><th>변경 비밀번호</th>
	<td><input type="password" name="chgpass" class="form-control"></td></tr>
<tr><th>재입력</th>
	<td><input type="password" name="chgpass2" class="form-control"></td></tr>
<tr><td colspan="2" align="center">
	<input type="submit" value="비밀번호변경" class="btn btn-primary">
	<input type= "reset" value="초기화" class="btn btn-secondary"></td></tr>
</table>
</form>
<script type="text/javascript">
function input_check(f){
	if(f.chgpass.value != f.chgpass2.value){
		alert("변경할비밀번호 제대로 재입력하세요");
		f.chgpass2.value="";
		f.chgpass2.focus();
		return false;
	}
	return true;
}
</script>


</body>
</html>

 

 

로그인하지않고  접근 시 loginForm으로 보내버리는 함수

	public String passwordLoginCheck(HttpServletRequest request, HttpServletResponse response) {
		String login = (String)request.getSession().getAttribute("login");
		if(login == null || login.trim().equals("")){
			request.setAttribute("msg", "로그인하세요");
			request.setAttribute("url", "loginForm");
			return "alert";
		}
		return null;

	}

(null은 신경쓰지마 )

 

 

Controller의 passwordForm매핑

passwordLoginCheck함수를 이용해

로그인을 한 사람이 접근 시 passwordForm으로 정상적으로보내줌 

@RequestMapping("passwordForm")
	@MSLogin("passwordLoginCheck")
	public String passwordForm(HttpServletRequest request, HttpServletResponse response) {
		return "member/passwordForm";
	}

 

Controller의 password 메서드 (passwordForm에서 찾기버튼 누를 시 발생)

	@RequestMapping("password")//비밀번호변경부분
	@MSLogin("passwordLoginCheck")
	public String password(HttpServletRequest request, HttpServletResponse response) {
		String login = (String)request.getSession().getAttribute("login");
		String pass = request.getParameter("pass");//입력비번
		String chgpass = request.getParameter("chgpass");//변경비번
		Member mem = dto.selectOne(login); 
		//select * from member where id='login값'
		
		//입력한비밀번호와 DB상의비번이 같다면
		if(pass.equals(mem.getPass())) {
			if(dto.updatePass(login, chgpass)) {
				request.setAttribute("msg", "성공(새로운비번으로 로그인_");
				request.setAttribute("url", "logout");
				return "openerAlert";
			}
			else { // 비밀번호는 맞지만 DB내에서문제 생길 시 
				StringBuilder sb =new StringBuilder();
				sb.append("alert('비밀번호수정시오류가발생했습니다.')");
				request.setAttribute("script", sb.toString());
				return "dumy";
			}
		}else { //비밀번호를 틀렸을 시
			request.setAttribute("msg", "비밀번호가틀려요");
			request.setAttribute("url", "passwordForm");
			return "alert";
		}
		
		
	}

 

view / openAlert.jsp

(opener 의 경로를 바꿔준 후 

내 자신의 창을 닫는다)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<script>
alert("${msg}");
opener.location.href = "${url}";
self.close();
</script>

 

view / dumy

(script 속성만 호출하는 곳 (페이지가없음))

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

 


4)아이디찾기 비밀번호찾기 조금의수정(화면)

id찾기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
 
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<title>idForm(아이디찾기)</title>
</head>
<body>
<h3 align="center">아이디찾기</h3>
<form action="id" method="post" >
<table class="table">
<tr><th>이름</th><td><input type="text" name="name" class="form-control"></td></tr>
<tr><th>전화번호</th><td><input type="text" name="tel" class="form-control"></td></tr>
<tr><td colspan="2"><input type="submit" value="아이디찾기" class="btn btn-outline-info"></td></tr>
</table></form>
</body>
</html>

 

 

pw찾기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%-- /webapp/member/pwForm.jsp--%>    
<!DOCTYPE html>
<html>
<!-- 비밀번호찾기버튼 클릭시 유효성검사 실시 추가 -->
<head>
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<meta charset="UTF-8">
<title>비밀번호찾기</title>
</head><body><h3 align="center">비밀번호찾기</h3>
<form action="pw" method="post" onsubmit="return input_check(this)">
  <table class="table">
     <tr><th>아이디</th><td><input type="text" name="id" class="form-control"></td></tr>
     <tr><th>이메일</th><td><input type="text" name="email" class="form-control"></td></tr>
     <tr><th>전화번호</th><td><input type="text" name="tel" class="form-control"></td></tr>
     <tr><td colspan="2"><input type="submit" value="비밀번호찾기" class="btn btn-light"></td></tr>
     <!-- submit을 누르면 pw로 넘어간다 -->
  </table>	
</form></body>
<script>
function input_check(f){
	if(f.id.value.trim() == ""){
		alert("ID입력바람")
		return false;
	}
	else if(f.email.value.trim() == ""){
		alert("Email입력바람")
		return false;
	}
	else if(f.tel.value.trim() == ""){
		alert("전화번호입력바람")
		return false;
	}
	else if(!isValidEmail(f.email.value.trim())){
		alert("올바르지않은 이메일형식")
		f.email.focus()
		return false;
	}
	else if(!isValidTel(f.tel.value.trim())){
		alert("올바르지않은 전화번호형식")
		f.tel.focus()
		return false;
	}
	else{
		return true;
	}
	
	function isValidEmail(email){
		const regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9._]+\.[a-zA-Z]{2,}$/;
		return regex.test(email);
		/*
		   /^  .... $/ => 정규표현식 시작과 끝
		   [a-zA-Z0-9._%+-]+ : 대소문자 숫자 . - % + - 중  1개이상
		   @[a-zA-Z0-9._]+ : @ 문자뒤에 대소문자 숫자.  _ 중 한개이상
		   \. : .문자
		[a-zA-Z]{2,} : 대소문자 2개이상
		*/
	}
	
	
	function isValidTel(tel){
		const regex = /^(02|01[0126789])-?\d{3,4}-?\d{4}$/;
		return regex.test(tel);
/*
	(02|01[0126789])  : 02 or 010 011 ...019
	-?  : - 가 0 또는 1개
	\d{3,4}  : 숫자 3개or4개	
	\d{4} : 숫자4개
*/
	}
	
}
</script>
</html>

 

id , pw 의 Controller부분

@RequestMapping("id")
	public String id(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
		String name = request.getParameter("name");
		//name="name"인 파라미터를 가져와
		//charEncodingFilter를 만들어놨으므로 인코딩이필요없음
		String tel = request.getParameter("tel");
		String id = dto.idSearch(name, tel);
		//MemberDto에 가서 DB정보와비교해 가져온다
		if(id==null) {
			request.setAttribute("msg", "id를 찾을수없어요");
			request.setAttribute("id", id);
			return "idSearch";
		}
		else {
			request.setAttribute("msg", name+"님의 id : "+id.substring(0,id.length()-2)+"**");
			request.setAttribute("id", id);
			return "idSearch";
		}
	}

	@RequestMapping("pw")
	public String pw(HttpServletRequest request, HttpServletResponse response) {
		String id = request.getParameter("id");
		//name="name"인 파라미터를 가져와
		String email = request.getParameter("email");
		String tel = request.getParameter("tel");
		String pass = dto.pwSearch(id, tel, email);
		//MemberDto에 가서 DB정보와비교해 가져온다
		if(pass==null) {
			request.setAttribute("msg", "password를 찾을수없어요");
			request.setAttribute("pass", pass);
			return "pwSearch";
		}
		else {
			request.setAttribute("msg", id+"님의 password : "+pass.substring(0,pass.length()-2)+"**");
			request.setAttribute("pass", pass);
			return "pwSearch";
		}
	}

 

 

idSearch  ,  pwSearch

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<script>
alert("${msg}")
//requestScope.msg
opener.document.f.id.value = "${id}"
//requestScope.id
self.close();
</script>




<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<script>
alert("${requestScope.msg}")

opener.document.f.pass.value = "${requestScope.pass}"
//request영역의 속성인 msg , pass

self.close();
</script>

5)picture 수정 , 등록

/view/pictureForm.jsp(수정 or 등록하는곳)

수정 시 opener : updateForm

등록시 opener : joinForm

<%@ 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><img id="preview" src=""></td></tr>
<tr><td>
<!--  MIME 타입 :문서의 형식설정 문서유형/세부종류 text/html , img/jpeg , img/gif...
	accept = "img/*" img문서유형만 업로드한단 뜻
-->
<form action="picture" method="post" enctype="multipart/form-data"><!-- 파일을 보내기위함 -->
	<input type="file" name="picture" id="imageFile" accept="img/*">
	<input type="submit" value="사진등록">
</form></td></tr>
</table>

<script type="text/javascript">
let imagefile = document.querySelector('#imageFile');
let preview = document.querySelector('#preview');
//파일이('change') 바뀌었을 때 발생하는 이벤트
imagefile.addEventListener('change',function(e){
	//선택된파일을 담는 변수
	//e.target.files : 선택된파일들
	let get_file = e.target.files;
	let reader = new FileReader(); //파일을 읽기위한 스트림객체
	
	//reader객체에 파일이 로드되는경우 이벤트등록
	//Img매개변수 : preview객체를 저장
	//자바스크립트에서는 함수객체를 리턴할수있음
	reader.onload = (function(Img){
		//preview(이미지태그)를 매개변수로하는 함수호출
		return function(e){
			//e.target.result: 선택된파일의value값(파일명)
			Img.src = e.target.result;
		}
	})(preview); // Img = preview
	
	//get_file : 선택된파일이존재하는가?
	//reader.readAsDataURL(get_file[0]) :
	//첫번쨰선택된 파일을 reader로 읽기
	if(get_file){reader.readAsDataURL(get_file[0]);}
});
</script>

</body>
</html>

 

 

(submit하면 넘어가는)Picutre Controller

C:\java\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\model2Study\picture

해당경로에 업로드되고

해당경로에서 사진을 가져오게될것임!!!!!

	@RequestMapping("picture")
	public String picture(HttpServletRequest request, HttpServletResponse response) throws IOException {
		String path = request.getServletContext().getRealPath("")+"/picture/";
		//기준 디렉토리 의 실제 경로
		//C:\java\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\model2Study\picture
		String fname = null;
		File f = new File(path);//업로드되는 폴더정보
		if(!f.exists()){
			f.mkdirs(); //없으면 폴더생성
		}
		//request : 이미지데이터저장
		//path : 업로드되는 폴더정보
		//10*1024*1024 : 최대업로드크기(10M)
		//new DefaultFileRenamePolicy() : 중복파일명존재시 이름변경해

		MultipartRequest multi = new MultipartRequest(
					request,path,10*1024*1024,"UTF-8",new DefaultFileRenamePolicy());
		fname = multi.getFilesystemName("picture");//사진명
		request.setAttribute("fname", fname);
		return "pic";
	}

 

pic.jsp (picture controller가 호출하는 곳)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<script>
img = opener.document.getElementById("pic");//id="pic" ..이미지객체임
img.src = "${pageContext.request.contextPath}/picture/${fname}"; 

/*form하위의 name=picture인 값에(type=hidden) 넣어라
 * DB에 경로를 전부다 넣기에는 길다.
 */
opener.document.f.picture.value = "${fname}";
//self : 현재페이지
self.close();//창을 닫는다
</script>

 

updateForm의  name="picture" 와 img.src부분

<input type="hidden" name="picture" value="${mem.picture}">
	<img src="${pageContext.request.contextPath}/picture/${mem.picture}>" width="100" height="120" id="pic"><br>

 

list 의 src부분만 남겨놓겠음 (사진이보여지는부분)

2025.04.11 - [JSP] - 부트캠프49일차(model2 {login ,main ,info ,update,delete,list,layout

 

부트캠프49일차(model2 {login ,main ,info ,update,delete,list,layout

1) login2)main3)info4)update5)delete6)list(목록)7)sitemesh , layout 1) memberController에 login구현 package controller;import javax.servlet.annotation.WebInitParam;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServletRequest

ddkk1120.tistory.com

여기에 자세한코드있음

</tr>
	<c:forEach var="mem" items="${list}"> <%--멤버객체가있는 list --%> 
		<tr>
<!-- mem.xx :  getxx프로퍼티 -->
<td><a href="info?id=${mem.id}">${mem.id}</a></td>
<td><img src="${pageContext.request.contextPath}/picture/${mem.picture}" width="30" height="30"></td>
<!--../picture/${mem.picture}  로 해도됨 ( url을 잘보자) -->
<!--C:/java/workspace/.metadata/.plugins/org.eclipse.wst.server.core
		/tmp0/wtpwebapps/model2Study/picture/ -->

 

 

절대경로 "${pageContext.request.contextPath}/picture/${mem.picutre}"; 

 

 

하지만

 

src는 ../picture/${ mem.picutre } 으로해도 무관하다

하지만 제발 URL을 잘 확인하자

 

../picture/${ mem.picutre } (상대경로) 사용 시

http://localhost:8080/model2Study/member/member/list

다음과같다면(../../을 사용하면해결은 될것이다 절대경로는 상관없음) 나오지않을것이고

 

http://localhost:8080/model2Study/member/list

다음과같이 변경시 정상적으로 상대경로가 작동할거다