Spring Framework 마이페이지 프로필 사진 업로드 기능 구현
이번 포스팅에서는 Spring Framework를 이용하여 마이페이지 프로필 사진 업로드 기능을 구현하는 방법을 단계별로 상세히 알아봅니다. 파일 업로드 라이브러리 설정부터 데이터베이스 연동, 그리고 비동기 방식의 화면 처리까지 전반적인 과정을 다룹니다.
1. 프로젝트 설정 및 라이브러리 추가
1.1. pom.xml 라이브러리 추가
파일 업로드를 처리하기 위해 commons-fileupload와 commons-io 라이브러리를 추가합니다.
pom.xml
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
1.2. members 테이블 수정
회원 테이블에 profile_img 컬럼을 추가하여 업로드된 프로필 이미지의 경로를 저장합니다.
SQL
ALTER TABLE members ADD profile_img VARCHAR(1000);
2. root-context.xml 설정
파일 업로드를 위한 CommonsMultipartResolver 빈(bean)을 등록하여 멀티파트 요청(파일 업로드)을 처리하도록 설정합니다.
root-context.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600" /> <!-- 100MB -->
<property name="maxUploadSizePerFile" value="104857600" />
<property name="maxInMemorySize" value="104857600" />
</bean>
3. VO 및 DAO 계층 구현
3.1. MemberVO 변수 추가
프로필 이미지 경로를 저장할 profileImg 변수를 MemberVO에 추가합니다.
MemberVO.java
public class MemberVO {
private String memId;
private String memPw;
private String memName;
private String profileImg; // 추가된 변수
private String addr;
// ... (기존 필드 및 getter/setter 생략)
}
3.2. DAO 인터페이스에 메서드 추가
프로필 이미지 경로 업데이트 메서드를 DAO 인터페이스에 추가합니다.
IBoardDAO.java (또는 MemberDAO.java)
public interface IBoardDAO {
// ... 기존 메서드들
int profileUpload(MemberVO member); // 프로필 이미지 경로 업데이트
}
3.3. Member.xml Mapper 수정
프로필 이미지 경로를 업데이트하는 SQL과 로그인 시 프로필 이미지 컬럼을 조회하는 SQL을 추가합니다.
Member.xml
<update id="profileUpload" parameterType="MemberVO">
UPDATE members
SET profile_img = #{profileImg}
WHERE mem_id = #{memId}
</update>
<select id="loginMember" parameterType="MemberVO" resultType="MemberVO">
SELECT
mem_id,
mem_pw,
mem_name,
profile_img,
addr
FROM members
WHERE mem_id = #{memId}
AND mem_pw = #{memPw}
AND del_yn = 'N'
</select>
4. Service 계층 구현
업로드된 파일을 서버에 저장하고, 데이터베이스에 프로필 이미지 경로를 업데이트하는 로직을 구현합니다.
MemberService.java
public class MemberService {
// DAO 주입 (예: @Autowired)
private IBoardDAO dao;
public String updateProfilePicture(MemberVO member, String uploadDir, String webPath, MultipartFile file) throws Exception {
String originalFilename = file.getOriginalFilename();
// UUID를 이용한 파일명 중복 방지
String storedFilename = UUID.randomUUID().toString() + "_" + originalFilename;
// DB에 저장될 웹 경로
String dbFilePath = webPath + storedFilename;
// 실제 파일 저장 경로
Path filePath = Paths.get(uploadDir, storedFilename);
try {
Files.copy(file.getInputStream(), filePath);
} catch (IOException e) {
throw new Exception("파일 저장 실패", e);
}
member.setProfileImg(dbFilePath);
int result = dao.profileUpload(member);
if (result == 0) {
throw new Exception("프로필 이미지 업데이트 실패");
}
return dbFilePath;
}
}
5. Controller 계층 구현
파일 업로드 요청을 처리하고, 저장된 이미지 경로를 JSON 형식으로 반환하는 Controller 구현 예시입니다.
MemberController.java
@Controller
public class MemberController {
@Autowired
private MemberService memberService;
@PostMapping("/files/upload")
public ResponseEntity<?> uploadFiles(@RequestParam("uploadImage") MultipartFile uploadImage,
HttpServletRequest req,
HttpSession session) throws Exception {
String webPath = "/resources/memberProfile/";
String folderPath = session.getServletContext().getRealPath(webPath);
System.out.println("저장 폴더 경로: " + folderPath);
MemberVO login = (MemberVO) session.getAttribute("login");
String imgPath = memberService.updateProfilePicture(login, folderPath, webPath, uploadImage);
Map<String, Object> response = new HashMap<>();
response.put("message", "Success");
response.put("imagePath", imgPath);
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
6. 화면 구현 (JSP + jQuery AJAX)
사용자가 프로필 이미지를 클릭하면 파일 선택 창이 열리고, 이미지 선택 즉시 서버로 업로드하고 화면에 반영하는 비동기 방식입니다.
JSP 화면 코드
<div class="divider-custom-icon">
<c:if test="${sessionScope.login.profileImg != null}">
<img id="myImage" class="rounded-circle img-thumbnail shadow-sm"
src="${pageContext.request.contextPath}${sessionScope.login.profileImg}"
width="200" alt="프로필 이미지" style="cursor: pointer;" />
</c:if>
<c:if test="${sessionScope.login.profileImg == null}">
<img id="myImage" class="rounded-circle img-thumbnail shadow-sm"
src="${pageContext.request.contextPath}/assets/img/Logos/non.png"
width="200" alt="기본 이미지" style="cursor: pointer;" />
</c:if>
<form id="profileForm" enctype="multipart/form-data">
<input type="file" name="uploadImage" id="uploadImage"
style="display:none;" accept="image/*" />
</form>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$('#myImage').click(function() {
$('#uploadImage').click();
});
$('#uploadImage').on('change', function() {
let file = $(this)[0].files[0];
if (file) {
let validTypes = ['image/gif', 'image/jpeg', 'image/png', 'image/webp'];
if (!validTypes.includes(file.type)) {
alert('이미지 파일만 업로드할 수 있습니다.');
$(this).val(''); // 초기화
return;
}
let formData = new FormData($('#profileForm')[0]);
$.ajax({
url: '<c:url value="/files/upload" />',
type: 'POST',
data: formData,
dataType: 'json',
processData: false,
contentType: false,
success: function(res) {
if (res.message === 'Success') {
$('#myImage').attr('src', '${pageContext.request.contextPath}' + res.imagePath);
alert('프로필 이미지가 성공적으로 변경되었습니다!');
}
},
error: function() {
alert('프로필 이미지 변경에 실패했습니다.');
}
});
}
});
</script>
'SPRING' 카테고리의 다른 글
| Spring.스프링 프레임워크 - 암호화 (0) | 2025.06.07 |
|---|---|
| Spring.스프링 프레임워크 - 로그 (2) | 2025.06.03 |
| Spring.스프링 프레임워크 - 댓글 (1) | 2025.06.03 |
| Spring.스프링 프레임워크 - 게시판 (0) | 2025.06.03 |
| Spring.스프링 프레임워크 (0) | 2025.06.03 |