Spring 23通知、全選択、管理者アクセス制限

104669 ワード

作成
  • 公告(+確認)、全選択、削除
  • のIDがないとエラーは発生しません
  • intercepter(管理者レベルでない場合は近い)
  • 管理層アクセス


    NoticeInterceptor

    //인터셉터 만드는 방법 2가지
    //1. extend HandlerInterceptorAdapter
    //2. implements HandlerInterceptor
    public class NoticeInterceptor extends HandlerInterceptorAdapter {
    
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		
    		MemberDto loginUser = (MemberDto) request.getSession().getAttribute("loginUser");
    		
    		//관리자인지 확인 (레벨로 하면 더 좋음, 여기서는 그냥 아이디로)
    		if("admin".equals(loginUser.getUserId())) {
    			return true;
    		}else {
    			//홈으로 보내버리기, app999
    			//response.sendRedirect(request.getServletContext().getContextPath());
    			request.setAttribute("msg", "관리자 계정이 아닙니다.");
    			request.getRequestDispatcher("/WEB-INF/views/error/errorPage.jsp").forward(request, response);
    			return false;
    		}
    		
    	}
    }
    

    ErrorProcessor

    @ControllerAdvice(annotations = Controller.class)
    @Slf4j
    public class ErrorProcessor {
    
    	@ExceptionHandler(Exception.class)
    	public String errorProcess(Exception e) {
    		//서버도 예외를 알게하기
    		log.error(e.toString());
    		log.error(e.getMessage());
    		e.printStackTrace();
    		return "error/exception";
    	}
    }
    

    ErrorPage.jsp

    <body>
    
    	<%@ include file="/WEB-INF/views/common/header.jsp" %>
    
    	<h1>에러페이지~~</h1>
    	<h2 id="msg">${msg}</h2>
    	
    	<script type="text/javascript">
    		console.log(document.getElementById('msg').innerText);	//메세지 띄우기
    		alert(document.getElementById('msg').innerText);	//메세지 띄우기
    		window.location.href = "${root}";	//홈화면으로 보내기
    	</script>
    	
    </body>

    servlet-context.xml

    	<!-- interceptor 등록 -->
    	<interceptors>
    		<interceptor>
    			<mapping path="/notice/**"/>
    			<!-- list 만 제외, 일반회원은 list 볼 수 있어야 하니까 -->
    			<exclude-mapping path="/notice/list/**"/>
    			<beans:bean class="com.kh.app999.interceptor.NoticeInterceptor"></beans:bean>
    		</interceptor>
    	</interceptors>

    ほうそう


    PageVo

    C,S,D


    MemberServiceImpl

    @Service
    @Slf4j
    @Transactional
    public class MemberServiceImpl implements MemberService {
    
    	@Autowired
    	private MemberDao dao;
    	
    	@Autowired
    	private PasswordEncoder pe;
    	
    	@Override
    	public int join(MemberDto dto, HttpServletRequest req) throws Exception{
    		//회원가입 처리
    		
    		//회원번호, 시퀀스 nextval
    		int no = dao.getMemberSeq();
    		//insert 처리
    		dto.setUserNo(no);
    		//암호화
    		dto.setUserPwd(pe.encode(dto.getUserPwd()));
    		log.info(dto.toString());
    		int result = dao.insertMember(dto);
    		
    		
    		//////////////////////
    		
    		//파일 업로드(우리 서버에)
    		MultipartFile f = dto.getF();
    		
    		if(!f.isEmpty()) {
    			//원래 이름	-> db에 저장
    			//변경된 이름 -> db에 저장
    			//서비스 레이어에서 작업하도록
    			String changeName = System.currentTimeMillis()+"_"+f.getOriginalFilename();
    			dto.setChangeName(changeName);
    			//사이즈, 타입
    			System.out.println("===============");
    			System.out.println(f.getOriginalFilename());
    			System.out.println(f.getSize());
    			System.out.println(f.getContentType());
    			System.out.println("===============");
    			
    			//파일을 톰캣에 저장
    			String path = req.getServletContext().getRealPath("/resources/upload/profile/");
    			//파일을 서버에 저장
    			//getREalPath == /spring999prjFinal/src/main/webapp
    //			File file = new File("D:/uploadForSpring/999prj/profile/"+ changeName);
    			File file = new File(path+ changeName);
    			f.transferTo(file);
    			
    			//db에 insert
    			dao.uploadProfile(dto);
    		}
    		
    		return result;
    	}
    
    	@Override
    	public MemberDto login(MemberDto dto) throws Exception {
    		//DB에서 회원 정보 조회(기준:id)
    		MemberDto dbUser = dao.getMember(dto);
    		//없는 id여도 에러 안나게
    		if(dbUser == null) {
    			return null;
    		}
    		
    		//비번 일치 체크
    		if(pe.matches(dto.getUserPwd(), dbUser.getUserPwd())) {
    			//일치함-> 멤버 리턴
    			return dbUser;
    		}else {
    			//불일치-> null 리턴
    			return null;
    		}
    	}
    
    	@Override
    	public MemberDto editMember(MemberDto dto) throws Exception {
    		//비밀번호 한번 더 확인..근데 여기선 패스
    		//비번을 입력했을 때만 수정 가능!!
    		if(dto.getUserPwd().length()>0) {
    			dto.setUserPwd(pe.encode(dto.getUserPwd()));
    		}
    		int result = dao.updateMember(dto);
    		MemberDto m = null;
    		if(result > 0) {
    			m = dao.getMember(dto);
    		}
    		return m;
    	}
    
    }

    NoticeController

    @Controller
    @RequestMapping("notice")
    @Slf4j
    public class NoticeController {
    	
    	@Autowired
    	private NoticeService service;
    
    	//공지사항 화면 보여주기
    	@GetMapping(value = "/list")
    		public String list(Model model) throws Exception {
    		//리스트 조회
    		List<NoticeVo> list = service.getNoticeList();
    		model.addAttribute("list", list);
    		return "notice/list";
    	}
    	
    	//공지사항 작성 화면 보여주기(디비가서 리스트 조회)
    	@GetMapping("write")
    	public String write() {
    		
    		return "notice/write";
    	}
    	
    	//공지사항 작성 로직 처리
    	@PostMapping("write")
    	public String write(NoticeVo vo, HttpServletRequest req) throws Exception {
    		System.out.println(vo);
    		
    //		한번에 많이 만들때 이렇게
    //		for(int i=0; i<500; i++) {
    //			service.write(vo);
    //		}
    		
    		int result = service.write(vo);
    		if(result>0) {
    			return "redirect:/notice/list";
    		}else {
    			req.setAttribute("msg", "공지사항 작성 실패");
    			return "error/errorPage";
    		}
    	}
    	
    	//공지사항 삭제
    	@PostMapping("delete")
    	@ResponseBody
    	public String delete(String str) throws Exception {
    		System.out.println(str);	// 삭제할 번호들: 1, 5, ...
    		System.out.println(str.length()/2);	// 
    		
    		int result = service.deleteNotice(str);
    		
    		log.warn("선택한 row 개수 : {}", result);
    		
    		if(result == str.length()/2) {
    			return "ok";
    		}else {
    			return "fail_" + result;
    		}
    		
    	}	
    	
    }

    NoticeServiceインタフェース

    public interface NoticeService {
    
    	int write(NoticeVo vo) throws Exception;
    
    	List<NoticeVo> getNoticeList() throws Exception;
    
    	int deleteNotice(String str) throws Exception;
    
    }

    NoticeServiceImpl

    @Service
    public class NoticeServiceImpl implements NoticeService{
    
    	@Autowired
    	private NoticeDao dao;
    	
    	@Override
    	public int write(NoticeVo vo) throws Exception {
    		
    		return dao.write(vo);
    	}
    
    	@Override
    	public List<NoticeVo> getNoticeList() throws Exception {
    		return dao.getNoticeList();
    	}
    
    	@Override
    	public int deleteNotice(String str) throws Exception {
    		String[] delArr = str.split(",");
    		return dao.deleteNotice(delArr);
    	}
    
    }
    

    NoticeDaoインタフェース

    public interface NoticeDao {
    
    	int write(NoticeVo vo) throws Exception;
    
    	List<NoticeVo> getNoticeList() throws Exception;
    
    	int deleteNotice(String[] delArr) throws Exception;
    
    }
    

    NoticeDaoImpl

    @Repository
    public class NoticeDaoImpl implements NoticeDao{
    
    	@Autowired
    	private SqlSession sqlSession;
    	
    	@Override
    	public int write(NoticeVo vo) throws Exception {
    		return sqlSession.insert("notice.insertNotice", vo);
    	}
    
    	@Override
    	public List<NoticeVo> getNoticeList() throws Exception {
    		return sqlSession.selectList("notice.getNoticeList");
    	}
    
    	@Override
    	public int deleteNotice(String[] delArr) throws Exception {
    		return sqlSession.update("notice.deleteNotice", delArr);
    	}
    
    }

    NoticeVo

    @Data
    public class NoticeVo {
    
    	private long no;
    	private String title;
    	private String content;
    	private long writer;
    	private Date writeDate;	//작성날짜
    	private Date editDate;	//최종수정날짜
    	private String del;
    	//JOIN한 테이블의 컬럼을 넣는다고???
    	private String userNick;
    }
    

    デビー


    notice-mapper.xml

    <mapper namespace="notice">
    
    	<insert id="insertNotice" parameterType="noticeVo">
    		INSERT INTO NOTICE
    		(
    			 NO 
    		    ,TITLE
    		    ,CONTENT 
    		    ,WRITER 
    		)
    		VALUES
    		(
    			 NOTICE_SEQ.NEXTVAL
    			,#{title}
    			,#{content}
    			,#{writer}
    		)
    		
    	</insert>
     
     	<select id="getNoticeList" resultType="noticeVo">
     		SELECT *
     		FROM NOTICE n
     		JOIN MEMBER m ON(n.WRITER = m.USER_NO)
     		WHERE DEL = 'N'
     		ORDER BY NO
     	</select>
     	
     	<update id="deleteNotice" >
     		UPDATE NOTICE
     		SET
     		DEL = 'Y'
     		WHERE NO IN 
     		<foreach collection="array" item="n" open="(" close=")" separator=",">
     		#{n}
     		</foreach>
     		
     	</update>
    </mapper>

    NOTICE

    DROP TABLE NOTICE CASCADE CONSTRAINTS;
    CREATE TABLE NOTICE(
    	 NO NUMBER PRIMARY KEY
        ,TITLE  VARCHAR2(100)
    	,CONTENT VARCHAR2(4000)
        ,WRITER NUMBER
    	,WRITE_DATE  DATE DEFAULT SYSDATE
        ,EDIT_DATE  DATE NULL
    	,DEL CHAR(1) DEFAULT('N')
        ,CONSTRAINT NOTICE_FK FOREIGN KEY(WRITER) REFERENCES MEMBER(USER_NO) ON DELETE CASCADE
    );
    
    DROP SEQUENCE NOTICE_SEQ;
    CREATE SEQUENCE NOTICE_SEQ NOCACHE NOCYCLE;
    
    SELECT * FROM NOTICE;

    mybatis-config.xml

    <configuration>
    	<settings>
    		<setting name="cacheEnabled" value="true"/>
    		<setting name="autoMappingBehavior" value="FULL"/>
    		<setting name="mapUnderscoreToCamelCase" value="true"/>
    		<setting name="jdbcTypeForNull" value="NULL"/>
    	</settings>
    	<!-- 경로의 별칭 지정 -->
    	
    	<typeAliases>
    		<typeAlias type="com.kh.app999.member.entity.MemberDto" alias="memberDto"/>
    		<typeAlias type="com.kh.app999.notice.vo.NoticeVo" alias="noticeVo"/>
    	
    	</typeAliases> 
    	
    </configuration>

    表示


    notice/list.jsp

    <body>
    
    	<%@ include file="/WEB-INF/views/common/header.jsp" %>
    	
    	<div id="div-main">
    		<div style="text-align:center;">
    			<h1>공지사항</h1>
    		</div>
    		
    		<table border="1" style="margin:auto;">
    			<thead>
    				<tr>
    					<th><input type="checkbox" id="allCheck"></th>
    					<th>글번호</th>
    					<th>제목</th>
    					<th>작성자</th>
    					<th>작성시간</th>
    				</tr>
    			</thead>
    			<tbody>
    				<c:forEach items="${list}" var="n">
    					<tr>
    						<td><input type="checkbox" class="checkbox-del" value="${n.no}"></td>
    						<td>${n.no}</td>
    						<td>${n.title}</td>
    						<td>${n.userNick}</td>
    						<td>${n.writeDate}</td>
    					</tr>
    				</c:forEach>
    			</tbody>
    		</table>
    		
    		<a href="${root}/notice/write">공지 작성</a>
    		<button onclick="del();">삭제하기</button>
    	</div>
    	
    	<script type="text/javascript">
    		//전체 선택
    		//let allCheck = document.querySelector('#allCheck');
    		let allCheck = document.querySelector('thead input[type=checkbox]');
    		let delArr = document.getElementsByClassName('checkbox-del');
    		
    		allCheck.onchange = function(e){
    			//console.log(e.target.checked);
    			console.log(this.checked);
    			if(this.checked){
    				for(let i=0; i<delArr.length; i++){
    					delArr[i].checked = true;
    				}
    			}else{
    				for(let i=0; i<delArr.length; i++){
    					delArr[i].checked = false;
    				}
    			}
    		}
    		
    		//삭제하기
    		function del() {
    			//삭제할 번호(들) 가져오기
    			let delArr = document.getElementsByClassName('checkbox-del');
    			//가져온 번호(들)을 하나의 문자열로 합치기
    			let result = "";
    			
    			for(let i = 0; i<delArr.length; i++){
    				let t = delArr[i];
    				if(t.checked){
    					//children[1]가 no가 있음
    					//console.log(t.parentNode.parentNode.children[1].innerText);					
    					console.log(t.value);	
    					result += t.value + ',';
    				}
    			}
    			
    			$.ajax({
    				url : "${root}/notice/delete",
    				data : {"str" : result},
    				type : "post",
    				success : function(data){
    					console.log(data);
    				}, 
    				error : function(error){
    					console.log(error)
    				},
    				complete : function(){
    					//새로고침
    					window.location.reload();
    				}
    			});
    		}//del()
    	</script>
    </body>

    notice/write.jsp

    <body>
    
    	<%@ include file="/WEB-INF/views/common/header.jsp" %>
    	
    	<div id="div-main">
    		<div style="text-align:center;">
    			<h1>공지사항 작성하기</h1>
    		</div>
    		
    		<form action="" method="post" style="text-align:center;" onsubmit="return writeCheck();">
    			제목 : <input type="text" name="title"><br>
    			작성자 : <input type = "text" value="${loginUser.userNick}" readonly="readonly"/> <br>
    			<input type = "hidden" name = "writer" value="${loginUser.userNo}"/> <br>
    			내용 : <br> <textarea rows="30" cols="100" name = "content"></textarea> <br>
    			 <input type = "submit" value = "공지사항 작성" />
    		</form>
    		
    	</div>
    	
    	<script type="text/javascript">
    		function writeCheck(){
    			return confirm("작성하시겠습니까?");
    		}
    	
    	</script>
    </body>

    common/header.jsp

  • の2番目のクエリ
  • を追加
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
    <c:set var="root" value="${pageContext.request.contextPath}"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <link rel="stylesheet" href="${root}/resources/css/common/header.css">
    
    	<div id="div-header">
    		<table border="1">
    			<tr>
    				<td>빈칸</td>
    				<td colspan="2"><a href="${root}"><img width="100%" height="50px" src="${pageContext.request.contextPath}/resources/imgs/qr.png"></a></td>
    				<!-- href="/app999" -->
    				<c:if test="${empty loginUser}">
    					<td>빈칸</td>
    				</c:if>
    				<c:if test="${not empty loginUser}">
    					<td><a href="${root}/member/mypage"><img src="${root}/resources/upload/profile/${loginUser.changeName}"></a></td>
    				</c:if>
    			</tr>
    			<tr>
    				<td><a href="${root}/notice/list">공지사항</a></td>
    				<td>메뉴2</td>
    				<td>메뉴3</td>
    				<c:if test="${empty loginUser}">
    					<td>
    						<a href="${root}/member/login">로그인</a><br>
    						<a href="${root}/member/join">회원가입</a>
    					</td>
    				</c:if>
    				<c:if test="${not empty loginUser}">
    					<td>
    						${loginUser.userNick}님 환영합니다!<br>
    						<a href="${root}/member/logout">로그아웃</a>
    					</td>
    				</c:if>
    			</tr>
    		</table>
    	</div>
    

    home.jsp

    <body>
    	<%@ include file="/WEB-INF/views/common/header.jsp" %>
    	<script type="text/javascript" src="${root}/resources/js/home.js"></script>
    
    	<div id="div-main">
    		<h1>홈페이지</h1>
    	</div>
    </body>

    js分離