728x90
300x250

[Spring-F.] 29. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법5(SqlMap Spring전용)


소스 코드 위주로 소개하겠다.


[실험 결과]

1. [Spring-Framework] Spring Framework 5.4, MyBatis 3.5 연동 방법 - 실험 결과, 2020-10-02

   - https://yyman.tistory.com/1437


[이전 게시글]

1. [Spring-F.] 28. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법4(SqlMap Spring전용)

   - https://yyman.tistory.com/1441



41. 결과


XML 방식의 XML Mapping으로 구성하여 동작한 결과이다.



그림 25. 결과 5번



그림 26. 프로젝트 구성도



42. web.xml - 기본값


web.xml 파일은 변경하지 않았다.


<?xml version="1.0" encoding="UTF-8"?>


<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_3_1.xsd"

version="3.1">


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<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>





43. com.example.spbatis.db - SqlMapSessionFactory.java


package com.example.spbatis.db;



import java.io.IOException;

import java.io.InputStream;

import java.sql.SQLException;


import javax.sql.DataSource;


import org.apache.ibatis.io.Resources;

import org.apache.ibatis.mapping.Environment;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.apache.ibatis.transaction.TransactionFactory;

import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import org.mybatis.spring.SqlSessionFactoryBean;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;


import com.example.spbatis.model.CompUsers;


import oracle.jdbc.pool.OracleDataSource;


public class SqlMapSessionFactory {


private static SqlMapSessionFactory factory = new SqlMapSessionFactory();

private final static String driverName = "oracle.jdbc.driver.OracleDriver";

private final static String dbUrl = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";

private final static String userName = "사용자계정명";

private final static String userPassword = "비밀번호";

public static SqlSessionFactory ssf;


public static SqlMapSessionFactory getInstance() {

return factory;

}

private SqlMapSessionFactory () {    }

static {

/* 방법1

DataSource dataSource = getOracleDataSource();

TransactionFactory transactionFactory = new JdbcTransactionFactory();

Environment environment = new Environment("development", transactionFactory, dataSource);

Configuration configuration = new Configuration(environment);

configuration.addMapper(CompUsersMapper.class);

ssf = new SqlSessionFactoryBuilder().build(configuration);

*/

}

    

    public static SqlSessionFactory getSqlSessionFactory(){

   


/* 방법2: 공식 메뉴얼 참고 */

DataSource dataSource = getOracleDataSource();


SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); // Spring Framework만 지원

factoryBean.setDataSource(dataSource);

try {

//쿼리가 정의된 xml 파일들의 위치 지정

        factoryBean.setMapperLocations(

                new PathMatchingResourcePatternResolver().getResources("com/example/spbatis/mapper/*.xml")

        );

    

ssf = factoryBean.getObject();

// 클래스 등록

// ssf.getConfiguration().addMapper(CompUsersMapper.class);

} catch (Exception e) {

e.printStackTrace();

}

   

    // 방법 1, 방법 2 공통

        return ssf;

    }

    

    /*

* Description: 순정 오라클 데이터소스

*/

    private static DataSource getOracleDataSource(){


    OracleDataSource oracleDS = null;


    try {

            oracleDS = new OracleDataSource();

            oracleDS.setURL(dbUrl);

            oracleDS.setUser(userName);

            oracleDS.setPassword(userPassword);


        } catch (SQLException e) {

            e.printStackTrace();

        }


        return oracleDS;


    }

    

}



파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip




44. com.example.spbatis.mapper - CompUsersMapper.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.example.spbatis.mapper">


<select id="allCompUsers" resultType="com.example.spbatis.model.CompUsers">

select * from comp_users

</select>

<!-- 

<select id="allAddress" resultType="com.edu.db.AddressDto">

select * from addressbook

</select>

<select id="selectAddress" parameterType="Integer" resultType="com.edu.db.AddressDto">

select NUM, NAME, ADDRESS, BIRTHDATE

from addressbook

  where num=#{num}

</select>

<insert id="insertAddress" parameterType="com.edu.db.AddressDto">

insert into

addressbook(NAME, ADDRESS, BIRTHDATE)

values

(#{name},#{address},#{birthdate})

</insert>

<delete id="deleteAddress" parameterType="Integer">

DELETE FROM AddressBook

WHERE NUM = #{num}

</delete>

<update id="updateAddress" parameterType="com.edu.db.AddressDto" >

update addressbook

set birthdate = #{birthdate}, name = #{name}, address =#{address}

where num = #{num}

</update>

 -->

</mapper>


파일명: CompUsersMapper.xml


[첨부(Attachments)]

CompUsersMapper.zip





45. com.example.spbatis.dao - CompUsersDao.java


package com.example.spbatis.dao;


import java.util.List;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;


import com.example.spbatis.db.SqlMapSessionFactory;

import com.example.spbatis.model.CompUsers;



public class CompUsersDao {


    SqlSessionFactory factory = SqlMapSessionFactory.getSqlSessionFactory();

    

    public CompUsersDao() {

        

    }

    

    // SQL 세션 열기

    public List<CompUsers> selectAddress() {


    List<CompUsers> user = null;

try (SqlSession session = factory.openSession()) {

 

user = session.selectList("com.example.spbatis.mapper.allCompUsers");

session.close();

// System.out.println("계정명:" + user.getUsername());


}

return user;


    }

    

}



파일명: CompUsersDao.java


[첨부(Attachments)]

CompUsersDao.zip





46. com.example.spbatis.service - CompUsersService.java


package com.example.spbatis.service;


import java.util.List;


import com.example.spbatis.dao.CompUsersDao;

import com.example.spbatis.model.CompUsers;


public class CompUsersService {


private CompUsersDao dao = null;

public CompUsersService() {

dao = new CompUsersDao();

}

public List<CompUsers> getAllCompUsers() {

return dao.selectAddress();

}

 

}



파일명: CompUsersService.java


[첨부(Attachments)]

CompUsersService.zip




47. com.example.spbatis - HomeController.java


package com.example.spbatis;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

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 org.springframework.web.bind.annotation.RequestMethod;


import com.example.spbatis.service.CompUsersService;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

private CompUsersService compUserService;

@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home5 - Java(XML Mappers)! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

compUserService = new CompUsersService();

model.addAttribute("serverTime", formattedDate );

model.addAttribute("list", compUserService.getAllCompUsers()) ;

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController.zip





48. view - home.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page session="false" %>


<html>

<head>

<title>Home</title>

</head>

<body>

<h1>

Hello world!  

</h1>


<P>  The time on the server is ${serverTime}. </P>

<h3>SqlMapSessionFactory 방식(Java - XML Mapper - Spring 전용 버전)</h3>

<c:forEach items="${list }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list }">

    ${"데이터가 존재하지않아요."}

</c:if>


</body>

</html>



파일명: home.jsp


[첨부(Attachments)]

home.zip



* 맺음글(Conclusion)


조금 작성하는데 힘이 들었지만. MyBatis 하나 셋팅에는 다양한 방법이 지원된다는 것을 알 수 있었다.



* 참고 자료(References)


1. mybatis-spring - 마이바티스 스프링 연동모듈 | 시작하기, https://mybatis.org/spring/ko/getting-started.html, Accessed by 2020-10-02, Last Modified 2020-06-05.

   [비고] - 공식 사이트이다. (이 메뉴얼만 가지고는 다 안 될 수도 있다.)


2. 스프링프레임워크 Java config로 MyBatis 사용하기, https://offbyone.tistory.com/381, Accessed by 2020-10-02, Last Modified 2019-03-17.


3. [mybatis] 다중 Database Setting, https://wfreud.tistory.com/310, Accessed by 2020-10-02, Last Modified 2019-03-21.


4. maven프로젝트 src/main/resource경로의 파일 읽기, https://blog.naver.com/down83/50092131189, Accessed by 2020-10-02, Last Modified 2010-07-13.


5. MyBatis List와 Map으로 데이터 불러오기, https://smujihoon.tistory.com/112, Accessed by 2020-10-02, Last Modified 2019-02-11.


5. [Mybatis] root-context.xml 자료(Oracle), https://datamod.tistory.com/81, Accessed by 2020-10-02, Last Modified 2018-05-20.


6. 7. 공용 클래스 작성 - commonDAo, https://tapasnote.tistory.com/21?category=697717, Accessed by 2020-10-02, Last Modified 2017-04-12.


7. DatsSource, 커넥션 풀을 이용한 DB 연결, https://m.blog.naver.com/PostView.nhn?blogId=2hyoin&logNo=220647895962, Accessed by 2020-10-02, Last Modified 2016-03-07.


8. MyBatis tutorial - Introductory MyBatis tutorial, http://zetcode.com/db/mybatis/, Accessed by 2020-10-02, Last Modified 2020-07-06.

   [영어 사이트]


반응형
728x90
300x250

[Spring-F.] 28. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법4(SqlMap Spring전용)


소스 코드 위주로 소개하도록 하겠다.


[실험 결과]

1. [Spring-Framework] Spring Framework 5.4, MyBatis 3.5 연동 방법 - 실험 결과, 2020-10-02

   - https://yyman.tistory.com/1437


[이전 게시글]

1. [Spring-F.] 27. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법3(SqlMap-XML-Class)     // 결과: 지원, 2020-10-02

    - https://yyman.tistory.com/1440



33. 결과


작업한 내용을 출력한 결과는 다음과 같다.



그림 23. 결과 모습(Java 방식) - XML Mapper - Spring Beans 객체 방식 적용 (Spring 전용)



그림 24. 프로젝트 구성도




34. web.xml (기본값) - 변동없음


<?xml version="1.0" encoding="UTF-8"?>


<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_3_1.xsd"

version="3.1">


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<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>





35. com.example.spbatis.db - SqlMapSessionFactory.java


package com.example.spbatis.db;



import java.io.IOException;

import java.io.InputStream;

import java.sql.SQLException;


import javax.sql.DataSource;


import org.apache.ibatis.io.Resources;

import org.apache.ibatis.mapping.Environment;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.apache.ibatis.transaction.TransactionFactory;

import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import org.mybatis.spring.SqlSessionFactoryBean;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;


import com.example.spbatis.mapper.CompUsersMapper;

import com.example.spbatis.model.CompUsers;


import oracle.jdbc.pool.OracleDataSource;


public class SqlMapSessionFactory {


private static SqlMapSessionFactory factory = new SqlMapSessionFactory();

private final static String driverName = "oracle.jdbc.driver.OracleDriver";

private final static String dbUrl = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";

private final static String userName = "사용자계정";

private final static String userPassword = "비밀번호";

public static SqlSessionFactory ssf;


public static SqlMapSessionFactory getInstance() {

return factory;

}

private SqlMapSessionFactory () {    }

static {

/* 방법1

DataSource dataSource = getOracleDataSource();

TransactionFactory transactionFactory = new JdbcTransactionFactory();

Environment environment = new Environment("development", transactionFactory, dataSource);

Configuration configuration = new Configuration(environment);

configuration.addMapper(CompUsersMapper.class);

ssf = new SqlSessionFactoryBuilder().build(configuration);

*/

}

    

    public static SqlSessionFactory getSqlSessionFactory(){

   


/* 방법2: 공식 메뉴얼 참고 */

DataSource dataSource = getOracleDataSource();


SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); // Spring Framework만 지원

factoryBean.setDataSource(dataSource);

try {

//쿼리가 정의된 xml 파일들의 위치 지정

/*

        factoryBean.setMapperLocations(

                new PathMatchingResourcePatternResolver().getResources("com/example/spbatis/mapper/*.xml")

        );

        */

    

ssf = factoryBean.getObject();

// 클래스 등록

ssf.getConfiguration().addMapper(CompUsersMapper.class);

} catch (Exception e) {

e.printStackTrace();

}

   

    // 방법 1, 방법 2 공통

        return ssf;

    }

    

    /*

* Description: 순정 오라클 데이터소스

*/

    private static DataSource getOracleDataSource(){


    OracleDataSource oracleDS = null;


    try {

            oracleDS = new OracleDataSource();

            oracleDS.setURL(dbUrl);

            oracleDS.setUser(userName);

            oracleDS.setPassword(userPassword);


        } catch (SQLException e) {

            e.printStackTrace();

        }


        return oracleDS;


    }

    

}



파일명: SqlSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip





36. com.example.spbatis.mapper - CompUsersMapper.java


package com.example.spbatis.mapper;


import java.util.List;


import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Select;


import com.example.spbatis.model.CompUsers;


@Mapper

public interface CompUsersMapper {

@Select("SELECT * FROM comp_users")

List<CompUsers> selectAll();

}


파일명: CompUsersMapper.java


[첨부(Attachments)]

