일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 스프링시큐리티
- 밸류즈
- register
- 캘린더 라이브러리
- 이미지 업로드
- Ajax
- 공통메서드
- 로그인 로직
- userManagement
- Update
- 빌드 및 배포
- 달력 라이브러리
- react
- Typesciprt
- 밸류즈 홈페이지
- 배포
- 마이페이지
- 인증처리
- 로그인
- stock option
- ui탬플릿
- mypage
- Token
- MRC
- 파생상품평가
- jsonwebtoken
- 회원가입로직
- Styled Components
- 관리자페이지
- RCPS
- Today
- Total
I T H
[포트폴리오 프로젝트 3] 관리자 페이지 구현 - 프로필 업데이트 본문
- 이번에는 관리자 페이지를 통해 메인 페이지의 프로필 이미지 및 프로필 정보를 등록하고 삭제 및 관리할 수 있는 화면을 구현하고자 한다.
- 해당 장은 연습 프로젝트 때 이미지 사용한 것으로 관리자 페이지 구현이 완료된 경우에는 관리자 페이지 구현 부분은 패스하고 하단의 메인 페이지에 이미지 및 프로필 조회만 처리하는 것으로 진행해도 된다.
[ 테이블 생성 ]
- 프로필 정보를 저장하기 위한 데이터베이스 테이블을 1개 생성한다.
CREATE TABLE `TBL_PROFILE_INFO` (
`PROFILE_ID` varchar(10) NOT NULL,
`PROFILE_NAME` varchar(20) NOT NULL,
`PROFILE_JOB` varchar(100) NOT NULL,
`PROFILE_EMAIL` varchar(100) DEFAULT NULL,
`PROFILE_IMG` varchar(100) DEFAULT NULL,
PRIMARY KEY (`PROFILE_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
[ Dependency 추가 ]
- 파일 업로드를 위한 라이브러리를 참조하기 위해 pom.xml 파일에 아래 내용을 추가한다.
참고 > https://commons.apache.org/proper/commons-fileupload/
FileUpload – Home
Commons FileUpload The Commons FileUpload package makes it easy to add robust, high-performance, file upload capability to your servlets and web applications. FileUpload parses HTTP requests which conform to RFC 1867, "Form-based File Upload in HTML". That
commons.apache.org
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
[ JavaConfig 설정 ]
- 패키지 아래에 ServletConfig클래스 파일 내용을 수정한다.
- 멀티파트 리졸버 빈 등록 ( public MultipartResolver multipartResolver() )
package kr.co.values.init;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
* servlet-context.xml 파일을 대신하는 클래스
* @ComponentScan 을 통하여 컨트롤러 클래스가 존재하는 패키지를 자동 스캔한다.
*/
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "kr.co.values.*.web" } ) // 수정됨
public class ServletConfig implements WebMvcConfigurer {
private final int MAX_SIZE = 10 * 1024 * 1024;
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/views/");
bean.setSuffix(".jsp");
registry.viewResolver(bean);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(MAX_SIZE); // 10MB
multipartResolver.setMaxUploadSizePerFile(MAX_SIZE); // 10MB
multipartResolver.setMaxInMemorySize(0);
return multipartResolver;
}
}
[환경 설정 내용수정]
- kr.co.values/init 패키지에 RootConfig.java, ServletConfig.java 내용을 수정해준다.
[RootConfig.java]
- kr.co.values.admin.persistence or kr.co.value.main.persistence처럼 패키지를 주제에 맞게 나누고 해당 패키지에 대한 persistence를 스캔하기 위해 내용을 수정함.
@MapperScan(basePackages= {"kr.co.values.*.persistence"})
[ServletConfig.java]
@ComponentScan(basePackages = { "kr.co.values.*.web" })
- 다음으로는 관리자용 페이지를 하나 생성한다. JSP~컨트롤러까지 admin 이라는 이름으로 한 세트를 작성한다.
[ JSP ]
- webapp/WEB-INF/views/main/admin.jsp 파일 생성한다.
- 파일 1개에 대한 이미지 업로드를 진행하기 위해 file 태그가 포함된 구문을 작성한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
</head>
<body>
<p>ADMIN PAGE</p>
<label>프로필 이미지</label>
<input id="file" name="file" type="file" style="padding: 5pt;">
<label>프로필 이름</label>
<input type="text" id="profileName">
<label>프로필 직업</label>
<input type="text" id="profileJob">
<label>프로필 이메일</label>
<input type="text" id="profileEmail">
<button id="btnRegister">프로필 등록</button>
<!-- page script -->
<script src="/resources/views/admin.js"></script>
</body>
</html>
[ 이벤트 처리 ]
- resources/views/admin.js 파일을 만들고 아래 스크립트 내용을 작성한다.
- 프로필 정보를 저장할 때 이미지를 등록한 경우에는 이미지(파일) 업로드를 먼저 진행한다.
- 반대로 이미지가 등록되지 않은 경우에는 정보 업데이트만 진행한다.
$("#btnRegister").on("click", function() {
var profileName = $("#profileName").val();
var profileJob = $("#profileJob").val();
var profileEmail = $("#profileEmail").val();
if(profileName == "") {
alert("프로필 이름을 입력하시기 바랍니다.");
return;
}
var obj = {
profileName: profileName,
profileJob: profileJob,
profileEmail: profileEmail,
profileImg: ""
}
// 프로필 저장 시에는 아래와 같은 순서로 처리한다.
// 1. 프로필 이미지를 포함하여 등록 버튼을 누른 경우에는 이미지를 먼저 업로드하고 (업로트 컨트롤러 호출) 저장된 이미지명을 전달받은 후
// 전달받은 이미지명을 파라미터에 포함한 뒤
// 2. 프로필 정보를 저장한다.
// 서버사이드에서는 프로필 정보가 이미 저장되어 있는지 체크 후 insert 혹은 update로 프로플 정보를 저장하게 된다.
var fileImg = $('#file').val();
if(fileImg == "" || fileImg == null) { // 이미지가 포함되지 않은 경우
$.ajax({
type: "POST",
url: "/admin/updateProfile.do",
contentType: "application/json;charset=UTF-8",
data: JSON.stringify(obj),
dataType: "json",
success: function(data) {
alert("프로필 저장 성공!");
},
error: function() {
alert("프로필 저장 실패!!");
}
});
} else {
var ext = $('#file').val().split('.').pop().toLowerCase();
if($.inArray(ext, ['gif','png','jpg','jpeg']) == -1) {
alert('gif, png, jpg, jpeg 파일만 업로드 할수 있습니다.');
return false;
}
var formData = new FormData();
formData.append("file", $("#file")[0].files[0]); //파일 한개
formData.append("params", JSON.stringify(obj));
formData.append("enctype", "multipart/form-data");
$.ajax({
url: "/admin/profileUpload.do",
type: "POST",
processData: false, // file전송시 필수
contentType: false, // file전송시 필수
data: formData,
dataType: "json",
success: function(data) {
// 이미지 등록이 완료되면 서버 사이드에서 전달해주는 src 키에 매핑된 파일명 값을 obj 파라미터에 담은 후
// 프로필 정보를 저장하는 컨트롤러를 호출한다.
console.log(data);
obj.profileImg = data.src;
$.ajax({
type: "POST",
url: "/admin/updateProfile.do",
contentType: "application/json;charset=UTF-8",
data: JSON.stringify(obj),
dataType: "json",
success: function(data) {
alert("프로필 저장 성공!");
},
error: function() {
alert("프로필 저장 실패!!");
}
});
},
error : function(request){
console.log(request);
}
});
}
});
[ 컨트롤러 구현 ]
- kr\co\values\admin\web\AdminController.java 파일을 생성하여 아래 내용을 입력한다.
<참고>
transferTo() : 파일을 저장한다
getOriginalFilename() : 파일 이름을 String 값으로 반환한다
getSize() : 파일 크기를 반환한다
getInputStream() : 파일에 대한 입력 스트림을 얻어온다
package kr.co.values.admin.web;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileUploadException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import kr.co.values.admin.service.AdminService;
@Controller
public class AdminController {
@Autowired
private AdminService adminService;
@RequestMapping("/admin/main.do")
public String main() {
return "main/admin";
}
// 프로필 정보 저장
@RequestMapping("/admin/updateProfile.do")
@ResponseBody
public Map<String, Object> updateProfile(@RequestBody Map<String, Object> params) {
adminService.updateProfile(params);
Map<String, Object> result = new HashMap<String, Object>();
result.put("result", true);
return result;
}
/**
* 업로드 (프로필 이미지 파일 업로드)
* for Servlet2.5 Multipart FileUpload
* @throws FileUploadException
*/
@RequestMapping("/admin/profileUpload.do")
@ResponseBody
public Map<String, Object> profileUpload(@RequestParam("file") MultipartFile part, HttpServletRequest request) throws FileUploadException {
ServletContext context = request.getSession().getServletContext();
String path = context.getRealPath("/resources/images/profile");
System.out.println("path : " + path);
String fileName = part.getOriginalFilename();
System.out.println("fileName : " + fileName);
InputStream in = null;
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
Date time = new Date();
String forTime = format.format(time);
int pos = fileName.lastIndexOf(".");
String ext = fileName.substring(pos + 1);
try {
File f = new File(path + "/" + forTime + "." + ext);
part.transferTo(f);
} catch (Exception e) {
throw new FileUploadException(); // 파일업로드를 실패하였습니다.
} finally {
if (in != null)
try {
in.close();
} catch (IOException e) {
}
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("src", forTime + "." + ext);
return result;
}
}
[ 서비스 구현 ]
- kr\co\values\admin\service\AdminService.java 파일을 생성한다.
package kr.co.values.admin.service;
import java.util.Map;
public interface AdminService {
// 프로필 정보 저장
void updateProfile(Map<String, Object> map);
}
서비스 단에서 이미 저장된 프로필 정보가 있는 경우를 체크하여 없으면 insert를 진행하고
반대라면 update를 진행하게 되도록 로직을 구현한다.
- kr\co\values\admin\service\AdminServiceImpl.java 파일을 생성한다.
package kr.co.values.admin.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import kr.co.values.admin.persistence.AdminMapper;
@Service
public class AdminServiceImpl implements AdminService {
@Autowired
private AdminMapper adminMapper;
@Override
public void updateProfile(Map<String, Object> map) {
// 1. 프로필 정보를 저장하기 전에 프로필 테이블에 이미 저장된 정보가 있는지 체크한다.
List<Map<String, Object>> list = adminMapper.searchProfile(map);
if(list.size() > 0) { // 정보가 있는 경우에는 업데이트로 프로필 정보를 변경
map.put("profileId", list.get(0).get("PROFILE_ID"));
adminMapper.updateProfile(map);
}
else { // 정보가 없는 경우에는 인서트로 프로필 정보를 최초 저장
adminMapper.insertProfile(map);
}
}
}
[ 매퍼 구현 ]
- kr\co\values\admin\persistence\AdminMapper.java 파일을 생성한다.
package kr.co.values.admin.persistence;
import java.util.List;
import java.util.Map;
public interface AdminMapper {
// 프로필 저장 정보 조회
public List<Map<String, Object>> searchProfile(Map<String, Object> map);
// 프로필 정보 저장
public void insertProfile(Map<String, Object> map);
// 프로필 정보 업데이트
public void updateProfile(Map<String, Object> map);
}
- kr\co\values\admin\persistence\AdminMapper.xml 파일을 생성한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.co.values.admin.persistence.AdminMapper">
<!-- 프로필 정보 조회 -->
<select id="searchProfile" parameterType="hashmap" resultType="hashmap">
SELECT *
FROM TBL_PROFILE_INFO
WHERE 1=1
</select>
<!-- 프로필 최초 저장 -->
<insert id="insertProfile" parameterType="hashmap">
INSERT INTO TBL_PROFILE_INFO (
PROFILE_ID
, PROFILE_NAME
, PROFILE_JOB
, PROFILE_EMAIL
, PROFILE_IMG
)
VALUES (
'profile'
, #{profileName}
, #{profileJob}
, #{profileEmail}
, #{profileImg}
)
</insert>
<!-- 프로필 정보 업데이트 -->
<update id="updateProfile" parameterType="hashmap">
UPDATE TBL_PROFILE_INFO
SET PROFILE_NAME = #{profileName}
, PROFILE_JOB = #{profileJob}
, PROFILE_EMAIL = #{profileEmail}
, PROFILE_IMG = #{profileImg}
WHERE PROFILE_ID = #{profileId}
</update>
</mapper>
[ 실행 결과 ]
- /admin/main.do 페이지로 접속 후 기능 테스트
관리자 페이지를 통해서 프로필 정보를 등록하는 기능이 추가된 이후
메인 페이지 상단에 프로필 정보를 출력하는 기능도 추가해준다.
[ 메인 JSP 파일 수정 ] - index.jsp
메인 페이지 상단에 프로필 정보를 출력하는 태그 부분을 아래처럼 수정한다.
각 태그들에 id 를 매핑하고 프로필 정보를 조회 후 id 를 통해 값들을 출력할 것이다.
<h1 id="logo" class="text-center">
<img id="profileImg" class="img-circle" src="" alt="">
<span id="profileName" class="title"> </span>
<span id="profileJob" class="tagline"> </span>
<span class="tagline"><a id="profileEmail" href=""> </a></span>
</h1>
[ resources / js / index.js 파일 내 스크립트 추가 ]
- 메인페이지가 로드될 때 프로필 정보를 조회하여 프로필 정보를 출력해준다.
// 프로필 정보를 조회하여 화면에 출력한다.
var obj = {};
$.ajax({
type: "POST",
url: "/main/searchProfile.do",
contentType: "application/json;charset=UTF-8",
data: JSON.stringify(obj),
dataType: "json",
success: function(data) {
console.log(data);
$("#profileImg").attr("src", "/resources/images/profile/" + data[0].PROFILE_IMG);
$("#profileName").html(data[0].PROFILE_NAME);
$("#profileJob").html(data[0].PROFILE_JOB);
$("#profileEmail").html(data[0].PROFILE_EMAIL);
},
error: function() {
console.log('search 통신실패!!');
}
});
[ 메인 컨트롤러 수정 ] - kr.co.values/main/web/MainController.java
- 메인 컨트롤러에 프로필 정보 조회용 메소드를 추가하여 준다.
// 프로필 이미지 조회
@RequestMapping("/main/searchProfile.do")
@ResponseBody
public List<Map<String, Object>> searchProfile(@RequestBody Map<String, Object> params) {
List<Map<String, Object>> list = mainMapper.searchProfile(params);
return list;
}
[ 메인 매퍼 수정 ] - kr.co.values/main/persistence/MainMapper.java
- 조회용 매퍼 인터페이스 메소드 및 쿼리를 작성하여 준다.
// 프로필 조회
public List<Map<String, Object>> searchProfile(Map<String, Object> map);
[MainMapper.xml]
<!-- 프로필 조회 -->
<select id="searchProfile" parameterType="hashmap" resultType="hashmap">
SELECT *
FROM TBL_PROFILE_INFO
WHERE 1=1
</select>
[ 실행 결과 ]
- 메인 페이지 접속 시 상단에 프로필 정보가 출력이 되면 정상 동작!
'Spring MyPortfolio Project' 카테고리의 다른 글
[포트폴리오 프로젝트 6] 관리자메뉴 - 사용자관리 페이지 구현 (0) | 2024.01.24 |
---|---|
[포트폴리오 프로젝트 5] 로그인 페이지 구현(spring security포함) (0) | 2024.01.24 |
[포트폴리오 프로젝트 4] 회원가입 페이지 구현 (0) | 2024.01.24 |
[포트폴리오 프로젝트 2] 메인페이지 구현 : 캐러셀 사용 (2) | 2024.01.24 |
[포트폴리오 프로젝트 1] 프로젝트 구현 - UI 템플릿 적용 (1) | 2024.01.24 |