Spring MVC웹 서비스

정원·2022년 6월 8일
0

Spring

목록 보기
8/11

22.06.08

Spring MVC Model 연습

VO -> serviceInteface -> service -> daoInterface -> dao -> controller -> jsp
서로 의존 관계에 있다.
Interface로 변수를 선언하고 service,dao에 어노테이션을 등록.
메서드 마다 객체를 생성할 필요가 없어진다.

score

ScoreVO.java

<script>
package com.spring.basic.model;

public class ScoreVO {
	
	private String stuName;
	private int kor;
	private int eng;
	private int math;
	private int total;
	private double average;

	//총점,평균 구하는 메서드
	public void calcData() {
		this.total = this.kor + this.eng + this.math;
		this.average = Math.round((this.total / 3.0) * 100) / 100.0;
	}
	
    //getter, setter
	public String getStuName() {
		return stuName;
	}

	public void setStuName(String stuName) {
		this.stuName = stuName;
	}
	...
    
	@Override
	public String toString() {
		return "ScoreVO [stuName=" + stuName + ", 
        kor=" + kor + ", eng=" + eng + ", math=" + math + ", 
        total=" + total	+ ", average=" + average + "]";
	}	
}
</script>

IScoreService.java

<script>
package com.spring.basic.service;

import java.util.List;

import com.spring.basic.model.ScoreVO;

public interface IScoreService {
	
	//점수 등록
	void insertScore(ScoreVO score);
	
	//점수 전체 조회
	List<ScoreVO> selectAllScores();
	
	//점수 삭제
	void deleteScore(int num);
	
	//점수 개별 조회
	ScoreVO selectOne(int num);	
}
</script>

ScoreService.java

<script>
package com.spring.basic.service;

//자동 빈 등록
@Service
public class ScoreService implements IScoreService {
	
	//service와 DAO사이의 의존성 자동 주입을 위한 변수 선언.
	//메서드마다 객체를 생성할 필요가 없음.
	@Autowired
	private IScoreDAO dao;
	
	@Override
	public void insertScore(ScoreVO score) {
		score.calcData();//총점,평균 계산
		System.out.println("service: " + score);
		dao.insertScore(score);
	}

	@Override
	public List<ScoreVO> selectAllScores() {		
		return dao.selectAllScores();
	}

	@Override //화면에서 index+1값을 번호로 사용하기 때문에 index는 번호의 -1
	public void deleteScore(int num) {
		dao.deleteScore(num - 1);
	}

	@Override
	public ScoreVO selectOne(int num) {		 
		return dao.selectOne(num-1);
	}
}
</script>

IScoreDAO.java

<script>
package com.spring.basic.repository;

public interface IScoreDAO {

	//점수 등록
	void insertScore(ScoreVO score);
	
	//점수 전체 조회
	List<ScoreVO> selectAllScores();
	
	//점수 삭제
	void deleteScore(int num);
	
	//점수 개별 조회
	ScoreVO selectOne(int num);		
}
</script>

SocoreDAO.java

<script>
package com.spring.basic.repository;

@Repository //자동 빈 등록
public class ScoreDAO implements IScoreDAO {
	
	//싱글톤패턴 작성 할 필요없음.
	//학생들의 점수 정보를 저장할 리스트를 생성(DB 대용으로 사용)
	private List<ScoreVO> scoreList = new ArrayList<ScoreVO>();	

	@Override
	public void insertScore(ScoreVO score) {
		scoreList.add(score);
	}

	@Override
	public List<ScoreVO> selectAllScores() {		
		return scoreList;
	}

	@Override
	public void deleteScore(int num) {
		scoreList.remove(num);
	}

	@Override
	public ScoreVO selectOne(int num) {
		return scoreList.get(num);
	}
}
</script>

ScoreController.java

<script>
package com.spring.basic.controller;

@Controller
@RequestMapping("/score")
public class ScoreController {
	
	//컨트롤러와 서비스 계층 사이의 의존성 자동 주입을 위해 변수를 선언.
	@Autowired
	private IScoreService service;
	
	//점수 등록 화면을 열어주는 처리를 하는 메서드
	@GetMapping("/register")
	public String register() {
		System.out.println("/score/register: GET");
		return "score/write-form";
	}
	
