관리 메뉴

DeseoDeSeo

[Spring] 3 tier architecture (1) 본문

spring

[Spring] 3 tier architecture (1)

deseodeseo 2023. 10. 4. 17:52

예전에는 Controller안에 mapper가 있었는데 이제 Service가 일을 하니까 Service안에 mapper가 있음.

Controller는 Service한테 요청하고 Service가 실질적으로 일함.

 

Client > presentation Layer( Controller, View )  > Business Layer( Service)  > Data Access  ( Model )

Presentation Layer : Client의 화면에 보여주는 기술을 사용하는 영역

Business Layer: 일을 하는 곳(비즈니스 로직을 담고 있는 영역, 서비스 영역)

Data Access Layer : db와 연결.

JUnit : 모듈별 테스트를 함.

 

pom.xml
<properties>
// 버전 변경
	<java-version>1.6</java-version>
    <org.springframework-version>5.0.7.RELEASE</org.springframework-version>
	<org.aspectj-version>1.6.10</org.aspectj-version>
	<org.slf4j-version>1.6.6</org.slf4j-version>
</properties

//버전변경, javax추가
<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>3.1.0</version>
	<scope>provided</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
			<dependency>
			    <groupId>org.projectlombok</groupId>
			    <artifactId>lombok</artifactId>
			    <version>1.18.24</version>
			    <scope>provided</scope>
			</dependency>
			
	<!-- MyBatis를 사용하기 위한 api추가  -->
			<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
			<dependency>
			    <groupId>org.mybatis</groupId>
			    <artifactId>mybatis</artifactId>
			    <version>3.4.6</version>
			</dependency>
			
	<!-- conncection Pool을 사용하기 위한 hikari cp추가.  -->
			<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
			<dependency>
			    <groupId>com.zaxxer</groupId>
			    <artifactId>HikariCP</artifactId>
			    <version>3.4.1</version>
			</dependency>
			
	<!-- MYBATIS 에서 connection을 하기 위한 mySQL Driver API 추가 -->
	
			<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
			<dependency>
			    <groupId>mysql</groupId>
			    <artifactId>mysql-connector-java</artifactId>
			    <version>5.1.42</version>
			</dependency>
			
	<!-- Spring에서 Mybatis 를 통해 JDBC를 사용하기 위한 aPI 추가 -->
	
	<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
			<dependency>
			    <groupId>org.springframework</groupId>
			    <artifactId>spring-jdbc</artifactId>
			    <version>5.0.20.RELEASE</version>
			</dependency>
			
	<!-- mybatis와 Spring을 연결해주는 API -->
	<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
			<dependency>
				    <groupId>org.mybatis</groupId>
				    <artifactId>mybatis-spring</artifactId>
				    <version>1.3.2</version>
			</dependency>
		
 <configuration>
    <source>1.8</source>
    <target>1.8</target>
    <compilerArgument>-Xlint:all</compilerArgument>
    <showWarnings>true</showWarnings>
     <showDeprecation>true</showDeprecation>
  </configuration>

 

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--xmlns="http://J 여기에서 대문자 J로 바꾸고 나서 alt + f5  force update~~ 체크하고 실행. -->
<web-app version="2.5" xmlns="http://Java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<!-- 여기로 root-context와 servlet-context가 읽어옴. -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>
MySQL.sql
CREATE TABLE TBLBOARD(
   IDX INT NOT NULL,
   MEMID VARCHAR(20) NOT NULL,
   TITLE VARCHAR(100) NOT NULL,
   CONTENT VARCHAR(2000) NOT NULL,
   WRITER VARCHAR(30) NOT NULL,
   INDATE DATETIME DEFAULT NOW(),
   COUNT INT DEFAULT 0,
   -- 댓글기능 추가 --
   BOARDGROUP INT, -- 부모 댓글 하나의 그룹 --
   BOARDSEQUENCE INT, -- 같은 그룹게시글안안에서 댓글의 순서 --
    BOARDLEVEL INT, -- 1단계 댓글인지 2단계 댓글인지에 대한 정보  원 댓글에 달린 대댓글인지, 다른 댓글에 달린건지 --   
   BOARDAVAILABLE INT, -- 삭제된 글인지 여부 --
   PRIMARY KEY(IDX)
);
INSERT INTO TBLBOARD
SELECT IFNULL(MAX(IDX+1), 1),
'aischool','공지사항 입니다.', '다음주 월요일 휴일', '교육 운영부', 
NOW(), 0, IFNULL(MAX(BOARDGROUP+1),1),0,0,1
FROM TBLBOARD;

INSERT INTO TBLBOARD
SELECT IFNULL(MAX(IDX+1), 1),
'aischool','여름여름.', '여름여름', '교육 운영부', 
NOW(), 0, IFNULL(MAX(BOARDGROUP+1),1),0,0,1
FROM TBLBOARD;

INSERT INTO TBLBOARD
SELECT IFNULL(MAX(IDX+1), 1),
'aischool','도르미르.', '도르미르', '교육 운영부', 
NOW(), 0, IFNULL(MAX(BOARDGROUP+1),1),0,0,1
FROM TBLBOARD;

SELECT * FROM TBLBOARD;