CompUsersMapper.zip





37. com.example.spbatis.dao - CompUsersDao.java


package com.example.spbatis.dao;


import java.util.List;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

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


import com.example.spbatis.db.SqlMapSessionFactory;

import com.example.spbatis.mapper.CompUsersMapper;

import com.example.spbatis.model.CompUsers;



public class CompUsersDao {


    SqlSessionFactory factory = SqlMapSessionFactory.getSqlSessionFactory();

    

    public CompUsersDao() {

        

    }

    

    // SQL 세션 열기

    public List<CompUsers> selectAddress() {


    List<CompUsers> user = null;

try (SqlSession session = factory.openSession()) {

CompUsersMapper mapper = session.getMapper(CompUsersMapper.class);

user = mapper.selectAll();

// System.out.println("계정명:" + user.getUsername());


}

return user;


    }

    

}



파일명: CompUsersDao.java


[첨부(Attachments)]

CompUsersDao.zip





38. com.example.spbatis.service - CompUsersService.java


package com.example.spbatis.service;


import java.util.List;


import com.example.spbatis.dao.CompUsersDao;

import com.example.spbatis.model.CompUsers;


public class CompUsersService {


private CompUsersDao dao = null;

public CompUsersService() {

dao = new CompUsersDao();

}

public List<CompUsers> getAllCompUsers() {

return dao.selectAddress();

}

 

}



파일명: CompUsersService.java


[첨부(Attachments)]

CompUsersService.zip





39. com.example.spbatis - HomeController.java


package com.example.spbatis;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

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 org.springframework.web.bind.annotation.RequestMethod;


import com.example.spbatis.service.CompUsersService;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

private CompUsersService compUserService;

@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home4(Class Mappers) - Java! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

compUserService = new CompUsersService();

model.addAttribute("serverTime", formattedDate );

model.addAttribute("list", compUserService.getAllCompUsers()) ;

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController.zip



40. View - Home.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page session="false" %>


<html>

<head>

<title>Home</title>

</head>

<body>

<h1>

Hello world!  

</h1>


<P>  The time on the server is ${serverTime}. </P>

<h3>SqlMapSessionFactory 방식(Java - Mapper - Spring 전용 버전)</h3>

<c:forEach items="${list }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list }">

    ${"데이터가 존재하지않아요."}

</c:if>


</body>

</html>



파일명: home.jsp


[첨부(Attachments)]

home.zip




* 5부에서 만나요.


1. [Spring-F.] 29. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법5(SqlMap Spring전용)  // 결과: 지원, 2020-10-02

    - https://yyman.tistory.com/1442



반응형
728x90
300x250

[Spring-F.] 27. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법3(SqlMap-XML-Class)


소스 코드 위주로 소개하도록 하겠다.


[실험 결과]

1. [Spring-Framework] Spring Framework 5.4, MyBatis 3.5 연동 방법 - 실험 결과, 2020-10-02

   - https://yyman.tistory.com/1437


[이전 게시글]

1. [Spring-F.] 26. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법2(SqlMap-XML-XML 맵핑)     // 결과: 지원, 2020-10-02

    - https://yyman.tistory.com/1439



24. 결과


완성된 실험 결과이다.



그림 21. 결과



그림 22. 프로젝트 구성도




25. web.xml - 기본값(변동 없음)


<?xml version="1.0" encoding="UTF-8"?>


<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_3_1.xsd"

version="3.1">


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<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>




26. view - home.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page session="false" %>


<html>

<head>

<title>Home</title>

</head>

<body>

<h1>

Hello world!  

</h1>


<P>  The time on the server is ${serverTime}. </P>

<h3>SqlMapSessionFactory 방식(XML - 환경설정 - 클래스-Mappers)</h3>

<c:forEach items="${list }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list }">

    ${"데이터가 존재하지않아요."}

</c:if>


<h3>XML - web.xml 설정방식</h3>

<c:forEach items="${list2 }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list2 }">

    ${"데이터가 존재하지않아요."}

</c:if>


</body>

</html>



파일명: home.jsp


[첨부(Attachments)]

home.zip




27. com.example.spbatis.db - SqlMapSessionFactory.java


package com.example.spbatis.db;



import java.io.IOException;

import java.io.InputStream;


import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;


import com.example.spbatis.mapper.CompUsersMapper;


public class SqlMapSessionFactory {

public SqlSessionFactory ssf;

public SqlMapSessionFactory () {


        String resource = "com/example/spbatis/mapper/mybatis-config.xml";

        InputStream is = null;


        try {

            is = Resources.getResourceAsStream(resource);

        } catch (IOException e) {

            e.printStackTrace();

        }


        ssf = new SqlSessionFactoryBuilder().build(is);

        ssf.getConfiguration().addMapper(CompUsersMapper.class);


    }

    

    public SqlSessionFactory getSqlSessionFactory(){

        return ssf;

    }

    

}



파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip





28. com.example.spbatis.mapper - 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>


<environments default="development">

    <environment id="development">

      <transactionManager type="JDBC"/>

      <!-- 커넥션 풀(MyBatis) -->

      <dataSource type="POOLED">

        <property name="driver" value="oracle.jdbc.driver.OracleDriver" />

        <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>

        <property name="username" value="UserName"/>

        <property name="password" value="Password"/>

        <property name="poolMaximumActiveConnections" value="20"/>

        <property name="poolMaximumIdleConnections" value="20"/>

        <property name="poolMaximumCheckoutTime" value="20000"/>

        <property name="poolPingEnabled" value="true"/>

        <property name="poolPingQuery" value="select 1"/>

        <property name="poolPingConnectionsNotUsedFor" value="10000"/>

        <property name="poolTimeToWait" value="15000"/>

      </dataSource>

    </environment>

</environments>


</configuration>


파일명: mybatis-config.xml


[첨부(Attachments)]

mybatis-config.zip




29. com.example.spbatis.mapper - CompUsersMapper.java


package com.example.spbatis.mapper;


import java.util.List;


import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Select;


import com.example.spbatis.model.CompUsers;


@Mapper

public interface CompUsersMapper {

@Select("SELECT * FROM comp_users")

List<CompUsers> selectAll();

}


파일명: CompUsersMapper.java


[첨부(Attachments)]

CompUsersMapper.zip




30. com.example.spbatis.dao - CompUsersDao.java


package com.example.spbatis.dao;


import java.util.List;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

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


import com.example.spbatis.db.SqlMapSessionFactory;

import com.example.spbatis.mapper.CompUsersMapper;

import com.example.spbatis.model.CompUsers;



public class CompUsersDao {

    private SqlMapSessionFactory ssfc;

    private SqlSessionFactory factory;

    

    public CompUsersDao() {

   

        ssfc = new SqlMapSessionFactory();

        factory = ssfc.getSqlSessionFactory();

        

    }

    

    // SQL 세션 열기

    public List<CompUsers> selectAddress() {


    List<CompUsers> user = null;

   

try (SqlSession session = factory.openSession()) {

CompUsersMapper mapper = session.getMapper(CompUsersMapper.class);

user = mapper.selectAll();

// System.out.println("계정명:" + user.getUsername());


}

return user;


    }

    

}



파일명: CompUsersDao.java


[첨부(Attachments)]

CompUsersDao.zip





31. com.example.spbatis.service - CompUsersService.java


package com.example.spbatis.service;


import java.util.List;


import com.example.spbatis.dao.CompUsersDao;

import com.example.spbatis.model.CompUsers;


public class CompUsersService {


private CompUsersDao dao = null;

public CompUsersService() {

dao = new CompUsersDao();

}

public List<CompUsers> getAllCompUsers() {

return dao.selectAddress();

}

 

}



파일명: CompUsersService.java


[첨부(Attachments)]

CompUsersService.zip





32. com.example.spbatis - HomeController.java


package com.example.spbatis;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

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 org.springframework.web.bind.annotation.RequestMethod;


import com.example.spbatis.service.CompUsersService;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

private CompUsersService compUserService;

@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home3! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

compUserService = new CompUsersService();

model.addAttribute("serverTime", formattedDate );

model.addAttribute("list", compUserService.getAllCompUsers()) ;

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController.zip



* 4부에서 만나요.


1. [Spring-F.] 28. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법4(SqlMap Spring전용)   // 결과: 지원, 2020-10-02

https://yyman.tistory.com/1441


반응형
728x90
300x250

[Spring-F.] 26. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법2(SqlMap-XML-XML 맵핑)


소스 코드 위주로 소개하도록 하겠다.


[실험 결과]

1. [Spring-Framework] Spring Framework 5.4, MyBatis 3.5 연동 방법 - 실험 결과, 2020-10-02

https://yyman.tistory.com/1437


[이전 게시글]

1. [Spring-F.] 25. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법1(web.xml-Beans), 2020-10-02

https://yyman.tistory.com/1438



15. 결과


2번째 실험에 대한 결과이다.



그림 19. 동작 결과



그림 20. 프로젝트 구성도


완성한 프로젝트의 구성도이다. 소스코드를 작성하는데 참고하면 도움이 될 것으로 보인다.



16. web.xml - 설정 (기본값)


기본값 소스코드로 두었다.


<?xml version="1.0" encoding="UTF-8"?>


<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_3_1.xsd"

version="3.1">


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<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>





17. view - home.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page session="false" %>


<html>

<head>

<title>Home</title>

</head>

<body>

<h1>

Hello world!  

</h1>


<P>  The time on the server is ${serverTime}. </P>

<h3>SqlMapSessionFactory 방식(XML - 환경설정 - XML-Mappers)</h3>

<c:forEach items="${list }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list }">

    ${"데이터가 존재하지않아요."}

</c:if>


<h3>XML - web.xml 설정방식</h3>

<c:forEach items="${list2 }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list2 }">

    ${"데이터가 존재하지않아요."}

</c:if>


</body>

</html>



파일명: home.jsp


[첨부(Attachments)]

home.zip




18. com.example.spbatis.mapper - mybatis-config.xml


Spring Boot가 아닌 이상, 참고로 해당 위치에 xml파일을 넣어줘야 한다.
예를 들면, the.getClass().getResources() 이런 함수를 활용해서 /src/main/resources 폴더를 생성하고 작업을 시도하려고 한다면, 

실패할 것이다. 운이 좋아서 경로를 찾아서 빌드했을 때 동작이 되었다고 해도, 톰캣 서버에 올려버리면 경로를 못 찾아버리는 현상이 발생한다.


충분히 시간을 가지고, 태스트를 거친 후에 작성한 글이다.


<?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>


<environments default="development">

    <environment id="development">

      <transactionManager type="JDBC"/>

      <!-- 커넥션 풀(MyBatis) -->

      <dataSource type="POOLED">

        <property name="driver" value="oracle.jdbc.driver.OracleDriver" />

        <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>

        <property name="username" value="UserName"/>

        <property name="password" value="Password"/>

        <property name="poolMaximumActiveConnections" value="20"/>

        <property name="poolMaximumIdleConnections" value="20"/>

        <property name="poolMaximumCheckoutTime" value="20000"/>

        <property name="poolPingEnabled" value="true"/>

        <property name="poolPingQuery" value="select 1"/>

        <property name="poolPingConnectionsNotUsedFor" value="10000"/>

        <property name="poolTimeToWait" value="15000"/>

      </dataSource>

    </environment>

</environments>


<mappers>

  <mapper resource="com/example/spbatis/mapper/CompUsersMapper.xml"/>

</mappers>


</configuration>


파일명: mybatis-config.xml


[첨부(Attachments)]

mybatis-config.zip





19. com.example.spbatis.mapper - CompUsersMapper.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.example.spbatis.mapper">


<select id="allCompUsers" resultType="com.example.spbatis.model.CompUsers">

select * from comp_users

</select>

<!-- 

<select id="allAddress" resultType="com.edu.db.AddressDto">

select * from addressbook

</select>

<select id="selectAddress" parameterType="Integer" resultType="com.edu.db.AddressDto">

select NUM, NAME, ADDRESS, BIRTHDATE

from addressbook

  where num=#{num}

</select>

<insert id="insertAddress" parameterType="com.edu.db.AddressDto">

insert into

addressbook(NAME, ADDRESS, BIRTHDATE)

values

