[Spring] MVC 연습

2024. 11. 28. 08:34·Spring
목차
  1. 공지사항목록조회
  2. 공지글검색
  3. 공지글페이징
  4. @RequestParam
  5. 회원목록조회페이징
  6. 공지글등록 후 조회
  7. 게시글수정&삭제
반응형

공지사항목록조회

mybatis_config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0/EN" 
				"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- vo 별칭 지정 -->
	<typeAliases>
		<!-- 별칭 지정시 반드시 클래스부터 선언 후 별칭 지정! -->
		<typeAlias type="edu.springboard.vo.UserVO" alias="userVO"/>
		<typeAlias type="edu.springboard.vo.NoticeVO" alias="noticeVO" />
	</typeAliases>
</configuration>

 
 
NoticeVO

package edu.springboard.vo;

public class NoticeVO extends UserVO {
	private String nno;
	private String title;
	private String content;
	private String rdate;
	private String hit;
	private String state;
	private String topYn; //DB의 컬럼은 top_yn이지만 카멜기법을 사용해 topYn로 사용해도 적용된다 
	private String filename;
	
	public String getNno()      {	return nno;		 }
	public String getTitle()    {	return title;	 }
	public String getContent()  {	return content;	 }
	public String getRdate()    {	return rdate;	 }
	public String getHit()      {	return hit;		 }
	public String getState()    {	return state;	 }
	public String getTopYn()    {	return topYn;   }
	public String getFilename() {	return filename; }

	public void setNno(String nno)           {	this.nno = nno;			  }
	public void setTitle(String title)       {	this.title = title;	      }
	public void setContent(String content)   {	this.content = content;	  }
	public void setRdate(String rdate)       {	this.rdate = rdate;	      }
	public void setHit(String hit)           {	this.hit = hit;	          }
	public void setState(String state)       {	this.state = state;	      }
	public void setTopYn(String topYn)       {	this.topYn = topYn;	  }
	public void setFilename(String filename) {	this.filename = filename; }
		
}

 
 
NoticeMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
			"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="edu.springboard.mapper.noticeMapper">
	
	<select id="selectAll" resultType="noticeVO">
		SELECT n.*,uid FROM notice_board n 
				inner join user u 
				 on n.uno = u.uno 
	</select>
	
	<select id="selectOne" parameterType="String" resultType="noticeVO">
		SELECT n.*,uid FROM notice_board n 
					 inner join user u 
					 on n.uno = u.uno 
					 WHERE nno=#{nno}
	</select>	
</mapper>

 
 
 
NoticeController

package edu.springboard.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
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 edu.springboard.service.NoticeService;
import edu.springboard.vo.NoticeVO;

@Controller
public class NoticeController {
	
	@Autowired
	public NoticeService noticeService;
	
	@RequestMapping(value="/notice/list.do")
	public String noticeList(Model model) {
		
		//비지니스 로직 : DB에 있는 전체 회원 목록 데이터 가져오기
		List<NoticeVO> list = noticeService.selectAll();
		//모델 객체 사용하여 조회 데이터 화면으로 포워딩
		model.addAttribute("list", list);
		
		return "notice/list";
	}
}

 
 
 
NoticeService

package edu.springboard.service;

import java.util.List;

import edu.springboard.vo.NoticeVO;

public interface NoticeService {
	public List<NoticeVO> selectAll(); 
}

 
 
 
NoticeServiceImpl

package edu.springboard.service;

import java.util.List;

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

import edu.springboard.dao.NoticeDAO;
import edu.springboard.vo.NoticeVO;

@Service
public class NoticeServiceImpl implements NoticeService {
	
	@Autowired
	public NoticeDAO noticeDAO;
	
	@Override
	public List<NoticeVO> selectAll() {
		return noticeDAO.selectAll();
	}
}

 
 
NoticeDAO

package edu.springboard.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import edu.springboard.vo.NoticeVO;

@Repository
public class NoticeDAO {
	@Autowired
	public SqlSession sqlSession;
	
	public List<NoticeVO> selectAll() {
		return sqlSession.selectList("edu.springboard.mapper.noticeMapper.selectAll");
	}
}

 
 
list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>공지사항목록조회</title>
</head>
<body>
	<a href="<%= request.getContextPath() %>">home으로 돌아가기</a>
	<h2>공지사항목록조회</h2><hr>
	<table border="0">
		<tr>
			<th style="width:60px;">글번호</th>
			<th style="width:220px;">제목</th>
			<th style="width:100px;">작성자</th>
			<th style="width:160px;">등록일</th>
		</tr>
		<c:forEach items="${list}" var="list">
			<tr>
				<td>${list.nno}</td>
				<td>
					<a href="view.do?uno=${list.nno}">${list.title}</a>
				</td>
				<td>${list.uid}</td>
				<td>${list.rdate}</td>
			</tr>
		</c:forEach>
	</table>
