본문 바로가기

STUDY/국비과정

[JAVA 웹 개발 공부] 국비지원 82일차 - 스프링 프레임 워크, IoC, 빈 등록, 어노테이션, Spring MVC, JdbcTemplate

Inversion of Control(IoC)


IoC란 기존 사용자가 모든 작업을 제어하던 것을 특별한 객체에 모든 것을 위임하여 객체의 생성부터 생명주기 등 모든 객체에 대한 제어권이 넘어 간 것을 IoC, 제어의 역전이라고 한다. IOC는 DI와 DL의 의해 구현된다.

DL(Dependency Lookup)
의존성 검색
컨테이너에서는 객체들을 관리하기 위해 별도의 저장소에 빈을 저장하는데 개발자들이 컨테이너에서 제공하는 API 를 이용하여 사용하고자 하는 빈을 검색하는 방법이다.
DI(Dependency Injection)
의존성 주입 
각 클래스 사이에 필요로 하는 의존관계를 빈 설정 정보를 바탕으로 컨테이너가 자동으로 연결해 주는 것이다.

 

 

스프링 빈(bean) 등록

 

스프링(Spring) 컨테이너가 관리하는 자바 객체를 빈(Bean)이라 한다.

 

1. xml 설정파일을 통해 Bean을 직접 등록

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="myFirstBean" class="ioc.MyObject" />
    
	<bean id="mySecondBean" class="ioc.MyBean">
		<constructor-arg value="임의값"/>
	</bean>	
	<alias name="mySecondBean" alias="hello"/>
</beans>

 

2. Bean Configuration File에 직접 Bean 등록

@Configuration과 @Bean 어노테이션을 이용하여 Bean을 등록할 수 있다.

어노테이션 설명
@Configuration 스프링 IOC Container에게 해당 클래스가 Bean 구성 Class임을 알려주는 어노테이션이다.
@Bean을 해당 클래스의 메소드에 적용하면, @Autowired로 빈을 부를 수 있다. (설정에 관련된 정보 어노테이션)
@Bean @Bean은 개발자가 직접 제어가 불가능한 외부 라이브러리등을 Bean으로 만들려할 때 사용되는 어노테이션이다.
라이브러리를 Bean으로 등록하기 위해서는 별도로 해당 라이브러리 객체를 반환하는 Method를 만들고 @Bean 어노테이션을 사용하면 된다.
@Autowired Bean을 주입받기 위하여 @Autowired 를 사용한다.
속성(field), setter method, constructor(생성자)에서 사용하며 Type에 따라 알아서 Bean을 주입 해준다.
Controller 클래스에서 DAO나 Service에 관한 객체들을 주입 시킬 때 많이 사용한다.
@Configuration
public class MyConfiguration {
    @Bean
    public MyController sampleController() {
        return new SampleController;
    }
}

 

3. 자바 어노테이션 사용하여 Bean 등록

컴포넌트 스캔(Component Scan)을 사용해 @Component 어노테이션이 있는 클래스들을 찾아서 자동으로 빈 등록을 해준다. @Component를 갖는 어노테이션으로 @Controller, @Service, @Repository 등이 존재한다.

어노테이션 설명
@ComponentScan @Component, @Service, @Repository, @Controller, @Configuration이 붙은 빈들을 찾아서
Context에 빈을 등록해 주는 어노테이션이다.
@ComponentScan 선언에 의해 특정 패키지 안의 클래스들을 자동 스캔하여
@ComponentScan 어노테이션이 있는 클래스들에 대하여 빈 인스턴스를 생성한다.
@Component 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 어노테이션이다.
@Component 어노테이션은 Controller, Service, DAO 세가지 이외의 클래스에만 사용한다.
@Component → (구체화) @Controller, @Service, @Repository
@Controller Spring MVC의 Controller로 사용되는 클래스 선언을 단순화 시켜주는 어노테이션이다.
Controller 클래스의 리턴타입이 String이면 jsp파일명을 의미한다.
@Service 비지니스 로직이 들어가는 Service로 사용되는 클래스임을 명시하는 어노테이션이다.
@Repository DB연동 작업을 하는 클래스인 DAO에 특화된 어노테이션으로,
해당 클래스에서 발생하는 DB 관련 예외를 spring의 DAOException으로 전환할 수 있는 장점이 있다.

 

 

스프링 MVC 흐름

 

1. 순서

Client → View → DispatcherServlet → HandlerMapping → Controller → ModelAndView → Controller → DispatcherServlet → ViewResolver → View → Client

 

