[Framework] TIL 053 - 23.09.27

유진·2023년 9월 27일
0

07_Framework

servlet-context.xml

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

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 접두사 -->
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<!-- 접미사 -->
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	
	<!-- 
		base-package 이하에 작성된 @Component 와
		자식 어노테이션 @Controller, @Service, @Repository 이 붙어있는
		클래스를 찾아서 Bean으로 등록
	 -->
	<context:component-scan base-package="edu.kh.project" />
	
	
	
</beans:beans>

MemberController.java

package edu.kh.project.member.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import edu.kh.project.member.model.dto.Member;
import edu.kh.project.member.model.service.MemberService;

@Controller // 요청/응답 클래스 + bean 등록(Spring 관리하는 객체)
@RequestMapping("/member") // 공통된 주소 앞부분 작성, member로 시작하는 요청은 해당 컨트롤러에서 처리
public class MemberController {
	
	// 등록된 Bean 중에서 필드와 타입이 일치하는 Bean 주입
	// -> MemberService를 구현한 MemberServiceImpl의 Bean 주입
	@Autowired
	private MemberService service;
	
	

	// 로그인 : /member/login
	// 로그아웃 : /member/logout
	
	// /member/login, post 처리방식
	
	
	// @RequestMapping : 요청 주소에 맞는 클래스/메서드 연결
	// @RequestMapping("요청주소") : -> GET / POST 구분 X , 주소만 맞으면 연결하지만 GET요청시 사용
	// @RequestMapping(value="/login", method=RequestMethod.GET/POST) -> GET/POST 방식을 구분
	
    // @RequestMapping(value="/login", method=RequestMethod.POST)
	public String login(HttpServletRequest req) {
		
		// 파라미터 전달 방법 1 : HttpServletRequest를 이용하는 방법
		// -> Controller 메서드에 매개변수로 HttpServletRequest를 작성
		
		// 매개변수에 적으면 사용 가능한 이유
		// Spring 제공하는 Argument Resolver(매개변수해결사)가 자동으로
		// 대입해주고 해결해줌.
		
		String inputEmail = req.getParameter("inputEmail");
		String inputPw = req.getParameter("inputPw");
		
		System.out.println("inputEmail : " + inputEmail);
		System.out.println("inputPw : " + inputPw);
		
		
		// ******************* redirect 방법! *******************
		// "redirect:요청주소"
		
		return "redirect:/";
	}
	
	
	// @PostMapping : @RequestMapping 자식으로
	//				Post 방식 요청을 연결하는 어노테이션
	//@PostMapping("/login")
	public String login(/*@RequestParam("inputEmail")*/ String inputEmail,
						/*@RequestParam("inputPw")*/ String inputPw/*,
						@RequestParam(value="saveId", required="fasle", defaultValue="1")*/) {
		
		// 파라미터 전달 방법 2 : @RequestParam 어노테이션 이용(+생략방법)
		
		// @RequestParam 어노테이션
		// - request 객체를 이용한 파라미터 전달 어노테이션
		// - 매개변수 앞에 해당 어노테이션 작성하면, 매개변수에 값이 주입됨.
		
		// ** 파라미터의 name 속성값과
		//	매개변수명이 같으면 @RequestParam 생략 가능! **
		
		
		// @RequestParam(value="name", required="fasle", defaultValue="1")
		// [속성]
		// value : 전달 받은 input 태그의 name 속성값
		
		// required : 입력된 name 속성값 파라미터 필수 여부 지정(기본값 true)
		// -> required = true인 파라미터가 존재하지 않는다면 400 Bad Request 에러 발생
		// -> required = true인 파라미터가 null인 경우에도 400 Bad Request

		// defaultValue : 파라미터 중 일치하는 name 속성 값이 없을 경우에 대입할 값 지정.
		// -> required = false인 경우 사용
		
		
		System.out.println("inputEmail : " + inputEmail);
		System.out.println("inputPw : " + inputPw);

		
		return "redirect:/";
	}
	
	
	@PostMapping("/login")
	public String login(/*@ModelAttribute*/ Member inputMember) {
		
		// 파라미터 전달 방법 3 : @ModelAttribute 이용한 방법
		
		// - DTO(또는 VO)와 같이 사용하는 어노테이션
		
		// - 전달 받은 파라미터의 name 속성 값이
		//   같이 사용되는 DTO의 필드명과 같다면
		//   자동으로 setter를 호출해서 필드에 값을 세팅
		
		System.out.println(inputMember);
		
		// ** @ModelAttribute 사용 시 주의 사항 **
		// - DTO에 기본 생성자가 필수로 존재해야 한다
		// - DTO에 setter가 필수로 존재해야 한다
		
		// ** ModelAttribute 어노테이션은 생략이 가능하다 ! ** 
		
		// ** @ModelAttribute를 이용해 값이 필드에 세팅된 객체를
		//	커맨드 객체 라고 부른다.
		
		
		// Member [ memberEmail = user123, memberPw = pass123.. ]
		
		
		return "redirect:/";
	}
	
	
	/* 찐 로그인 메서드 */
	