	//점수 등록 요청을 처리할 메서드
	@PostMapping("/register")
	public String register(ScoreVO vo) {
		System.out.println("/score/register: POST");
		System.out.println("param: " + vo);
		service.insertScore(vo);//service에 받아온 객체 넣기
		return "score/write-result";
	}
	
	//점수 전체 조회를 처리하는 요청 메서드
	@GetMapping("/list")
	public void list(Model model) {
		System.out.println("/score/list: GET");
//		List<ScoreVO> list = service.selectAllScores(); 변수 필요 없으면 바로 model에 저장
		model.addAttribute("sList", service.selectAllScores());
	}
	
	//점수 삭제 요청 처리 메서드
	@GetMapping("/delete")
	public String delete(@RequestParam("stuNum") int stuNum, RedirectAttributes ra) {
		//삭제 처리를 완료하신 후 list 요청이 다시 컨트롤러로 들어갈 수 있도록 처리해 보세요.
	    //list요청이 다시 들어가서 list.jsp로 갔을 때, 삭제 이후에 간 것이 판단된다면
	    //브라우저에 '삭제가 완료되었습니다.' 문구를 빨간색으로 띄워보세요.
	    //(RedirectAttributes 사용, 경고창으로 띄워도 좋아요.)
		System.out.println("삭제할 할번: " + stuNum);
		service.deleteScore(stuNum);
		
//		ra.addFlashAttribute("msg", stuNum + "번의 삭제가 완료 되었습니다.");
		ra.addFlashAttribute("msg","delSuccess");//경고창
		return "redirect:/score/list";
	}
	
	//점수 개별 조회 화면 처리 메서드
	@GetMapping("/search")
	public void search() {
		System.out.println("/score/search: GET");
	}
	
	//점수 개별 조회 요청 처리 메서드
	@GetMapping("/selectOne")
	public String selectOne(@RequestParam("stuNum") int stuNum, 
							Model model, RedirectAttributes ra) {
		//전체 목록 끌어와서 길이보다 크거나 0과 같거나 작으면 학번이 없는 것이다.
		List<ScoreVO> list = service.selectAllScores();
		
		if(stuNum > list.size() || stuNum <= 0) {
			ra.addFlashAttribute("msg", "학번 정보가 없습니다.");
			return "redirect:/score/search";
		} else {
			model.addAttribute("stu", service.selectOne(stuNum));
			return "score/search-result";
		}		
	}
}
</script>

write-form.jsp

<body>
	<h2>시험점수등록</h2>
	<form method="post">
		<p>
			#이름: <input type="text" name="stuName"> <br>
			#국어: <input type="text" name="kor"><br>
			#영어: <input type="text" name="eng"><br>
			#수학: <input type="text" name="math"><br>
			<input type="submit" value="확인">
		</p>
	</form>	
</body>

write-result.jsp

컨텍스트루트 JSTL 이용하기

/basic 컨텍스트루트의 경우 변경,삭제 가능성이 높다.
해결방법.
JSTL : core 설정 추가 후
<a href="/basic/score/register">
아래코드로 컨텍스트루트 빼고 나머지 경로 value에 적어주기.
<a href="<c:url value='/score/register'/>">
<c:url value='uri 경로' />
- value속성 안에 컨텍스트 루트 경로를 제외한 절대 경로를 작성.
- 컨텍스츠 루트를 제외하고 연결이 가능. (컨텍스트 루트 변경 가능성을 대비)

<body>
	<h2>점수 등록 성공</h2>
	
	<p>
		<a href="<c:url value='/score/register' />">다른 점수 등록하기</a>
		<a href="<c:url value='/score/list' />">점수 전체 조회하기</a>
		<a href="<c:url value='/score/search' />">점수 개별 조회하기</a>
	</p>
</body>

list.jsp

varStatus

forEach태그에서 varStatus를 사용하면 반복문의 목록수나 목록의 현재 index,
count 등의 위치값을 사용할 수 있습니다.

