국비교육(22-23)

53일차(1)/Spring(12) : ajax 요청 JSON으로 응답하기, 파일 업로드 처리

서리/Seori 2022. 12. 21. 14:58

53일차(1)/Spring(12) : ajax 요청 JSON으로 응답하기, 파일 업로드 처리

 

- updateform 요청/메소드 작성

- update 요청/메소드 작성

- spring에서 json으로 응답하는 방법 실습

- 파일 업로드 메소드 작성(ajax 요청 처리)

 

 

- 서버를 시작하면 가장 기본으로 응답되는 페이지.(home)

 

- 처음 프로젝트를 서버로 열면 이 경로로 요청해주지만, 이렇게 직접 요청할 수는 없다.

(WEB-INF는 클라이언트에게 공개되지 않음. 직접 입력하면 이동되지 않는다)

 

- context 경로의 최상위 경로를 요청하게 되면 home.jsp로 forward 이동이 되어서 이동한다.

- 물리적인 위치는 webapp 안쪽이라고 생각하면 된다.

 

- 저 문자열은 포워드 이동할 위치를 가리키는 것이다.

- 포워드 이동이란 다른 페이지로 응답을 위임하는 것.

- 경로의 앞, 뒤로 접두어, 접미어를 붙여서 이동시켜 준다.

 

 

- 공지사항은 request 영역으로부터 읽어낸 것이다. EL로 읽어온 것.

 

- 이런 응답에 필요한 데이터를 모델이라고도 한다.

- request 영역이나 session 영역에 담아서 전달받는다.

 

- 위 내용은 HomeController에서 request 영역에 담아서 포워드 이동시킨 것이다.

 

 

- 담긴 내용이 List<>이므로 item로 받아서 바로 출력한 것

 (제너릭이 string타입이므로 바로 출력가능)

 

** Controller와 view페이지 사이의 관계를 알아둘 것!

 

- 현재 JSTL을 사용해서 home의 내용을 조건부로 출력하게 했다. 로그인 여부에 따라!

- 사실 sessionScope. 도 생략 가능하다. 키 값만 가지고도 자동으로 request 영역, session 영역을 찾아준다.

 


 

 

- Controller는 Spring bean container로부터 필요한 객체를 주입(DI)받아서 사용한다.

 

- 클라이언트가 전달해준 dto를 받고, 로그인처리를 위해 필요한 session도 받아서 그 안에서 처리해준다.

- Controller는 필요한 객체를 넣어주고, 여러 비즈니스 로직은 service에서 해준다.

- Service는 Controller의 유틸리티 같은 것.

 

- 서비스에서 DB에 있는 정보가 맞는지 확인해서 로그인 처리를 한다.

- 서비스는 dao에 의존한다. DB에서 작업할 게 있으면 dao에서 한다.

 

 

- Interceptor 는 컨트롤러 메소드의 수행 직전에 관여하도록 했다.

- 어떤 것에 관여할지 기준이 되는 것은 servlet-context에 명시되어 있다.

- 먼저 spring에서 bean이 되어야 하고, 어떤 요청에 대해 동작할지는 mapping에 명시해두었다.

 

- login 하고 난 후에 접속되도록 처리해주는 것.

- 로그인 성공 후에 원래 가려던 곳으로 보내줄 수 있도록 encodedUrl도 같이 넣어준다.

 


 

- 파일 업로드 기능 구현 (프로필 이미지 변경)

- MultipartFile 객체를 사용한다.

 

- jsp에서는 직접 응답했는데, 그 내용을 그대로 구현하고자 한다면 필요한 javascript가 있다.

 

sy_util.js

