BE - 미션

수현·2023년 10월 15일
0

Ucamp

목록 보기
17/19

@PatchMapping("/{email}")
public Customer updateCustomer(@PathVariable String email, @RequestBody Customer customer) {
Customer existCustomer = customerRepository.findByEmail(email)
.orElseThrow(() -> new BusinessException("Email이 존재하지 않습니다", HttpStatus.NOT_FOUND));
if (customer.getName() != null)
existCustomer.setName(customer.getName());
if (customer.getAge() != 0)
existCustomer.setAge(customer.getAge());
return customerRepository.save(existCustomer);
}

📘 미션 (10/06)

1. 문제

  • customer 테이블 구조
customer
 id - auto increment
 name
 email - unique
 age
 entryDate (DB에서 날짜를 어떻게 insert 하는지 확인)
  • 생성할 파일
    CustomerDAO.java
    CustomerBO.java
    index.jsp
    CustomerListServlet.java
    customerList.jsp
    web.xml 설정
    mariadb.jar / jstl.jar lib에 이동

코드

1) DB 설정

  • table 생성
create table customer(
	id int(10) not null auto_increment primary key,
	name varchar(100) not null,
	email varchar(100) not null,
	age int(10),
	entryDate date,
 	UNIQUE KEY uk_name (email)
);
alter table customer add unique(id);

insert into customer(name, email, age, entryDate) values ('gildong', 'gildong@naver.com', 20, '2023-10-01');
insert into customer(name, email, age, entryDate) values ('dooly', 'dooly@google.com', 25, '2023-10-05');
insert into customer(name, email, age, entryDate) values ('huidong', 'huidong@google.com', 18, '2023-09-05');
insert into customer(name, email, age, entryDate) values ('micole', 'micole@naver.com', 28, '2022-10-10');
insert into customer(name, email, age, entryDate) values ('ddochi', 'ddochi@google.com', 20, '2023-05-05');
commit;


📘 미션 (10/11)

pom.xml 의존성 주입

pom.xml

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

<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>com.maven.spring</groupId>
	<artifactId>MySpringFW</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>CustomerSpringWeb Maven Webapp</name>
	<!-- FIXME change it to the project's website -->
	<url>http://www.example.com</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
		<spring.version>5.2.25.RELEASE</spring.version>
	</properties>

	<dependencies>
		<!-- 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-test -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-test</artifactId>
		    <version>${spring.version}</version>
		    <scope>test</scope>
		    <!-- scope : test라고 이름 지어진 폴더에만 적용 -->
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
		<dependency>
		    <groupId>org.mariadb.jdbc</groupId>
		    <artifactId>mariadb-java-client</artifactId>
		    <version>3.1.4</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
		    <version>${spring.version}</version>
		</dependency>
		
		<!-- Hikari Connection Pooling -->
		<dependency>
		   <groupId>com.zaxxer</groupId>
		   <artifactId>HikariCP</artifactId>
		   <version>4.0.3</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis</artifactId>
		    <version>3.5.6</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis-spring</artifactId>
		    <version>2.0.6</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.11.0</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-webmvc</artifactId>
		    <version>${spring.version}</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		
	</dependencies>

	<build>
		<finalName>MySpringFW</finalName>
		<pluginManagement><!-- lock down plugins versions to avoid using Maven 
				defaults (may be moved to parent pom) -->
			<plugins>
				<plugin>
					<artifactId>maven-clean-plugin</artifactId>
					<version>3.1.0</version>
				</plugin>
				<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
				<plugin>
					<artifactId>maven-resources-plugin</artifactId>
					<version>3.0.2</version>
				</plugin>
				<plugin>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.8.0</version>
				</plugin>
				<plugin>
					<artifactId>maven-surefire-plugin</artifactId>
					<version>2.22.1</version>
				</plugin>
				<plugin>
					<artifactId>maven-war-plugin</artifactId>
					<version>3.2.2</version>
				</plugin>
				<plugin>
					<artifactId>maven-install-plugin</artifactId>
					<version>2.5.2</version>
				</plugin>
				<plugin>
					<artifactId>maven-deploy-plugin</artifactId>
					<version>2.8.2</version>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
</project>

1. DataSource

  • DB와 관계된 커넥션 정보를 담고있으며 빈으로 등록하여 인자로 넘겨준다. → 이 과정을 통해 Spring은 DataSource로 DB와의 연결을 획득한다.
    • DB 서버와의 연결을 해준다.
    • DB Connetion pooling기능

1) DB 설정

spring-bean-customer.xml

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

	<!-- Properties file 정보 설정 -->
	<context:property-placeholder location="classpath:value.properties"/>
	
	<!-- DataSource 구현체인 HikariDataSource를 SpringBean으로 등록 -->
	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" 
		p:driverClassName="${db.driverClass}"
		p:jdbcUrl="${db.url}"
		p:username="${db.username}"
		p:password="${db.password}"
	/>
</beans>

2) 속성값을 properties 파일에 작성

value.properties

db.driverClass=org.mariadb.jdbc.Driver
db.url=jdbc:mariadb://127.0.0.1:3306/boot_db?useUnicode=true&charaterEncoding=utf-8&useSSL=false&serverTimezone=UTC
db.username=boot
db.password=boot

myname=Spring
myprinter=printer
value1=JUnit
value2=AOP
value3=DI
printer1=stringPrinter
printer2=consolePrinter

3) 테스트

CustomerDBTest.java

package myspring.customer;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "classpath:spring-beans-customer.xml")
public class CustomerDBTest {
	@Autowired
	DataSource dataSource;
	
	@Test
	public void conn() {
		try {
			Connection connection = dataSource.getConnection();
			DatabaseMetaData metaData = connection.getMetaData();
			System.out.println("DB Product Name : " + metaData.getDatabaseProductName()); //MariaDB
			System.out.println("DB Driver : " + metaData.getDriverName()); // MariaDB Connector/J
			System.out.println("DB URL : " + metaData.getURL()); // jdbc:mariadb://127.0.0.1/boot_db?user=boot&password=***&...
			System.out.println("DB Username : " + metaData.getUserName()); // boot
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

2. SqlSession

1) myspring.customer.vo 패키지 생성

2) CustomerVO 클래스 생성

  • src/main/java 하단에 생성
    • private으로 변수 선언
    • 기본 생성자
    • getter/setter
    • toString 생성

CustomerVO.java

package myspring.customer.vo;

public class CustomerVO {
	
	private Long id;
	private String name;
	private String email;
	private int age;
	private String entryDate;

	// 기본생성자 
	public CustomerVO() {}
	
	public CustomerVO(String name, String email, int age, String entryDate) {
		this.name = name;
		this.email = email;
		this.age = age;
		this.entryDate = entryDate;
	}

	// getter와 setter 생성
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	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;
	}

	public String getEntryDate() {
		return entryDate;
	}

	public void setEntryDate(String entryDate) {
		this.entryDate = entryDate;
	}

