07_Framework
package edu.kh.project.common.scheduling;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import edu.kh.project.board.model.service.BoardService;
// 스프링이 일정 시간마다 해당 객체를 이용해서 코드를 수행
// == 스프링이 해당 클래스를 객체로 만들어서 관리를 해야함
// == Bean 등록
// @Controller, @Service, @Repository 의 부모 어노테이션
@Component // Bean 등록을 하겠다고 명시하는 어노테이션
public class ImageDeleteScheduling {
@Autowired
private ServletContext servletContext;
@Autowired
private BoardService service;
//@Scheduled(fixedDelay = 10000) // ms단위
// 일(1초) -> 대기(10초) -> 일(1초) -> 대기(10초)
//@Scheduled(fixedRate = 10000)
// 일(1초)
// 대기(10초)
//cron="초 분 시 일 월 요일 [년도]" - 요일 : 1(SUN) ~ 7(SAT)
//@Scheduled(cron = "0,30 * * * * *") // 매 분 0초, 30초 마다 수행
@Scheduled(cron = "0 0 * * * *") // 매 정시 (*시 0분 0초)
public void test() {
//System.out.println("스케줄러가 일정 시간마다 자동으로 출력");
System.out.println("------------ DB, 서버 불일치 파일 제거 ------------");
// 서버에 저장된 파일 목록을 조회해서
// DB에 저장된 파일 목록과 비교하여
// 매칭되지 않는 서버 파일 제거
// 1) 서버에 저장된 파일 목록 조회
// -> application 객체를 이용해서
// /resources/images/board의 실제 서버 경로를 얻어옴
String filePath = servletContext.getRealPath("/resources/images/board");
// C:\workspace\7_Framework\boardProject\src\main\webapp\resources\images\board
// 2) filePath에 저장된 모든 파일 목록 읽어오기
File path = new File(filePath);
File[] imageArr = path.listFiles();
// 배열 -> List로 변환
List<File> serverImageList = Arrays.asList(imageArr);
// 확인(임시)
// for(File f : serverImageList) {
// System.out.println(f.toString());
// }
// 3) DB 파일 목록 조회
List<String> dbImageList = service.selectImageList();
// for(String s : dbImageList) {
// System.out.println(s);
// }
// 4) 서버에 파일 목록이 있을 경우에 비교를 시작
if( !serverImageList.isEmpty() ) {
// 5) 서버 파일 목록을 순차 접근
for(File server : serverImageList) {
// 6) 서버에 존재하는 파일이
// DB(dbImageList)에 없다면 삭제
//server.toString();
//C:\workspace\7_Framework\boardProject\src\main\webapp\resources\images\board\이미지명
// List.indexOf(객체) = 객체가 List에 있으면 해당 인덱스 반환, 없으면 -1 반환
if(dbImageList.indexOf(server.getName()) == -1) {
//db파일목록 서버 파일 이름 == -1 (없음)
System.out.println(server.getName() + " 삭제");
server.delete(); // File.delete() : 파일 삭제
}
}
}
}
}
/*
* @Scheduled
*
* * Spring에서 제공하는 스케줄러 - 스케줄러 : 시간에 따른 특정 작업(Job)의 순서를 지정하는 방법.
*
* 설정 방법
* 1) servlet-context.xml -> Namespaces 탭 -> task 체크 후 저장
* 2) servlet-context.xml -> Source 탭 -> <task:annotation-driven/> 추가
*
*
* @Scheduled 속성
* - fixedDelay : 이전 작업이 끝난 시점으로 부터 고정된 시간(ms)을 설정.
* @Scheduled(fixedDelay = 10000) // '이전 작업이 끝난 후 10초 뒤'에 실행
*
* - fixedRate : 이전 작업이 수행되기 시작한 시점으로 부터 고정된 시간(ms)을 설정.
* @Scheduled(fixedRate = 10000) // '이전 작업이 시작된 후 10초 뒤'에 실행
*
*
* * cron 속성 : UNIX계열 잡 스케쥴러 표현식으로 작성 - cron="초 분 시 일 월 요일 [년도]" - 요일 : 1(SUN) ~ 7(SAT)
* ex) 2019년 9월 16일 월요일 10시 30분 20초 cron="20 30 10 16 9 2 " // 연도 생략 가능
*
* - 특수문자 * : 모든 수.
* - : 두 수 사이의 값. ex) 10-15 -> 10이상 15이하
* , : 특정 값 지정. ex) 3,4,7 -> 3,4,7 지정
* / : 값의 증가. ex) 0/5 -> 0부터 시작하여 5마다
* ? : 특별한 값이 없음. (월, 요일만 해당)
* L : 마지막. (월, 요일만 해당)
* @Scheduled(cron="0 * * * * *") // 매 분마다 실행
*
*
*
*
* * 주의사항 - @Scheduled 어노테이션은 매개변수가 없는 메소드에만 적용 가능.
*
*/
fixedDelay
fixedRate
== 긴 sql 구문 사용시, fixedDelay 사용하지 않고 fixedRate 사용!
cron(fixedRate보다 많이 사용함)
package edu.kh.project.board.model.service;
import java.util.List;
import java.util.Map;
import edu.kh.project.board.model.dto.Board;
public interface BoardService {
List<Map<String, Object>> selectBoardTypeList();
/** 게시글 목록 조회
* @param boardCode
* @param cp
* @return map
*/
Map<String, Object> selectBoardList(int boardCode, int cp);
/** 게시글 상세 조회
* @param map
* @return board
*/
Board selectBoard(Map<String, Object> map);
/** 좋아요 여부 확인 서비스
* @param map
* @return result
*/
int boardLikeCheck(Map<String, Object> map);
/** 조회수 증가 서비스
* @param boardNo
* @return result
*/
int updateReadCount(int boardNo);
int like(Map<String, Integer> paramMap);
/** 게시글 목록 조회 (검색)
* @param paramMap
* @param cp
* @return boardList
*/
Map<String, Object> selectBoardList(Map<String, Object> paramMap, int cp);
/** DB 이미지(파일) 목록 조회
* @return
*/
List<String> selectImageList();
}
package edu.kh.project.board.model.service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import edu.kh.project.board.model.dao.BoardDAO;
import edu.kh.project.board.model.dto.Board;
import edu.kh.project.board.model.dto.Pagination;
@Service
public class BoardServiceImpl implements BoardService{
@Autowired
private BoardDAO dao;
// 게시판 종류 목록 조회
@Override
public List<Map<String, Object>> selectBoardTypeList() {
return dao.selectBoardTypeList();
}
// 게시글 목록 조회
@Override
public Map<String, Object> selectBoardList(int boardCode, int cp) {
// 1. 특정 게시판의 삭제되지 않은 게시글 수 조회
int listCount = dao.getListCount(boardCode);
// 2. 1번 조회 결과 + cp 를 이용해서 Pagination 객체 생성
// -> 내부 필드가 모두 계산되어 초기화됨
Pagination pagination = new Pagination(listCount, cp);
// 3. 특정 게시판에서
// 현재 페이지에 해당하는 부분에 대한 게시글 목록 조회
// ex) 100개
// 10개 씩 보여준다
// 1page -> 100 ~ 91
// 2page -> 90 ~ 81
// 어떤 게시판에서(boardCode)
// 몇페이지(pagination.currentPage)에 대한
// 게시글 몇개(pagination.limit)인지 조회
List<Board> boardList = dao.selectBoardList(pagination, boardCode);
// 4. pagination, boardList를 Map에 담아서 반환
Map<String, Object> map = new HashMap<String, Object>();
map.put("pagination", pagination);
map.put("boardList", boardList);
return map;
}
// 게시글 상세 조회
@Override
public Board selectBoard(Map<String, Object> map) {
return dao.selectBoard(map);
}
// 좋아요 여부 확인 서비스
@Override
public int boardLikeCheck(Map<String, Object> map) {
return dao.boardLikeCheck(map);
}
// 조회수 증가 서비스
@Transactional(rollbackFor = Exception.class)
@Override
public int updateReadCount(int boardNo) {
return dao.updateReadCount(boardNo);
}
// 좋아요 처리 서비스
@Transactional(rollbackFor = Exception.class)
@Override // paramMap => boardNo, loginMemberNo, check
public int like(Map<String, Integer> paramMap) {
// check == 0 / 1
// check 값이 무엇이냐에 따라서 BOARD_LIKE 테이블 INSERT / DELETE
// 결과 저장용 변수선언
int result = 0;
if(paramMap.get("check") == 0) { // 좋아요 상태 X
// BOARD_LIKE 테이블 INSERT ( dao.insertBoardLike() )
result = dao.insertBoardLike(paramMap);
} else { // 좋아요 상태 O
// BOARD_LIKE 테이블 DELETE ( dao.deleteBoardLike() )
result = dao.deleteBoardLike(paramMap);
}
if(result == 0) return -1;
// 현재 게시글의 좋아요 개수 조회
int count = dao.countBoardLike(paramMap.get("boardNo"));
return count;
}
// 게시글 목록 조회(검색)
@Override
public Map<String, Object> selectBoardList(Map<String, Object> paramMap, int cp) {
// 1. 특정 게시판의 삭제되지 않았고, 검색 조건이 일치하는 게시글 수 조회
int listCount = dao.getListCount(paramMap); // 오버로딩
// 2. 1번 조회 결과 + cp 를 이용해서 Pagination 객체 생성
// -> 내부 필드가 모두 계산되어 초기화됨
Pagination pagination = new Pagination(listCount, cp);
// 3. 특정 게시판에서
// 현재 페이지에 해당하는 부분에 대한 게시글 목록 조회
// 단 , 검색 조건 일치하는 글만
List<Board> boardList = dao.selectBoardList(pagination, paramMap);
// 4. pagination, boardList를 Map에 담아서 반환
Map<String, Object> map = new HashMap<String, Object>();
map.put("pagination", pagination);
map.put("boardList", boardList);
return map;
}
// DB 이미지 파일 목록 조회
@Override
public List<String> selectImageList() {
return dao.selectImageList();
}
}
package edu.kh.project.board.model.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.RowBounds;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import edu.kh.project.board.model.dto.Board;
import edu.kh.project.board.model.dto.Pagination;
@Repository
public class BoardDAO {
@Autowired
private SqlSessionTemplate sqlSession;
/** 게시판 종류 목록 조회
* @return
*/
public List<Map<String, Object>> selectBoardTypeList() {
return sqlSession.selectList("boardMapper.selectBoardTypeList");
}
/** 특정 게시판의 삭제되지 않은 게시글 수 조회
* @param boardCode
* @return listCount
*/
public int getListCount(int boardCode) {
return sqlSession.selectOne("boardMapper.getListCount", boardCode);
}
/** 특정 게시판에서 현재 페이지에 해당하는 부분에 대한 게시글 목록 조회
* @param pagination
* @param boardCode
* @return
*/
public List<Board> selectBoardList(Pagination pagination, int boardCode) {
// RowBounds 객체
// - 마이바티스에서 페이징처리를 위해 제공하는 객체
// - offset 만큼 건너뛰고
// 그 다음 지정된 행 개수만큼(limit) 만큼 조회
// 1) offset 계산
int offset
= (pagination.getCurrentPage() - 1) * pagination.getLimit();
// 2) RowBounds 객체 생성
RowBounds rowBounds = new RowBounds(offset, pagination.getLimit());
// 3) selectList("namespace.id", 파라미터(boardCode), RowBounds) 호출
return sqlSession.selectList("boardMapper.selectBoardList", boardCode, rowBounds);
}
/** 게시글 상세 조회
* @param map
* @return board
*/
public Board selectBoard(Map<String, Object> map) {
return sqlSession.selectOne("boardMapper.selectBoard", map);
}
/** 좋아요 여부 확인 DAO
* @param map
* @return result
*/
public int boardLikeCheck(Map<String, Object> map) {
return sqlSession.selectOne("boardMapper.boardLikeCheck", map);
}
/** 조회수 증가 DAO
* @param boardNo
* @return result
*/
public int updateReadCount(int boardNo) {
return sqlSession.update("boardMapper.updateReadCount", boardNo);
}
/** 좋아요 테이블 삽입
* @param paramMap
* @return
*/
public int insertBoardLike(Map<String, Integer> paramMap) {
return sqlSession.insert("boardMapper.insertBoardLike", paramMap);
}
/** 좋아요 삭제
* @param paramMap
* @return
*/
public int deleteBoardLike(Map<String, Integer> paramMap) {
return sqlSession.delete("boardMapper.deleteBoardLike", paramMap);
}
/** 좋아요 개수 조회
* @param integer
* @return
*/
public int countBoardLike(Integer boardNo) {
return sqlSession.selectOne("boardMapper.countBoardLike", boardNo);
}
/** 게시글 수 조회(검색)
* @param paramMap
* @return
*/
public int getListCount(Map<String, Object> paramMap) {
return sqlSession.selectOne("boardMapper.getListCount_search", paramMap);
}
/** 게시글 목록 조회 (검색)
* @param pagination
* @param paramMap
* @return
*/
public List<Board> selectBoardList(Pagination pagination, Map<String, Object> paramMap) {
// 1) offset 계산
int offset
= (pagination.getCurrentPage() - 1) * pagination.getLimit();
// 2) RowBounds 객체 생성
RowBounds rowBounds = new RowBounds(offset, pagination.getLimit());
// 3) selectList("namespace.id", 파라미터(boardCode), RowBounds) 호출
return sqlSession.selectList("boardMapper.selectBoardList_search", paramMap, rowBounds);
}
/** DB 이미지 파일 목록 조회
* @return
*/
public List<String> selectImageList() {
return sqlSession.selectList("boardMapper.selectImageListAll");
}
}
SELECT IMG_RENAME FROM BOARD_IMG;