	@PostMapping("/login")
	public String login(Member inputMember, Model model) {
		
		return null;
	}
	
}

MemberService.java

package edu.kh.project.member.model.service;

import edu.kh.project.member.model.dto.Member;

// Service Interface 사용 이유

// 1. 프로젝트에 '규칙성'을 부여하기 위해서 == 모든 클래스가 같은 형태를 띔(협업 위함)

// 2. 클래스간의 결합도를 약화 시키기 위해서 (객체 지향적 설계) == MemberService service = new MemberServiceImpl();
// -> 유지보수성 향상								   MemberService service = new MemberServiceImpl2();
//												   MemberService service = new MemberServiceImpl3();

// 3. Spring AOP 사용을 위해서
// -> AOP는 spring-proxy를 이용해서 동작하는데
//  이 때 Service 인터페이스가 필요하다!

public interface MemberService {
	
	Member login(Member inputMember);

}

MemberServiceImpl.java

package edu.kh.project.member.model.service;

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

import edu.kh.project.member.model.dao.MemberDAO;
import edu.kh.project.member.model.dto.Member;

@Service // 비즈니스 로직(데이터 가공, DAO 호출, 트랜잭션 제어)처리하는 클래스 명시
		// + Bean으로 등록하는 어노테이션
public class MemberServiceImpl implements MemberService{
	
	// @Autowired : 작성된 필드와
	// Bean으로 등록된 객체 중 타입이 일치하는 Bean을
	// 해당 필드에 자동 주입(Injection) 하는 어노테이션.
	// == DI(Dependency Injection, 의존성 주입)
	// -> 객체를 직접 만들지 않고, Spring이 만든걸 주입함(Spring에 의존)
	
	@Autowired
	private MemberDAO dao;

	@Override
	public Member login(Member inputMember) {
		// TODO Auto-generated method stub
		return null;
	}
	
	
}

MemberDAO.java

package edu.kh.project.member.model.dao;

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

@Repository // Persistence Layer, 영속성 관련 클래스 // 영속성 == 영원히 지속되는 성질
			// (DB관련 클래스) + Bean(== Spring 객체화) 등록
public class MemberDAO { // IOC == 제어의 역전
	
	// DAO는 DB랑 연결하기 위한 Connection이 공통적으로 필요하다
	// + Mybatis 영속성 프레임워크를 이용하려면 Connection을 이용해서 만들어진 객체
	// SqlSessionTemplate을 사용
	
	
	@Autowired
	private sqlSessionTemplate sqlSession;

}