</body>
</html>

 


공지글검색

noticeMapper

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
			"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="edu.springboard.mapper.noticeMapper">
	
	<select id="selectAll" parameterType="searchVO" resultType="noticeVO">
		SELECT n.*,uid FROM notice_board n 
				inner join user u 
				 on n.uno = u.uno 
				 <if test="searchType != null and searchType.equals('title')">
				 	WHERE title LIKE concat('%',#{searchValue} ,'%')
				 </if>
				 <if test="searchType != null and searchType.equals('id')">
				 	WHERE uid LIKE concat('%',#{searchValue} ,'%')
				 </if>
	</select>
	
	<select id="selectOne" parameterType="String" resultType="noticeVO">
		SELECT n.*,uid FROM notice_board n 
					 inner join user u 
					 on n.uno = u.uno 
					 WHERE nno=#{nno}
	</select>	
</mapper>

 
 
SearchVO

package edu.springboard.vo;

public class SearchVO {
	private String searchType;
	private String searchValue;
	
	public String getSearchType()  { return searchType;  }
	public String getSearchValue() { return searchValue; }
	
	public void setSearchType(String searchType)   { this.searchType = searchType;   }
	public void setSearchValue(String searchValue) { this.searchValue = searchValue; }
}

 
 
mybatis_config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0/EN" 
				"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- vo 별칭 지정 -->
	<typeAliases>
		<!-- 별칭 지정시 반드시 클래스부터 선언 후 별칭 지정! -->
		<typeAlias type="edu.springboard.vo.UserVO" alias="userVO"/>
		<typeAlias type="edu.springboard.vo.NoticeVO" alias="noticeVO" />
		<typeAlias type="edu.springboard.vo.SearchVO" alias="searchVO" />
	</typeAliases>
</configuration>

 
 
list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>공지사항목록조회</title>
<link rel="stylesheet" type="text/css" href="<%= request.getContextPath() %>/resources/css/spring.css" />
</head>
<body>
	<a href="<%= request.getContextPath() %>"><button class="sBtn">home</button></a>
	<h2>공지사항목록조회</h2><hr>
	<form action="list.do" method="get">
		<select name="searchType">
			<option value="title">제목</option>
			<option value="id">작성자(id)</option>
		</select>
		<input type="text" name="searchValue">
		<button style="width:80px; height:30px;">검색</button>
	</form>
	<table border="0" style="text-align:center;">
		<tr>
			<th style="width:60px;">글번호</th>
			<th style="width:220px;">제목</th>
			<th style="width:100px;">작성자</th>
			<th style="width:160px;">등록일</th>
		</tr>
		<c:forEach items="${list}" var="list">
			<tr>
				<td>${list.nno}</td>
				<td>
					<a href="view.do?nno=${list.nno}">${list.title}</a>
				</td>
				<td>${list.uid}</td>
				<td>${list.rdate}</td>
			</tr>
		</c:forEach>
	</table>
	<!--  
	메인페이지에서 공지사항 목록 이동 링크 클릭시 현재 list.jsp가 포워드 될 수 있도록 기능을 구현합니다.
	이때 테이블은 notice_board 테이블을 사용합니다
	작성자는 게시글 등록자 id를 출력합니다
	-->
</body>
</html>

 
 
NoticeDAO

package edu.springboard.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import edu.springboard.vo.NoticeVO;
import edu.springboard.vo.SearchVO;

@Repository
public class NoticeDAO {
	@Autowired
	public SqlSession sqlSession;
	
	public List<NoticeVO> selectAll(SearchVO searchVO) {
		return sqlSession.selectList("edu.springboard.mapper.noticeMapper.selectAll",searchVO);
	}
	
	public NoticeVO selectOne(String nno) {
		return sqlSession.selectOne("edu.springboard.mapper.noticeMapper.selectOne",nno);
	}
}

 
 
 
NoticeServiceImpl

package edu.springboard.service;

import java.util.List;

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

import edu.springboard.dao.NoticeDAO;
import edu.springboard.vo.NoticeVO;
import edu.springboard.vo.SearchVO;

@Service
public class NoticeServiceImpl implements NoticeService {
	
	@Autowired
	public NoticeDAO noticeDAO;
	
	@Override
	public List<NoticeVO> selectAll(SearchVO searchVO) {
		return noticeDAO.selectAll(searchVO);
	}
	
	@Override
	public NoticeVO selectOne(String nno) {
		return noticeDAO.selectOne(nno);
	}
}

 
 
 
NoticeService

package edu.springboard.service;

import java.util.List;

import edu.springboard.vo.NoticeVO;
import edu.springboard.vo.SearchVO;
import edu.springboard.vo.UserVO;

public interface NoticeService {
	public List<NoticeVO> selectAll(SearchVO searchVO); 
	public NoticeVO selectOne(String nno); 
}

 
 
 
NoticeController

package edu.springboard.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
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 edu.springboard.service.NoticeService;
import edu.springboard.vo.NoticeVO;
import edu.springboard.vo.SearchVO;
import edu.springboard.vo.UserVO;

@Controller
public class NoticeController {
	
	@Autowired
	public NoticeService noticeService;
	
	@RequestMapping(value="/board/list.do")
	public String noticeList(Model model,SearchVO searchVO) {
		
		//비지니스 로직 : DB에 있는 전체 회원 목록 데이터 가져오기
		List<NoticeVO> list = noticeService.selectAll(searchVO);
		//모델 객체 사용하여 조회 데이터 화면으로 포워딩
		model.addAttribute("list", list);
		
		return "notice/list";
	}
	
	@RequestMapping(value="/board/view.do")
	public String view(String nno, Model model) {
		
		NoticeVO notice = noticeService.selectOne(nno);
		
		if(notice != null) {
			System.out.println("조회완료");
			model.addAttribute("notice",notice);
			
			return "notice/view";
		}else {
			System.out.println("조회실패");
			return "redirect:/";
		}
	}
}

 
 


공지글페이징

PagingUtil

package edu.springboard.util;

public class PagingUtil {  //(o) : 반드시 필요
	// o : 외부에서 받아올 연산에 필요한 데이터를 담을 필드
	// o 없음 : o 데이터들을 활용하여 연산된 결과를 담을 필드
	private int nowPage;   //현재페이지번호(o)
	private int startPage; //사작페이지번호
	private int endPage;   //종료페이지번호
	private int total;	   //전체 게시글 수(o)
	private int perPage;   //한 페이지당 게시글 갯수(o)
	private int lastPage;  //최종 페이지 번호
	private int start;     //시작 게시글 번호
	private int end;       //종료 게시글 번호
	private int cntPage=5;//한 페이지에서 보여지는 페이징 번호 수(o)
	
	public PagingUtil() {}
	public PagingUtil(int nowPage,int total, int perPage) {
		setNowPage(nowPage);
		setTotal(total);
		setPerPage(perPage);
		
		calcStartEnd(nowPage,perPage); //시작번호 종료번호 연산 기능 호출
		calcLastPage(total, perPage);
		calcStartEndPage(nowPage,cntPage);
	}
	
	public void calcStartEnd(int nowPage,int perPage) {
		int end = nowPage * perPage; //게시글 종료번호(oracle에서 사용)
		/*
		현재 페이지 : 1 / 게시글 노출 갯수 : 5
		종료번호 : 1*5 -> 5
		시작번호 : 종료번호 - 게시글 노출 갯수(5-5 = 0) 
		--> limit 0,5
		현재 페이지 : 2 / 게시글 노출 갯수 : 5
		종료번호 : 2*5 -> 10
		시작번호 : 종료번호 - 게시글 노출 갯수(10-5 = 5)
		--> limit 5,5
		*/
		int start = end - perPage; //게시글 시작번호.(oracle에서는 +1을 해야함)
		
		setEnd(end);
		setStart(start);
	}
	
	//총 11개 한페이지당 10개씩 페이지 최종 번호 : 2
	public void calcLastPage(int total, int perPage) {
		//전체 게시글에서 페이지당 게시글 수를 나눈 실수를 올림처리 한 값을 반환
		int lastPage = (int)Math.ceil((double)total/perPage);
		setLastPage(lastPage);
	}
	
	//현재페이지 : 3 / 시작페이지 번호 : 1 / 종료페이지 번호 : 10
	public void calcStartEndPage(int nowPage,int cntPage) {
		//현재 페이지의 10의 자리를 구해와 +1을 한 후 페이지당 노출 페이지 갯수 곱하기
		int endPage = (int)Math.ceil((double)nowPage / cntPage) * cntPage;
		
		int startPage = endPage - cntPage + 1;

		if(endPage > lastPage) {
			endPage = lastPage;
		}
		
		setEndPage(endPage);
		setStartPage(startPage);
	}
	
	public int getNowPage()   { return nowPage;   }
	public int getStartPage() { return startPage; }
	public int getEndPage()   { return endPage;   }
	public int getTotal()     { return total;     }
	public int getPerPage()   { return perPage;   }
	public int getLastPage()  { return lastPage;  }
	public int getStart()     { return start;     }
	public int getEnd()       { return end;       }
	public int getCntPage()   { return cntPage;   }
	
	public void setNowPage(int nowPage)     { this.nowPage = nowPage;	  }
	public void setStartPage(int startPage) { this.startPage = startPage; }
	public void setEndPage(int endPage)     { this.endPage = endPage;	  }
	public void setTotal(int total)         { this.total = total;	      }
	public void setPerPage(int perPage)     { this.perPage = perPage;	  }
	public void setLastPage(int lastPage)   { this.lastPage = lastPage;	  }
	public void setStart(int start)         { this.start = start;	      }
	public void setEnd(int end)             { this.end = end;	          }
	public void setCntPage(int cntPage)     { this.cntPage = cntPage;	  }
}

 
 
SearchVO

package edu.springboard.vo;

import edu.springboard.util.PagingUtil;

public class SearchVO extends PagingUtil {
	private String searchType;
	private String searchValue;
	
	public String getSearchType()  { return searchType;  }
	public String getSearchValue() { return searchValue; }
	
	public void setSearchType(String searchType)   { this.searchType = searchType;   }
	public void setSearchValue(String searchValue) { this.searchValue = searchValue; }
}

 
 
noticeMapper

<select id="selectAll" parameterType="searchVO" resultType="noticeVO">
    SELECT n.*,uid FROM notice_board n 
        inner join user u 
         on n.uno = u.uno 
         WHERE state='E'
         <if test="searchType != null and searchType.equals('title')">
            AND title LIKE concat('%',#{searchValue} ,'%') 
         </if>
         <if test="searchType != null and searchType.equals('id')">
            AND uid LIKE concat('%',#{searchValue} ,'%') 
         </if>
         order by nno desc 
        limit #{start},#{perPage}	 
</select>

 
 
NoticeDAO

public int selectCount(SearchVO searchVO) {
    return sqlSession.selectOne("edu.springboard.mapper.noticeMapper.selectCount",searchVO);
}

 
 
NoticeServiceImpl

@Override
public int selectCount(SearchVO searchVO) {
    return noticeDAO.selectCount(searchVO);
}

 
 
NoticeService

public int selectCount(SearchVO searchVO);

 
 
 
NoticeController

@RequestMapping(value="/board/list.do")
public String noticeList(Model model,SearchVO searchVO
        , @RequestParam(value="nowPage", required = false, defaultValue = "1") int nowPage) {
    //@RequestParam의 value는 넘어오는 값을 그 이름으로
    //required false를 하면 필수가 아니고 값이 넘어오지 않을 경우 defaultValue로 적용된다

    System.out.println("nowPage:" + nowPage);

    //DB에서 공지사항의 전체 게시글 갯수를 조회
    int total = noticeService.selectCount(searchVO);
    System.out.println("공지글 갯수:" + total);


    //int nowPage,int total, int perPage
    PagingUtil paging = new PagingUtil(nowPage,total,5);

    searchVO.setStart(paging.getStart());
    searchVO.setPerPage(paging.getPerPage());
    System.out.println("paging.getStart():"+ paging.getStart());
    System.out.println("paging.getPerPage():"+ paging.getPerPage());
    //비지니스 로직 : DB에 있는 전체 회원 목록 데이터 가져오기
    List<NoticeVO> list = noticeService.selectAll(searchVO);
    //모델 객체 사용하여 조회 데이터 화면으로 포워딩
    model.addAttribute("list", list);

    return "notice/list";
}

 
 

@RequestParam

value (또는 name)

  • 클라이언트가 요청 시 전달하는 쿼리 파라미터의 이름을 지정합니다.
  • 지정된 이름의 값이 요청에 포함되어야만 매핑이 이루어집니다.
  • 예를 들어, /board/list.do?nowPage=3와 같은 요청이 들어오면, nowPage 파라미터의 값 3이 int nowPage 변수에 저장됩니다.

required

  • 기본값: true
  • true: 해당 파라미터가 요청에 반드시 포함되어야 함. 포함되지 않으면 예외 발생.
  • false: 요청에 파라미터가 없어도 허용.

defaultValue

  • 파라미터가 요청에 포함되지 않거나 빈 값일 경우 사용할 기본값을 지정합니다.
  • required = false와 함께 사용하는 것이 일반적입니다.
  • 만약 nowPage가 요청에 포함되지 않은 경우(/board/list.do), defaultValue에 지정된 기본값인 1이 nowPage에 할당됩니다.
  • required = false로 설정했기 때문에, nowPage가 쿼리 파라미터로 전달되지 않아도 예외가 발생하지 않습니다.

 
 
list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>공지사항목록조회</title>
<link rel="stylesheet" type="text/css" href="<%= request.getContextPath() %>/resources/css/spring.css" />
</head>
<body>
	<a href="<%= request.getContextPath() %>"><button class="sBtn">home</button></a>
	<h2>공지사항목록조회</h2><hr>
	<form action="list.do" method="get">
		<select name="searchType">
			<option value="title"
			<c:if test="${param.searchType eq 'title'}">
				selected
			</c:if>
			>제목</option>
			<option value="id"
			<c:if test="${param.searchType eq 'id'}">
				selected
			</c:if>
			>작성자(id)</option>
		</select>
		<input type="text" name="searchValue" value="${param.searchValue}">
		<button style="width:80px; height:30px;">검색</button>
	</form>
	<table border="0" style="text-align:center; width:700px;">
		<tr>
			<th style="width:60px; text-align:center; ">글번호</th>
			<th style="width:220px; text-align:center; ">제목</th>
			<th style="width:100px; text-align:center; ">작성자</th>
			<th style="width:160px; text-align:center; ">등록일</th>
		</tr>
		<c:forEach items="${list}" var="list">
		<tr>
			<td>${list.nno}</td>
			<td>
				<a href="view.do?nno=${list.nno}">${list.title}</a>
			</td>
			<td>${list.uid}</td>
			<td>${list.rdate}</td>
		</tr>
		</c:forEach>
	</table>
	<!-- 페이징 영역 -->
	<div style="text-align: center; width:700px;">
		<!-- 이전페이지로 이동 -->
		<c:if test="${paging.startPage > 1 }">
			<a href="list.do?nowPage=${paging.startPage-1}&searchValue=${param.searchValue}&searchType=${param.searchType}">&lt;</a>
		</c:if>
		
		<!-- 페이지번호 -->
		<c:forEach begin="${paging.startPage}" end="${paging.endPage}" var="cnt">
			<c:if test="${paging.nowPage eq cnt}">
				<b style="color:#FF5722;">${cnt}</b>
			</c:if>
			<c:if test="${paging.nowPage ne cnt}">
				<a href="list.do?nowPage=${cnt}&searchValue=${param.searchValue}&searchType=${param.searchType}">${cnt}</a>
			</c:if>
		</c:forEach>
		
		<!-- 다음페이지로 이동 -->
		<c:if test="${paging.endPage < paging.lastPage}">
			<a href="list.do?nowPage=${paging.endPage+1}&searchValue=${param.searchValue}&searchType=${param.searchType}">&gt;</a>
		</c:if>
	</div>
</body>
</html>

 


회원목록조회페이징

UserController

@RequestMapping(value="/user/list.do")
public String userList(Model model, HttpServletRequest request,SearchVO searchVO
        , @RequestParam(value="nowPage", required = false, defaultValue = "1") int nowPage) {
    //권한체크 : 로그인된 회원 권한이 관리자인지
    HttpSession session = request.getSession();
    if(session.getAttribute("loginUser") == null 
            ||	
        !((UserVO)session.getAttribute("loginUser")).getUauthor().equals("A")) {
        return "redirect:/";
    }


    System.out.println("nowPage:" + nowPage);

    int total = userService.selectCount(searchVO);
    System.out.println("공지글 갯수:" + total);

    PagingUtil paging = new PagingUtil(nowPage,total,3);

    searchVO.setStart(paging.getStart());
    searchVO.setPerPage(paging.getPerPage());
    System.out.println("paging.getStart():"+ paging.getStart());
    System.out.println("paging.getPerPage():"+ paging.getPerPage());

    //비지니스 로직 : DB에 있는 전체 회원 목록 데이터 가져오기
    List<UserVO> userList = userService.selectAll(searchVO);
    //모델 객체 사용하여 조회 데이터 화면으로 포워딩
    model.addAttribute("userList", userList);
    model.addAttribute("paging", paging);
    model.addAttribute("total", total);

    return "user/list";
}

 
 
UserService

package edu.springboard.service;

import java.util.List;

import edu.springboard.vo.SearchVO;
import edu.springboard.vo.UserVO;

public interface UserService {
	public int insert(UserVO userVO); //추상메소드
	public int update(UserVO userVO); //추상메소드
	public UserVO selectbyLogin(UserVO userVO); 
	public List<UserVO> selectAll(SearchVO searchVO); 
	public int selectCount(SearchVO searchVO); 
	public UserVO selectOne(String uno); 
}

 
 
 
UserServiceImpl

@Override
public List<UserVO> selectAll(SearchVO searchVO) {
    return userDAO.selectAll(searchVO);
}

@Override
public int selectCount(SearchVO searchVO) {
    return userDAO.selectCount(searchVO);
}

 
 
UserDAO

public List<UserVO> selectAll(SearchVO searchVO) {
    return sqlSession.selectList("edu.springboard.mapper.userMapper.selectAll",searchVO);
}

public int selectCount(SearchVO searchVO) {
    return sqlSession.selectOne("edu.springboard.mapper.userMapper.selectCount",searchVO);
}

 
 
 
UserMapper.xml

<select id="selectAll" parameterType="searchVO" resultType="userVO">
    SELECT * FROM user   
     <if test="searchType != null and searchType.equals('id')">
        WHERE uid LIKE concat('%',#{searchValue} ,'%')  
     </if>
     limit #{start},#{perPage}	
</select>

<select id="selectCount" parameterType="searchVO" resultType="int">
    SELECT count(*) as total FROM user 
     <if test="searchType != null and searchType.equals('id')">
        WHERE uid LIKE concat('%',#{searchValue} ,'%')
     </if>
</select>

 
 
list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원목록조회</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/resources/css/spring.css" />
</head>
<body>
	<a href="<%= request.getContextPath() %>"><button class="sBtn">home</button></a>
	<h2>회원목록조회</h2><hr>
	<form action="list.do" method="get">
		<select name="searchType">
			<option value="id"
			<c:if test="${param.searchType eq 'id'}">
				selected
			</c:if>
			>아이디</option>
			<option value="uname"
			<c:if test="${param.searchType eq 'uname'}">
				selected
			</c:if>
			>이름</option>
		</select>
		<input type="text" name="searchValue" value="${param.searchValue}">
		<button style="width:80px; height:30px;">검색</button>
	</form>
	<table border="0" style="text-align: center; width:550px;">
		<tr>
			<th style="text-align: center; width:60px;">회원번호</th>
			<th style="text-align: center; width:120px;">아이디</th>
			<th style="text-align: center; width:120px;">이름</th>
			<th style="text-align: center; width:160px;">가입일</th>
		</tr>
		<c:forEach items="${userList}" var="userList">
			<tr>
				<td>${userList.uno}</td>
				<td>
					<a href="view.do?uno=${userList.uno}">${userList.uid}</a>
				</td>
				<td>${userList.uname}</td>
				<td>${userList.rdate}</td>
			</tr>
		</c:forEach>
	</table>
	<!-- 페이징 영역 -->
	<div style="text-align: center; width:550px;">
		<!-- 이전페이지로 이동 -->
		<c:if test="${paging.startPage > 1 }">
			<a href="list.do?nowPage=${paging.startPage-1}&searchValue=${param.searchValue}&searchType=${param.searchType}">&lt;</a>
		</c:if>
		
		<!-- 페이지번호 -->
		<c:forEach begin="${paging.startPage}" end="${paging.endPage}" var="cnt">
			<c:if test="${paging.nowPage eq cnt}">
				<b style="color:#FF5722;">${cnt}</b>
			</c:if>
			<c:if test="${paging.nowPage ne cnt}">
				<a href="list.do?nowPage=${cnt}&searchValue=${param.searchValue}&searchType=${param.searchType}">${cnt}</a>
			</c:if>
		</c:forEach>
		
		<!-- 다음페이지로 이동 -->
		<c:if test="${paging.endPage < paging.lastPage}">
			<a href="list.do?nowPage=${paging.endPage+1}&searchValue=${param.searchValue}&searchType=${param.searchType}">&gt;</a>
		</c:if>
	</div>
</body>
</html>

공지글등록 후 조회

noticeMapper

<select id="selectOne" parameterType="int" resultType="noticeVO">
    SELECT n.*,uid FROM notice_board n 
                 inner join user u 
                 on n.uno = u.uno 
                 WHERE nno=#{nno}
</select>	

<insert id="insert" parameterType="noticeVO">
    insert into notice_board(
        title,
        content,
        uno
    ) values(
        #{title},
        #{content},
        #{uno}
    )

    <selectKey order="AFTER" resultType="int" keyProperty="nno">
        select max(nno) from notice_board
    </selectKey>
</insert>

 

selectKey

 
order="AFTER"

  • 이 속성은 SELECT 키가 실행될 타이밍을 지정합니다.
  • AFTER: INSERT 문 실행 후에 키 값을 가져옵니다.
  • BEFORE: INSERT 문 실행 전에 키 값을 가져옵니다.

resultType="int"

  • 키 값의 반환 타입을 지정합니다. 이 예에서는 반환 타입이 정수형(int)입니다.

 
keyProperty="nno"

  • 키 값을 매핑할 객체의 속성 이름을 지정합니다.
  • 반환된 값을 매핑할 객체의 nno 속성에 저장합니다

 
 
NoticeDAO

package edu.springboard.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import edu.springboard.vo.NoticeVO;
import edu.springboard.vo.SearchVO;

@Repository
public class NoticeDAO {
	@Autowired
	public SqlSession sqlSession;
	
	private final String namespace = "edu.springboard.mapper.noticeMapper";
	
	public List<NoticeVO> selectAll(SearchVO searchVO) {
		return sqlSession.selectList(namespace+".selectAll",searchVO);
	}
	
	public int selectCount(SearchVO searchVO) {
		return sqlSession.selectOne(namespace+".selectCount",searchVO);
	}
	
	public NoticeVO selectOne(int nno) {
		return sqlSession.selectOne(namespace+".selectOne",nno);
	}
	
	public int insert(NoticeVO noticeVO) {
		return sqlSession.insert(namespace+".insert",noticeVO);
	}
	
	public int selectLast() {
		return sqlSession.selectOne(namespace+".selectLast");
	}
}

 
 
NoticeServiceImpl

@Override
public NoticeVO selectOne(int nno) {
    return noticeDAO.selectOne(nno);
}

@Override
public int insert(NoticeVO noticeVO) {
    return noticeDAO.insert(noticeVO);
}

@Override
public int selectLast() {
    return noticeDAO.selectLast();
}

 
 
NoticeService

public NoticeVO selectOne(int nno); 
public int insert(NoticeVO noticeVO); 
public int selectLast();

 
 
NoticeController

@RequestMapping(value="/board/view.do")
public String view(int nno, Model model) {

    NoticeVO notice = noticeService.selectOne(nno);

    if(notice != null) {
        System.out.println("조회완료");
        model.addAttribute("notice",notice);

        return "notice/view";
    }else {
        System.out.println("조회실패");
        return "redirect:/";
    }
}


@RequestMapping(value="/board/write.do", method = RequestMethod.POST)
public String write(NoticeVO noticeVO,HttpServletRequest request) {

    HttpSession session = request.getSession();

    noticeVO.setUno(((UserVO)session.getAttribute("loginUser")).getUno());

    int result = noticeService.insert(noticeVO);

    if(result > 0) {
        System.out.println("글등록완료");
        /* int nno = noticeService.selectLast(); */
        System.out.println("nno:"+noticeVO.getNno());
        return "redirect:view.do?nno="+noticeVO.getNno();
    }else {
        System.out.println("글등록실패");
        return "redirect:write.do";
    }

}

 
 
 
NoticeVO

package edu.springboard.vo;

public class NoticeVO extends UserVO {
	private int nno;
	private String title;
	private String content;
	private String rdate;
	private String hit;
	private String state;
	private String topYn; //DB의 컬럼은 top_yn이지만 카멜기법을 사용해 topYn로 사용해도 적용된다 
	private String filename;
	
	public int getNno()         {	return nno;		 }
	public String getTitle()    {	return title;	 }
	public String getContent()  {	return content;	 }
	public String getRdate()    {	return rdate;	 }
	public String getHit()      {	return hit;		 }
	public String getState()    {	return state;	 }
	public String getTopYn()    {	return topYn;   }
	public String getFilename() {	return filename; }

	public void setNno(int nno)              {	this.nno = nno;			  }
	public void setTitle(String title)       {	this.title = title;	      }
	public void setContent(String content)   {	this.content = content;	  }
	public void setRdate(String rdate)       {	this.rdate = rdate;	      }
	public void setHit(String hit)           {	this.hit = hit;	          }
	public void setState(String state)       {	this.state = state;	      }
	public void setTopYn(String topYn)       {	this.topYn = topYn;	  }
	public void setFilename(String filename) {	this.filename = filename; }
		
}

게시글수정&삭제

NoticeController

@RequestMapping(value="/board/modify.do", method = RequestMethod.GET)
public String modify(int nno, Model model) {
    NoticeVO noticeVO = noticeService.selectOne(nno);
    model.addAttribute("view",noticeVO);
    return "notice/modify";
}

@RequestMapping(value="/board/modify.do", method = RequestMethod.POST)
public String modify(NoticeVO noticeVO) {
    int result = noticeService.update(noticeVO);

    if(result > 0) {
        System.out.println("글수정완료");
        return "redirect:view.do?nno="+noticeVO.getNno();
    }else {
        System.out.println("글수정실패");
        return "redirect:modify.do";
    }
}

@RequestMapping(value="/board/delete.do", method = RequestMethod.POST)
public String delete(int nno) {
    int result = noticeService.delete(nno);

    if(result > 0) {
        System.out.println("글삭제완료");
        return "redirect:list.do";
    }else {
        System.out.println("글삭제실패");
        return "redirect:view.do?nno="+nno;
    }
}

 
 
 
NoticeService

public int update(NoticeVO noticeVO); 
public int delete(int nno);

 
 
 
NoticeServiceImpl

@Override
public int update(NoticeVO noticeVO) {
    return noticeDAO.update(noticeVO);
}

@Override
public int delete(int nno) {
    return noticeDAO.delete(nno);
}

 
 
 
NoticeDAO

public int update(NoticeVO noticeVO) {
    return sqlSession.update(namespace+".noticeUpdate",noticeVO);
}

public int delete(int nno) {
    return sqlSession.update(namespace+".noticeDelete",nno);
}

 
 
noticeMapper

<update id="noticeUpdate" parameterType="noticeVO">
    UPDATE notice_board 
        SET title=#{title},
            content=#{content}
        WHERE nno=#{nno}
</update>

<update id="noticeDelete" parameterType="int">
    UPDATE notice_board 
        SET state='D'
        WHERE nno=#{nno}
</update>

 
 
view.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>공지글상세페이지</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/resources/css/spring.css" />
</head>
<body>
	<a href="<%= request.getContextPath() %>"><button class="sBtn">home</button></a><br>
	<a href="list.do"><button class="sBtn">공지글목록</button></a>
	<h2>공지사항상세페이지</h2><hr>
	<!-- 회원목록 페이지에서 id 클릭시 상세정보 페이지로 이동합니다 
	이때 클릭한 아이디 회원 정보를 전부 상세페이지에 출력합니다
	-->
	<table>
		<tr>
			<th>글번호 : </th>
			<td>${notice.nno}</td>
		</tr>
		<tr>
			<th>제목 : </th>
			<td>${notice.title}</td>
		</tr>
		<tr>
			<th>작성자 : </th>
			<td>${notice.uid}</td>
		</tr>
		<tr>
			<th>등록일 : </th>
			<td>${notice.rdate}</td>
		</tr>
		<tr>
			<th>내용 : </th>
			<td>
				<div style="white-space: pre-wrap;"><c:out value="${notice.content}" /></div>
			</td>
		</tr>
	</table>
	<c:if test="${notice.uno == loginUser.uno}">
		<a href="modify.do?nno=${notice.nno}"><button type="" style="width:80px; height:30px;">수정</button></a>
		<button style="width:80px; height:30px;" onclick="document.getElementById('deleteFn').submit();">삭제</button>
		<form action="delete.do" method="post" id="deleteFn">
			<input type="hidden" name="nno" value="${notice.nno}">
		</form>
	</c:if>
</body>
</html>

<div style="white-space: pre-wrap;"><c:out value="${notice.content}" /></div>

 
white-space 속성:

  • CSS 속성으로 텍스트가 표시되는 방식을 제어합니다.
  • pre-wrap은 텍스트를 줄바꿈 없이 유지하지만, 필요할 경우 컨테이너 폭에 따라 자동으로 줄을 바꿉니다.

pre-wrap의 동작:

  • HTML 코드에 작성된 줄바꿈(\n)과 공백이 그대로 유지됩니다.
  • 하지만 텍스트가 컨테이너의 폭을 초과하면 자동으로 줄바꿈이 일어납니다.

 
만약 위의 코드를 밑처럼 사용하게 될 경우 첫줄의 앞에 띄어쓰기가 적용되어 보여집니다

<div style="white-space: pre-wrap;">
	<c:out value="${notice.content}" />
</div>

 
 
 
modify.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>공지글수정</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/resources/css/spring.css" />
<style>
textarea{
	width: 250px;
	border: 1px solid #EEEEEE;
	border-radius: 5px;
}

input[type="text"]{
	width: 250px;
}
</style>
</head>
<body>
	<a href="<%= request.getContextPath() %>"><button class="sBtn">home</button></a>
	<h2>공지글수정</h2><hr>
	<form action="modify.do" method="post">
		<table>
			<tr>
				<th>제목 : </th>
				<td><input type="text" name="title" id="title" value="${view.title}"></td>
			</tr>
			<tr>
				<th>내용 : </th>
				<td>
					<textarea name="content" id="content" rows="10" cols="40">${view.content}</textarea>
				</td>
			</tr>
		</table>
		<br>
		<input type="hidden" name="nno" value="${view.nno}">
		<button>수정하기</button>
	</form>
</body>
</html>

 
 

반응형

'Spring' 카테고리의 다른 글

[Spring] AJAX 여러건의 데이터 받기  (0) 2024.11.30
[Spring] AJAX 한 건의 데이터 받기  (1) 2024.11.29
[Spring] Spring MVC  (2) 2024.11.27
[Spring] @Controller  (0) 2024.11.25
[Spring] 스프링 MVC 프로젝트  (0) 2024.11.24
  1. 공지사항목록조회
  2. 공지글검색
  3. 공지글페이징
  4. @RequestParam
  5. 회원목록조회페이징
  6. 공지글등록 후 조회
  7. 게시글수정&삭제
'Spring' 카테고리의 다른 글
  • [Spring] AJAX 여러건의 데이터 받기
  • [Spring] AJAX 한 건의 데이터 받기
  • [Spring] Spring MVC
  • [Spring] @Controller
초보개발자J
초보개발자J
J의 코딩 노트초보개발자J 님의 블로그입니다.
초보개발자J
J의 코딩 노트
초보개발자J
전체
오늘
어제
  • 분류 전체보기 (126)
    • Java (49)
    • MySQL (10)
    • HTML, CSS (8)
    • JavaScript, jQuery, Ajax (12)
    • Spring (15)
    • Python (0)
    • Baekjoon [Java] (27)
    • Git (1)
    • Spring Boot (3)
    • Visual Studio Code (1)
    • 일상 (0)
    • 영어 (0)
반응형

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

hELLO· Designed By정상우.v4.5.3
초보개발자J
[Spring] MVC 연습

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.