SPRING

SPRING Controller 구현

Adev 2022. 11. 11. 00:01

: 클라이언트의 요청을 처리한다.

직간접적으로 뷰 이름과 모델 정보를 설정하는 ModelAndView 객체를 생성한다.

파라미터가 자동으로 수집(binding)되어 request.getParameter()를 사용하지 않아도 된다.

상속/인터페이스/전송 방식에 대한 처리를 어노테이션만으로 설정할 수 있다.

 

DispatcherServlet이 사용하는 설정 파일인 servlet-context.xml에 Controller Class를 Bean으로 등록해야한다.

<context.component-scan>태그를 이용해 해당 패키지를 스캔하도록 설정하면 자동으로 어노테이션을 파악해 객체를 생성해준다.

<context:component-scan base-package="org.zerock.controller" />

</beans:beans>

 

 

1. 어노테이션

  • @Controller

: 해당 Class가 spring mvc의 컨트롤러를 구현한 Class라는 것을 지정한다.

 

  • @RequestMapping

: 클라이언트의 요청을 처리할 메서드 설정한다. 해당 클래스의 모든 메서드에서 처리할 기본적인 URI 경로를 값으로 가진다. (클래스 선언과 메소드 선언에 사용)

method 속성으로 전송방식 설정이 가능하며, 축양형인 @GetMapping와 @PostMapping을 사용해도 된다. (spring 4.3 이후)

 

  • @InitBinder

: Controller에서 파라미터를 바인딩(파라미터 수집) 시 자동 호출된다.

보통 파라미터 타입에 따라 자동으로 타입 변환이 이뤄지지만, 일부 직접 변환 처리를 해야 하는 경우에 사용한다.

 

cf) binding = 파라미터 수집

 

  • @DateTimeFormat

:  java.util.Date타입으로 변환 시 사용한다.

 

  • @Data (Lombok)

: getter/setter, equals(), toString() 등의 메서드를 자동 생성한다.

 

 

 

2. Controller 메서드의 HTTP 전송 방식 한정

: 하나의 Controller에서 하나의 요청 URL에 대해 HTTP GET요청과  POST요청을 처리할 경우, @RequestMapping Annotaition의 method 속성을 사용한다.

GET요청은 form()메소드, POST요청은 submit()메서드가 처리한다.

@RequestMapping(value="/article/newArticle.do", method = RequestMethod.GET)
public String form() {
return "article/newArticleForm";
}
@RequestMapping(value="/article/newArticle.do", method = RequestMethod.POST)
public String submit() {
return "article/newArticleSubmitted";
}

 

축양형인 @GetMapping와 @PostMapping을 사용해도 된다. (스프링 4.3이후)

@GetMapping("/basic")
public void basic() {

 

 

3. HTML 폼과 Command 객체(JavaBean)

1) HTML 폼에 입력한 데이터를 JavaBean 객체를 이용해 전달 받을 수 있다.

 

@RequestMapping이 적용된 메서드의 파라미터로 JavaBean 타입을 추가한다.

(메서드 파라미터로 Class타입, HttpServletRequest, HttpServletResponse, HttpSession, @RequestParam, Map, Model, ModelMap등 다양한 타입을 가짐)

@RequestMapping(method = RequestMethod.POST)
public String submit(NewArticleCommand command) {

 

2) View에서 Command 객체의 Class이름을 이용해 Command 객체에 접근할 수 있다.

 

(Command 객체는 자동으로 모델에 추가된다. 첫글자는 소문자)

  	<body>
			...
		제목 : ${newArticleCommand.title}

 

@ModelAttribute를 이용해 View에서 사용할 모델의 이름을 변경할 수 있다.

@RequestMapping(method = RequestMethod.POST)
public String submit(@ModelAttribute("com") NewArticleCommand command) {
	  	<body>
			...
		제목 : ${com.title}

 

3) Command 객체로 List를 받을 수 있다.

 

List 타입의 프로퍼티에 값을 전달하려면 폼에서 입력 폼의 name을 "프로퍼티명[인덱스].프로퍼티"로 설정한다.

<form method="post">
			상품1 : ID - <input type="text" name="orderItems[0].itemId"/>

 

+ 파라미터를 '[인덱스]' 형식으로 전달할 때, 전송URL이 '[', ']'특수문자를 허용하지 않는다면 '%5B', '%5D'로 변경한다.  (Tomcat 버전에 따라 다름)

 

 

