본문 바로가기
Back-end

Spring 용어정리(3)

by 신재권 2021. 8. 16.

간단한 게시판 생성

Controller : 리퀘스트 매핑 위한

DTO, DAO : 데이터베이스와 테이블을 사용하기 위한

쿼리문의 결과가 하나 이상 즉 여러개가 나오는 SQL문을 처리하기위해서는 JdbcTemplate의 query 메서드를 사용한다.

그리고 결과가 하나만 나오는 SQL문을 처리하기 위해서는 JdbcTemplate의 queryForObject 메서드를 사용한다.

SQL의 insert, delte, update 문은 JdbcTemplate의 update 메서드를 사용한다.

변수를 이용해 SQL문을 완성시킬 수도 있고, 메서드에 값을 파라미터로 넘길 수도 있다.

package com.study.springboot;

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.RequestMapping;



@Controller
public class MyController {
	
	@Autowired
	ISimpleBbsDao dao;
	
	@RequestMapping("/")
	public String root() throws Exception{
		// JdbcTemplate : SimpeBBS
		return "redirect:list";
	}
	
	@RequestMapping("/list")
	public String userlistPage(Model model) {
		//게시판의 리스트를 출력하기위해 dao의 listDao() 메서드를 호출하여 리턴 값을 model 변수에 담는다.
		model.addAttribute("list", dao.listDao()); 
		return "list";
	}
	
	@RequestMapping("/view")
	public String view(HttpServletRequest request, Model model) {
		String sId = request.getParameter("id");
		//개별 게시글을 보기 위해 dao의 viewDao 메서드를 호출하여 리턴값을 model 변수에 담는다.
		model.addAttribute("dto", dao.viewDao(sId)); 
		return "view";
	}
	
	@RequestMapping("/writeForm")
	public String writeForm() {
		//입력 폼을 가진 JSP 파일을 호출한다.
		return "writeForm"; 
	}
	
	@RequestMapping("/wirte")
	public String write(Model model, HttpServletRequest request) {
//		폼의 입력값을 파라미터로 받아 dao의 writeDao 메서드를 호출해 데이터베이스에 insert를 한다
		dao.writeDao(request.getParameter("writer"),
					 request.getParameter("title"), 
					 request.getParameter("content"));
		return "redirect:list";
	}
	
	@RequestMapping("/delete")
	public String delete(HttpServletRequest request, Model model) {
		dao.deleteDao(request.getParameter("id")); 
//		파라미터로 넘어온 값을 이용해 dao의 deleteDao 
//		메서드를 호출해 데이터베이스에서 게시글을 delete한다.
		return "redirect:list";
	}
	
}

@Autowired //자동 주입을 지정하고 ISimpleBbsDao dao; //dao 객체 변수를 만들었다.

여기서 주목할 점은 자동 주입으로 만들어질 객체 변수의 값을 인터페이스 타입의 변수로 받았다는 점이다.

또한 디자인 패턴에서 자주 사용하는 '자식 객체를 부모 타입의 변수에 대입할 수 있다'를 활용한 것이다.

그리고 redirect 기능을 활용해서 url로 /가 호출되면 url이 자동으로 /list로 연결이 되게 만들었다.


JdbcTemplate의 기능을 이용하면, 데이터베이스 처리 부분이 매우 간단해져서 비지니스 로직에 집중할 수 있다,


MyBatis란?

MyBatis는 개발자가 지정한 SQL, 저장 프로시저 그리고 몇 가지 고급 매핑을 지원하는 퍼시스턴스 프레임 워크이다.

MyBatis는 JDBC로 처리하는 상당 부분의 코드와 파라미터 설정 및 결과 매핑을 대신해준다.

MyBatis는 데이터베이스 레코드에 원시타입과 Map 인터페이스 그리고 자바 POJO를 설정해서 매핑하기 위해 XML과 어노테이션을 사용할 수 있다.


요약하면 자바에서 데이터베이스를 사용하기 쉽게 해준다는 것이다.

기존의 JDBC를 이용하여 프로그래밍을 하는 방식은 데이터베이스를 사용하기 위해 드라이버 로드, 접속, 쿼리 실행, 종료 등 반복적인 작업과 커넥션풀 등의 관리를 개발자가 매번 해야 한다.

기존의 JdbcTemplate를 이용해서 이런 부분을 개선했다.

하지만 여전히 프로그램 소스 안에 SQL 문을 작성하는 방식이어서 , SQL의 변경 등이 발생한 경우, 자바 소스를 수정하고 재컴파일해야 해서 그 유연성이 좋지 못했다.