Spring환경 Mybatis

  • DAO에서만 관여

  • 반드시 dependencies 태그 안에 넣어야 함!

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 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>edu.kh</groupId>
	<artifactId>project</artifactId>
	<name>boardProject</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	
	<!-- properties : 메이븐이 적용된 프로젝트에서 공통적으로 사용할 값을 작성하는 태그 -->
	<properties>
		<java-version>11</java-version>
		<org.springframework-version>5.3.14</org.springframework-version>
		<org.aspectj-version>1.9.9.1</org.aspectj-version>
		<org.slf4j-version>1.7.25</org.slf4j-version>
	</properties>
	
	<!-- dependencies : Maven 프로젝트는 외부 저장소와 의존 관계를 맺고 있어 프로젝트에 필요한 파일(라이브러리)을
		사용자가 직접 다운 받을 필요 없이, 해당 태그 내에 지정된 형식으로 작성하면 네트워크를 통해 외부 저장소에서 자동으로 얻어와 세팅함
	 -->
	<dependencies>
	
		<!-- lombok 라이브러리 -->
		<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
		<dependency>
		    <groupId>org.projectlombok</groupId>
		    <artifactId>lombok</artifactId>
		    <version>1.18.24</version>
		    <scope>provided</scope>
		</dependency>
		
		<!-- 오라클 JDBC 드라이버 -->
		<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc11 -->
		<dependency>
		    <groupId>com.oracle.database.jdbc</groupId>
		    <artifactId>ojdbc11</artifactId>
		    <version>21.5.0.0</version>
		</dependency>
		
		<!-- 스프링에서 JDBC를 사용할 수 있게하는 라이브러리 -->
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>
		
		<!-- Mybatis 영속성 프레임워크 -->
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis</artifactId>
		    <version>3.5.9</version>
		</dependency>
		
		<!-- Spring - Mybatis 연결 모듈, 연결 역할을 하는 라이브러리 -->
		<!-- 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.commons/commons-dbcp2 -->
		<dependency>
		    <groupId>org.apache.commons</groupId>
		    <artifactId>commons-dbcp2</artifactId>
		    <version>2.9.0</version>
		</dependency>
		
		
		
		
		<!-- Spring 모듈 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
				
		<!-- AspectJ : AOP 기능을 사용하기 위한 언어 문법 -->
		<!-- aspectjrt : AspectJ 런타임 프로그램 -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<!-- AspectJ Weaver : aspect의 정보를 바탕으로 aspect를 구성한 코드를 생성하는데 필요한 유틸리티 프로그램 -->
		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>
		
		<!-- Log4j (Logging) -->
		<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
		<dependency>
		    <groupId>org.apache.logging.log4j</groupId>
		    <artifactId>log4j-core</artifactId>
		    <version>2.17.1</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
				
		<!-- Servlet -->
		<!-- Servlet 버전을 4.0으로 변경 -->
		<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
		<dependency>
		    <groupId>javax.servlet</groupId>
		    <artifactId>javax.servlet-api</artifactId>
		    <version>4.0.1</version>
		    <scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		
		
		<!-- 단위 테스트 도구 (JUnit) -->
		<!-- https://mvnrepository.com/artifact/junit/junit -->
		<dependency>
		    <groupId>junit</groupId>
		    <artifactId>junit</artifactId>
		    <version>4.13.2</version>
		    <scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-test</artifactId>
		    <version>${org.springframework-version}</version>
		    <scope>test</scope>
		</dependency>    
	</dependencies>
	
	<!-- build : 프로젝트 빌드 시 사용되는 플러그인 추가 및 버전 정보 설정 -->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            
            <!-- 컴파일러 플러그인은 프로젝트의 소스(자바코드)를 컴파일하는 데 사용
			jdk 1.6 이상 사용 시 3.0 이상 버전을 사용, source, taget에는 사용하는 jdk 버전을 작성 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
            
            <!-- Could not initialize class org.apache.maven.plugin.war.util.WebappStructureSerializer -->
			<!-- 메이븐 구성 문제로 인한 pom.xml 오류 발생 시 해결 -->
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.2.2</version>
			</plugin>
        </plugins>
    </build>
</project>

Next > Finish

  • 이러한 형식으로 작성하면 됨.

mybatis-config.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>

	<!-- SqlSessionTemplate 관련 설정 -->
	<settings>
	
		<!-- insert, update 사용 값중 null 이 있을 경우 
			SQL 구문에 null 포함되어 있다는 오류 발생
			이 설정 후, 오류 발생 X, NULL 값을 컬럼에 대입
			단, NOT NULL 제약조건이 없는 컬럼에만 가능
		-->
		<setting name="jdbcTypeForNull" value="NULL"/>
	</settings>
	
	<!-- 별칭 작성 부분 -->
	<!-- VO/DTO 클래스의 패키지명+클래스명 작성하는게 불편하기 때문에 짧은 별칭을 부여 -->
	<typeAliases></typeAliases>
	
	
	<!-- mapper파일(SQL 작성되는파일) 위치 등록 부분 -->
	<mappers></mappers>


</configuration>

