[부스트코스 웹] Spring MVC 실습

June·2021년 1월 9일
0

부스트코스

목록 보기
22/23

Controller 작성 실습 1/3

  1. 웹 브라우저에서 http://localhost:8080/mvcexam/plusform이라고 요청을 보내면 서버는 웹 브라우저에게 2개의 값을 입력받을 수 있는 입력 창과 버튼이 있는 화면을 출력한다.
  2. 웹 브라워제에게 2개의 값을 입력하고 버튼을 클릭하면 http://localhost:8080/mvcexam/plus URL로 2개의 입력값이 POST 방식으로 서버에게 전달한다. 서버는 2개의 값을 더한 후, 그 결과 값을 JSP에게 request scope으로 전달하여 출력한다.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>kr.or.connect</groupId>
	<artifactId>daoexam</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>daoexam</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>4.3.5.RELEASE</spring.version>
	</properties>

	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- basic data source -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>2.1.1</version>
		</dependency>


		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.45</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.6.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

MVC 사용할 수 있게 설정

DispatcherServlet을 FrontController로 설정하기

  1. web.xml 파일에 설정
  2. javax.servlet.ServletContainerInitializer 사용
    1. 서블릿 3.0 스펙 이상에서 web.xml 파일을 대신해서 사용할 수 잇다
  3. org.springframework.web.WebApplicationInitializer 인터페이스를 구현해서 사용

web.xml 이용 방법

  1. web.xml 파일에서 DispatcherServlet 설정하기 1/2
  • xml spring 설정 읽어들이도록 DispatcherServlet 설정
<?xml version="1.0" encoding = "UTF-8"?>
<web-app>
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:WebMVCContextConfig.xml</param-value>
    <init-param>
  </servlet>
</web-app>
  1. Java config spring 설정 읽어들이도록 DispatcherServlet 설정

WebApplicationInitializer를 구현해서 설정하기

  • Spring MVC는 ServletContainerInitalizer를 구현하고 있는 SpringServletContainerInitalizer를 제공한다
  • SpringServletContainerInitializer는 WebApplicationInitializer 구현체를 찾아 인스턴스를 만들고 해당 인스턴스의 onStartup메소드를 호출하여 초기화 한다.

Spring MVC 설정

  • kr.or.connect.webmvc.config.WebMvcContextConfiguration

@Configuration

  • org.springframework.context.annotation의 Configuration 애노테이션과 Bean 애노테이션 코드를 이용하여 스프링 컨테이너에 새로운 빈 객체를 제공할 수 있다.

@EnableWebMvc

  • DispatcherServlet의 RequestMappingHandlerMapping, RequestMappingHandlerAdapter, ExceptionHandlerExceptionResolver, MessageConverter 등 Web에 필요한 빈들을 대부분 자동으로 설정해준다.
  • xml로 설정의 <mvc:annotation-driven/> 와 동일하다.
  • 기본 설정 이외의 설정이 필요하다면 WebMvcConfigurerAdapter 를 상속받도록 Java config class를 작성한 후, 필요한 메소드를 오버라이딩 하도록 한다.

@ComponentScan

  • ComponentScan애노테이션을 이용하면 Controller, Service, Repository, Component애노테이션이 붙은 클래스를 찾아 스프링 컨테이너가 관리하게 된다.
  • DefaultAnnotationHandlerMapping과 RequestMappingHandlerMapping구현체는 다른 핸드러 매핑보다 훨씬 더 정교한 작업을 수행한다. 이 두 개의 구현체는 애노테이션을 사용해 매핑 관계를 찾는 매우 강력한 기능을 가지고 있다. 이들 구현체는 스프링 컨테이너 즉 애플리케이션 컨텍스트에 있는 요청 처리 빈에서 RequestMapping애노테이션을 클래스나 메소드에서 찾아 HandlerMapping객체를 생성하게 된다.
    • HandlerMapping은 서버로 들어온 요청을 어느 핸들러로 전달할지 결정하는 역할을 수행한다.
  • DefaultAnnotationHandlerMapping은 DispatcherServlet이 기본으로 등록하는 기본 핸들러 맵핑 객체이고, RequestMappingHandlerMapping은 더 강력하고 유연하지만 사용하려면 명시적으로 설정해야 한다.

WebMvcConfigurerAdapter

  • org.springframework.web.servlet.config.annotation. WebMvcConfigurerAdapter
  • @EnableWebMvc 를 이용하면 기본적인 설정이 모두 자동으로 되지만, 기본 설정 이외의 설정이 필요할 경우 해당 클래스를 상속 받은 후, 메소드를 오버라이딩 하여 구현한다.

Controller(Handler) 클래스 작성하기

  • @Controller 애노테이션을 클래스 위에 붙인다
  • 맵핑을 위해 @RequestMapping 애노테이션을 클래스나 메소드에서 사용한다.