MyBatis에서는 SQL을 자바 코드 외부의 XML 파일에 작성할 수 있어서 SQL의 수정이 자유롭고, SQL문의 가독성이 좋다는 장점이 있다.

기존의 JDBC를 이용하여 프로그래밍을 하는 방식에 비해서 MyBatis는 개발자의 부담을 많이 덜어주고 생산성 향상도 돕는다.


package com.study.springboot.jdbc;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface IMyUserDao {
	List<MyUserDTO> list();
}

@Mapper

@Mapper 어노테이션은 다음 인터페이스의 구현을 XML로 한다는 의미이다.


매퍼 구현

인터페이스의 구현을 자바 코드로 하지 않고 XML로 SQL만 만든다.

SQL문을 사용하는 자바 코드는 정형화되어 있기 때문에 스프링이 자동으로 생성해 줄 수 있다.

application.properties 에 추가
#mybatis
mybatis.mapper-locations=classpath:mybatis/mapper/**/**.xml

위 설정의 의미는 mybatis / mapper 아래의 모든 폴도의 () 모든 xml( .xml)을 매퍼로 사용한다고 지정한 것이다.

그러므로 @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="com.study.springboot.jdbc.IMyUserDao">
	<select id="list" resultType="com.study.springboot.jdbc.MyUserDTO">
		select id, name from myuser
	</select>	
</mapper>

위의 파일은 XML 파일이다.

namespace는 이 매퍼가 어떤 인터페이스와 관련된 매퍼인지 알려준다.

id는 인터페이스에 정의된 메서드의 이름이다.

그리고 결과 타입을 지정한다.


SQL문을 사용하는 자바 코드는 정형화 되어 있기 때문에 누구나 같은 코드를 작성하게 될 것이다.

다만 프로젝트마다 사용하는 SQL문만 다르게 될것이다.

그러므로 자바 코드는 생략하고 사용하고 싶은 SQL문만 여기에 적어 주는 것이다.

자바코드는 스프링이 자동으로 생성해준다.

사용하는 SQL문에 따라 태그를 select, insert, update, delete를 사용한다.


15라인에서 자동 주입을 지정하고 16라인에서 userDao 객체 변수를 만들었다. 여기서 주목할 점은 자동 주입으로 만들어질 객체 변수의 값을 인터페이스 타입의 변수로 받았다는것이다 매퍼를 사용했기에 현재 코드상에는 인터페이스를 구현한 클래스가 없기 때문이다. 디자인 패턴에서 자주 사용하는 '자식 객체를 부모 타입의 변수에 대입'를 활용한 것이다.


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
	out.println("MyBatis : Hello Wolrd");
%>
<br>

<c:forEach var="dto" items="${users}">
	${dto.id} / ${dto.name} <br>
</c:forEach>


</body>
</html>

모델의 users 속성에 리스트 데이터를 넣어 두었기 때문에 16라인에서처럼 jstl의 for문을 사용하는데, users에서 데이터 dto를 하나씩 꺼내어 dto의 속성값을 이용해 개별 내용을 출력한다.


MyBatis를 사용하면 SQL문이 매퍼 파일에 작성되어 있어서 SQL문의 변경이 훨씬 쉬워진다.

SQL문이 코드와 섞여 있지 않기 떄문에 가독성도 좋다.


