스프링 MVC_요청매핑, 커맨드 객체, 폼 태그, 모델

예지성준·2024년 7월 11일

스프링프레임워크

목록 보기
8/14
post-thumbnail

스프링 MVC : 요청 매핑, 커맨드 객체, 리다이렉트, 폼 태그, 모델

1. 요청 매핑 애노테이션을 이용한 경로 매핑

요청 메서드(method)

  • GET, DELETE
  • POST, PATCH, PUT

@RequestMapping

  • 모든 요청 메서드에 매핑, method 설정에 GET, POST, DELETE 등등 설정 가능
  • 상세하게 메서드 설정 가능
    • RequestMethod: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE 들의 enum들이 설정되어있다.
 @RequestMapping(path = "/member/join", method = {RequestMethod.GET,RequestMethod.POST}) //두개의 요청을 가져올 수 있는 상태
    public String join(Model model, HttpServletRequest request){
        model.addAttribute("member", "안녕하세요.");
        //jsp에서 el식으로 접근 가능

        System.out.println("method: "+request.getMethod());
        return "member/join";
    }

가입하기 했을때 Post방식으로 변경 되서 유입

@GetMapping
  • params 사용 예시

    @GetMapping("/join" )
    public String join1(Model model, HttpServletRequest request){
        System.out.println("mode없음");
        return "member/join";
    }

mode 없을때 mapping을 따로 넣어줘야함 400오류 나오지 않는다.

🔽 mode값 여러개 적용시

@PostMapping
@PatchMapping : 부분 수정
@PutMapping : 치환
@DeleteMapping

<공통>

  • params : 요청 데이터를 한정해서 매핑 시킴
  • header: 요청헤더 데이터 한정
  • consumes: 요청헤더 contentType에 한정 체크
  • produces: 응답 헤더쪽 Content-Type 설정

👩‍💻참고) sysout.println 대신 로거 사용
private final Logger log = LoggerFactory.getLogger(MemberController.class);
log.fatal()
log.debug()
log.info()
log.warn()
log.error()
log.trace()

..
public class MemberController {
    private final Logger log = LoggerFactory.getLogger(MemberController.class);
    @GetMapping("/join" )
    public String join1(Model model, HttpServletRequest request){
        log.info("mode없음");
        return "member/join";
    }
    @GetMapping(path="/join",params ={"mode=join"} ) //mode값에 반드시 join이 있어야지 여기로 유입이 된다.
    public String join(Model model, HttpServletRequest request){
        log.info("mode=join");
        return "member/join";
    }
    ..

🔽🔽

  • lombok 활용시
    @slf4j
    @log4j
    @log4j2
    .. 애노테이션으로 로거 연도 코드 자동 생성
    변수명은 log

redirect

  • return "redirect:/member/login";는 클라이언트를 /member/login URL로 리다이렉트 시켜준다.
    • 현재 URL 경로와 상관없이 contextPath+/member/login으로 리다이렉트
  • redirect: 접두사는 Spring MVC에게 이 메서드가 URL 리다이렉션을 수행할 것임을 알려준다.
  • 클라이언트(브라우저)는 서버로부터 HTTP 302 상태 코드와 함께 새로운 URL (/member/login)로 리다이렉트하라는 응답을 받는다.
  • 브라우저는 자동으로 새로운 URL로 요청을 보냄

redirect -> 뷰이동 x 주소이동 시켜주는데 HandlerAdapter가 읽고 주소 앞에 contextPath를 붙여준다.

  • 리다이렉션은 주로 폼 제출 후 사용자에게 다른 페이지를 보여주거나, 특정 작업 후 상태를 변경하기 위해 사용된다.

302: 임시이동 - 요청한 페이지가 일시적으로 옮겨졌다. 즉 언제든지 이전 URL로 다시 돌아올 수 있다.

상대경로 지정시
return "redirect:member/login";
-> 현재 URL 경로를 기준으로 이동한다.

foward: 버퍼 치환

  • 반환값으로 forward:주소 형태도 가능

  • 해당 주소의 출력 데이터로 버퍼를 치환

  • RequestDispatcher

    • forward

주소는 바뀌지 않음!!!


통합 테스트

MockMvc - 컨트롤러 테스트
-> 서버를 껏다키지 않아도 알아서 코드가 반영된다.

@SpringJUnitConfig
@ContextConfiguration(classes = MvcConfig.class)
public class MemberControllerTest {
    
    private WebApplicationContext ctx;
    
    private MockMvc mockMvc;
    
    @BeforeEach
    void init(){
//        mockMvc = MockMvcBuilders.standaloneSetup() // 특정 컨트롤러 한정 테스트
        mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build(); //전체
    }
}
...

webAppContextSetup(..)

  • 의존성은 스프링 컨테이너가 필요함
    • web.xml에서 지정한 AnnotationConfigWebApplicationContext가 아닌 WebApplicationContext로 쓰는 이유.. 다형성..

서버 재로딩 없이 콘솔에서 확인 가능