root-context.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	
	
	<!-- root-context.xml 파일 
		- web.xml에서 가장 먼저 읽어들이는 파일.
		- 프로젝트 전반적으로 사용되는 자원을 생성하고 설정하는 파일
		- DB 연결 정보, 트랜잭션 처리, 파일 업로드 등을 작성
	-->
	
	
	<!-- DBCP 사용을 위한 DataSource를 Bean으로 등록 -->
	<!-- DataSource란? : java에서 Connection Pool을 지원하기 위한 인터페이스 // 트랜잭션 자동 제어, 자원반환 자동 -->
	<!-- BasicDataSource : DataSource인터페이스를 구현한 클래스, 아파치 commons.dbcp에서 제공 -->
	<!-- destroy-method="close" : 주어진 세션을 자동으로 반환(close)하라는 설정 -->
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
		
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
		<property name="username" value="project" />
		<property name="password" value="project1234" />
		
		<!-- defaultAutoCommit: SQL 수행 후 자동 COMMIT 설정. (기본값 : true) -->
		<property name="defaultAutoCommit" value="false" />
		
		<!-- 커넥션 풀 설정 -->
		<property name="initialSize" value="10" /> <!-- 초기 커넥션 수, 기본 0 -->
		<property name="maxTotal" value="500" /> <!-- 최대 커넥션 수, 기본 8 -->
		<property name="maxIdle" value="100" /> <!-- 유휴 상태로 존재할 수 있는 커넥션 최대 수, 기본 8 -->
		<property name="minIdle" value="10" /> <!-- 유휴 상태로 존재할 수 있는 커넥션 최소 수, 기본 0 -->
		<property name="maxWaitMillis" value="-1" /> <!-- 예외 발생 전 커넥션이 반환 될 떄 까지 대기하는 최대 시간(ms), 기본 -1(무기한) -->
	</bean>
		
</beans>

root-context.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	
	
	<!-- root-context.xml 파일 
		- web.xml에서 가장 먼저 읽어들이는 파일.
		- 프로젝트 전반적으로 사용되는 자원을 생성하고 설정하는 파일
		- DB 연결 정보, 트랜잭션 처리, 파일 업로드 등을 작성
	-->
	
	
	<!-- DBCP 사용을 위한 DataSource를 Bean으로 등록 -->
	<!-- DataSource란? : java에서 Connection Pool을 지원하기 위한 인터페이스 // 트랜잭션 자동 제어, 자원반환 자동 -->
	<!-- BasicDataSource : DataSource인터페이스를 구현한 클래스, 아파치 commons.dbcp에서 제공 -->
	<!-- destroy-method="close" : 주어진 세션을 자동으로 반환(close)하라는 설정 -->
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
		
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
		<property name="username" value="project" />
		<property name="password" value="project1234" />
		
		<!-- defaultAutoCommit: SQL 수행 후 자동 COMMIT 설정. (기본값 : true) -->
		<property name="defaultAutoCommit" value="false" />
		
		<!-- 커넥션 풀 설정 -->
		<property name="initialSize" value="10" /> <!-- 초기 커넥션 수, 기본 0 -->
		<property name="maxTotal" value="500" /> <!-- 최대 커넥션 수, 기본 8 -->
		<property name="maxIdle" value="100" /> <!-- 유휴 상태로 존재할 수 있는 커넥션 최대 수, 기본 8 -->
		<property name="minIdle" value="10" /> <!-- 유휴 상태로 존재할 수 있는 커넥션 최소 수, 기본 0 -->
		<property name="maxWaitMillis" value="-1" /> <!-- 예외 발생 전 커넥션이 반환 될 떄 까지 대기하는 최대 시간(ms), 기본 -1(무기한) -->
	</bean>
	
	
	<!-- SqlSession : sql구문을 DB에 전달, 실행하는 객체
	SqlSessionFactory : SqlSession을 만드는 객체
	sqlSessionFactoryBean : mybatis 설정 파일(mybatis-config.xml)과 Connection Pool 정보를 이용하여 SqlSessionFactory를 만드는 객체
	sqlSessionTemplate : SqlSession 객체에 트랜잭션 처리 역할이 가능하도록 하는 객체 -->
	
	<!-- 마이바티스 SqlSession 등록하기 (xml 방식으로 bean 등록) -->
	<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
	
		<!-- mybatis-config.xml 설정 불러오기 -->
		<property name="configLocation" value="classpath:mybatis-config.xml" />
		<property name="dataSource" ref="dataSource" />
	</bean>
		<!-- SqlSessionTemplate : 기본 SQL 실행 + 트랜잭션 관리 역할을 하는 SqlSession을 생성할 수 있게 하는 객체(Spring bean으로 등록해야함.) -->
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
	
		<constructor-arg ref="sqlSessionFactoryBean" />
	
	</bean>
		<!-- 스프링에서 사용하는 proxy를 이용한 트랜잭션 제어가 안될 경우 추가적인 트랜잭션 매니저를 추가해서 문제 해결 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	
		<property name="dataSource" ref="dataSource" />
	
	</bean>
		
