반응형
반응형
import java.io.IOException;

import org.springframework.core.io.ClassPathResource;

public class test {

	public static void main(String[] args) throws IOException {

		ClassPathResource resource = new ClassPathResource("properties.ini");

		System.out.println("resource.getFile() : " + resource.getFile());
		System.out.println("resource.getFilename() : " + resource.getFilename());
		System.out.println("resource.getInputStream() : " + resource.getInputStream());
		System.out.println("resource.getPath() : " + resource.getPath());
		System.out.println("resource.getURL() : " + resource.getURL());
		System.out.println("resource.getURI() : " + resource.getURI());

		/**
		 * 
		 	resource.getFile() : F:\project\normal_spring_project\workspace\sample\target\classes\properties.ini
		 	resource.getFilename() : properties.ini
			resource.getInputStream() : java.io.BufferedInputStream@5ebec15
			resource.getPath() : properties.ini
			resource.getURL()) : file:/F:/project/normal_spring_project/workspace/sample/target/classes/properties.ini
			resource.getURI() : file:/F:/project/normal_spring_project/workspace/sample/target/classes/properties.ini
		 * 
		 */
		
	}

}

Spring에서 쉽게 가져올 수 있도록 제공해주는 라이브러리[ClassPathResource]로 쉽게 가져올 수 있습니다

가져올 경로는 src/main/resources가 기본 경로입니다

 

🔗참고 및 출처 

http://june0313.github.io/2018/08/11/read-resource-file-on-spring/

 

반응형
반응형

 

 

이클립스 폴더 안에 eclipse.ini 에 하기 내용을 추가한다.

-Dfile.encoding=UTF-8

반응형
반응형
package com.lsj.blog;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.lsj.blog.repository.UserRepository;
import com.lsj.dto.ResponseDto;

@RestController
public class DummyController {

	@Autowired // DI
	private UserRepository userRepository;
	
	@PostMapping("/api/login")
	public ResponseDto<Integer> login(@RequestBody BlogUser user, HttpSession session){
		
		BlogUser principal = loginService(user); //principal (접근주체)
		if(principal != null) session.setAttribute("principal", principal);
		
		System.out.println("principal : " + session.getAttribute("principal"));
		
		return new ResponseDto<Integer>(HttpStatus.OK.value(), 1);
		
	}
	
	@Transactional(readOnly = true) // Select 할 때 트랜잭션 시작, 서비스 종료시 트랜잭션 종료 (데이터 일관성)
	public BlogUser loginService(BlogUser user) {
		return userRepository.findByUsernameAndPassword(user.getUsername(), user.getPassword());
	}
}
package com.lsj.blog.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.lsj.blog.BlogUser;


// extends JapRepository가 있는 경우 @Repository 생략가능
// JpaRepostiory는 다양한 기능을 가지고 있다. findAll (모든 레코드 select) 페이징해서 보내줄 수 있는 기능도 존재
public interface UserRepository extends JpaRepository<BlogUser, Integer>{ // BlogUser의 Repository이고 PK는 Integer이다.
	
	// JPA Naming 쿼리
	// SELECT * FROM bloguser WHERE username = ? AND password = ?;
	// SELECT * FROM ${리턴타입} WHERE username = ${첫번째 파라미터} AND password = ${두번째 파라미터};
	BlogUser findByUsernameAndPassword(String username, String password);
	
	// nativeQuery 방식 위와 동일하다
	@Query(value="SELECT * FROM bloguser WHERE username =1 ? AND password = 2?", nativeQuery = true)
	BlogUser login(String username, String password);
}
반응형
반응형

오라클의 경우 Read Commit 방식을 채택한다.

트랜잭션A가 시작되어 Update를 할 경우 Commit이 이루어질 때까지 UnDo의 영역을 읽기 때문에 Update하고 Commit의 사이에서 누군가 select할 시 1,000원이 출력된다.

 

트랜잭션A가 진행되면 누군가한테는 홍길동 누군가한테는 1,000원 누군가한테는 2,000원이 보일 수 있다.

이런식으로 보일 수 있기 때문에 정합성이 깨진다 → Phantom Read (데이터가 보였다 안 보였다)

 