  • header 사용 예시
    테스트1
    @PostMapping(value = "/join", headers = "appKey=1234")
    //Post방식 처리시 여기로 유입됨 요청 헤더 쪽에 appKey=1234가 있어야 이 메서드가 실행된다.
    public String joinPs(RequestJoin form){
        log.info("JoinPs실행...");
        return "redirect:/member/login";   
    }

🔽

테스트 환경에서 요청헤더에 values넣어줌

@SpringJUnitWebConfig
@ContextConfiguration(classes = MvcConfig.class)
public class MemberControllerTest {

    @Autowired
    private WebApplicationContext ctx;

    private MockMvc mockMvc;

    @BeforeEach
    void init() {
        mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
    }

    @Test
    void test1() throws Exception {
        mockMvc.perform(post("/member/join")
                        .header("appKey","1234") //요청헤더
                )
                .andDo(print());
    }

}

  • consumes 사용 예시
    테스트2
@PostMapping(value = "/join", headers = "appKey=1234", consumes = "application/json")
    public String joinPs(RequestJoin form){
        log.info("JoinPs실행...");
        return "redirect:/member/login"; // 절대경로 기준 이동
    }

오타 방지를 위해서 enum 상수 형태로 코드 수정!

...컨트롤러
@PostMapping(value = "/join", headers = "appKey=1234", consumes = MediaType.APPLICATION_JSON_VALUE)
    public String joinPs(RequestJoin form){
        log.info("JoinPs실행...");
        return "redirect:/member/login"; // 절대경로 기준 이동
    }

...
@Test
    void test1() throws Exception {
        mockMvc.perform(post("/member/join")
                        .header("appKey","1234") //요청헤더
                        .contentType(MediaType.APPLICATION_JSON_VALUE)
                )
                .andDo(print());
    }
  • produces 사용 예시
    테스트3
@PostMapping(value = "/join", headers = "appKey=1234", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public String joinPs(RequestJoin form){
        log.info("JoinPs실행...");
        return "redirect:/member/login";
    }
    ...
    

2. 요청 파라미터 접근

1) @RequestParam

2) 커맨드 객체를 이용해서 요청 파라미터 사용하기

커맨드 객체 클래스명 -> EL 속성으로 자동 추가
ex) RequestJoin -> requestJoin

 @PostMapping("/join")
    public String joinPs(RequestJoin form){ //같은 이름의 setter가 있으면 알아서 값을 대입해준다.
        log.info(form.toString()); //폼에 작성한 요청 데이터 넘어오는지 확인
        return "member/join";
    }

내가 요청했던 form 데이터들 el속성으로 추가 가능하다.

<input type="text" name="email" value="${requestJoin.email}">
기존 HTMl코드처럼 하면 서버 측에서 폼 데이터와 객체의 필드를 매핑하는 코드가 추가로 필요하고, 검증 로직을 따로 작성해야 하는 단점이 있다.

3. 뷰 JSP 코드에서 커맨드 객체 사용하기

스프링 커스텀 태그

  • JSP 페이지에서 Spring의 커스텀 태그를 사용하여 HTML 폼 요소를 더 쉽게 관리하고 바인딩 할 수 있다.
  • 자동 바인딩, 검증 지원, 코드 간소화, 유지보수 용이

스프링에서 지원하는 form 형태로 바꾸기

커스텀 태그 추가
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>


RequestJoin form: 커맨드 객체
커맨드 객체가 검증 실패시 다시 양식을 보여주게 되는데..
커맨드 객체는 Post방식일때만(양식을 제출할때만) 넘어온다.
하지만 Getmapping일때는 커맨드객체로 주입된게 없다. el식에 값 비어있는 상태가 되버림

비어있으면 오류 발생함

스프링 커스텀태그를 사용할 시 커맨드객체와 동일한 이름의 객체를 유지시켜줘야한다.

Model주입!

@Slf4j
@Controller
@RequestMapping("/member")
public class MemberController {

    @GetMapping("/join")
    public String join(Model model) {
        //값이 없더라도 비어있는 값이라도 줘야함
        RequestJoin form  = new RequestJoin();
        model.addAttribute("requestJoin",form);

        return "member/join";
    }
    ...
        @PostMapping("/join")
    public String joinPs(RequestJoin form){ //같은 이름의 setter가 있으면 알아서 값을 대입해준다.
        log.info(form.toString()); //폼에 작성한 요청 데이터 넘어오는지 확인
        return "member/join";
    }
    ...
    

4. @ModelAttribute 애노테이션으로

1) 커맨드 객체가 없으면 빈 커맨드 객체 생성

🔽🔽🔽

@GetMapping("/join")
    public String join(@ModelAttribute RequestJoin form) {
 // 값이 없을때 RequestJoin 이름을 가지고 앞자를 소문자로 바꿔서 자동으로 만들어줌

        return "member/join";
    }

Get방식 요청때도 자동으로 null값 주입된 것을 확인 할 수 있다!

2) 커맨드 객체 속성 이름 변경

기본 이름은 클래스명에서 앞자를 소문자로 바꿔서 커맨드 객체 이름으로 사용했다.

value값에 입력하면 이름 바꿀 수 있다.