</beans>
  • pdf 파일에 누락된 부분이 있음.

    tx 체크하고 ok 누르기 후 저장하기

  • root-context.xml에 추가됨

root-context.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:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	
	
	<!-- root-context.xml 파일 
		- web.xml에서 가장 먼저 읽어들이는 파일.
		- 프로젝트 전반적으로 사용되는 자원을 생성하고 설정하는 파일
		- DB 연결 정보, 트랜잭션 처리, 파일 업로드 등을 작성
	-->
	
	
	<!-- DBCP 사용을 위한 DataSource를 Bean으로 등록 -->
	<!-- DataSource란? : java에서 Connection Pool을 지원하기 위한 인터페이스 // 트랜잭션 자동 제어, 자원반환 자동 -->
	<!-- BasicDataSource : DataSource인터페이스를 구현한 클래스, 아파치 commons.dbcp에서 제공 -->
	<!-- destroy-method="close" : 주어진 세션을 자동으로 반환(close)하라는 설정 -->
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
		
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
		<property name="username" value="project" />
		<property name="password" value="project1234" />
		
		<!-- defaultAutoCommit: SQL 수행 후 자동 COMMIT 설정. (기본값 : true) -->
		<property name="defaultAutoCommit" value="false" />
		
		<!-- 커넥션 풀 설정 -->
		<property name="initialSize" value="10" /> <!-- 초기 커넥션 수, 기본 0 -->
		<property name="maxTotal" value="500" /> <!-- 최대 커넥션 수, 기본 8 -->
		<property name="maxIdle" value="100" /> <!-- 유휴 상태로 존재할 수 있는 커넥션 최대 수, 기본 8 -->
		<property name="minIdle" value="10" /> <!-- 유휴 상태로 존재할 수 있는 커넥션 최소 수, 기본 0 -->
		<property name="maxWaitMillis" value="-1" /> <!-- 예외 발생 전 커넥션이 반환 될 떄 까지 대기하는 최대 시간(ms), 기본 -1(무기한) -->
	</bean>
	
	
	<!-- SqlSession : sql구문을 DB에 전달, 실행하는 객체
	SqlSessionFactory : SqlSession을 만드는 객체
	sqlSessionFactoryBean : mybatis 설정 파일(mybatis-config.xml)과 Connection Pool 정보를 이용하여 SqlSessionFactory를 만드는 객체
	sqlSessionTemplate : SqlSession 객체에 트랜잭션 처리 역할이 가능하도록 하는 객체 -->
	
	<!-- 마이바티스 SqlSession 등록하기 (xml 방식으로 bean 등록) -->
	<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
	
		<!-- mybatis-config.xml 설정 불러오기 -->
		<property name="configLocation" value="classpath:mybatis-config.xml" />
		<property name="dataSource" ref="dataSource" />
	</bean>
		<!-- SqlSessionTemplate : 기본 SQL 실행 + 트랜잭션 관리 역할을 하는 SqlSession을 생성할 수 있게 하는 객체(Spring bean으로 등록해야함.) -->
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
	
		<constructor-arg ref="sqlSessionFactoryBean" />
	
	</bean>
		<!-- 스프링에서 사용하는 proxy를 이용한 트랜잭션 제어가 안될 경우 추가적인 트랜잭션 매니저를 추가해서 문제 해결 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	
		<property name="dataSource" ref="dataSource" />
	
	</bean>
	
	<!-- 트랜잭션 처리 시 @Transactional 어노테이션을 사용할 예정
		
		해당 어노테이션을 인식하라는 설정이 필요함
		
		@Transactional: 클래스 또는 메서드 수행 후 트랜잭션 처리를 하라고 알려주는 어노테이션
		
	 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
		
</beans>