(#{name},#{address},#{birthdate})

</insert>

<delete id="deleteAddress" parameterType="Integer">

DELETE FROM AddressBook

WHERE NUM = #{num}

</delete>

<update id="updateAddress" parameterType="com.edu.db.AddressDto" >

update addressbook

set birthdate = #{birthdate}, name = #{name}, address =#{address}

where num = #{num}

</update>

 -->

</mapper>


파일명: CompUsersMapper.xml


[첨부(Attachments)]

CompUsersMapper.zip




20. com.example.spbatis.db - SqlMapSessionFactory.java


package com.example.spbatis.db;



import java.io.IOException;

import java.io.InputStream;


import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;


public class SqlMapSessionFactory {

public SqlSessionFactory ssf;

public SqlMapSessionFactory () {


        String resource = "com/example/spbatis/mapper/mybatis-config.xml";

        InputStream is = null;


        try {

            is = Resources.getResourceAsStream(resource);

        } catch (IOException e) {

            e.printStackTrace();

        }


        ssf = new SqlSessionFactoryBuilder().build(is);


    }

    

    public SqlSessionFactory getSqlSessionFactory(){

        return ssf;

    }

    

}



파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip




21. com.example.spbatis.dao - CompUsersDao.java


package com.example.spbatis.dao;


import java.util.List;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

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


import com.example.spbatis.db.SqlMapSessionFactory;

import com.example.spbatis.model.CompUsers;



public class CompUsersDao {

    private SqlMapSessionFactory ssfc;

    private SqlSessionFactory factory;

    

    public CompUsersDao() {

   

        ssfc = new SqlMapSessionFactory();

        factory = ssfc.getSqlSessionFactory();

        

    }

    

    // SQL 세션 열기

    public List<CompUsers> selectAddress() {


        SqlSession session = factory.openSession();


        List<CompUsers> compDTO = session.selectList("com.example.spbatis.mapper.allCompUsers");

        session.close();

        return compDTO;


    }

    

}



파일명: CompUsersDao.java


[첨부(Attachments)]

CompUsersDao.zip




22. com.example.spbatis.service - CompUsersService.java


package com.example.spbatis.service;


import java.util.List;


import com.example.spbatis.dao.CompUsersDao;

import com.example.spbatis.model.CompUsers;


public class CompUsersService {


private CompUsersDao dao = null;

public CompUsersService() {

dao = new CompUsersDao();

}

public List<CompUsers> getAllCompUsers() {

return dao.selectAddress();

}

 

}



파일명: CompUsersService.java


[첨부(Attachments)]

CompUsersService.zip




23. com.example.spbatis - HomeController.java


package com.example.spbatis;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

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 org.springframework.web.bind.annotation.RequestMethod;


import com.example.spbatis.service.CompUsersService;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

private CompUsersService compUserService;

@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home2! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

compUserService = new CompUsersService();

model.addAttribute("serverTime", formattedDate );

model.addAttribute("list", compUserService.getAllCompUsers()) ;

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController.zip



* 방법 3에 대한 글로 이동하기


3. [Spring-F.] 27. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법3(SqlMap-XML-Class)

https://yyman.tistory.com/1440


반응형
728x90
300x250

[Spring-F.] 25. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법1(web.xml-Beans)


MyBatis 3.5 - 연동 방법에 관한 글을 시작하겠다.


1. [Spring-Framework] Spring Framework 5.4, MyBatis 3.5 연동 방법 - 실험 결과, 2020-10-02

https://yyman.tistory.com/1437


소스코드를 위주로 소개하겠다.


동작되지 않은 소스이지만, 분석해보고 싶은 사람들을 위해서 소스코드를 공개하도록 하겠다.



7. 방법 1 - 출력 결과


결과는 동작하지 않았다.



그림 14. 결과 (방법1) - 미지원



8. 프로젝트 구성


프로젝트는 아래처럼 구성하였다.




그림 15, 그림 16. 프로젝트 구성 모습



9. web.xml 


<?xml version="1.0" encoding="UTF-8"?>


<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_3_1.xsd"

version="3.1">


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

/WEB-INF/spring/root-context.xml

/WEB-INF/spring/mybatis-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>



파일명: web.xml


[첨부(Attachments)]

web.zip





10. mybatis-context.xml (없는 파일 - 생성해줘야 함)


셋팅 파일의 경로에 관한 것이다. /src/main/java/webapp/WEB-INF/spring 폴더 내에 만들어줘야 한다.



그림 17. mybatis-context.xml의 위치



<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:jdbc="http://www.springframework.org/schema/jdbc"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 현재는 빈(Bean) 등록 방식 미지원함(2020-10-02 / Spring Framework 5 이상) -->

<!-- org.apache.ibatis.datasource.pooled.PooledDataSource -->

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>

<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>

<property name="username" value="사용자계정"/>

<property name="password" value="비밀번호"/>

</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="configLocation" value="/WEB-INF/mybatis-config.xml"/>

<property name="mapperLocations" value="classpath:com/example/spbatis/mapper/*.xml" />

    </bean>

<!-- 

<property name="mapperLocations" value="classpath:com/think/mapper/**/*.xml" />

        <property name="mapperLocations" value="/WEB-INF/mybatis/mapper/*.xml" />

-->

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">

<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>

</bean>

</beans> 


파일명: mybatis-context.xml


[첨부(Attachments)]

mybatis-context.zip




10. mybatis-config.xml (없는 파일 - 생성해줘야 함)


mybatis-config.xml의 위치이다.

/src/main/webapp에 생성해주면 된다.



그림 18. 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>

<settings>

<setting name="cacheEnabled" value="false" />

<setting name="useGeneratedKeys" value="true" />

<setting name="defaultExecutorType" value="REUSE" />

</settings>


<!-- 별명 -->

    <typeAliases>

         <typeAlias alias="hashMap" type="java.util.HashMap" />

         <typeAlias alias="map" type="java.util.Map" />

    </typeAliases>


<!--

<mappers>

<mapper resource="mybatis/mapper/tempMapper.xml" />

</mappers>

<mappers>

<mapper resource="mybatis/mapper/bbsMapper.xml" />

</mappers>

-->

</configuration>



파일명: mybatis-config.xml


[첨부(Attachments)]

mybatis-config.xml





11. view - home.jsp


경로: /src/main/webapp/WEB-INF/views/home.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page session="false" %>


<html>

<head>

<title>Home</title>

</head>

<body>

<h1>

Hello world!  

</h1>


<P>  The time on the server is ${serverTime}. </P>

<h3>Beans 방식(XML)</h3>

<c:forEach items="${list }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list }">

    ${"데이터가 존재하지않아요."}

</c:if>


<h3>XML - web.xml 설정방식</h3>

<c:forEach items="${list2 }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list2 }">

    ${"데이터가 존재하지않아요."}

</c:if>


</body>

</html>



파일명: home.jsp


[첨부(Attachments)]

home.zip



11. Controller - HomeController.java


패키지 경로: com.example.spbatis;


package com.example.spbatis;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

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 org.springframework.web.bind.annotation.RequestMethod;


import com.example.spbatis.service.CompUsersService;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

private CompUsersService compUserService;

@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

compUserService = new CompUsersService();

model.addAttribute("serverTime", formattedDate );

model.addAttribute("list2", compUserService.getAllCompUsers()) ;

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController.zip



12. Service - CompUsersService.java


패키지 경로: com.example.spbatis.service


package com.example.spbatis.service;


import java.util.List;


import com.example.spbatis.dao.CompUsersDao;

import com.example.spbatis.model.CompUsers;


public class CompUsersService {


CompUsersDao dao = new CompUsersDao();

public List<CompUsers> getAllCompUsers() {

return dao.selectAddress();

}

 

}



파일명: CompUsersService.java


[첨부(Attachments)]

CompUsersService.zip




13. DAO - CompUsersDao.java


패키지 경로: com.example.spbatis.dao


package com.example.spbatis.dao;


import java.util.List;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.mybatis.spring.SqlSessionTemplate;

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

import org.springframework.stereotype.Component;


import com.example.spbatis.model.CompUsers;


@Component

public class CompUsersDao {

/* 동작 안함1

    @Autowired

    private SqlSessionFactory sqlSessionFactory;

*/

/* 동작 안함2 */

@Autowired

private SqlSession sqlSession;

/* */

    public CompUsersDao() {

   

    }

    

    // SQL 세션 열기

    public List<CompUsers> selectAddress() {

   

    /* 동작 안함2 */

    return sqlSession.selectList("com.example.spbatis.mapper.allCompUsers");

   

   

    /* 동작 안함1

    SqlSession session = sqlSessionFactory.openSession();

    try 

    {

    return session.selectList("com.example.spbatis.mapper.allCompUsers");

    }

    finally

    {

        session.close();

    }

    */

    // return null;


    }

    

}



파일명: CompUsersDao.java


[첨부(Attachments)]

CompUsersDao.zip




14. Mapper - CompUsersMapper.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.example.spbatis.mapper">


<select id="allCompUsers" resultType="com.example.spbatis.model.CompUsers">

select * from comp_users

</select>

<!-- 

<select id="allAddress" resultType="com.edu.db.AddressDto">

select * from addressbook

</select>

<select id="selectAddress" parameterType="Integer" resultType="com.edu.db.AddressDto">

select NUM, NAME, ADDRESS, BIRTHDATE

from addressbook

  where num=#{num}

</select>

<insert id="insertAddress" parameterType="com.edu.db.AddressDto">

insert into

addressbook(NAME, ADDRESS, BIRTHDATE)

values

(#{name},#{address},#{birthdate})

</insert>

<delete id="deleteAddress" parameterType="Integer">

DELETE FROM AddressBook

WHERE NUM = #{num}

</delete>

<update id="updateAddress" parameterType="com.edu.db.AddressDto" >

update addressbook

set birthdate = #{birthdate}, name = #{name}, address =#{address}

where num = #{num}

</update>

 -->

</mapper>


파일명: CompUsersMapper.java


[첨부(Attachments)]

CompUsersMapper.zip




* 방법2 - 실험 결과 보기


2. [Spring-F.] 26. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법2(SqlMap-XML-XML 맵핑)     // 결과: 지원, 2020-10-02

   - https://yyman.tistory.com/1439


반응형
728x90
300x250

[JSP] 18. JSP/Servlet MVC2 - 페이징네이션과 검색 그리고 오라클 프로젝트 (2)


2부에서는 페이징, DB구현부, 모델, 서비스 영역에 대해서 소개하겠다.


1. [JSP] 18. JSP/Servlet MVC2 - 페이징네이션과 검색 그리고 오라클 프로젝트 (1)

https://yyman.tistory.com/1428




14. 페이징네이션 


실제경로: /target/generated-sources/annotations/com/smile/web/model

패키지명: com.smile.web.logic

파일명: Paging.java


아마 이거 하나면, 현존에 있는 페이지 기법은 충분히 소화되지 않겠냐는 생각이다.

물론 정답은 아니다. 오류가 있을 수도 있다.


이러한 복잡한 문제에 직면했을 때, 수학을 공부 많이 해야 한다고 생각한다.

머리가 좋으신 분들이 많으시니깐 더 좋은 방법이 있다면, 개선해봐도 좋을 듯 싶다.


package com.smile.web.logic;


public class Paging {

    private long pageSize; // 게시 글 수

    private long firstPageNo; // 첫 번째 페이지 번호

    private long prevPageNo; // 이전 페이지 번호

    private long startPageNo; // 시작 페이지 (페이징 네비 기준)

    private long pageNo; // 페이지 번호

    private long endPageNo; // 끝 페이지 (페이징 네비 기준)

    private long nextPageNo; // 다음 페이지 번호

    private long finalPageNo; // 마지막 페이지 번호

    private long totalCount; // 게시 글 전체 수

    private long dbStartNum; // db 조회 (시작번호)

    private long dbEndNum; // db 조회 (종료번호)


    /**

     * @return the pageSize

     */

    public long getPageSize() {

        return pageSize;

    }


    /**

     * @param pageSize the pageSize to set

     */

    public void setPageSize(long pageSize) {

        this.pageSize = pageSize;

    }


    /**

     * @return the firstPageNo

     */

    public long getFirstPageNo() {

        return firstPageNo;

    }


    /**

     * @param firstPageNo the firstPageNo to set

     */

    public void setFirstPageNo(long firstPageNo) {

        this.firstPageNo = firstPageNo;

    }


    /**

     * @return the prevPageNo

     */

    public long getPrevPageNo() {

        return prevPageNo;

    }


    /**

     * @param prevPageNo the prevPageNo to set

     */

    public void setPrevPageNo(long prevPageNo) {

        this.prevPageNo = prevPageNo;

    }


    /**

     * @return the startPageNo

     */

    public long getStartPageNo() {

        return startPageNo;

    }


    /**

     * @param startPageNo the startPageNo to set

     */

    public void setStartPageNo(long startPageNo) {

        this.startPageNo = startPageNo;

    }


    /**

     * @return the pageNo

     */

    public long getPageNo() {

        return pageNo;

    }


    /**

     * @param pageNo the pageNo to set

     */

    public void setPageNo(long pageNo) {

        this.pageNo = pageNo;

    }


    /**

     * @return the endPageNo

     */

    public long getEndPageNo() {

        return endPageNo;

    }


    /**

     * @param endPageNo the endPageNo to set

     */

    public void setEndPageNo(long endPageNo) {

        this.endPageNo = endPageNo;

    }


    /**

     * @return the nextPageNo

     */

    public long getNextPageNo() {

        return nextPageNo;

    }


    /**

     * @param nextPageNo the nextPageNo to set

     */

    public void setNextPageNo(long nextPageNo) {

        this.nextPageNo = nextPageNo;

    }


    /**

     * @return the finalPageNo

     */

    public long getFinalPageNo() {

        return finalPageNo;

    }


    /**

     * @param finalPageNo the finalPageNo to set

     */

    public void setFinalPageNo(long finalPageNo) {

        this.finalPageNo = finalPageNo;

    }


    /**

     * @return the totalCount

     */

    public long getTotalCount() {

        return totalCount;

    }


    /**

     * @param totalCount the totalCount to set

     */

    public void setTotalCount(long totalCount) {

        this.totalCount = totalCount;

        this.makePaging();

        this.makeDbPaging();

    }


    /**

     * 페이징 생성 (setTotalCount에서 호출함)

     */

    private void makePaging() {

   

        if (this.totalCount == 0) 

        return; 

        

        // 게시 글 전체 수가 없는 경우

        

        if (this.pageNo == 0) 

        this.setPageNo(1); // 기본 값 설정

        

        if (this.pageSize == 0) 

        this.setPageSize(10); // 기본 값 설정


        long finalPage = (totalCount + (pageSize - 1)) / pageSize; // 마지막 페이지

        

        if (this.pageNo > finalPage) 

        this.setPageNo(finalPage); // 기본 값 설정


        if (this.pageNo < 0 || this.pageNo > finalPage) 

        this.pageNo = 1; // 현재 페이지 유효성 체크


        boolean isNowFirst = pageNo == 1 ? true : false; // 시작 페이지 (전체)

        boolean isNowFinal = pageNo == finalPage ? true : false; // 마지막 페이지 (전체)


        long startPage = ((pageNo - 1) / 10) * 10 + 1; // 시작 페이지 (페이징 네비 기준)

        long endPage = startPage + 10 - 1; // 끝 페이지 (페이징 네비 기준)


        if (endPage > finalPage) { // [마지막 페이지 (페이징 네비 기준) > 마지막 페이지] 보다 큰 경우

            endPage = finalPage;

        }


        this.setFirstPageNo(1); // 첫 번째 페이지 번호


        if (isNowFirst) {

            this.setPrevPageNo(1);    // 이전 페이지 번호

        } else {

            this.setPrevPageNo(((pageNo - 1) < 1 ? 1 : (pageNo - 1))); // 이전 페이지 번호

        }


        this.setStartPageNo(startPage); // 시작 페이지 (페이징 네비 기준)

        this.setEndPageNo(endPage); // 끝 페이지 (페이징 네비 기준)


        if (isNowFinal) {

            this.setNextPageNo(finalPage); // 다음 페이지 번호

        } else {

            this.setNextPageNo(((pageNo + 1) > finalPage ? finalPage : (pageNo + 1))); // 다음 페이지 번호

        }


        this.setFinalPageNo(finalPage); // 마지막 페이지 번호

        

    }

    

    private void makeDbPaging() {

   

    long current = this.getPageNo();

    long weight = this.getPageSize();

    long endNum = 0;

   

    this.setDbEndNum( current * weight );

   

    endNum = this.getDbEndNum();

    this.setDbStartNum( (endNum - weight) + 1 );

   

    }


    /**

     * @return the dbStartNum

     */

public long getDbStartNum() {

return dbStartNum;

}



    /**

     * @param dbStartNum the dbStartNum to set

     */

public void setDbStartNum(long dbStartNum) {

this.dbStartNum = dbStartNum;

}


    /**

     * @return dbEndNum

     */


public long getDbEndNum() {

return dbEndNum;

}



    /**

     * @param dbEndNum the dbEndNum to set

     */

public void setDbEndNum(long dbEndNum) {

this.dbEndNum = dbEndNum;

}

    

}


파일명: Paging.java


[첨부(Attachments)]

Paging.zip




15. Board.java - 모델(Model)


실제경로: /target/generated-sources/annotations/com/smile/web/model

패키지명: com.smile.web.model

파일명: Board.java


게시판 모델에 대한 설계이다.


package com.smile.web.model;


import java.sql.Timestamp;


public class Board {


private long id;

private String name;

private String subject;

private String memo;

private long count;

private Timestamp regidate;

public long getId() {

return id;

}

public void setId(long id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getSubject() {

return subject;

}

public void setSubject(String subject) {

this.subject = subject;

}

public String getMemo() {

return memo;

}

public void setMemo(String memo) {

this.memo = memo;

}


public long getCount() {

return count;

}


public void setCount(long count) {

this.count = count;

}


public Timestamp getRegidate() {

return regidate;

}


public void setRegidate(Timestamp regidate) {

this.regidate = regidate;

}

}



파일명: Board.java


[첨부(Attachments)]

Board.zip




16. BoardService.java - Service 영역


실제경로: /target/generated-sources/annotations/com/smile/web/service

패키지명: com.smile.web.service

파일명: BoardService.java


게시판 서비스에 필요한 영역을 구현한 것이다.


package com.smile.web.service;


import java.util.List;


import com.smile.web.model.Board;


public class BoardService {

private static BoardService service = null;

private static BoardServiceImpl dao = null;

private BoardService() {}

public static BoardService getInstance() {


        if(service == null){

        service = new BoardService();

    dao = BoardServiceImpl.getInstatnce();

        }


        return service;

}

public List<Board> getBoardList(long startNum, long endNum){

return dao.getBoardList(startNum, endNum);

}

public long getTotalCount() {

return dao.getTotalCount();

}

public List<Board> getBoardKeywordList(String keyword, long startNum, long endNum){

return dao.getBoardKeywordList(keyword, startNum, endNum);

}


public long getTotalKeywordCount(String keyword) {

return dao.getTotalKeywordCount(keyword);

}

}



파일명: BoardService.java


[첨부(Attachments)]

BoardService.zip





16. BoardServiceImpl.java - Service 영역(DAO)


실제경로: /target/generated-sources/annotations/com/smile/web/service

패키지명: com.smile.web.service

파일명: BoardServiceImpl.java


DAO 영역에 관한 것이다. (실제 DB를 처리하는 영역)


package com.smile.web.service;


import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;


import com.smile.web.db.DBFactory;

import com.smile.web.model.Board;


public class BoardServiceImpl {

private static BoardServiceImpl boardDAO;

private static DBFactory dbPool;

private BoardServiceImpl() {}

public static BoardServiceImpl getInstatnce() {

if ( boardDAO == null ) {

boardDAO = new BoardServiceImpl();

dbPool = new DBFactory();

}

return boardDAO;

}

public List<Board> getBoardList(long startNum, long endNum){

Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    Board node = null;

   

    List<Board> boardList = new ArrayList<Board>();


    String sql = "select * from (select /*+INDEX_DESC(tbl_board pk_board) */ rownum rn, A.*" + 

    " from board A order by id desc) " + 

    "where rn >= ? and rn <= ?";


    //System.out.println(sql);

    //System.out.println(startNum + "/" + endNum);

   

    try {

    conn = dbPool.getConnection();

    pstmt = conn.prepareStatement(sql);

    pstmt.setLong(1, startNum);

    pstmt.setLong(2, endNum);

   

    rs = pstmt.executeQuery();


    while ( rs.next() ) {

    // 데이터가 존재할 때, 노드 생성

    node = new Board();

   

    node.setId(rs.getLong(2));

    node.setSubject(rs.getNString(3));

    node.setMemo(rs.getNString(4));

    node.setName(rs.getNString(5));

   

    boardList.add(node);

   

    System.out.println("rs:" + rs.getLong(1));

   

    }


    }catch(Exception ex) {

    System.out.println("오류 발생: " + ex);

    }

    finally {

    dbPool.close(conn, pstmt, rs);

    }

return boardList;

}

public List<Board> getBoardKeywordList(String keyword, long startNum, long endNum){

Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    Board node = null;

   

    String allKeyword = "%" + keyword + "%";

   

    List<Board> boardList = new ArrayList<Board>();


    String sql = "select * " + 

    "from (select /*+INDEX_DESC(tbl_board pk_board) */ rownum rn, A.* " + 

    "from board A where subject like ? order by id desc) " + 

    "where rn >= ? and rn <= ?";

   

    //System.out.println(sql);

   

    try {

    conn = dbPool.getConnection();

    pstmt = conn.prepareStatement(sql);

    pstmt.setNString(1, allKeyword);

    pstmt.setLong(2, startNum);

    pstmt.setLong(3, endNum);

   

    rs = pstmt.executeQuery();


    while ( rs.next() ) {

    // 데이터가 존재할 때, 노드 생성

    node = new Board();

   

    node.setId(rs.getLong(2));

    node.setSubject(rs.getNString(3));

    node.setMemo(rs.getNString(4));

    node.setName(rs.getNString(5));

   

    boardList.add(node);

   

    //System.out.println("rs:" + rs.getLong(1));

   

    }


    }catch(Exception ex) {

    System.out.println("오류 발생: " + ex);

    }

    finally {

    dbPool.close(conn, pstmt, rs);

    }

return boardList;

}

public long getTotalCount() {

Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    Board node = null;

   

    long cnt = 0;


    String sql = "select count(*) from board";

   

    System.out.println("sql:" + sql);


    try {

    conn = dbPool.getConnection();

    //System.out.println( conn.getSchema() );

    pstmt = conn.prepareStatement(sql);

   

    rs = pstmt.executeQuery();

    //System.out.println( rs.getFetchSize() );


    if ( rs.next() ) {

    cnt = rs.getLong(1);

        System.out.println("전체갯수:" + cnt + "/" + rs.getLong(1));

    }


    }catch(Exception ex) {

    System.out.println("오류 발생: " + ex);

    }

    finally {

    dbPool.close(conn, pstmt, rs);

    }

return cnt;

}

public long getTotalKeywordCount(String keyword) {

Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    Board node = null;

   

    String allKeyword = "%" + keyword + "%";

   

    long cnt = 0;


    String sql = "select count(*) from board where subject like ?";

   

    //System.out.println("sql:" + sql + "/키:" + keyword);


    try {

    conn = dbPool.getConnection();

    /// System.out.println( conn.getSchema() );

    pstmt = conn.prepareStatement(sql);

    pstmt.setNString(1, allKeyword);

   

    rs = pstmt.executeQuery();

    /// System.out.println( rs.getFetchSize() );


    if ( rs.next() ) {

    cnt = rs.getLong(1);

        System.out.println("특정 갯수:" + cnt + "/" + rs.getLong(1));

    }


    }catch(Exception ex) {

    System.out.println("오류 발생: " + ex);

    }

    finally {

    dbPool.close(conn, pstmt, rs);

    }

return cnt;

}


}


파일명: BoardServiceImpl.java


[첨부(Attachments)]

BoardServiceImpl.zip



17. 데이터베이스 - 응용 영역


이 부분이 의외로 어려울 수 있다고 본다. 머리를 조금 써야 한다.


[개선 후 SQL 파일 내용]


-- Oracle 11 - 자동번호 생성 테이블 정의
-- Table 생성 (BOARD)
-- NEW.ID (Table의 id를 가리킴)
CREATE TABLE board
(
    id NUMBER PRIMARY KEY,
    name VARCHAR2(30),
    subject VARCHAR2(30),
    memo NCLOB,
    count NUMBER,
    regidate DATE
);

-- Sequence 정의
CREATE SEQUENCE board_sequence
START WITH 1
INCREMENT BY 1;

-- Trigger 생성
-- BEFORE INSERT on '테이블명'
CREATE OR REPLACE TRIGGER board_trigger
BEFORE INSERT
    ON board
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT board_sequence.nextval INTO :NEW.ID FROM dual;
END;


/* 데이터 추가 */
INSERT INTO board (name, subject, memo, count, regidate) VALUES ('홍길동', '안녕하세요.', '메모메모', '0', '2020-09-29 11:11:00');

/* 데이터 등록 후 커밋할 것(대량 정보 처리 후) */
COMMIT;


-- 싱글 쿼리 (페이징)
SELECT * FROM (
SELECT /*+ INDEX_DESC(Z OP_SAMPLE_PK) */ ROWNUM AS RNUM, Z.* FROM (
SELECT * from board order by id desc
) Z WHERE ROWNUM <= 10
) WHERE RNUM >= 1

-- 특정 싱글 쿼리 SQL
SELECT * FROM (
SELECT /*+ INDEX_DESC(Z OP_SAMPLE_PK) */ ROWNUM AS RNUM, Z.* FROM (
SELECT * from board where subject like '%야해해%' order by id desc
) Z WHERE ROWNUM <= 10
) WHERE RNUM >= 1


파일명: board-tbl-oracle_개선후.sql (변경해도 되는 쿼리)  /  board-tbl-oracle_개선전.sql (이 글의 16번 소스코드에 적용된 페이징 쿼리)


(16번 파일의 페이징 쿼리를 수정해서 사용해도 됨.)

-> 개선 전 쿼리라고 해서 파일을 두 개로 두었음.


[첨부(Attachments)]

board-tbl-oracle.zip (업데이트: 2020-10-11)


페이징 로직 설계가 되었다면, 다음 계획해야 할 작업이 실질적으로는 이 작업이다.

의외로 작업을 하다보면, 골치가 아픈 문제들이 많이 생긴다.


[Oracle Databases 코너에 쿼리 관련 작업에 대해서 추가로 보충하여 소개하도록 하겠다.]

- 단일 테이블 게시물 쿼리 방법, 뷰 테이블 쿼리 방법, 테이블 조인(2개 이상) 사용 방법


-> 태스트 결과로는 "Java 페이징 로직"은 크게 문제가 없다. 
    다만, 나머지 부분은 쿼리라고 본다.



[쿼리 관련 - 보충 글]
1. [Oracle Databases] 번외글 - 게시판 페이징 관련 로직 쿼리, 2020-10-11.
- https://yyman.tistory.com/1466




18. 뷰 - css


css 하나 만들어준다. 보안 영역에 만들지 말고 외부 영역에 만들어준다.



그림 23. style.css 프로젝트 위치


생성할 폴더: 

/src/main/webapp/board

/src/main/webapp/board/css


생성할 파일

/src/main/web/app/board/css/style.css


사실 style.css을 먼저 만들고 나서 작업하는 건 절대적으로 아니다.

웹 페이지를 보고 하나 하나 왕복 화면 전환 등 복합적으로 하면서 수많은 태스트과정을 거쳐서 작성하게 된다.

css 작업을 하는데 있어서도 어떻게 하면 깔끔하면서 표준을 지킬지 고민을 많이 해봐야 한다고 본다.


@charset "utf-8";


/* 1. 제목 */

h3{

font-size:20px;

font-family:'Nanum Gothic';

text-align:center;

}


/* 2. 게시판 */

/* 게시판 목록 출력 */

.board_list{

border-top:1px solid #e2e2e2;

border-bottom:1px solid #e2e2e2;

font-size:12px;

font-family:'Nanum Gothic';

width:900px;

margin:auto;

text-align:center;

}


/* 제목 */

.board_list th{


border-right:1px solid #666;

border-bottom:1px solid #666;

font-size:15px;

font-family:'Nanum Gothic';

height:20px;

text-align:center;

background-color:#eeeeee;

}


/* 내용 */

.board_list td{


border-right:1px solid #e2e2e2;

font-size:15px;

font-family:'Nanum Gothic';

height:20px;

text-align:center;

}


/* 3. 페이징 네이션 */

.paginate{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

}


.paginate .first{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


.paginate .prev{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


.paginate .next{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


.paginate .last{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


.paginate .choice{


font-size:20px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


/* 4. 링크 */

a{

text-decoration:none;

color:#666;

}


/* 5. 검색 영역 */

.searchArea{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

}


파일명: style.css


[첨부(Attachments)]

style.zip




19. 뷰(view) - jsp파일 작성하기


이번에 소개할 것은 include를 실제 적용한 코드이다.



그림 24. board 폴더 내 파일들 (작업할 부분)


생성할 폴더: 

/src/main/webapp/WEB-INF/views/

/src/main/webapp/WEB-INF/views/board


생성할 파일

/src/main/webapp/WEB-INF/views/board/list.jsp

/src/main/webapp/WEB-INF/views/board/search.jsp

/src/main/webapp/WEB-INF/views/board/paging.jsp


list.jsp를 호출하면, search.jsp, paging.jsp도 함께 호출이 된다.

기능을 전문적으로 분리하여 설계한 것이다.




20. 뷰(view) - list.jsp


list.jsp에 관한 것이다.

코드를 보고 한눈에 알 수 없는 사람들을 위해서 실제 동작 결과화면을 소개하겠다.



그림 25. list.jsp 화면 영역 구성도



<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ page import = "java.util.*" %>

<%@ page import = "com.smile.web.model.*" %>

<%@ page session="false" %>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>게시물 목록</title>

<style>

@import url('https://fonts.googleapis.com/css?family=Nanum+Gothic:400,700,800');


</style>

<link href="css/style.css" rel="stylesheet" type="text/css" />

</head>

<body>

<%

List<Board> boardList = (List<Board>)request.getAttribute("list");

%>


<h3>게시물 목록</h3>


<!-- 목록 출력 -->

<table class="board_list">

<tr>

<th style="width:15%;">

번호(Num)

</th>

<th>

제목(Subject)

</th>

<th style="width:13%;">

글쓴이(Author)

</th>

<th style="width:13%; border-right:none;">

조회수(Count)

</th>

</tr>

<%

for(Board board:boardList){

%>

<tr>

<td style="width:15%;">

<%= board.getId() %>

</td>

<td>

<%= board.getSubject() %>

</td>

<td style="width:13%;">

<%= board.getName() %>

</td>

<td style="width:13%; border-right:none;">

<%= board.getCount() %>

</td>

</tr>

<%

}

%>

</table>


<!-- 페이징 -->

<jsp:include page="/WEB-INF/views/board/paging.jsp">

<jsp:param name="customURL" value="${pagingUrl}" />

    <jsp:param name="firstPageNo" value="${paging.firstPageNo}" />

    <jsp:param name="prevPageNo" value="${paging.prevPageNo}" />

    <jsp:param name="startPageNo" value="${paging.startPageNo}" />

    <jsp:param name="pageNo" value="${paging.pageNo}" />

    <jsp:param name="endPageNo" value="${paging.endPageNo}" />

    <jsp:param name="nextPageNo" value="${paging.nextPageNo}" />

    <jsp:param name="finalPageNo" value="${paging.finalPageNo}" />

</jsp:include>


<!-- 검색 -->

<jsp:include page="/WEB-INF/views/board/search.jsp" />


</body>

</html>


파일명: list.jsp


[첨부(Attachments)]

list.zip



21. 뷰(view) - paging.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>



<div class="paginate">

    <a href="${param.customURL}page=${param.firstPageNo}" class="first">처음 페이지</a>

    <a href="${param.customURL}page=${param.prevPageNo}" class="prev">이전 페이지</a>

    <span>

        <c:forEach var="i" begin="${param.startPageNo}" end="${param.endPageNo}" step="1">

            <c:choose>

                <c:when test="${i eq param.pageNo}"><a href="${param.customURL}page=${i}" class="choice">${i}</a></c:when>

                <c:otherwise><a href="${param.customURL}page=${i}">${i}</a></c:otherwise>

            </c:choose>

        </c:forEach>

    </span>

    <a href="${param.customURL}page=${param.nextPageNo}" class="next">다음 페이지</a>

    <a href="${param.customURL}page=${param.finalPageNo}" class="last">마지막 페이지</a>

</div>



파일명: paging.jsp


[첨부(Attachments)]

paging.zip




22. 뷰(view) - search.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


<div class="searchArea">

<form id="searchForm" action="list.do" method='get'>

<select name="type">

<option value="T">제목</option>

<option value="C">내용</option>

<option value="W">작성자</option>

</select>

<input type="text" name="keyword">

<button class="">검색</button>

</form>

</div>


파일명: search.jsp


[첨부(Attachments)]

search.zip




23. 데이터베이스 작업시 성능 - 꼭 파악하면서 작업해보기


오늘 날 게시판 뿐만 아니라 DB의 비중이 매우 중요한 시대에 직면해 있다.

성능 측정 꼭 해보기 바란다.

동작도 물론 중요한데, 결과는 정확한지 등 많이 고민하고 수 십번, 수 백법 이상 찍어봐야 한다.



그림 26. 데이터베이스 작업 모습 - 오라클 SQL Developer




* 맺음글(Conclusion)


페이징네이션 기반의 게시판 프로젝트에 대해서 살펴보았다.




* 참고자료(References)


1. [Oracle] 오라클 데이터타입(DataType) 총정리, https://coding-factory.tistory.com/416, Accessed by 2020-09-29, Last Modified 2019-11-03.


2. [JSP]include 와 forward 의 페이지 이동, https://jerryjerryjerry.tistory.com/31, Accessed by 2020-09-29, Last Modified 2018-04-13.


3. 오라클 페이징 쿼리, 오라클 paging 방법 - 개발자 삽질 일기, https://programmer93.tistory.com/4, Accessed by 2020-09-29, Last Modified 2019.


4. [OracleDB] 페이징(Paging) 처리하는 법, https://m.blog.naver.com/wideeyed/221796538283, Accessed by 2020-09-29, Last Modified 2020-02-04.

반응형
728x90
300x250

[JSP] 17. JSP/Servlet MVC2 - 페이징네이션과 검색 그리고 오라클 프로젝트 (1)


Command 패턴과 Front Controller 패턴을 적용한 페이징네이션과 검색에 대해서 소개하려고 한다.

불필요한 기능은 다 제거하고 순수한 페이징네이션과 검색 그리고 오라클 연동에 대해서 다뤄보았다.


IDE: Spring-Tool Suite 4-4.7.2 RELEASES

Databases: Oracle Databases 19g

 - Maven 3.6.3/1.16.0.20200610-1735

 - javax.servlet-api (4.0.1) - servlet(서블렛)

 - jstl (1.2) - jstl 태그 적용

 - taglibs (1.1.2) - c태그 적용

 - HikariCP (3.4.2) - 커넥션 풀

 - com.oracle.database.jdbc - ojdbc8 (19.7.0.0)



[쿼리 관련해서 조금 더 보충한 글이다.]
1. [Oracle Databases] 번외글 - 게시판 페이징 관련 로직 쿼리, 2020-10-11.
- https://yyman.tistory.com/1466




1. 프로젝트 구조


작성할 프로젝트를 미리 살펴보면 조금 작업해야 할 양이 의외로 상당하다는 것을 알 수 있다.



그림 1, 그림 2. 프로젝트 작성 구조도




2. 게시판 - 설계


데이터베이스 설계는 매우 간단하게 작성하였다.


그림 3. Board - 테이블 설계(1)




그림 4. Board 게시판 설계(2)





3. 사용자 인터페이스 - 결과


이번 주제에서 다뤄볼 프로젝트의 완성 모습이다.

참고로 페이징네이션 로직에 대해서 다 기억할 수 없다.


다만 어떤 흐름인지는 대략적으로 알고는 있으면 하는 바람이다.

워낙 페이징 로직에 대해서 전문적으로 잘 연구하시는 분들이 많이 계시니깐 그건 골고루 참고도 해보고 개선도 해보고 하면 될 것 같다.



그림 5. list.do - 첫 화면



그림 6. list.do - 7번 페이지 / 기초



그림 7. list.do - 10106번 페이지 / 기초


10106번 페이지를 통해서 알 수 있는 것은 약 10106 * 10 = 101,106개의 DB가 존재한다는 것을 알 수 있다.

그림 8부터는 응용부분에 가까워진다.



그림 8. list.do - 키워드 검색 및 페이징 처리(1) / 심화


의외로 응용력이 많이 요구되는 부분이다.



그림 9. list.do - 키워드 검색 및 페이징 처리(2) / 심화


키워드 검색을 했을 때 "친"은 약 13개가 있었다는 사실을 유추할 수 있다.



그림 10. list.do - 키워드 검색 및 페이징 처리(3)


참고로 list.do 반응에 대해서 여러 조건으로 튜닝이 필요하다.



4. 프로젝트 생성하기


프로젝트는 Maven Project로 생성하여 진행하였다.



그림 11. Maven Project 생성하기(1)


File -> New -> Maven Project를 클릭한다.



그림 12. Maven Project 생성하기(2)


org.apache.maven.archetypes | maven-archetype-web을 선택하고 Next를 누른다.



그림 13. Maven Project 생성하기(3)


프로젝트의 Group Id, Artifact Id를 입력한다.

Finish를 누른다.




5. POM.xml - 설정하기


다음은 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>


  <groupId>com.boardMaven</groupId>

  <artifactId>web</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


  <name>board Maven Webapp</name>

  <!-- FIXME change it to the project's website -->

  <url>http://www.example.com</url>


  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <maven.compiler.source>1.7</maven.compiler.source>

    <maven.compiler.target>1.7</maven.compiler.target>

  </properties>


  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.11</version>

      <scope>test</scope>

    </dependency>

    

<!-- Servlet -->

<!-- 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>

<!-- JSTL -->

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

<version>1.2</version>

</dependency>

<!-- taglibs -->

<dependency>

<groupId>taglibs</groupId>

<artifactId>standard</artifactId>

<version>1.1.2</version>

<scope>compile</scope>

</dependency>


<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->

<dependency>

    <groupId>com.zaxxer</groupId>

    <artifactId>HikariCP</artifactId>

    <version>3.4.2</version>

</dependency>

<dependency>

<groupId>com.oracle.database.jdbc</groupId>

<artifactId>ojdbc8</artifactId>

<version>19.7.0.0</version>

</dependency>

  </dependencies>


  <build>

    <finalName>board</finalName>

    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->

      <plugins>

        <plugin>

          <artifactId>maven-clean-plugin</artifactId>

          <version>3.1.0</version>

        </plugin>

        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->

        <plugin>

          <artifactId>maven-resources-plugin</artifactId>

          <version>3.0.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-compiler-plugin</artifactId>

          <version>3.8.0</version>

        </plugin>

        <plugin>

          <artifactId>maven-surefire-plugin</artifactId>

          <version>2.22.1</version>

        </plugin>

        <plugin>

          <artifactId>maven-war-plugin</artifactId>

          <version>3.2.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-install-plugin</artifactId>

          <version>2.5.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-deploy-plugin</artifactId>

          <version>2.8.2</version>

        </plugin>

      </plugins>

    </pluginManagement>

  </build>

</project>



파일명: pom.xml


[첨부(Attachments)]

pom.zip



6. 프로젝트의 Build-Path, Properties 수정하기


프로젝트의 자바 버전에 대한 환경설정이다.



그림 14. 프로젝트의 마우스 오른쪽 버튼 모습


프로젝트를 클릭한다.

마우스 오른쪽 버튼을 누른다.

Properties를 클릭한다.



그림 15. Build-Path 환경설정


JRE System Library를 JavaSE-14버전으로 변경한다. (14버전으로 변경)

Apply를 누른다.



그림 16. Project Facets 환경 설정


Project Facets의 Java 버전을 14로 변경한다.

Apply를 누른다.

Apply and close를 누른다.



7. Resource 폴더와 db.properties 만들기


Resource 폴더와 db.properties를 생성할 것이다.



그림 17. /src/main 폴더 - 오른쪽 버튼 메뉴 모습


src/main 폴더를 마우스 오른쪽으로 클릭한다.

New-> Folder를 클릭한다.


폴더명: Resource



그림 17. /src/main/resource 폴더 - 오른쪽 버튼 메뉴 모습


src/main/resource 폴더를 마우스 오른쪽으로 클릭한다.

New-> File를 클릭한다.


파일명: db.properties



그림 18. /src/main/resource 폴더와 db.properties 모습


성공적으로 만들어진 것을 확인할 수 있다.



그림 19. db.propeties 모습


jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl

dataSourceClassName=oracle.jdbc.driver.OracleDriver

dataSource.user=userName

dataSource.password=password

cachePrepStmts=true

prepStmtCacheSize=250

prepStmtCacheSqlLimit=2048


파일명: db.propeties


[첨부(Attachments)]

db.zip




9. Servlet 생성하기


servlet 생성하고 나서 web.xml 수정을 진행하면 타이핑을 적게 해도 되는 장점이 생긴다.



그림 20. 프로젝트 오른쪽 버튼 - 메뉴 모습


프로젝트를 선택한다.

마우스 오른쪽 버튼을 클릭한다.

New->Servlet을 클릭한다.



그림 21. Servlet 생성하기


Java package명을 입력한다. ("예: com.smile.web.controller // 이런 형식으로 작성하면 됨.)

Class name을 입력한다. ("예: FrontController" )

Finish를 누른다.



10. web.xml - 수정하기


charset 초기값을 추가하였다.

Servlet 2.5 문서 양식에서 3.1 양식으로 변경하였다.


<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xmlns="http://java.sun.com/xml/ns/javaee" 

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 

id="WebApp_ID" version="3.0">

 

  <display-name>Archetype Created Web Application</display-name>

  

  <servlet>

  <servlet-name>FrontController</servlet-name>

  <servlet-class>com.smile.web.controller.FrontController</servlet-class>

  <init-param>

<param-name>charset</param-name>

<param-value>UTF-8</param-value>

</init-param>

  </servlet>

  <servlet-mapping>

  <servlet-name>FrontController</servlet-name>

  <url-pattern>*.do</url-pattern>

  </servlet-mapping>

  

</web-app>


파일명: web.xml


[첨부(Attachments)]

web.zip




10. 폴더 2개(views, settings), 파일 하나 만들기(root-servlet.xml)


추가적으로 만들어줄 폴더와 파일이 있다.


폴더1: /src/main/webapp/WEB-INF/settings

폴더2: /src/main/webapp/WEB-INF/views

파일: /src/main/webapp/WEB-INF/settings/root-servlet.xml


Settings 폴더는 큰 의미는 없지만, 활용할 여지를 고려하여 생성하였다.
이 프로젝트에서는 root-servlet.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 -->
</beans>


파일명: root-servlet.xml


[첨부(Attachments)]

root-servlet.zip



그림 22. 작업된 프로젝트의 모습




11. FrontController.java - 서블렛(Servlet)


실제경로: /target/generated-sources/annotations/com/smile/web/controller

패키지명: com.smile.web.controller

파일명: FrontController.java


FrontController를 list만 정의하였다.

의외로 코드를 살펴보면, 간단하다는 것을 알 수 있다.


package com.smile.web.controller;


import java.io.IOException;

import java.sql.SQLException;


import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.smile.web.db.DBFactory;


public class FrontController extends HttpServlet {

private static final long serialVersionUID = 1L;

private String charset = null;

/**

* @see HttpServlet#doGet(HttpServletRequest req, HttpServletResponse res)

*/

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

doAction(req, res);

}


/**

* @see HttpServlet#doPost(HttpServletRequest req, HttpServletResponse res)

*/

protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

doAction(req, res);

}

// FrontController 패턴 & Command 패턴

protected void doAction(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {


ServletConfig sc = this.getServletConfig();

charset = sc.getInitParameter("charset");


req.setAttribute("charset", charset);

req.setCharacterEncoding(charset);

res.setContentType("text/html; charset=" + charset);


String uri = req.getRequestURI();

String conPath = req.getContextPath();

String command = uri.substring(conPath.length());


Controller subController = null;


if(command.equals("/board/list.do")){

System.out.println("-----------------------------");

System.out.println("게시판 목록");

System.out.println("-----------------------------");

req.setAttribute("controllerName", "list");

subController = new com.smile.web.controller.board.ListController();

subController.execute(req, res);

}

}


}



파일명: FrontController.java


[첨부(Attachments)]

FrontController.zip




12. Controller.java - 인터페이스


실제경로: /target/generated-sources/annotations/com/smile/web/controller

패키지명: com.smile.web.controller

파일명: Controller.java


인터페이스에 관한 것이다. (forward 정의 관련한 것)


package com.smile.web.controller;


import java.io.IOException;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public interface Controller {

public void execute(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;


}


파일명: Controller.java


[첨부(Attachments)]

Controller.zip



12. /Board/ListController.java - 클래스


실제경로: /target/generated-sources/annotations/com/smile/web/controller/board

패키지명: com.smile.web.controller.board

파일명: ListController.java


게시판 목록에 관한 컨트롤러 명세이다.


package com.smile.web.controller.board;


import java.io.IOException;

import java.net.URLEncoder;

import java.util.List;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.smile.web.controller.Controller;

import com.smile.web.logic.Paging;

import com.smile.web.model.Board;

import com.smile.web.service.BoardService;

import com.smile.web.util.HttpUtil;


public class ListController implements Controller {


@Override

public void execute(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

String controllerName = (String) req.getAttribute("controllerName");

BoardService service = BoardService.getInstance();

List<Board> boardList = null;

// long totalCount = boardList.size();

long currentPage = 1; // 기본값

long pageSize = 10;

long totalCount = service.getTotalCount();

long startNum, endNum;

String keyword = null;

String pagingUrl = controllerName + ".do?";

// 페이지 번호 존재할 때

if (req.getParameter("page") != null){

currentPage = Integer.valueOf( req.getParameter("page") );

}

// 키워드가 존재할 때

if (req.getParameter("keyword") != null) {

keyword = req.getParameter("keyword");

totalCount = service.getTotalKeywordCount(keyword);

// 키워드 값이 하나라도 존재할 때

if ( keyword.length() > 0) {

pagingUrl = pagingUrl + "keyword=" + URLEncoder.encode(keyword, "UTF-8") + "&";

}

}

        Paging paging = new Paging();

        /*

        paging.setPageNo(1);

        paging.setPageSize(10);

        paging.setTotalCount(totalCount);

        */

        

        paging.setPageNo(currentPage);

        paging.setPageSize(pageSize);

        paging.setTotalCount(totalCount);


        System.out.println("현재페이지번호:" + currentPage);

        System.out.println("페이지크기:" + pageSize);

        System.out.println("키워드:" + keyword);

        System.out.println("페이징URL:" + pagingUrl);

        

        startNum = paging.getDbStartNum();

        endNum = paging.getDbEndNum();


        

// 키워드가 존재할 때

if (keyword != null) {

// 키워드 값이 하나라도 존재할 때

if ( keyword.length() > 0) {

boardList = service.getBoardKeywordList(keyword, startNum, endNum);

}

else {

boardList = service.getBoardList(startNum, endNum);

}

}

else {

        boardList = service.getBoardList(startNum, endNum);

}

        

        req.setAttribute("paging", paging);

        req.setAttribute("list", boardList);

        req.setAttribute("pagingUrl", pagingUrl);

HttpUtil.forward(req, res, "/WEB-INF/views/board/" + controllerName + ".jsp");

}


}



파일명: ListController.java


[첨부(Attachments)]

ListController.zip



13. HttpUtil.java - 클래스


실제경로: /target/generated-sources/annotations/com/smile/web/util

패키지명: com.smile.web.controller.util

파일명: HttpUtil.java


RequestDispatcher와 forward에 대한 정의이다.

추가로 업로드 기능에 대한 명세도 있다.


package com.smile.web.util;


import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.io.PrintWriter;


import javax.servlet.RequestDispatcher;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;



public class HttpUtil extends HttpServlet {

private static final long serialVersionUID = 1L;

private static String charset = null;


public static void forward(HttpServletRequest req, HttpServletResponse res,

String path) throws ServletException, IOException {

try {

RequestDispatcher dispatcher = req.getRequestDispatcher(path);

dispatcher.forward(req, res);

}catch(Exception e) {

e.printStackTrace();

}

}

public static void fileUpload(HttpServletRequest req, HttpServletResponse res,

String path) throws ServletException, IOException {


charset = (String) req.getAttribute("charset");

System.out.println(charset);

PrintWriter out = res.getWriter();

// 파일 업로드된 경로

String root = req.getSession().getServletContext().getRealPath("/");

String savePath = root + "upload" + File.separator + "upload";

// 서버에 실제 저장된 파일명

String filename = "1600955663095" ;

System.out.println("파일 실제 폴더경로:" + savePath);

// 실제 내보낼 파일명

String orgfilename = "license한글.txt" ;

req.setCharacterEncoding(charset);

res.setCharacterEncoding(charset);

InputStream in = null;

OutputStream os = null;

File file = null;

boolean skip = false;

String client = "";

try{

    // 파일을 읽어 스트림에 담기

    try{

        file = new File(savePath, filename);

        in = new FileInputStream(file);

    }catch(FileNotFoundException fe){

        skip = true;

    }

    client = req.getHeader("User-Agent");

    // 파일 다운로드 헤더 지정

    res.reset() ;

    res.setContentType("application/octet-stream");

    res.setHeader("Content-Description", "JSP Generated Data");

    if(!skip){

        // IE

        if(client.indexOf("MSIE") != -1){

            res.setHeader ("Content-Disposition", "attachment; filename="+new String(orgfilename.getBytes("KSC5601"),"ISO8859_1"));

        }else{

            // 한글 파일명 처리

            orgfilename = new String(orgfilename.getBytes("KSC5601"),"iso-8859-1");

            res.setHeader("Content-Disposition", "attachment; filename=\"" + orgfilename + "\"");

            res.setHeader("Content-Type", "application/octet-stream; charset=utf-8");

        }  

        res.setHeader ("Content-Length", ""+file.length() );

        os = res.getOutputStream();

        

        byte b[] = new byte[(int)file.length()];

        int leng = 0;

        while( (leng = in.read(b)) > 0 ){

            os.write(b,0,leng);

        }

    }else{

    // 한글 깨짐 - 해결

    res.setContentType("text/html;charset=" + charset);

        out.println("<html><head>");

        out.println("<script language='javascript'>alert('파일을 찾을 수 없습니다.');history.back();</script>");

        out.println("</head><body></body></html>");

    }

    in.close();

    os.close();

}catch(Exception e){

e.printStackTrace();

}

    

}


}



파일명: HttpUtil.java


[첨부(Attachments)]

HttpUtil.zip



13. DBFactory.java - 커넥션 풀 적용


실제경로: /target/generated-sources/annotations/com/smile/web/db

패키지명: com.smile.web.controller.db

파일명: DBFactory.java


HikariCP 3.4.2를 적용한 코드이다.


package com.smile.web.db;



import java.io.IOException;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Statement;

import java.util.Properties;

import java.io.IOException;


import java.io.InputStream;


import java.io.Reader;

import java.util.Properties;

import java.sql.Connection;

import java.sql.SQLException;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.zaxxer.hikari.HikariConfig;

import com.zaxxer.hikari.HikariDataSource;


import oracle.jdbc.pool.OracleDataSource;


public class DBFactory {


private static final Logger logger = LoggerFactory.getLogger(DBFactory.class);


    private static String CLASSNAME;

    private static String JDBC_URL;

    private static String USERNAME;

    private static String PASSWORD;

    private static String CACHE_PREP_STMTS;

    private static HikariDataSource ds;


    private HikariConfig config;


    

    public DBFactory() {


    InputStream inputStream;

    config = new HikariConfig();


        String resource = "db.properties";

        Properties properties = new Properties();


        try {


        inputStream = getClass().getClassLoader().getResourceAsStream(resource);

            properties.load(inputStream);


            System.out.println("jdbcurl:" + properties.getProperty("jdbcUrl"));

            System.out.println("className" + properties.getProperty("dataSourceClassName"));


            CLASSNAME = properties.getProperty("dataSourceClassName");

            JDBC_URL = properties.getProperty("jdbcUrl");

            USERNAME = properties.getProperty("dataSource.user");

            PASSWORD = properties.getProperty("dataSource.password");

            CACHE_PREP_STMTS = properties.getProperty("cachePrepStmts");


            config.setDriverClassName(CLASSNAME);

            config.setJdbcUrl( JDBC_URL );

            config.setUsername( USERNAME );

            config.setPassword( PASSWORD );

            

            config.addDataSourceProperty( "cachePrepStmts" , CACHE_PREP_STMTS );

            config.addDataSourceProperty( "prepStmtCacheSize" , "250" );

            config.addDataSourceProperty( "prepStmtCacheSqlLimit" , "2048" );

            

            ds = new HikariDataSource( config );

            

        } catch (IOException e) {

            e.printStackTrace();

        }


    }


    public Connection getConnection() throws SQLException {

   

    /*

        try(Connection con = ds.getConnection()){

            System.out.println("연결상태확인:" + con);

            

            String sql = "SELECT * from board where id > 4 and id < 10";

            

            PreparedStatement pstmt = con.prepareStatement(sql);

            ResultSet rs = pstmt.executeQuery();

            

            while (rs.next()) {

                System.out.println("진짜 연결되었는가:" + rs.getString(2));

            }

        }

        catch(Exception e) {

        System.out.println("연결실패확인:" + e.getMessage());

        }

    */

   

        return ds.getConnection();

    }

    

    public void close(Connection conn, PreparedStatement ps, ResultSet rs) {


if ( rs != null ) {


try {

rs.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}

close(conn, ps); // Recursive 구조 응용(재귀 함수)

} // end of if


}


public void close(Connection conn, PreparedStatement ps) {


if (ps != null ) {


try {

ps.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}

} // end of if


if (conn != null ) {

try {

conn.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}

} // end of if


}

    

}


파일명: DBFactory.java


[첨부(Attachments)]

DBFactory.zip



* 2부에서는 핵심적인 로직 등에 대해서 소개하겠다.


2부에서 만나요.


1. [JSP] 17. JSP/Servlet MVC2 - 페이징네이션과 검색 그리고 오라클 프로젝트 (2), 2020-09-30

https://yyman.tistory.com/1429


반응형
728x90
300x250

[Spring-Framework] 16. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-Java) (1)


이번에 소개할 프로젝트는 13, 14, 15번 게시글을 Java 방식으로 구현한 프로젝트이다.

동일하게 진행할 것이다. 실질적으로 제대로 소개하고 있는 책이나 게시글은 찾아보질 못했다.

많은 오류가 있었다는 이야기이다.


순수한 Spring-Framework에서도 Spring Security를 원만히 잘 사용할 수 있도록 하는 게 글의 핵심이다.

이번 게시글도 양이 많아서 나눠서 작성하였으니 잘 따라해보면 도움이 될 것으로 보인다.



[작업환경]


[WAS(Web Application Server), 웹 애플리케이션 서버]

1. apache-tomcat-9.0.37-windows-x64


[DBMS(DataBase Management System - Tools]

2. sqldeveloper-19.2.1.247.2212-x64


[DB(DataBase)]

3. Oracle Databases 19.3.0.0


[IDE(Integration Development Environment)]

4. Spring-Tool Suites 4-4.7.2. Releases.


[Framework(프레임워크)]

5. spring-security-taglibs(5.4)

6. spring-security-config(5.4)

7. spring-security-web(5.4)

8. spring-security-core(5.4)

9. javax.servlet-api(4.0.1)

10. spring-webmvc(5.2.9.RELEASE)

11. spring-context(5.2.9.RELEASE)

12. Maven 3.6.3/1.16.0.20200610-1735


[Java]

OpenJDK-14.0.2 (https://openjdk.java.net/)



[이전 글 주제]

1. [Spring-Framework] 13. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-XML) (1)

https://yyman.tistory.com/1419

2. [Spring-Framework] 13. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-XML) (2)

https://yyman.tistory.com/1420

3. [Spring-Framework] 13. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-XML) (3)  // 자동 로그인 유지, 유지 세션

https://yyman.tistory.com/1421




1. XML 기반 프로젝트 vs 자바 기반 프로젝트


이번에 소개할 주제는 자바 기반 프로젝트이다.

이전 게시물과 지금 구현할 게시물의 차이점에 대해서 간단하게 소개하겠다.


 


그림 1. XML 방식


 


그림 2. 자바 방식(Java)




(특징)
- Spring 폴더가 있으며, xml 파일이 존재함.

- web.xml 파일이 있음.

- 기본 프로젝트 pom.xml을 별도로 설정하지 않아도 됨.

(특징)
- Spring 폴더가 없음. (있으면 충돌나서 실행이 안 됨.)

- web.xml 파일이 없음. 

- 기본 프로젝트 생성 후 pom.xml을 별도로 설정해야 함.

(구현 난이도) 무난함.

(셋팅 값 및 지정된 변수 등을 잘 사용하는 것이 매우 중요함)


- 적당한 지식이면 무난할 것으로 보임.

(구현 난이도) 머리를 조금 사용해야 함.
- 초기 구축을 놓고 보면,
  코드가 늘어나고 조금 복잡할 수 있음.
  (쉽지만 않다. API도 읽어내야 하고 많은 실험이 요구됨.)


- 많은 프로그래밍 지식이 다소 필요함.

사용해보면, 장/단점이 있음.

-> 간단하게 관리하는 면에서는 편할 수도 있음.

   (xml)

-> 튜닝에 있어서 제약이 있을 수도 있음.

......


[이전 - XML 기반 게시글]

1. [Spring-Framework] 13. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-XML) (1), 2020. 9. 26

https://yyman.tistory.com/1419


2. [Spring-Framework] 13. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-XML) (2), 2020. 9. 26

https://yyman.tistory.com/1420


3. [Spring-Framework] 13. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-XML) (3), 2020. 9. 26

https://yyman.tistory.com/1421



2. 결과(1) - (Result)


출력 결과는 이전 프로젝트(13, 14, 15번)과 동일하게 구현 하였다.



그림 3. 결과(자바 버전) - 메인



그림 4. 결과(자바 버전) - 로그인 폼


그림 5. 결과(자바 버전) - 로그인 실패



그림 6. 결과(자바 버전) - 로그인 후



그림 7. 결과(자바 버전) - 비밀번호 출력의 예(암호화 패키지) - 업데이트 전



그림 8. 결과(자바 버전) - 로그인 후 모습 - 업데이트 전




그림 9. 결과(자바 버전) - 권한이 없는 계정이 특정 페이지를 접속할 때 모습(1) // 순정 (업데이트 전)



그림 9-1. 결과(자바 버전) - 권한이 없는 계정이 특정 페이지를 접속할 때 모습(2) // 커스텀 (업데이트 완료함)



그림 9-2. 결과(자바 버전) - 권한이 있는 계정의 메뉴 모습 // 커스텀 (업데이트 함)



그림 9-3. 결과(자바 버전) - 권한이 없는 계정의 메뉴 모습 // 커스텀 (업데이트 함)






3. 결과(2) - 프로젝트 구성


프로젝트 구성에 대한 것이다.

상당히 양이 많다. 초기 셋팅만 잘 해주면, 나머지는 순조로울 것으로 보인다.



그림 10, 11. 프로젝트 구성


다소 구현할 양이 많다는 것을 확인할 수 있다.


완성된 프로젝트 구성에 대해서 살펴보는 것은 무엇을 진행할 것인지 예상할 수 있는 방법 중 하나라고 주장해본다.



4. 데이터베이스 설계


크게 데이터베이스는 공식적으로 설계하라고 제시하는 규격 테이블 1개와 사용자 정의 테이블 5개로 총 6개의 테이블을 작성해야 한다.
아마 이런 부분은 시중 책이나 강의 등에서는 다뤄보지 못한 부분일 수도 있다.
권한이 있는 계정을 그룹별 권한, 페이지별 권한으로 체계화시킨 설계도이다.

Spring Security에서 요구하는 기능을 기본적으로 담은 설계이니 활용하면 참고하면 도움이 될 것으로 보인다.



그림 12. ER-D


테이블을 작성하는 데, 순번을 대략적으로 잡아본 이유는 외래키, 참조키 등에 기준이 되는 테이블을 먼저 생성하고 작업하는 것이 좋기 때문이다.

편집해서 외래키, 참조키 등 지정해줘도 무방하다. 단, 무결성이나 각종 조건 등 때문에 데이터가 존재하지 않은 상태에서 진행해야 한다.



그림 13. 테이블: COMP_GROUP



그림 14. 테이블: COMP_USERS



그림 15. 테이블: COMP_GROUP_AUTHORITIES



그림 16. 테이블: COMP_GROUP_MEMBERS



그림 17. 테이블: COMP_AUTHORITIES




그림 18. 테이블: PERSISTENT_LOGINS




5. 테이블 - SQL(Create table - DML)


테이블 작성에 관한 사항이다.


CREATE TABLE comp_users (

username VARCHAR(50) NOT NULL,

password VARCHAR(300) NOT NULL,

enabled INT NOT NULL,

PRIMARY KEY (username)

);


CREATE TABLE comp_authorities (

  username VARCHAR(50) NOT NULL,

  authority VARCHAR(50) NOT NULL,

  CONSTRAINT fk_authorities_users FOREIGN KEY (username) REFERENCES comp_users (username)

); 


CREATE TABLE comp_groups(

id VARCHAR2(20) NOT NULL,

group_name VARCHAR2(20) NULL

);


CREATE TABLE comp_group_authorities(

group_id VARCHAR2(20) NOT NULL,

authority VARCHAR2(20) NOT NULL

);


CREATE TABLE comp_group_members(

group_id VARCHAR2(20) NOT NULL,

username VARCHAR2(20) NOT NULL

);


CREATE TABLE persistent_logins (

username VARCHAR(64) NOT NULL,

series VARCHAR(64) PRIMARY KEY,

token VARCHAR(64) NOT NULL,

last_used TIMESTAMP NOT NULL

);



-- 계정

INSERT INTO comp_users (username, password, enabled) VALUES ('user', '$2a$10$x04djNV2e9rpcPPRyXoLk.rMm6iZe2/vYdzpqHQcLeNSYdt7kc30O', 1);

INSERT INTO comp_users (username, password, enabled) VALUES ('admin', '$2a$10$QUddY3O/6ZgkYCR6MFlv9.nqA501Fm0cc/ZxQHX5pwb1o0CYCTiIS', 1);


-- 사용자 권한

INSERT INTO comp_authorities (username, authority) VALUES ('user', 'ROLE_ADMIN');

INSERT INTO comp_authorities (username, authority) VALUES ('admin', 'ROLE_USER');


-- 그룹

INSERT INTO comp_groups (id, group_name) VALUES ('G01', '관리자 그룹');

INSERT INTO comp_groups (id, group_name) VALUES ('G02', '사용자 그룹');


-- 그룹 권한

INSERT INTO comp_group_authorities (group_id, authority) VALUES ('G01', 'ROLE_ADMIN');

INSERT INTO comp_group_authorities (group_id, authority) VALUES ('G01', 'ROLE_USER');

INSERT INTO comp_group_authorities (group_id, authority) VALUES ('G02', 'ROLE_USER');


-- 그룹 회원

INSERT INTO comp_group_members (group_id, username) VALUES ('G01', 'user');

INSERT INTO comp_group_members (group_id, username) VALUES ('G02', 'admin');



파일명: sampleDb-oracledb.sql


[첨부(Attachments)]

sampleDb-oracledb.zip



비고: 꼭 오라클만 되는 것은 아니고, 살짝 튜닝하면 MySQL 등에서도 사용할 수 있는 형태로 작성하였다.

(SQL 명령어가 일부 데이터베이스에서는 차이가 있을 수도 있음. 특정 DB의 함수 등)



6. 프로젝트 - 신규 생성하기


Spring-Legacy-Project를 생성한다.



그림 19. 테이블: Spring MVC Project 생성하기


Spring MVC Project를 선택한다.

Project Name의 항목을 입력한다.

Next를 누른다.




그림 20. 테이블: Spring MVC Project 생성하기


top-level-package를 입력한 후 Finish를 누른다.




7. 프로젝트 - 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>com.springMVC</groupId>

<artifactId>javaSecurity5</artifactId>

<name>SpringSecurity5-Java</name>

<packaging>war</packaging>

<version>1.0.0-BUILD-SNAPSHOT</version>

<properties>

<!-- web.xml 사용 안함 표기 -->

<failOnMissingWebXml>false</failOnMissingWebXml>

<java-version>14</java-version>

<org.springframework-version>5.2.9.RELEASE</org.springframework-version>

<org.aspectj-version>1.6.10</org.aspectj-version>

<org.slf4j-version>1.6.6</org.slf4j-version>

</properties>

<dependencies>

<!-- 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 -->

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjrt</artifactId>

<version>${org.aspectj-version}</version>

</dependency>

<!-- Logging -->

<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>

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.15</version>

<exclusions>

<exclusion>

<groupId>javax.mail</groupId>

<artifactId>mail</artifactId>

</exclusion>

<exclusion>

<groupId>javax.jms</groupId>

<artifactId>jms</artifactId>

</exclusion>

<exclusion>

<groupId>com.sun.jdmk</groupId>

<artifactId>jmxtools</artifactId>

</exclusion>

<exclusion>

<groupId>com.sun.jmx</groupId>

<artifactId>jmxri</artifactId>

</exclusion>

</exclusions>

<scope>runtime</scope>

</dependency>


<!-- @Inject -->

<dependency>

<groupId>javax.inject</groupId>

<artifactId>javax.inject</artifactId>

<version>1</version>

</dependency>

<!-- Servlet -->

<!-- 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>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

<version>1.2</version>

</dependency>

<!-- Test -->

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.7</version>

<scope>test</scope>

</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->

<dependency>

    <groupId>org.springframework.security</groupId>

    <artifactId>spring-security-core</artifactId>

    <version>5.4.0</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->

<dependency>

    <groupId>org.springframework.security</groupId>

    <artifactId>spring-security-web</artifactId>

    <version>5.4.0</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->

<dependency>

    <groupId>org.springframework.security</groupId>

    <artifactId>spring-security-config</artifactId>

    <version>5.4.0</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs -->

<dependency>

    <groupId>org.springframework.security</groupId>

    <artifactId>spring-security-taglibs</artifactId>

    <version>5.4.0</version>

</dependency>

<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->

<dependency>

    <groupId>javax.validation</groupId>

    <artifactId>validation-api</artifactId>

    <version>2.0.1.Final</version>

</dependency>


<dependency>

<groupId>com.oracle.database.jdbc</groupId>

<artifactId>ojdbc8</artifactId>

<version>19.7.0.0</version>

</dependency>

</dependencies>

    <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>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-compiler-plugin</artifactId>

                <version>2.5.1</version>

                <configuration>

                    <source>1.6</source>

                    <target>1.6</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>

        </plugins>

    </build>

</project>




- oracle jdbc를 못 찾는 사람들을 위해서, oracle jdbc라고 검색하거나 ojdbc8.jar 파일을 구해서 사용하면 된다.
- Oracle Databases를 설치해서 사용중인 경우에는 아래처럼 하면 사용할 수 있다.


그림 21. pom.xml 파일 선택 후 마우스 오른쪽 버튼 메뉴 모습


pom.xml을 선택한다.

마우스 오른쪽 버튼을 누른다.

maven-> Add Dependency를 클릭한다.



그림 22. Add Dependency에서 Oracle 검색하기


oracle을 검색한다.
com.oracle.database.jdbc  | ojdbc8을 선택한 후 OK를 누른다.






8. 프로젝트 - web.xml, spring 폴더 제거 작업


파일: /src/main/web-app/WEB-INF/web.xml   (삭제할 것)

폴더: /src/main/web-app/WEB-INF/spring      (삭제할 것)




9. 프로젝트 - Build Path, Project factes 버전 바꾸기


초기 Spring MVC Project를 생성하면 1.6버전으로 설정되어 있다. 14버전으로 바꿔주겠다.



그림 23. Properties 속성 바꿔주기(1) / Build-Path - JavaSE 14로


JRE System Library [JavaSE-14]로 Edit 버튼을 통해서 수정해준다.



그림 23. Properties 속성 바꿔주기(2) / Project Factes - JavaSE 14로


Java 버전을 1.6에서 14로 바꿔준다.




10. Controller - web.xml 제거 (핵심작업)


web.xml 제거한 Spring MVC라는 주제로 접근하여 작성하려고 한다.

지금 작업, pom.xml 수정 작업을 중심으로 HomeController.java(Servlet) 파일을 구성해서 view파일 jsp를 만들면 web.xml없이 동작하는 화면을 

볼 수 있다.


package com.springMVC.javaSecurity5.config;


import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;


public class SpringMvcAnnotation extends AbstractAnnotationConfigDispatcherServletInitializer {


  @Override

  protected Class<?>[] getRootConfigClasses() {

    return null;

  }


// bean 설정과 spring container 설정을 위한 Config 클래스를 등록한다.

// Config 클래스는 web.xml의 dispatcher servlet 초기화에 사용된 xml과 같은 기능을 한다.

  @Override

  protected Class<?>[] getServletConfigClasses() {

    return new Class[] { WebConfig.class };

  }


// web.xml의 servlet mapping 부분을 대체한다.

  @Override

  protected String[] getServletMappings() {

    return new String[] { "/" };

  }


}


파일명: SpringMvcAnnotation.java


[첨부(Attachments)]

SpringMvcAnnotation.zip




이 파일을 시작점으로 한다.


package com.springMVC.javaSecurity5.config;


import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import org.springframework.web.servlet.view.InternalResourceViewResolver;

 

@EnableWebMvc // <mvc:annotation-driven>에 해당.

// @ComponentScan(basePackages = {"com.figo.web"})  // <context:component-scan base-package="”com.figo.web”/">에 해당됨.

@ComponentScan("com.springMVC.javaSecurity5")

@Configuration

public class WebConfig extends WebMvcConfigurerAdapter {

 

    // <resources mapping="/resources/**" location="/resources/">에 해당됨.

    @Override

    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/").setCachePeriod(31556926);

    }

 

    // <mvc:default-servlet-handler>에 해당됨.

    @Override

    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

        configurer.enable();

    }   

     

    // web.xml에서 봤던 내용들임.

    @Bean

    public InternalResourceViewResolver getInternalResourceViewResolver() {

        InternalResourceViewResolver resolver = new InternalResourceViewResolver();

        resolver.setPrefix("/WEB-INF/views/");

        resolver.setSuffix(".jsp");

        return resolver;

    }

    

    /*

    @Override

    public void addViewControllers(ViewControllerRegistry registry) {

   

        // registry.addViewController("/web").setViewName("home");

        registry.addViewController("/").setViewName("home");

        

    }

    */

 

}


파일명: WebConfig.java


[첨부(Attachments)]

WebConfig.zip



참고: HomeController의 초기내용으로 두고 서버 상에서 실행시켜봤다면, 동작했을 것으로 보인다.
(10번까지 잘 따라왔으면 화면 출력을 볼 수 있음.)



11. Controller - HomeController.java


HomeController에 관한 내용이다. 자세히 보면, "13, 14, 15번"글하고 거의 동일하다는 것을 알 수 있다.

쉽게 이야기하면, web.xml 파일부터 xml로 구성된 환경설정 파일을 프로젝트 내에서 제거한 것이다.

그러니 Controller 등은 동일할 수 밖에 없다고 본다.



package com.springMVC.javaSecurity5.controller;


import java.security.Principal;

import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import javax.servlet.http.HttpServletRequest;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.crypto.password.PasswordEncoder;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;


//@CrossOrigin(origins = "*", allowedHeaders = "*")

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);


@RequestMapping("/")

public String home(Locale locale, Model model, Principal principal) {


logger.info("Welcome home! The client locale is {}.", locale);


Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

String username = null;

// Principal 예제

if (principal != null) {

username = principal.getName();

System.out.println("타입정보 : " + principal.getClass());

System.out.println("ID정보 : " + principal.getName());

}

model.addAttribute("username", username);

model.addAttribute("serverTime", formattedDate );


return "home";

}

@RequestMapping("/admin")

public String admin(Locale locale, Model model) {

return "admin";

}


@RequestMapping(value = "/encode-password", method = RequestMethod.GET)

public String passwordEncode(Locale locale, Model model, HttpServletRequest req) {


// 1. xml 방식에서 java 방식으로 전환

// web.xml 파일 제거로 인한 사용 불가(ServletConfig sc 연결됨)

// WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());

        // PasswordEncoder passwordEncoder = context.getBean(PasswordEncoder.class);


PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        String password = req.getParameter("password");

        String encode = passwordEncoder.encode(password);


        model.addAttribute("encode", encode);

        System.out.println(encode);

        

        return "home";

        

}


}


