ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 36일차 - 기초적인 MVC와 DB(JDBC) 연결
    백엔드(웹 서버, WAS)/Spring 2024. 3. 13. 17:46

     

     

    Maven Central: commons-dbcp:commons-dbcp

    Discover commons-dbcp in the commons-dbcp namespace. Explore metadata, contributors, the Maven POM file, and more.

    central.sonatype.com

    다중 URL 예제

    // /index 로 요청이 오면 index() 메서드를 실행해라
    // 1. http://localhost:8080/main/index 
    // 로 클라이언트 요청이 오면 서버는 index() 를 실행한다
    
    // 2. method = RequestMethod.GET
    // GET 방식으로 요청받겠다
    @RequestMapping(value="/index", method = RequestMethod.GET)
    public String index() {
    	logger.info("/index 요청");
        return "index"; // 가야할 jsp 이름
    }

    1. 서버를 끈 상태에서 꼭 @RequestMapping 을 작성해야한다 그렇지 않으면 서버에 수정 사항이 적용되지 않는다

    2. 브라우저에서 http://localhost:8080/main/index 로 접속을 시도하면 서버에 /index 요청이라고 로그가 올라온다

    @RequestMapping(value="/index", method = RequestMethod.GET)
    public String index(Model model) { // Model 이라는 녀석으로 jsp 에 데이터를 보낼 수 있다
        // 매개변수 소괄호 안에 ctrl + space 누르면 추천 목록 나옴
        // Model 은 MVC 패턴과 전혀 관계 없는 놈이다
        logger.info("/index 요청");
     	// name(jsp 에서 el 태그로 부를 때 사용하는 이름), value
        model.addAttribute("msg", "index 페이지에 오셨습니다");
        return "index"; // 가야할 jsp 이름

    3. index.jsp 에는 model.addAttribute("msg", "index 페이지에 오셨습니다") 로 보내준 msg 값이 출력된다

     

    예제 정리.

    a. 브라우저에게 /main/index 요청이 오면 HomeController 에서 index() 메서드를 실행한다

    b. 요청은  method = RequestMethod.GET 이므로 GET 방식으로 받는다

    c. Logger.info() 로 통해 서버 로그에 "/index 요청" 출력

    d. model.addAttribute("msg", "main 페이지에 오셨습니다"); <- 이건 아직 이해 못함

    Model 개요
    Model은 스프링이 지원하는 기능으로써, key와 value로 이루어져있는 HashMap이다.
    Model의 .addAttribute()를 통해 view에 전달할 데이터를 저장할 수 있다.
    Servlet의 request.setAttribute()와 비슷한 역할을 한다.

    e. 마지막으로 return "index" 가야할 jsp 파일의 이름을 알려준다


    문제

    /main 으로 요청이 오면 main() 메서드를 실행하도록
    jsp 로 전달되는 문구는 "main 페이지에 오셨습니다"

    @RequestMapping(value="/main", method = RequestMethod.GET)
    public String main(Model model) { // Model 이라는 녀석으로 jsp 에 데이터를 보낼 수 있다
        logger.info("/main 요청");
        model.addAttribute("msg", "main 페이지에 오셨습니다");
        return "index"; // 가야할 jsp 이름
    }

     

    http://localhost:8080/main/main 으로 요청하면

    a. logger.info("/main 요청"); 으로 메소드가 실행되었는지 꼭 확인하자

    b. model.addAttribute("msg", "main 페이지에 오셨습니다");

    c. return "index" index.jsp 파일로 전달한다


    예제 만들기 전 준비 단계

    이제부터 모든 프로젝트를 만들때 매번 pom.xml 파일을 아래 내용처럼 수정해줘야한다

    1. Sample 프로젝트를 복사 붙여넣기 해서 03_Calc 를 만들고

    2. 

    maven: build 툴 + 라이브러리를 자동 다운로드하게 해준다
    build: 개발 소스가 동작할 수 있는 프로그램으로 만들어주는 것 

    pom.xml 에 원하는 라이브러리 정보를 넣으면 알아서 다운로드 해준다

    ㄴ 인터넷 안되는 환경에서는 당연히 안된다

    처음 프로젝트 할때 pom.xml 적힌 라이브러리 다운로드하느라 느려짐

    자바 버젼이 1.6 에서 1.8 로 바뀌었는지 확인

    기존의 index.jsp 파일은 삭제하고

    home.jsp 를 views 폴더에 생성 직전까지 간다음에

    jsp 

     

    <%@ page language="java" contentType="text/html; charset=${encoding}" pageEncoding="${encoding}"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head>
    <meta charset="${encoding}">
    <title>Insert title here</title>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    </head>
    <body>
    ${cursor}
    </body>
    <script>
    </script>
    </html>

    New JSP File (html 5)의 템플릿 내용을 위의 코드로 바꾸어줘야한다

    home.jsp 에 똑같은 코드가 나왔는지 확인하자


    계산기 예제

    1. su1, su2, oper 세가지 파리미터를 HomeController 로 보내고

    2. HomeController 두가지의 수(su1, su2) 를 연산자(oper)에 따른 결과를 result 파리미터를 저장해 result.jsp 로 보낸다 

    3. result.jsp 에서는 계산된 결과를 보여준다

    문제 : val1, val2, oper 를 서버에 출력해라 

    1. http://localhost:8080/main 으로 요청이 들어오면 home.jsp 를 불러와서 사용자에게 페이지를 출력하게 된다 

    package com.sprng.main;
    
    import java.util.Date;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    
    @Controller
    public class HomeController {
    	
    	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);	
    
    	@RequestMapping(value = "/", method = RequestMethod.GET)
    	public String home(Model model, HttpServletRequest req) {
    		logger.info("/home 요청");
    		return "home";
    	}
    	
    	@RequestMapping(value = "/calc", method = RequestMethod.POST)
    	public String calc(Model model, HttpServletRequest req) {
    		logger.info("/calc 요청");
    		String val1 = req.getParameter("val1");
    		String val2 = req.getParameter("val2");
    		String oper = req.getParameter("oper");
    		logger.info(val1 + " " + oper + " " + val2);
    		
    		int su1 = Integer.parseInt(val1);
    		int su2 = Integer.parseInt(val2);
    		// 어떤 값이 입력될지(들어올지) 모르기 때문에 최상위 클래스 타입으로
    		// 받는다
    		Object result = 0;
    		
    		// 여기에 default 를 넣지 않아도 된다 왜냐하면 이미 
    		// 입력 받는것은 사칙연산이 끝이다
    		switch(oper) {
    			case "+":
    				result = su1 + su2;
    				break;
    			case "-":
    				result = su1 - su2;
    				break;
    			case "*":
    				result = su1 * su2;
    				break;
    			case "/":
    				result = su1 / su2;
    				break;
    		}
    		
    		// result 속성으로 결과값을 보내라
    		model.addAttribute("result", result);
    		return "result";
    	}
    }

     

    home.jsp
    
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    </head>
    <body>
    	<form action="calc" method="post">
    		<input type="text" name="val1"/>
    		<select name="oper">
    			<option value="+">+</option>
    			<option value="-">-</option>
    			<option value="*">*</option>
    			<option value="/">/</option>
    		</select>
    		<input type="text" name="val2"/>
    		<input type="submit" value="전송"/>
    	</form>
    </body>
    <script>
    	
    </script>
    </html>

     

    result.jsp
    
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    </head>
    <body>
    	<h3>답 : ${result}</h3>
    </body>
    <script>
    </script>
    </html>

    2. post 방식으로 /calc 요청 을 보내게 되고 HomeController 에서 그 요청을 받아 val1,val2, oper 를 서버 로그에 출력한다 

    2-1. req 에는 request 객체로 home.jsp 에서 보낸 val1, val2, oper 파라미터도 함께 객체에 담겨서 보내진다

    그 값을 calc 메서드에서 처리해서 출력할 수 있다

     

    3.입력받은 값들을 게산하여 마지막에 model.addAttribute("result", result); 가 result.jsp 에 결과 값을 저장하고 result.jsp 에서 그 값을 가져와서 출력한다


    DAO와 DTO

    1. DB 가 필요하면 Model이 MAINDAO 에게 DB 요청을 보내고 

    1. DB가 필요없는 없을 경우 Service 에게 시킨다

    2. 필요하면 DAO 에게 데이터를 시킨다

    2. Model은 가져온 데이터를 Controller 에게 다시 전달한다

    3. Controller 는 받은 데이터를 DTO(빈, VO)에 저장한다

     

    스프링과 DB 연결

    JDBC 라이브러리를 다운받아서 알아서 DB가 연결되게 만들어주기 위해 pom.xml(maven) 을 수정한다

     

    반드시 MARIADB와 DBeaver 설치되어있어야하고 mydb 데이터베이스, web_user 계정이 생성되어있야지 진행할 수 있다

     

    1. 04_JDBC 프로젝트를 만든다

    2. pom.xml 을 전에 준비 단계에서 했던

     

    pom.xml 파일에서 7-8칸의 공백을 넣어준다

    maven repository 사이트에 접속해서 즐겨찾기 하기

    mariadb 를 검색한후 맨 상단 검색결과 클릭

     

    pom.xml 에 붙여넣는다 항상 라이브러리를 추가할때에는 url 를 추가해서 다른 사람을 위해서 링크를 남겨두자

    controller, dao, service 세개의 패키지를 만들고 각각 클래스를 만들어주자

    HomeController.java
    
    @Controller
    public class HomeController {
    	
    	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);	
    
    	@RequestMapping(value = "/", method = RequestMethod.GET)
    	public String home(Model model) {		
    		logger.info("controller home 접근");
    		HomeService service = new HomeService();
    		service.dbConnect();
    		return "index";
    	}
    	
    }
    
    HomeService.java
    
    public class HomeService {
    	private static final Logger logger = LoggerFactory.getLogger(HomeService.class);	
    	
    	public String dbConnect() {
    		logger.info("컨트롤러에서 호출하면...");
    		logger.info("DB가 필요한 일인지에 따라 내가 처리하던지");
    		logger.info("DAO에 시키던지 결정한다");
    		return null;
    	}
    }

    HomeController, HomeService 에 두개를 작성해주고 서버 콘솔에서 출력되는지 확인하자

    main.DAO 패키지에 HomeDAO 클래스를 만들어주자

     

     

    이제 DB 에 접속해서 데이터를 가져오자

    1. 접속하려는 데이터베이스의 정보를 준비해야한다

    DBeaver 접속 설정을 한번 확인해보자

    DBeaver 에 접속해서 Edit Driver Settings 를 누르자

    클래스명과 URL 가 들어가 있고 아이디 패스워드 등이 필요하다

    HomeController.java
    
    @Controller
    public class HomeController {
    	
    	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);	
    
    	@RequestMapping(value = "/", method = RequestMethod.GET)
    	public String home(Model model) {		
    		logger.info("controller home 접근");
    		HomeService service = new HomeService();
    		String msg = service.dbConnect();
    		model.addAttribute("msg", msg);
    		return "index";
    	}
    }
    
    
    
    
    HomeService.java
    
    public class HomeService {
    	private static final Logger logger = LoggerFactory.getLogger(HomeService.class);	
    	
    	public String dbConnect() {
    		logger.info("컨트롤러에서 호출하면...");
    		logger.info("DB가 필요한 일인지에 따라 내가 처리하던지");
    		logger.info("DAO에 시키던지 결정한다");
    		
    		String msg = "DB 접속에 실패 했습니다.";
    		HomeDAO dao = new HomeDAO();
    		if (dao.dbConnect()) {
    			msg = "DB 접속에 성공 했습니다.";
    		}
    		
    		return msg;
    	}
    }
    
    
    
    
    HomeDAO.java
    
    public class HomeDAO {
    	private static final Logger logger = LoggerFactory.getLogger(HomeDAO.class);
    	
    	// 슬래시 + 별 + 별 + 엔터
    	/**
    	 * 데이터베이스 접속 후 성공 여부를 반환해주는 메서드
    	 * @return 성공 여부를 true 또는 false 로 반환
    	 */
    	public boolean dbConnect() {
    		logger.info("DB가 필요하면 이게 실행되어야 한다");
    		boolean success = false;
    		// 1. 접속하려는 데이터베이스의 정보를 준비해야한다
    		String id = "web_user";
    		String pw = "pass";
    		String url = "jdbc:mariadb://localhost:3306/mydb";
    		String driver = "org.mariadb.jdbc.Driver";
    		
    		try {
    			Class.forName(driver);// 2. 드라이버 매니저를 부른다
    			// DriverManager.getConnection(url) 클래스에서 정적 메서드를 불러왔다
    			// 자바의 정적을 다시 기억하자
    			// 접속이 성공해야지 conn 객체가 생성되고 아니라면 실패하면 당연히 null 이다
    			Connection conn = DriverManager.getConnection(url, id, pw);// 3. 만능 열쇠(Connection)을 받는다
    			// 4. 할거 하고..
    			if (conn != null) {
    				// DB 의 접속이 정상적으로 연결되었다면
    				// true 로 
    				success = true;
    			}
    			// 연결을 끊지 않으면 계속 연결이 쌓여서
    			// 반드시 사용한 자원을 닫아줘야한다
    			conn.close();
    		} catch (Exception e) {
    			// 자바의 OOP 4대 특성 중 다형성을 이용해서
    			// 모든 예외를 처리했다
    			e.printStackTrace();
    		}
    		// 5. 만능 열쇠(Connection)를 반납해야 한다
    		return success;
    	}
    }

     

     

    HomeController -> HomeService -> HomeDAO -> HomeService -> HomeController 으로 순서가 진행된다

    직접 한번 흐름을 따라가보자


     

    Connection Pool

    예제를 통해 커넥션을 사용한것은 하나씩 만들어서 쓰는것이였다

    하지만 효율적으로 하기 위해서는 미리 만들어둔 커넥션을 쓰는것이 효율적이다

    예제

    방금 설명한 커넥션 풀을 사용하기 위해 외부에서 라이브러리를 다운로드 받아야한다 하지만 라이브러리를 다운로드 받기 위해서는 pom.xml 에 라이브러리를 설치하는 코드를 넣어줘야한다

    https://central.sonatype.com/

     

     

    Maven Central

    Official search by the maintainers of Maven Central Repository.

    central.sonatype.com

    위 링크의 사이트에서 commons-dbcp 를 검색 한후

     

    사이트에서 라이브러리를 다운로드하는 코드를 복사해주고 

     

    pom.xml 에 붙여 넣어주면 된다

     

     

    <Resource
        name="jdbc/MariaDB"
        auth="Container"
        type="javax.sql.DataSource"
        driverClassName="org.mariadb.jdbc.Driver"
        url="jdbc:mariadb://localhost:3306/mydb"
        username="web_user"
        password="pass"
    />

    이 내용을 context.xml 에 입력해주면 된다

    	/*
    	<Resource
    		name="jdbc/MariaDB" <- 호출할 이름
    		auth="Container" <- 제어를 누가 할 것인가(톰캣|Spring|개발자)
    		type="javax.sql.DataSource" <- xml 의 태그를 자바의 어떤 데이터 타입으로 변경할것 인가?
    		driverClassName="org.mariadb.jdbc.Driver" 
    		url="jdbc:mariadb://localhost:3306/mydb"
    		username="web_user"
    		password="pass"
    	/>
    	 * xml 파일의 내용을 자바 데이터 형태로 바꾸는 작업이다
    	*/
    	public boolean poolConnect() {
    		boolean success = false;
    		try {
    			// 1. context.xml 을 자바 객체로 변환한다
    			Context ctx = new InitialContext();
    			// 2. Resource 태그를 이름으로 검색해서 찾아온다 -> java 형태(javax.sql.DataSource)로 변환한다
    			// java:comp/env/ 자바 환경은
    			// jdbc/MariaDB 으로 사용할거야
    			// lookup의 반환 형태는 Object 형태이므로 자식의 기능과 속성을 쓸려면 캐스팅해줘야한다
    			DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/MariaDB");
    			// 3. 커넥션을 불러온다
    			Connection conn = ds.getConnection();
    			logger.info("pool connection : " + conn);
    			// 1213687881, URL=jdbc:mariadb://localhost:3306/mydb, MariaDB Connector/J
    			if (conn != null) {
    				success = true;
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return success;
    	}

    코드리뷰

    HomeController.java
    
    @Controller
    public class HomeController {
    	
    	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);	
    
    	// /pool 요청이 들어오면
    	@RequestMapping(value = "/pool")
    	public String pool(Model model) {
    		// 요청이 들어왔는지 logger로 확인 
    		logger.info("/pool - Connection Pool 접속 요청");
    		// service 의 poolConnect 메소드를 사용하기 위해 객체를 생성
    		HomeService service = new HomeService();
    		// msg 는 성공, 실패 여부의 메시지를 service로부터 전달받는다
    		String msg = service.poolConnect();
    		// msg 파라미터에 메시지를 담아서 jsp 파일에 전달해준다 
    		model.addAttribute("msg", msg);
    		return "index";
    	}
    }
    
    HomeService.java
    
    public class HomeService {
    	// 현재 클래스가 서버에 로그를 출력하는 메서드이다
    	private static final Logger logger = LoggerFactory.getLogger(HomeService.class);	
    
    	public String poolConnect() {
    		// 성공 실패 여부를 담는 변수의 기본값을 실패로 설정한다
    		String msg = "DB 연결에 실패했습니다";
    		// dao 객체 생성
    		HomeDAO dao = new HomeDAO();
    		// dao.poolConnect() 는 성공 여부를 true false 로 반환해주므로
    		// 성공하면 메시지를 바꾸어준다
    		if (dao.poolConnect()) {
    			msg = "DB 연결에 성공했습니다";
    		}
    		// 성공 실패 메시지를 반환해준다
    		return msg;
    	}
    }
    
    HomeDAO.java
    
    public class HomeDAO {
    	private static final Logger logger = LoggerFactory.getLogger(HomeDAO.class);
    	/*
    	<Resource
    		name="jdbc/MariaDB" <- 호출할 이름
    		auth="Container" <- 제어를 누가 할 것인가(톰캣|Spring|개발자)
    		type="javax.sql.DataSource" <- xml 의 태그를 자바의 어떤 데이터 타입으로 변경할것 인가?
    		driverClassName="org.mariadb.jdbc.Driver" 
    		url="jdbc:mariadb://localhost:3306/mydb"
    		username="web_user"
    		password="pass"
    	/>
    	 * xml 파일의 내용을 자바 데이터 형태로 바꾸는 작업이다
    	*/
    	public boolean poolConnect() {
    		// DB 접속 여부의 기본값을 false 로 두고
    		boolean success = false;
    		try {
    			// xml 파일을 자바의 Context 형태인 객체로 가져온다 
    			Context ctx = new InitialContext();
    			
    			// 2. Resource 태그를 이름을 사용해서 찾아온다
    			// -> javax.sql.DataSource 형태로 변환한다 왜냐하면 resource에 적혀있음
    	        // 하지만 Object 형태이기 때문에 DataSource로 형변환을해서 ds에 값을 담아준다
    			DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/MariaDB");
    			// ds 객체에 담긴 정보들을 통해 db에 연결 시도한다
    			Connection conn = ds.getConnection();
    			logger.info("pool connection : " + conn);
    			// 연결 성공하면 
    			if (conn != null) {
    				// success 를 true 로 바꾸고
    				success = true;
    				// 4. 자원 반납
    				conn.close();
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		// 메소드는 성공여부 결과를 반환해줍니다
    		return success;
    	}
    }
    
    index.jsp
    
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    	<h1>코드 리뷰</h1>
    	<!-- msg 파라미터로 전달받은 메시지를 출력한다 -->
    	Connection Pool 에 접속 성공 여부 : ${msg} <!-- model 에서 보내온 msg 값 -->
    </body>
    </html>

     

    '백엔드(웹 서버, WAS) > Spring' 카테고리의 다른 글

    41일차 - 게시판 구현 & 문제  (0) 2024.03.20
    39,40일차 - Mybatis  (0) 2024.03.19
    38일차-회원 가입 시스템 구현  (0) 2024.03.15
    37일차 - 자바에서 DB 연결  (0) 2024.03.14
    35일차-JSTL TAG  (0) 2024.03.12
Designed by Tistory.