	// toString 생성
	@Override
	public String toString() {
		return "CustomerVO [id=" + id + ", name=" + name + ", email=" + email + ", age=" + age + ", entryDate="
				+ entryDate + "]";
	}
}
  • customer 테이블 참고

3) sqlMapConfig 생성

  • src/main/resources 하단에 생성
    • mybatis 폴더 생성
    • log4j2 설정
    • CustomerVO 설정

sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
	"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<!-- log4j2 설정 -->
	<settings>
         <setting name="defaultStatementTimeout" value="3"/> 
         <setting name="logImpl" value="LOG4J2"/>
    </settings>
    
	<typeAliases>
		<!-- CustomerVO 설정  -->
		<typeAlias alias="Customer" type="myspring.customer.vo.CustomerVO" />
	</typeAliases>

</configuration>

4) log4j2.xml 추가

  • src/main/resources 하단에 추가
  • appender를 이용해서 console에도 찍을 수 있고 file에 로그 정보 저장 가능

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
	<Appenders>
		<File name="File" fileName="./logs/logfile.log" append="true">
			<PatternLayout
				pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-5level %logger{36} - %msg%n" />
		</File>
		<Console name="console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
	</Appenders>

	<Loggers>
		<Logger name="org.springframework" level="INFO" additivity="false" />
			
		<Logger name="myspring" level="DEBUG" />

		<Root level="DEBUG">
			<AppenderRef ref="console" level="DEBUG" />
			<AppenderRef ref="File" level="DEBUG" />
		</Root>
	</Loggers>
</Configuration>

5) CustomerMapper 생성

  • src/mainresoures/mybatis 하단에 생성
    • selectCustomerById select 쿼리문 생성
    • selectCustomerList select 쿼리문 생성
    • select의 결과값이 CustomerVO 객체에 저장
      CustomerMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="customerNS"> 
	<!-- 조회 쿼리는 id를 이용하여 실행 -->
	<!-- parameter에 들어가는 값이 {value} 변수로 들어옴  -->
	<select id="selectCustomerById" parameterType="string" resultType="Customer"> 
		select * from customer where name=#{value}
	</select>

	<select id="selectCustomerList" resultType="Customer">
		select * from customer order by id
	</select>
	
</mapper>

6) sqlsession

  • sqlsessionfactory

    • setDataSource() 메서드의 인자로 hikaridatasource 들어옴
    • setConfigLocation() 으로 MyBatisConfig(sqlMapConfig) 파일 연결
    • setMapperLocations() mapping (*Mapper) 파일 연결
  • sqlsession

    • sql 실행 목적
    • SqlSessionFactory를 통해 취득한 SqlSession을 실행중인 트랜잭션에 할당함

spring-beans-customer.xml

// 하단에 추가 

