[JSP] 8. 영속프레임워크 MyBatis를 활용한 CRUD 구현 - JSP와 Oracle(XML 방식)
조금 알기 쉽게 작성하였다.
"영속 프레임워크"라고 보면 된다.
영속 프레임워크라는 것은 DAO 객체에서 데이터베이스 데이터의 처리 기능을 제공하는 프레임워크이다.
대표적인 것: myBatis, Hibernate가 있다.
* 사용되는 언어: JSP / Servlet,
* 데이터베이스: Oracle 12 이상 (Oracle 18g에서 태스트 완료 하였음.)
* 프레임워크: mybatis-3.5.5
[첨부(Attachments)]
mybatis-3.5.5.jar
mybatis-3.5.5(원본).7z
1. 최소한 관련 프레임워크에 대해서 이해해보기
프레임워크의 특징에 대해서 간단하게 작성해보았다.
[특징]
myBatis란 그나마 학습하기 쉽고, 사용방법이 간단함.
초기 셋팅을 조금한 후에 나머지는 SQL명령문과 간단한 자바 소스코드로 구현하여 사용할 수 있음.
(iBatis 프로젝트로 시작해서 현재는 Apache Foundation에서 관리하는 자바 오픈소스 프레임워크)
http://www.mybatis.org
hibernate란 ORM(Object-Relational Mapping) 프레임워크라는 영속 프레임워크로서 자바와 객체와 데이터베이스를 매핑하여 데이터를 처리하므로 엔터프라이즈 환경에 적합한 특징을 가지고 있음.
(배우기 어려움. - 객체 모델링 경험이 요구됨.)
http://hibernate.org
[생각해보기]
생각을 조금해본다면, 꼭 반드시 웹 프로젝트에만 MyBatis를 활용할 필요가 없음.
일반적인 Swing 프로젝트 연습 등에서도 사용해볼 수도 있겠음.
- 프레임워크 사용하기 전에 고민해야 할 점
1. 기본적으로 제공하는 JDBC 구현에 대해서도 생각해보기
(이유: 자바에서 자체적으로 제공하는 jdbc 구현(예: ResultSet, prepareStatement 등)에 대해서 이해하고 있으면 좋음.)
2. 프레임워크를 사용하는 것이 만능인지, 고민하기
3. SQL Injection 등의 보안 문제에 대해서 생각하기
(프레임워크를 사용하면, SQL Injection 문제는 간단하게 해소된다.)
결론은 좋긴 좋다. 프레임워크!!!
[코드 비교하기]
Mybatis 사용전 코드 방식 | Mybatis 사용후 코드 방식 |
public Entity selectFAQList(UserConnection conn, Entity param)
throws SQLException { UserStatement stmt = null; //stmt 초기값 선언 ResultSet rslt = null; //rslt 초기값 선언 StringBuffer sql = new StringBuffer(); sql.append("\n SELECT *"); // sql.append("\n FROM"); //코드 추가 sql.append("\n TABLE1"); stmt = conn.prepareStatement(sql.toString()); rslt = stmt.executeQuery(); Entity _DATA = new Entity(); _DATA.put("_DATA", EntityUtil.ResultSetToClobList(rslt)); return _DATA; }
| <?xml version="1.0" encoding="UTF-8"?> <ENTITY id="table.getTable1List" type="SQL" return="List"> <![CDATA[ SELECT * FROM TABLE1 ]]> <PARAMS> </PARAMS> </ENTITY>
// xml로 빼내서 쿼리문을 작성하면 내부적 처리는 Mybatis에서
// 모두 처리해주므로 // Entity ID값을 java에서 호출만하면 된다. |
2. 초기 환경설정 셋팅하기
시중 블로그를 다수 검색하고, 교제등을 참고하였으나 왕초보 수준으로 알기 쉽게 적용하는 방법은 나오지 않은 거 같아서 작성해보려고 한다.
그림 1. 초기 셋팅해줘야 하는 프로젝트 파일
최소 못해도 기본적으로 갖춰줘야 하는 소스 파일들을 몇 개 찝어보았다.
"Address_****.파일확장자명"으로 구성된 파일은 사용자에 따라 임의적으로 구성해봐도 무방하다.
ojdbc8_g.jar은 어디에 있는가?
오라클 설치파일이 있는 폴더에 보면 jdbc 폴더가 있는데 해당 위치에 있다.
그림 2. 오라클 설치 파일이 있는 폴더
그림 3. jdbc 폴더에 있는 readme.txt
그림 4. jdbc/lib 폴더 내에 있음.
[첨부(Attachments)]
oracle12lib.z01
oracle12lib.z02
oracle12lib.zip
(참고로 반디집을 통해서 압축을 풀 수 있음.)
소스코드를 통해서 살펴보는 것이 조금 빠를 수 있다고 주장해 본다.
3. 데이터베이스 설계하기
예제 데이터베이스를 설계하도록 하겠다.
tableName(테이블명): addressbook
키 |
항목명 |
속성 |
PK(기본키) |
num |
인덱스(ID) |
|
name |
nvarchar |
|
address |
nvarchar |
|
birthdate |
date |
그림 5. 테이블 만들기(오라클)
그림 5는 SQL Developer를 통해서 테이블을 생성한 모습이다.
원래 복잡하게 쿼리라는 것을 통해서 작성해야 하는데, 세상이 시간이 지나다보니 편리해진 것도 있다고 주장한다.
CREATE TABLE "C##USER"."ADDRESSBOOK"
( "NUM" NUMBER(*,0) NOT NULL ENABLE,
"NAME" NVARCHAR2(20),
"ADDRESS" NVARCHAR2(100),
"BIRTHDATE" DATE,
CONSTRAINT "ADDRESSBOOK_PK" PRIMARY KEY ("NUM")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
...............................
(중략)
ALTER TRIGGER "C##USER"."ADDRESSBOOK_TRG" ENABLE;
그림 6. SQL문으로 Create Table 구성하기
그림 6은 흔히 CRUD(Create Read Update Delete)에서의 Create를 의미하는 작업이다.
예를 들면 원래는 이렇게 복잡하게 작성해야 하는데 지금은 훨씬 편하게 만들 수 있다고 보면 된다.
4. 프로젝트 구성하기 - 과정 소개 (소스코드를 통해서 살펴보는 프로젝트 구성)
1단계 설계
SQL - 테이블 작성
2단계 기본 환경설정 작성(준비)
web.xml을 먼저 작성한다. (암기가 되는 부분인가? 불가능. 이거 외우는 거 불가능.)
mybatis-config.xml (암기가 되는 부분인가? 불가능. 이거 외우는 거 불가능.)
SqlMapSessionFactory.java (암기가 되는 부분인가? 불가능. 이거 외우는 거 불가능.)
AddressDto.java
addressMapper.xml (암기가 되는 부분인가? 불가능. 이거 외우는 거 불가능.)
3단계(간단한 CRUD 템플릿 준비)
addressDao.java (암기가 되는 부분인가? 코드는 간단하나 2단계 셋팅이 안 되어 있으면 의미 없음.)
4단계(인터페이스 설계 및 구현부 작성)
address.java
addressImpl.java
5단계(뷰 페이지 구성하기)
web.xml (수정 - 작업)
servlet 페이지로 진행 또는 jsp파일로 진행해도 무방
5. 소스코드
소스코드는 순서대로 소개하겠다.
(2단계 - 소스코드)
<?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">
<display-name>edu-mybatis</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- Board List -->
<servlet>
<servlet-name>boardList</servlet-name>
<servlet-class>com.edu.view.BoardListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>boardList</servlet-name>
<url-pattern>/board/list.do</url-pattern>
</servlet-mapping>
<!-- Board Insert -->
<servlet>
<servlet-name>boardInsert</servlet-name>
<servlet-class>com.edu.view.BoardInsertServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>boardInsert</servlet-name>
<url-pattern>/board/insert.do</url-pattern>
</servlet-mapping>
<!-- Board Delete -->
<servlet>
<servlet-name>boardDelete</servlet-name>
<servlet-class>com.edu.view.BoardDeleteServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>boardDelete</servlet-name>
<url-pattern>/board/delete.do</url-pattern>
</servlet-mapping>
</web-app>
* 파일명: web.xml
[첨부(Attachments)]
web.zip
예를 들면, 이런 형태로 구성해서 사용할 수 있다.
크게 어렵게 작성하진 않았으니 참고하면 도움이 될 것 같다.
<?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"/>
<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="사용자 계정"/>
<property name="password" value="비밀번호"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/edu/db/addressMapper.xml"/> // 리소스 증가시 추가해서 사용해보기
</mappers>
</configuration>
* 파일명: mybatis-config.xml
[첨부(Attachments)]
mybatis-config.zip
package com.edu.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 static SqlSessionFactory ssf;
static{
String resource = "com/edu/db/mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
ssf = new SqlSessionFactoryBuilder().build(inputStream);
}
public static SqlSessionFactory getSqlSessionFactory(){
return ssf;
}
}
* 파일명: SqlMapSessionFactory.java
[첨부(Attachments)]
SqlMapSessionFactory.zip
package com.edu.db;
import java.sql.Timestamp;
public class AddressDto {
private int num;
private String name;
private String address;
private Timestamp birthdate;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Timestamp getBirthdate() {
return birthdate;
}
public void setBirthdate(Timestamp birthdate) {
this.birthdate = birthdate;
}
}
* 파일명: AddressDto.java
[첨부(Attachments)]
AddressDto.zip
<?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.edu.db.mappers.addressMapper">
<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>
* 파일명: addressMappper.xml
[첨부(Attachments)]
addressMapper.zip
(3단계 - 소스코드)
package com.edu.db;
import java.io.*;
import java.util.*;
import org.apache.ibatis.io.*;
import org.apache.ibatis.session.*;
public class AddressDao {
private AddressDao() {}
private static AddressDao dao;
public static AddressDao getInstance(){
if(dao == null){
dao = new AddressDao();
}
return dao;
}
// SQL 세션 열기
SqlSessionFactory factory = SqlMapSessionFactory.getSqlSessionFactory();
public AddressDto selectAddress(Integer num) {
SqlSession session = factory.openSession();
AddressDto addressDTO = session.selectOne("com.edu.db.mappers.addressMapper.selectAddress", num);
session.close();
return addressDTO;
}
public int updateAddress(AddressDto addressDTO) {
SqlSession session = factory.openSession();
int update = session.update("com.edu.db.mappers.addressMapper.updateAddress", addressDTO);
// update나 delete의 경우 반드시 커밋 필요.
// session.commit();을 해주거나 factory.openSession(true);로 설정하면 자동 커밋된다.
session.commit();
session.close();
return update;
}
public int insertAddress(AddressDto addressDTO) {
SqlSession session = factory.openSession();
int insert = session.insert("com.edu.db.mappers.addressMapper.insertAddress", addressDTO);
session.commit();
session.close();
return insert;
}
public int deleteAddress(Integer num) {
SqlSession session = factory.openSession();
int delete = session.delete("com.edu.db.mappers.addressMapper.deleteAddress", num);
session.commit();
session.close();
return delete;
}
}
* 파일명: AddressDao.java
특징: Singleton 패턴을 적용함.
[첨부(Attachments)]
AddressDao.zip
(4단계 - 소스코드)
package com.edu.db;
public interface Address {
public AddressDto getAddress(Integer num);
public int updateAddress(AddressDto addressDTO);
public int insertAddress(AddressDto addressDTO);
public int deleteAddress(Integer num);
}
* 파일명: Address.java
특징: Interface 파일
[첨부(Attachments)]
Address.zip
package com.edu.db;
public class AddressImpl implements Address {
AddressDao dao = AddressDao.getInstance();
@Override
public AddressDto getAddress(Integer num) {
return dao.selectAddress(num);
}
@Override
public int updateAddress(AddressDto addressDTO) {
return dao.updateAddress(addressDTO);
}
@Override
public int insertAddress(AddressDto addressDTO) {
return dao.insertAddress(addressDTO);
}
@Override
public int deleteAddress(Integer num) {
return dao.deleteAddress(num);
}
}
* 파일명: AddressImpl.java
특징: Address 인터페이스 구현파일
[첨부(Attachments)]
AddressImpl.zip
(5단계 - Servlet 파일 예)
package com.edu.view;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.edu.db.Address;
import com.edu.db.AddressDto;
import com.edu.db.AddressImpl;
/**
* Servlet implementation class boardListServlet
*/
public class BoardListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BoardListServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest req, HttpServletResponse res)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=UTF-8");
PrintWriter out = res.getWriter();
out.print("<br/>");
AddressImpl address = new AddressImpl();
AddressDto addressDto = address.getAddress(1);
out.println("<html><head><title>CRUD - List2</title></head>");
out.println("<body><h2>MyBatis - List</h2>");
SimpleDateFormat format1 = new SimpleDateFormat ( "yyyy-MM-dd" );
String birthdate = format1.format(addressDto.getBirthdate());
out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");
out.print(addressDto.getAddress() + "/" + birthdate);
out.print("<br/>");
out.println("</body></html>");
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest req, HttpServletResponse res)
*/
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
doGet(req, res);
}
}
* 파일명: boardListServlet.java
어노테이션으로 맵핑하지 않고, web.xml에 URL 맵핑하였음.
[첨부(Attachments)]
BoardListServlet.zip
package com.edu.view;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Timestamp;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.edu.db.Address;
import com.edu.db.AddressDto;
import com.edu.db.AddressImpl;
/**
* Servlet implementation class boardInsertServlet
*/
public class BoardInsertServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BoardInsertServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest req, HttpServletResponse res)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=UTF-8");
PrintWriter out = res.getWriter();
out.print("<br/>");
AddressImpl address = new AddressImpl();
AddressDto dbNode = new AddressDto();
dbNode.setName("도도" + serialVersionUID);
dbNode.setAddress("행복시 행복동");
// 버그1: new Date() 사용안됨. (2020을 3920으로 인식함.)
// 버그2: new Timestamp() 사용안됨. (2020을 3920으로 인식함.)
String userDate = "2020-02-01";
java.sql.Timestamp sqlDate = java.sql.Timestamp.valueOf(userDate);
dbNode.setBirthdate(sqlDate);
int result = address.insertAddress(dbNode);
AddressDto addressDto = address.getAddress(1);
out.println("<html><head><title>CRUD - Insert</title></head>");
out.println("<body><h2>MyBatis - Insert</h2>");
out.print("<br/>");
out.print("등록여부:" + result + "</br>");
out.print("<br/>");
out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");
out.print(addressDto.getAddress() + "/" + addressDto.getBirthdate());
out.println("</body></html>");
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest req, HttpServletResponse res)
*/
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
doGet(req, res);
}
}
* 파일명: boardInsertServlet.java
[첨부(Attachments)]
BoardInsertServlet.zip
package com.edu.view;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Timestamp;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.edu.db.Address;
import com.edu.db.AddressDto;
import com.edu.db.AddressImpl;
/**
* Servlet implementation class boardInsertServlet
*/
public class BoardDeleteServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BoardDeleteServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest req, HttpServletResponse res)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=UTF-8");
PrintWriter out = res.getWriter();
out.print("<br/>");
AddressImpl address = new AddressImpl();
int result = address.deleteAddress(5);
AddressDto addressDto = address.getAddress(5);
out.println("<html><head><title>CRUD - Delete</title></head>");
out.println("<body><h2>MyBatis - Delete</h2>");
out.print("<br/>");
out.print("삭제여부:" + result + "</br>");
out.print("<br/>");
if ( addressDto != null ) {
out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");
out.print(addressDto.getAddress() + "/" + addressDto.getBirthdate());
}
out.println("</body></html>");
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest req, HttpServletResponse res)
*/
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
doGet(req, res);
}
}
* 파일명: BoardDeleteServlet.java
[첨부(Attachments)]
BoardDeleteServlet.zip
package com.edu.view;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Timestamp;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.edu.db.AddressDto;
import com.edu.db.AddressImpl;
@WebServlet("/board/update.do")
public class BoardUpdateServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public BoardUpdateServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=UTF-8");
PrintWriter out = res.getWriter();
out.print("<br/>");
AddressImpl address = new AddressImpl();
AddressDto dbNode = new AddressDto();
dbNode.setNum(3);
dbNode.setName("도도수정" + serialVersionUID);
dbNode.setAddress("행복시 행복동");
// 버그1: new Date() 사용안됨. (2020을 3920으로 인식함.)
// 버그2: new Timestamp() 사용안됨. (2020을 3920으로 인식함.)
String userDate = "2020-07-01";
java.sql.Timestamp sqlDate = java.sql.Timestamp.valueOf(userDate);
dbNode.setBirthdate(sqlDate);
int result = address.updateAddress(dbNode);
AddressDto addressDto = address.getAddress(3);
out.println("<html><head><title>CRUD - Update</title></head>");
out.println("<body><h2>MyBatis - Update</h2>");
out.print("<br/>");
out.print("수정여부:" + result + "</br>");
out.print("<br/>");
out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");
out.print(addressDto.getAddress() + "/" + addressDto.getBirthdate());
out.println("</body></html>");
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
doGet(req, res);
}
}
* 파일명: BoardUpdateServlet.java
특징: web.xml으로 맵핑하지 않고, @WebServlet으로 어노테이션을 사용하여 매핑처리함.
[첨부(Attachments)]
BoardUpdateServlet.zip
6. 맺음글
순수한 JSP 기반의 MyBatis 프레임워크 사용방법에 대해서 소개해보았다.
많은 도움이 되었으면 좋겠다.
1. [JSP] 19. MyBatis-3.5.5 와 Maven / Servlet 연동하기 (Oracle 19g) - Java 방식, 2020-10-01
https://yyman.tistory.com/1434
[참고 자료(Reference)]
1. [Java, OpenJDK] Timestamp 형식 변환, https://infotake.tistory.com/16, Accessed by 2020-09-18, Last Modified 2018-09-13.
-> 참고 이유: Timestamp 명령 사용방법 참고함.
2. 내가 그리는 세상 DB(mysql)에 timestamp로 저장된 값 java에서 불러오기_getTimestamp(), https://yoonka.tistory.com/450, Accessed by 2020-09-18, Last Modified 2013-10-28.
3. [JSP] Mybatis 사용하기 또리야 개발하자, https://ddoriya.tistory.com/entry/JSP-Mybatis-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0, Accessed by 2020-09-17, Last Modified 2014-11-18.
-> 추천(60점 이상): 이 사이트의 글만 가지고 따라하면, 완벽하게 동작이 되진 않음. 몇 가지 보충을 해줘야 해서 추가적으로 검색하였음.
그래도 순수한 MyBatis 원리에 대해서 많은 영감을 얻었음.
4. Oracle와 mybatis 연동 실습, https://dlgkstjq623.tistory.com/228, Accessed by 2020-09-18, Last Modified 2019-06-05.
-> 추천(40점 이상): 이 사이트의 글을 이해하려면, Spring Framework 지식과 JSTL 지식이 있어야 함.
기본적인 흐름 정도 파악하는데 참고하였음. (이론적인 느낌을 얻었음.)
5. MyBatis – 마이바티스 3 | 소개, https://mybatis.org/mybatis-3/ko/index.html, Accessed by 2020-09-18, Last Modified 2020-06-05.
-> 추천(20점 이상): 설명서가 조금 어렵게 되어 있음. 셋팅 파일을 가지고 셋팅한 후 설명서를 참고하면 도움이 될 수도 있음.
6. 4. Spring Boot Oracle DB 연동(JSP, MyBatis), https://dotheright.tistory.com/173, Accessed by 2020-09-18, Last Modified 2020-07-15.
-> 삽질하여 실패와 탐구 등의 횟수 기록이 담겨져 있음. ("삽질을 하게 된다.??" 이런 느낌을 보여줌.)
-> Spring Framework 기반으로 만든 소스코드를 소개하고 있음. (이 게시글 작성에 있어서 크게 영향을 주지 못함.)
7. [JSP] JSP에 MyBatis 연결하기, https://yuja-kong.tistory.com/8, Accessed by 2020-09-18, Last Modified 2018-04-17.
-> 추천(50점 이상): 순수한 JSP와 MyBatis 연결에 대해서 소개하고 있는데, 이 글을 작성할 수 있는 가능성을 만들어 줌.
8. JSP 서블릿 한글 세팅(한글 깨짐 해결 하기), https://developsd.tistory.com/100, Accessed by 2020-09-18, Last Modified 2019-05-18.
-> 추천(20점): 오라클DB(이하 "UTF-8 셋팅한 오라클")로 데이터를 불러오려고 했을 때, ?????라고 한글을 인식하지 못했음.
간단한 명령어 하나로 해결하는 데 도움을 받았음. (가끔은 쉬운 게 어렵고, 어려운 게 쉬울 때도 있다는 생각이 듬.)
1. 파일의 인코딩 속성을 "UTF-8"으로 변경
2. response.setContentType("text/html;charset=UTF-8");