이러한 점의 문제점은 트랜잭션 B와 같이 조회한 4개를 더해서 총 합을 구하는 시스템이라면 도중에 원래 기대값이 4,000원이지만 6,000원이 나오는 문제가 생긴다.

 

 

MySQL의 경우 Repeatable Read 방식을 채용한다.

UnDo 영역에 데이터를 읽고 자기 트랜잭션 번호보다 낮은 데이터를 읽기 때문에 중간에 Update를 해도 데이터의 일관성을 지킬 수 있다.

 

Insert, Select, Update, Delete의 경우 모두 @Transactional 이 필요하다

반응형
반응형
package com.lsj.blog;

import java.util.Random;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.lsj.blog.model.RoleType;
import com.lsj.blog.repository.UserRepository;
import com.lsj.dto.ResponseDto;

@RestController
public class DummyController {

	@Autowired // DI
	private UserRepository userRepository;
	
	@PostMapping("/api/user")
	@Transactional
	public ResponseDto<String> save(@RequestBody BlogUser user){

		BlogUser usre2 = new BlogUser();
		
		Random random = new Random();

		usre2.setUsername(String.valueOf(random.nextInt(10)));
		usre2.setPassword("12345"); 
		usre2.setEmail("abc@naver.com");
		userRepository.save(usre2); 
			
		new ResponseDto<String>(HttpStatus.OK.value(), "데이터 insert에 성공했습니다.");
		// HttpStatus.OK.value() → 200이라는 코드 반환 (정상 성공)
	}
}
package com.lsj.blog.handler;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

import com.lsj.dto.ResponseDto;

@ControllerAdvice // 어떤 Exception이 오든 이 페이지로 오게 된다.
@RestController
public class GlobalExceptionHandler {
	
	@ExceptionHandler(value=Exception.class) // 모든 부모 Exception
	public ResponseDto<String> handleException(Exception e) {
		return new ResponseDto<String>(HttpStatus.INTERNAL_SERVER_ERROR.value(),e.getMessage());
		// HttpStatus.INTERNAL_SERVER_ERROR.value() → 500 코드 반환 (서버 에러)
		//return "<h1>" + e.getMessage() + "</h1>";
	}
}
package com.lsj.dto;

import org.springframework.http.HttpStatus;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseDto<T> {
	int status;
//	HttpStatus status;
	T data;
}

 

반응형
반응형

📝텍스트 파일로만 페이지 띄우기

tomcat path : C:\tomcat9
server.xml path : C:\tomcat9\conf\server.xml

<Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
    <Context path="it" docBase="C:\tomcat9\webapps\ITWeb" privileged="true"/>
    ....


페이지에 띄울 텍스트파일 경로 : C:\tomcat9\webapps\ITWeb\nana.txt
nana.txt 내용 : 안녕하세요
페이지 호출 URL : http://localhost:8080/it/nana.txt

 

 

📝클래스 파일 직접 만들어서 페이지 띄우기

test.java 

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class test extends HttpServlet {
 public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
 {
  System.out.println("hello Servlet");
 }
}
1. cmd test.java 있는 경로로 이동
2. class 파일 만들기 → javac -cp C:\tomcat9\lib\servlet-api.jar test.java

3. 호출하기 위한 설정파일 수정 (web.xml) [WEB-INF안에 있는 파일은 직접 요청이 불가능하다.]
   WEB-INF 호출하기 위한 설정 파일 경로 : C:\tomcat9\webapps\ROOT\WEB-INF\web.xml
   실행시킬 class파일 : C:\tomcat9\webapps\ROOT\WEB-INF\classes\test.class

web.xml 내용

<servlet>
<servlet-name>testing</servlet-name>
<servlet-class>test</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>testing</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>


→
hello라는 url 요청이 오면 testing이라는 서블릿의 이름을 가진 애를 실행시키라는 의미
testing이라는 이름을 가지는 서블릿의 클래스파일은 test이다


이렇게 매핑정보를 xml으로 할수도 있지만(2.x) annotation(3.x)으로도 사용 가능하다.

annotation 방식을 이용하고 싶을 경우 metadata-complete를 false로 바꿔야한다.
경로 : C:\tomcat9\webapps\ROOT\WEB-INF\web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0"
  metadata-complete="false">



반응형
반응형

 

package runnable_jar;

import java.text.SimpleDateFormat;
import java.util.Date;