4. 파리미터 수집과 변환

1) 파라미터타입 DTO 객체

 

Controller의 메서드가 DTO를 파라미터로 사용하면 자동으로 setter 메서드가 동작해 파라미터를 수집한다.

public class SampleDTO {

	private String name;
	private int age;
}
	@GetMapping("/ex01")
	public String ex01(SampleDTO dto) {
		
		log.info("" + dto);
		
		return "ex01";
	}

 

2) @RequestParam을 이용해 파라미터를 Mapping할 수 있다.

 

파라미터로 사용된 변수명과 전달되는 파라미터 이름이 다른 경우에 유용하다. 

기본적으로 필수 파라미터로 required 속성 값이 true이다. 값이 존재하지 않을 경우 400에러가 발생하기 때문에, 필수가 아닌 파라미터는 required 속성 값을 false로 지정한다 (값이 존재하지 않는다면 null).

	@GetMapping("/ex02")
	public String ex02(@RequestParam("NM") String name, @RequestParam("AG") int age) {
		
		log.info("name: " + name);
		log.info("age: " + age);
		
		return "ex02";
	}

 

defaultValue 속성을 이용해 기본값을 지정할 수 있다.

@RequestMapping("/search/internal.do")
		public ModelAndView searchInternal(@RequestParam("query") String query,
				@RequestParam(value = "p", defaultValue = "1") int pageNumber) {

 

3) 리스트, 배열 처리

 

3.1) 리스트 파라미터 타입 ArrayList<>
: 동일한 이름의 파라미터가 여러 개 전달될 시 이용한다.
(인터페이스 타입인 List<> 등이 아닌 실제 클래스 타입으로 지정한다.)

	@GetMapping("/ex02List")
	public String ex02List(@RequestParam("IDS")ArrayList<String> ids) {
		
		log.info("IDS: " + ids);
		
		return "ex02List";
		
	}

 

3.2) 배열(array) 파라미터타입 String[]

	@GetMapping("/ex02Array")
	public String ex02List(@RequestParam("IDS") String[] ids) {
		
		log.info("IDS: " + ids);
		log.info("array IDS: " + Arrays.toString(ids));  
		
		return "ex02Array";
		
	}

 

3.3) 객체 리스트

DTO와 같은 객체 타입을 여러개 처리할 수 있다.

DTO의 List를 포함하는 DTOList 클래스를 만들어 사용한다.

@Data
public class SampleDTOList {

	private List<SampleDTO> list;
	
	public SampleDTOList() {
		list = new ArrayList<>();
	}
}
	@GetMapping("/ex02Bean")
	public String ex02Bean(SampleDTOList list) {
		
		log.info("list dtos: " + list);
		
		return "ex02Bean";
	}

톰캣 버전에 따라 문자열에서 특수문자를 허용하지 않는 경우가 있다. "["는 %5B , "]"는 %5D로 변경한다. (tomcat9)

 

3.4) @CookieValue를 이용해 쿠키 값을 파라미터로 전달받을 수 있다.

 

쿠키가 필수가 아니라면 required 속성 값을 false로 지정한다.

defaultValue 속성을 이용해 기본값을 지정할 수 있다.

@RequestMapping("/cookie/view.do")
		public String view(
			@CookieValue(value = "auth", defaultValue = "0") String auth) {

 

4) @InitBinder

: 보통 파라미터 타입에 따라 변환 처리를 해야 하는 경우에 어노테이션을 직접 사용한다.

(Date타입으로의 변환은 @DateTimeFormat을 사용하는 것이 더 간단하다.)

@Data
public class TodoDTO {

	private String title;
	private Date dueDate;
}
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(dateFormat, false));
	}
	
	@GetMapping("/ex03")
	public String ex03(TodoDTO todo) {
		log.info("todo: " + todo);
		return "ex03";		
	}

Date타입으로 자동 변환되지 않기 때문에 @InitBinder로 처리를 하지 않으면 "dueDate=2023-02-07(문자열)"의 값은 제대로 전달되지 않는다.

 

5) @DateTimeFormat

날짜 변환 시 인스턴스 변수에 @DateTimeFormat을 적용한다.

@Data
public class TodoDTO {

	private String title;
	
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private Date dueDate;
}

 