mybatis-config.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>

	<!-- SqlSessionTemplate 관련 설정 -->
	<settings>
	
		<!-- insert, update 사용 값중 null 이 있을 경우 
			SQL 구문에 null 포함되어 있다는 오류 발생
			이 설정 후, 오류 발생 X, NULL 값을 컬럼에 대입
			단, NOT NULL 제약조건이 없는 컬럼에만 가능
		-->
		<setting name="jdbcTypeForNull" value="NULL"/>
	</settings>
	
	<!-- 별칭 작성 부분 -->
	<!-- VO/DTO 클래스의 패키지명+클래스명 작성하는게 불편하기 때문에 짧은 별칭을 부여 -->
	<typeAliases>
		<typeAlias type="edu.kh.project.member.model.dto.Member" alias="Member"/>
	
	</typeAliases>
	
	
	<!-- mapper파일(SQL 작성되는파일) 위치 등록 부분 -->
	<mappers>
		<mapper resource="/mappers/member-mapper.xml"/>
	</mappers>


</configuration>

member-mapper.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="memberMapper">
	<!-- namespace : 해당 공간의 이름 지정 -->

	<!-- mapper 파일 생성 시 아래 태그 반드시 삭제 -->
	<!--   <cache-ref namespace=""/>   -->
	
	<!-- 작성예시 -->
	<!-- <select id=""></select>  -->
	<!-- <insert id=""></insert>  -->
	
	<!-- 
		resultMap  
		- SELECT 조회 결과(ResultSet) 컬럼명과
		  컬럼 값을 옮겨 담을 DTO의 필드명이 같지 않을 때
		  이를 매핑 시켜 SELECT시 자동으로 담기게하는 역할
	 
	 
	 	-속성
	 	type : 연결할 DTO (패키지명 + 클래스명 또는 별칭)
	 	id : 만들어진 resultMap을 지칭할 식별명(이름)
	 	
	 	<id> 태그 : PK 역할 컬럼 - 필드 매핑
	 	<result> 태그 : <id>제외 나머지
	 -->
	 
	<resultMap type="Member" id="member_rm">
	
		<!-- DB의 기본 키(복합키면 여러 개 작성) -->
		<id property="memberNo" column="MEMBER_NO" />

		<!-- DB의 일반 컬럼들 -->
		<result property="memberEmail" column="MEMBER_EMAIL" />
		<result property="memberPw" column="MEMBER_PW" />
		<result property="memberNickname" column="MEMBER_NICKNAME" />
		<result property="memberTel" column="MEMBER_TEL" />
		
		<result property="memberAddress" column="MEMBER_ADDR" />
		
		<result property="profileImage" column="PROFILE_IMG" />
		<result property="enrollDate" column="ENROLL_DATE" />
		<result property="memberDeleteFlag" column="MEMBER_DEL_FL" />
		<result property="authority" column="AUTHORITY" />
	</resultMap>
	
	<!--  
  		SQL 관련 태그의 속성
  		
  		- parameterType : 전달 받은 값의 자료형
  						기본 : 패키지명 + 클래스명
  						별칭 : Mybatis 별칭 또는 사용자 지정 별칭
  						
		- parameterMap : (사용 안함)
		
		- resultType : select 결과를 담아서 반환할 자료형
					단, DTO를 작성할 경우 필드명 = 컬럼명 인 경우만 가능
										memberNo   MEMBER_NO
		
		- resultMap : select 결과의 컬럼명과 
					 결과를 저장할 DTO 필드명이 다를 경우
					 이를 알맞게 매핑(연결)시켜주는 <resultMap> id 작성
  	-->
  	
  	
  	<!-- 
  		** 마이바티스에서 전달 받은 값을 SQL에 작성하는 방법 **
  		
  		#{변수명|필드명} : PreparedStatement
  						 : SQL에 값 대입 시 양쪽에 '' 붙여서 대입
  		
  		${변수명|필드명} : Statement
  						 : SQL에 값 대입 시 양쪽에 아무것도 붙이지 않음
 						 
		사용 예시)
		test1 = "user01"
		test2 = MEMBER_EMAIL
  	
  		- MEMBER_EMAIL이 'user01'인 회원 조회
  		SELECT * FROM MEMBER WHERE ${test2} = #{test1}
  								 MEMBER_EMAIL = 'user01'
  	 -->
	
	
	<select id="login" parameterType="Member" resultMap="member_rm">
  		SELECT MEMBER_NO, MEMBER_EMAIL, MEMBER_NICKNAME, MEMBER_PW,
			MEMBER_TEL, MEMBER_ADDR, PROFILE_IMG, AUTHORITY,
			TO_CHAR(ENROLL_DATE, 'YYYY"년" MM"월" DD"일" HH24"시" MI"분" SS"초"') AS ENROLL_DATE 
		FROM "MEMBER"
		WHERE MEMBER_DEL_FL = 'N'
		AND MEMBER_EMAIL = #{memberEmail}
  	</select>
	
