반갑읍니다 즐거운 주말이네요 ~ 오늘은 몽고DB를 이용한 FAQ의 백엔드 부분을 포스팅하고자합니다. (^人^)

 

몽고DB는 좀 재밌는 .. 일화가 있는데요 .. ?

바로 .. 해킹 사건입니다 .. 몽고DB에 비밀번호를 걸지 않을 경우 해킹당할 수 있습니다. 조심하시오 ..

 

발표 때 쓸려고 이쁜 데이터를 넣어뒀는데 뭔가 날라갈 거 같아서 백업해둔 게 빛을 발휘했습니다.

사실 그런 거짓 데이터 만드는 거 얼마 안 걸리는데 은근 머리 쓰잖아요 .. ?

 

해킹당해버린 .. 몽고DB

 

 

다른 건 다 오라클 / mysql 사용했는데 FAQ만 몽고DB로 한 이유는,

다양한 DB를 쓰기 위해서였습니다.

근데 페이징도 간단하고 그래서 좋았었움 ㅎ0ㅎ ~~ 프론트 부분은 내일 보여드리겠습니다 !@


테이블 먼저 보여드리겠습니다. 몽고DB의 경우 시퀀스는 없지만 어떻게 만든 걸 보고,

그거 쓰면 되겠거니 했는데 프라이머리키는 절대적으로 '_id'로만 가능하다는 걸 나중에 알았습니다 ..