<!-- Mybatis-spring의 SqlSessionFactoryBean을 SpringBean으로 등록 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
		<property name="mapperLocations">
			<list>
				<value>classpath:mybatis/*Mapper.xml</value>
			</list>
		</property>
	</bean>

<!-- SqlSessionTemplate -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg ref="sqlSessionFactory"/>
		
	</bean>

7) 테스트

CustomerDBTest.java

package myspring.customer;

import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import myspring.customer.vo.CustomerVO;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "classpath:spring-beans-customer.xml")
public class CustomerDBTest {
	@Autowired
	SqlSession sqlSession;
	
	
	@Test
	public void session() {
		CustomerVO customer = sqlSession.selectOne("customerNS.selectCustomerById", "dooly");
		System.out.println(customer);
	}

}

3. Mapper

1) myspring.customer.dao.mapper 패키지 생성

2) CustomerMapper 인터페이스 생성

  • 사용 이유
    • CustomerMapper의 mapper의 namespace 방식은 오류의 위험이 있음
// CustomerMapper.xml
<mapper namespace="customerNS"> 

// CustomerDBTest.java
@Test
	public void session() {
		CustomerVO customer = sqlSession.selectOne("customerNS.selectCustomerById", "dooly");
		System.out.println(customer);
	}
  • mapper 사용시 주의 사항
    • Mapper.xml과 Mapper 인터페이스의 메서드명 일치시키기
    • xml이 수정될 때마다 업데이트 필요
    • Mapper과 SqlSession 부르기 위해 연결하기 위한 설정 필요

CustomerMapper.java

package myspring.customer.dao.mapper;

import java.util.List;

import myspring.customer.vo.CustomerVO;

public interface CustomerMapper {
	CustomerVO selectCustomerById(String id);
	List<CustomerVO> selectCustomerList();
}

3) CustomerMapper.xml 파일 수정

CustomerMapper.xml

// 변경 <mapper namespace="customerNS"> -> <mapper namespace="myspring.customer.dao.mapper.CustomerMapper">
  
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="myspring.customer.dao.mapper.CustomerMapper">
	<!-- 조회 쿼리는 id를 이용하여 실행 -->
	<!-- parameter에 들어가는 값이 {value} 변수로 들어옴  -->
	<select id="selectCustomerById" parameterType="string" resultType="Customer"> 
		select * from customer where name=#{value}
	</select>

	<select id="selectCustomerList" resultType="Customer">
		select * from customer order by id
	</select>
	
</mapper>

4) mapper와 sqlSession 연결

spring-beans-customer.xml

// 하단에 추가

<!-- Mybatis-Spring의 MapperScannerConfigurer을 SpringBean으로 등록 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<!-- 참조하는 것 없어서 bean id 없어도 됨 -->
		<property name="basePackage" value="myspring.customer.dao.mapper" />
		<property name="sqlSessionTemplateBeanName" value="sqlSession"/>
	</bean>

5) 테스트

CustomerDBTest.java

package myspring.customer;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import myspring.customer.dao.mapper.CustomerMapper;
import myspring.customer.vo.CustomerVO;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "classpath:spring-beans-customer.xml")
public class CustomerDBTest {
	@Autowired
	CustomerMapper customerMapper;
	
	@Test
	public void mapper() {
		// id가 메서드 이름이 되어 argument 전달 
		CustomerVO customer = customerMapper.selectCustomerById("dooly"); 
		System.out.println(customer);
	}

}

4. DAO와 Service

1) myspring.customer.dao와 service 패키지 생성

  • src/main/java 하단에 생성

2) CustomerDao 인터페이스 생성

CustomerDao.java

package myspring.customer.dao;

import java.util.List;

import myspring.customer.vo.CustomerVO;

public interface CustomerDAO {
	public List<CustomerVO> readAll();
	public CustomerVO read(String id);
}

3) CustomerDaoImpl 클래스 생성

CustomerDaoImpl.java

package myspring.customer.dao;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import myspring.customer.dao.mapper.CustomerMapper;
import myspring.customer.vo.CustomerVO;

@Repository("customerDao")
public class CustomerDaoImpl implements CustomerDao {
	@Autowired
	private CustomerMapper customerMapper;	
	
	@Override
	public CustomerVO read(String id) {
		CustomerVO user  = customerMapper.selectCustomerById(id);
		return user;
	}
	
	public List<CustomerVO> readAll() {
		List<CustomerVO> userList = customerMapper.selectCustomerList();
		return userList;
	}
}

4) CustomerService 인터페이스 생성

CustomerService.java

package myspring.customer.sevice;

import java.util.List;

import myspring.customer.vo.CustomerVO;

public interface CustomerService {
	public List<CustomerVO> getCustomerList();
	public CustomerVO getUser(String id);
}

5) CustomerServiceImpl 클래스 생성

CustomerServiceImpl.java

package myspring.customer.sevice;

import java.util.List;

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

import myspring.customer.dao.CustomerDao;
import myspring.customer.vo.CustomerVO;

@Service("customerService")
public class CustomerServiceImpl implements CustomerService {

	@Autowired
	CustomerDao customerdao;

	public List<CustomerVO> getCustomerList() {
		return customerdao.readAll();
	}

	@Override
	public CustomerVO getUser(String id) {
		return customerdao.read(id);
	}

}

6) dao와 service의 component scan

spring-beans-customer.xml

// 하단에 추가 
<!-- DAO, Service에 해당하는 Bean을 Scanning -->
	<context:component-scan base-package="myspring.customer" >
		<!-- 하단의  myspring.customer에서 controller만 제외하고 scan -->
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>

7) 테스트

CustomerDBTest.java

package myspring.customer;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import myspring.customer.dao.mapper.CustomerMapper;
import myspring.customer.sevice.CustomerService;
import myspring.customer.vo.CustomerVO;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "classpath:spring-beans-customer.xml")
public class CustomerDBTest {
	@Autowired
	CustomerService customerService;
	
	@Test
	public void service() {
		CustomerVO customer = customerService.getUser("dooly");
		System.out.println(customer);
	}

}

5. Controller

1) web.xml 수정

  • contextLoadListener 추가

    • tomcat 메모리 상에 application context를 로드하는 것
    • param location 태그에 spring-beans-user.xml을 알려줘야함
  • dispatcherservlet 추가

    • servlet의 param location : controller 쪽에만 적용되는 xml 파일 있을 경우 적용
  • src/main/webapp/WEB-INF의 web.xml 수정

// 하단에 코드 추가 

 <!-- needed for ContextLoaderListener -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-beans-customer.xml</param-value>
	</context-param>

	<!-- Bootstraps the root web application context before servlet initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>springDispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-beans-customer.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>springDispatcherServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

3) 테스트

  • tomcat 구동하고 index.jsp 통해 실행
    index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>customer list</title>
</head>
<body>
	<h1>고객 관리 메인</h1>
	<ul>
		<li><a href="customerList.do">Customer 리스트</a></li>
	</ul>
</body>
</html>

6. CustomerController

1) myspring.customer.controller 패키지 생성

2) customerInfo.jsp 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>고객 상세정보</title>
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
	<div class="container">
	    <h2 class="text-center">고객 상세정보</h2>
		<table class="table table-bordered table table-hover">
			<tr><td>이름 :</td><td>${customer.name}</td></tr>
			<tr><td>이메일 :</td><td>${customer.email}</td></tr>
			<tr><td>나이 :</td><td>${customer.age}</td></tr>
			<tr><td>등록일자 : </td><td>${customer.entryDate}</td></tr>
		</table>
	</div>
</body>
</html>

3) customerList.jsp 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>고객 관리</title>
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>
<body>
	<div class="container">
		<h2 class="text-center">고객 목록</h2>
		<table class="table table-bordered table table-hover"> 
			<thead> 
				<tr> 
					<th>&nbsp;</th>
					<th>이름</th> 
					<th>이메일</th>
					<th>나이</th>
					<th>등록일자</th>
					<th>&nbsp;</th>
				</tr> 
		</thead> 
		<tbody> 
			<c:forEach var="customer" items="${customerList}">
				<tr>
					<td>
					 	<a href="getUser.do?id=${customer.name}">${customer.name}</a>
					 </td>
					<td>${customer.name}</td>
					<td>${customer.email}</td>
					<td>${customer.age}</td>
					<td>${customer.entryDate}</td>
					
				</tr>
			</c:forEach>
		</tbody> 
	</table>
	</div>
</body>
</html>

4) CustomerController 클래스 생성

CustomerController.java

package myspring.customer.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import myspring.customer.sevice.CustomerService;
import myspring.customer.vo.CustomerVO;

@Controller
public class CustomerController {
	@Autowired
	private CustomerService customerService;
	
	public CustomerController() {
		System.out.println(this.getClass().getName() + "생성자 호출됨");
	}
	
	// db에서 가져오고 화면에 보이는 것도 함께 설정 
	// View와 Model을 한꺼번에 전달하는 방법
	@RequestMapping("/customerList.do")
	public ModelAndView customerList() {
		// service 불러와서 리스트로 받기
		// 뿌려줄 jsp 페이지를 ModelAndView 객체에 담음 (viewName=jsp파일 이름(jsp확장자 없이 이름만 기재), modelName=키값(forEach구문의 items), modelList=서비스에서 받아온 list 기재)
		// key 값(customerList)과 일치하여 list 변수명 바꾸기 
		List<CustomerVO> customerVOList = customerService.getCustomerList();
		// ModelAndView(viewName, keyName, valueObject)
		return new ModelAndView("customerList", "customerList", customerVOList);
	}
	
	//getUser.do?id=dooly
	// View와 Model을 분리해서 전달하는 방법
	@RequestMapping("/getUser.do")
	public String getUser(@RequestParam("id") String userId, Model model) {
		// @requestparam을 이용하여 ?(쿼리 스트링) 다음의 id 값 가져올 수 있음
		// 받아온 customerVO를 model에 담아줌
		CustomerVO userVO = customerService.getUser(userId);
		model.addAttribute("customer", userVO);
		// 페이지 이름 return 
		return "customerInfo";
	}
	
}

5) beans-web.xml 생성

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
	
	<context:component-scan base-package="myspring.customer">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>

	<!-- Spring MVC에 필요한 Bean들을 자동으로 등록해주는 태그-->
	<mvc:annotation-driven />
	
	<!-- DispatcherServlet의  변경된 url-pattern 때문에 필요한 태그 설정 -->	
	<mvc:default-servlet-handler/>
	
	<!-- 아래 주석은 Controller에서  포워딩 되는  .jsp 확장자를  생략할 수 있다. -->
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/" />
		<property name="suffix" value=".jsp" />
	</bean>


	<!-- annotation-driven  태그에서 내부적으로 처리해주는 설정 -->
	<!-- <bean id="jsonHttpMessageConverter"  -->
	<!--         class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /> -->
	<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> -->
	<!-- 	<property name="messageConverters"> -->
	<!-- 	  <list> -->
	<!-- 		<ref bean="jsonHttpMessageConverter"/> -->
	<!-- 	  </list> -->
	<!-- 	</property> -->
	<!-- </bean> -->

</beans>

6) web.xml 수정

// 하단에 추가 
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>springDispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:beans-web.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

7) 테스트



📒 Servlet/JSP/JDBC

📕 (MyDynamicWe)

1. jdbc

1) DBConn.java

package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DBConn {

	public static void main(String[] args) {
		final String driver = "org.mariadb.jdbc.Driver";
		final String DB_IP = "localhost";
		final String DB_PORT = "3306";
		final String DB_NAME = "boot_db";
		final String DB_URL = 
				"jdbc:mariadb://" + DB_IP + ":" + DB_PORT + "/" + DB_NAME;

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		try {
			// 1. Driver class Loading
			Class.forName(driver);
			System.out.println("DB_URL = " + DB_URL);
			// 2. DB와 연결을 담당하는 Connection 객체 생성 
			conn = DriverManager.getConnection(DB_URL, "boot", "boot");
			System.out.println("Connection className = " + conn.getClass().getName()); 
			// Connection className = org.mariadb.jdbc.MariaDbConnection
			if (conn != null) {
				System.out.println("DB 접속 성공");
			}

		} catch (ClassNotFoundException e) { // class 예외 처리
			System.out.println("드라이버 로드 실패");
			e.printStackTrace();
		} catch (SQLException e) { // getConnection 예외 처리 
			System.out.println("DB 접속 실패");
			e.printStackTrace();
		}

		try {
			String sql = "select * from users where userId = ?";

			// 3. SQL문을 DB에게 전달해주는 역할을 하는 Statement 생성 
			pstmt = conn.prepareStatement(sql);
			System.out.println("Statement Class Name = " + pstmt.getClass().getName());
			// Statement Class Name = org.mariadb.jdbc.ClientSidePreparedStatement
			pstmt.setString(1, "dooly"); // parameter index 1부터 시작, preapareStatement의 set변수타입 설정
			
			// 4. SQL문 실행결과를 담는 역할을 하는 ResultSet 생성
			rs = pstmt.executeQuery();
			System.out.println("ResultSet Class Name = " + rs.getClass().getName());
			// ResultSet Class Name = org.mariadb.jdbc.internal.com.read.resultset.SelectResultSet
			
			String userId = null;
			String name = null;
			String gender = null;
			String city = null;
            
			while (rs.next()) { // 메모리의 ResultSet 접근 (다 읽으면 true -> false 출력 )
				userId = rs.getString("userId"); // 컬럼명 변경 (컬럼 index도 가능) 
				name = rs.getString("name"); 	// getString : 해당 컬럼의 값 가져오기 
				gender = rs.getString("gender");
				city = rs.getString("city");
				
				System.out.print(userId);
				System.out.print(name);
				System.out.print(gender);
				System.out.print(city);
				System.out.println();
			}
			
		} catch (SQLException e) {
			System.out.println("error: " + e);
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}
				if (pstmt != null) {
					pstmt.close();
				}

				if (conn != null && !conn.isClosed()) {
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

	}
}

2. vo

1) UserVO.java

package vo;

public class UserVO {
	private int id;
	private String UserId;
	private String name;
	private String gender;
	private String city;
	
	public UserVO() { // 기본 생성자
		
	}
	public UserVO(int id, String userId, String name, String gender, String city) { // argument 인자 받는 생성자 
		super();
		this.id = id;
		UserId = userId;
		this.name = name;
		this.gender = gender;
		this.city = city;
	}
	public int getId() {
		return id;
	}
	public String getUserId() {
		return UserId;
	}
	public String getName() {
		return name;
	}
	public String getGender() {
		return gender;
	}
	public String getCity() {
		return city;
	}
	@Override
	public String toString() {
		return "UserVO [id=" + id + ", UserId=" + UserId + ", name=" + name + ", gender=" + gender + ", city=" + city
				+ "]";
	}
	
	
}

3. dao

1) UserDAO.java

package dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import vo.UserVO;

public class UserDAO {
	private Connection connection;
	
	public UserDAO(String driverClass, String url, String username, String password) {		
		// 1. Driver class Loading (1번만 실행 필요)
		try {
			Class.forName(driverClass);
			
			// 2. DB와 연결을 담당하는 Connection 객체 생성 
			connection = DriverManager.getConnection(url, username, password);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void connectionClose() { // // connection은 close 필요 
		try {
			if (connection != null) connection.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	// where 조건 조회 
	public UserVO getUser(String userId) {
		PreparedStatement pStmt = null;
		UserVO userVO = null;
		
		String sql = "select * from users where userid = ?";
		
		// 3. SQL문을 DB에게 전달해주는 역할을 하는 Statement 생성 
		try {
			pStmt = connection.prepareStatement(sql);
			pStmt.setString(1,  userId);
			
			ResultSet rs = pStmt.executeQuery();
			if (rs.next()) {
				userVO = new UserVO(rs.getInt("id"), 
								rs.getString("userId"), 
								rs.getString("name"), 
								rs.getString("gender"),
								rs.getString("city"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (pStmt != null) pStmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return userVO;
	}
	
	// 목록 조회 
	public List<UserVO> getUserList() {
		PreparedStatement pStmt = null;
		List<UserVO> userList = new ArrayList<>();
		
		String sql = "select * from users order by id";

		try {
			pStmt = connection.prepareStatement(sql);
			
			ResultSet rs = pStmt.executeQuery();
			while (rs.next()) {
				UserVO userVO = new UserVO(rs.getInt("id"), 
								rs.getString("userId"), 
								rs.getString("name"), 
								rs.getString("gender"),
								rs.getString("city"));
				userList.add(userVO);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (pStmt != null) pStmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return userList;
	}
}

4. controller

1) UserListServlet.java

package controller;

import java.io.IOException;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import dao.UserDAO;
import vo.UserVO;

/**
 * Servlet implementation class UserListServlet
 */