<body>
	<h2>학생들의 전체 성적 조회</h2>
	<%-- forEach태그에서 varStatus를 사용하면 반복문의 목록수나 목록의 현재 index,
		count 등의 위치값을 사용할 수 있습니다. --%>
	<c:forEach var="stu" items="${sList}" varStatus="stuNum">
		<p>
			학번: ${stuNum.index+1}, 이름: ${stu.stuName}, 국어: ${stu.kor}, 영어: ${stu.eng},
			수학: ${stu.math}, 총점: ${stu.total}, 평균: ${stu.average}
			<a href="<c:url value='/score/delete?stuNum=${stuNum.index+1}'/>">[삭제]</a>
		</p> 		
	</c:forEach>
	
	<a href="<c:url value='/score/register' />"> 다른 점수 등록하기</a>
	
	<%-- <p style="color:red">
		${msg}
	</p>--%>
	
	<script type="text/javascript">
		const msg = "${msg}"
		if(msg === "delSuccess") {
			alert('삭제가 완료 되었습니다.')
		}
	</script>
</body>

search.jsp

<body>
	<%-- /selectOne 요청을 통해 해당 학번을 가진 학생의 성적 정보를 조회하여 
		search-result.jsp에 학생의 모든 정보를 적절하게 출력하세요. --%>
	<form action="<c:url value='/score/selectOne' />">
		<p>
			#조회할 학번: <input type="text" name="stuNum" size="5">
			<input type="submit" value="확인">
		</p>
	</form>
	<%-- 사용자가 입력한 학번의 학생이 없다면 "학번 정보가 없습니다." 메세지를 띄워보세요. --%>
</body>

search-result.jsp

<body>	
	<h2>${stuNum}번 학생 정보</h2>
	<p>
		#이름: ${stu.stuName} <br>
		#국어: ${stu.kor} <br>
		#영어: ${stu.eng} <br>
		#수학: ${stu.math} <br>
		#총점: ${stu.total} <br>
		#평균: ${stu.average} <br>
	</p>
	<a href="<c:url value='/score/search' />">점수 개별 조회</a>
	<p style="color:green;">
		${msg}
	</p>
</body>

Board

BoardVO.java

<script>
package com.spring.basic.model;

public class BoardVO {
	
	private String writer;
	private String title;
	private String content;
	
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
    ...
}
</script>

IBoardService.java

<script>
package com.spring.basic.service;

public interface IBoardService {
	
	//게시글 등록
	void insertArticle(BoardVO vo);
	
	//전제 게시글 목록
	List<BoardVO> getArticles();
	
	//게시글 상세 보기
	BoardVO getArticle(int bId);
	
	//게시글 삭제
	void deleteArticle(int bId);
	
	//게시글 수정
	void updateArticle(int bId, BoardVO vo);
}

</script>

BoardService.java

<script>
package com.spring.basic.service;

@Service
public class BoardService implements IBoardService {
	
	@Autowired
	private IBoardDAO dao;
	
	@Override
	public void insertArticle(BoardVO vo) {
		dao.insertArticle(vo);
	}

	@Override
	public List<BoardVO> getArticles() {		
		return dao.getArticles();
	}

	@Override
	public BoardVO getArticle(int bId) {
		return dao.getArticle(bId);
	}

	@Override
	public void deleteArticle(int bId) {
		dao.deleteArticle(bId);
	}

	@Override
	public void updateArticle(int bId, BoardVO vo) {
		dao.updateArticle(bId, vo);
	}
}
</script>

IBoardDAO.java

<script>
package com.spring.basic.repository;

public interface IBoardDAO {
	
	//게시글 등록
	void insertArticle(BoardVO vo);
	
	//전제 게시글 목록
	List<BoardVO> getArticles();
	
	//게시글 상세 보기
	BoardVO getArticle(int bId);
	
	//게시글 삭제
	void deleteArticle(int bId);
	
	//게시글 수정
	void updateArticle(int bId, BoardVO vo);
}
</script>

BoardDAO.java

<script>
package com.spring.basic.repository;

@Repository
public class BoardDAO implements IBoardDAO {
	
	//게시글을 저장할 리스트(DB 대용)
	private List<BoardVO> articles = new ArrayList<BoardVO>();

	@Override
	public void insertArticle(BoardVO vo) {
		articles.add(vo);
	}

	@Override
	public List<BoardVO> getArticles() {
		return articles;
	}

