Skip to content

공지사항

Gaeun Kim edited this page Feb 26, 2023 · 2 revisions

📌 공지사항

👆🏻 공지사항 메인 페이지


✔️ CRUD

👨‍💻code

NoticeController
    @PostMapping("/admin/write")
    public String writeNotice(CommitMap commitMap, HttpServletRequest request) throws Exception {
        noticeService.writeNotice(commitMap.getMap(), request);
        return "redirect:/notice/list";
    }

공지사항 작성 (C)

    @GetMapping("/detail")
    public ModelAndView getNoticeDetail(CommitMap commitMap, HttpServletRequest request) throws Exception {

        /* 공지사항 상세, 공지사항 수정 페이지에서 getNoticeDetail 메소드 사용. 
        수정 페이지에서만 textarea태그 사이에 content를 넣어주는데 textarea는 br태그를 줄바꿈 태그로 인식 안함. 따라서 데이터를 꺼내올 때 br태그를 개행문자로 바꿔 줄 필요가 있다. 
        (상세에서는 필요X) 상세와 수정을 구분하기 위해 "detail"이라는 구분값을 넣어준다.*/
        Map<String, Object> noticeDetail = noticeService.getNoticeDetail(commitMap.getMap(), request, "detail");
        ModelAndView mv = new ModelAndView("/notice/detail");

        if (noticeDetail.isEmpty()) {
            mv.addObject("msg", "삭제된 게시글입니다.");
            mv.addObject("path", "/notice/list");
            mv.setViewName("/alert/alert");
        } else {
            mv.addObject("detail", noticeDetail.get("detail"));
            mv.addObject("list", noticeDetail.get("list"));

        }
        return mv;
    }

공지사항 상세 (R)

    @PostMapping("/admin/update")
    public ModelAndView updateNotice(CommitMap commitMap, HttpServletRequest request) throws Exception {
        noticeService.updateNotice(commitMap.getMap(), request);
        ModelAndView mv = new ModelAndView("redirect:/notice/detail");
        mv.addObject("NOTICE_IDX", commitMap.get("NOTICE_IDX"));
        return mv;
    }

공지사항 수정 (U)

    @PostMapping("/admin/delete")
    public String deleteNotice(@RequestBody Map<String, Object> map) throws Exception {
        noticeService.deleteNotice(map);
        return "redirect:/notice/list";
    }

공지사항 삭제 (D)

NoticeServiceImpl
    @Override
    public void writeNotice(Map<String, Object> map, HttpServletRequest request) throws Exception {
        
        String originalContent = map.get("CONTENT").toString();
        // 개행 문자 모두 <br>로 변경
        String replaceContent = originalContent.replaceAll(System.lineSeparator(), "<br>");
        map.put("CONTENT", replaceContent);
        //공지사항 등록
        noticeDAO.insertNotice(map);

        List<Map<String, Object>> fileList = fileUtils.parseInsertFileInfo(map, request);

        // 파일을 추가했다면
        if (!fileList.isEmpty()) {
            for (Map<String, Object> file : fileList) {
                // 공지사항 파일 등록
                noticeDAO.insertFile(file);
            }
        }
    }

공지사항 작성 (C)

    @Override
    public Map<String, Object> getNoticeDetail(Map<String, Object> map, HttpServletRequest request, String state) throws Exception {

        map = sessionHelper.make(map, request);

        // 일반 회원일 때만 조회 수 증가
        if (map.get("admin") == null) {
            noticeDAO.updateHitCount(map);
        }
        // 게시글 (게시글 상세 내용과 파일 리스트를 포함한)
        Map<String, Object> notice = new HashMap<>();
        // 게시글 상세
        Map<String, Object> detail = noticeDAO.selectNoticeDetail(map);
        if (detail != null) {
            if (state.equals("update")) {
                // 수정시에만 <br>을 OS에 맞는 개행 문자로 변경
                String originalContent = detail.get("CONTENT").toString();
                String replaceContent = originalContent.replaceAll("<br>", System.lineSeparator());
                detail.put("CONTENT", replaceContent);
            }

            List<Map<String, Object>> fileList = noticeDAO.selectFileList(map);
            notice.put("detail", detail);
            notice.put("list", fileList);
        }
        return notice;
    }

공지사항 상세 (R)

    @Override
    public void updateNotice(Map<String, Object> map, HttpServletRequest request) throws Exception {
        
        String originalContent = map.get("CONTENT").toString();
        // 개행 문자 모두 <br>로 변경
        String replaceContent = originalContent.replaceAll(System.lineSeparator(), "<br>");
        map.put("CONTENT", replaceContent);
        
        // 공지사항 수정
        noticeDAO.updateNotice(map);
        // 공지사항 파일 목록 전부 삭제 처리
        noticeDAO.deleteFileList(map);
        
        List<Map<String, Object>> fileList = fileUtils.parseUpdateFileInfo(map, request);

        for (Map<String, Object> file : fileList) {
            // IS_NEW의 값이 Y면 새로운 파일, N이면 기존 파일
            if (file.get("IS_NEW").equals("Y")) {
                noticeDAO.insertFile(file);
            } else {
                // 기존 파일일경우 DEL(삭제유무)값을 Y에서 N으로 변경
                noticeDAO.updateFile(file);
            }
        }

    }