(1) DispatcherServlet이 클라이언트에게서 요청을 받는다.

(2) DispatcherServlet이 컨트롤러의 요청 핸들러 메서드를 호출한다.

(3) 컨트롤러는 비지니스 로직 처리를 실행하여 처리 결과를 취득한다.

(4) 처리 결과를 Model로 설정하고 뷰 이름을 반환한다.

(5) DispatcherServlet은 뷰 이름에 대응하는 뷰에 대해서 화면 표시 처리를 의뢰한다.

(6) 클라이언트가 응답을 받고 브라우저에 화면이 표시된다.

 

2. 역할

DispatcherServlet 애플리케이션으로 들어오는 모든 Request를 받는 부분. Request를 실제로 처리할 Controller에게 전달하고 그 결과값을 받아서 View에 전달하여 적절한 응답을 생성할 수 있도록 흐름을 제어
HandlerMapping Request URL에 따라 각각 어떤 Controller가 실제로 처리할 것인지 찾아주는 역할
Controller Request를 직접 처리한 후 그 결과를 다시 DispatcherServlet에 돌려주는 역할
ModelAndView Controller가 처리한 결과와 그 결과를 보여줄 View에 관한 정보를 담고 있는 객체
ViewResolver View 관련 정보를 갖고 실제 View를 찾아주는 역할
View Controller가 처리한 결과값을 보여줄 View를 생성

 

 

JdbcTemplate

 

1. JdbcTemplate

JdbcTemplate는 DAO객체에서 DB와 연동하기 위해 SQL 연산들을 수행 할 수 있도록 도와주는 JDBC를 위한 틀이다.

 

*사용방법

(1) DataSource를 설정
(2) JdbcTemplate에서 DataSource를 주입(생성자)
(3) 메소드에 SQL 문 작성
(4) JdbcTemplate 메소드를 활용해 쿼리문 처리

 

 

2. JdbcTemplate 메소드

메소드 설명
query() sql 파라미터로 전달받은 쿼리를 실행하고 RowMapper를 이용해서 ResultSet의 결과를 자바 객체로 변환해주는 메소드
queryForObject() queryForObject() 메서드는 쿼리 실행 결과가 한 행인 경우 사용할 수 있는 메소드
update() SQL 연산을 통해 데이터베이스를 갱신시켜줄 때(INSERT, DELETE, UPDATE) 사용하는 메소드


+) RowMapper<T> 인터페이스
ResultSet에서 데이터를 읽어와 Member 객체로 변환해주는 기능을 제공한다.
RowMapper의 mapRow() 메서드는 SQL 실행 결과로 구한 ResultSet에서 한 행의 데이터를 읽어와 자바 객체로 변환하는 매퍼 기능을 구현한다.

 

 

JdbcTemplate 사용

 

 

*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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>ioc</groupId>
	<artifactId>ioc</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	
	<properties>
		<spring-version>5.3.25</spring-version>
	</properties>
	
	<dependencies>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>2.9.0</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.32</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring-version}</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring-version}</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-version}</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring-version}</version>
		</dependency>
	</dependencies>
	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

 

*Book.java

package book;

public class Book {
	private int no;
	private String title;
	private int price;
	
	public Book() {}
	public Book(int no, String title, int price) {
		super();
		this.no = no;
		this.title = title;
		this.price = price;
	}
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	
	@Override
	public String toString() {
		return "Book [no=" + no + ", title=" + title + ", price=" + price + "]";
	}
}

 

*BookRepository.java

package book;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

@Repository
public class BookRepository {
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public List<Book> getAll() {
		return jdbcTemplate.query("SELECT no, title, price FROM book", new RowMapper<Book>() {
			@Override
			public Book mapRow(ResultSet rs, int rowNum) throws SQLException {
				int no = rs.getInt("no");
				String title = rs.getString("title");
				int price = rs.getInt("price");
				
				return new Book(no, title, price);
			}
		});
	}
	
	public Integer count() {
		return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM book", Integer.class);
	}
	
	public Map<String, Object> minmax() {
		return jdbcTemplate.queryForMap("SELECT MIN(price) AS min, MAX(price) as max FROM book");
	}
	
	public List<String> titles() {
		return jdbcTemplate.queryForList("SELECT title FROM book", String.class);
	}
	
	public Book getByNo(int no) {
		return jdbcTemplate.queryForObject("SELECT * FROM book WHERE no = ?"
				, new BeanPropertyRowMapper<Book>(Book.class)
				, no);
	}
	
