1.15 (spring tiles (db연동)- 회원관리 끝 / 게시판 시작)
<마이페이지 기본 설정>
<마이페이지 사진 설정 카메라 사진 넣기>
마이페이지 속 이미지가 static 안에 있어야 하기 때문에 그 안에 폴더 만들고 저장할 것임
src/main/resources
static
images (folder)
mbox에서 camera 사진 다운 받은 후 images 에 넣기
한 건의 레코드 읽어와서 정보 뿌리기
kr.spring.member.dao
MemberMapper.java
@Select("SELECT * FROM spmember JOIN spmember_detail USING(mem_num) WHERE mem_num=#{mem_num}")
public MemberVO selectMember(int mem_num);//한건의 레코드 반환
Service 파일에서 처리하기
kr.spring.member.service
MemberServiceImpl
@Override
public MemberVO selectMember(int mem_num) {
return memberMapper.selectMember(mem_num);
}
컨트롤러에서 호출하기
kr.spring.member.controller
MemberController
/*=======================
* MyPage
*======================= */
@RequestMapping("/member/myPage")
public String process(HttpSession session,Model model) {
MemberVO user = (MemberVO)session.getAttribute("user");
//회원 정보
MemberVO member = memberService.selectMember(user.getMem_num()); //한건의 레코드 읽어오기
log.debug("<<회원 상세 정보>> : " + member); //member -> toString 동작 (내용 출력)
model.addAttribute("member", member);
return "myPage";
}
myPage body부분 view 수정
views
member
memberView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 내용 시작 -->
<div class="page-main">
<h2>회원 상세 정보 <input type="button" value="회원 정보 수정" onclick="location.href='update'"></h2>
<ul>
<li>이름 : ${member.name}</li>
<li>별명 : ${member.nick_name}</li>
<li>전화번호 : ${member.phone}</li>
<li>이메일 : ${member.email}</li>
<li>우편번호 : ${member.zipcode}</li>
<li>주소 : ${member.address1} ${member.address2}</li>
<li>가입날짜 : ${member.reg_date}</li>
<c:if test="${!empty member.modify_date}">
<li>정보 수정일 : ${member.modify_date}</li>
</c:if>
</ul>
</div>
<!-- 내용 끝 -->
=============================
restart 후 읽어오면 화면에
화면 상세 정보 출력됨
<프로필 사진 저장하기 - db저장>
프로필 사진이 없을 시 이전에 사용했던 face.png로 기본 이미지 처리할 것임
mbox에서 face.png 받아서 images 에 넣기
이미지 업로드 시 spmember_detail에 업로드
마이바티스는 byte[] 배열 단위만 처리 가능 (ajax를 사용해야 하니까 jquery 필요)
template
nav_mypage.jsp
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/member.profile.js"></script>
아래에 jquey 구문 붙여주기
java script는 하나씩 확인하는 게 에러 확인에 더 좋음
일단 더 편하게 확인하기 위해 nav_mypage.jsp 에서
<img src="${pageContext.request.contextPath}/images/face.png" width="200" height="200" class="my-photo">
라고 기본 이미지 face.png로 설정하기
1. 카메라 아이콘 클릭 시 파일선택, 전송, 취소 버튼 출력하기
src/main/resources
static
js
member.profile.js (javascript file)
$(function(){
//My페이지 프로필 사진 등록 및 수정
//수정 버튼 이벤트 처리
$('#photo_btn').click(function(){
$('#photo_choice').show();
$(this).hide();
});
});
2. 미리보기 후 취소 버튼 누르면 기본 이미지로 변경되는 것까지 확인
src/main/resources
static
js
member.profile.js (javascript file)
$(function(){
//My페이지 프로필 사진 등록 및 수정
//수정 버튼 이벤트 처리
$('#photo_btn').click(function(){
$('#photo_choice').show();
$(this).hide();
}); // end of click
//처음 화면에 보여지는 이미지 읽기
//업데이트 하려다가 취소 누르면 다시 원래 이미지로 돌아가야하는데 그걸 위해서 저장해놓는 거임
let photo_path = $('.my-photo').attr('src');
let my_photo; //업로드 하고자 선택한 이미지 저장
//파일 선택 이벤트 연결
$('#upload').change(function(){
my_photo = this.files[0]; //선택한 이미지 저장
//선택한 파일이 없을 때에
if(!my_photo){
$('.my-photo').attr('src',photo_path);
return;
}
//파일 업로드 처리 시 용량체크
if(my_photo.size > 1024*1024){ //1mb까지만 업로드
alert(Math.round(my_photo.size/1024) + 'kbytes(1024kbytes까지만 업로드 가능)');
$('.my-photo').attr('src',photo_path);
$(this).val(''); //파일명 지우기
return;
}
//이미지 미리보기 처리
let reader = new FileReader();
reader.readAsDataURL(my_photo);
reader.onload=function(){
$('.my-photo').attr('src',reader.result);
};
}); // end of change
//파일 업로드 처리
$('#photo_submit').click(function(){
if($('#upload').val()==''){
alert('파일을 선택하세요!');
$('#upload').focus();
return;
}
//서버에 전송할 파일 선택
let form_data = new FormData();
form_data.append('upload', my_photo);
//서버와의 통신
$.ajax({
url:'../member/updateMyPhoto',
type:'post',
data:form_data, //문자열이 아닌 변수로 명시했기 때문에 ''가 없음
dataType:'json',
contentType:false,
processData:false,
success:function(param){
if(param.result == 'logout'){
alert('로그인 후 사용하세요');
}else if(param.result == 'success'){
alert('프로필 사진이 수정되었습니다.');
//교체된 이미지를 저장해서 변심 시(원상복귀 할 경우) 저장된 파일로 원상복귀 하게끔 함
photo_path = $('.my-photo').attr('src');
//초기화
$('#upload').val('');
$('#photo_choice').hide();
$('#photo_btn').show();
}else {
alert('파일 전송 오류 발생');
}
},
error:function(){
alert('네트워크 오류 발생');
}
});
});//end of click - 파일 전송
//취소 버튼 처리
$('#photo_reset').click(function(){
$('.my-photo').attr('src',photo_path); //취소 버튼 click시 원래 이미지로 돌아가기
$('#upload').val('');
$('#photo_choice').hide();
$('#photo_btn').show();
});//end of click - 취소 버튼 처리
});
1.
let photo_path = $('.my-photo').attr('src');
my-photo의 src 속성을 가져와서 photo_path에 담기
2.
contentType은 보내는 데이터의 타입이다.
application/json; charset-utf-8이 흔히 쓰인다.
디폴트는 application/x-www-form-urlencoded; charset=utf-8 이다.
dataType은 서버에서 어떤 타입을 받을 것인지를 의미한다.
json, html, text 등등...
jQuery가 이것을 이용해 success나 done 함수의 파라미터로 받아 처리한다.
Ajax 요청에서 dataType 과 contentType은 뭐가 다른걸까? (velog.io)
Ajax 요청에서 dataType 과 contentType은 뭐가 다른걸까?
이 글은 stackoverflow 의 글을 해석한 글입니다. 출처 https://stackoverflow.com/questions/18701282/what-is-content-type-and-datatype-in-an-ajax-request/18701357다음
velog.io
=============================
여기까지 수행 후 사진 미리보기 후 취소 버튼 누르면 기본 이미지로 되는 것까지 되어야 함
Mapper에 sql문 추가 작성
MemberMapper.java
//자동 로그인
public void updateAu_id(String au_id, int mem_num);
public void selectAu_id(String au_id);
public void deleteAu_id(int mem_num);
//프로필 이미지 업데이트
@Update("UPDATE spmember_detail SET photo=#{photo},photo_name=#{photo_name} WHERE mem_num=#{mem_num}")
public void updateProfile(MemberVO member);
위 구문 복사해서 MemberService.java에도 붙여넣기 (updateProfile 어노테이션은 삭제)
--> 붙여 넣으면 Serviceimpl 에도 자동으로 에러가 나는데 unimplements 누르면 자동으로 메서드 생기면서 에러 없어짐
MemberServiceImpl
@Override
public void updateProfile(MemberVO member) {
memberMapper.updateProfile(member);
}
MemberAjaxController
/*=======================
* 프로필 사진 업로드
*======================= */
@RequestMapping("/member/updateMyPhoto")
@ResponseBody
public Map<String,String> processProfile(MemberVO memberVO,HttpSession session){
Map<String,String> mapAjax = new HashMap<String,String>();
//로그인 유무 체크 후 처리
MemberVO user = (MemberVO)session.getAttribute("user");
if(user==null) {
mapAjax.put("result", "logout");
}else {
memberVO.setMem_num(user.getMem_num());
memberService.updateProfile(memberVO);
mapAjax.put("result", "success");
}
return mapAjax;
}
============================
restart 후 my페이지에서 사진 업로드하면
photo (null) -> (blob)
photo_name (null) -> (파일이름.jpg)
라고 오라클 변경됨 (정상 실행 됐을 때에)
=============================
MemberVO 를 보면
public void setUpload(MultipartFile upload) 라고 upload라 지정했기 때문에 반드시 이름을 upload로 지정해야함
그래서 member.profile을 보면 파일 업로드 처리 시 form_data.append('upload', my_photo) 라고 upload 이름으로 넘기고 있음
<db저장 후 페이지에도 보이게 출력하기>
데이터가 db에는 들어갔지만 저장 후 page에 들어가진 않음 호출하는 방법을 해볼것
++
이전에 기본 이미지 본다고 nav_mypage에 주석처리 했던 구문 정상적으로 바꾸기
ServiceImpl의 selectMember가 이미 작성이 되어 있고 이걸 사용할 거임
컨트롤러에서 호출
MemberController
/*=======================
* 프로필 사진 출력
*======================= */
//1. 프로필 사진 출력(로그인 전용)
//2. 프로필 사진 출력(회원번호 지정)
//3. 프로필 사진 처리를 위한 공통 코드 (1,2에 사용됨)
//4. 기본 이미지 읽기 (1,2에 사용됨)
public void getBasicProfileImage(HttpServletRequest request, Model model) {
}
}
nav_mypage의 /member/photoView가 저장된 파일을 읽어오게 함
src/main/java
kr.spring.util (package)
FileUtil (class)
package kr.spring.util;
import java.io.FileInputStream;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class FileUtil {
public static byte[] getBytes(String path) {
FileInputStream fis = null;
byte[] readbyte = null;
try {
fis = new FileInputStream(path);
readbyte = new byte[fis.available()];
fis.read(readbyte);
}catch(Exception e) {
log.error(e.toString());
}finally {
if(fis!=null)try {fis.close();}catch(IOException e) {}
}
return readbyte;
}
}
본래 이미지가 static안에 있지만 request.getServletContext().getRealPath를 이용해서 읽어오게 된다면
webapp에 읽어와지기 때문에 경로를 추가해야함
정리 >> (db에 올리는 것이 아닌) context경로 상에서 파일을 읽어올 때는 webapp밑에 있는걸 읽어오기 때문에 경로가 다름!!!!
webapp
image_bundle (folder) 생성하고
face.png 복사해서 저 안에 넣기
MemberController
/*=======================
* 프로필 사진 출력
*======================= */
//1. 프로필 사진 출력(로그인 전용)
@RequestMapping("/member/photoView")
public String getProfile(HttpSession session, HttpServletRequest request, Model model) {
MemberVO user = (MemberVO)session.getAttribute("user");
log.debug("<<프로필 사진 읽기>> : " + user);
if(user==null) { //로그인이 되지 않은 경우
getBasicProfileImage(request, model);
}else { //로그인된 경우
MemberVO memberVO = memberService.selectMember(user.getMem_num());
viewProfile(memberVO, request, model);
}
return "imageView";
}
//2. 프로필 사진 출력(회원번호 지정)
//3. 프로필 사진 처리를 위한 공통 코드 (1,2에 사용됨)
public void viewProfile(MemberVO memberVO, HttpServletRequest request, Model model) {
if(memberVO==null || memberVO.getPhoto_name()==null) {
//업로드한 프로필 사진 정보가 없어서 기본 이미지 표시
getBasicProfileImage(request, model);
}else {//업로드한 이미지 읽기
model.addAttribute("imageFile", memberVO.getPhoto());
model.addAttribute("filename", memberVO.getPhoto_name());
}
}
//4. 기본 이미지 읽기 (1,2에 사용됨)
public void getBasicProfileImage(HttpServletRequest request, Model model) {
//바이트 배열로 변환해서 읽어오기
byte[] readbyte = FileUtil.getBytes(request.getServletContext().getRealPath("/image_bundle/face.png"));
model.addAttribute("imageFile", readbyte);
model.addAttribute("filename", "face.png");
}
mbox에서 선생님이 공유해준 imageView 다운받기
src/main/java
kr.spring.view (package) 생성 후 붙여넣기
=============================
byte[] 을 읽어들여서 string으로 변환, 전송해주는 view임
그럼 이제 mypage로 가보면 기본 이미지에서 저장했던 이미지로 화면 출력됨
<header에 프로필 미리보기 추가>
header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 상단 시작 -->
<h2 class="align-center">SpringPage</h2>
<div class="align-right">
<c:if test="${!empty user}">
<a href="${pageContext.request.contextPath}/member/myPage">MY페이지</a>
<img src="${pageContext.request.contextPath}/member/photoView" width="25" height="25" class="my-photo">
</c:if>
<c:if test="${!empty user && !empty user.nick_name}">
[<span class="user_name">${user.nick_name}</span>]
</c:if>
<c:if test="${!empty user && empty user.nick_name}">
[<span class="user_name">${user.id}</span>]
</c:if>
<c:if test="${!empty user}">
<a href="${pageContext.request.contextPath}/member/logout">로그아웃</a>
</c:if>
<c:if test="${empty user}">
<a href="${pageContext.request.contextPath}/member/registerUser">회원가입</a>
<a href="${pageContext.request.contextPath}/member/login">로그인</a>
</c:if>
<c:if test="${empty user || user.auth != 9}">
<a href="${pageContext.request.contextPath}/main/main">홈으로</a>
</c:if>
<c:if test="${!empty user && user.auth == 9}">
<a href="${pageContext.request.contextPath}/main/admin">관리자</a>
</c:if>
</div>
<!-- 상단 끝 -->
프로필 update 순서
자바빈 메서드 byte[] 설정 ->
Member.profile.js 미리보기 처리 ->
MemberAjaxController
Map으로 받아서 ajax통신 / jackson lib사용
->memberVO 저장 ->
service ->mapper.java
<게시판 처리>
sql
table.sql
--게시판
create table spboard(
board_num number not null,
title varchar2(90) not null,
content clob not null,
hit number(8) default 0 not null,
reg_date date default sysdate not null,
modify_date date,
ip varchar2(40) not null,
mem_num number not null,
constraint spboard_pk primary key (board_num),
constraint spboard_fk foreign key (mem_num) references spmember (mem_num)
);
create sequence spboard_seq;
VO생성
kr.spring.board.vo (package)
BoardVO
package kr.spring.board.vo;
import java.sql.Date;
import javax.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@ToString
@Setter
@Getter
public class BoardVO {
private int board_num;
@NotBlank
private String title;
@NotBlank
private String content;
private int hit;
private Date reg_date;
private Date modify_date;
private String ip;
private int mem_num; //작성자
private String id;
private String nick_name;
private int re_cnt; //댓글 개수
private int fav_cnt; //좋아요 개수
}
validation.properties
#게시판
NotBlank.title=제목은 필수
NotBlank.content=내용은 필수
kr.spring.board.dao (package)
BoardMapper (interface)
package kr.spring.board.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
import kr.spring.board.vo.BoardVO;
@Mapper
public interface BoardMapper {
//부모글
public List<BoardVO> selectList(Map<String,Object> map);
public int selectRowCount(Map<String,Object> map);
public void insertBoard(BoardVO board);
public BoardVO selectBoard(int board_num); //한 건의 레코드 반환
public void updateHit(int board_num);
public void updateBoard(BoardVO board);
public void deleteBoard(int board_num);
//좋아요
//댓글
}
kr.spring.board.service
BoardService (interface)
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import kr.spring.board.vo.BoardVO;
public interface BoardService {
//부모글
public List<BoardVO> selectList(Map<String,Object> map);
public int selectRowCount(Map<String,Object> map);
public void insertBoard(BoardVO board);
public BoardVO selectBoard(int board_num); //한 건의 레코드 반환
public void updateHit(int board_num);
public void updateBoard(BoardVO board);
public void deleteBoard(int board_num);
//좋아요
//댓글
}
kr.spring.board.service
BoardServiceImpl (class)
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import kr.spring.board.dao.BoardMapper;
import kr.spring.board.vo.BoardVO;
@Service
@Transactional
public class BoardServiceImpl implements BoardService{
@Autowired
private BoardMapper boardMapper;
@Override
public List<BoardVO> selectList(Map<String, Object> map) {
// TODO Auto-generated method stub
return null;
}
@Override
public int selectRowCount(Map<String, Object> map) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void insertBoard(BoardVO board) {
// TODO Auto-generated method stub
}
@Override
public BoardVO selectBoard(int board_num) {
// TODO Auto-generated method stub
return null;
}
@Override
public void updateHit(int board_num) {
// TODO Auto-generated method stub
}
@Override
public void updateBoard(BoardVO board) {
// TODO Auto-generated method stub
}
@Override
public void deleteBoard(int board_num) {
// TODO Auto-generated method stub
}
}
kr.spring.board.controller
BoardController
package kr.spring.board.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import kr.spring.board.service.BoardService;
import lombok.extern.slf4j.Slf4j;
@Controller
@Slf4j
public class BoardController {
@Autowired
private BoardService boardService;
/*===========================
* 게시판 글 목록
* ==========================*/
@RequestMapping("/board/list")
public ModelAndView process(@RequestParam(value="pageNum",defaultValue="1") int currentPage, String keyfield, String keyword) {
Map<String,Object> map = new HashMap<String,Object>();
ModelAndView mav = new ModelAndView();
return mav;
}
}