6) @RequestHeader를 이용해 HTTP 요청 헤더 값을 메서드의 파라미터로 전달 받을 수 있다.

 

필수가 아니라면 required 속성 값을 false로 지정한다.

defaultValue 속성을 이용해 기본값을 지정할 수 있다.

@RequestMapping("/header/check.do")
			public String check(@RequestHeader("Accept-Language") String languageHeader) {

 

+ Servlet API를 사용해 파라미터를 전달 받을 수 있다.

 

 

5. Controller의 리턴타입

: Controller 메서드는 ModelAndView, Model, Map, String, View 객체, void, httpHeaders 등 다양한 리턴 타입을 가진다.

 

String 타입 : .jsp를 생략한 jsp파일명으로 리턴한다. 상황에 따라 다른 화면을 보여줄 때. ex) if~else 

return "home";

 

void 타입 : 자동으로 해당 URL과 동일한 이름의 jsp파일을 리턴한다. (servlet-context에서 url경로를 view로 처리하기 때문)


VO, DTO타입 등 객체 타입  : 주로 JSON데이터를 만드는 용도로 사용한다. (@ResponseBody 사용)

	@GetMapping("/ex06")
	public @ResponseBody SampleDTO ex06() {
		log.info("/ex06......");
		SampleDTO dto = new SampleDTO();
		dto.setAge(5);
		dto.setName("김이박");
		
		return dto;
	}

 

ResponseEntity 타입 : 헤더 정보나 데이터 전달한다.

@GetMapping("/ex07")
	public ResponseEntity<String> ex07() {
		log.info("/ex07.....");
		String msg = "{\"name\": \"김이박\"}";
		
		HttpHeaders header = new HttpHeaders();
		header.add("Content-Type", "application/json;charset=UTF-8");
		
		return new ResponseEntity<>(msg, header, HttpStatus.OK);
	}

 

 

6. Controller의 Exception 처리

6.1. @ControllerAdvice, @ExceptionHandler (AOP방식)

1) 어노테이션

@ControllerAdvice : 해당 객체가 예외를 처리함을 명시한다.

@ExceptionHandler(클래스타입) : 해당 메서드가 ()안의 예외 클래스 타입을 처리함을 의미한다.

 

ex)

@ControllerAdvice
@Log4j
public class CommonExceptionAdvice {
	
	@ExceptionHandler(Exception.class)
	public String except(Exception ex, Model model) {
		
		log.error("Exception..." + ex.getMessage());
		model.addAttribute("exception", ex);
		log.error(model);
		return "error_page";
	}

 

2) servlet- context에서 해당 컨트롤러 조사하도록 설정한다.

 

xml 설정 : servlet-context.xml에 코드 추가

<context:component-scan 
base-package="com.toy.exception"/>

 

java 설정 : ServletConfig.java에 코드 추가

@ComponentScan(basePackages = { "com.toy.controller", "com.toy.exception" })

//@ComponentScan(basePackages = { "com.toy.exception" })

 

6.2. 404 에러페이지

: 404dpfjzhemsms @ExceptionHandler가 아닌 다른 방식으로 처리한다.

: DispatcherServlet이 404에러를 처리하도록 web.xml을 수정하고 예외처리 클래스에 메서드를 추가하고 jsp를 작성한다. 

 

1) web 설정 수정

 

xml 설정 : web.xml - <servlet>에 <init-param> 추가 (DispatcherServlet)

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
...
        <init-param>
			<param-name>throwExceptionIfNoHandlerFound</param-name>
			<param-value>true</param-value>
		</init-param>
        
		<load-on-startup>1</load-on-startup>
	</servlet>

 

java 설정 - WebConfig.java에 코드 추가

@Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {
        registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
    }

 

2) 예외처리 클래스에 메서드를 추가한다

	@ExceptionHandler(NoHandlerFoundException.class)
	@ResponseStatus(HttpStatus.NOT_FOUND)
		public String handle404(NoHandlerFoundException ex) {
			
			return "custom404";
		}

 

 


참고

스프링 웹프로젝트

'SPRING' 카테고리의 다른 글

SPRING View 영역 구현  (0) 2022.11.14
SPRING Controller Model  (0) 2022.11.13
SPRING View 지정  (0) 2022.11.12
SPRING MVC 구조, 처리 흐름, 개발 과정  (0) 2022.11.10
SPRING Framework 개념, 기능, 특징  (0) 2022.11.09