	public int insert(Book book) {
		return jdbcTemplate.update("INSERT INTO book (title, price) VALUES (?, ?)"
				, book.getTitle(), book.getPrice());
	}
	
	public int update(Book book) {
		return jdbcTemplate.update("UPDATE book SET title = ?, price = ?, WHERE no = ?", 
				book.getTitle(), book.getPrice(), book.getNo());
	}
}

 

*DataSourceConfig.java

package config;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

@Configuration
@ComponentScan("book")
public class DataSourceConfig {
	@Bean
	public DataSource dataSource() {
		BasicDataSource ds = new BasicDataSource();
		ds.setUrl("jdbc:mysql://localhost:3306/my_db");
		ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
		ds.setUsername("root");
		ds.setPassword("root");
		
		return ds;
	}
	
	@Bean
	@Autowired
	public JdbcTemplate jdbcTemplate(DataSource dataSource) {
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
		return jdbcTemplate;
	}
	
//	@Bean
//	public BookRepository bookRepository() {
//		return new BookRepository();
//	}
}

 

*Test.java

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import book.Book;
import book.BookRepository;
import config.DataSourceConfig;

public class Test {
	public static void main(String[] args) {
		ApplicationContext context = new AnnotationConfigApplicationContext(DataSourceConfig.class);
		BookRepository repo = context.getBean(BookRepository.class);
		
		List<Book> result = repo.getAll();
		System.out.println(result);
		
		System.out.println("개수: " + repo.count());
		System.out.println("2번 책: " + repo.getByNo(2));
		System.out.println("최소, 최대값: " + repo.minmax());
		
		Book newBook = new Book();
		newBook.setTitle("jdbc로 row 추가하기");
		newBook.setPrice(15000);
		
		int inserted = repo.insert(newBook);
		System.out.println("추가된 행 개수: " + inserted);
		
	}
}
[Book [no=2, title=구의 증명, price=6480], Book [no=6, title=테스트용책이름, price=50000], Book [no=7, title=테스트용책이름, price=50000], Book [no=8, title=테스트용책이름, price=50000], Book [no=9, title=테스트용책이름, price=50000], Book [no=10, title=테스트용책이름, price=50000], Book [no=14, title=new title, price=30000], Book [no=15, title=new title, price=30000], Book [no=16, title=new title, price=30000], Book [no=17, title=jdbc로 row 추가하기, price=15000]]
개수: 10
2번 책: Book [no=2, title=구의 증명, price=6480]
최소, 최대값: {min=6480, max=50000}
추가된 행 개수: 1

 

 

DB 연동

 

 

*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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>spring-mvc</groupId>
	<artifactId>spring-mvc</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<dependencyManagement>
		<dependencies>
			<!-- https://mvnrepository.com/artifact/org.springframework/spring-framework-bom -->
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-framework-bom</artifactId>
				<version>5.3.25</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
		<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>2.0.6</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.3.5</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/junit/junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.13.2</version>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jcl -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jcl</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>2.9.0</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.32</version>
		</dependency>
	</dependencies>
	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.2.3</version>
				<configuration>
					<warSourceDirectory>webapp</warSourceDirectory>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

*WebInit.java

package kr.co.greenart.config;

import javax.servlet.Filter;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { RootConfig.class };
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] { WebConfig.class };
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}
	
	@Override
	protected Filter[] getServletFilters() {
		CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
		encodingFilter.setEncoding("UTF-8");
		encodingFilter.setForceEncoding(true);
		return new Filter[] { encodingFilter };
	}
}

 

*WebConfig.java

package kr.co.greenart.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan("kr.co.greenart")
public class WebConfig implements WebMvcConfigurer {
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/WEB-INF/views/", ".jsp");
	}
}

 

*RootConfig.java

package kr.co.greenart.config;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;

@Configuration
@PropertySource("classpath:/kr/co/greenart/config/datasource.properties")
public class RootConfig {
	@Value("${mysql.dirverClassName}")
	private String driverClassName;
	@Value("${mysql.url}")
	private String url;
	@Value("${mysql.userName}")
	private String userName;
	@Value("${mysql.password}")
	private String password;	
	
	@Bean
	public DataSource dataSource() {
		BasicDataSource ds = new BasicDataSource();
		ds.setDriverClassName(driverClassName);
		ds.setUrl(url);
		ds.setUsername(userName);
		ds.setPassword(password);
		
		return ds;
	}
	
	@Bean
	@Autowired
	public JdbcTemplate jdbcTemplate(DataSource dataSource) {
		return new JdbcTemplate(dataSource);
	}
}

 