CREATE TABLE TBLMEMBER(
   MEMID VARCHAR(50) NOT NULL,
   MEMPWD VARCHAR(50) NOT NULL,
   MEMNAME VARCHAR(50) NOT NULL,
   MEMPHONE VARCHAR(50) NOT NULL,
   MEMADDR VARCHAR(100),
   LATITUDE DECIMAL(13, 10), -- 현재위치위도 --
   LONGITUDE DECIMAL(13, 10), -- 현재위치경도 --
   PRIMARY KEY(MEMID)
);

INSERT INTO TBLMEMBER(MEMID, MEMPWD,MEMNAME, MEMPHONE)
VALUES('aischool','1234','교육운영부','010-1111-2222');

INSERT INTO TBLMEMBER(MEMID, MEMPWD,MEMNAME, MEMPHONE)
VALUES('aischool1','12345','교육운영부1','010-1111-2222');

INSERT INTO TBLMEMBER(MEMID, MEMPWD,MEMNAME, MEMPHONE)
VALUES('aischool2','123456','교육운영부2','010-1111-2222');

SELECT* FROM TBLMEMBER;
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>
	
	<!--  controller안에서 controller뿐만 아니라 service도 찾아야함.-->
	<context:component-scan base-package="kr.spring.controller" />
	<!-- 10/04(2) 내가 만든 Service도 scan할 수 있게 명시해야함.  -->
	<context:component-scan base-package="kr.spring.service" />
	
	
	
</beans:beans>

 

BoardMapper.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="kr.spring.mapper.BoardMapper">

	<select id="getList" resultType="kr.spring.entity.Board">
		SELECT * FROM TBLBOARD
		ORDER BY BOARDGROUP DESC
	</select>
</mapper>
BoardController.java
package kr.spring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class BoardController {
	
	@GetMapping("/boardList.do")
	public String boardList() {
		// board파일의 boardList.
		return "board/boardList";
	}
	
	
}
BoardMapper.java
package kr.spring.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import kr.spring.entity.Board;

@Mapper
public interface BoardMapper {
	public List<Board> getList();
	
}
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:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd 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 -->
   <!-- API(HikariCP) -->
   <!--  rootconfig 클래스 파일로 만드는 것도 함. -->
   <!-- bean : 객체를 생성하는 태그 -->
   <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
      <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
      <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/com"/>
      <property name="username" value="com"/>
      <property name="password" value="com01"/>
   </bean>
   
   <!-- dataSource가 커넥션역할,  -->
   <!-- HikariDataSource(Connection POOL을 만드는 역할을 한다) -->
   <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
      <constructor-arg ref="hikariConfig" />
   </bean>
   
   <!-- Mapper interface들을 메모리에 올리는 방법(scan) -->
   <!-- spring안에 있는 mapper를 찾아라. -->
   <mybatis-spring:scan base-package="kr.spring.mapper"/>
   
   <!-- BoardMapper interface의 구현클래스 생성
   SqlSessionFactoryBean(SQL을 실행하는 API) -->
   
   <!-- sqlsessionfactorybean jdbc 수행하고 내가 만든 인터페이스를 가져다가 실행해줌.  -->
   <bean class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource" />
   </bean>
   
</beans>
Board.java
package kr.spring.entity;

import java.util.Date;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@ToString
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Board {
	private int idx;
	private String memID;
	private String title;
	private String content;
	private String writer;
	private Date indate;
	private int count;
	private int boardGroup;
	private int boardSequence;
	private int boardLevel;
	private int boardAvailable;
	
}
Member.java
package kr.spring.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@NoArgsConstructor
@AllArgsConstructor
@ToString
@Data
public class Member {
	private String memID;
	private String memPwd;
	private String memName;
	private String memPhone;
	private String memAddr;
	private String latitude;
	private String longitude;
}
BoardService.java
package kr.spring.service;

public interface BoardService {

}
BoardServiceImpl.java
package kr.spring.service;

import org.springframework.stereotype.Service;

@Service
public class BoardServiceImpl implements BoardService {
	//여기가 실질적으로 일하는 service임.
	
}

 

DataSourceTest.java
package kr.spring.mapper;

import java.sql.Connection;
import java.util.List;

import javax.sql.DataSource;

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

import kr.spring.entity.Board;
import lombok.extern.log4j.Log4j;

@Log4j // 테스트 실행결과를 콘솔창에 나오게 하기위함
@RunWith(SpringJUnit4ClassRunner.class) // 실행하기위해 스프링컨테이너에 올리는 코드
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") 
// root-context.xml 경로를 잡아주는과정
public class DataSourceTest {
   // root-context.xml이 이상없는지 
   // test하는 클래스
   
   // Connection이 잘되는지 테스트
   @Autowired // root-context.xml에 있는 id가 dataSource인 녀석을 사용하겠다
   private DataSource dataSource;
   
   @Autowired
   private BoardMapper mapper;
   
   @Test
   public void testGetList() {
	   List<Board> list  = mapper.getList();
	   for(Board vo : list) {
		   System.out.println(vo.toString());
	   }
   }   
   //junit을 통해서 jsp없이도 테스트 가능하다. 모듈별로 테스트 가능하다.
//   @Test
//   public void testConnection() {
//      
//      try( Connection conn = dataSource.getConnection() ){
//         log.info(conn);
//      }catch(Exception e) {
//         e.printStackTrace();
//      }
//      
//   }   
   
}