// @WebServlet("/userList")
public class UserListServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	UserDAO userDao;
    /**
     * @see HttpServlet#HttpServlet()
     */
    public UserListServlet() {
        super();
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
    	System.out.println(">> init");
    	String driver = config.getInitParameter("driverClass"); // org.mariadb.jdbc.Driver (web.xml의 param.value)
    	String url = config.getInitParameter("dbUrl");
    	String username = config.getInitParameter("dbUsername");
    	String password = config.getInitParameter("dbPassword");
    	System.out.println(driver);
    	System.out.println(url);
    	System.out.println(username);
    	System.out.println(password);
    	
    	userDao = new UserDAO(driver, url, username, password);
    }
    
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println(">> doGet");
		// response(응답) 데이터를 utf-8로 인코딩
		response.setContentType("text/html; charset=UTF-8");
		// response.getWriter() : 응답에 대한 string 생성 
		response.getWriter().append("Served at: ").append(request.getContextPath());
		
		// UserDAO를 호출해서 DB 데이터를 가져오기
		List<UserVO> userList = userDao.getUserList();
		
		// Request 객체에 userList를 저장하기
		request.setAttribute("users", userList); // key : users, value : userList
		// RequestDispatcher 생성하기
		RequestDispatcher dispatcher = request.getRequestDispatcher("userList.jsp"); //userList.jsp 포워딩 필요
		// userList.jsp 페이지로 포워딩하기
		dispatcher.forward(request, response); // 전달 받은 인자값 그대로 forward
	}
	
	@Override
	public void destroy() {
		System.out.println(">> destroy");
		super.destroy();
	}

}