@RequestMapping

  • Http 요청과 이를 다루기 위한 Controller 의 메소드를 연결하는 어노테이션
  • Http Method 와 연결하는 방법
    • @RequestMapping(value="/users", method=RequestMethod.POST)
    • From Spring 4.3 version
      (@GetMapping,
      @PostMapping,
      @PutMapping,
      @DeleteMapping,
      @PatchMapping)
  • Http 특정 해더와 연결하는 방법
    • @RequestMapping(method = RequestMethod.GET, headers = "content-type=application/json")
  • Http Parameter 와 연결하는 방법
    • @RequestMapping(method = RequestMethod.GET, params = "type=raw")
  • Content-Type Header 와 연결하는 방법
    • @RequestMapping(method = RequestMethod.GET, consumes = "application/json")
  • Accept Header 와 연결하는 방법
    • @RequestMapping(method = RequestMethod.GET, produces = "application/json")

실습

실습 자료 링크

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(31556926);
        registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
        registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
        registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
    }

기본적으로 모든 요청을 한 DispatcherServlet이 받지만, css, img 와 같은 요청들은 어디로 보낼지 결정하는 것이다.

@Override
public void addViewControllers(final ViewControllerRegistry registry) {
	System.out.println("addViewControllers가 호출됩니다");
	registry.addViewController("/").setViewName("main");
}

특정 url에 대한 처리를 controller 클래스를 맵핑하지 않고 처리할 수 있게 해주는 것이다.

    //view name (위에서 'main')은 ViewResolver라는 객체를 이용해서 찾는다.
    //getInternalResourceViewResolver()에서 설정된 형태로 뷰를 사용하게 된다.
    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        ///WEB-INF/views/main.jsp
        resolver.setPrefix("/WEB-INF/views/");//main 앞쪽
        resolver.setSuffix(".jsp");              //main 뒷 쪽
        return resolver;
    }

web.xml 파일에서 DispatcherServlet 설정하기

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>

  <display-name>Spring JavaConfig Sample</display-name>

  <servlet>
    <servlet-name>mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextClass</param-name>
      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>kr.or.connect.mvcexam.config.WebMvcContextConfiguration</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>


</web-app>

실습 2

plusForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form method = "post" action = "plus">
		value 1: <input type = "text" name = "value1"><br>
		value 2: <input type = "text" name = "value2"><br>
		<input type="submit" value="확인">
	</form>
</body>
</html>

"/plus" URL로 요청이 들어오면 입력 값을 두개 받고, post 방식으로 보낸다.

plusResult.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
${value1} 더하기 ${value2} (은/는) ${result} 입니다. 
</body>
</html>

결과값을 보여주는 창이다

PlusController.java

package kr.or.connect.mvcexam.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframe ork.web.bind.annotation.RequestParam;

@Controller
public class PlusController {
	@GetMapping(path="/plusform") //Get방식으로 들어온다. URL은 /plusform
	public String plusform() { //"plusForm.jsp"의 이름이다. 
		return "plusForm";	//WebMvcContextConfiguration에서 getInternalResourceViewResolver()함수가 경로와 파일 양식을 붙인다.
	}
	
	@PostMapping(path="/plus") //"value1"이라는 이름으로 넘어온 값을 value1 변수로 받는다. modelMap은 Spring이 제공하는 객체다. 알아서 request scope에 맵핑 시켜준다. 
	public String plus(@RequestParam(name = "value1", required = true) int value1,
			@RequestParam(name = "value2", required = true) int value2, ModelMap modelMap) {
		int result = value1 + value2;
		
		modelMap.addAttribute("value1", value1);
		modelMap.addAttribute("value2", value2);
		modelMap.addAttribute("result", result);
		return "plusResult";
	}
}

실습 3

userForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form method = "post" action = "regist">
		name : <input type = "text" name = name"><br>
		email : <input type = "text" name = "email"><br>
		age : <input type = "text" name = "age"><br>
		<input type = "submit" value = "확인">
	</form>
</body>
</html>

User

package kr.or.connect.mvcexam.dto;

public class User {
	private String name;
	private String email;
	private int age;
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", email=" + email + ", age=" + age + "]";
	}
}

UserController.java

package kr.or.connect.mvcexam.controller;

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 kr.or.connect.mvcexam.dto.User;

@Controller
public class UserController {
	@RequestMapping(path = "/userform", method = RequestMethod.GET)
	public String userform() {
		return "userForm";
	}
	
	@RequestMapping(path = "/regist", method = RequestMethod.POST)
	public String regist(@ModelAttribute User user) {
		System.out.println("사용자가 입력한 user 정보입니다. 해당 정보를 이용하는 코드가 와야합니다.");
		System.out.println(user);
		return "regist";
	}
}

goodsById.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
id: ${id } <br>
user_agent: ${userAgent }<br>
path: ${path }<br>
</body>
</html>

GoodsController.java

package kr.or.connect.mvcexam.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;

@Controller
public class GoodsController {
	@GetMapping("/goods/{id}")
	public String getGoodsById(@PathVariable(name="id") int id,
							   @RequestHeader(value="User-Agent", defaultValue="myBrowser") String userAgent,
							  HttpServletRequest request,
							  ModelMap model
							  ) {
		
		String path = request.getServletPath();
		
		System.out.println("id : " + id);
		System.out.println("user_agent : " + userAgent);
		System.out.println("path : " + path);
		
		model.addAttribute("id", id);
		model.addAttribute("userAgent", userAgent);
		model.addAttribute("path", path);
		return "goodsById";
	}
}

0개의 댓글