<!-- * 실습 (공지사항 수정하기) 1) 공지사항 상세페이지에서 수정페이지로 이동 링크 만들기 (/notice/modifyForm.do?no=현재글번호 url 요청되도록) 2) 해당 url 요청시 실행되는 Controller 작업 ㄴ 요청시 전달되는 파라미터(수정할글번호) 뽑기 ㄴ 해당 번호로 공지사항 조회 서비스 요청 ㄴ 조회된 공지사항 객체를 수정페이지에서 사용할수 있도록 담기 ㄴ 수정페이지로 포워딩 3) 해당 url 요청시 포워딩되는 수정페이지(/WEB-INF/views/notice/modifyForm.jsp) 제작하기 ㄴ 수정할수 있는 폼요소로 만들기 (제목 텍스트상자, 내용 텍스트상자 존재) 이때 조회된 기존의 공지사항 정보 노출시키기 ㄴ 수정 요청을 보낼 수 있는 submit 버튼 두기 ㄴ 수정 요청시 /notice/update.do url로 요청되도록 4) 해당 url 요청시 실행되는 Controller 작업 ㄴ 요청시 전달되는 파라미터들(번호(숨김상태로), 제목, 내용)을 NoticeDto 객체의 필드에 바로 매핑될 수 있도록 하기 ㄴ 해당 NoticeDto 객체를 전달하면서 수정요청할 수 있는 service측 메소드 만들기 ㄴ dao측도 만들기 (이때 그냥 1로 반환되도록 하기 or 넘겨받은 글번호로 찾아서 반환) ㄴ 성공했을 경우 상세페이지로 다시 이동될수있도록 하기 -->
ㅁ detail.jsp
< %@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
< c:set var = "contextPath" value = "${pageContext.request.contextPath}" />
<! DOCTYPE html >
< html >
< head >
< meta charset = "UTF-8" >
< title > Insert title here </ title >
</ head >
< body >
< h3 > 공지사항 상세 페이지 </ h3 >
< c:choose >
< c:when test = "${ empty notice }" >
조회된 공지사항이 없습니다.
</ c:when >
< c:otherwise >
번호 : ${ notice.no } < br >
제목 : ${ notice.title } < br >
내용 : ${ notice.content } < br >< br >
< a href = "${contextPath}/notice/modifyForm.do?no=${notice.no}" > 수정페이지로 이동 </ a >
</ c:otherwise >
</ c:choose >
</ body >
</ html >
ㅁ NoticeController
package com.br.mvc.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.br.mvc.dto.NoticeDto;
import com.br.mvc.service.NoticeService;
import lombok.RequiredArgsConstructor;
@ RequiredArgsConstructor // lombok
//@AllArgsConstructor lombok
@ RequestMapping ( "/notice" )
@ Controller
public class NoticeController {
// 직접 생성하면 결합도가 높아지는 문제가 있다. 매번 생성해서 메모리도 많이 사용한다.
// private NoticeService noticeService = new NoticeServiceImpl();
// @Autowired로 스프링에게서 주입받아 사용한다.
// 그러려면 NoticeServiceImpl을 빈으로 등록해야 한다.
// xml 파일에 가서 빈 등록을 해도 되지만 NoticeServiceImpl 클래스 위에 @Service 어노테이션을 작성하면 빈 스캐닝에 의해 빈 등록이 된다.
/*
(1) 필드 주입 방식
@Autowired
private NoticeService noticeService;
*/
/*
(2) 메소드 주입 방식
private NoticeService noticeService;
@Autowired
public void setNoticeService(NoticeService noticeService) { // 자동실행
this.noticeService = noticeService;
}
*/
//(3) 생성자 주입 방식 (생성자는 자동으로 실행되기 때문에 @Autowired 생략 가능)
private int no ;
private final NoticeService noticeService ;
/*
public NoticeController(NoticeService noticeService) { <- 롬복
this.noticeService = noticeService;
}
*/
// =========== 포워딩할 응답페이지에 필요한 데이터를 담는 방법 ===========
// (1) Model 객체 이용하기
@ GetMapping ( "/list.do" )
public String noticeList ( Model model ) {
List < NoticeDto > list = noticeService . selectNoticeList (); // 응답페이지에 필요한 데이터
model . addAttribute ( "list" , list);
// /WEB-INF/views/notice/list.jsp로 포워딩
return "notice/list" ;
}
// (2) ModelAndView 객체 이용하기
@ GetMapping ( "/detail.do" )
public ModelAndView noticeDetail ( int no , ModelAndView mv ) { // key값과 매개변수명이 같으면 @RequestParam 생략가능
// NoticeDto n = noticeService.selectNoticeByNo(no); 응답 페이지에 필요한 데이터
// return "notice/detial"; 응답뷰
mv . addObject ( "notice" , noticeService . selectNoticeByNo (no)); // 응답 페이지에 필요한 데이터
mv . setViewName ( "notice/detail" ); // 응답뷰
// mv.addObject("notice", noticeService.selectNoticeByNo(no)).setViewName("notice/detail");
// addObject 메소드가 해당 ModelAndView 객체를 반환하기 때문에 한줄로 메소드 체이닝 가능하다.
return mv;
}
@ RequestMapping ( "/modifyForm.do" )
public String noticeModifyForm ( int no , Model model ) {
NoticeDto notice = noticeService . selectNoticeByNo (no);
model . addAttribute ( "notice" , notice);
return "notice/modifyForm" ;
}
}
- noticeModifyForm 메소드를 만든다.
- 매개변수에 두면 스프링이 알아서 주입해준다.
ㅁ notice 폴더에 modifyForm.jsp를 만든다.
< %@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
< c:set var = "contextPath" value = "${pageContext.request.contextPath}" />
<! DOCTYPE html >
< html >
< head >
< meta charset = "UTF-8" >
< title > Insert title here </ title >
</ head >
< body >
< h2 > 공지사항 수정 페이지 </ h2 >
< form action = "${contextPath}/notice/update.do" method = "post" >
제목 : < input type = "text" value = "${notice.title}" > < br >
내용 : < textarea > ${ notice.content } </ textarea >
< input type = "submit" value = "수정" >
</ form >
</ body >
</ html >
ㅁ ModifyForm.jsp
< %@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
< c:set var = "contextPath" value = "${pageContext.request.contextPath}" />
<! DOCTYPE html >
< html >
< head >
< meta charset = "UTF-8" >
< title > Insert title here </ title >
</ head >
< body >
< h2 > 공지사항 수정 페이지 </ h2 >
< form action = "${contextPath}/notice/update.do" method = "post" >
< input type = "hidden" name = "no" value = "${notice.no}" >
제목 : < input type = "text" name = "title" value = "${notice.title}" > < br >
내용 : < textarea name = "content" > ${ notice.content } </ textarea >
< input type = "submit" value = "수정" >
</ form >
</ body >
</ html >
- input 요소 중 제목에 name="title", 내용에 name="content"를 준다.
- 특정 게시글만 업데이트되도록 hidden타입 input으로 글번호를 넘긴다.
ㅁ NoticeController
package com.br.mvc.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.br.mvc.dto.NoticeDto;
import com.br.mvc.service.NoticeService;
import lombok.RequiredArgsConstructor;
@ RequiredArgsConstructor // lombok
//@AllArgsConstructor lombok
@ RequestMapping ( "/notice" )
@ Controller
public class NoticeController {
// 직접 생성하면 결합도가 높아지는 문제가 있다. 매번 생성해서 메모리도 많이 사용한다.
// private NoticeService noticeService = new NoticeServiceImpl();
// @Autowired로 스프링에게서 주입받아 사용한다.
// 그러려면 NoticeServiceImpl을 빈으로 등록해야 한다.
// xml 파일에 가서 빈 등록을 해도 되지만 NoticeServiceImpl 클래스 위에 @Service 어노테이션을 작성하면 빈 스캐닝에 의해 빈 등록이 된다.
/*
(1) 필드 주입 방식
@Autowired
private NoticeService noticeService;
*/
/*
(2) 메소드 주입 방식
private NoticeService noticeService;
@Autowired
public void setNoticeService(NoticeService noticeService) { // 자동실행
this.noticeService = noticeService;
}
*/
//(3) 생성자 주입 방식 (생성자는 자동으로 실행되기 때문에 @Autowired 생략 가능)
private int no ;
private final NoticeService noticeService ;
/*
public NoticeController(NoticeService noticeService) { <- 롬복
this.noticeService = noticeService;
}
*/
// =========== 포워딩할 응답페이지에 필요한 데이터를 담는 방법 ===========
// (1) Model 객체 이용하기
@ GetMapping ( "/list.do" )
public String noticeList ( Model model ) {
List < NoticeDto > list = noticeService . selectNoticeList (); // 응답페이지에 필요한 데이터
model . addAttribute ( "list" , list);
// /WEB-INF/views/notice/list.jsp로 포워딩
return "notice/list" ;
}
// (2) ModelAndView 객체 이용하기
@ GetMapping ( "/detail.do" )
public ModelAndView noticeDetail ( int no , ModelAndView mv ) { // key값과 매개변수명이 같으면 @RequestParam 생략가능
// NoticeDto n = noticeService.selectNoticeByNo(no); 응답 페이지에 필요한 데이터
// return "notice/detial"; 응답뷰
mv . addObject ( "notice" , noticeService . selectNoticeByNo (no)); // 응답 페이지에 필요한 데이터
mv . setViewName ( "notice/detail" ); // 응답뷰
// mv.addObject("notice", noticeService.selectNoticeByNo(no)).setViewName("notice/detail");
// addObject 메소드가 해당 ModelAndView 객체를 반환하기 때문에 한줄로 메소드 체이닝 가능하다.
return mv;
}
@ RequestMapping ( "/modifyForm.do" )
public String noticeModifyForm ( int no , Model model ) {
NoticeDto notice = noticeService . selectNoticeByNo (no);
model . addAttribute ( "notice" , notice);
return "notice/modifyForm" ;
}
@ PostMapping ( "/update.do" )
public String noticeUpdate ( NoticeDto n ) { // 1) 요청시 전달값 처리 - 커맨드 객체
// 2) 요청처리를 위한 서비스 호출
int result = noticeService . updateNotice (n);
// 3) 응답
if (result > 0 ) {
// return "notice/detail"; 이건 포워딩이다.
return "redirect:/notice/detail.do?no=" + n . getNo ();
// 스프링에서 "redirect:" 뒤에 context path 안줘도 됨.
// 여기에도 글번호 넘겨야 함.
} else {
// return "main"; 이렇게 하면 메인페이지가 뜨긴 하는데 url이 메인 페이지가 아니라 /update.do다.
// MvcController 가보면 이미 메인페이지로 이동하는 메소드가 정의되어 있음.
return "redirect:/" ;
}
}
}
- noticeUpdate() 메소드를 만든다.
- 매개변수로 NoticeDto n을 둬서 커맨드 객체 방식을 사용한다.
ModifyForm.jsp <- input 태그의 name 속성값(key값)과 NoticeDto의 필드명과 일치시킨다. 그러면 자동으로 담긴다.
- 1) 요청시 전달값 처리
- 2) 요청 처리를 위한 서비스 호출
- 3) 응답
- detail.jsp를 보면 notice 객체에서 값을 뽑는데 notice객체를 우리가 넘기지 않았다.
포워딩을 하고 싶다면 model 객체를 만들어서 notice라는 key값으로 notice 객체가 담겨있어야 한다.
- NoticeController의 noticeDetail 메소드를 보면 no만 넘기면 그 게시글을 조회해서 notice로 담아서 넘기는 메소드가 이미 정의되어 있다.
- response.sendRedirect(request.getContextPath() + "/notice/detail.do");
스프링을 사용하지 않을 때(Servlet이나 JSP를 사용하여 직접 리다이렉트를 구현할 경우)에는 context path를 명시해야 했다.
ㅁ NoticeService
package com.br.mvc.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.br.mvc.dto.NoticeDto;
public interface NoticeService {
// 목록조회
List < NoticeDto > selectNoticeList ();
// 상세조회
NoticeDto selectNoticeByNo ( int noticeNo );
// 수정
int updateNotice ( NoticeDto n );
}
- updateNotice 추상메소드를 만든다.
ㅁ NoticeServiceImpl
package com.br.mvc.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.br.mvc.dao.NoticeDao;
import com.br.mvc.dto.NoticeDto;
import lombok.RequiredArgsConstructor;
@ Service // Service 역할의 클래스에 부여하는 Component 어노테이션 (빈 스캐닝에 의해 자동으로 빈 등록됨)
@ RequiredArgsConstructor
public class NoticeServiceImpl implements NoticeService {
private final NoticeDao noticeDao ;
@ Override
public List < NoticeDto > selectNoticeList () {
return noticeDao . selectNoticeList ();
}
@ Override
public NoticeDto selectNoticeByNo ( int noticeNo ) {
return noticeDao . selectNoticeByNo (noticeNo);
}
@ Override
public int updateNotice ( NoticeDto n ) {
return noticeDao . updateNotice (n);
}
}
- updateNotice 추상메소드를 구현한다.
ㅁ NoticeDao
package com.br.mvc.dao;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.br.mvc.dto.NoticeDto;
@ Repository // dao 역할의 클래스에 부여하는 Componenet 어노테이션(빈 스캐닝에 의해 빈 등록됨)
public class NoticeDao {
// db에서 조회되었다고 가정하고 샘플데이터 만들기
// db에 담겨있는 공지사항 데이터 재사용
// list를 생성하고 add로 담지 않고, 한줄로 끝냄.
private List < NoticeDto > dbList = Arrays . asList (
new NoticeDto ( 1 , "제목1" , "내용1" )
, new NoticeDto ( 2 , "제목2" , "내용2" )
, new NoticeDto ( 3 , "제목3" , "내용3" ) );
public List < NoticeDto > selectNoticeList (){
return dbList;
}
public NoticeDto selectNoticeByNo ( /*SqlSession sqlSession,*/ int noticeNo ) {
// return 쿼리결과;
// 그냥 3개의 NoticeDto 객체 중에서 하나를 찝어도 되고,
for ( NoticeDto n : dbList) {
if ( n . getNo () == noticeNo) {
return n;
}
}
return null ; // db 연동해도 조회결과 없으면 null 반환이다. for문이 끝나기 전까지 조회결과를 못찾으면 null 반환.
}
public int updateNotice ( NoticeDto n ) {
// 원래라면 쿼리 실행. 그러나 지금 db 연동이 되어있지 않으므로 가상의 dbList를 사용한다.
for ( NoticeDto notice : dbList) {
if ( notice . getNo () == n . getNo ()) {
notice . setTitle ( n . getTitle ());
notice . setContent ( n . getContent ());
return 1 ; // 업데이트 성공
}
}
return 0 ;
}
}
- updateNotice 메소드를 만든다.
===========================================================================================
ㅁ 수정 성공시 alert 띄우기
package com.br.mvc.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.br.mvc.dto.NoticeDto;
import com.br.mvc.service.NoticeService;
import lombok.RequiredArgsConstructor;
@ RequiredArgsConstructor // lombok
//@AllArgsConstructor lombok
@ RequestMapping ( "/notice" )
@ Controller
public class NoticeController {
// 직접 생성하면 결합도가 높아지는 문제가 있다. 매번 생성해서 메모리도 많이 사용한다.
// private NoticeService noticeService = new NoticeServiceImpl();
// @Autowired로 스프링에게서 주입받아 사용한다.
// 그러려면 NoticeServiceImpl을 빈으로 등록해야 한다.
// xml 파일에 가서 빈 등록을 해도 되지만 NoticeServiceImpl 클래스 위에 @Service 어노테이션을 작성하면 빈 스캐닝에 의해 빈 등록이 된다.
/*
(1) 필드 주입 방식
@Autowired
private NoticeService noticeService;
*/
/*
(2) 메소드 주입 방식
private NoticeService noticeService;
@Autowired
public void setNoticeService(NoticeService noticeService) { // 자동실행
this.noticeService = noticeService;
}
*/
//(3) 생성자 주입 방식 (생성자는 자동으로 실행되기 때문에 @Autowired 생략 가능)
private int no ;
private final NoticeService noticeService ;
/*
public NoticeController(NoticeService noticeService) { <- 롬복
this.noticeService = noticeService;
}
*/
// =========== 포워딩할 응답페이지에 필요한 데이터를 담는 방법 ===========
// (1) Model 객체 이용하기
@ GetMapping ( "/list.do" )
public String noticeList ( Model model ) {
List < NoticeDto > list = noticeService . selectNoticeList (); // 응답페이지에 필요한 데이터
model . addAttribute ( "list" , list);
// /WEB-INF/views/notice/list.jsp로 포워딩
return "notice/list" ;
}
// (2) ModelAndView 객체 이용하기
@ GetMapping ( "/detail.do" )
public ModelAndView noticeDetail ( int no , ModelAndView mv ) { // key값과 매개변수명이 같으면 @RequestParam 생략가능
// NoticeDto n = noticeService.selectNoticeByNo(no); 응답 페이지에 필요한 데이터
// return "notice/detial"; 응답뷰
mv . addObject ( "notice" , noticeService . selectNoticeByNo (no)); // 응답 페이지에 필요한 데이터
mv . setViewName ( "notice/detail" ); // 응답뷰
// mv.addObject("notice", noticeService.selectNoticeByNo(no)).setViewName("notice/detail");
// addObject 메소드가 해당 ModelAndView 객체를 반환하기 때문에 한줄로 메소드 체이닝 가능하다.
return mv;
}
@ RequestMapping ( "/modifyForm.do" )
public String noticeModifyForm ( int no , Model model ) {
NoticeDto notice = noticeService . selectNoticeByNo (no);
model . addAttribute ( "notice" , notice);
return "notice/modifyForm" ;
}
@ PostMapping ( "/update.do" )
public String noticeUpdate ( NoticeDto n , Model model ) { // 1) 요청시 전달값 처리 - 커맨드 객체
// 2) 요청처리를 위한 서비스 호출
int result = noticeService . updateNotice (n);
// 3) 응답
if (result > 0 ) {
// return "notice/detail"; 이건 포워딩이다.
model . addAttribute ( "alertMsg" , "성공적으로 수정되었습니다." );
return "redirect:/notice/detail.do?no=" + n . getNo (); // context path 안줘도 됨. 여기에도 글번호 넘겨야 함.
} else {
// return "main"; 이렇게 하면 메인페이지가 뜨긴 하는데 url이 메인 페이지가 아니라 /update.do다.
// MvcController 가보면 이미 메인페이지로 이동하는 메소드가 정의되어 있음.
return "redirect:/" ;
}
}
}
- noticeUpdate 메소드에 수정 성공시 alert를 띄우기 위해서 model.addAttribute("alertMsg", "성공적으로 수정되었습니다.");를 추가했다.
ㅁ detail.jsp
< %@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
< c:set var = "contextPath" value = "${pageContext.request.contextPath}" />
<! DOCTYPE html >
< html >
< head >
< meta charset = "UTF-8" >
< title > Insert title here </ title >
</ head >
< body >
< c:if test = "${ not empty alertMsg }" >
< script >
alert ( "${alertMsg}" );
</ script >
</ c:if >
< h3 > 공지사항 상세 페이지 </ h3 >
< c:choose >
< c:when test = "${ empty notice }" >
조회된 공지사항이 없습니다.
</ c:when >
< c:otherwise >
번호 : ${ notice.no } < br >
제목 : ${ notice.title } < br >
내용 : ${ notice.content } < br >< br >
< a href = "${contextPath}/notice/modifyForm.do?no=${notice.no}" > 수정페이지로 이동 </ a >
</ c:otherwise >
</ c:choose >
</ body >
</ html >
- detail.jsp에 오는 경우가 2가지다. 그냥 오는경우, 수정 후 오는 경우. 수정 후 오는 경우에만 alertMsg가 있다.
ㅁ 그런데 alert가 뜨지 않는다.
- 처음 상세페이지가 뜰 때는 alert가 안 뜨는 것이 맞다.
- 그런데 수정하고 상세페이지로 redirect할 때도 alert가 안 뜬다.
- 그리고 url에 파라미터로 되어있다.
- 포워딩이 아니라 redirect인데 model 객체에 담으면 파라미터로 된다.
- 포워딩 방식이었으면 됐을 건데 포워딩은 적절치 않아서 redirct를 했다.
noticeDetail 메소드를 호출하기 때문에 거기서 포워딩 할 때는 model에 notice 객체 밖에 담겨있지 않다.
- 전에는 redirect할 때 session에 담았었다.
session은 일회용이 아니라 꼐속 담겨있기 때문에 우리가 지우는 것까지 했었다.
ㅁ redirect시 포워딩 되는 페이지에 필요한 데이터를 담는 방법
- model 객체는 따지고보면 request scope다. 그래서 바로 포워딩되는 jsp에서만 사용 가능하다.
- redirect로 다른 controller가 실행되는 순간 현재 만들어진 Model 객체는 소멸된다.
- 특정 url로 요청해서 controller가 실행되고, 거기서 바로 포워딩(주로 조회페이지로 이동)하는 경우에는 controller에서 생성하는 Model 객체에 데이터를 담으면 포워딩된 jsp까지 Model 객체가 유지된다.
- 그런데 지금 케이스는 수정 url을 요청해서 controller(/update.do)가 실행되고, 여기서 성공하면 redirect로 다른 controller(/detail.do)를 재요청했다. 두번째 컨트롤러에서 포워딩을해서 /notice/detail.jsp가 보여진다.
- 처음 컨트롤러에서 만든 Model 객체는 2번째 컨트롤러로 리다이렉트할 때 사라지고, 두번째 컨트롤러에서 만든 모델 객체만 포워딩된 jsp에도 유지된다.
- RedirectAttributes 객체를 생성해서 데이터를 담으면 건너 건너 포워딩된 페이지(jsp)까지 RedirectAttributes 객체가 유지된다.
- 즉 현재 controller에서 url 재요청을 통해 다른 controller에 의해 포워딩되는 jsp에서까지 데이터를 쭉 사용하고 싶다면 Model 객체가 아니라 RedirectAttributes 객체를 사용하면 된다.
이때 addAttribute 메소드도 있는데 그걸로 담으면 Model에 담은 것과 동일하다.
addFlashAttribute 메소드로 담으면 된다.
- RedirectAttributes는 Model의 역할도 하고 멀티다.
- 스프링에서 제공하는 객체다.
ㅁ NoticeController
package com.br.mvc.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.br.mvc.dto.NoticeDto;
import com.br.mvc.service.NoticeService;
import lombok.RequiredArgsConstructor;
@ RequiredArgsConstructor // lombok
//@AllArgsConstructor lombok
@ RequestMapping ( "/notice" )
@ Controller
public class NoticeController {
// 직접 생성하면 결합도가 높아지는 문제가 있다. 매번 생성해서 메모리도 많이 사용한다.
// private NoticeService noticeService = new NoticeServiceImpl();
// @Autowired로 스프링에게서 주입받아 사용한다.
// 그러려면 NoticeServiceImpl을 빈으로 등록해야 한다.
// xml 파일에 가서 빈 등록을 해도 되지만 NoticeServiceImpl 클래스 위에 @Service 어노테이션을 작성하면 빈 스캐닝에 의해 빈 등록이 된다.
/*
(1) 필드 주입 방식
@Autowired
private NoticeService noticeService;
*/
/*
(2) 메소드 주입 방식
private NoticeService noticeService;
@Autowired
public void setNoticeService(NoticeService noticeService) { // 자동실행
this.noticeService = noticeService;
}
*/
//(3) 생성자 주입 방식 (생성자는 자동으로 실행되기 때문에 @Autowired 생략 가능)
private int no ;
private final NoticeService noticeService ;
/*
public NoticeController(NoticeService noticeService) { <- 롬복
this.noticeService = noticeService;
}
*/
// =========== 포워딩할 응답페이지에 필요한 데이터를 담는 방법 ===========
// (1) Model 객체 이용하기
@ GetMapping ( "/list.do" )
public String noticeList ( Model model ) {
List < NoticeDto > list = noticeService . selectNoticeList (); // 응답페이지에 필요한 데이터
model . addAttribute ( "list" , list);
// /WEB-INF/views/notice/list.jsp로 포워딩
return "notice/list" ;
}
// (2) ModelAndView 객체 이용하기
@ GetMapping ( "/detail.do" )
public ModelAndView noticeDetail ( int no , ModelAndView mv ) { // key값과 매개변수명이 같으면 @RequestParam 생략가능
// NoticeDto n = noticeService.selectNoticeByNo(no); 응답 페이지에 필요한 데이터
// return "notice/detial"; 응답뷰
mv . addObject ( "notice" , noticeService . selectNoticeByNo (no)); // 응답 페이지에 필요한 데이터
mv . setViewName ( "notice/detail" ); // 응답뷰
// mv.addObject("notice", noticeService.selectNoticeByNo(no)).setViewName("notice/detail");
// addObject 메소드가 해당 ModelAndView 객체를 반환하기 때문에 한줄로 메소드 체이닝 가능하다.
return mv;
}
@ RequestMapping ( "/modifyForm.do" )
public String noticeModifyForm ( int no , Model model ) {
NoticeDto notice = noticeService . selectNoticeByNo (no);
model . addAttribute ( "notice" , notice);
return "notice/modifyForm" ;
}
@ PostMapping ( "/update.do" )
public String noticeUpdate ( NoticeDto n , /*Model model*/ RedirectAttributes ra ) { // 1) 요청시 전달값 처리 - 커맨드 객체
// 2) 요청처리를 위한 서비스 호출
int result = noticeService . updateNotice (n);
// 3) 응답
if (result > 0 ) {
// return "notice/detail"; 이건 포워딩이다.
//model.addAttribute("alertMsg", "성공적으로 수정되었습니다.");
ra . addFlashAttribute ( "alertMsg" , "성공적으로 수정되었습니다." );
return "redirect:/notice/detail.do?no=" + n . getNo (); // context path 안줘도 됨. 여기에도 글번호 넘겨야 함.
} else {
// return "main"; 이렇게 하면 메인페이지가 뜨긴 하는데 url이 메인 페이지가 아니라 /update.do다.
// MvcController 가보면 이미 메인페이지로 이동하는 메소드가 정의되어 있음.
return "redirect:/" ;
}
}
}
- 우리가 직접 생성할 필요 없이 매개변수에 써두기만 하면 된다.
- session에 담아도 되는데 session은 계속 유지가 돼서 내가 비워줘야 했다.
이건 한번 하고 끝남.
- detail.jsp는 수정하지 않았다.
- 이렇게 작성하면 업데이트 성공 후 alert 메세지가 뜬다.