<?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.study.springboot.dao.ISimpleBbsDao">
	
	<select id="listDao" resultType="com.study.springboot.dto.SimpleBbsDto">
		select * from simple_bbs order by id desc
	</select>
	
	<select id="viewDao" resultType="com.study.springboot.dto.SimpleBbsDto">
		select * from simple_bbs where id = #{param1}
	</select>
	
	<insert id="writeDao">
		insert into simpe_bbs(id,writer, title, content)
			values (simple_bbs_seq.nextval, #{param1}, #{param2}, #{param3})
	</insert>
	
	<delete id="deleteDao">
		delete from simpe_bbs where id = #{param1}
	</delete>
		
	
	
	
</mapper>

namespace는 이 매퍼가 어떤 인터페이스와 관련된 매퍼인지 알려준다.

그리고 사용하는 SQL문에 따라 태그를 select, insert, update, delete를 사용한다.

id는 ISimpleBbsDao 인터페이스에 정의된 메서드 이름이다.

resultType은 리턴되는 값의 타입을 지정한다.

insert와 delete는 select문과 달리 결괏값이 없으므로 리턴타입을 지정하지 않는다.


SQL문에서 사용되는 파라미터가 있다면 필요한 만큼 차례대로 #{param1}, #{param2}, #{param} .. 이런식으로 숫자를 늘려가면서 사용하면 된다.


package com.study.springboot;

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.RequestMapping;

import com.study.springboot.dao.ISimpleBbsDao;

@Controller //클래스를 빈으로 등록하는데 컨트롤러로 사용 
public class MyController {
	
	@Autowired
	ISimpleBbsDao dao;
	
	@RequestMapping("/")
	public String root() throws Exception{
		//MyBatis : SimpleBBS
		return "redirect:list";
	}
	
	@RequestMapping("/list")
	public String userlistPage(Model model) {
		model.addAttribute("list", dao.listDao());
		return "list";
	}
	
	@RequestMapping("/view")
	public String view(HttpServletRequest request, Model model) {
		String sId = request.getParameter("id");
		model.addAttribute("dto", dao.viewDao(sId));
		return "view";
	}
	
	@RequestMapping("/writeForm")
	public String writeForm() {
		
		return "writeForm";
	}
	
	@RequestMapping("/write")
	public String write(HttpServletRequest request, Model model) {
		dao.writeDao(request.getParameter("writer"),
			     	 request.getParameter("title"),
			     	 request.getParameter("content"));
		return "redirect:list";
	}
	
	@RequestMapping("/delete")
	public String delete(HttpServletRequest request, Model model) {
		dao.deleteDao(request.getParameter("id"));
		return "redirect:list";
	}
}

위에서 인터페이스에 자동주입을 지정하고 인터페이스 타입 변수로 dao 객체 변수를 만들었다.

매퍼를 사용했기 때문에 코드상에서는 인터페이스를 구현한 클래스가 없기 때문이다.

또한 redirect 기능을 이용해 url로 /가 호출되면 바로 /list가 연결되게 하였다.


실행하자마자 root() 메서드가 호출되 리다이렉션 코드가 실행된다.

그러면 list로 요청이 발생하고 userlistPage() 메서드가 호출된다.

결과로 게시판의 리스트 페이지가 나온다.


스프링에서 사용할 수 있는 MyBatis 의 기능을 이용하면 데이터베이스 처리 부분이 매우 간단해진다.

사실 모든 개발자가 데이터베이스를 사용할 때 비지니스 로직에 따라 SQL문만 다를 뿐이지 처리해야 하는 부분과 방법은 모두 같다.

MyBatis는 이런점을 이용하여 서비스를 제공해준다.


MyBatis에서 파라미터 사용하기

MyBatis에서 SQL문에 동적으로 변경되는 부분의 데이터를 파라미터로 전달하는 방법은 4가지로 정리할 수 있다.


방법 1 : param1, param2, param3,.. 과 같이 param 변수 뒤의 숫자를 늘려 가면서 #{ } 사이에 적어서 사용하는 방법이다

<select>
		select * from 테이블명 where 컬럼=#{param1}and컬럼=#{param2}
</select>

 


방법2 : 0부터 시작하는 인덱스를 사용하여 #{ } 사이에 적어준다.

작성할 때는 편하나 나중에 이 항목이 어떤 항목이었는지 파악하기가 쉽지 않다.

<select>
		select * from 테이블명 where 컬럼=#{0} and 컬럼#{1}		
</select>

방법 3 : 지정한 파라미터명을 사용하기 위해 @Param 어노테이션을 사용하여 이름을 지정해주는 방법이다.

작성할 때는 번거로울 수 있으나, 나중에 이 항목이 어떤 항목이었는지 파악하기 쉽다.

인터페이스 추상 메서드 정의 시
		public void 함수명(@Param("파라미터명")String 파라미터명,...)
Mapper 파일에서 
		select * from 테이블명 where 필드명 =#{파라미터명}
으로 사용할 수 있다.

방법 4 : 다량의 데이터를 파라미터로 받을 때 해시맵을 사용하여 받는 방법이다.

인터페이스 추상메서드 정의시
		public int writeDao(Map<String, String> 파라미터명);
Controller 파일에서
		Map<String, String> map = new HashMap<String, String>();
		map.put("item1", sName);
		map.put("item2", sContent);
Mapper 파일에서
		insert into simple_bbs(id, writer, content)
				values(1, #{item1}, #{item2})
으로 사용할 수 있다.

Dao 인터페이스를 변경한다.

package com.study.springboot.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.study.springboot.dto.SimpleBbsDto;

@Mapper
public interface ISimpleBbsDao {

	public List<SimpleBbsDto> listDao(); //리스트를 보기 위한 select 
	public SimpleBbsDto viewDao(String id); //개별 뷰 보기 위한 select
	public int writeDao(String writer, String title, String content); //글 작성 insert
	public int deleteDao(@Param("_id")String id); //글 삭제 delete
}

마지막 @Param은 id 변수에 대해 매퍼에서 사용할 이름을 정의한 것이다.

즉 "_id"로 지정했다.

실제 상황에서는 긴 이름을 짧게 만들거나, 이해하기 어려운 변수를 이해하기 쉬운 변수명으로 바꾸는데 사용할 수 있다.

인터페이스 대응하는 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="com.study.springboot.dao.ISimpleBbsDao">
	
	<select id="listDao" resultType="com.study.springboot.dto.SimpleBbsDto">
		select * from simple_bbs order by id desc
	</select>
	
	<select id="viewDao" resultType="com.study.springboot.dto.SimpleBbsDto">
		select * from simple_bbs where id = #{0}
	</select>
	
	<insert id="writeDao">
		insert into simpe_bbs(id,writer, title, content)
			values (simple_bbs_seq.nextval, #{param1}, #{param2}, #{param3})
	</insert>
	
	<delete id="deleteDao">
		delete from simpe_bbs where id = #{_id}
	</delete>
		
	
	
	
</mapper>

viewDao와 deleteDao 메서드를 수정했다.

viewDao는

기존 파라미터에서 숫자로 변경했다.

첫번쨰 파라미터를 사용하므로 숫자 0을 지정했다.

숫자는 0부터 시작한다.

deleteDao 에서는 인터페이스를 만들 때 어노테이션으로 지정한 값을 이용하여 사용한다.

숫자나 순서가 아닌 이름을 사용하기 때문에 어떤 값이 사용되는지 파악하기 쉽다.


MyBatis에서 SQL 쿼리 결괏값 사용하기

MyBatis에서 SQL 쿼리가 성공하면 다음과 같은 결괏값을 얻을 수 있다.

  • Select - Select문에 해당하는 결과
  • Insert - 1(여러 개일 경우도 1)
  • Update - Update된 행의 개수 반환(없다면 0)
  • Delete - Delete된 행의 개수(없다면 0)

비지니스 로직에 따라 쿼리의 결괏값을 비교하여 로직을 처리할 필요도 있다.

그때 이런 결괏값을 이용하면 된다.


package com.study.springboot.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.study.springboot.dto.SimpleBbsDto;

@Mapper
public interface ISimpleBbsDao {

	public List<SimpleBbsDto> listDao(); //리스트를 보기 위한 select 
	public SimpleBbsDto viewDao(String id); //개별 뷰 보기 위한 select
	public int writeDao(Map<String, String> map); //글 작성 insert
	public int deleteDao(@Param("_id") String id); //글 삭제 delete
	public int articleCount();
}

writeDao 의 파라미터를 맵을 사용하는것 으로 변경되었다.

또한 articleCount() 글의 개수를 세서 리턴하는 메서드를 생성하였다.

<?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.study.springboot.dao.ISimpleBbsDao">
	
	<select id="listDao" resultType="com.study.springboot.dto.SimpleBbsDto">
		select * from simple_bbs order by id desc
	</select>
	
	<select id="viewDao" resultType="com.study.springboot.dto.SimpleBbsDto">
		select * from simple_bbs where id = #{0}
	</select>
	
	<insert id="writeDao" parameterType="java.util.HashMap">
		insert into simple_bbs(writer, title, content)
			values (#{item1}, #{item2}, #{item3})
	</insert>
	
	<delete id="deleteDao">
		delete from simple_bbs where id = #{_id}
	</delete>
		
	<select id="articleCount" resultType="_int">
		select count(*) from simple_bbs
	</select>
	
	
	
</mapper>

writeDao의 파라미터 타입을 해쉬맵으로 정하였고, 파라미터 전달을 #{param1}에서 #{item1}으로 변경하였다.

item1, item2, item3은 파라미터로 전달된 해쉬맵 변수의 키값이다.

articleCount에서는 결괏값의 타입을 정해줬다.

리턴하는 데이터 타입이 원시형인 경우 언더바를 앞에 붙인다.

붙이지 않은 경우 래퍼(Wrapper) 클래스로 변환된다.

예약된 별칭은 org.apache.ibatis.type.TypeAliasRegistry에 지정되어 있다.


package com.study.springboot;

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

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.RequestMapping;

import com.study.springboot.dao.ISimpleBbsDao;

@Controller //클래스를 빈으로 등록하는데 컨트롤러로 사용 
public class MyController {
	
	@Autowired
	ISimpleBbsDao dao;
	
	@RequestMapping("/")
	public String root() throws Exception{
		//MyBatis : SimpleBBS
		return "redirect:list";
	}
	
	@RequestMapping("/list")
	public String userlistPage(Model model) {
		model.addAttribute("list", dao.listDao()); //게시판의 리스트를 출력하기 위해 dao의 
		//listDao() 메서드를 호출하여 리턴값을 model 변수에 담는다
		
		int nTotalCount = dao.articleCount();
		System.out.println("Count : "+ nTotalCount);
		
		return "/list";
	}
	
	@RequestMapping("/view")
	public String view(HttpServletRequest request, Model model) {
		String sId = request.getParameter("id");// 개별 게시글을 보기 위해 dao viewDao 메서드를
		//호출하여 리턴값을 model변수에 담는다
		model.addAttribute("dto", dao.viewDao(sId));
		return "/view";
	}
	
	@RequestMapping("/writeForm")
	public String writeForm() {
		
		return "/writeForm";
	}
	
	@RequestMapping("/write") //폼의 입력값을 파라미터로 받아 dao의 writeDao 메서드를 호출해
	//데이터베이스에 insert 한다.
	public String write(HttpServletRequest request, Model model) {
//		dao.writeDao(request.getParameter("writer"),
//			     	 request.getParameter("title"),
//			     	 request.getParameter("content"));
		
		String sName = request.getParameter("writer");
		String sTitle = request.getParameter("title");
		String sContent = request.getParameter("content");
		
		Map<String, String> map = new HashMap<String, String>();
		map.put("item1", sName);
		map.put("item2", sTitle);
		map.put("item3", sContent);
		
		int nResult = dao.writeDao(map);
		System.out.println("Write : "+nResult);
		
		
		return "redirect:list";
	}
	
	@RequestMapping("/delete") //파라미터로 넘어온 값을 이용해 dao의 deleteDao 메서드를 호출해
	//데이터 베이스에서 게시글을 delete 한다.
	public String delete(HttpServletRequest request, Model model) {
//		dao.deleteDao(request.getParameter("id"));
		String sId = request.getParameter("id");
		int nResult = dao.deleteDao(sId);
		System.out.println("Delete : "+nResult);
		return "redirect:list";
	}
}

list 메서드에서 글의 개수를 가져온느 메서드를 호출한다.

여기서는 결괏값을 출력만 하였지만, 실제로는 게시판의 리스트를 페이징 처리할 때는 이 값을 사용해야 한다.


write 메서드에서는 해쉬맵 변수를 선언하고 이 변수의 값으로 파라미터로 들어온 값들을 넣고 있다.

그리고 메서드의 파라미터 값으로 해쉬맵 변수를 넣고있다.

그리고 메서드 호출의 결괏값을 리턴받고 있다.

인서트가 성공했다면 1이 리턴되고, 실패헀다면 0이 리턴될것이다.

이 값에 따라서 알맞은 비지니스 로직을 구현하면 된다.


delete 메서드에서도 글을 삭제하는 메서드를 호출하고 리턴값을 받았다.

역시 이 값에 따라서 알맞은 비지니스 로직을 구현하면된다.


MyBatis로 SQL 로그 출력하기

자바는 많은 로깅 프레임워크를 가지고 있다.

log4j, logback, log4j2, apache common logging, SLF4J등 다양한 프레임워크들이 있다.

스프링 부트는 logback을 기본적인 로깅 시스템으로 지원하고 있다.

스프링에서 logback을 사용하기 위해 별도로 추가할 디펜던시는 없으며, application.properties를 통한 로깅 설정을 할 수도 있고, xml 파일로 따로 설정 정보를 관리하면서 개발할 수 있는 로깅 커스터마이징(Spring Boot Logging Customizing)도 지원한다.

로깅 커스터 마이징을 사용할 경우 스프링이나 일반 자바 프로그램의 경우는 보통 logback.xml 파일을 resources 디렉토리에 만들어서 참조한다.

logback은 이 설정 파일을 자동으로 찾는데 logback.groovy → logback-text.xml → logback.xml 순서로 찾고 없으면 디폴트 설정을 따른다.

스프링 부트의 경우 조금 다르게 logback.xml이라는 이름 대신 logback-spring.xml을 사용한다.


MyBatis를 사용하면 편하기는 한데, 프로그래밍을 할때 불편한 점이 한 가지 있다.

SQL 관련해서 로그를 출력하여 볼 수 가 없다는 것이다.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<Pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] [%thread]
					 %-5level %logger{36} - %msg%n</Pattern>
		</encoder>
	</appender>
	
	<logger name="com.study.springboot" level="debug"/>
	
	<root level="info">
		<appender-ref ref="console"/>
	</root>
</configuration>

appender에서 지정하는 클래스에 따라 로그의 출력 방법을 콘솔이나 파일, 데이터베이스, 메일 등으로 정할 수 있다.

우리는 콘솔에 출력하기 위한 클래스를 지정했고 어펜더의 이름은 console이라고 만들었다.

Pattern에서 출력되는 패턴을 지정한다.

root에서 프로그램 전체에 대해서는 info 수준으로 로그를 출력하도록 설정하였다.

appender-ref에서 출력할 대상의 이름을 위에서만든 console로 지정하였다.

logger에서 패키지 하위부분에 대해서는 debug 수준으로 로그가 출력하도록 추가 설정하였다.

[2021-08-16 14:35:46:15398] [http-nio-8080-exec-2]
					 DEBUG c.s.springboot.jdbc.IMyUserDao.list - ==>  Preparing: select id, name from myuser
[2021-08-16 14:35:46:15422] [http-nio-8080-exec-2]
					 DEBUG c.s.springboot.jdbc.IMyUserDao.list - ==> Parameters: 
[2021-08-16 14:35:46:15451] [http-nio-8080-exec-2]
					 DEBUG c.s.springboot.jdbc.IMyUserDao.list - <==      Total: 3

우리가 설정한 레벨에 맞게 info 수준으로 로그가 출력이 되다가, com.study.springboot 하위 부분에 대해서는 debug 수준으로 로그를 출력되는 것을 확인할 수 있다.

우리가 사용한 SQL문이 출력이 되고 select문의 결괏값도 출력이 된다는 것을 확인할 수 있다.

SQL문의 로그 출력은 debug 레벨부터 가능하다.


<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<Pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] [%thread]
					 %-5level %logger{36} - %msg%n</Pattern>
		</encoder>
	</appender>
	
	<logger name="com.study.springboot" level="info"/>
	
	<!-- log4j2-jdbc4 -->
	<logger name="jdbc" level="OFF"/>
	<logger name="jdbc.sqlonly" level="OFF"/>
	<logger name="jdbc.sqltiming" level="DEBUG"/>
	<logger name="jdbc.resultset" level="OFF"/>
	<logger name="jdbc.resultsettable" level="DEBUG"/>
	<logger name="jdbc.connection" level="OFF"/>
	<!-- log4j2-jdbc4 -->
	
	<root level="off">
		<appender-ref ref="console"/>
	</root>
</configuration>

xml 파일을 수정하고, log4jdbc.log4j2.Properties를 추가한다.

log4jdb.spylogdelegator.name=net.sf.log4jdbc.,log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0

application.properties도 수정한다.

#JSP
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
# MySQL set
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/sjk
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.url=jdbc:log4jdbc:mysql://localhost:3306/sjk
spring.datasource.username=sjk
spring.datasource.password=sjk1234

#mybatis
mybatis.mapper-locations=classpath:mybatis/mapper/**/**.xml

이 설정으로 데이터베이스를 사용할 때 스프링의 로깅 시스템이 데이터베이스의 출력 로그를 후킹하는 처리를 한다.

또한 build.gradle에 디펜던시를 추가한다.

implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc:4:1.16'

이렇게 하면 로그가 이전 출력보다 다양한 정보와 함께 보기 좋게 출력된 것을 볼 수 있다.

사용된 쿼리문이 출력되고, 쿼리에 걸린 시간이 표시되며, ResultSet이 출력된다.

다만 한글을 출력할 경우 세로선은 잘 맞지 않는다.

 

'Back-end' 카테고리의 다른 글

JSP의 에러처리  (0) 2021.08.21
JSP의 내장객체  (0) 2021.08.21
JSP 기초  (0) 2021.08.14
Spring 용어정리 (2)  (0) 2021.08.11
Spring 용어정리 (1)  (0) 2021.08.10