

만약 resources 폴더 이름을 assets으로 바꿔본다면

servlet-context의 location도 자동으로 assets으로 바뀜. 다만 매핑 주소는 그대로 -> 주소를 요청할 땐 resources로 요청해야 함. 그러면 폴더는 assets 폴더를 찾아갈거임
바뀐 폴더 이름인 assets이 아닌 매핑 주소인 resources를 적어줬음

근데 아직 컨트롤러가 없어서 서버 돌리면 오류남. 컨트롤러도 만들기

저 주소를 열어줬을 때 main.jsp 열어줄 수 있도록 컨트롤러로 지정해야 함
@Controller
public class MvcController {
@RequestMapping(value="/", method =RequestMethod.GET)
public String main() {
return "/WEB-INF/main.jsp"; // 뷰리졸버있으니 main으로 써도된다. 지금 프젝에선 쌤이 지우자 해서 지웠음. 그래서 전부 그대로 씀
}
}
contextPath 정보를 요청하면 main.jsp로 이동
이제 실행하면

잘 뜬다.
작성페이지로 화면 넘겨서 작성창으로 이동
요청을 jsp에서 만들고 실제로 이동하기 위한 controller 작업할 예정
<div>
<a href="${contextPath}/write.do">작성페이지로 가기</a>
</div>
article 폴더의 write.jsp와 연결되도록 해보자
@Controller
public class MvcController {
@RequestMapping(value="/", method =RequestMethod.GET)
public String main() {
return "/WEB-INF/main.jsp";
}

articleVo 내용은 이렇다. 이걸 활용한 실습. 작성화면 만들기
<div>
<h3>기사 작성하기</h3>
<form action="${contextPath}/register.do" method="post">
<div>
<label for="articleNo">기사번호</label>
<input type="text" id="articleNo" name="articleNo">
</div>
<div>
<label for="title">기사제목</label>
<input type="text" id="title" name="title">
</div>
<div>
<label for="content">기사내용</label>
<input type="text" id="content" name="content">
</div>
<div>
<button type="submit">기사작성완료</button>
</div>
</form>
</div>
name은 key, value는 value
1. name: 태그명, form submit시 서버에서 name 명으로 값을 가져올 수 있다. (전달받는 입장에서 값을 꺼낼 수 있는 키, value를 찾기 위한 key)


write.jsp에서 건너온 3개의 데이터는 여기서 받아야한다. 3가지 방법이 있었다.

이제 끝. 그런데 톰캣 실행하면 인코딩 오류 뜬다.


이렇게 적었는데 콘솔창엔 한글을 못 읽어내는 거.. 영어는 된다. 일단 영어로 하는 걸로 하고 넘어감.

실행결과 콘솔창에 잘 출력된다


정상실행됨


이게 코드

이게 출력결과(잘 출력됨)
*모델은 포워딩할 데이터, 주로 select할 때 쓴다.
현주한테 물어봤더니
현주: 포워딩은 select(조회)-GET, 리다이렉트는 insert(삽입) update(수정) delete(삭제) 등 데이터 내용 바뀔때-POST
목록을 전달할 때는 모델에 list 담고, 개별 항목을 전달할 때는 dto 하나를 담는다
@RequestMapping(value="/register.do", method=RequestMethod.POST)
public String register2(@RequestParam(value="articleNo") int articleNo
, @RequestParam(value="title") String title
, @RequestParam(value="content") String content
, Model model) {
ArticleVo vo = new ArticleVo(articleNo, title, content);
model.addAttribute("vo",vo);
return "/WEB-INF/article/result.jsp";
}
이번에는 객체 형태로 전달했다.
vo.뭐뭐뭐로 불러준다
<div>
<div>${vo.articleNo}</div>
<div>${vo.title}</div>
<div>${vo.content}</div>
</div>
실행결과 잘나옴
커맨드 객체를 이용하는 방식에서는 모델 선언 및 모델에 저장하는 코드가 불필요, 모델에
@RequestMapping(value="/register.do", method=RequestMethod.POST)
public String register3(ArticleVo vo) {
return "/WEB-INF/article/result.jsp";
}
모델에 저장되는 이름은 ArticleVo vo 중 ArticleVo

//MvcController
@RequestMapping(value="/register.do", method=RequestMethod.POST)
public String register4(@ModelAttribute(value="atcvo") ArticleVo vo) {
return "/WEB-INF/article/result.jsp";
}
<!--result.jsp-->
<div>
<div>${atcvo.articleNo}</div>
<div>${atcvo.title}</div>
<div>${atcvo.content}</div>
</div>
<div>
<div>${articleVo.articleNo}</div>
<div>${articleVo.title}</div>
<div>${articleVo.content}</div>
</div>
실행결과 잘나옴
목록보기로 리다이렉트(/list.do)상세보기로 리다이렉트(/detail.do) 수정목록 확인해야하니까

MyController05 만든다 (작성은 안하고 일단 넘어감)
이 뒤로 갑자기 필터얘기시작함. 결론 걍 xml 복붙하면 됨. 리다이렉트 보려면 4교시로 바로 넘어가기
index.jsp에서 MyController05로 요청
<%-- MyController05으로 요청 --%>
<div>
<form action="${contextPath}/faq/add.do" method="post">
<div>
<label for="title">제목</label>
<input type="text" id="title" name="title">
</div>
<div>
<button type="submit">작성완료</button>
</div>
</form>
</div>
만약 이대로 값을 전달하면 한글이 깨질거임
jsp에서는 컨트롤러에 가서 인코딩했었음
request.setCharacterEncoding("UTF-8");
스프링에서도 파라미터로 HttpServletRequest request 받아서 저렇게 처리해주면 불가능한 건 아니지만 이럴 경우 메소드마다 각자 인코딩을 해줘야해서 완전 불편해짐 예를들면 이렇게

적어줘도 add 메소드에만 인코딩이 적용됐을 뿐인거임.
그렇기때문에 공통작업으로 인코딩을 해결해줘야한다.

다음시간에는 필터를 만드는 두가지 방법
3교시에 대충 설명했음. 그냥한다. 해보는데 의의를 두라
(어차피 안외워도 되니까 대충 설명해야지)

필터이름: AccessFilter

Filter mapping 즉 필터가 언제 동작할지에 대해서
/필터이름 -> / (or /* ,/**)로 변경 : contextPath 포함되는 모든 경로에서 매핑돼서 동작하도록

doFilter : 실제로 필터를 처리하는 곳
여기서 인코딩 작업을 해주면됨 (위는 인코딩오류날 예정)
확인해볼 겸 MyController05작성

return은 임시로 쓴거라서 아직 비어있음. jsp는 오류날 예정

필터동작에는 문제없는데(필터동작합니다 정상출력됨) 인코딩은 안됐음
AccessFilter는 지우자

(이 ppt는 3장 mvc 14페이지에 있다)
<!-- Encoding Filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
이제 이거 복붙해서 쓰면 됨. 인코딩 문제 없음


이렇게 필터네임 맞춰주고 동작 주소로 모든 경로해주면 모든 곳에서 동작.
걍 복붙해서 쓰면댐

다음 시간에 자세히 설명

과연 이렇게 모델로 데이터를 전달할 수 있을까.
-> 못함. 모델은 jsp로 전달하는건데 redirect는 jsp로 가지를 않는다
=> 그렇기 때문에 리다이렉트에서는 모델 전달이 없다.
그럼 리다이렉트에서는 어떻게 데이터를 전달해야하는지.
-> redirect문에 추가
return "redirect:/faq/list.do?addResult=" + addResult;
addResult를 갖고가고 싶다고 했으니까 그걸 redirect문 자체에 추가하면 된다. addresult는 list.do로 이동한다.
@RequestMapping(value="/faq/list.do", method=RequestMethod.GET)
public String list(@RequestParam(value="addResult") String addResult, Model model) {
model.addAttribute("addResult", addResult);
// ViewResolver prefix : /WEB-INF/views/
// ViewResolver suffix : .jsp
return "faq/list"; // /WEB-INF/views/faq/list.jsp
}
여기서 모델 작업해준다. addResult @RequestParam으로 불러와서 String addResult에 저장하고 이걸 모델 이용해서 드디어 list.jsp로 보내는거
이제 list.jsp로 데이터 잘 넘어간다. 제목 써주는지 안 써주는지에 따라서 0, 1 잘 표시된다. 원래는 ${addResult}해도 아무것도 표시안됐었음

만약에 주소창에서 ?addRequestResult=1 값을 지워버린다면
그냥 addResult 부분만 사라지는게 아니라 400 오류 난다.

필수 파라미터인 addResult가 보이지 않는다는 거임
이럴때는 @RequestParam의 required를 false로 해주면 해결
public String list(@RequestParam(value="addResult", required=false)
(addResult 변수 String으로 해준 이유 : int로 해주면 자동으로 paresInt처리가 돼서 int로 저장되는 건데 만약 필수 설정을 없애주고 int로 저장한다면 addResult 들어온 값 자체를 안 받게 되는거라서 parseInt 할 값이 없는데 머하라는거냐 이런 또다른 이유가 발생)
응용


list.jsp에서 script 활용해서 알람으로 뜨게 할 수도 있다
5교시 예제 그대로 또 한번더.
아까는 faq 목록보기 list로 이동하는걸 보내고 받아서 다시 보내는 방식으로 두번에 나눠서 했는데 사실 리다이렉트도 곧바로 전달할 수 있다.
=> 이 때 사용하는 attribute를 flash attribute라고 부름(스프링에서 새로 생긴 것)
faq 목록보기로 redirect 할 때 addResult를 "flash attribute"로 곧바로 전달하기 --> redirectAttributes 사용
리다이렉트 시 값 전달용으로 만들어짐.
주의할 점. 
add attribute를 할 때 그냥 addAttribute도 있고 addFlashAttribute도 있는데 addAttribute 쓰지 않도록 주의 (addAttribute는 모델이랑 똑같음. 5교시꺼보면 알듯이 모델은 리다렉에서 전달 안됨)
@RequestMapping(value="/faq/add.do", method=RequestMethod.POST)
public String add2(HttpServletRequest request
, RedirectAttributes redirectAttributes) { // redirect 상황에서 값을 전달할 때 사용한다.
// 요청 파라미터
String title = request.getParameter("title");
// title이 빈 문자열이면 add 실패
int addResult = title.isEmpty() ? 0 : 1;
// faq 목록보기로 redirect 할 때 addResult를 "flash attribute"로 곧바로 전달하기
redirectAttributes.addFlashAttribute("addResult", addResult);
// faq 목록보기로 redirect
return "redirect:/faq/list.do";
}
이제 아까랑은 달리 이동만 다시 시켜주면 됨
@RequestMapping(value="/faq/list.do", method=RequestMethod.GET)
public String list2() {
return "faq/list";
}
훨씬 간단해짐

이 밑줄친 과정들이 사라짐. 리다렉 주소에 붙여서 전달하고 그걸 다시 받아서 모델로 다시 전달하는 과정
리다렉 처리 방법 두가지 공부 끝
하나는 주소에 붙여 보내기
하나는 redirectAttributes
뜬금팁: MyController05를 보면 모든 매핑 주소가 다 faq로 시작하는데 이건 프로젝트를 할 때 한 컨트롤러 당 하나의 기능을 구현하기 때문임. MyController05는 faq에 대한 기능을 구현하는 것 (나중에 프젝할 때 이렇게 해야한다)
(30분 정도 다 생략)
Spring Container에 저장된 객체를 가져오는 방식
1) @Inject
(1) javax.inject.Inject
(2) 타입(class)이 일치하는 객체를 찾아서 가져온다.
(3) 동일한 타입(class)의 객체가 2개 이상 있다면 이름(id)이 일치하는 객체를 가져온다.
(4) 타입(class)과 이름(id)이 일치하는 Bean이 없는 경우 오류가 발생한다.
(5) 가져올 객체의 이름(id)을 지정하기 위해서 @Named(javax.inject.Named)를 사용할 수 있다.
(6) 필요한 디펜던시
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
2) @Resource
(1) javax.annotation.Resource
(2) 이름(id)이 일치하는 객체를 찾아서 가져온다.
(3) 동일한 이름(id)을 가진 객체가 없으면 오류가 발생한다.
(4) 필요한 디펜던시(Javax Annotation API)
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
3) @Autowired
(1) org.springframework.beans.factory.annotation.Autowired
(2) @Inject 기반의 Spring Annotation이다. (타입 기반)
타입(class)이 일치하는 객체를 찾아서 가져온다.이름(id)이 일치하는 객체를 가져온다.(3) 가져올 객체의 이름(id)을 지정하기 위해서 @Qualifier(org.springframework.beans.factory.annotation.Qualifier)를 사용할 수 있다.
1) 객체를 Spring Container에 넣는다. (아래 3가지 방법 중 하나 이용)
(1) <bean> 태그
(2) @Configuration + @Bean
(3) @Component (제일 간단, 아직 안배움)
2) @Autowired를 이용해서 Spring Container에서 원하는 타입의 객체를 가져온다. (아래 3가지 방법 중 하나 이용)
(1) 필드에 주입하기
(2) 생성자에 주입하기
(3) Setter 형식의 메소드에 주입하기
<bean class="com.gdu.app05.service.BoardServiceImpl" id="boardService"/>

new를 대신한게 spring이니까 일단 new 부분 싹 지워줌
// 주입된 boardService 객체의 변경 방지를 위해 final 처리한다.
@Autowired
private final BoardService boardService;
@Autowired가 하는 일 = 컨테이너 역할, 타입이 일치하면 bean을 알아서 가져옴 (getBean같은거 할 필요없음)
=> 자동으로 넣어주기 때문에 주입이라고 함
가져올 bean 태그는 1번과 동일
// boardService에 final 처리를 하면 생성자 주입만 가능하다.(필드 주입과 Setter 주입은 불가능하다.)
// 생성자 주입의 @Autowired는 생략할 수 있으므로 @RequiredArgsConstructor와 같은 Annotation으로 대체할 수 있다.
@Autowired
public BoardController(BoardService boardService) {
super();
this.boardService = boardService;
}
생성자의 매개변수로 주입이 된다.
@Autowired
public void setBoardService(BoardService boardService) {
this.boardService = boardService;
}
실습 쎔 정리본
@Autowired 사용 예시
┌-- Spring Container --┐
│ BoardDto boardDto1 │
│ BoardDto boardDto2 │
└----------------------┘
1) 필드에 주입하기
@Autowired
private BoardDto boardDto1; // Spring Container에 BoardDto 타입의 객체가 2개가 있으므로 이름이 일치하는 boardDto1 객체를 가져온다.
@Autowired
private BoardDto boardDto2; // Spring Container에 BoardDto 타입의 객체가 2개가 있으므로 이름이 일치하는 boardDto2 객체를 가져온다.
@Autowired
@Qualifier(value="boardDto1") // 가져올 객체 이름을 boardDto1으로 지정한다.
private BoardDto b1;
@Autowired
@Qualifier(value="boardDto2") // 가져올 객체 이름을 boardDto1으로 지정한다.
private BoardDto b2;
2) 생성자에 주입하기
private BoardDto boardDto1;
private BoardDto boardDto2;
@Autowired // 스프링 4 이후 생략 가능 (생성자의 autowired)
public BoardController(BoardDto boardDto1, BoardDto boardDto2) { // Spring Container에 저장된 객체를 매개변수로 가져온다.
this.boardDto1 = boardDto1;
this.boardDto2 = boardDto2;
}
3) Setter 형식의 메소드에 주입하기
private BoardDto boardDto1;
private BoardDto boardDto2;
@Autowired
public void setBean(BoardDto boardDto1, BoardDto boardDto2) { // Spring Container에 저장된 객체를 매개변수로 가져온다.
this.boardDto1 = boardDto1;
this.boardDto2 = boardDto2;
}
autowire는 매개변수로 자동주입된다. 이름이 꼭 set어쩌구 아니어도 매개변수에 조건 맞는 애 있으면 자동주입