왜 갑자기 노래를 넣느냐고 물어본다면 대답해주는 게 인지상정.
한창 프로젝트하던 시절 이 노래를 제일 많이 들었거든요 (아련)
오늘의 포스팅 내용은 .. 바로바로 ~ 게시판 부분 ~!
제가 맡았던 게시판은 공지사항과 FAQ입니다만, 오늘은 그 중에서도 공지사항 부분을 말씀드리겠습니다. φ(゜▽゜*)♪
사유 : FAQ는 몽고DB임.
제가 이런 포스팅을 본 적도 없고 쓰는 것도 처음이라 갠잔히 어색할 수 있는데 잘 봐주십쇼 얄루 ~
최종 진화 형태의 저희 프로젝트입니다.
참고로 브랜치 이름이 저런 이유는 .. 처음에는 소스트리를 쓰다가 나중에 맛이 가서 계속 하나씩 만들다보니깐 저렇게 됐읍니다.
공지사항에서 구현한 기능으로는 기본적으로 CRUD / 글 고정 / 첨부파일 업로드, 다운로드 기능이 있습니다.
실제 배포 시점에서는 네이버 서버를 이용하다보니 Mysql로 변경하였었습니다.
NOTICE_NO는 프라이머리키로 줬고요, NOTICE_TITLE과 NOTICE_CONTENT는 글 내용입니다.
MANAGER_ID는 공지사항을 적는 관리자 아이디고 유저가 보는 화면에서는 보이지 않게 하였습니다. 글 작성할 때는 자동으로 아이디를 받아오게하였고요 !
NOTICE_WRITEDATE는 글을 작성하는 날짜이며, NOTICE_FIX는 글 공지 여부입니다.
제 pc 안에 저장돼있는 글들입니다.
제일 먼저 NoticeDTO를 보여드리겠습니다.
NoticeFileDTO고요 ~~
package com.project.notice;
public class NoticeFileDTO {
private String Notice_no;
private String originalFilename;
private String storeFilename;
private String NoticeFileno;
private NoticeFileDTO() {
}
public NoticeFileDTO(String originalFilename, String storeFilename) {
super();
this.originalFilename = originalFilename;
this.storeFilename = storeFilename;
}
//Noticefile의 상세정보 - insert
public NoticeFileDTO(String originalFilename, String storeFilename, String NoticeFileno) {
super();
this.originalFilename = originalFilename;
this.storeFilename = storeFilename;
this.NoticeFileno = NoticeFileno;
}
//select
public NoticeFileDTO(String Notice_no, String originalFilename, String storeFilename, String NoticeFileno) {
super();
this.Notice_no = Notice_no;
this.originalFilename = originalFilename;
this.storeFilename = storeFilename;
this.NoticeFileno = NoticeFileno;
}
@Override
public String toString() {
return "NoticeFileDTO [Notice_no=" + Notice_no + ", originalFilename=" + originalFilename + ", storeFilename="
+ storeFilename + ", NoticeFileno=" + NoticeFileno + "]";
}
public String getNotice_no() {
return Notice_no;
}
public void setNotice_no(String Notice_no) {
this.Notice_no = Notice_no;
}
public String getOriginalFilename() {
return originalFilename;
}
public void setOriginalFilename(String originalFilename) {
this.originalFilename = originalFilename;
}
public String getStoreFilename() {
return storeFilename;
}
public void setStoreFilename(String storeFilename) {
this.storeFilename = storeFilename;
}
public String getNoticeFileno() {
return NoticeFileno;
}
public void setNoticeFileno(String NoticeFileno) {
this.NoticeFileno = NoticeFileno;
}
}
위에 DB에 있는 테이블들을 불러와줬습니다.
NoticeDAO입니다.
package com.project.notice;
import java.util.List;
import com.project.file.BoardFileDTO;
public interface NoticeDAO {
//게시글등록 - db에 처리
int insert(NoticeDTO noticeBoard);
//게시글목록보기 - db에 처리
List<NoticeDTO> noticeList();
//게시글상세조회 - db에 처리
NoticeDTO read(String notice_no);
//게시글수정 - db에 처리
int update(NoticeDTO noticeBoard);
//게시글삭제 - db에 처리
int delete(String notice_no);
//제목으로 검색
List<NoticeDTO> search(String data);
//제목,작성자, 본문, 작성일별로 검색
List<NoticeDTO> search(String tag,String data);
// *************** 첨파 ***************
//첨부파일을 저장하기 위한 메소드
int insertFile(List<BoardFileDTO> boardfiledtolist);
// List<BoardFileDTO> getFileList(String notice_no);
// BoardFileDTO getFile(String inputdata);
}
기본적으로 글 작성, 리스트, read 화면, 수정, 삭제 등을 두었고 그 외에 몇 가지 기능들이 보이는데
실제 공지사항 화면에서는 전부 다 구현하진 않았습니다.
이어서 NoticeDAOImpl입니다.
package com.project.notice;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.project.file.BoardFileDTO;
@Repository
public class NoticeDAOImpl implements NoticeDAO {
SqlSession sqlSession;
public NoticeDAOImpl() {
}
@Autowired
public NoticeDAOImpl(SqlSession sqlSession) {
super();
this.sqlSession = sqlSession;
}
@Override
public int insert(NoticeDTO noticeBoard) {
return sqlSession.insert("com.project.notice.write", noticeBoard);
}
@Override
public NoticeDTO read(String notice_no) {
NoticeDTO dto = sqlSession.selectOne("com.project.notice.read",notice_no);
dto.setNotice_writedate(dto.getNotice_writedate().substring(0,19));
return dto;
}
@Override
public int update(NoticeDTO noticeBoard) {
return sqlSession.update("com.project.notice.update",noticeBoard);
}
@Override
public int delete(String notice_no) {
return sqlSession.delete("com.project.notice.delete",notice_no);
}
@Override
public List<NoticeDTO> search(String data) {
return sqlSession.selectList("com.project.notice.search",data);
}
@Override
public List<NoticeDTO> search(String tag, String data) {
Map<String, String> map = new HashMap<String, String>();
map.put("tag", tag);
map.put("data", data);
return sqlSession.selectList("com.project.notice.dynamicSearch", map);
}
@Override
public List<NoticeDTO> noticeList() {
List<NoticeDTO> list = sqlSession.selectList("com.project.notice.selectall");
for(int i=0; i<list.size();i++) {
list.get(i).setNotice_writedate(list.get(i).getNotice_writedate().substring(0,19));
}
return list;
}
@Override
public int insertFile(List<BoardFileDTO> boardfiledtolist) {
return sqlSession.insert("com.project.notice.notice_fileinsert", boardfiledtolist);
}
// @Override
// public List<BoardFileDTO> getFileList(String notice_no) {
// return sqlSession.selectList("com.project.notice.fileselect", notice_no);
// }
//
// @Override
// public BoardFileDTO getFile(String inputdata) {
// return sqlSession.selectOne("com.project.notice.getfileinfo", inputdata);
//
// }
}
mapper은은 뒤쪽에서 확인 가능합니다 ~
NoticeService입니다.
package com.project.notice;
import java.util.List;
import org.springframework.stereotype.Service;
import com.project.file.BoardFileDTO;
@Service
public interface NoticeService {
//게시글등록 - tbNotice테이블과 Notice_file테이블에 저장
int insert(NoticeDTO Notice, List<BoardFileDTO> boardfiledtolist);
//게시글 그냥 등록
int insert(NoticeDTO Notice);
//게시글목록보기
List<NoticeDTO> noticeList();
//게시글상세조회
NoticeDTO getNoticeInfo(String Notice_no);
//게시글수정
int update(NoticeDTO Notice);
//게시글삭제
int delete(String notice_no);
//제목으로 검색
List<NoticeDTO> search(String data);
//제목,작성자, 본문, 작성일별로 검색
List<NoticeDTO> search(String tag,String data);
//게시글을 상세보기한 경우 보여질 업로드한 파일의 목록
// List<BoardFileDTO> getFileList(String boardno);
// BoardFileDTO getFile(BoardFileDTO inputdata);
}
이어서 NoticeServiceImpl입니다.
package com.project.notice;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.project.file.BoardFileDTO;
@Service
public class NoticeServiceImpl implements NoticeService{
NoticeDAO dao;
public NoticeServiceImpl() {
}
@Autowired
public NoticeServiceImpl(NoticeDAO dao) {
super();
this.dao = dao;
}
@Override
public List<NoticeDTO> noticeList() {
return dao.noticeList();
}
@Override
public NoticeDTO getNoticeInfo(String notice_no) {
return dao.read(notice_no);
}
@Override
public int update(NoticeDTO notice) {
return dao.update(notice);
}
@Override
public int delete(String notice_no) {
return dao.delete(notice_no);
}
@Override
public List<NoticeDTO> search(String data) {
return dao.search(data);
}
@Override
public List<NoticeDTO> search(String tag, String data) {
return dao.search(tag, data);
}
@Override
public int insert(NoticeDTO Notice, List<BoardFileDTO> boardfiledtolist) {
dao.insert(Notice);
dao.insertFile(boardfiledtolist);
return 0;
}
@Override
public int insert(NoticeDTO Notice) {
dao.insert(Notice);
return 0;
}
// @Override
// public BoardFileDTO getFile(BoardFileDTO inputdata) {
// // TODO Auto-generated method stub
// return /*dao.getFile(inputdata);*/ null;
// }
//
// @Override
// public List<BoardFileDTO> getFileList(String notice_no) {
// return dao.getFileList(notice_no);
// }
}
NoticeController입니다.
package com.project.notice;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.WebUtils;
import com.project.file.BoardFileDTO;
import com.project.file.BoardFileService;
import com.project.file.FileUploadLogic;
@Controller
public class NoticeController {
FileUploadLogic fileuploadService;
NoticeService service;
BoardFileService boardservice;
public NoticeController() {
}
@Autowired
public NoticeController(NoticeService service, FileUploadLogic fileuploadService, BoardFileService boardservice) {
super();
this.service = service;
this.fileuploadService = fileuploadService;
this.boardservice = boardservice;
}
// insert 페이지로 이동
@RequestMapping(value = "/service/noticeinsert", method = RequestMethod.GET)
public String insert() {
return "service_noticeinsert";
}
@RequestMapping(value = "/service/noticeinsert", method = RequestMethod.POST)
public String insert(NoticeDTO Notice, HttpSession session) throws IllegalStateException, IOException {
System.out.println("Notice=>" + Notice);
// 1. MultipartFile 정보를 추출하기
List<MultipartFile> files = Notice.getFiles();
// 2. 업로드될 서버의 경로 - 실제 서버의 경로를 추출하기 위해서 context의 정보를 담고 있는 ServletContext객체를 추출
// =>getServletContext는 우리가 생성한 프로젝트가 서버에 배포되는 실제 경로와 context에 대한 정보를 담고 있는 객체
String path = WebUtils.getRealPath(session.getServletContext(), "/WEB-INF/upload");
// System.out.println(path);
// 3. 파일업로드 서비스를 호출해서 실제 서버에 업로드되도록 작업하기
List<BoardFileDTO> boardfiledtolist = fileuploadService.uploadFiles(files, path);
// 업로드된 파일의 file_no의 값을 셋팅 - 1부터 1,2,3,4....첨부파일마지막번호
// System.out.println("boardfiledtolist???????? " + boardfiledtolist);
// 4. 게시글에 대한 일반적인 정보와 첨부되는 파일의 정보를 db에 저장하기
if (boardfiledtolist.isEmpty()) {
service.insert(Notice);
} else {
int count = 1;
for (BoardFileDTO boardfiledto : boardfiledtolist) {
boardfiledto.setFile_no(count + "");
count++;
}
service.insert(Notice, boardfiledtolist);
}
return "redirect:/admin_notice.do";
}
@RequestMapping("/Notice/list.do")
public ModelAndView list() {
ModelAndView mav = new ModelAndView("service_notice");
List<NoticeDTO> noticelist = service.noticeList();
mav.addObject("noticelist", noticelist);
return mav;
}
@RequestMapping("/admin_notice.do")
public ModelAndView list2() {
ModelAndView mav = new ModelAndView("admin_noticelist");
List<NoticeDTO> noticelist = service.noticeList();
mav.addObject("noticelist", noticelist);
return mav;
}
// User notice read
@RequestMapping("/notice/read.do")
public String read(String notice_no, String state, Model model) {
NoticeDTO notice = service.getNoticeInfo(notice_no);
List<BoardFileDTO> boardfiledtolist = boardservice.getFileListNo(notice_no);
System.out.println("공지사항boardfiledtolist: " + boardfiledtolist);
String view = "";
if (state.equals("READ")) {
view = "service_noticeread";
} else {
view = "service_noticeupdate";
}
model.addAttribute("notice", notice);
model.addAttribute("boardfiledtolist", boardfiledtolist);
return view;
}
// admin notice read
@RequestMapping("/notice/readadmin.do")
public String read2(String notice_no, String state, Model model) {
NoticeDTO notice = service.getNoticeInfo(notice_no);
List<BoardFileDTO> boardfiledtolist = boardservice.getFileListNo(notice_no);
// System.out.println("공지사항boardfiledtolist: "+boardfiledtolist);
String view = "";
if (state.equals("READ")) {
view = "service_noticereadadmin";
} else {
view = "service_noticeupdate";
}
model.addAttribute("notice", notice);
model.addAttribute("boardfiledtolist", boardfiledtolist);
return view;
}
// delete를 시도하면 로그인 유무를 체크해서 로그인을 하지 않은 사용자는 로그인을 할 수 있도록 로그인페이지로 리다이렉트
@RequestMapping("/notice/delete.do")
public String delete(String notice_no, HttpSession session) {
// MemberDTO user = (MemberDTO) session.getAttribute("user");
String view = "";
// if(user==null) { //로그인 하지 않은 상태
// view = "redirect:/emp/login.do";
// }else { //로그인 성공 상태
// int result = service.delete(Notice_no);
// view = "redirect:/Notice/list.do?category=all";
// }
service.delete(notice_no);
view = "redirect:/admin_notice.do";
return view;
}
// 실제 업데이트기능을 처리
@RequestMapping("/notice/update.do")
public String update(NoticeDTO noticeboard) {
System.out.println(noticeboard + "-----------업데이트---------------------");
service.update(noticeboard);
return "redirect:/admin_notice.do";
}
@RequestMapping("/notice/search.do")
public ModelAndView search(String tag, String data) {
ModelAndView mav = new ModelAndView("notice/list");
List<NoticeDTO> Noticelist = service.search(tag, data);
System.out.println(Noticelist);
mav.addObject("Noticelist", Noticelist);
return mav;
}
}
마지막으로 FileUploadLogic입니다.
package com.project.notice;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@Service("notice")
public class FileUploadLogic {
//파일을 업로드한 후 이 정보를 NoticeFileDTO로 변환해서 리턴
public List<NoticeFileDTO> uploadFiles(List<MultipartFile> multipartFiles, String path) throws IllegalStateException, IOException{
List<NoticeFileDTO> filedtolist = new ArrayList<NoticeFileDTO>();
for(MultipartFile MultipartFile : multipartFiles) {
if(!MultipartFile.isEmpty()) {
String originalFilename = MultipartFile.getOriginalFilename();
//서버에서 식별할 수 있도록 파일명을 변경
String storeFilename = createStoreFilename(originalFilename);
System.out.println(originalFilename);
//File객체를 실제 경로에 저장
MultipartFile.transferTo(new File(path+File.separator+storeFilename));
filedtolist.add(new NoticeFileDTO(originalFilename, storeFilename));
}
}
return filedtolist;
}
//uploadFile메소드를 작성
// -> 한 개의 파일만 업로드 할 수 있도록 정의
// -> uploadFiles메소드에서 작성한 uploadFile메소드를 호출해서 작업하기
//클라이언트가 입력한 파일명을 중복 없는 이름으로 변경
//UUID- 32자리의 16진수로 표기
private String createStoreFilename(String originalFilename) {
int pos = originalFilename.lastIndexOf(".");
String ext = originalFilename.substring(pos+1);
String uuid = UUID.randomUUID().toString();
return uuid+"."+ext;
}
}
mapper에 있는 noticeboard.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.project.notice">
<!-- <select id="fileselect" parameterType="String" resultType="boardfile">
select * from file_tb where notice_no = #{notice_no}
</select>
<select id="getfileinfo" parameterType="boardfile" resultType="boardfile">
select * from file_tb where notice_no = #{notice_no} and file_no =#{file_no}
</select> -->
<insert id="write" parameterType="notice">
insert into NOTICE_TB
values(null,#{notice_title},#{notice_content},#{manager_id},now(), #{notice_fix})
</insert>
<select id="selectall" resultType="notice">
select * from NOTICE_TB order by notice_writedate desc
</select>
<insert id="notice_fileinsert" parameterType="java.util.List">
insert into FILE_TB values
<foreach collection="list" item="file" separator="">
(#{file.file_no}, 0, #{file.storeFilename}, #{file.originalFilename}, '공지사항', last_insert_id())
</foreach>
</insert>
<select id="read" resultType="notice" parameterType="String">
select * from NOTICE_TB where notice_no = #{notice_no}
</select>
<delete id="delete" parameterType="String">
delete from NOTICE_TB where notice_no = #{notice_no}
</delete>
<update id="update" parameterType="notice">
update NOTICE_TB
set notice_title=#{notice_title},notice_content=#{notice_content}
where notice_no=#{notice_no}
</update>
<!-- 검색기능 -->
<select id="search" resultType="notice" parameterType="String" >
select * from NOTICE_TB where title like concat('%',#{notice_title},'%')
</select>
<select id="dynamicSearch" resultType="notice" parameterType="Map">
select * from NOTICE_TB
<where>
<if test="tag=='title' and data!=''">
title like concat('%',#{data},'%')
</if>
<if test="tag=='id' and data!=''">
id like concat('%',#{data},'%')
</if>
<if test="tag=='content' and data!=''">
content concat('%',#{data},'%')
</if>
<if test="tag=='notice_writedate' and data!=''">
<![CDATA[
notice_writedate <= #{data}
]]>
</if>
</where>
</select>
</mapper>
내일은 공지사항 프론트 부분으로 오겠습니다 ~! (´▽`ʃ♡ƪ)
'coding > Java' 카테고리의 다른 글
웹서비스 백엔드 개발자 과정 수료 후기 - 6 (API/미세먼지A) (0) | 2023.02.06 |
---|---|
웹서비스 백엔드 개발자 과정 수료 후기 - 5 (게시판/FAQ B) (0) | 2023.02.05 |
웹서비스 백엔드 개발자 과정 수료 후기 - 4 (게시판/FAQ A) (0) | 2023.02.04 |
웹서비스 백엔드 개발자 과정 수료 후기 - 3 (게시판/공지사항B) (0) | 2023.02.03 |
웹서비스 백엔드 개발자 과정 수료 후기 - 1 (후기) (1) | 2023.02.01 |