파일명: HomeController.java


[첨부(Attachments)]

HomeController.zip





12. Controller - AdminController.java


관리자 페이지에 관한 내용이다.


package com.springMVC.javaSecurity5.controller;

import java.util.Locale;


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 AdminController {


private static final Logger logger = LoggerFactory.getLogger(AdminController.class);


@RequestMapping(value = "/admin/home", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome - 관리자 페이지(Admin Home)!");


return "admin/home";

}


}



파일명: AdminController.java


[첨부(Attachments)]

AdminController.zip



13. Controller - MemberController.java


MemberController.java에 관한 내용이다.


package com.springMVC.javaSecurity5.controller;


import java.util.Locale;


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 MemberController {


// 커스텀 페이지 - 양식만

private static final Logger logger = LoggerFactory.getLogger(MemberController.class);


@RequestMapping(value = "/member/loginForm")

public String loginForm(Locale locale, Model model) {

logger.info("안녕 - 로그인 폼(Hello - Login Form");

// model.addAttribute("serverTime", formattedDate );

return "member/loginForm";

}


@RequestMapping(value = "/member/accessDenied")

public String accessDenied(Locale locale, Model model) {

logger.info("접근 금지 - 이동(Accessed Denied)");

// model.addAttribute("serverTime", formattedDate );

return "redirect:/member/accessDeniedView";

}

@RequestMapping(value = "/member/accessDeniedView")

public String accessDeniedView(Locale locale, Model model) {

logger.info("접근 금지 - 출력(Accessed Denied)");

// model.addAttribute("serverTime", formattedDate );

return "member/accessDenied";


}

}



파일명: MemberController.java


[첨부(Attachments)]

MemberController.zip




* 2부에서는


2부에서는 Spring-Security 설정에 대해서 집중적으로 다뤄보도록 하겠다.

조금 어려울 수도 있으니 마음을 편안하게 하고 따라해보면 좋겠다.


1. [Spring-Framework] 16. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-Java) (2), 2020-09-27

https://yyman.tistory.com/1423


반응형

+ Recent posts