@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>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
<!-- scope : test라고 이름 지어진 폴더에만 적용 -->
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.1.4</version>
</dependency>
<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>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<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>
<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" ?>
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" ?>
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" ?>
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"%>
http://www.w3.org/TR/html4/loose.dtd">
고객 상세정보
이름 : | ${customer.name} |
이메일 : | ${customer.email} |
나이 : | ${customer.age} |
등록일자 : | ${customer.entryDate} |
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"%>
고객 목록
이름 | 이메일 | 나이 | 등록일자 | ||
---|---|---|---|---|---|
${customer.name} | ${customer.name} | ${customer.email} | ${customer.age} | ${customer.entryDate} |
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" %>
사용자 리스트
<%-- ${users} --%>
<%-- user는 UserVO를 의미 --%>
ID | UserId | Name | Gender | City |
---|---|---|---|---|
${user.id} | ${user.userId} | ${user.name} | ${user.gender} | ${user.city} |
📒 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" ?>
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" ?>
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"%>
고객 목록
이름 | 이메일 | 나이 | 등록일자 | ||
---|---|---|---|---|---|
${customer.name} | ${customer.name} | ${customer.email} | ${customer.age} | ${customer.entryDate} |
4) customerInfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
http://www.w3.org/TR/html4/loose.dtd">
고객 상세정보
이름 : | ${customer.name} |
이메일 : | ${customer.email} |
나이 : | ${customer.age} |
등록일자 : | ${customer.entryDate} |
📒 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;
}
}
'프로젝트 > U-CAMP' 카테고리의 다른 글
BE - 수업 실습 (0) | 2025.04.10 |
---|---|
톰캣, DB 환경설정 (0) | 2025.04.10 |
BE - 시험 (0) | 2025.04.10 |
SQL 문제 (0) | 2025.04.10 |
VeganRoadMap (0) | 2023.11.03 |