public class ThreadGroupExample {

	public static void main(String[] args) {

		Date today = new Date();
		SimpleDateFormat yyyymmddForamt = new SimpleDateFormat("yyyyMMdd");
		
		String todayDate = yyyymmddForamt.format(today); 
		String date = "20221201";
		
		System.out.println("todayDate : " + todayDate); // 20221201
		
		int compare = todayDate.compareTo(date);

		// A.compareTo(B) 
		// A = B  → 0
		// A < B  → -1
		// A > B  → 1
		
		if     (compare > 0) System.out.println("date 날짜는 오늘 날짜 이전입니다."); 
		else if(compare < 0) System.out.println("date 날짜는 오늘 날짜 이후입니다.");
		else                 System.out.println("date 날짜는 오늘 날짜와 동일합니다.");
	}

}

// 출처 : https://soraji.github.io/java/2019/04/15/compareDATE/
package runnable_jar;

import java.text.SimpleDateFormat;
import java.util.Date;

public class ThreadGroupExample {

	public static void main(String[] args) {

		Date today = new Date();
		SimpleDateFormat yyyymmddForamt = new SimpleDateFormat("HHmmss");
		
		String todayTime = yyyymmddForamt.format(today); 
		String time = "224246";
		
		System.out.println("todayTime : " + todayTime); // 20221201
		
		int compare = todayTime.compareTo(time);

		// A.compareTo(B) 
		// A = B  → 0
		// A < B  → -1
		// A > B  → 1
		
		if     (compare > 0) System.out.println("time < 현재 시각"); 
		else if(compare < 0) System.out.println("time > 현재시각");
		else                 System.out.println("time = 현재시각");
	}

}
반응형
반응형

📝1. keysotre 파일 생성 (SSL인증서)

1. cmd 관리자 권한으로 실행
2. cd ${jdk/bin경로}
3. 하기 명령어 입력
keytool -genkey -alias tomcat -keyalg RSA -keystore tomcat.keystore
설명 : keytool -genkey -alias tomcat -keyalg RSA -keystore ${keystore 파일명}

4. 하기 내용 입력하기

키 저장소 비밀번호 입력:
새 비밀번호 다시 입력:
이름과 성을 입력하십시오.
[Unknown]: 
조직 단위 이름을 입력하십시오.
[Unknown]:
조직 이름을 입력하십시오.
[Unknown]: 
구/군/시 이름을 입력하십시오?
[Unknown]:
시/도 이름을 입력하십시오.
[Unknown]: seoul
이 조직의 두 자리 국가 코드를 입력하십시오.
[Unknown]: KR
N=maruara, OU=Unknown, O=Unknown, L=Unknown, ST=seoul, C=KR이(가) 맞습니까?
[아니오]: y
tomcat>에 대한 키 비밀번호를 입력하십시오.
(키 저장소 비밀번호와 동일한 경우 Enter 키를 누른다):

 

📝2. tomcat의 server.xml에서 https 설정하기

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystorePass="gkgkgk" keystoreFile="d:/openssl/tomcat.keystore"/>

port → https 통신 포트
keystorePass → 위에서 설정한 패스워드
keystoreFile → ssl 인증서 경로
반응형
반응형

📝 Mybatis 연결하기

<bean id="dataSource"
    class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName"
        value="com.mysql.cj.jdbc.Driver" />
    <property name="url"
        value="jdbc:mysql://localhost:3306/customer?characterEncoding=UTF-8" />
    <property name="username" value="root" />
    <property name="password" value="1234" />

</bean>

<bean id="sqlSessionFactory"
    class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation"
        value="classpath:mybatis/mybatis-config.xml" />
    <property name="mapperLocations"
        value="classpath:mybatis/mappers/**/*mapper.xml" />
</bean>
<!-- classpath란 src/main/java를 의미한다. classpath:com.mycompany.myapp -->



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

root-context.xml

<!-- Mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.8</version>
</dependency>

<!-- Mybatis-Spring -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.2.2</version>
</dependency>

pom.xml

package com.company.macro;

import java.util.List;

import com.company.macro.VO.CustomerVO;

public interface MybatisImpl {

	public String selectCount();
	public List<CustomerVO> selectAll();
	public void insertAll();
	
//	@Select("SELECT * FROM customer")
//	public String selectAll();
}