5. WEB-INF/lib

1) web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">
	<display-name>MyDynamicWe</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	
	<servlet>
		<servlet-name>UserListServlet</servlet-name>
		<servlet-class>controller.UserListServlet</servlet-class>
		<init-param>
			<param-name>driverClass</param-name>
			<param-value>org.mariadb.jdbc.Driver</param-value>
		</init-param>
		<init-param>
			<param-name>dbUrl</param-name>
			<param-value>jdbc:mariadb://localhost:3306/boot_db</param-value>
		</init-param>
		<init-param>
			<param-name>dbUsername</param-name>
			<param-value>boot</param-value>
		</init-param>
		<init-param>
			<param-name>dbPassword</param-name>
			<param-value>boot</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>UserListServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>

2) index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Main Page</title>
</head>
<body>
	<h1>사용자 관리</h1>
	<ul>
		<li><a href="userList.do" >사용자 목록</a></li>
	</ul>
</body>
</html>

3) userList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>사용자 리스트</h2>
	<%-- ${users} --%>
	<table border="1">
		<tr>
			<th>ID</th>
			<th>UserId</th>
			<th>Name</th>
			<th>Gender</th>
			<th>City</th>
		</tr>
		<c:forEach var="user" items="${users}">
			<%-- user는  UserVO를 의미 --%>
			<tr>
				<td>${user.id}</td>
				<td>${user.userId}</td>
				<td>${user.name}</td>
				<td>${user.gender}</td>
				<td>${user.city}</td>
			</tr>
		</c:forEach>
	</table>
</body>
</html>

📒 Spring Framework

📕

1. xml

1) strategy1.xml

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

	<bean id="userDaoImpl" class="myspring.di.strategy1.dao.UserDaoImpl"></bean>
	<bean id="userServiceImpl" class="myspring.di.strategy1.service.UserServiceImpl">
		<property name="userdao" ref="userDaoImpl"></property>
	</bean>

</beans>

2) UserServiceTest.java

package myspring.di.strategy1;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

import myspring.di.strategy1.dao.UserDao;
import myspring.di.strategy1.service.UserService;


public class UserServiceTest {

	BeanFactory factory;
	
	@BeforeEach
	void conn() {
		factory = new GenericXmlApplicationContext("classpath:service-beans-strategy1.xml");
	}
	
	@Test
	public void serviceTest() {
		UserDao userDao = factory.getBean("userDaoImpl",UserDao.class);
		UserService userService = factory.getBean("userServiceImpl",UserService.class);
		
		assertEquals(2, userService.getUserList().size());
	}
}

3) UserXmlTest.java

package myspring.di.strategy1;

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

import myspring.di.strategy1.dao.UserDao;
import myspring.di.strategy1.service.UserService;

public class UserXmlTest {

	@Test
	void user() {
		BeanFactory factory = new GenericXmlApplicationContext("classpath:spring-bean-configuration.xml");
		UserService service = factory.getBean("userService", UserService.class);
		
		System.out.println("get User List = " + service.getUserList());
		assertEquals("dooly", service.getUser(1).getUserId());
		
		UserDao dao = factory.getBean("userDao", UserDao.class);
		
		System.out.println("read All = " + dao.readAll());
		assertEquals("dooly", dao.read(1).getUserId());
	}
}

2. xml + annotation

1) strategy2.xml

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

		<context:component-scan base-package="myspring.di.strategy2"></context:component-scan>
</beans>

2) UserServiceTest.java

package myspring.di.strategy2;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import myspring.di.strategy2.service.UserService;
import myspring.di.strategy2.dao.UserDao;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "file:src/main/resources/service-beans-strategy2.xml")
public class UserServiceTest {

	@Autowired
	UserService userService;
	
	@Autowired
	UserDao userDao;
	
	@Test
	public void serviceTest() {
		assertEquals(2, userService.getUserList().size());
	}
	
}

3) UserXmlTest.java

package myspring.di.strategy2;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import myspring.di.strategy2.dao.UserDao;
import myspring.di.strategy2.service.UserService;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "classpath:spring-bean-configuration2.xml")
public class UserXmlTest {
	@Autowired
	@Qualifier("userService")
	UserService service;
	
	@Autowired
	@Qualifier("userDao")
	UserDao dao;
	
	@Test
	void user() {
		System.out.println("get User List = " + service.getUserList());
		assertEquals("dooly", service.getUser(1).getUserId());
		
		System.out.println("read All = " + dao.readAll());
		assertEquals("dooly", dao.read(1).getUserId());
	}
}

3. configuration + annotation

1) configuration.xml

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

	<bean id="userDao" class="myspring.di.strategy1.dao.UserDaoImpl" />
	<bean id="userService" class="myspring.di.strategy1.service.UserServiceImpl" >
		<!-- property는 setter -->
		<property name="userDao" ref="userDao"/>
	</bean>
	
</beans>

2) configuration2.xml

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

	<bean id="userDao" class="myspring.di.strategy1.dao.UserDaoImpl" />
	<bean id="userService" class="myspring.di.strategy1.service.UserServiceImpl" >
		<!-- property는 setter -->
		<property name="userDao" ref="userDao"/>
	</bean>
	
</beans>

3) starategy3

  • SpringBeanConfiguration.java
package myspring.di.strategy3;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"myspring.di.strategy3"})
public class SpringBeanConfiguration {

}

4) strategy3/config

  • ServiceBeanConfig.java
package myspring.di.strategy3.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import myspring.di.strategy1.dao.UserDao;
import myspring.di.strategy1.dao.UserDaoImpl;
import myspring.di.strategy1.service.UserService;
import myspring.di.strategy1.service.UserServiceImpl;

@Configuration
public class ServiceBeanConfig {

	@Bean
	UserDao userDao() {
		return new UserDaoImpl();
	}
	
	@Bean
	UserService userService() {
		UserServiceImpl userService = new UserServiceImpl();
		userService.setUserdao(userDao());
		return userService;
	}
}
  • ServiceConfig.java
package myspring.di.strategy3.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"myspring.di.strategy2"})
public class ServiceConfig {
	
}

5) UserServiceTest.java

package myspring.di.strategy3;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import myspring.di.strategy2.service.UserService;
import myspring.di.strategy2.dao.UserDao;
import myspring.di.strategy3.config.ServiceConfig;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ServiceConfig.class)
public class UserServiceTest {

	@Autowired
	UserService userService;
	
	@Autowired
	UserDao userDao;
	
	@Test
	public void serviceTest() {
		assertEquals(2, userService.getUserList().size());
	}
	
}

6) UserXmlTest.java

package myspring.di.strategy3;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