*datasource.properties

mysql.dirverClassName=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/my_db
mysql.userName=root
mysql.password=root

*Book.java

package kr.co.greenart.book;

public class Book {
	private int no;
	private String title;
	private int price;
	public Book() {}
	public Book(int no, String title, int price) {
		super();
		this.no = no;
		this.title = title;
		this.price = price;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	@Override
	public String toString() {
		return "Book [no=" + no + ", title=" + title + ", price=" + price + "]";
	}
}

 

*BookController.java

package kr.co.greenart.book;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class BookController {
	private static final Logger logger = LoggerFactory.getLogger(BookController.class);
	
	@Autowired
	private BookService service;
	
	@GetMapping("/book")
	public String booklist(Model model) {
		model.addAttribute("name", service.getAll());
		return "booklist";
	}
	
	@GetMapping("/book/add")
	public String bookadd() {
		return "bookform";
	}
	
	@PostMapping("/book/add")
	public String bookaddpost(@RequestParam(name = "title") String title
			, @RequestParam(name = "price") int price) {
		Book book = new Book();
		book.setTitle(title);
		book.setPrice(price);
		
		service.insert(book);
		
		return "redirect:/";
	}
}

 

*BookRepository.java

package kr.co.greenart.book;

import java.util.List;

public interface BookRepository {
	public List<Book> getAll();
	public int insert(Book book);
}

 

*BookRepositoryMySQL.java

package kr.co.greenart.book;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository("bookMySQL")
//@Primary
public class BookRepositoryMySQL implements BookRepository {
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	@Override
	public List<Book> getAll() {
		return jdbcTemplate.query("SELECT * FROM book", new BeanPropertyRowMapper<Book>(Book.class));
	}

	@Override
	public int insert(Book book) {
		return jdbcTemplate.update("INSERT INTO book (title, price) VALUES (?, ?)"
				, book.getTitle()
				, book.getPrice());
	}
}

 

*BookService.java

package kr.co.greenart.book;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookService {
	@Autowired
	@Qualifier("bookMySQL")
	private BookRepository repo;
	
	public List<Book> getAll() {
		return repo.getAll();
	}
	
	public int insert(Book book) {
		return repo.insert(book);
	}
}

*HandlerTestController.java

package kr.co.greenart.handler;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HandlerTestController {
	@GetMapping("/void") // mapping 경로와 같은 view 이름으로 forward
	public void voidView() {
		
	}
	
	@GetMapping("/forward")
	public String forward() {
		return "index";
	}
	
	@GetMapping("/mv")
	public ModelAndView mv() { // 응답코드, Model의 Attribute, forward View 이름 설정 가능한 객체
		ModelAndView mv = new ModelAndView(); 
		mv.addObject("asdf", "asdf");
		mv.setStatus(HttpStatus.OK);
		mv.setViewName("index");
		
		return mv;
	}
	
	@GetMapping("/entity")
	public ResponseEntity<String> entity() {
		String body = "body 내용";
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.TEXT_PLAIN);
		
		ResponseEntity<String> response = new ResponseEntity<String>(body, HttpStatus.OK);
		return response;
	}
	
	@GetMapping("/entity2")
	public ResponseEntity<String> entity2() {
		return ResponseEntity.ok().header("Content-Type", "plain/text").body("응답 body 내용");
	}
}

*IndexController.java

package kr.co.greenart.index;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class IndexController {
	private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
	
	@RequestMapping(value = { "/", "/index.jsp" }, method = RequestMethod.GET)
	public String index() {
		logger.info("사용자가 INDEX 페이지를 요청하였습니다.");
		return "index";
	}
}

*TestConnection.java

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import kr.co.greenart.config.RootConfig;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { RootConfig.class })
public class TestConnection {
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	@Test
	public void testConnection() {
		int result = jdbcTemplate.queryForObject("SELECT 1", Integer.class);
		assertEquals(1, result);
	}
}

*index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
	<h1>INDEX PAGE</h1>
	<a href="./book">책 목록 보기</a>
	<a href="./book/add">책 추가하기</a>
</body>
</html>

 

*bookform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>책 추가 페이지</title>
</head>
<body>
	<form action="" method="post">
		<input type="text" name="title"> 
		<input type="number" name="price"> 
		<input type="submit">
	</form>
</body>
</html>

 

*booklist.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>책 목록</title>
</head>
<body>
	<h1>책 목록을 보여줄 view</h1>
	<p>${ name }</p>
</body>
</html>

 

*void.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>
	<h1>Void View</h1>
</body>
</html>