MybatisImpl.java

 

query문의 이름과 반환 타입을 선언합니다.

public class CustomerVO {
	private String customer_no;
	private String customer_nm;
	// DB에 있는 컬럼명과 VO와 동일하게 가야한다.

	
	public String getCustomer_no() {
		return customer_no;
	}
	public void setCustomer_no(String customer_no) {
		this.customer_no = customer_no;
	}
	public String getCustomer_nm() {
		return customer_nm;
	}
	public void setCustomer_nm(String customer_nm) {
		this.customer_nm = customer_nm;
	}
	
	
}

CustomerVO.java

 

 

<?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>
   <properties>
        <property name="mybatis 안에서 사용될 column의 이름" value="디비 컬럼명" />
        <property name="tblCustomer" value="customer" />
        <property name="customer_no" value="customer_no" />
        <property name="customer_nm" value="customer_nm" />
        
        <property name="tblMember" value="tbl_member"/>
        <property name="colUserid" value="userid"/>
        <property name="colPassword" value="password"/>
        <property name="colEmail" value="email"/>
    </properties>

    <typeAliases>
        <typeAlias alias="customerVO" type="com.company.macro.VO.CustomerVO" />
    </typeAliases>
    <!-- VO가 들어있는 패키지명  -->
</configuration>

webapps/resources/mybatis-config.xml

 

property는 mapper.xml에서 쓰이는

typeAliases는 mapper.xml의 select해서 나온 데이터를 VO에 바로 담을수 있게 사용하겠다는 의미입니다.

<?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">
<!-- 상기 내용은 반드시 필요한 내용 -->

<!-- interface 명 -->
<mapper namespace="com.company.macro.mybatisImpl">

	<select id="selectCount" resultType="string">
		SELECT count(*) FROM customer
	</select>

	<select id="selectAll" resultType="customerVO">
		SELECT * FROM ${tblCustomer}
	</select>

</mapper>

webapps/resources/mappers/mapper.xml

 

resultType에는 typeAliases에 적은 VO를 사용할 수 있습니다.

${property name명} 으로 name에 해당하는 value를 가져올 수 있습니다.

 

 

 

📝 Mybatis 동작 구조

 

 

 

Mybatis 사용시 데이터 흐름

사용자 → 컨트롤러 → Servie(interface)[DI용 + 규격화] → ServiceImpl(class) → Dao(interface)[DI용 + 규격화] → mapper.xml(xml이지만 Dao에 설정된 interface를 따라감 implements한 class라고 생각하면 됨) → DB → 실행결과 → ServiceImpl → Controller → 사용자

 

Service → 비즈니스 로직 (DaoImpl을 통해 여러가지 쿼리문(Dao를 1개 이상 실행)을 가져오고 Java를 이용해 데이터를 만들어 반환 가능)

Dao       → DB Query 실행문이 들어감 (1개의 Query문)

mapper.xml → Query문에 대한 내용

Interface 사용 이유 → DI 하기 위함과 규격화를 위해 사용 → DI를 제대로 활용할 줄 몰라서 아직 와닿지 않음

 

* 참고 : 보통은 어떻게 처리하는지 모르겠지만 Service에 로직이 길어졌는데 해당 부분에 공통 로직이 있어서 (로그인 세션 체크 등...) 공통 API로 뺄 때 그 안에 Mapper를 이용해야하는 경우(DB Connection이 들어가는 로직)일 경우 해당 Util(공통 API)도 또한 Mapper를 Injection해서(Autowired) 사용할텐데 해당 Mapper를 이용하기 위해서는 @Component 또는 @Service 등 해당 클래스를 IoC컨테이너에 담아야한다.

 

LoginUtil util = new Util
LoginVo vo = util.getSessionInfo()
----------- (X)

@Autowired
LoginUtil loginUtil;

....

LoginVo vo = loginUtil.getSessionInfo();
----------- (O)

 

<!-- spring version과 spring-jdbc version은 동일해야한다 -->
<!-- mybatis, mybatis-spring, spring-version 서로 호환되는 버전으로해야한다. -->
<!-- 만약 호환 안 되는 버전 사용시 sqlSession 객체 만들 때 에러 나오는데 버전이 맞지 않습니다라 이런 에러도 안 나와서 에러 체킹이 힘듬 -->
<!-- root-context.xml에서 설정후 실행 시 sqlSession 객체 만들 때 정상 호환 버전들이면 정상 작동하거나 잘못 된 부분에 대한 정확한 에러가 나옴 -->