속성명 새롭게 만듦!༼ つ ◕_◕ ༽つ

커맨드 객체 그대로 이름을 사용하는 경우가 더 많다(. ❛ ᴗ ❛.)

3) 공통 데이터(속성)으로 사용할 데이터 지정에 사용

  • Controller, RestController: 컨트롤러에서의 공통 데이터로 설정

  • ControllerAdvice, RestControllerAdvice: 지정된 패키지 범위에서의 공통 데이터

5. 커맨드 객체와 스프링 폼 연동

1) <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
2) <form:form>
3) <form:input>
4) <form:password>

6. 컨트롤러 구현 없는 경로 매핑

  • 스프링쪽에서 제공하는 기능을 사용하면 단순히 페이지만 연동하는 경우 컨트롤러 생성 없이 뷰만 연동해서 주소를 연결 할 수 있다.

  • 컨트롤러 구성을 할 필요 없는 간단한 페이지 구성
    WebMvcConfigurer 인터페이스

    • addViewControllers 설정

컨트롤러 없이 페이지 연동 시켜보겠듬!!!!

index.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<h1>메인 페이지</h1>

...
MvcConfig
...
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/")
                .setViewName("main/index");
    }

registry로 하단에 코드 추가해주면 컨트롤러없이 연동할 페이지 추가 가능함

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/")
                .setViewName("main/index");
        
        registry.addViewController("/mypage")
                .setViewName("mypage/index");
    }
  • Spring6에 추가된..
    Record클래스
    • 값은 상수로, 읽기전용, 값이 final로
    • 값 자체를 표현하는 객체
    • getter()만 존재 setter() X
    • @builder 가능
package org.choongang.member.controllers;

public record RequestLogin2(
        //값만 담을 수 있는 데이터 클래스
        String email,
        String password
) {}

7. 커맨드 객체: 중첩 · 콜렉션 프로퍼티

콜렉션 프로퍼티

  • 요청 데이터가 여러개일때 ex) 체크박스

  • form 태그에 체크박스 기능

중첩: 커맨드 객체 안에 커맨드 객체

커맨드도 주소 같은 경우 동일 내용을 입력하는 항목이 있을것이다 -> 재활용 하고싶을때

분리!

addr.항목명

join.jsp

중첩된 커맨드 객체의 매핑 완성 ˋ( ° ▽、° )

8. Model을 통해 컨트롤러에서 뷰에 데이터 전달하기

9. ModelAndView를 통한 뷰 선택과 모델 전달

10. GET 방식과 POST 방식에 동일 이름 커맨드 객체 사용하기

주요 폼 태그 설명

강의자료
1. <form> 태그를 위한 커스텀 태그: <form:form>

  • 〈form:form〉태그의 method 속성과 action 속성을 지정하지 않으면 method 속성값은 "post"로 설정되고 action 속성값은 현재 요정 URL로 설정된다.
    • action : 폼 데이터를 전송할 URL을 입력 (HTML <form> 태그 속성)
    • enctype : 전송될 데이터의 인코딩 타입. HTML <form> 태그 속성과 동일
    • method : 전송 방식. HTML <form> 태그 속성과 동일
  1. <input> 관련 커스텀 태그 : <form:input>, <form:password>, <form:hidden>

  1. <select> 관련 커스텀 태그 : <form:select>, <form:options>, <form:option>
  • <select> 태그는 선택 옵션을 제공할 때 주로 사용한다.

  1. 체크박스 관련 커스텀 태그 : <form:checkboxes>, <form:checkbox>

  2. 라디오버튼 관련 커스텀 태그: <form:radiobuttons>, <form:radiobutton>

  • 여러 가지 옵션 중에서 한 가지를 선택해야 하는 경우 radio 타입의 <input> 태그를 사용한다.
  1. <textarea〉 태그를 위한 커스텀 태그 : <form:textarea>
  • 게시글 내용과 같이 여러 줄을 입력받아야 하는 경우 <textarea> 태그를 사용한다.

CSS 및 HTML 태그와 관련된 공통 속성

  1. cssClass: HTML의 class 속성값
    <dl>
        <dt>이메일</dt>
        <dd>
            <form:input path="email" cssClass="input-txt" cssStyle="border-color: red"/>
        </dd>
    </dl>
  1. cssErrorClass : 폼 검증 에러가 발생했을 때 사용할 HTML의 class 속성값
  1. cssStyle: HTML의 style 속성값

HTML 태그가 사용하는 다음 속성도 사용 가능하다.

  1. id, title, dir

  2. disabled, tabindex

  3. onfocus, onblur, onchange onclick, ondblclick

  4. onkeydown, onkeypress, onkeyup

  5. onmousedown, onmousemove, onmouseup

  6. onmouseout, onmouseover

각 커스텀 태그는 htmlEscape 속성을 사용해서 커맨드 객체의 값에 포함된 HTML 특수 문자를 엔티티 레퍼런스로 변환할지를 결정할 수 있다.

profile
꽁꽁 얼어붙은 한강 위로 😺

0개의 댓글