import myspring.di.strategy3.dao.UserDao;
import myspring.di.strategy3.service.UserService;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = SpringBeanConfiguration.class, loader = AnnotationConfigContextLoader.class)
public class UserXmlTest {
	@Autowired
	UserService service;
	
	@Autowired
	UserDao dao;
	
	@Test
	void user() {
		System.out.println("get User List = " + service.getUserList());
		assertEquals("dooly", service.getUser(1).getUserId());
		
		System.out.println("read All = " + dao.readAll());
		assertEquals("dooly", dao.read(1).getUserId());
	}

}

7) UserServiceBeanTest.java

package myspring.di.strategy3;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import myspring.di.strategy1.dao.UserDao;
import myspring.di.strategy1.service.UserService;
import myspring.di.strategy3.config.ServiceBeanConfig;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ServiceBeanConfig.class)
public class UserServiceBeanTest {

	@Autowired
	UserService userService;
	
	@Autowired
	UserDao userDao;
	
	@Test
	public void serviceTest() {
		assertEquals(2, userService.getUserList().size());
	}
	
}

공통. dao

1) UserDao.java

package myspring.di.strategy*.dao;

import java.util.List;

import myspring.user.vo.UserVO;

public interface UserDao {

	public List<UserVO> readAll();

	public UserVO read(int id);

}

2) UserDaoImpl.java

package myspring.di.strategy*.dao;

import java.util.Arrays;
import java.util.List;

import myspring.user.vo.UserVO;

@Component("userDao")
public class UserDaoImpl implements UserDao {
	List<UserVO> userList;
	
	public UserDaoImpl() {
		userList = Arrays.asList(
				new UserVO(1L,"gildong", "홍길동", "남", "마곡"),
				new UserVO(2L,"dooly", "둘리", "남", "마곡나루"));
	}
	
	@Override
	public UserVO read(int index) {
		return userList.get(index);
	}

	@Override
	public List<UserVO> readAll() {		
		return userList;
	}	
}

공통. service

1) UserService.java

package myspring.di.strategy*.service;

import java.util.List;

import myspring.user.vo.UserVO;

public interface UserService {
	
	public List<UserVO> getUserList();

	public UserVO getUser(int index);
	
}

2) UserServiceImpl.java

package myspring.di.strategy*.service;

import java.util.List;

import myspring.di.strategy1.dao.UserDao;
import myspring.user.vo.UserVO;

@Component("userService")
public class UserServiceImpl implements UserService {

	UserDao userdao;	
	
	public void setUserdao(UserDao userdao) {
		this.userdao = userdao;
	}

	public List<UserVO> getUserList() {
		return userdao.readAll();
	}

	@Override
	public UserVO getUser(int index) {
		return userdao.read(index);
	}

}

📕 MySpringCustomer

1. resources

