목차는 다음과 같다.
1. 다양한 @과 속성
1) method
2) @ModelAttribute
3) Model클래스
4) @RequestParam
해당 포스팅까지의 작업이 담긴 코드는 아래 링크를 통해 확인할 수 있다.
https://github.com/Hamjeonghui/Spring_MVC_2.git
GitHub - Hamjeonghui/Spring_MVC_2
Contribute to Hamjeonghui/Spring_MVC_2 development by creating an account on GitHub.
github.com
1. 다양한 @과 속성
1) method
view에서 특정 요청에 대한 method의 전송 방법이 get인지, post인지에 따라 요청에 대한 처리를 다르게 설정할 수 있게 해주는 속성이다.
사용 예시는 아래와 같다.
package com.test.app.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.test.app.member.MemberVO;
import com.test.app.member.impl.MemberDAO;
@Controller
public class MemberController {
@RequestMapping(value="/login.do", method =RequestMethod.POST) //method방식이 post인 경우
public String login_post(MemberVO vo,MemberDAO memberDAO,HttpSession session) {
System.out.println("post로 로그인 요청");
vo=memberDAO.getMember(vo);
if(vo==null){
return "redirect:login.jsp";
}
session.setAttribute("member", vo);
return "redirect:main.do";
}
@RequestMapping(value="/login.do", method =RequestMethod.GET) //method방식이 get인 경우
public String login_get(MemberVO vo) { // view에서 넘어오는 정보가 없어도 커맨드객체 사용함
System.out.println("get으로 로그인 요청");
// 테스트 전달 데이터!
vo.setId("test"); //${memberVO.id} -> 클래스의 맨 첫글자를 대문자-소문자로 변경해주면 호출 가능
vo.setPassword("1234");//${memberVO.password}
return "login.jsp"; //redirect일 필요 없어짐
}
}
@RaquestMapping어노테이션에 value와 함께 method=RequestMethod.요청 방식을 통해 요청 방식에 대한 처리를 다르게 구분해줄 수 있다. model에서 커맨드 객체에 set한 정보를 view에서 표현식을 통해 확인할 수 있다!
위의 코드에 따라 view에서 login.jsp에 EL식을 통해 id와 password를 불러오면 쿠키를 사용하지 않아도 아래와 같이 값이 전달된다.
2) @ModelAttribute
① command객체의 이름을 설정할 수 있다.
EL식을 활용해 view에서 커맨드객체에 set된 정보를 가져오기 위해서는 model에 대한 상황을 알고 있어야한다. ${해당 VO의 클래스명(첫글자는 소문자로 함).멤버변수명}으로 불러야 하기 때문에, model의 클래스명을 view 작업자가 전부 알고있어어야하거나 controller에서 model과 view에서 다르게 표현하는 명령어를 바꾸어 출력될 수 있게 해주어야한다는 의미이다.
허나 해당 어노테이션을 통해 위와 같은 불편사항을 해소시켜 줄 수 있다. model에서 set한 정보를 무어라고 부를지 지정할 수 있게 된다.
package com.test.app.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.test.app.member.MemberVO;
import com.test.app.member.impl.MemberDAO;
@Controller
public class MemberController {
@RequestMapping(value="/login.do", method =RequestMethod.POST) //method방식이 post인 경우
public String login_post(MemberVO vo,MemberDAO memberDAO,HttpSession session) {
System.out.println("post로 로그인 요청");
vo=memberDAO.getMember(vo);
if(vo==null){
return "redirect:login.jsp";
}
session.setAttribute("member", vo);
return "redirect:main.do";
}
@RequestMapping(value="/login.do", method =RequestMethod.GET) //method방식이 get인 경우
public String login_get(@ModelAttribute("user")MemberVO vo) { // 해당 vo의 값을 user라는 이름으로 viewd에서 호출 가능
System.out.println("get으로 로그인 요청");
// 테스트 전달 데이터!
vo.setId("test"); //${user.id} -> 클래스의 맨 첫글자를 대문자-소문자로 변경해주면 호출 가능
vo.setPassword("1234");//${user.password}
return "login.jsp"; //redirect일 필요 없어짐
}
}
커맨드객체 앞에 @ModelAttribute("설정할 이름")을 달아주게 되면 이 설정한 이름으로 view에서 호출할 수 있게 된다. 자세한 내용은 주석을 통해 확인이 가능하다.
② view(jsp)에서 사용할 데이터를 설정할 수 있다.
만약 프로그램 업그레이드를 위해서 검색조건에 추가가 이루어진다면, 로직의 추가가 이루어지는것임에도 view 작업자가 화면을 수정해야하는 상황이 발생하게 된다. 이러한 점에서 수정되는 부분을 최소화 하여 유지보수를 용이하게 할 목적으로 사용된다.
package com.test.app.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.test.app.board.BoardVO;
import com.test.app.board.impl.BoardDAO;
@Controller // ★x100
public class BoardController {
@ModelAttribute("conMap")// @RequestMapping에 설정된 메서드보다 먼저 수행된다.
public Map<String, String> searchConditioinMap(){
// 어떤 검색조건을 view에 나열할지 전달할 예정이다.
// view에서 사용할 데이터를 설정할 수 있다.
Map<String, String> conMap=new HashMap<String, String>();
conMap.put("제목","title");
conMap.put("작성자","writer");
conMap.put("내용","content");
return conMap; //반환값은 자동으로 Model에 저장된다.->다음 view에서도 볼 수 있다.
}
@RequestMapping(value="/main.do")
public String getBoardList(BoardVO vo,BoardDAO boardDAO,Model model) {
// 검색 로직 추가할 예정
List<BoardVO> datas=boardDAO.getBoardList(vo);
model.addAttribute("datas", datas);
return "main.jsp";
}
}
필요한 부분의 로직만 남겨두었다.
@ModelAttribute를 통해 설정한 데이터를, 지정한 이름으로 다음 페이지에서 호출할 수 있게 된다.
view의 코드는 하단에 첨부하였다.
// 변경 전
<form action="main.do" method="post">
<table border="1">
<tr>
<td><select name="searchCondition">
<option value="title">제목</option>
<option value="writer">작성자</option>
<option value="content">내용</option>
</select> <input type="text" name="searchKeyword"> <input
type="submit" value="검색"></td>
</tr>
</table>
</form>
// 변경 후
<form action="main.do" method="post">
<table border="1">
<tr>
<td>
<select name="searchCondition">
<c:forEach var="v" items="${comMap}">
<option value="${v.value}">${v.key}</option>
</c:forEach>
</select> <input type="text" name="searchKeyword"> <input
type="submit" value="검색">
</td>
</tr>
</table>
</form>
3) Model클래스
위의 설명을 통해 커맨드 객체에 담긴 값을 view에서 확인해볼 수 있다는 것을 알게 되었다.
일반적으로 컨트롤러의 return은 String으로 맞추어두는 편인데, 위의 내용을 반영하여 현재 ModelAndView 커맨드객체를 통해 전달되고 있는 요청 처리 메서드의 output을 String으로 변경해보자!
변경 전과 후 코드는 아래에서 확인해 볼 수 있다.
@Controller // ★x100
public class BoardController {
// 변경 전 로직
@RequestMapping(value="/main.do")
public String getBoardList(BoardVO vo,BoardDAO boardDAO,ModelAndView mav) {
// 검색 로직 추가할 예정
List<BoardVO> datas=boardDAO.getBoardList(vo);
mav.addObject("datas", datas); // Model을 이용하여 전달할 정보를 저장!
mav.setViewName("main.jsp");
return mav;
}
// 변경한 로직!!
@RequestMapping(value="/main.do")
public String getBoardList(BoardVO vo,BoardDAO boardDAO, Model model) {
// 검색 로직 추가할 예정
List<BoardVO> datas=boardDAO.getBoardList(vo);
model.addAttribute("datas", datas);
return "main.jsp";
}
}
output을 String으로 변경해주고, 커맨드 객체 또한 ModelAndView가 아닌, Model로 변경해준다. 해당 객체에 addAttribute메서드를 사용해주면, view에서 해당 메서드를 통해 데이터를 전달받을 수 있게 된다.
4) @RequestParam
vO에 없는 값을 사용해야하는 경우에 사용되며, request.getParameter과 같은 역할을 수행한다.
아래의 어노테이션 코드를 내용 적용할 객체 앞에 배치하면 된다.
@RequestParam(value="view에서 가져온 name",defaultValue="기본값",required=필수유무)
검색 조건에 따른 결과를 보여주기 위한 로직으로 작성해보자면 아래와 같다.
@RequestMapping(value="/main.do")
public String getBoardList(@RequestParam(value="searchCondition",defaultValue="title",required=false)String sc,@RequestParam(value="searchKeyword",defaultValue="",required=false)String sk,BoardVO vo,BoardDAO boardDAO,Model model) {
System.out.println("검색조건: "+sc);
System.out.println("검색어: "+sk);
// 검색 로직 추가할 예정
List<BoardVO> datas=boardDAO.getBoardList(vo);
model.addAttribute("datas",datas); // Model을 이용하여 전달할 정보를 저장!
return "main.jsp";
}
vo로 설정되지 않는 경우 사용되는 방식이기는 하나, 설정정보가 길고 가독성이 좋지 않기 때문에 일반적으로는 해당 어노테이션보다는 별도로 VO를 생성하여 사용한다.
5) @SessionAttribute
* 언급되는 model은 이전 내용에서 ModelAndView를 대신하여 사용된 Model클래스이다. *
간혹 view에서 해당 데이터를 전달해주지 않는데, model에서 dao로 전달되지 않을 데이터를 필요로 할때 null업데이트 이슈가 발생하게 된다. 이는 update로직 수행시 가장 보편적으로 발생하게 된다.
로직상 게시글 수정을 누른다면, 작성자의 정보는 view에서 넘어오지 않는데, sql문에는 작성자 정보가 필요하게 되면 예외가 발생하는 상황이다.
즉, 예외없이 프로그램을 정상수행 시키기 위해서는 기존에 writer정보가 존재한다면, 기존의 정보를 유지해줄 수 있도록 요청해야한다.
@Controller // ★x100
@SessionAttributes("data") //view에서 data로 사용중! data라는 이름의 정보가 model에 들어온다면, session에 기억해둬라!
public class BoardController {
@RequestMapping(value="/board.do")
public String getBoard(BoardVO vo,BoardDAO boardDAO,Model model) {
vo=boardDAO.getBoard(vo);
model.addAttribute("data", vo); // 여기서 data가 set되어서 session에 저장되었다!
return "board.jsp";
}
//c가 동작시 data라고 등록된 vo(커맨드객체)가 있는지 살펴본다.
@RequestMapping(value="/updateBoard.do")
public String updateBoard(@ModelAttribute("data")BoardVO vo,BoardDAO boardDAO) { //기존에 존재하던 data정보를 먼저set, 새로 들어온 정보를 나중에 set
boardDAO.updateBoard(vo); // 아까 data가 ~던데? 일단 set / 만약 새로 들어왔다면 그걸로 덮어쓰기
return "redirect:main.do";
}
}
해당 코드의 내부 순서를 파악해보면 이해가 쉽다.
1) @SessionAttributes("data") : data라는 이름의 정보가 Model에 add되게 되면 session에 저장되도록 설정
2) getBoard()에서 model에 "data"가 add되었다!! -> session에 저장
3) updateBoard()에서 @ModelAttribute : 나 data누군지 알아! 이런 내용이던데? -> 1차로 set
4) if, 사용자에게 data의 내용 중 변경 사항이 들어오게 되면 새로 들어온 정보로 덮어쓰기 ! -> 2차로 set
즉, 새로 요청된 내용이 없다면 기존 내용을 유지하고 새로 들어온 정보가 있다면 해당 정보로 덮어쓰기 된다.
'Spring' 카테고리의 다른 글
[레이어] 비즈니스 컴포넌트 (0) | 2022.04.11 |
---|---|
[AOP] 트랜잭션 관리자 (2) | 2022.04.08 |
[AOP] JDBC Template_DAO2 (0) | 2022.04.06 |
[AOP] xml을 @로 바꾸기 : 횡단관심_aop(2) (0) | 2022.04.05 |
[AOP] AOP개념의 이해 : 횡단관심_aop(1) (0) | 2022.04.04 |