	@Override
	public BoardVO getArticle(int bId) {		
		return articles.get(bId - 1);
	}

	@Override
	public void deleteArticle(int bId) {
		articles.remove(bId - 1);
	}

	@Override
	public void updateArticle(int bId, BoardVO vo) {
		articles.set(bId - 1, vo);
	}
}
</script>

BoardController.java

<script>
package com.spring.basic.controller;

@Controller
@RequestMapping("/board")
public class BoardController {

	@Autowired
	private IBoardService service;

	// 글 작성 화면을 열어주는 메서드
	@GetMapping("/write")
	public void write() {
		System.out.println("/board/write: GET");
	}

	// 작성된 글 등록 처리 요청 메서드
	@PostMapping("/write")
	public String write(BoardVO vo) {
		System.out.println("/board/write: POST");
		service.insertArticle(vo);
		return "redirect:/board/list";
	}

	// 글 목록 화면 요청
	@GetMapping("/list")
	public void list(Model model) {
		System.out.println("/board/list: GET");
		model.addAttribute("articles", service.getArticles());
	}

	// 글 내용 상세보기 요청 처리 메서드
	@GetMapping("/content")
	public void content(@ModelAttribute("boardNo") int boardNo, Model model) {
		model.addAttribute("article", service.getArticle(boardNo));
	}

	// 글 수정하기 화면으로 이동 요청
	@GetMapping("/modify")
	public void modify(@ModelAttribute("boardNo") int boardNo, Model model) {
		System.out.println("/board/modify: GET");
		model.addAttribute("article", service.getArticle(boardNo));
	}
	
	// 글 수정 요청 메서드
	@PostMapping("/modify")
	public String modify(@RequestParam("boardNo") int boardNo, BoardVO vo) {
		System.out.println("/board/modify: POST");
		service.updateArticle(boardNo, vo); 
		return "redirect:/board/content?boardNo=" + boardNo;
	}	 

	// 글 삭제하기
	@GetMapping("/delete")
	public String delete(@RequestParam("boardNo") int boardNo) {
		service.deleteArticle(boardNo);
		return "redirect:/board/list";
	}
}
</script>

write.jsp

<body>
	<h2>게시글 등록</h2>
	<form method="post">
		<p>
			# 작성자: <input type="text" name="writer"> <br>
			# 제목: <input type="text" name="title"> <br>
			# 내용: <textarea rows="3" name="content"></textarea> <br>
			<input type="submit" value="등록">
		</p>
	</form>
</body>

list.jsp

<body>
	<h2>게시글 목록</h2>
	<table border="1">
		<tr> 
			<th>글번호</th>
			<th>제목</th>
			<th>작성자</th>
			<th>비고</th>
		</tr>
		<c:forEach var="article" items="${articles}" varStatus="num">
			<tr>
				<td>${num.index+1}</td> 
				<td>
					<a href="<c:url value='/board/content?boardNo=${num.index+1}'/>">${article.title}</a>
				</td> 
				<td>${article.writer}</td> 
				<td>
					<a href="<c:url value='/board/delete?boardNo=${num.index+1}'/>">[삭제]</a>
				</td> 
			</tr>
		</c:forEach>
	</table>
	
	<a href="<c:url value='/board/write' />">게시물 작성하기</a>
</body>

content.jsp

<body>
	<h2> ${boardNo}번 게시물 내용</h2>
	<p>
		# 작성자: ${article.writer}<br>
		# 제목: ${article.title} <br>
		# 내용: <textarea rows="5" readonly=>${article.content}</textarea>
	</p>
	
	<a href="<c:url value='/board/list'/>">글 목록 보기</a>
	<a href="<c:url value='/board/modify?boardNo=${boardNo}'/>">글 수정 하기</a>
</body>

modify.jsp

<body>
	<h2>${boardNo}번 게시물 내용 수정</h2>
	<form method="post">
		<input type="hidden" name="boardNo" value="${boardNo}">
		<p>
			# 작성자: <input type="text" name="writer" value="${article.writer}"> <br>
			# 제목: <input type="text" name="title" value="${article.title}"> <br>
			# 내용: <textarea rows="3" name="content">${article.content}</textarea>
			<input type="submit" value="수정">
		</p>
	</form>
</body>

0개의 댓글