34일차(2)/jsp(20) : 회원 프로필 이미지 등록, 수정 기능 구현
- 어떤 이미지를 업로드한다면, 파일이 실제 업로드되는 폴더는 /upload 가 아니다
- /webapp/upload/kim1.png 라는 이미지파일이 업로드된다면
DB에는 /upload/kim1.png 을 저장하고
해당 이미지를 출력할때는 DB에 저장된 /upload/kim1.png를 불러와서
<img src="${pageContext.request.contextPath}/upload/kim1.png"> 형식으로 이미지를 출력하는 것이다.
- 파일을 업로드하면 저장된 파일 경로를 알 수 있다.
그 경로를 통해 DB에 이미지를 저장하 고, 그 경로에서 불러와서 src에 출력하는 것이다.
- upload는 webapp아래에 있어서 클라이언트가 요청을 통해서 접근 가능한 폴더이다.
- DB칼럼에 경로 값을 저장해두고, ajax로 이미지를 업로드 한다.
<updateform.jsp> 수정
<%@page import="test.users.dao.UsersDao"%>
<%@page import="test.users.dto.UsersDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//session scope에 저장된 아이디를 이용해서
String id=(String)session.getAttribute("id");
//수정할 회원의 정보를 얻어온다.
UsersDto dto=UsersDao.getInstance().getData(id);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/users/private/updateform.jsp</title>
<style>
/* 이미지 업로드 폼을 숨긴다 */
#imageForm{
display: none;
}
#profileImage{
width: 100px;
height: 100px;
border: 1px solid #cecece;
border-radius: 50%;
}
</style>
</head>
<body>
<div class="container">
<h3>회원가입 수정 폼입니다.</h3>
<a id="profileLink" href="javascript:">
<%if(dto.getProfile() == null){%>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
<path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
<path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/>
</svg>
<%}else{ %>
<img id="profileImage" src="${pageContext.request.contextPath }<%=dto.getProfile()%>">
<%} %>
</a>
<form action="update.jsp" method="post">
<input type="hidden" name="profile"
value="<%=dto.getProfile()==null ? "empty" : dto.getProfile()%>"/>
<div>
<label for="id">아이디</label>
<input type="text" id="id" value="<%=dto.getId() %>" disabled />
</div>
<div>
<label for="email">이메일</label>
<input type="text" id="email" name="email" value="<%=dto.getEmail() %>" />
</div>
<button type="submit">수정확인</button>
<button type="reset">취소</button>
</form>
<form id="imageForm" action="profile_upload.jsp" method="post" enctype="multipart/form-data">
프로필 사진
<input type="file" id="image" name="image" accept=".jpg, .png, .gif"/>
<button type="submit">업로드</button>
</form>
</div>
<!-- sy_util.js 로딩 -->
<script src="${pageContext.request.contextPath }/js/sy_util.js"></script>
<script>
//프로필 이미지 링크를 클릭하면
document.querySelector("#profileLink").addEventListener("click", function(){
// input type="file" 을 강제 클릭 시킨다.
document.querySelector("#image").click();
});
//프로필 이미지를 선택하면(바뀌면) 실행할 함수 등록
document.querySelector("#image").addEventListener("change", function(){
//ajax 전송할 폼의 참조값 얻어오기
const form=document.querySelector("#imageForm");
//sy_util.js 에 있는 함수를 이용해서 ajax 전송하기
ajaxFormPromise(form)
.then(function(response){
return response.json();
})
.then(function(data){
console.log(data);
// input name="profile" 요소의 value 값으로 이미지 경로 넣어주기
document.querySelector("input[name=profile]").value=data.imagePath;
//img 요소를 문자열로 작성한 다음
let img=`<img id="profileImage"
src="${pageContext.request.contextPath }\${data.imagePath}">`;
//id가 profileLink인 요소의 내부(자식요소)에 덮어쓰기 하면서 html 형식으로 해석해주세요 라는 의미
document.querySelector("#profileLink").innerHTML=img;
});
});
</script>
</body>
</html>
- 파일을 업로드할 수 있는 폼을 새로 하나 만들고, 제출을 막는다.
document.querySelector("#image").click();
- console창에서 테스트해보면 이 버튼을 javascript에서 강제로 클릭시킬 수 있다.
- 입력하면 id가 image인 버튼이 강제로 클릭된다.
- 아이디가 image인 요소(input)의 참조값을 읽어와서 제어한다.
- 기본 아이콘을 하나 넣어주고,
이 아이콘을 클릭하면 아래 [파일 선택] 버튼이 강제로 클릭되도록 수정할 예정이다.
<a id="profileLink" href="javascript:">
<script>
document.querySelector("#profileLink").addEventListener("click", function(){
document.querySelector("#image").click();
});
</script>
→ javascript 를 추가해서 아이콘에 위 코드를 연결해준다.
- style에서 input 요소를 display: none으로 한다. 보이지않도록!
- 그러면 폼이 없어지고, 아이콘을 누르면 파일선택이 열리는 것으로만 보인다.
- 이제 폴더에서 사진을 선택하는 순간, ajax로 파일을 업로드하도록 할 것이다.
- 바로 제출되어 업로드를 하고, 응답을 json으로 주는 것이다.
그러면 클라이언트가 바로 볼 수 있도록 해줄 것이다.(응답)
- 이미지 링크를 만들어서 올린다.
- profile_upload.jsp 페이지에서 파일 업로드 처리를 한다.
- 경로를 구성해서 JSON으로 응답한다.
- 이 " " 안쪽은 동적으로 작동한다.
- 위에 있는 <% %>설정값을 contentType="application/json; 으로 바꿔주기
- 경로가 저장되고, 프로필 이미지가 바뀐다
(아직 DB에 저장한 것은 아니다. upload폴더에 저장하고 브라우저에 응답만 한 것이다.
- 이 안에 들어있는 imagePath를 이용해서 이미지를 부여하고 innerHTML로 집어넣은 것이다.
동적으로 만든 마크업!
- svg(기본아이콘)가 들어있던 자리에 다른 내용을 넣는 방법은
<a>의 .innerHTML="<img xx>"; 으로 이 위치를 대체한다. innerhtml 에 들어갈 내용을 바꾸어 준다.
- javascript 를 사용해서 방금 업로드한 이미지로 문자열을 만들어서 집어넣으면서 html로 해석해주세요~ 한 것이다.
- 이 수정된 이미지 정보는 폼이 제출될때 같이 제출되어야 한다. 그래야 수정이 반영되니까!
- 즉 input type="hidden"으로 같이 보내면 된다.
- hidden으로 들어간 input type. 지금은 value가 empty이다.
- 이미지를 넣어주면 value 값이 수정된 것을 볼 수 있다. 이미지를 수정하면 해당 이미지의 경로가 나오게된다.
- update.jsp에서는 getProfile로 얻어낼 수 있다.
- 다음에 수정폼에 들어오면 위 이미지가 출력된 상태로나온다.
<update.jsp> 수정
<%@page import="test.users.dao.UsersDao"%>
<%@page import="test.users.dto.UsersDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//1.수정할 회원의 정보를 읽어와서
String id=(String)session.getAttribute("id");
String email=request.getParameter("email");
//프로필 이미지의 경로 읽어오기(등록하지 않았으면 "empty"이다)
String profile=request.getParameter("profile");
UsersDto dto=new UsersDto();
dto.setId(id);
dto.setEmail(email);
//만일 profile 이미지를 등록했다면(profile 이미지가 empty가 아니라면)
if(!profile.equals("empty")){
//dto에 전송된 프로필 이미지 경로를 담아준다.
dto.setProfile(profile);
}
//2. DB에 수정반영하고
boolean isSuccess=UsersDao.getInstance().update(dto);
//3.응답하기
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/users/private/update.jsp</title>
</head>
<body>
<script>
<% if(isSuccess){%>
alert("수정했습니다.");
location.href="info.jsp";
<%}else{%>
alert("수정 실패!");
location.href="updateform.jsp";
<%}%>
</script>
</body>
</html>
String profile=request.getParameter("profile");
if(!profile.equals("empty")){
dto.setProfile(profile);
}
- 이 내용을 추가해줌! 들어온 프로필 파라미터 값을 읽어오기.
<UsersDao>의 update 메소드도 수정
//개인정보(이메일)를 수정하는 메소드
public boolean update(UsersDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = "UPDATE users"
+ " SET email=?, profile=?"
+ " WHERE id=?";
pstmt = conn.prepareStatement(sql);
//?에 바인딩
pstmt.setString(1, dto.getEmail());
pstmt.setString(2, dto.getProfile());
pstmt.setString(3, dto.getId());
//INSERT or UPDATE or DELETE문을 수행하고 수정,삭제,추가된 row의 개수 리턴
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e2) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
- sql문에 profile을 추가해주고, ?의 순서가 바뀌었으므로 다시 바인딩해준다.
- 보이는 프로필 이미지가 수정되고, DB의 Profile 칼럼에도 값이 들어가 있는 것을 확인할 수 있다.
Q) `` 백틱을 사용하는 이유는?
A) 문자열을 이어 붙이기 위해 사용하는 것이다.
webapp/<test.jsp> 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/test.jsp</title>
</head>
<body>
<div id="one"></div>
<script>
let data={imagePath:"/images/b1.png"};
let img1='<img src="/Step04_Final/images/b1.png">';
let img2='<img src="/Step04_Final'+data.imagePath+'">';
let img3=`<img src="/Step04_Final\${data.imagePath}">`;
</script>
</body>
</html>
- img3은 백틱을 사용한 것.
- 브라우저의 콘솔 창에서 자바스크립트 마크업을 해볼 것
- 똑같은 문자열을 만든다고 할 때, img1, img2, img3는 모두 같다.
- ` `에서 ${} 는 중요한 의미이다. 저 안쪽은 javascript영역으로, ``을 사용해서 이어 붙일 수 있다.
- 그런데 위 img1, 2, 3을 파일 안에 직접 작성하고 페이지 소스보기를 하면 다르게 나온다.
- jsp페이지에서 ${ }는 매우 특별한 기호이다.
(이 안에서 사용할수있는 특별한 언어 EL이 있다.)
- 그런데 클라이언트에게 출력되기 전에 이미 jsp페이지가 저걸 해석해버린다.
- 그래서 클라이언트에게 출력되는 단계에서는 읽어올 수 있는 것이 없어서 아무것도 없다고 나온 것이다.
- 따라서 이 $를 특별하게 해석하지 말고, 그냥 문자열로 봐달라는 의미에서 \를 붙인다. 그러면 정상적으로 출력됨!
- 그러면 페이지 소스 보기에 있는 이 소스를 웹브라우저가 해석할 수 있다.
- object의 imagepath에 있는 경로를 이어붙이기위함이다.
- jsp 페이지가 이어붙이는 것이 아니라, 웹브라우저가 이어붙인다.
- 그 앞부분은 jsp페이지가 해석한다.
- updateform의 이 경로(cpath) 부분은 jsp가 해석했고,
그 뒷부분인 ${} 안쪽은 앞으로 브라우저가 해석할 예정이다.
- 각각 innerText에 img1을 넣었을 때와 innerHTML에 img1을 넣었을 때! 출력되는 내용이 달라진다.
→ 문자열 취급하느냐, 아니면 마크업으로 해석해주느냐가 달라진다.
document.querySelector("#image").addEventListener("change", function(){ })
→ id가 image인 요소에 change 이벤트가 발생하면 어떤 함수를 실행한다.
const form=document.querySelector("#imageForm");
→ ajaxFormPromise() 함수에 참조값을 넣어주기 위해 참조값을 얻어온다.
- 폼에 참조값만 넣어주면 알아서 제출해준다.
- 초록박스를 선택했을때 (사진이 업로드되고, ajaxFormPromise() 함수가 data를 받아서 promise를 리턴해준다.
- 만약 sy_util.js( ajaxFormPromise() 함수)를 사용하지 않을 경우, 이렇게 작성해볼 수 있다.
- 폼에참조값만 넣어주면된다.
ajaxFormPromise(form)
.then(function(response){
return response.json();
})
→ 페이지 전환없이 폼을 제출하기 위해(파일을 업로드 하기 위해) 사용하는 것!
- 파일 전송, 업로드 후 그 파일을 읽어올 때 getFilesystemName 값은 input name의 value와 동일해야 한다.
그래야 정상적으로 읽어올 수 있다.
'국비교육(22-23)' 카테고리의 다른 글
35일차(2)/jsp(22) : 게시판 SmartEditor 적용 / 글 수정, 삭제 기능 구현 (0) | 2022.11.27 |
---|---|
35일차(1)/jsp(21) : 게시판 목록 보기, 새 글 작성, 글 상세보기 기능 구현 (0) | 2022.11.25 |
34일차(1)/jsp(19) : fetch, ajax 함수 (0) | 2022.11.24 |
33일차(4)/javascript : Promise (0) | 2022.11.24 |
33일차(3)/jsp(18) : 자료실 게시판 페이징 처리 (0) | 2022.11.24 |