ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Camel][Spring] 게시판 만들기 #12. 회원정보 변경
    Spring/게시판 만들기 2020. 7. 6. 03:00

    [Camel][Spring] 게시판 만들기 #12. 회원정보 변경

     

    본 게시판 만들기 프로젝트는 더블에스 Devlog Spring-MVC 를 참조하여 작성했음을 알려드립니다. 또한 개인적인 학습을 목적으로한 포스팅이기 때문에 완벽하지 않을 수 있음을 알려드립니다. 문제점이나 궁금한점은 댓글로 남겨주시면 감사하겠습니다. 프로젝트 생성에 앞서 이번 게시판 만들기 프로젝트는 이클립스를 사용하여 구현하였습니다.

     

    이번 포스팅에서는 회원 정보(프로필) 변경 기능을 구현하겠습니다. 회원 이미지 또한 변경가능한 기능을 구현하기 위해 이전에 사용했었던 파일업로드와 연관되어 있음을 미리 알려드립니다. 

     

     

    1. 회원 정보Persistence 계층 작성

    회원 정보 수정 처리관련 내용을 처리하기 위해 UserDAO 인터페이스에 추상메소드를 추가하고, UserDAOImpl 클래스에 메소드들을 오버라이딩하여 구현해주겠습니다. 

    // 회원정보 수정처리
    public void updateUser(UserVO userVO) throws Exception;
    
    // 회원 비밀번호
    public UserVO getUser(String uid) throws Exception;
    
    // 회원비밀번호 수정처리
    public void updatePw(UserVO userVO) throws Exception;
    
    // 회원 프로필 사진 수정
    public void updateUimage(String uid, String uimage) throws Exception;
    // 회원 비밀번호
    @Override
    public UserVO getUser(String userId) throws Exception {
    	return sqlSession.selectOne(NAMESPACE + ".getUser", userId);
    }
    
    // 회원정보 수정처리
    @Override
    public void updateUser(UserVO userVO) throws Exception {
    	sqlSession.update(NAMESPACE + ".updateUser", userVO);
    }
    
    // 회원비밀번호 수정처리
    @Override
    public void updatePw(UserVO userVO) throws Exception {
    	sqlSession.update(NAMESPACE + ".updatePw", userVO);
    }
    
    // 회원 프로필 사진 수정
    @Override
    public void updateUimage(String userId, String userImg) throws Exception {
    	Map<String, Object> paramMap = new HashMap<String, Object>();
    	paramMap.put("userId", userId);
    	paramMap.put("userImg", userImg);
    	sqlSession.update(NAMESPACE + ".updateUimage", paramMap);
    }

    이어서 userMapper.xml에 회원 정보 관련 SQL문을 추가해주겠습니다. 

    	<!--회원 정보 수정-->
        <update id="updateUser">
            UPDATE tb_user
            SET
                user_name = #{userName}
                , user_email =  #{userEmail}
            WHERE user_id = #{userId}
        </update>
    
        <!--회원 비밀번호-->
        <select id="getUser" resultMap="userVOResultMap">
            SELECT *
            FROM tb_user
            WHERE user_id = #{userId}
        </select>
    
        <!--회원비밀번호 수정-->
        <update id="updatePw">
            UPDATE tb_user
            SET
                user_pw = #{userPw}
            WHERE user_id = #{userId}
        </update>
    
        <!--회원 프로필 이미지 변경-->
        <update id="updateUimage" >
            UPDATE tb_user
            SET
                user_img = #{userImg}
            WHERE user_id = #{userId}
        </update>

     

     

    2. Service 계층 작성

    회원 정보 수정 처리관련 내용을 처리하기 위해 UserService 인터페이스에 추상메소드를 추가하고, UserServiceImpl 클래스에 메소드들을 오버라이딩하여 구현해주겠습니다. 

    // 회원정보 수정처리
    public void modifyUser(UserVO userVO) throws Exception;
    
    // 회원 정보
    public UserVO getUser(String uid) throws Exception;
    
    // 회원비밀번호 수정처리
    public void modifyPw(UserVO userVO) throws Exception;
    
    // 회원 프로필 사진 수정
    public void modifyUimage(String uid, String uimage) throws Exception;
    // 회원 비밀번호
    @Override
    public UserVO getUser(String userId) throws Exception {
    	return userDAO.getUser(userId);
    }
    
    // 회원정보 수정처리
    @Override
    public void modifyUser(UserVO userVO) throws Exception {
    	userDAO.updateUser(userVO);
    }
    
    // 회원비밀번호 수정처리
    @Override
    public void modifyPw(UserVO userVO) throws Exception {
    	userDAO.updatePw(userVO);
    }
    
    // 회원 프로필 사진 수정
    @Override
    public void modifyUimage(String userId, String userImg) throws Exception {
    	userDAO.updateUimage(userId, userImg);
    }

     

    3. UserInfoController 작성

     이전에 로그인 기능을 구현할 때와 마찬가지로 User관련 URI를 통합해서 하나의 컨트롤러에 전부 매핑시키는 것도 가능하지만, 코드가 많아지고 구분이 어려워지기 때문에 회원 정보 처리만을 매핑하는 컨트롤러를 따로 만들어 사용하겠습니다. 

    package com.cameldev.mypage.controller;
    
    
    import org.apache.commons.fileupload.FileUploadException;
    import org.mindrot.jbcrypt.BCrypt;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Controller;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    import org.springframework.web.servlet.mvc.support.RedirectAttributes;
    import org.springframework.web.util.WebUtils;
    
    import com.cameldev.mypage.commons.util.UploadFileUtils;
    import com.cameldev.mypage.domain.ArticleVO;
    import com.cameldev.mypage.domain.ReplyVO;
    import com.cameldev.mypage.domain.UserVO;
    import com.cameldev.mypage.service.ArticleService;
    import com.cameldev.mypage.service.ReplyService;
    import com.cameldev.mypage.service.UserService;
    
    import javax.annotation.Resource;
    import javax.inject.Inject;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.io.IOException;
    import java.util.Date;
    import java.util.List;
    @Controller
    @RequestMapping("/user")
    public class UserInfoController {
    	
    	private static final Logger logger = LoggerFactory.getLogger(UserInfoController.class);
    	
    	@Inject
        private UserService userService;
    
        @Inject
        private ArticleService articleService;
    
        @Inject
        private ReplyService replyService;
    	
    	@Resource(name = "uimagePath")
        private String uimagePath;
    	
    	// 회원 프로필 이미지 수정처리
        @RequestMapping(value = "/modify/image", method = RequestMethod.POST)
        public String userImgModify(String userId,
                                    MultipartFile file,
                                    HttpSession session,
                                    RedirectAttributes redirectAttributes) throws Exception {
            if (file == null) {
                redirectAttributes.addFlashAttribute("msg", "FAIL");
                return "redirect:/user/profile";
            }
            String uploadFile = UploadFileUtils.uploadFile(uimagePath, file.getOriginalFilename(), file.getBytes());
            String front = uploadFile.substring(0, 12);
            String end = uploadFile.substring(14);
            String userImg = front + end;
            userService.modifyUimage(userId, userImg);
            Object userObj = session.getAttribute("login");
            UserVO userVO = (UserVO) userObj;
            userVO.setUserImg(userImg);
            session.setAttribute("login", userVO);
            redirectAttributes.addFlashAttribute("msg", "SUCCESS");
            return "redirect:/user/profile";
        }
    
        // 회원정보 수정처리
        @RequestMapping(value = "/modify/info", method = RequestMethod.POST)
        public String userInfoModify(UserVO userVO, HttpSession session,
                                     RedirectAttributes redirectAttributes) throws Exception {
        	logger.info(userVO.toString());
            UserVO oldUserInfo = userService.getUser(userVO.getUserId());
            logger.info(oldUserInfo.toString());
            logger.info("1");
            if (!BCrypt.checkpw(userVO.getUserPw(), oldUserInfo.getUserPw())) {
                redirectAttributes.addFlashAttribute("msg", "FAILURE");
                logger.info("2");
                return "redirect:/user/profile";
            }
            logger.info("3");
            userService.modifyUser(userVO);
            userVO.setUserJoinDate(oldUserInfo.getUserJoinDate());
            userVO.setUserLoginDate(oldUserInfo.getUserLoginDate());
            userVO.setUserImg(oldUserInfo.getUserImg());
            session.setAttribute("login", userVO);
            redirectAttributes.addFlashAttribute("msg", "SUCCESS");
            return "redirect:/user/profile";
        }
    
        // 회원 비밀번호 수정처리
        @RequestMapping(value = "/modify/pw", method = RequestMethod.POST)
        public String userPwModify(@RequestParam("userId") String userId,
                                   @RequestParam("oldPw") String oldPw,
                                   @RequestParam("newPw") String newPw,
                                   HttpSession session,
                                   RedirectAttributes redirectAttributes) throws Exception {
            UserVO userInfo = userService.getUser(userId);
            if (!BCrypt.checkpw(oldPw, userInfo.getUserPw())) {
                redirectAttributes.addFlashAttribute("msg", "FAILURE");
                return "redirect:/user/profile";
            }
            String newHashPw = BCrypt.hashpw(newPw, BCrypt.gensalt());
            userInfo.setUserPw(newHashPw);
            userService.modifyPw(userInfo);
            session.setAttribute("login", userInfo);
            redirectAttributes.addFlashAttribute("msg", "SUCCESS");
            return "redirect:/user/profile";
        }
    
        // 회원 정보 페이지
        @RequestMapping(value = "/profile", method = RequestMethod.GET)
        public String profile(HttpSession session, Model model) throws Exception {
    
            Object userObj = session.getAttribute("login");
            UserVO userVO = (UserVO) userObj;
            String userId = userVO.getUserId();
            List<ArticleVO> userBoardList = articleService.userBoardList(userId);
            List<ReplyVO> userReplies = replyService.userReplies(userId);
    
            model.addAttribute("userBoardList", userBoardList);
            model.addAttribute("userReplies", userReplies);
    
            return "user/profile";
        }
    }

    컨트롤러의 변수 선언 부분을 확인해보면 uimagePath라는 이미지를 확인할 수 있습니다. 회원 이미지 변경시에도 파일 업로드와 같이 서버에 파일을 전송하고 출력해주어야하기 때문에 파일업로드 당싱 첨부파일 저장 경로를 설정해주었던 것처럼 회원 이미지를 저장하기위한 경로를 설정해주어야 합니다. 이러한 이유로 root-context.xml 파일에 아래 내용을 추가해주겠습니다. 

    <!--프로필 이미지 파일 저장 경로 설정-->
    <bean id="uimagePath" class="java.lang.String">
      <constructor-arg value="C:\\Users\\cameldev\\eclipse-workspace\\mypage\\src\\main\\webapp\\resources\\dist\\img\\profile">
      </constructor-arg>
    </bean>

    4. 회원 게시물 정보

    위의 Persistence, Service, Controller 작성을 하면서 회원 정보를 보여주는 부분이 있음을 확인할 수 있었습니다. 회원 정보 페이지에서는 로그인한 회원이 작성한 글들의 목록을 확인할 수 있으며, 회원이 작성한 댓글또한 확인할 수 있도록 구현하고자 합니다. 

     회원이 작성한 게시글 목록을 가져오기 위해 게시글의 Persistence 계층과 Service 계층 그리고 컨트롤러에 아래의 내용을 추가해주겠습니다. 또한 회원 프로필 사진 수정과 관련된 내용도 이곳에 추가해주겠습니다. 

    4-1. ArticleDAO, ArticleDAOImpl 수정

    // 회원이 작성한 게시글 목록
    List<ArticleVO> userBoardList(String userId) throws Exception;
    
    // 회원 프로필 사진 수정
    void updateWriterImg(ArticleVO articleVO) throws Exception;
    // 회원이 작성한 게시글 목록
    @Override
    public List<ArticleVO> userBoardList(String userId) throws Exception {
    	return sqlSession.selectList(NAMESPACE + ".userBoardList", userId);
    }
    
    // 회원 프로필 사진 수정
    @Override
    public void updateWriterImg(ArticleVO articleVO) throws Exception {
    	sqlSession.update(NAMESPACE + ".updateWriterImg", articleVO);
    }

    4-2. ArticleService, ArticleServiceImpl 수정

    List<ArticleVO> userBoardList(String uid) throws Exception;
    // 회원이 작성한 게시글 목록
    @Override
    public List<ArticleVO> userBoardList(String uid) throws Exception {
    	return articleDAO.userBoardList(uid);
    }

    추가적으로 게시글 작성시 작성자의 회원이미지가 반영될 수 있도록 ArticleServiceImpl 클래스의 create 메소드의 내부를 아래와 같이 수정해주도록 하겠습니다 .

    @Transactional
    @Override
    public void create(ArticleVO articleVO) throws Exception {
     
      String[] files = articleVO.getFiles();  
    
      if (files == null) {
        articleDAO.create(articleVO);
        articleDAO.updateWriterImg(articleVO); // 추가
        return;
      }
      articleVO.setFileCnt(files.length);
    
      articleDAO.create(articleVO);
      articleDAO.updateWriterImg(articleVO);   //추가
      Integer article_no = articleVO.getArticle_no();
      
      for (String fileName : files) {
        articleFileDAO.addAttach(fileName, article_no);
      }
    
    }

     

    이 과정에서 추가적으로 작성해야하는 부분을 알아차리셨을지 모르겠습니다. 그것은 바로 작성자의 이미지를 저장하기 위해서는 데이터베이스에 writerImg이라는 column을 추가하고 ArticleVO에도 멤버변수를 추가해야한다는 것입니다. 작성자 이미지의 경우 User 테이블에서 가져와야하기 때문에 ArticleVO에 UserVO 객체 또한 멤버변수로 선언해주겠습니다. 

    private String writerImg;
        
    private UserVO userVO;
    
    public UserVO getUserVO() {
    	return userVO;
    }
    
    public void setUserVO(UserVO userVO) {
    	this.userVO = userVO;
    }
    
    public String getWriterImg() {
    	return writerImg;
    }
    
    public void setWriterImg(String writerImg, UserVO userVO) {
    	writerImg = userVO.getUserImg();
    	this.writerImg = writerImg;
    }

    이어서 articleMapper.xml에 위의 과정을 수행하기 위한 SQL문을 추가해주겠습니다. 

    <!--회원 프로필 이미지 변경-->
    <update id="updateWriterImg" >
      UPDATE tb_article
      SET
      writerImg = (SELECT user_img FROM tbl_user WHERE user_id = #{writer})
      WHERE article_no = #{article_no}
    </update>
    
    <select id="userBoardList" resultType="ArticleVO">
      SELECT
      *
      FROM tb_article
      WHERE writer = #{userId}
      ORDER BY article_no DESC, reg_date DESC
    </select>
    
    <resultMap id="ArticleResultMap" type="ArticleVO">
      <id property="article_no" column="article_no"/>
      <result property="title" column="title" />
      <result property="content" column="content" />
      <result property="writer" column="writer" />
      <result property="regDate" column="regdate" />
      <result property="viewCnt" column="viewcnt" />
      <result property="replyCnt" column="reply_cnt" />
      <result property="fileCnt" column="file_cnt" />
      <result property="writerImg" column="writerImg" />
      <association property="userVO" resultMap="userVOResultMap"/>   <!-- 추가 -->
    </resultMap>
    
     <!-- 추가 -->
    <resultMap id="userVOResultMap" type="UserVO">
      <id property="userId" column="user_id"/>
      <result property="userPw" column="user_pw"/>
      <result property="userName" column="user_name"/>
      <result property="userEmail" column="user_email"/>
      <result property="userJoinDate" column="user_join_date"/>
      <result property="userLoginDate" column="user_login_date"/>
      <result property="userSignature" column="user_signature"/>
      <result property="userImg" column="user_img"/>
      <result property="userPoint" column="user_point"/>
    </resultMap>

     

     

    5. 회원 댓글 정보

    회원이 작성한 댓글 목록을 가져오기 위해 게시글의 Persistence 계층과 Service 계층 그리고 컨트롤러에 아래의 내용을 추가해주겠습니다.

    4-1. ReplyDAO, ReplyDAOImpl 수정

    // 회원이 작성한 댓글 목록
    List<ReplyVO> userReplies(String userId) throws Exception;
    // 회원이 작성한 댓글 목록
    @Override
    public List<ReplyVO> userReplies(String userId) throws Exception {
    	return sqlSession.selectList(NAMESPACE + ".userReplies", userId);
    }

    4-1. replyMpper.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="com.cameldev.mypage.mappers.reply.ReplyMapper">
    	
    	<select id="list" resultMap="ReplyResultMap">
            SELECT
              reply_no
              , article_no
              , reply_text
              , reply_writer
              , reg_date
              , update_date
            FROM tb_reply
            WHERE article_no = #{article_no}
            ORDER BY reply_no
        </select>
    	
    	<select id="listPaging" resultMap="ReplyResultMap">
    	    SELECT
    	        *
    	    FROM tb_reply
    	    INNER JOIN tb_user ON user_id = reply_writer
    	    WHERE article_no = #{article_no}
    	    ORDER BY reply_no DESC
    	    LIMIT #{criteria.pageStart}, #{criteria.perPageNum}
    	</select>
    	
        <insert id="create">
            INSERT INTO tb_reply (
                article_no
                , reply_text
                , reply_writer
            ) VALUES (
                #{article_no}
                , #{reply_text}
                , #{reply_writer}
            )
        </insert>
    
        <update id="update">
            UPDATE tb_reply
            SET
                reply_text = #{reply_text}
                , update_date = NOW()
            WHERE reply_no = #{reply_no}
        </update>
    
        <delete id="delete">
            DELETE FROM tb_reply
            WHERE reply_no = #{reply_no}
        </delete>
        
        
    
    	<select id="countReplies" resultType="int">
    	    SELECT
    	        COUNT(article_no)
    	    FROM tb_reply
    	    WHERE article_no = #{article_no}
    	</select>
    	
    	<select id="getArticleNo" resultType="int">
    	    SELECT
    	        article_no
    	    FROM tb_reply
    	    WHERE reply_no = #{reply_no}
    	</select>
    	
    	<!--회원이 작성한 댓글 목록-->
        <select id="userReplies" resultMap="ReplyResultMap">
            SELECT
                r.reply_text
                , r.reg_date
                , a.title
                , a.article_no
            FROM tb_reply r
                LEFT OUTER JOIN tb_article a
                    ON a.article_no = r.article_no
            WHERE reply_writer = #{userId}
        </select>
    
        <resultMap id="ReplyResultMap" type="ReplyVO">
            <id property="reply_no" column="reply_no"/>
            <result property="article_no" column="article_no"/>
            <result property="reply_text" column="reply_text"/>
            <result property="reply_writer" column="reply_writer"/>
            <result property="reg_date" column="reg_date"/>
            <result property="update_date" column="update_date"/>
            <association property="userVO" resultMap="userVOResultMap"/>
            <association property="articleVO" resultMap="ArticleResultMap"/>
        </resultMap>
    
        <resultMap id="ArticleResultMap" type="ArticleVO">
            <id property="article_no" column="article_no"/>
            <result property="title" column="title" />
            <result property="content" column="content" />
            <result property="writer" column="writer" />
            <result property="regDate" column="regdate" />
            <result property="viewCnt" column="viewcnt" />
            <result property="replyCnt" column="reply_cnt" />
            <result property="fileCnt" column="file_cnt" />
            <result property="writerImg" column="writerImg" />
            <association property="userVO" resultMap="userVOResultMap"/>
        </resultMap>
       
    	<resultMap id="userVOResultMap" type="UserVO">
            <id property="userId" column="user_id"/>
            <result property="userPw" column="user_pw"/>
            <result property="userName" column="user_name"/>
            <result property="userEmail" column="user_email"/>
            <result property="userJoinDate" column="user_join_date"/>
            <result property="userLoginDate" column="user_login_date"/>
            <result property="userSignature" column="user_signature"/>
            <result property="userImg" column="user_img"/>
            <result property="userPoint" column="user_point"/>
        </resultMap>
        
    </mapper>

    4-2. ReplyService, ReplyServiceImpl 수정

    // 회원이 작성한 댓글 목록
    List<ReplyVO> userReplies(String userId) throws Exception;
    // 회원이 작성한 댓글 목록
    @Override
    public List<ReplyVO> userReplies(String userId) throws Exception {
    	return replyDAO.userReplies(userId);
    }

     

     

    5. 회원 프로필 출력 페이지(profile.jsp) 작성

    로그인을 실행한 후 우측 상단의 드랍박스를 클릭하면 보여지는 내 프로필 버튼을 클릭할 시 보여지는 회원 프로필 페이지를 작성하겠습니다. 기존의 페이지들과 동일하게 home.jsp의 내용을 복사해주겠습니다. include 태그의 경우는 이제 알맞게 수정하실 수 있다고 생각하고 자세한 내용은 생략하겠습니다. 

     메인 콘텐츠 부분에는 아래의 코드를 추가해주겠습니다.

    <div class="container-fluid">
    <div class="row">
    <div class="col-md-5">
    <div class="card card-primary card-outline">
    <div class="card-body box-profile">
    <div class="text-center">
    <img class="profile-user-img img-fluid img-circle"
    src="${path}/dist/img/profile/${login.userImg}"
    alt="User profile picture">
    </div>
    
    <h3 class="profile-username text-center">${login.userName}</h3>
    
    <div class="text-center">
    <a href="#" class="btn btn-primary btn-xs" data-toggle="modal"
    data-target="#userPhotoModal"> <i class="fa fa-photo">
    프로필사진 수정</i>
    </a>
    </div>
    <ul class="list-group list-group-unbordered mb-5">
    <li class="list-group-item"><b>아이디</b> <a
    class="float-right">${login.userId}</a></li>
    <li class="list-group-item"><b>이메일</b> <a
    class="float-right">${login.userEmail}</a></li>
    <li class="list-group-item"><b>가입일자</b> <a
    class="float-right"> <fmt:formatDate
    value="${login.userJoinDate}" pattern="yyyy-MM-dd" />
    </a></li>
    <li class="list-group-item"><b>최근 로그인 일자</b> <a
    class="float-right"> <fmt:formatDate
    value="${login.userLoginDate}" pattern="yyyy-MM-dd" />
    
    </a></li>
    </ul>
    </div>
    <div class="card-footer text-center">
    <a href="#" class="btn btn-primary btn-xs" data-toggle="modal"
    data-target="#userInfoModal"> <i class="fa fa-info-circle">
    회원정보 수정</i>
    </a> <a href="#" class="btn btn-primary btn-xs" data-toggle="modal"
    data-target="#userPwModal"> <i
    class="fa fa-question-circle"> 비밀번호 수정</i>
    </a> <a href="#" class="btn btn-primary btn-xs" data-toggle="modal"
    data-target="#userOutModal"> <i class="fa fa-user-times">
    회원 탈퇴</i>
    </a>
    </div>
    </div>
    </div>
    
    <div class="col-md-7">
    <div class="card">
    <div class="nav-tabs-custom">
    <div class="card-header p-2">
    <ul class="nav nav-pills">
    <li class="nav-item">
    <a class="nav-link active" href="#myPosts" data-toggle="tab">
    <i class="fas fa-pencil-square-o"></i> 나의 게시물
    </a>
    </li>
    <li class="nav-item">
    <a class="nav-link" href="#myReplies" data-toggle="tab">
    <i class="fas fa-comment-o"></i> 나의 댓글
    </a>
    </li>										
    </ul>
    </div>
    <div class="card-body">
    <div class="tab-content">
    <div class="active tab-pane" id="myPosts">
    <table id="myPostsTable"
    class="table table-bordered table-striped">
    <thead>
    <tr>
    <th style="width: 10%">번호</th>
    <th style="width: 70%">제목</th>
    <th style="width: 20%">작성일자</th>
    </tr>
    </thead>
    <tbody>
    <c:forEach var="articleVO" varStatus="i"
    items="${userBoardList}">
    <tr>
    <td>${i.index + 1}</td>
    <td><a
    href="${path}/article/paging/search/read?article_no=${articleVO.article_no}">
    <c:choose>
    <c:when test="${fn:length(articleVO.title) > 30}">
    <c:out value="${fn:substring(articleVO.title, 0, 29)}" />....
    </c:when>
    <c:otherwise>
    <c:out value="${articleVO.title}" />
    </c:otherwise>
    </c:choose>
    </a></td>
    <td><fmt:formatDate pattern="yyyy-MM-dd"
    value="${articleVO.regDate}" /></td>
    </tr>
    </c:forEach>
    </tbody>
    </table>
    </div>
    <div class="tab-pane" id="myReplies">
    <table id="myRepliesTable"
    class="table table-bordered table-striped">
    <thead>
    <tr>
    <th style="width: 10px">번호</th>
    <th style="width: 250px">게시글 제목</th>
    <th style="width: 250px">내용</th>
    <th style="width: 150px">작성일자</th>
    </tr>
    </thead>
    <tbody>
    <c:forEach var="userReply" varStatus="i"
    items="${userReplies}">
    <tr>
    <td>${i.index + 1}</td>
    <td><a
    href="${path}/article/paging/search/read?article_no=${userReply.articleVO.article_no}">
    <c:choose>
    <c:when
    test="${fn:length(userReply.articleVO.title) > 10}">
    <c:out
    value="${fn:substring(userReply.articleVO.title, 0, 9)}" />....
    </c:when>
    <c:otherwise>
    <c:out value="${userReply.articleVO.title}" />
    </c:otherwise>
    </c:choose>
    </a></td>
    <td><c:choose>
    <c:when test="${fn:length(userReply.reply_text) > 10}">
    <c:out
    value="${fn:substring(userReply.reply_text, 0, 9)}" />....
    </c:when>
    <c:otherwise>
    <c:out value="${userReply.reply_text}" />
    </c:otherwise>
    </c:choose></td>
    <td><fmt:formatDate pattern="yyyy-MM-dd"
    value="${userReply.reg_date}" /></td>
    </tr>
    </c:forEach>
    </tbody>
    </table>
    </div>
    </div>
    </div>
    
    </div>
    </div>
    </div>
    
    </div>
    </div>

    Script 코드는 아래와 같습니다.

    <script src="${path}/plugins/datatables/js/jquery.dataTables.min.js"></script>
    <script src="${path}/plugin/datatables-bs4/js/dataTables.bootstrap4.min.js"></script>
    <script>
        $(document).ready(function () {
        	
            var msg = "${msg}";
            if (msg == "FAILURE") {
                alert("비밀번호가 일치하지 않습니다. 비밀번호를 확인해주세요");
            } else if (msg == "FAIL") {
                alert("이미지가 존재하지 않습니다.");
            } else if (msg == "SUCCESS") {
                alert("수정되었습니다.");
            }
            // 회원정보 수정
            $(".infoModBtn").on("click", function () {
                $("#userInfoForm").submit();
            });
            // 회원비밀번호 수정
            $(".pwModBtn").on("click", function () {
                $("#userPwForm").submit();
            });
            // 회원 프로필 이미지 수정
            $(".imgModBtn").on("click", function () {
                var file = $("#file").val();
                if (file == "") {
                    alert("파일을 선택해주세요.");
                    return;
                }
                $("#userImageForm").submit();
            });
            var param = {
                "language": {
                    "lengthMenu": "_MENU_ 개씩 보기",
                    "zeroRecords": "내용이 없습니다.",
                    "info": "현재 _PAGE_ 페이지 / 전체 _PAGES_ 페이지",
                    "infoEmpty": "내용이 없습니다.",
                    "infoFiltered": "( _MAX_개의 전체 목록 중에서 검색된 결과)",
                    "search": "검색:",
                    "paging": {
                        "first": "처음",
                        "last": "마지막",
                        "next": "다음",
                        "previous": "이전"
                    }
                }
            };
            $("#myPostsTable").DataTable(param);
            $("#myRepliesTable").DataTable(param);
            $("#myBookmarksTable").DataTable(param);
        });
    </script>

     

    추가적으로 inculde의 main_header.jsp와 left_column.jsp에서 회원 이미지를 보여주는 부분의 코드를 수정해주시면 로그인한 회원의 이미지가 출력되는 것을 확인할 수 있습니다. 뿐만아니라 회원정보테이블에서는 로그인한 사용자가 작성한 게시글과 댓글 또한 확인할 수 있습니다. 

     

     

     

    6. 추가 사항 ( 로그인 일자 갱신)

    6-1. UserDAO

    // UserDAO
    // 로그인 일자 갱신
    public void updateLoginDate(String userId) throws Exception;

    6-2. UserDAOImpl

    // UserDAOImpl
    // 로그인 일자 갱신
    @Override
    public void updateLoginDate(String userId) throws Exception {
    	sqlSession.update(NAMESPACE + ".updateLoginDate", userId);
    }

    6-3. userMapper

    <!--로그인 일자 갱신-->
    <update id="updateLoginDate">
      UPDATE tb_user
      SET user_login_date = NOW()
      WHERE user_id = #{userId}
    </update>

    6-4. UserServiceImpl 

    // UserServiceImpl
    @Override
    public UserVO login(LoginDTO loginDTO) throws Exception {
    	userDAO.updateLoginDate(loginDTO.getUserId()); // 추가
    	return userDAO.login(loginDTO);
    }

     

     

    다시 로그인해보면 로그인 날짜가 갱신된 것을 확인할 수 있습니다. 

     

     

     

    7. 포스팅을 마치며

    이번 포스팅을 마지막으로 게시판 만들기 포스팅이 끝났습니다. 아직 구현하지 못한기능도 많고 구현하고 싶은 기능도 많지만 천천히 추가해나아가면서 시간되는대로 포스팅할 수 있으면 포스팅하도록 하겠습니다. 

     

     

     

     

     

    글을 읽으시면서 잘못된 부분이나 궁금하신 사항은 댓글 달아주시면 빠른 시일내에 수정 및 답변하도록 하겠습니다. 

    댓글

Camel`s Tistory.