공지사항 수정 (U)

    @Override
    public void deleteNotice(Map<String, Object> map) throws Exception {
        // 글 삭제
        noticeDAO.deleteNotice(map);
        // 파일 삭제
        noticeDAO.deleteFileList(map);
    }

공지사항 삭제 (D)

Notice_SQL.xml
    -- 공지사항을 등록함과 동시에 파일도 같이 등록해야 하기 때문에 NOTICE_IDX를 selectKey로 꺼내옴.
    -- 파라미터로 들어온 hashmap에 NOTICE_IDX라는 이름으로 꺼내온 selectKey가 다시 담김.(keyProperty="NOTICE_IDX")
    <insert id="insertNotice" parameterType="hashmap"
            useGeneratedKeys="true" keyProperty="NOTICE_IDX">

        <selectKey keyProperty="NOTICE_IDX" resultType="string"
                   order="BEFORE">

            SELECT NOTICE_SEQ.NEXTVAL FROM DUAL

        </selectKey>

        INSERT INTO NOTICE
        (
        NOTICE_IDX,
        TITLE,
        CONTENT
        )
        VALUES
        (
        #{NOTICE_IDX},
        #{TITLE},
        #{CONTENT}
        )

    </insert>

공지사항 작성 (C)

        SELECT NOTICE_IDX,
               TITLE,
               CONTENT,
               TO_CHAR(REG_DATE, 'YYYY-MM-DD') AS REG_DATE,
               HIT,
               DEL
        FROM NOTICE
        WHERE NOTICE_IDX = #{NOTICE_IDX}
          AND DEL = 'N'

공지사항 상세 (R)

        SELECT FILE_IDX,
               ORIGINAL_NAME,
               ROUND(FILE_SIZE / 1024, 1) AS FILE_SIZE
        FROM NOTICE_FILE
        WHERE NOTICE_IDX = #{NOTICE_IDX}
          AND DEL = 'N'

공지사항 상세 - 파일 목록 (R)

        UPDATE NOTICE
        SET TITLE   = #{TITLE},
            CONTENT = #{CONTENT}
        WHERE NOTICE_IDX = #{NOTICE_IDX}

공지사항 수정 (U)

        UPDATE NOTICE
        SET DEL = 'Y'
        WHERE NOTICE_IDX = #{NOTICE_IDX}

공지사항 삭제 (D)

🖥️view

공지사항 상세

✔️ 파일

  • 업로드
  1. Request로 들어온 파일을 MultipartHttpServletRequest로 변환.
  2. multipart 파일들의 파라미터 이름을 Iterator에 담아줌.
  3. 서버의 절대경로를 구해 파일이 저장될 위치 설정.
  4. Iterator에 담긴 파일의 파라미터 이름으로 실제 파일 객체를 가져옴.
  5. 파일 객체가 있다면 DB에 저장될 파일의 이름을 UUID로 랜덤 생성.
  6. 3번에서 지정한 위치에 임시 이름으로 파일 업로드.
  7. selectKey로 뽑아온 공지사항 번호, 파일 원본 이름, 파일 임시 이름등을 DB에 저장.

  • 수정
    - 4번까지는 업로드와 동일하고, 파일을 수정하기 전 해당 게시글의 모든 파일은 삭제처리됨
  1. 실제 파일 객체가 있는지 확인
    5-1. 객체가 있다면 새로 추가한 파일이므로 업로드와 동일하지만 "IS_NEW", "Y"라는 구분값을 추가.
    5-2. 객체가 없다면 map에 'IDX_번호'로 이루어진 key가 있는지 확인 후, 있다면 기존 파일이므로 DEL(삭제유무)값 N으로 변경.
    기존 파일이 남아 있을 경우 map에 "IDX_번호", "파일 인덱스 번호"(="key", "value")가 담겨있다.

👨‍💻code