1) spring-beans-customer.xml

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

	<!-- Properties file 정보 설정 -->
	<context:property-placeholder location="classpath:value.properties"/>
	
	<!-- DataSource 구현체인 HikariDataSource를 SpringBean으로 등록 -->
	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" 
		p:driverClassName="${db.driverClass}"
		p:jdbcUrl="${db.url}"
		p:username="${db.username}"
		p:password="${db.password}"
	/>
	
	<!-- Mybatis-spring의 SqlSessionFactoryBean을 SpringBean으로 등록 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
		<property name="mapperLocations">
			<list>
				<value>classpath:mybatis/*Mapper.xml</value>
			</list>
		</property>
	</bean>
	
	<!-- SqlSession으로 sql 실행  -->
	<!-- SqlSessionFactory를 통해 취득한 SqlSession을 실행중인 트랜잭션에 할당함 -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg ref="sqlSessionFactory"/>
	</bean>
	
	<!-- Mybatis-Spring의 MapperScannerConfigurer을 SpringBean으로 등록 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<!-- 참조하는 것 없어서 bean id 없어도 됨 -->
		<property name="basePackage" value="myspring.customer.dao.mapper" />
		<property name="sqlSessionTemplateBeanName" value="sqlSession"/>
	</bean>
	
	<!-- DAO, Service에 해당하는 Bean을 Scanning -->
	<context:component-scan base-package="myspring.customer" >
		<!-- 하단의  myspring.customer에서 controller만 제외하고 scan -->
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
</beans>

2) value.properties

db.driverClass=org.mariadb.jdbc.Driver
db.url=jdbc:mariadb://127.0.0.1:3306/boot_db?useUnicode=true&charaterEncoding=utf-8&useSSL=false&serverTimezone=UTC
db.username=boot
db.password=boot

myname=Spring
myprinter=printer
value1=JUnit
value2=AOP
value3=DI
printer1=stringPrinter
printer2=consolePrinter

3) log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
	<Appenders>
		<File name="File" fileName="./logs/logfile.log" append="true">
			<PatternLayout
				pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-5level %logger{36} - %msg%n" />
		</File>
		<Console name="console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
	</Appenders>

	<Loggers>
		<Logger name="org.springframework" level="INFO" additivity="false" />
			
		<Logger name="myspring" level="DEBUG" />

		<Root level="DEBUG">
			<AppenderRef ref="console" level="DEBUG" />
			<AppenderRef ref="File" level="DEBUG" />
		</Root>
	</Loggers>
</Configuration>

4) beans-web.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
	
	<context:component-scan base-package="myspring.customer">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>

	<!-- Spring MVC에 필요한 Bean들을 자동으로 등록해주는 태그-->
	<mvc:annotation-driven />
	
	<!-- DispatcherServlet의  변경된 url-pattern 때문에 필요한 태그 설정 -->	
	<mvc:default-servlet-handler/>
	
	<!-- 아래 주석은 Controller에서  포워딩 되는  .jsp 확장자를  생략할 수 있다. -->
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/" />
		<property name="suffix" value=".jsp" />
	</bean>


	<!-- annotation-driven  태그에서 내부적으로 처리해주는 설정 -->
	<!-- <bean id="jsonHttpMessageConverter"  -->
	<!--         class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /> -->
	<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> -->
	<!-- 	<property name="messageConverters"> -->
	<!-- 	  <list> -->
	<!-- 		<ref bean="jsonHttpMessageConverter"/> -->
	<!-- 	  </list> -->
	<!-- 	</property> -->
	<!-- </bean> -->

</beans>

5) mybatis/CustomerMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="myspring.customer.dao.mapper.CustomerMapper">
	<!-- 조회 쿼리는 id를 이용하여 실행 -->
	<!-- parameter에 들어가는 값이 {value} 변수로 들어옴  -->
	<select id="selectCustomerById" parameterType="string" resultType="Customer"> 
		select * from customer where name=#{value}
	</select>

	<select id="selectCustomerList" resultType="Customer">
		select * from customer order by id
	</select>
	
</mapper>

6) mybatis/SqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
	"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<!-- log4j2 설정 -->
	<settings>
         <setting name="defaultStatementTimeout" value="3"/> 
         <setting name="logImpl" value="LOG4J2"/>
    </settings>
    
	<typeAliases>
		<!-- CustomerVO 설정  -->
		<typeAlias alias="Customer" type="myspring.customer.vo.CustomerVO" />
	</typeAliases>

</configuration>

2. vo

1) CustomerVO.java

package myspring.customer.vo;

public class CustomerVO {
	
	private Long id;
	private String name;
	private String email;
	private int age;
	private String entryDate;

	// 기본생성자 
	public CustomerVO() {}
	
	public CustomerVO(String name, String email, int age, String entryDate) {
		this.name = name;
		this.email = email;
		this.age = age;
		this.entryDate = entryDate;
	}
	public CustomerVO(Long id, String name, String email, int age, String entryDate) {
		this(name, email, age, entryDate);
		this.id = id;
	}

	// getter와 setter 생성
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	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;
	}

	public String getEntryDate() {
		return entryDate;
	}

	public void setEntryDate(String entryDate) {
		this.entryDate = entryDate;
	}

	// toString 생성
	@Override
	public String toString() {
		return "CustomerVO [id=" + id + ", name=" + name + ", email=" + email + ", age=" + age + ", entryDate="
				+ entryDate + "]";
	}
}

3. dao

1) CustomerDao.java

package myspring.customer.dao;

import java.util.List;

import myspring.customer.vo.CustomerVO;

public interface CustomerDao {
	public List<CustomerVO> readAll();
	public CustomerVO read(String id);
}

2) CustomerDaoImpl.java

package myspring.customer.dao;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import myspring.customer.dao.mapper.CustomerMapper;
import myspring.customer.vo.CustomerVO;

@Repository("customerDao")
public class CustomerDaoImpl implements CustomerDao {
	@Autowired
	private CustomerMapper customerMapper;	
	
	@Override
	public CustomerVO read(String id) {
		CustomerVO user  = customerMapper.selectCustomerById(id);
		return user;
	}
	
	public List<CustomerVO> readAll() {
		List<CustomerVO> userList = customerMapper.selectCustomerList();
		return userList;
	}
}

4. dao/mapper

1) CustomerMapper.java

package myspring.customer.dao.mapper;

import java.util.List;

import myspring.customer.vo.CustomerVO;

public interface CustomerMapper {
	CustomerVO selectCustomerById(String id);
	List<CustomerVO> selectCustomerList();
}

5. service

1) CustomerService.java

package myspring.customer.sevice;

import java.util.List;

import myspring.customer.vo.CustomerVO;

public interface CustomerService {
	public List<CustomerVO> getCustomerList();
	public CustomerVO getUser(String id);
}

2) CustomerServiceImpl.java

package myspring.customer.sevice;

import java.util.List;

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

import myspring.customer.dao.CustomerDao;
import myspring.customer.vo.CustomerVO;

@Service("customerService")
public class CustomerServiceImpl implements CustomerService {

	@Autowired
	CustomerDao customerdao;

	public List<CustomerVO> getCustomerList() {
		return customerdao.readAll();
	}

	@Override
	public CustomerVO getUser(String id) {
		return customerdao.read(id);
	}

}

6. controller

1) CustomerController.java

package myspring.customer.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import myspring.customer.sevice.CustomerService;
import myspring.customer.vo.CustomerVO;

@Controller
public class CustomerController {
	@Autowired
	private CustomerService customerService;
	
	public CustomerController() {
		System.out.println(this.getClass().getName() + "생성자 호출됨");
	}
	
	// db에서 가져오고 화면에 보이는 것도 함께 설정 
	// View와 Model을 한꺼번에 전달하는 방법
	@RequestMapping("/customerList.do")
	public ModelAndView customerList() {
		// service 불러와서 리스트로 받기
		// 뿌려줄 jsp 페이지를 ModelAndView 객체에 담음 (viewName=jsp파일 이름(jsp확장자 없이 이름만 기재), modelName=키값(forEach구문의 items), modelList=서비스에서 받아온 list 기재)
		// key 값(customerList)과 일치하여 list 변수명 바꾸기 
		List<CustomerVO> customerVOList = customerService.getCustomerList();
		// ModelAndView(viewName, keyName, valueObject)
		return new ModelAndView("customerList", "customerList", customerVOList);
	}
	
	//getUser.do?id=dooly
	// View와 Model을 분리해서 전달하는 방법
	@RequestMapping("/getUser.do")
	public String getUser(@RequestParam("id") String userId, Model model) {
		// @requestparam을 이용하여 ?(쿼리 스트링) 다음의 id 값 가져올 수 있음
		// 받아온 customerVO를 model에 담아줌
		CustomerVO userVO = customerService.getUser(userId);
		model.addAttribute("customer", userVO);
		// 페이지 이름 return 
		return "customerInfo";
	}
	
}

7. webapp

1) web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
	id="WebApp_ID" version="3.1">
  <display-name>CustomerSpringWeb</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <!-- needed for ContextLoaderListener -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-beans-customer.xml</param-value>
	</context-param>

	<!-- Bootstraps the root web application context before servlet initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>springDispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:beans-web.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>springDispatcherServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
  
</web-app>

2) index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>customer list</title>
</head>
<body>
	<h1>고객 관리 메인</h1>
	<ul>
		<li><a href="customerList.do">고객 리스트</a></li>
	</ul>
</body>
</html>

3) customerList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>고객 관리</title>
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>
<body>
	<div class="container">
		<h2 class="text-center">고객 목록</h2>
		<table class="table table-bordered table table-hover"> 
			<thead> 
				<tr> 
					<th>&nbsp;</th>
					<th>이름</th> 
					<th>이메일</th>
					<th>나이</th>
					<th>등록일자</th>
					<th>&nbsp;</th>
				</tr> 
		</thead> 
		<tbody> 
			<c:forEach var="customer" items="${customerList}">
				<tr>
					<td>
					 	<a href="getUser.do?id=${customer.name}">${customer.name}</a>
					 </td>
					<td>${customer.name}</td>
					<td>${customer.email}</td>
					<td>${customer.age}</td>
					<td>${customer.entryDate}</td>
					
				</tr>
			</c:forEach>
		</tbody> 
	</table>
	</div>
</body>
</html>

4) customerInfo.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>고객 상세정보</title>
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
	<div class="container">
	    <h2 class="text-center">고객 상세정보</h2>
		<table class="table table-bordered table table-hover">
			<tr><td>이름 :</td><td>${customer.name}</td></tr>
			<tr><td>이메일 :</td><td>${customer.email}</td></tr>
			<tr><td>나이 :</td><td>${customer.age}</td></tr>
			<tr><td>등록일자 : </td><td>${customer.entryDate}</td></tr>
		</table>
	</div>
</body>
</html>

📒 Spring Boot

📕 Controller ➡️ Repository

1. repository

1) CustomerRepository

package com.mission.mymission.repository;

import com.mission.mymission.entity.Customer;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface CustomerRepository extends JpaRepository<Customer, Long> {
    // < Entity 클래스, PK값 >
    // Insert, Delete, Select만 존재

    // select * from account where username = 'spring'
    Optional<Customer> findByEmail(String email);
    List<Customer> findByName(String name);
}

2. entity

1) Customer

package com.mission.mymission.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;

import java.time.LocalDateTime;

@Entity
@Table(name = "customer")
@Getter @Setter
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String email;

    private int age;

    @Column(updatable = false)
    @CreationTimestamp
    private LocalDateTime entryDate = LocalDateTime.now();
}

3. controller

1) CustomerRestController

package com.mission.mymission.controller;

import com.mission.mymission.entity.Customer;
import com.mission.mymission.exception.BusinessException;
import com.mission.mymission.repository.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/customer")
public class CustomerController {
    @Autowired
    private CustomerRepository customerRepository;

    @PostMapping
    public Customer create(@RequestBody Customer customer) {
        return customerRepository.save(customer);
    }

    @GetMapping
    public List<Customer> getCustomers() {
        return customerRepository.findAll();
    }

    @GetMapping("/{id}")
    public Customer getCustomer(@PathVariable Long id) {
        Optional<Customer> optionalCustomer = customerRepository.findById(id);

        Customer customer = optionalCustomer.orElseThrow(() -> new BusinessException("Customer Not Found", HttpStatus.NOT_FOUND));
        return customer;
    }

    @GetMapping("/email/{email}")
    public Customer getCustomerByEmail(@PathVariable String email) {
        return customerRepository.findByEmail(email)
                .orElseThrow(() -> new BusinessException("Email이 존재하지 않습니다", HttpStatus.NOT_FOUND));
    }

    @GetMapping("/name/{name}")
    public List<Customer> getCustomerByName(@PathVariable String name) {
        return customerRepository.findByName(name);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteUser(@PathVariable Long id) {
       Customer customer = customerRepository.findById(id)
                .orElseThrow(() -> new BusinessException("Customer Not Found", HttpStatus.NOT_FOUND));
        customerRepository.delete(customer);
        return ResponseEntity.ok(id + " User가 삭제 되었습니다");
    }
}

4. resource

1) application-properties

# 서버 포트 설정
#server.port=8087

# 스프링 유니코드 작성
# (applcation-prod/test.properties에서 설정)
myboot.name=\uc2a4\ud504\ub9c1 
myboot.fullName=${myboot.name} Boot

spring.datasource.url=jdbc:mariadb://127.0.0.1:3306/boot_db
spring.datasource.username=boot
spring.datasource.password=boot
spring.datasource.driverClassName=org.mariadb.jdbc.Driver

# JPA를 사용한 데이터베이스 초기화
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
# DB Dialect 설정
spring.jpa.database-platform=org.hibernate.dialect.MariaDBDialect

5. MyMissionApplication

package com.mission.mymission;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyMissionApplication {

	public static void main(String[] args) {

		// SpringApplication.run(MySpringBoot3Application.class, args);
		SpringApplication application = new SpringApplication(MyMissionApplication.class);
		// WebApplication Type을 변경하기 위한 목적
		application.setWebApplicationType(WebApplicationType.SERVLET);
		// None : 더이상 WebApplication이 아님
		application.run(args);
	}

}

6. exception

1) BusinessException

package com.mission.mymission.exception;

import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
public class BusinessException extends RuntimeException {
	
	private static final long serialVersionUID = 1L;
    private String message;
    private HttpStatus httpStatus;

    public BusinessException(String message) {
        //417
        this(message, HttpStatus.EXPECTATION_FAILED);
    }

    public BusinessException(String message, HttpStatus httpStatus) {
        this.message = message;
        this.httpStatus = httpStatus;
    }
}

2) SystemException

package com.mission.mymission.exception;

import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
public class SystemException extends RuntimeException {
	private static final long serialVersionUID = 1L;
	private String message;
    private HttpStatus httpStatus;
    private Throwable throwable; 

    public SystemException(Exception e) {
        this(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    public SystemException(String message) {
        this(message, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    public SystemException(String message, Throwable t) {
    	this.message = message;
    	this.throwable =t;
    }
    
    public SystemException(Throwable t) {
    	this.throwable = t;
    }
    
    public SystemException(String message, HttpStatus httpStatus) {
        this.message = message;
        this.httpStatus = httpStatus;
    }
    
    public Throwable getThrowable() {
    	return this.throwable;
    }
}

7. advice

1) DefaultExceptionAdvice

package com.mission.mymission.advice;

import com.mission.mymission.exception.BusinessException;
import com.mission.mymission.exception.SystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class DefaultExceptionAdvice {
	private final Logger LOGGER = LoggerFactory.getLogger(DefaultExceptionAdvice.class);


    @ExceptionHandler(BusinessException.class)
    protected ResponseEntity<Object> handleException(BusinessException e) {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("message", "[안내] " + e.getMessage());
        result.put("httpStatus", e.getHttpStatus().value());

        return new ResponseEntity<>(result, e.getHttpStatus());
    }
    
    @ExceptionHandler(SystemException.class)
    protected ResponseEntity<Object> handleException(SystemException e) {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("message", "[시스템 오류] " + e.getMessage());
        result.put("httpStatus", e.getHttpStatus().value());

        return new ResponseEntity<>(result, e.getHttpStatus());
    }

    //숫자타입의 값에 문자열타입의 값을 입력으로 받았을때 발생하는 오류
    @ExceptionHandler(HttpMessageNotReadableException.class)
    protected ResponseEntity<Object> handleException(HttpMessageNotReadableException e) {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("message", e.getMessage());
        result.put("httpStatus", HttpStatus.BAD_REQUEST.value());

        return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(Exception.class)
    protected ResponseEntity<Object> handleException(Exception e) {
        Map<String, Object> result = new HashMap<String, Object>();
        ResponseEntity<Object> ret = null;
        
        if (e instanceof BusinessException) {
        	BusinessException b = (BusinessException) e;
        	result.put("message", "[안내]\n" + e.getMessage());
        	result.put("httpStatus", b.getHttpStatus().value());
        } else if ( e instanceof SystemException) {
    		SystemException s = (SystemException)e;
            result.put("message", "[시스템 오류]\n" + s.getMessage());
            result.put("httpStatus", s.getHttpStatus().value());
            ret = new ResponseEntity<>(result, s.getHttpStatus());
            
            LOGGER.error(s.getMessage(), s);
    	 } else {
    		String msg = "예상치 못한 문제가 발생했습니다.\n관리자에게 연락 하시기 바랍니다.";
	        result.put("message", msg);
	        result.put("httpStatus", HttpStatus.INTERNAL_SERVER_ERROR.value());
	        ret = new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
	        e.printStackTrace();
	        
            LOGGER.error(e.getMessage(), e);
    	}
        return ret;
    }
}
profile
Notion으로 이동 (https://24tngus.notion.site/3a6883f0f47041fe8045ef330a147da3?v=973a0b5ec78a4462bac8010e3b4cd5c0&pvs=4)

0개의 댓글