</mapper>

MemberController.java

package edu.kh.project.member.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import edu.kh.project.member.model.dto.Member;
import edu.kh.project.member.model.service.MemberService;

@Controller // 요청/응답 클래스 + bean 등록(Spring 관리하는 객체)
@RequestMapping("/member") // 공통된 주소 앞부분 작성, member로 시작하는 요청은 해당 컨트롤러에서 처리
public class MemberController {
	
	// 등록된 Bean 중에서 필드와 타입이 일치하는 Bean 주입
	// -> MemberService를 구현한 MemberServiceImpl의 Bean 주입
	@Autowired
	private MemberService service;
	
	

	// 로그인 : /member/login
	// 로그아웃 : /member/logout
	
	// /member/login, post 처리방식
	
	
	// @RequestMapping : 요청 주소에 맞는 클래스/메서드 연결
	// @RequestMapping("요청주소") : -> GET / POST 구분 X , 주소만 맞으면 연결하지만 GET요청시 사용
	// @RequestMapping(value="/login", method=RequestMethod.GET/POST) -> GET/POST 방식을 구분
	
    // @RequestMapping(value="/login", method=RequestMethod.POST)
	public String login(HttpServletRequest req) {
		
		// 파라미터 전달 방법 1 : HttpServletRequest를 이용하는 방법
		// -> Controller 메서드에 매개변수로 HttpServletRequest를 작성
		
		// 매개변수에 적으면 사용 가능한 이유
		// Spring 제공하는 Argument Resolver(매개변수해결사)가 자동으로
		// 대입해주고 해결해줌.
		
		String inputEmail = req.getParameter("inputEmail");
		String inputPw = req.getParameter("inputPw");
		
		System.out.println("inputEmail : " + inputEmail);
		System.out.println("inputPw : " + inputPw);
		
		
		// ******************* redirect 방법! *******************
		// "redirect:요청주소"
		
		return "redirect:/";
	}
	
	
	// @PostMapping : @RequestMapping 자식으로
	//				Post 방식 요청을 연결하는 어노테이션
	//@PostMapping("/login")
	public String login(/*@RequestParam("inputEmail")*/ String inputEmail,
						/*@RequestParam("inputPw")*/ String inputPw/*,
						@RequestParam(value="saveId", required="fasle", defaultValue="1")*/) {
		
		// 파라미터 전달 방법 2 : @RequestParam 어노테이션 이용(+생략방법)
		
		// @RequestParam 어노테이션
		// - request 객체를 이용한 파라미터 전달 어노테이션
		// - 매개변수 앞에 해당 어노테이션 작성하면, 매개변수에 값이 주입됨.
		
		// ** 파라미터의 name 속성값과
		//	매개변수명이 같으면 @RequestParam 생략 가능! **
		
		
		// @RequestParam(value="name", required="fasle", defaultValue="1")
		// [속성]
		// value : 전달 받은 input 태그의 name 속성값
		
		// required : 입력된 name 속성값 파라미터 필수 여부 지정(기본값 true)
		// -> required = true인 파라미터가 존재하지 않는다면 400 Bad Request 에러 발생
		// -> required = true인 파라미터가 null인 경우에도 400 Bad Request

		// defaultValue : 파라미터 중 일치하는 name 속성 값이 없을 경우에 대입할 값 지정.
		// -> required = false인 경우 사용
		
		
		System.out.println("inputEmail : " + inputEmail);
		System.out.println("inputPw : " + inputPw);

		
		return "redirect:/";
	}
	
	
	//@PostMapping("/login")
	public String login(/*@ModelAttribute*/ Member inputMember) {
		
		// 파라미터 전달 방법 3 : @ModelAttribute 이용한 방법
		
		// - DTO(또는 VO)와 같이 사용하는 어노테이션
		
		// - 전달 받은 파라미터의 name 속성 값이
		//   같이 사용되는 DTO의 필드명과 같다면
		//   자동으로 setter를 호출해서 필드에 값을 세팅
		
		System.out.println(inputMember);
		
		// ** @ModelAttribute 사용 시 주의 사항 **
		// - DTO에 기본 생성자가 필수로 존재해야 한다
		// - DTO에 setter가 필수로 존재해야 한다
		
		// ** ModelAttribute 어노테이션은 생략이 가능하다 ! ** 
		
		// ** @ModelAttribute를 이용해 값이 필드에 세팅된 객체를
		//	커맨드 객체 라고 부른다.
		
		
		// Member [ memberEmail = user123, memberPw = pass123.. ]
		
		
		return "redirect:/";
	}
	
	
	/* 찐 로그인 메서드 */
	