FileUpload
    public List<Map<String, Object>> parseInsertFileInfo(Map<String, Object> map, HttpServletRequest request) throws Exception {

        MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
        Iterator<String> iterator = multipartHttpServletRequest.getFileNames();
        // 서버의 절대경로를 구해 파일이 저장될 위치 설정.
        String filePath = request.getSession().getServletContext().getRealPath("/") + "static/uploadFile/";
        MultipartFile multipartFile;
        String originalFileName;
        String originalFileExtension;
        String storedFileName;

        List<Map<String, Object>> fileList = new ArrayList<>();
        Map<String, Object> fileInfo;
                           //selectKey로 담긴 NOTICE_IDX
        String noticeIdx = map.get("NOTICE_IDX").toString();

        File file = new File(filePath);
        
        // 해당 폴더가 없다면 생성
        if (!file.exists()) {
            file.mkdirs();
        }

        while (iterator.hasNext()) {
            // 실제 파일 객체를 가져옴
            multipartFile = multipartHttpServletRequest.getFile(iterator.next());
            if (!multipartFile.isEmpty()) {
                originalFileName = multipartFile.getOriginalFilename();
                // 파일 이름에서 확장자만 분리
                originalFileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
                // UUID로 생성된 이름과 확장자를 합침
                storedFileName = CommitUtils.getRandomString() + originalFileExtension;

                // 위에서 설정한 경로와 생성된 이름으로 파일 업로드
                file = new File(filePath + storedFileName);
                multipartFile.transferTo(file);

                fileInfo = new HashMap<>();
                fileInfo.put("NOTICE_IDX", noticeIdx);
                fileInfo.put("ORIGINAL_NAME", originalFileName);
                fileInfo.put("STORED_NAME", storedFileName);
                fileInfo.put("FILE_SIZE", multipartFile.getSize());
				fileList.add(fileInfo);
            }
        }
        return fileList;
    }

파일 업로드

    public List<Map<String, Object>> parseUpdateFileInfo(Map<String, Object> map, HttpServletRequest request) throws Exception {
        MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
        Iterator<String> iterator = multipartHttpServletRequest.getFileNames();
        String filePath = request.getSession().getServletContext().getRealPath("/") + "static/uploadFile/";
        MultipartFile multipartFile;
        String originalFileName;
        String originalFileExtension;
        String storedFileName;

        List<Map<String, Object>> fileList = new ArrayList<>();
        Map<String, Object> fileInfo;

        String noticeIdx = map.get("NOTICE_IDX").toString();
        String requestName;
        String idx;


        while (iterator.hasNext()) {
            multipartFile = multipartHttpServletRequest.getFile(iterator.next());
            if (!multipartFile.isEmpty()) {
                originalFileName = multipartFile.getOriginalFilename();
                originalFileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
                storedFileName = CommitUtils.getRandomString() + originalFileExtension;

                multipartFile.transferTo(new File(filePath + storedFileName));

                fileInfo = new HashMap<>();
                // 기존 파일과 구분하기 위해 "IS_NEW", "Y" 라는 값을 넣어줌. IS_NEW 값이 Y일 경우 insert
                fileInfo.put("IS_NEW", "Y");
                fileInfo.put("NOTICE_IDX", noticeIdx);
                fileInfo.put("ORIGINAL_NAME", originalFileName);
                fileInfo.put("STORED_NAME", storedFileName);
                fileInfo.put("FILE_SIZE", multipartFile.getSize());
				fileList.add(fileInfo);
            } else {
                // <input type="file" name="file_${var.index }"/>에서 name값인 file_${var.index }를 가져옴 
                requestName = multipartFile.getName();
                // file_${var.index }에서 _뒤에 숫자만 추출 후 "IDX_"랑 합침.
                idx = "IDX_" + requestName.substring(requestName.indexOf("_") + 1);
                /* 기존 파일인 경우 <input type="hidden" name="IDX_${var.index }" value="${row.FILE_IDX }">에서
                name과 value가 map에 담겨있음.(input type hidden으로 날라옴)
                (기존 파일을 삭제했을 경우에는 담겨있지않음. 신규로 생성된 파일도 담겨있지않음.) */
                if (map.containsKey(idx) && !"".equals(map.get(idx))) {
                    fileInfo = new HashMap<>();
                    // IS_NEW 값이 N일 경우 update, DEL 값을 Y에서 N으로
                    fileInfo.put("IS_NEW", "N");
                                            // 기존 파일 인덱스 번호
                    fileInfo.put("FILE_IDX", map.get(idx));
					fileList.add(fileInfo);
                }

            }
        }
        return fileList;
    }

파일 수정

FileDownload
    @Override
    public void downloadFile(Map<String, Object> commitMap, HttpServletResponse response, HttpServletRequest request) throws Exception {

        // 파일 정보를 꺼내옴
        Map<String, Object> fileInfo = noticeDAO.selectFileInfo(commitMap);

        // 임시 저장 이름
        String storedFileName = fileInfo.get("STORED_NAME").toString();
        // 파일 실제 이름
        String originalFileName = fileInfo.get("ORIGINAL_NAME").toString();
        String filePath = request.getSession().getServletContext().getRealPath("/") + "static/uploadFile/";

        // 파일이 업로드 된 경로에서 임시 이름으로 저장된 파일을 읽어 byte배열에 담음
        byte[] fileByte = org.apache.commons.io.FileUtils.readFileToByteArray(new File(filePath + storedFileName));

        response.setContentType("application/octet-stream");
        response.setContentLength(fileByte.length);
        response.setHeader("Content-Disposition", "attachment; fileName=\"" + URLEncoder.encode(originalFileName, StandardCharsets.UTF_8) + "\";");
        response.setHeader("Content-Transfer-Encoding", "binary");
        // byte[]타입으로 변환된 file을 response를 통해 client에게 전송
        response.getOutputStream().write(fileByte);
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }

파일 다운로드

Clone this wiki locally