<properties>
    <java-version>11</java-version>
    <org.springframework-version>5.0.5.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
....

<!-- jdbc -->
<dependency>
  <groupId>org.mariadb.jdbc</groupId>
  <artifactId>mariadb-java-client</artifactId>
  <version>2.0.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>
<!-- Mybatis -->	
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<!-- Mybatis + Spring -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.2</version>
</dependency>

pom.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 -->
	<bean id="dataSource"
	    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	    <property name="driverClassName"
	        value="org.mariadb.jdbc.Driver" />
	    <property name="url"
	        value="jdbc:mariadb://192.168.0.40:7001/ocr_search" />
	    <property name="username" value="testid" />
	    <property name="password" value="testpassword" />
	</bean>

	<bean id="sqlSessionFactory"
	    class="org.mybatis.spring.SqlSessionFactoryBean">
	    <property name="dataSource" ref="dataSource" />
        <property name="configLocation"
        value="classpath:mybatis-config.xml" />
    	<property name="mapperLocations"
     	   value="classpath:mappers/*Mapper.xml" />
	</bean>
	
	<!-- classpath란 src/main/java 또는 src/main/resources를 의미한다. -->
	<!-- classpath는 build path - source에 등록된 경로들이다.  -->
	<!-- classpath:mybatis-config.xml → Alias등 설정 하는 설정 파일 -->
	<!-- classpath:mappers/*Mapper.xml → Query를 적는 파일이다 -->
	<!-- src/main/java/mappers 폴더에 관리하겠다는 의미이고 파일명이 Mapper.xml로 끝나는 파일들을 등록하겠다는 의미이다. -->
	
	<bean id="sqlSession"
	    class="org.mybatis.spring.SqlSessionTemplate">
	    <constructor-arg ref="sqlSessionFactory" />
	</bean>
	
	<!-- mapper 어노테이션을 인식 시키기위해 필요 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	    <property name="basePackage" value="com.company.ocrsearch" />
	</bean>
		
</beans>

root-context.xml

 

SqlSession : DB 연결하기 위한 객체 및 Query 수행 역할 (SqlSessionFactory가 주입 됨)

SqlSessionFactory : mapper.xml에 대한 설정 및 mapper.xml(쿼리문) 읽을 객체

 

 

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class EngineDto {

	private String uuid = "";
	private String id = "";
	private String password = "";
	private String salt = "";
	private String fail_cnt ="";
	
	public String getUuid() {
		return uuid;
	}
	public void setUuid(String uuid) {
		this.uuid = uuid;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getSalt() {
		return salt;
	}
	public void setSalt(String salt) {
		this.salt = salt;
	}
	public String getFail_cnt() {
		return fail_cnt;
	}
	public void setFail_cnt(String fail_cnt) {
		this.fail_cnt = fail_cnt;
	}
	
	public String toStringShortPrefix() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
	
	
}

EngineDto.java

→ 데이터가 담기는 부분이다.

 

 

---- String 단일 매개변수 동적 쿼리 ----


import java.io.IOException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;

import global.configuration.Config;
import global.dto.DirectoryPathDto;
import global.dto.ServerInfoDto;


@Controller
public class EngineAPI {
	
	@Autowired
	@Qualifier("EngineSerive")
	EngineService engineService;
	
	@RequestMapping(value = "/myabtis-test", method = RequestMethod.GET)
	public void testMybatis(String uuid) throws Exception{
		
		EngineDto engineDto = engineService.getUserInfo(uuid);
		System.out.println(engineDto.toStringShortPrefix());
		
	}
	
}

EngineAPI.java

→ Controller로 사용자의 요청이 들어오는 부분이다.

 


import com.company.ocrsearch.engine.dto.EngineDto;

public interface EngineService {
	
	public EngineDto getUserInfo(String uuid) throws Exception;
}

EngineSerivce.java

→ 비즈니스 로직이 들어가며 규격화 및 DI 역할

 

 

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

import com.company.ocrsearch.engine.dao.EngineDao;
import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;

@Service("EngineSerive")
public class EngineServiceImpl implements EngineService{

	@Autowired
	private EngineDao engineDao;
	
	@Override
	public EngineDto getUserInfo(String uuid) throws Exception {
		
		EngineDto engineDto = engineDao.selectUser(uuid);
		return engineDto;
	}

}

EngineServiceImpl.java

→ 실제 비즈니스 로직 구현한 것으로 DB 쿼리문을 사용할 경우 1개 이상의 Dao로 구성되어 있다.

받아온 쿼리문을 가지고 여러 동작을 하거나 여러개의 Dao를 호출해서 결과를 조합해서 Dto에 담아서 내려주는 형태

 

 

 

 

package com.company.ocrsearch.engine.dao;

import org.apache.ibatis.annotations.Mapper;

import com.company.ocrsearch.engine.dto.EngineDto;

@Mapper
public interface EngineDao {
	public EngineDto selectUser(String uuid) throws Exception;
	
}

EngineDao.java

→ root-context.xml에서 설정한 org.mybatis.spring.mapper.MapperScannerConfigurer에 포함된 패키지일 경우 @mapper 어노테이션을 찾아서 *mapper.xml과 연결해준다. interface이기 때문에 규격화및 DI 역할을 한다.

 

 

 

<?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="com.company.ocrsearch.engine.dao.EngineDao">

	<select id="selectUser" parameterType="String"
		resultType="com.company.ocrsearch.engine.dto.EngineDto">
			SELECT
			        ID          -- 아이디
			      , FAIL_CNT    -- 로그인 실패 횟수
			 FROM   admin_user	
			 WHERE 
			        uuid = #{UUID}
	</select>
</mapper>

EngineInfoMapper.xml 

→  쿼리문이 여기에 작성되며 연결할 interface명을 mapper namespace에 적는다.

xml을 EngineDao inteface를 implements한 class라고 생각하면 된다. 

 

id → Dao Interface에서 구현해야할 Funciton Name을 의미한다.

parameterType → 동적 쿼리를 위해 넘겨주는 파라미터를 의미한다. #{UUID}에 들어가는 파라미터는 String이 된다.

[ String 뿐만 아니라 HashMap 등이 있기 때문에 상황에 맞게 쓰면 된다 java.util.HashMap 등...)

String의 경우 HashMap의 경우 키 값으로 들어가기 때문에

resultType → 결과가 담길 곳을 의미한다. 일반적으로 여러개의 결과이고 데이터의 이동은 Dto에 담아서 하기 때문에 Dto를 적어줬다.

너무 당연한 이야기지만 내려받을 필드명과 Dto 필드는 같아야한다. (Alias 걸어서 Dto 수정 없이 Dto에 맞출 수도 있음)

[ String 뿐만 아니라 HashMap 등이 있기 때문에 상황에 맞게 쓰면 된다 java.util.HashMap 등...)

 

* 상속받는 놈(mapper.xml)이 ParameterType을 받기로 했기 때문에 Dao (interface)에도 그렇게 설정해줘야한다.

→ 매개변수가 1개의 String 이여야 함 (String의 경우 이름(#{UUID})을 정할 수 없기 때문에 들어온 그대로 들어가게 된다.)

     여러개의 매개변수를 받으려면 HashMap이나 Dto가 적당하다.

타입은 신경 안 쓰는 것 같다. → DB 필드가 문자 타입이여도 parameterType=int로 보내줘도 인식함

 

 

 

 

---- HashMap 매개변수 동적 쿼리 ----

 

pom.xml, root-context.xml, DTO는 동일합니다.

 

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;


@Controller
public class EngineAPI {
	
	@Autowired
	@Qualifier("EngineSerive")
	EngineService engineService;
	
	@RequestMapping(value = "/mybatis-test", method = RequestMethod.GET)
	public void testMybatis(String uuid, String userId) throws Exception{
		
		HashMap<String, String> data = new HashMap<>();
		data.put("UUID", uuid); // mapper에서 대소문자 구분합니다.
		data.put("userId", userId);
		
		
		EngineDto engineDto = engineService.getUserInfo(data);
		System.out.println(engineDto.toStringShortPrefix());
		
	}
	
}

EngineAPI.java

 

import java.util.HashMap;

import com.company.ocrsearch.engine.dto.EngineDto;

public interface EngineService {
	
	public EngineDto getUserInfo(HashMap<String, String> uuid) throws Exception;
}

EngineService.java

 

import java.util.HashMap;

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

import com.company.ocrsearch.engine.dao.EngineDao;
import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;

@Service("EngineSerive")
public class EngineServiceImpl implements EngineService{

	@Autowired
	private EngineDao engineDao;
	
	@Override
	public EngineDto getUserInfo(HashMap<String, String> uuid) throws Exception {
		
		EngineDto engineDto = engineDao.selectUser(uuid);
		return engineDto;
	}
}

EngineServiceImpl.java

 

import java.util.HashMap;

import org.apache.ibatis.annotations.Mapper;

import com.company.ocrsearch.engine.dto.EngineDto;

@Mapper
public interface EngineDao {
	public EngineDto selectUser(HashMap<String, String> uuid) throws Exception;
	
}

EngineDao.java

 

 

<?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="com.company.ocrsearch.engine.dao.EngineDao">

	<select id="selectUser" parameterType="java.util.HashMap"
		resultType="com.company.ocrsearch.engine.dto.EngineDto">
			SELECT
			        ID          -- 아이디
			      , FAIL_CNT    -- 로그인 실패 횟수
			 FROM   admin_user	
			 WHERE  uuid = #{UUID}
			   AND  id   = #{userId}
	</select>
</mapper>

EngineInfoMapper.xml

달라진 점은 HashMap을 파라미터로 넘긴다는 점입니다.

키의 값을 기준으로 동적쿼리가 생성되며 대소문자를 구분하니 주의하시길 바랍니다.

 

 

 

---- Dto 매개변수 동적 쿼리 ----

 

pom.xml, root-context.xml, DTO는 동일합니다.

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;


@Controller
public class EngineAPI {

	@Autowired
	@Qualifier("EngineSerive")
	EngineService engineService;
	
	@RequestMapping(value = "/mybatis-test", method = RequestMethod.GET)
	public void testMybatis(EngineDto requestEngineDto) throws Exception{

		EngineDto engineDto = engineService.getUserInfo(requestEngineDto);
		System.out.println(engineDto.toStringShortPrefix());
		
	}
	
}

EngineAPI.java

 

 

import com.company.ocrsearch.engine.dto.EngineDto;

public interface EngineService {
	
	public EngineDto getUserInfo(EngineDto requestEngineDto) throws Exception;
}

EngineService.java

 

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

import com.company.ocrsearch.engine.dao.EngineDao;
import com.company.ocrsearch.engine.dto.EngineDto;
import com.company.ocrsearch.engine.service.EngineService;

@Service("EngineSerive")
public class EngineServiceImpl implements EngineService{

	@Autowired
	private EngineDao engineDao;
	
	@Override
	public EngineDto getUserInfo(EngineDto requestEngineDto) throws Exception {
		
		EngineDto engineDto = engineDao.selectUser(requestEngineDto);
		return engineDto;
	}
}

EngineServiceImpl.java

 

import org.apache.ibatis.annotations.Mapper;

import com.company.ocrsearch.engine.dto.EngineDto;

@Mapper
public interface EngineDao {
	public EngineDto selectUser(EngineDto requestEngineDto) throws Exception;
}

EngineDao.java

 

<?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="com.company.ocrsearch.engine.dao.EngineDao">

	<select id="selectUser" parameterType="com.company.ocrsearch.engine.dto.EngineDto"
		resultType="com.company.ocrsearch.engine.dto.EngineDto">
			SELECT
			        ID          -- 아이디
			      , FAIL_CNT    -- 로그인 실패 횟수
			  FROM  admin_user	
			 WHERE  uuid = #{uuid}
			   AND  id   = #{id}
	</select>
</mapper>

mapper.xml

 

 

 

 

 

https://wildeveloperetrain.tistory.com/26

 

@Component 와 @Bean, @Autowired 어노테이션 알아보기

자주 사용하면서도 정확하게 무슨 용도로 사용되는지, 어떤 동작 원리를 가지는지, 어떤 차이가 있는지 잘 몰랐던 부분에 대해서 공부합니다. 먼저 Annotation에 대해서 간단하게 알아보겠습니다.

wildeveloperetrain.tistory.com

 

반응형