	@PostMapping("/login")
	public String login(Member inputMember, Model model) {
		
		
		// 로그인 서비스 호출
		Member loginMember = service.login(inputMember);
		
		// DB 조회 결과 확인
		System.out.println(loginMember);
		
		return null;
	}
	
}

MemberService.java

package edu.kh.project.member.model.service;

import edu.kh.project.member.model.dto.Member;

// Service Interface 사용 이유

// 1. 프로젝트에 '규칙성'을 부여하기 위해서 == 모든 클래스가 같은 형태를 띔(협업 위함)

// 2. 클래스간의 결합도를 약화 시키기 위해서 (객체 지향적 설계) == MemberService service = new MemberServiceImpl();
// -> 유지보수성 향상								   MemberService service = new MemberServiceImpl2();
//												   MemberService service = new MemberServiceImpl3();

// 3. Spring AOP 사용을 위해서
// -> AOP는 spring-proxy를 이용해서 동작하는데
//  이 때 Service 인터페이스가 필요하다!

public interface MemberService {
	
	/** 로그인 서비스
	 * @param inputMember (email, pw)
	 * @return email, pw가 일치하는 회원정보 또는 null
	 */
	Member login(Member inputMember);

}

MemberServiceImpl.java

package edu.kh.project.member.model.service;

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

import edu.kh.project.member.model.dao.MemberDAO;
import edu.kh.project.member.model.dto.Member;

@Service // 비즈니스 로직(데이터 가공, DAO 호출, 트랜잭션 제어)처리하는 클래스 명시
		// + Bean으로 등록하는 어노테이션
public class MemberServiceImpl implements MemberService{
	
	// @Autowired : 작성된 필드와
	// Bean으로 등록된 객체 중 타입이 일치하는 Bean을
	// 해당 필드에 자동 주입(Injection) 하는 어노테이션.
	// == DI(Dependency Injection, 의존성 주입)
	// -> 객체를 직접 만들지 않고, Spring이 만든걸 주입함(Spring에 의존)
	
	@Autowired
	private MemberDAO dao;

	@Override
	public Member login(Member inputMember) {
		
		// dao 메서드 호출
		Member loginMember = dao.login(inputMember);
		
		return loginMember;
	}
	
	
}

memberDAO.java

package edu.kh.project.member.model.dao;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import edu.kh.project.member.model.dto.Member;

@Repository // Persistence Layer, 영속성 관련 클래스 // 영속성 == 영원히 지속되는 성질
			// (DB관련 클래스) + Bean(== Spring 객체화) 등록
public class MemberDAO { // IOC == 제어의 역전
	// DAO는 DB랑 연결하기 위한 Connection이 공통적으로 필요하다
	// + Mybatis 영속성 프레임워크를 이용하려면 Connection을 이용해서 만들어진 객체
	// SqlSessionTemplate을 사용
	@Autowired
	private SqlSessionTemplate sqlSession;
	
	

	/** DAO
	 * @param inputMember
	 * @return 회원 정보 또는 null
	 */
	public Member login(Member inputMember) {
		
		// 마이바티스를 이용해서 1행 조회(selectOne)
		
		// sqlSession.selectOne("namespace값.id값", 전달할 값);
		// -> namespace가 일치하는 Mapper에서
		// id가 일치하는 SQL 구문을 수행 후
		// 결과를 1행 반환
		
		return sqlSession.selectOne("memberMapper.login", inputMember);
	}

}

Server 실행 > 이메일 / 비밀번호 입력 후 로그인 버튼 클릭 시,

0개의 댓글