그 강제 시퀀스 문장 찾아다닐려고 한창 구글링했는데 .. (´。_。`) 

 

보시면 title과 content가 있습니다.

몽고DB 테이블

글번호 / 날짜 / 매니저 아이디까지는 받을 필요가 없어서 딱 '_id', 'title', 'content'만 있습니다 !@

 

맛있는 몽고DB 패키지

이중에 Criteria와 Paging는 사용되지 않았습니다 ~~


제일 먼저 FAQDTO 보여드리겠습니다.

DB에 있는대로 생성해줬고요 ~

package com.project.faq;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "faq")
public class FaqDTO {
	@Id
	private String _id;
	private String title;
	private String content;
	
	public FaqDTO() {
	}
	
	public FaqDTO(String _id, String title, String content) {
		super();
		this._id = _id;
		this.title = title;
		this.content = content;
	}
	
	@Override
	public String toString() {
		return "faqDTO [_id=" + _id + ", title=" + title + ", content=" + content + "]";
	}

	public String get_id() {
		return _id;
	}

	public void set_id(String _id) {
		this._id = _id;
	}

	public String gettitle() {
		return title;
	}

	public void settitle(String title) {
		this.title = title;
	}

	public String getcontent() {
		return content;
	}

	public void setcontent(String content) {
		this.content = content;
	}
	
}

 

FaqMongoDAO입니다. 실제로 웹사이트에 구현돼있는 기술은 CRUD, list, paging, search 입니다.

package com.project.faq;

import java.util.List;

public interface FaqMongoDAO {
		public List<FaqDTO> findCriteria(String key,String value);
		public FaqDTO findById(String key,String value);
		public void insertDocument(FaqDTO doc);
		public void insertAllDocument(List<FaqDTO> docs);
		public void update(FaqDTO document);	//업데이트
		public void delete(String _id);			//삭제
		
		//페이징 처리돼있는 목록 화면
		public List<FaqDTO> findAll();
		public List<FaqDTO> findAll(int pageNo);//페이징
}

 

FaqMongodbDAOImpl입니다.

package com.project.faq;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

@Repository
public class FaqMongodbDAOImpl implements FaqMongoDAO {
	//spring-data-mongodb에서 제공하는 라이브러리
	MongoTemplate mongoTemplate;
	//페이징처리와 소트를 쉽게 구현하기 위해서 (spring-data-commons라이브러리에서 제공) - CRUD(CLRUD)를 위한 메소드를 제공
	FaqRepository FaqRepository; //SimpleMongoRepository이용해서 작업
	
	@Autowired
	public FaqMongodbDAOImpl(MongoTemplate mongoTemplate, FaqRepository faqRepository) {
		super();
		this.mongoTemplate = mongoTemplate;
		this.FaqRepository = faqRepository;
	}
	
	@Override
	public void insertDocument(FaqDTO doc) {
		mongoTemplate.insert(doc);		
	}

	//search
	@Override
	public List<FaqDTO> findCriteria(String key, String value) {
		String[] data =  key.split(",");
		Criteria criteria = new Criteria(data[0]);
		//^ =>해당 필드가 ^다음의 문자열로 시작하는 데이터 => like 연산자와 동일 where dept like '인사%' 
		//criteria.regex("^"+value);
		criteria.regex(".*"+value+".*");//dept like '%사%'
		Query query = new Query(criteria);
		List<FaqDTO> docs = mongoTemplate.find(query, FaqDTO.class,"faq");
		System.out.println("dao=>"+docs);
		return docs;
	}
	
	
	//
	@Override
	public FaqDTO findById(String key, String value) {
		//Criteria객체는 spring data mongodb에서 조건을 모델링한 객체
		//어떤 필드에 어떤 조건을 적용할 것인지 정의
		//필드명과 필드의 조건을 정의하면 내부에서 json의 쿼리조건을 만들어 처리
		//1. 조건을 객체로 정의
		Criteria criteria = new Criteria(key);
		//조건에 대한 설정
		criteria.is(value);
		
		//2.Criteria객체를 이용해서 Query를 생성
		System.out.println("findById->"+value);
		Query query = new Query(criteria);
		FaqDTO doc = mongoTemplate.findOne(query, FaqDTO.class,"faq");
		System.out.println("doc ~~~"+doc);
		return doc;
	}

	@Override
	public void update(FaqDTO document) {
		//조건(Criteria,Query) - 조건에 만족하는 document를 수정
		Criteria criteria = new Criteria("_id");
		criteria.is(document.get_id());
		Query query = new Query(criteria);
		
		//업데이트기능을 수행하는 객체를 생성하고 적절한 값을 셋팅
		Update update = new Update();
		update.set("title", document.gettitle());
		update.set("content", document.getcontent());
		System.out.println("query : "+query);
		System.out.println("update : "+update);
		mongoTemplate.updateFirst(query, update,"faq");
	}
	
	//https://souning.tistory.com/68
	//https://sg-choi.tistory.com/388
	public void delete(String _id){
        Criteria criteria = new Criteria("_id");
		criteria.is(_id);
        Query query = new Query(criteria);
        System.out.println("DAOImpl _id : "+_id);
        mongoTemplate.remove(query,"faq");
        System.out.println("DAOImpl"+query);
    }
	
	@Override
	public List<FaqDTO> findAll() {
		return mongoTemplate.findAll(FaqDTO.class,"faq");
	}
	
	//리스트 페이징처리
	@Override
	public List<FaqDTO> findAll(int pageNo) {
		Page<FaqDTO> page = FaqRepository.findAll(new PageRequest(pageNo, 10));
		return page.getContent();
	}

	@Override
	public void insertAllDocument(List<FaqDTO> docs) {
		// TODO Auto-generated method stub
		
	}


}

 

FaqMongoService입니다.

package com.project.faq;

import java.util.List;


public interface FaqMongoService {
	//데이터 찾기
	public FaqDTO findById(String key,String value);
	//데이터 추가
	public void insertDocument(FaqDTO doc);
	public List<FaqDTO> findCriteria(String key,String value);
	public void update(FaqDTO document);	//진짜 업데이트
	public List<FaqDTO> findAll();
	public void delete(String _id);			//삭제
	
	//페이징처리
	public List<FaqDTO> findAll(int pageNo);//페이징
	void insertAllDocument(List<FaqDTO> docs);
}

 

FaqMongoServiceImpl입니다 ~

package com.project.faq;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class FaqMongoServiceImpl implements FaqMongoService {
	FaqMongoDAO dao;
	
	@Autowired
	public FaqMongoServiceImpl(FaqMongoDAO dao) {
		super();
		this.dao = dao;
	}

	@Override
	public FaqDTO findById(String key, String value) {
		return dao.findById(key, value);
	}

	@Override
	public void insertDocument(FaqDTO doc) {
		dao.insertDocument(doc);
	}
	
	@Override
	public void insertAllDocument(List<FaqDTO> docs) {
		dao.insertAllDocument(docs);
	}

	@Override
	public List<FaqDTO> findCriteria(String key, String value) {
		return dao.findCriteria(key, value);
	}

	@Override
	public List<FaqDTO> findAll() {
		return dao.findAll();
	}

	@Override
	public List<FaqDTO> findAll(int pageNo) {	//페이징
		//PaginfAndSortingRepository의 findAll메소드를 호출하면 페이징 처리된 객체를 전달 받을 수 있다.
		//fiindAll 메소드 내부에서 페이징 처리를 할 수 있도록 PageRequest객체를 이용해서 실행할 페이지의 번호와 한 페이지를 구성할 document
		//를 매개 변수로 전달해야하 한다.
		return dao.findAll(pageNo);
	}

	@Override
	public void update(FaqDTO document) {
		System.out.println("서비스입플 도큐먼트입니다 ~~~ "+document);
		dao.update(document);
	}
	
	@Override
	public void delete(String _id) {
		System.out.println("서비스임플입니다 _id >> "+_id);
		dao.delete(_id);
	}

}

 

몽고DB에서 중요한 FaqRepository도 보여드리겠습니다 !

package com.project.faq;

import java.util.List;

import org.springframework.data.repository.PagingAndSortingRepository;

import oracle.jdbc.proxy.annotation.Post;

//spring-data 내부에서 자동으로 하위 객체를 생성하고 코드를 만들고 mongodv에서 데이터를 조회해서 매핑시킨다.
public interface FaqRepository extends PagingAndSortingRepository<FaqDTO, String>{
//	List<Post> findAllByOrderByIdDesc();
}

 

FaqIndexController입니다.

package com.project.faq;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class FaqIndexController {
	@RequestMapping("/faq.do")
	public String basefaq() {
		return "faq";
		
	}
}

 

대부분의 역할을 수행하는 FaqController입니다.

package com.project.faq;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class FaqController {
	FaqMongoService service;

	public FaqController() {
	}

	@Autowired
	public FaqController(FaqMongoService service) {
		super();
		this.service = service;
	}

	// inset페이지로 이동
	@RequestMapping(value = "/service/faqinsert", method = RequestMethod.GET)
	public String insertPage() {
		return "service_faqinsert"; // .jsp
	}

	// faq에 insert하기
	@RequestMapping(value = "/service/faqinsert", method = RequestMethod.POST)
	public String insert(FaqDTO document) {
		// System.out.println("컨트롤러:"+document);
		service.insertDocument(document);
		System.out.println("FAQ컨트롤러 ~~" + document);
		return "redirect:/admin_faq.do?pageNo=0";
	}

	// search 하기.
	@RequestMapping(value = "/faq/search", method = RequestMethod.POST)
	public ModelAndView search(String field, String criteria, String value) {
		List<FaqDTO> docs = service.findCriteria(field + "," + criteria, value);
		return new ModelAndView("faq_search", "faqlist", docs);
	}

	// 읽기
	@RequestMapping("/faq/detail")
	public ModelAndView findById(String key, String value, String action) {
		System.out.println("findById _id 1234 : " + value);
		FaqDTO list = service.findById(key, value);
		System.out.println("list 1234 : " + list);
		String view = "";
		if (action.equals("read")) {
			view = "service_faqread";
		} else {
			view = "service_faqupdate";
		}
		return new ModelAndView(view, "list", list);
	}

	// get : 디비에서 데이터 가져올 때
	// post : 디비에 데이터 생성, 수정 할 때

	// RESTful API
	//
	// get.article
	// post.article
	// put.article 기존 게시글에 덮어 씌우기 (업데이트. 통째로 덮어씌움)
	// patch.article 기존 게시글에 일부만 바꿔서 업데이트 (업데이트. 일부만 업데이트 함)
	// 개발자끼리 이렇게 개발하자고 약속

	@RequestMapping("/faq/list")
	public String mongolist(Model model) {
		List<FaqDTO> faqlist = service.findAll();
		model.addAttribute("faqlist", faqlist);
		return "list";
	}

	// user list
	// user list
	@RequestMapping("/faq/paginglist")
	public ModelAndView pagemongolist(String pageNo) {
		ModelAndView mav = new ModelAndView("service_faq");
		
		List<FaqDTO> faqlist = service.findAll(Integer.parseInt(pageNo));
		List<FaqDTO> faqcount = service.findAll();
		int total_article = faqcount.size();
		mav.addObject("faqlist", faqlist);
		mav.addObject("faqcount", total_article);
		return mav;
	}
//	@RequestMapping("/faq/paginglist")
//	public ModelAndView pagemongolist(String pageNo, HttpServletRequest request) {
//		List<FaqDTO> faqlist = service.findAll();
//		int total_article = faqlist.size();
//		// 페이징 객체
////		Paging paging = new Paging();
////		paging.setCri(pageNo);
//		paging.setTotalCount(total_article); // 리스트 총갯수 (디비에서 count(*) 가지고 와야 함)
//
//		request.setAttribute("paging", paging);
//
////		model.addAttribute("faqlist", faqlist);
////
////		List<FaqDTO> faqlist = service.findAll(Integer.parseInt(pageNo));
//		// System.out.println(pageNo);
//
//		return new ModelAndView("service_faq", "faqlist", faqlist);
//	}

	// admin list
	@RequestMapping("/admin_faq.do")
	public ModelAndView pagemongolist2(String pageNo) {
		ModelAndView mav = new ModelAndView("admin_faqlist");
		
		List<FaqDTO> faqlist = service.findAll(Integer.parseInt(pageNo));
		List<FaqDTO> faqcount = service.findAll();
		int total_article = faqcount.size();
		mav.addObject("faqlist", faqlist);
		mav.addObject("faqcount", total_article);
		return mav;
	}

	@RequestMapping(value = "/faq/update", method = RequestMethod.POST)
	public String update(FaqDTO document, @RequestParam String _id) {
		System.out.println("update test1234 : " + document);
		System.out.println("_id test1234 : " + _id);
		document.set_id(_id);
		service.update(document);

		return "redirect:/admin_faq.do?pageNo=0";
	}

	// admin delete
	@RequestMapping(value = "/faq/delete.do", method = RequestMethod.GET)
	public String delete(String _id) {
		System.out.println("FAQ 컨트롤러 ~~삭제하기 눌려짐");
		service.delete(_id);
		System.out.println("컨트롤러 document > " + _id);
		return "redirect:/admin_faq.do?pageNo=0";
	}
}

 

몽고DB를 사용하기 위해서는 pom.xml에 추가해야하는 내용도 있는데 남겨두겠습니다.

 

...
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-mongodb</artifactId>
			<version>1.6.0.RELEASE</version>
		</dependency>
...

 

위에도 남겨두었는데 내일은 프론트 부분을 포스팅하겠습니다 ~

오늘은 공지사항 프론트 부분을 작성하고자 합니다 ~

 

타일즈로 만든 웹사이트라서 타일즈 부분 먼저 보여드리겠습니다 ~

service 폴더

service-tiles.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>

	<!-- 고객센터 추가 -->
	<!-- 공지사항 -->
	<definition name="service_notice" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/cs_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_notice.jsp"></put-attribute>
	</definition>
	<definition name="service_noticeread" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/cs_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_noticeread.jsp"></put-attribute>
	</definition>
	
	
	<!-- 1:1 문의하기 -->
	<definition name="service_insert" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/cs_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_insert.jsp"></put-attribute>
	</definition>
	
	<!-- faq -->
	<definition name="service_faq" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/cs_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_faq.jsp"></put-attribute>
	</definition>
	<definition name="faq_search" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/cs_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_faqlist.jsp"></put-attribute>
	</definition>

	<!-- 공지사항 글작성 -->

	<!-- 글등록성공 -->
	<definition name="insertok" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/cs_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_insertok.jsp"></put-attribute>
	</definition>
</tiles-definitions>

 

admin_tiles.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
	<!-- 충전소 관리-->
	<definition name="station/list" extends="subTemplate">
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/admin/stationList.jsp"></put-attribute>	
	</definition>
	<definition name="station/insert" extends="subTemplate">
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/admin/stationInsert.jsp"></put-attribute>	
	</definition>
	<definition name="station/read" extends="subTemplate">
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/admin/stationRead.jsp"></put-attribute>	
	</definition>
	<definition name="station/update" extends="subTemplate">
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/admin/stationUpdate.jsp"></put-attribute>	
	</definition>
	<!-- 충전소 관리 끝 -->
	<definition name="adminRegister" extends="admin">
		<put-attribute name="content" value="/WEB-INF/admin/admin_register.jsp"></put-attribute>
	</definition>
	<definition name="adminList" extends="admin">
		<put-attribute name="content" value="/WEB-INF/admin/list.jsp"></put-attribute>
	</definition>
	<definition name="adminRead" extends="admin">
		<put-attribute name="content" value="/WEB-INF/admin/admin_read.jsp"></put-attribute>
	</definition>
	<definition name="adminUpdate" extends="admin">
		<put-attribute name="content" value="/WEB-INF/admin/admin_update.jsp"></put-attribute>
	</definition>
	<!-- 관리자페이지 추가 --> 
	<!-- 문의사항 리스트확인 -->
	<definition name="admin_service" extends="subTemplate">  
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/admin/admin_service.jsp"></put-attribute>
	</definition>
	<!-- 문의사항 제목눌러서 상세보기 -->
	<definition name="admin_service_read" extends="subTemplate">   
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/admin/admin_service_read.jsp"></put-attribute>
	</definition>
	<!-- 답변하기 -->
	<definition name="admin_service_reply" extends="subTemplate">   
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/admin/admin_service_reply.jsp"></put-attribute>
	</definition>
	<!-- 답변내용보기 -->
	<definition name="admin_service_reply_read" extends="subTemplate">   
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/admin/admin_service_reply_read.jsp"></put-attribute>
	</definition>
	<definition name="admin_customer_read" extends="admin">   
		<put-attribute name="content" value="/WEB-INF/admin/admin_customer_read.jsp"></put-attribute>
	</definition>
	<definition name="admin_customer_update" extends="admin">   
		<put-attribute name="content" value="/WEB-INF/admin/admin_customer_update.jsp"></put-attribute>
	</definition>
	<!-- 공지사항 -->
	<definition name="admin_noticelist" extends="admin">   
		<put-attribute name="content" value="/WEB-INF/service/service_notice2.jsp"></put-attribute>
	</definition>
	<definition name="service_noticeinsert" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_noticeinsert.jsp"></put-attribute>
	</definition>
	<definition name="service_noticeupdate" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_noticeupdate.jsp"></put-attribute>
	</definition>
	<definition name="service_noticereadadmin" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_noticereadadmin.jsp"></put-attribute>
	</definition>
	
	<!-- FAQ -->
	<definition name="admin_faqlist" extends="admin">   
		<put-attribute name="content" value="/WEB-INF/service/service_faq2.jsp"></put-attribute>
	</definition>
	<definition name="service_faqread" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_faqreadadmin.jsp"></put-attribute>
	</definition>
		<definition name="service_faqinsert" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_faqinsert.jsp"></put-attribute>
	</definition>
		<definition name="service_faqupdate" extends="subTemplate"> 
		<put-attribute name="menu" value="/WEB-INF/menu/admin_menu.jsp"></put-attribute>
		<put-attribute name="content" value="/WEB-INF/service/service_faqupdate.jsp"></put-attribute>
	</definition>
	
</tiles-definitions>

 

FAQ 부분에서는 타일즈를 생략해도 되겠어오 .. o(*^@^*)o

 

공지사항의 경우 어드민은 글을 작성 / 수정 할 수 있도록하였고,

유저의 경우 글을 열람 / 첨부 파일 다운로드만 할 수 있도록하였습니다.


제일 먼저 service_notice(유저 화면)입니다. 공지사항 list를 볼 수 있도록 하였고요,

특별히 페이징이나 서치 기능은 넣지 않았습니다. 개발할 시간은 적고 FAQ/몽고DB 게시판도 만들 예정인데

몽고DB로 페이징하는 게 더 간단해서 하나만 넣었습니다 ~

 

forEach를 사용하여 notice_fix 값에 y가 있을 경우 우선으로 정렬하고

n일 경우 뒤에서 정렬하도록하였습니다.

 

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>service</title>
</head>
<body>
	<!-- User View -->
	<div>
		<h1 class="pagetitle">공지사항</h1>
		<br />
		<!-- 본문 시작 -->
		<table class="table table-hover">
			<thead>
				<tr bgcolor="#FFFFFF">
					<th>제목</th>
					<th></th>
				</tr>

				<c:forEach var="notice" items="${noticelist }">
					<c:choose>
						<c:when test="${notice.notice_fix eq 'y'}">
							<tr>
								<td> 📌 <a
									href="/evweb/notice/read.do?notice_no=${notice.notice_no }&state=READ">${notice.notice_title }</a></td>
								<td scope="col" style="width: 200px">${notice.notice_writedate }</td>
							</tr>
						</c:when>
					</c:choose>
				</c:forEach>
				<c:forEach var="notice" items="${noticelist }">
					<c:choose>
						<c:when test="${notice.notice_fix eq 'n'}">
							<tr>
								<td><a
									href="/evweb/notice/read.do?notice_no=${notice.notice_no }&state=READ">${notice.notice_title }</a></td>
								<td scope="col" style="width: 200px">${notice.notice_writedate }</td>
							</tr>
						</c:when>
					</c:choose>
				</c:forEach>

			</thead>
		</table>
	</div>
</body>
</html>

 

service_notice2입니다. 동일하게 공지사항 리스트 화면이지만, 관리자가 보는 화면이라  글쓰기 버튼도 있습니다 ~

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>service</title>
</head>
<body>
	<!-- Admin View -->
	<div>
		<h1 class="pagetitle">공지사항</h1>
		<br />
		<!-- 본문 시작 -->
		<table class="table table-hover">
			<thead>
				<tr bgcolor="#FFFFFF">
					<th>제목</th>
					<th></th>
				</tr>
				<c:forEach var="notice" items="${noticelist }">
					<c:choose>
						<c:when test="${notice.notice_fix eq 'y'}">
							<tr>
								<td>📌 <a
									href="/evweb/notice/readadmin.do?notice_no=${notice.notice_no }&state=READ">${notice.notice_title }</a></td>
								<td scope="col" style="width: 200px">${notice.notice_writedate }</td>
							</tr>
						</c:when>
					</c:choose>
				</c:forEach>
				<c:forEach var="notice" items="${noticelist }">
					<c:choose>
						<c:when test="${notice.notice_fix eq 'n'}">
							<tr>
								<td><a
									href="/evweb/notice/readadmin.do?notice_no=${notice.notice_no }&state=READ">${notice.notice_title }</a></td>
								<td scope="col" style="width: 200px">${notice.notice_writedate }</td>
							</tr>
						</c:when>
					</c:choose>
				</c:forEach>
				<!-- ```````````````````````````````````````````````````````````````````````` -->
			</thead>
		</table>
	</div>
	<div class="nav navbar-nav">
		<button type="button" onclick="location.href='/evweb/service/noticeinsert'" style="margin-left: auto;" class="btn btn-primary"><i class="bi bi-pencil-square"></i> 등록</button>
		<!-- <a href="/evweb/service/noticeinsert" style="text-align: right;">글쓰기</a> -->
	</div>
</body>
</html>

 

service_noticeinsert입니다. sql문은 .. 중간에 한 번 수정되어서 공유하고자 넣었습니다.

처음에는 작성자 아이디를 수기로 입력했었는데요, 나중에는 아이디를 받아오게 변경하였고요 ~

내용에는 기본적으로 '안녕하세요, 차지모양입니다'를 적도록 하였습니다.

 

첨부파일을 업로드 할 수 있게 하였고, 하단에 라디오 버튼을 통해서 고정하기 O / X 를 구현하였습니다.

등록할 경우 글 등록이 완료되고, 취소할 경우 어드민 공지사항 리스트로 넘어오도록 하였습니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!-- <link href="/erp/common/css/font-awesome.css" rel="stylesheet" /> -->
<!-- Custom styles for this template -->
</head>
<body>
	<!-- CREATE SEQUENCE notice_tb_seq
       INCREMENT BY 1
       START WITH 1
       MINVALUE 1
       MAXVALUE 9999
       NOCYCLE
       NOCACHE
       NOORDER; -->
	<div class="col-lg-8">
		<!-- 가로범위 -->
		<div>
			<h5 class="card-title">
				<strong>공지사항 작성하기</strong>
			</h5>
			<hr>
			<form action="/evweb/service/noticeinsert" method="POST"
				enctype="multipart/form-data">
				<div class="row mb-3">
					<label for="inputId" class="col-sm-2 col-form-label">작성자</label>
					<div class="col-sm-10">
						<p class="form-control-static">${user.manager_id }</p>
						<input type="hidden" name="manager_id" value="${user.manager_id }">
						<!-- 숨길 거면 -->
					</div>
				</div>
				<div class="row mb-3">
					<label for="inputEmail" class="col-sm-2 col-form-label">제목</label>
					<div class="col-sm-10">
						<input type="text" class="form-control" name="notice_title">
					</div>
				</div>
				<div class="row mb-3">
					<label for="inputPassword" class="col-sm-2 col-form-label">내용</label>
					<div class="col-sm-10">
						<textarea class="form-control" style="height: 300px"
							name="notice_content">안녕하세요, 차지모양입니다.</textarea>
					</div>
				</div>
				<div class="row mb-3">
					<label class="col-sm-2 col-form-label">파일첨부</label>
					<div class="col-sm-10">
						<input class="form-control" type="file" id="files" name="files"
							multiple="multiple">
					</div>
				</div>

				<div class="row mb-3">
				<label class="col-sm-2 col-form-label">고정하기</label>
					<fieldset>
						X <input type="radio" name="notice_fix" value="n" checked /> O <input
							type="radio" name="notice_fix" value="y" />
					</fieldset>
				</div>

				<div class="row mb-3">
					<label class="col-sm-2 col-form-label"></label>
					<div class="col-sm-10">
						<button type="submit" class="btn btn-primary">등록</button>
						<input type="button"
							onclick="location.href='/evweb/admin_notice.do'" value="취소"
							class="btn btn-primary">
					</div>
				</div>
			</form>
		</div>
	</div>
</body>
</html>

 

service_noticeread고, 일반 유저들이 보는 화면입니다.

공지사항 번호와 제목 / 내용 / 첨부파일이 보입니다.

<%@page import="com.project.file.BoardFileDTO"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" session="true"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE>
<html>
<head>
<title>Insert title here</title>
<meta name="viewport"
	content="wmanager_idth=device-wmanager_idth, initial-scale=1">
</head>
<body>
	<!-- User View -->
	<form class="form-horizontal"
		action="/evweb/notice/read.do?state=UPDATE&notice_no=${notice.notice_no }"
		method="post">

		<div class="col-lg-8">
			<!-- 가로범위 -->
			<div class="card-body">
				<h3 class="card-title">
					<br> <strong>공지사항 No. ${notice.notice_no }</strong>
				</h3>
				${notice.notice_writedate }
				<hr />
				<br>
				<h4 class="row mb-3">
					<label class="col-form-label"><strong>[
							${notice.notice_title } ]</strong></label>
				</h4>

				<% List<BoardFileDTO> list = (List<BoardFileDTO>) request.getAttribute("boardfiledtolist");
			int size = list.size(); 
					if (size > 0) { %>
					<div class="row mb-3">
						<div class="col-sm-6">
							<label class="col-sm-3 col-form-label">첨부파일</label>

							<c:forEach var="file" items="${boardfiledtolist}">
								<a
									href="/evweb/notice/download/${notice.manager_id}/${notice.notice_no}/${file.file_no}">${file.originalFilename}</a>
							</c:forEach>
						</div>
					</div>
					<%} %>
				<div class="row mb-3">
					<div class="col-sm-10">
						<div class="card">
							<div class="card-body" style="height: 300px">
								${notice.notice_content}</div>
						</div>
					</div>
				</div>
				<br> <br>
				<div class="row mb-3">
					<div class="col-sm-10" style="text-align: right;">
						<%-- 	<button type="submit" class="btn btn-primary" 
						onclick="location.href='/evweb/reply/write.do?board_no=${list.board_no}'">수정</button> --%>
						<button type="button" class="btn btn-primary"
							onclick="location.href='/evweb/Notice/list.do'">목록</button>
						<%-- 	<button type="button" class="btn btn-primary" 
						onclick="location.href='/evweb/notice/delete.do?notice_no=${notice.notice_no }'">삭제</button> --%>
					</div>
				</div>
			</div>
		</div>
	</form>
</body>
</html>

 

service_noticereadadmin입니다. 위와 동일한 내용이지만, 수정 / 삭제 버튼을 통해서 수정과 삭제할 수 있도록하였습니다.

<%@page import="com.project.file.BoardFileDTO"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" session="true"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE>
<html>
<head>
<title>Insert title here</title>
<meta name="viewport" content="wmanager_idth=device-wmanager_idth, initial-scale=1">
</head>
<body>
<!-- Admin View -->
	<form class="form-horizontal"
		action="/evweb/notice/read.do?state=UPDATE&notice_no=${notice.notice_no }"
		method="post">

		<div class="col-lg-8">
			<!-- 가로범위 -->
			<div class="card-body">
				<h3 class="card-title">
				<br>
					<strong>공지사항 No. ${notice.notice_no }</strong>
				</h3>
				${notice.notice_writedate }
				<hr />
				<br>
				<h4 class="row mb-3">
					<label class="col-form-label"><strong>[ ${notice.notice_title } ]</strong></label>
				</h4>
				<% List<BoardFileDTO> list = (List<BoardFileDTO>) request.getAttribute("boardfiledtolist");
			int size = list.size(); 
					if (size > 0) { %>
					<div class="row mb-3">
						<div class="col-sm-6">
							<label class="col-sm-3 col-form-label">첨부파일</label>

							<c:forEach var="file" items="${boardfiledtolist}">
								<a
									href="/evweb/notice/download/${notice.manager_id}/${notice.notice_no}/${file.file_no}">${file.originalFilename}</a>
							</c:forEach>
						</div>
					</div>
					<%} %>
				<div class="row mb-3">
					<div class="col-sm-10">
						<div class="card">
							<div class="card-body" style="height: 300px">
								${notice.notice_content}</div>
						</div>
					</div>
				</div>
				<br>
				<br>
				<div class="row mb-3">
					<div class="col-sm-10" style="text-align: right;">
						<button type="submit" class="btn btn-primary" 
						onclick="location.href='/evweb/reply/write.do?board_no=${list.board_no}'">수정</button>
						<button type="button" class="btn btn-primary" 
						onclick="location.href='/evweb/admin_notice.do'">목록</button>
						<button type="button" class="btn btn-primary" 
						onclick="location.href='/evweb/notice/delete.do?notice_no=${notice.notice_no }'">삭제</button>
					</div>
				</div>
			</div>
		</div>
	</form>
</body>
</html>

 

service_noticeupdate 수정하는 화면입니다.

기본적인 틀은 글 작성하는 화면에서 가져왔습니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" session="true"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page import="com.project.notice.NoticeDTO"%>
<!DOCTYPE>
<html>
<head>
<title>Insert title here</title>
<link rel="stylesheet"
	href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script
	src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>


<script type="text/javascript">
	
</script>
<style type="text/css">
.btn-primary {
	background-color: #F37321;
	border-color: #F37321;
}
</style>
</head>
<body>
	<div>
		<h1 class="pagetitle">공지사항 수정하기</h1>
		<br />
		<form class="form-horizontal" action="/evweb/notice/update.do"
			method="post">


			<div class="form-group">
				<div class="col-md-2 text-right">
					<label id="notice_no" class="control-label">번호</label>
				</div>
				<div class="col-md-8">${notice.notice_no}</div>
			</div>
			<input type="hidden" name="notice_no" value="${notice.notice_no }">
			<div class="form-group" style="">
				<label class="col-sm-2 col-sm-2 control-label">작성자</label>
				<div class="col-sm-10">

					<p class="form-control-static">${notice.manager_id }</p>
					<input type="hidden" name="manager_id"
						value="${notice.manager_id }">
				</div>


				<!-- <div class="form-group"> -->
				<label class="col-sm-2 col-sm-2 control-label">제목</label>
				<div class="col-sm-8">
					<input type="text" class="form-control" name="notice_title"
						value="${notice.notice_title }"> <span class="help-block">게시글
						유형에 맞는 내용으로 작성 부탁드립니다. </span>
					<!-- </div> -->
				</div>

				<!-- <div class="form-group">
			<div class="col-md-2 text-right">
				<label for="title" class="control-label">첨부파일</label>
			</div> -->
				<%-- 	<div class="col-md-8">
			<!-- 디비에 저장된 파일명을 출력(클라이언트가 선택한 파일명) : JSTL -->
			<c:forEach var="file" items="">
				<h5><a href="/erp/board/download/${notice.manager_id}/${notice.notice_no}/${file.boardFileno}">${file.originalFilename}</a></h5>
			</c:forEach>
			</div> --%>
			</div>

			<div class="form-group">
				<div class="col-md-2 text-right">
					<label for="notice_writedate" class="control-label">최초 작성날짜</label>
				</div>
				<div class="col-md-8">${notice.notice_writedate }</div>
				<input type="hidden" name="notice_writedate"
					value="${notice.notice_writedate }">
			</div>
			<div class="form-group">
				<label class="col-sm-2 col-sm-2 control-label">내용</label>
				<div class="col-sm-8">
					<textarea id="notice_content"
						style="width: 100%; border: 1; overflow: visible; text-overflow: ellipsis;"
						rows=15 name="notice_content">${notice.notice_content } </textarea>

				</div>
			</div>

			<div class="form-group">
				<div class="col-md-2 text-right">
					<label for="notice_writedate" class="control-label">고정 여부</label>
				</div>
					<fieldset>
						<c:choose>
							<c:when test="${notice.notice_fix eq 'y'}">
						X <input type="radio" name="notice_fix" value="n" />
						O <input type="radio" name="notice_fix" value="y" checked />
							</c:when>
						</c:choose>
						<c:choose>
							<c:when test="${notice.notice_fix eq 'n'}">
						X <input type="radio" name="notice_fix" value="n" checked />
						O <input type="radio" name="notice_fix" value="y" />
							</c:when>
						</c:choose>
					</fieldset>
				</div>
			</div>

			<div class="row mb-3">
				<div class="col-sm-10" style="text-align: right;">
					<button type="submit" class="btn btn-primary">수정</button>
					<button type="button" class="btn btn-primary"
						onclick="location.href='/evweb/admin_notice.do'">취소</button>
				</div>
			</div>

		</form>
	</div>
</body>
</html>

 

내일은 FAQ의 백엔드 부분 보여드리겠습니다 ~ (*^▽^*)

왜 갑자기 노래를 넣느냐고 물어본다면 대답해주는 게 인지상정.

한창 프로젝트하던 시절 이 노래를 제일 많이 들었거든요 (아련)

오늘의 포스팅 내용은 .. 바로바로 ~ 게시판 부분 ~!

제가 맡았던 게시판은 공지사항과 FAQ입니다만, 오늘은 그 중에서도 공지사항 부분을 말씀드리겠습니다. φ(゜▽゜*)♪

사유 : FAQ는 몽고DB임.

제가 이런 포스팅을 본 적도 없고 쓰는 것도 처음이라 갠잔히 어색할 수 있는데 잘 봐주십쇼 얄루 ~


six ..

최종 진화 형태의 저희 프로젝트입니다.

참고로 브랜치 이름이 저런 이유는 .. 처음에는 소스트리를 쓰다가 나중에 맛이 가서 계속 하나씩 만들다보니깐 저렇게 됐읍니다.

공지사항에서 구현한 기능으로는 기본적으로 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>

 

내일은 공지사항 프론트 부분으로 오겠습니다 ~! (´▽`ʃ♡ƪ)

+ Recent posts