// webapp/js/sy_util.js

   /*
      ajaxPromise("요청url", "요청메소드", query string or object)
      와 같은 형식으로 사용하고 
      Promise type 을 리턴해주는 함수 
   */
   function ajaxPromise(url, method, data){
      //만일 필요한 값이 전달 되지 않으면 기본값을 method 와 data 에 넣어준다. 
      if(method == undefined || method == null){
         method="GET";
      }
      if(data == undefined || data == null){
         data={};
      }
      
      let queryString;
      if(typeof data == "string"){
         queryString=data;
      }else{
         queryString=toQueryString(data);
      }
      
      // Promise 객체를 담을 변수 만들기 
      let promise;
      if(method=="GET" || method=="get"){//만일 GET 방식 전송이면 
         //fetch() 함수를 호출하고 리턴되는 Promise 객체를 변수에 담는다. 
         promise=fetch(url+"?"+queryString);
      }else if(method=="POST" || method=="post"){//만일 POST 방식 전송이면
         //fetch() 함수를 호출하고 리턴되는 Promise 객체를 변수에 담는다. 
         promise=fetch(url,{
            method:"POST",
            headers:{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"},
            body:queryString
         });
      }
      return promise;
   }
   
   //함수의 인자로 ajax 전송할 폼의 참조값을 넣어주면 알아서 ajax 전송되도록 하는 함수 
   function ajaxFormPromise(form){
      const url=form.getAttribute("action");
      const method=form.getAttribute("method");
      
      // Promise 객체를 담을 변수 만들기 
      let promise;
      //파일 업로드 폼인지 확인해서
      if(form.getAttribute("enctype") == "multipart/form-data"){
         //폼에 입력한 데이터를 FormData 에 담고 
         let data=new FormData(form);
         // fetch() 함수가 리턴하는 Promise 객체를 
         promise=fetch(url,{
            method:"post",
            body:data
         });
         return promise;//리턴해 준다 (여기서 함수가 종료 된다.)         
      }
      
      const queryString=new URLSearchParams(new FormData(form)).toString();
      
      if(method=="GET" || method=="get"){//만일 GET 방식 전송이면 
         //fetch() 함수를 호출하고 리턴되는 Promise 객체를 변수에 담는다. 
         promise=fetch(url+"?"+queryString);
      }else if(method=="POST" || method=="post"){//만일 POST 방식 전송이면
         //fetch() 함수를 호출하고 리턴되는 Promise 객체를 변수에 담는다. 
         promise=fetch(url,{
            method:"POST",
            headers:{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"},
            body:queryString
         });
      }
      return promise;
   }
   
   //함수의 인자로 요청 url 과 ajax 전송할 내용이 있는 input 요소의 참조값을 전달하면 ajax 전송해주는 함수
   function ajaxInputPromise(url, input){
      const type=input.getAttribute("type");
      const name=input.getAttribute("name");
      
      let promise;
      if(type=="file"){ // input type="file" 인 경우 
         
         let data=new FormData();
         data.append(name, input.files[0]);
         
         promise=fetch(url,{
            method:"post",
            body:data
         });
      }else{ //아닌경우 
         
         //전송할 쿼리 문자열 구성
         const data=name+"="+encodeURIComponent(input.value);
         promise=fetch(url,{
            method:"POST",
            headers:{"Content-Type":"application/x-www-form-urlencoded; charset=utf-8"},
            body:data
         });
      }
      return promise;
   }
   
   //인자로 전달하는 object 를 이용해서 query  문자열을 만들어서 리턴해주는 함수
   function toQueryString(obj){
      //빈배열을 일단 만든다.
      let arr=[];
      //반복문 돌면서 obj 에 있는 정보를 "key=value" 형태로 만들어서 배열에 저장한다.
      for(let key in obj){
         //value 는 인코딩도 해준다. 
         let tmp=key+"="+encodeURIComponent(obj[key]);
         arr.push(tmp);
      }
      //query 문자열을 얻어낸다
      let queryString=arr.join("&");
      //결과를 리턴해준다.
      return queryString;
   }

 

- 이런 폼의 속성들을 읽어와서 작업해주는 js 코드가 들어있다.

- 이 폼의 참조값을 전달하면 ajax를 리턴하고, json으로 응답해준다.

 

- 업로드 폴더는 resources/upload 여기에. sy_util 파일이 들어있는 js 폴더도 이곳에 넣어준다.

 

 

- 컨트롤러 작성(updateform)

//회원정보 수정 폼 요청 처리
@RequestMapping("/users/updateform")
public ModelAndView updateForm(HttpSession session, ModelAndView mView) {
    service.getInfo(session, mView);		
    mView.setViewName("users/updateform");
    return mView;
}

- session과 mView를 전달하면 mView에 회원정보가 담기는 메소드 작성

- 메소드에 인자를 선언하는 것만으로도 알아서 객체가 들어온다.

 

- 서비스의 메소드에서 이 작업을 해준다.

- ModelAndView 객체의 addObject는 request.setAttribute를 대신하는 것이다.

 

 

- 보통은 위와 같이 하는데, 이것을 mView로 대신할 수 있다.

- 데이터(model) 도 담고 이동할 view page도 담는다. 

 

 

- 담는다고 해서 무조건 req 영역에 담기는 것은 아니고, controller에서 이 mView를 리턴해줘야 한다.

 

updateform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/views/users/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:">
      	<c:choose>
      		<c:when test="${ empty dto.profile }">
      			<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>
      		</c:when>	
      		<c:otherwise>
      			<img id="profileImage" src="${pageContext.request.contextPath }${dto.profile}">
      		</c:otherwise>
      	</c:choose>         
      </a>
      <form action="${pageContext.request.contextPath}/users/update" method="post">
         <input type="hidden" name="profile" 
            value="${ empty dto.profile ? 'empty' : dto.profile }"/>
         <div>
            <label for="id">아이디</label>
            <input type="text" id="id" value="${dto.id}" disabled/>
         </div>
         <div>
            <label for="email">이메일</label>
            <input type="text" id="email" name="email" value="${dto.email}"/>
         </div>
         <button type="submit">수정확인</button>
         <button type="reset">취소</button>
      </form>   
      
      <form id="imageForm" action="${pageContext.request.contextPath}/users/profile_upload" 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 }/resources/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");
         //gura_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>

 

- 이전 jsp 페이지에서 했던 이부분은 필요없다. 삭제!

 

- 서비스의 getInfo 메소드에서 이렇게 담았기 때문에 EL을 사용해서 추출할 수 있는 것이다.

- key 값과 type 을 기억하기 : "dto" 키워드로 UsersDto 타입을 담아두었다!

 

 

- 어떤값이 없는지 확인하려면 empty를 쓰는게 좋다. 깔끔하게 사용하기!

- 필드명만 적어도 알아서 getter메소드 호출해줌.

 

- profile 값이 null이라면(비어있다면) 기본 이미지를 출력해준다.

 

- 저장한 이미지가 있다면 출력되도록 해주는 것.

- 이 위치에는 이런 문자열이 들어가도록 해주어야 한다.

 

- 아래를 위와 같이 수정해주기

- ${ } EL 안에서도 3항연산자를 쓸 수 있다.

 

- 프로필 이미지는 empty 값이 넘어온다.

 

- resources 폴더 안으로 위치시켜주기

 

- 그러면 수정 폼이 위와 같이 나온다.(현재 프로필 값이 null이므로 기본이미지)

 

 


 

- 그러면 이제 update 요청을 해야한다.

 

controller

//회원정보 수정 반영 요청 처리
@RequestMapping(value="/users/update", method = RequestMethod.POST)
public ModelAndView update(UsersDto dto, HttpSession session, ModelAndView mView,
        HttpServletRequest request) {
    //서비스를 이용해서 개인정보를 수정하고
    service.updateUser(dto, session);
    //개인정보 보기로 리다이렉트 이동시킨다.
    mView.setViewName("redirect:/users/info");		
    return mView;
}

 

서비스 updateUser

@Override
public void updateUser(UsersDto dto, HttpSession session) {
    //수정할 회원의 아이디(아이디는 넘어오지 않으므로)
    String id=(String)session.getAttribute("id");
    //dto에 넣어준다.
    dto.setId(id);
    //만약 프로필 이미지를 등록하지 않은 상태이면
    if(dto.getProfile().equals("empty")) {
        //users 테이블의 profile 칼럼을 null인 상태로 유지하기 위해 profile에 null을 넣어준다.
        dto.setProfile(null);
    }
    dao.update(dto);
}

- empty라는 문자열로 바뀐 profile 값을 다시 null로 돌려주는 작업!

 

 

- mapper의 update문 수정

 

 

- myBatis의 장점 중 하나! 동적 sql문이 가능하다.(Dynamic sql)

- sql문을 조건부로 작성할 수 있다.

 

 

- 그런데 JDBC에서는 null을 집어넣을 수 있었는데, myBatis에서는 안된다.

→ 그렇다면 null이 아닐 때에만 조건부로 profile값이 들어가도록 수정

 

- 이것이 동적 SQL문이다! JSTL과 비슷하지만 myBatis만의 문법이다.

- parameter에 저장된 필드값을 가지고 비교하는 것이다.

 

 

- 아니면 이렇게 수정해줄 수도 있다.

 

- 이것은 원래 ? 인 부분에 myBatis가 setString, setInt, setDouble 등으로 알아서 넣어주는 것인데

null을 넣으려고 하면 myBatis가 타입을 몰라서 오류가 나는 것이다.

- VARCHAR이라고 jdbcType을 명시해서 넣어줄 수 있도록 하면 된다.

 


 

- 프로필사진을 업로드하는 요청 작성(ajax 요청 처리)

- ajax요청에 대한 응답은 json으로 처리한다.

 

- 먼저 spring에서 json으로 어떻게 응답하는지를 연습할 예정

- java의 jsp 파일에서는 json응답이 불편했다. spring에서는 편해진다!

 

 

- home.jsp 수정

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/home.jsp</title>
</head>
<body>
	<div class="container">
		<c:choose>
	         <c:when test="${ empty sessionScope.id}">
	            <a href="${pageContext.request.contextPath}/users/loginform">로그인</a>
	            <a href="${pageContext.request.contextPath}/users/signup_form">회원가입</a>
	         </c:when>
	         <c:otherwise>
	            <p>
	               <a href="${pageContext.request.contextPath}/users/info">${sessionScope.id }</a> 로그인중... 
	               <a href="${pageContext.request.contextPath}/users/logout">로그아웃</a>
	            </p>
	         </c:otherwise>
	      </c:choose>   
	      		
		<h1>인덱스 페이지입니다.</h1>
		<ul>
			<li><a href="get_msg">@ResponseBody 어노테이션 테스트</a></li>
			<li><a href="get_person">한명의 정보</a></li>
			<li><a href="get_user">회원 한명 정보</a></li>
			<li><a href="get_friends">친구목록</a></li>
			<li><a href="get_users">회원 목록</a></li>
		</ul>
		<h3>공지사항입니다.</h3>
		<ul>
			<c:forEach var="tmp" items="${noticeList }">
				<li>${tmp }</li>
			</c:forEach>
		</ul>
	</div>
</body>
</html>

 

 

- 기본패키지에 JSONTestController 생성

package com.sy.spring04;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.sy.spring04.users.dto.UsersDto;

/*
 * 1. jackson-databind 라이브러리가 dependency에 명시가 되어 있고
 * 2. servlet-context.xml 에 <annotation-driven/> 이 명시되어 있고
 * 3. 컨트롤러의 메소드에 @ResponseBody 어노테이션이 붙어 있으면
 * Map or dto or List 객체에 담긴 내용이 json 문자열로 변환되어 응답된다.
 */

@Controller
public class JSONTestController {
	
	@ResponseBody //컨트롤러에서 리턴한 문자열을 그대로 클라이언트에게 출력하는 기능
	@RequestMapping("/get_msg")
	public String getMsg() {
		return "hello";
	}
		
	@ResponseBody
	@RequestMapping("/get_person")
	public Map<String, Object> getPerson(){
		
		Map<String, Object> map=new HashMap<>();
		map.put("num", 1);
		map.put("name", "바나나");
		map.put("isMan", false);
		
		return map;
	}
	
	@ResponseBody
	@RequestMapping("/get_user")
	public UsersDto getUser() {
		
		UsersDto dto=new UsersDto();
		dto.setId("banana");
		dto.setPwd("1234");
		dto.setEmail("banana@a.com");
		
		return dto;
	}
	
	@ResponseBody
	@RequestMapping("/get_friends")
	public List<String> getFriends(){
		List<String> friends=new ArrayList<>();
		friends.add("바나나");
		friends.add("딸기");
		friends.add("복숭아");
		return friends;
	}
	
	@ResponseBody
	@RequestMapping("/get_users")
	public List<UsersDto> getUsers(){
		List<UsersDto> list=new ArrayList<>();
		
		UsersDto dto=new UsersDto();
		dto.setId("banana");
		dto.setPwd("1234");
		dto.setEmail("banana@a.com");
		
		UsersDto dto2=new UsersDto();
		dto2.setId("berry");
		dto2.setPwd("1234");
		dto2.setEmail("berry@a.com");
		
		list.add(dto);
		list.add(dto2);
		
		return list;
	}
}

 

1. jackson-databind 라이브러리가 dependency에 명시되어 있고,
2. servlet-context.xml 에 <annotation-driven/> 이 명시되어 있고,
3. 컨트롤러의 메소드에 @ResponseBody 어노테이션이 붙어 있으면
Map or dto or List 객체에 담긴 내용이 json 문자열로 변환되어 응답된다.

 

- 1번은 pom.xml에 이미 세팅되어 있다. 2번도 되어 있다.

 

- /get_msg 에서 /views/hello.jsp 로 forward 이동하는 형태

- 리턴으로 웹브라우저에 새 페이지를 보여주는 것이 아니라 바로 저 문자열만 전달하는 방법이 있다.

@ResponseBody 를 사용한다.

 

 

- controller에서 리턴한 문자열이 바로 응답된다.

- return에 넣은 문자열이 다이렉트로 날아온다!

 

- 이 annotation과 jackson-databind 라이브러리를 잘 사용하면

  map, list, dto 등을 JSON으로 간편하게 응답할 수 있다.

 

 

home.jsp에 링크 추가

get_person

 

 

- 위와 같이 작성하면 map에 담긴 내용이 JSON문자열로 변환되어 응답된다.

- 응답의 Body로서 바로 응답을 한다.

 

get_user

- UsersDto 폼 안에 넣어져서 (없으면 null) 응답된다.

- { } JSON 문자열로 변환되어서 응답된다.

 

get_friends

- List를 넣어주면 배열 형태로 응답된다.

 

 

** JSON의 응답방식은 아래와 같은 형태로 응답된다.

Map => { }

Dto => { }

List => [  ]

List<Map> => [ { }, { }. { }. ... ]

List<Dto>

=> [ { }, { }. { }. ... ]

Map<String, List<Map>> => { "key" : [ { }, { }. ...] }

 

 

get_users

[ {  } , {  } , {  }. ... ]

- 이런 형태로 list에 2명의 정보를 담아 리턴해줄 수 있다.

 


 

- updateform의 내용을 json으로 응답해보기

- service에 Map을 리턴하는 서비스가 있다.(saveProfileImage)

 

- 이 폴더가 있어야 업로드 가능하다.

 

- 이렇게 지시하는 것을 예로 들면, 이 자체가 이미지인 것은 아니다.

- 이 경로로 웹브라우저가 요청(request)을 해서 이미지가 출력되는 것이다.

- 이 경로에 없으면 이미지가 출력되지 않는다.

 

- spring에서는 이렇게 요청한다.

- 하지만 저 경로에는 파일이 없으니 응답하지 않는다.

 

- 그래서 resources 안에 upload 폴더를 만들어놓고, 이 안에 존재한다면 응답하도록 한다.

- 이렇게 요청하면 이 resources 하위의 요청에 대해서는 관여하지 않는다.

 

- 필요할 때 불러올 수 있도록 이 문자열을 DB에 저장해 놓는다.

- 저장할 때는 파일명을 바꾸어서 알아서 저장한다.

 

- 이전에 작성한 jsp에서는 전체 경로를 구성해서 넣어주었는데,

 Spring에서는 multipartFile을 사용해서 처리한다.

 

- Service 메소드 작성(saveProfileImage)

@Override
public Map<String, Object> saveProfileImage(HttpServletRequest request, MultipartFile mFile) {
    //업로드된 파일에 대한 정보를 MultipartFile 객체를 이용해서 얻어낼수 있다.   

    //원본 파일명
    String orgFileName=mFile.getOriginalFilename();
    //upload 폴더에 저장할 파일명을 직접구성한다.
    // 1234123424343xxx.jpg
    String saveFileName=System.currentTimeMillis()+orgFileName;

    // webapp/upload 폴더까지의 실제 경로 얻어내기 
    String realPath=request.getServletContext().getRealPath("/resources/upload");
    // upload 폴더가 존재하지 않을경우 만들기 위한 File 객체 생성
    File upload=new File(realPath);
    if(!upload.exists()) {//만일 존재 하지 않으면
       upload.mkdir(); //만들어준다.
    }
    try {
       //파일을 저장할 전체 경로를 구성한다.  
       String savePath=realPath+File.separator+saveFileName;
       //임시폴더에 업로드된 파일을 원하는 파일을 저장할 경로에 전송한다.
       mFile.transferTo(new File(savePath));
    }catch(Exception e) {
       e.printStackTrace();
    }

    // json 문자열을 출력하기 위한 Map 객체 생성하고 정보 담기 
    Map<String, Object> map=new HashMap<String, Object>();
    map.put("imagePath", "/resources/upload/"+saveFileName);

    return map;
}

 

- 경로가 구성된 파일 객체를 transferTo() 메소드에 전달하면 알아서 저장해준다.

 

 

- 그리고 json 문자열을 응답할 준비를 하기위해서 Map안에 넣어주는 것.

- imagePath라는 키값으로 이미지경로가 저장된 것이다.

- javascript에서 이 json문자열을 받아서 object로 바꿔서 쓰면 된다.

- controller에 저 ajax 요청에 대한 응답을 하는 메소드가 필요하다.

 

 

controller에 메소드 작성

//ajax 프로필 사진 업로드 요청 처리	
@RequestMapping(value = "/users/profile_upload", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> profileUpload(HttpServletRequest request, MultipartFile image){
    //서비스를 이용해서 이미지를 upload 폴더에 저장하고 리턴되는 Map을 리턴해서 json 문자열 응답하기
    return service.saveProfileImage(request, image);		
}

 

- controller의 MultipartFile은 폼의 name 속성의 값과 같아야 한다.

 

 

- 서버는 json문자열을 응답하고, 웹브라우저는 그 값을 object로 바꾸어서 data에 전달한다.

- data가 object이므로 아래에서 data. 점찍어서 사용할 수 있는 것이다.

 

- response.json 으로 코드를 작성했기 때문에 { } object type 으로 바꾸어 준 것이다.

- 만약 response.text 한다면 문자열이 된다.

 

- service.saveProfileImage() 메소드에서 map을 리턴해준 것이므로,

 return map; 과 같은 방식으로 리턴된다고 보면 된다.

 

 

<!-- 
      Multipart 폼 전송 처리를 위한 bean 설정 
      최대 업로드 사이즈 제한하기 
      name="maxUploadSize"  value="byte 단위" 
   -->
   <beans:bean id="multipartResolver"
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
      <beans:property name="maxUploadSize" value="102400000"/>
   </beans:bean>

- 그리고 파일 업로드하려면 반드시 servlet-context에 MultipartResolver가 있어야 한다.

 

 

 

- 이렇게 이미지가 들어간다.

- 수정확인을 누르면 최종 저장되어 들어가진다!