728x90
300x250

[심심풀이(pastime)] 전자 - 연구노트(디지털노트)

 

이번에 소개할 내용은 앞에서 종이 연구노트에 대해서 살펴보았는데, 이번에는 전자식 연구노트에 대해서 살펴보려고 한다.

구현은 다 하진 않았으나 큰 의미는 없을 것으로 보인다.

기술적으로는 "인증체계를 갖추고, 전자식 서명을 해야한다."라고 되어 있으나, 오픈소스 게시판을 활용하거나 다른 다양한 방법으로 사용해도 무방할 것으로 보인다.

 

[심심풀이(pastime)] 연구 노트 작성하기(종이 연구노트), 2021-06-27. 19:32
https://yyman.tistory.com/1573

1. 소개

전자식 연구노트이다. 

완성 작품은 아니지만, 공개를 하였다.

 

package com.stream.digitalnote.dto;

public class MemberDTO {

          private String id;
          private String uuid;

          private String email;
          private String passwd;

          private String level;
          private String ipv4;
          private String ipv6;

          private String regidate;

          public String getId() {
                    return id;
          }

          public void setId(String id) {
                    this.id = id;
          }

          public String getUuid() {
                    return uuid;
          }

          public void setUuid(String uuid) {
                    this.uuid = uuid;
          }

          public String getEmail() {
                    return email;
          }

          public void setEmail(String email) {
                    this.email = email;
          }

          public String getPasswd() {
                    return passwd;
          }

          public void setPasswd(String passwd) {
                    this.passwd = passwd;
          }

          public String getLevel() {
                    return level;
          }

          public void setLevel(String level) {
                   this.level = level;
          }

          public String getIpv4() {
                   return ipv4;
          }

          public void setIpv4(String ipv4) {
                    this.ipv4 = ipv4;
          }

          public String getIpv6() {
                    return ipv6;
          }

          public void setIpv6(String ipv6) {
                   this.ipv6 = ipv6;
          }

          public String getRegidate() {
                    return regidate;
          }

          public void setRegidate(String regidate) {
                   this.regidate = regidate;
          }

}
 

 


2. 첨부(Attachment)

210627_based_web_electronic_write_a_study.zip
0.73MB

(Apache License v2.0을 적용받는다.)

 


3. 맺음글(Conclusion)

전자식 연구노트에 대해서 살펴보았다.

 


4. 참고자료(Reference)

1.

반응형
728x90
300x250

[이야기] JSP/Servlet의 RestEasy 4.8(Jboss)로 Rest 실험 이야기(한글 미지원)


결론부터 이야기하면, REST 구현에는 성공했다. 하지만, 문제는 한글 문제인데, 인코딩 관련해서 많은 실험을 하였으나 동작하지 않았다.

삽질하려고 하는 사람이 있다면, 정리하는 걸 추천한다.


REST가 쉽사리 활성화되지 않은 이유도 있을 거 같다. 

C#이나 PHP, C++은 되는지 아직 확인은 안 해봤으나 C#은 되지 않을까 싶다.



1. 주제, 실험 환경


자바 JSP/Servlet으로 REST를 구축할 수 있는지 실험하였다.


- Apache Tomcat 9 - 2020년 9월 기준 - 최신

- Maven 3.6 - 2020년 9월 기준 - 최신

- 각종 RESTEasy 4.5.3 - 2020년 9월 기준 - 최신 (pom 셋팅)......



2. 내용 - 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.restmaven</groupId>

  <artifactId>restWeb</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


  <name>restWeb Maven Webapp</name>

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

  <url>http://localhost</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>

    

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

       

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->

<dependency>

    <groupId>com.fasterxml.jackson.core</groupId>

    <artifactId>jackson-databind</artifactId>

    <version>2.11.2</version>

</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->

<dependency>

    <groupId>com.fasterxml.jackson.core</groupId>

    <artifactId>jackson-core</artifactId>

    <version>2.11.2</version>

</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->

<dependency>

    <groupId>com.fasterxml.jackson.core</groupId>

    <artifactId>jackson-annotations</artifactId>

    <version>2.11.2</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-core -->

<dependency>

    <groupId>org.jboss.resteasy</groupId>

    <artifactId>resteasy-core</artifactId>

    <version>4.5.8.Final</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-jaxb-provider -->

<dependency>

    <groupId>org.jboss.resteasy</groupId>

    <artifactId>resteasy-jaxb-provider</artifactId>

    <version>4.5.8.Final</version>

</dependency>


<!-- https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-jsapi -->

<dependency>

    <groupId>org.jboss.resteasy</groupId>

    <artifactId>resteasy-jsapi</artifactId>

    <version>4.5.8.Final</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-jackson2-provider -->

<dependency>

    <groupId>org.jboss.resteasy</groupId>

    <artifactId>resteasy-jackson2-provider</artifactId>

    <version>4.5.8.Final</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-multipart-provider -->

<dependency>

    <groupId>org.jboss.resteasy</groupId>

    <artifactId>resteasy-multipart-provider</artifactId>

    <version>4.5.8.Final</version>

</dependency>

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->

<dependency>

    <groupId>commons-io</groupId>

    <artifactId>commons-io</artifactId>

    <version>2.8.0</version>

</dependency>

  

  </dependencies>

 


  <build>

    <finalName>restWeb</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



3. 내용 - web.xml 설정 사항


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

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"

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

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

 

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

  

  <context-param>

  <param-name>resteasy.resources</param-name>

  <param-value>com.example.restweb.resources.MyResources</param-value>

  </context-param>

  <context-param>

  <param-name>resteasy.servlet.mapping.prefix</param-name>

  <param-value>/rest</param-value>

  </context-param>


  <listener>

  <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>

  </listener>


  <servlet>

  <servlet-name>Resteasy JSAPI</servlet-name>

<servlet-class>org.jboss.resteasy.jsapi.JSAPIServlet</servlet-class>

</servlet>

  <servlet-mapping>

  <servlet-name>Resteasy JSAPI</servlet-name>

  <url-pattern>/rest-js</url-pattern>

  </servlet-mapping>


  <servlet>

  <servlet-name>Resteasy</servlet-name>

  <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>

  </servlet>

  <servlet-mapping>

  <servlet-name>Resteasy</servlet-name>

  <url-pattern>/rest/*</url-pattern>

  </servlet-mapping>

 

  <servlet>

  <servlet-name>HomeServlet</servlet-name>

  <servlet-class>com.example.restweb.controller.HomeServlet</servlet-class>

  </servlet>

  <servlet-mapping>

  <servlet-name>HomeServlet</servlet-name>

  <url-pattern>/HomeServlet</url-pattern>

  </servlet-mapping>

  

</web-app>



파일명: web.xml



4. 내용 - 기본 컨트롤러 셋팅하기


RestEasy의 사용자 구현에서는 핵심이라고 보면 된다.

크게 사용방법에서는 어려운 건 아니다.


난해할 수 있는 주제가 있는데, String 등으로 바로 반환이 안 되는지.

고민해볼 수 있는 문제가 있다.


= "안 된다. 미지원이다."


Response로 무조건 return 반환을 해줘야 한다. 

(Spring Framework 5 - REST 공부하다가 이거 하라고 하면 납득이 안 될 수 있는 부분이 많다.)


package com.example.restweb.resources;


import com.example.restweb.model.FileInfo;


import javax.ws.rs.Consumes;

import javax.ws.rs.Encoded;

import javax.ws.rs.FormParam;

import javax.ws.rs.GET;

import javax.ws.rs.POST;

import javax.ws.rs.PUT;

import javax.ws.rs.Path;

import javax.ws.rs.PathParam;

import javax.ws.rs.Produces;

import javax.ws.rs.QueryParam;

import javax.ws.rs.core.Context;

import javax.ws.rs.core.MediaType;

import javax.ws.rs.core.Response;

import javax.ws.rs.core.UriInfo;


import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;


@Path("/api")

public class MyResources

{

// Index

@GET

@Path("")

    @Produces("application/json")

public Response get()

{

StringBuffer buf = new StringBuffer();

buf.append("ok");

return Response.status(200).entity(buf).build();

}


    @GET

    @Path("users/{id}")

    @Produces("application/json")

    public Response getUserById(@PathParam("id") Integer id)

    {

        User user = new User();

        user.setId(id);

        user.setFirstName("Lokesh");

        user.setLastName("Gupta");

        

        return Response.status(200).entity(user).build();

    }

    

    @Path("foo/{param}-{other}")

@PUT

    @Produces("application/json")

public Response putFooParam(@PathParam("param") String param,

  @PathParam("other") String other)

{

StringBuffer buf = new StringBuffer();

buf.append("param").append("=").append(param).append(";");

buf.append("other").append("=").append(other).append(";");

return Response.status(200).entity(buf).build();

}

    

@Path("form")

@POST

    @Produces("application/json")

public String postForm(@FormParam("id") String a,

   @FormParam("passwd") String b){

return a +"/" +b;

}


@Path("lookup")

@GET

    @Produces("application/json")

public Response lookup(@QueryParam("id") String id,

@Context UriInfo uriInfo)

{


StringBuffer buf = new StringBuffer();

buf.append("param").append("=").append(id).append(";");

return Response.status(200).entity(buf).build();

}


    @POST

    @Path("/upload-file")

    @Consumes(MediaType.MULTIPART_FORM_DATA)

    public Response uploadFile(@MultipartForm FileInfo info) throws Exception {

   

    String fileName = info.getFileName();

   

    // RESTEasy는 한글 자체가 안됨.

   

    /*

    form.setFileName(filename);

   

    System.out.println("파일명1:" + form.getFileName());

   

        String fileName = form.getFileName() == null ? "Unknown" : form.getFileName() ;

        String completeFilePath = "c:/temp2/" + fileName;

        try

        {

            //Save the file

            File file = new File(completeFilePath);

              

            if (!file.exists()) 

            {

                file.createNewFile();

            }

      

            FileOutputStream fos = new FileOutputStream(file);

      

            fos.write(form.getFileData());

            fos.flush();

            fos.close();

        } 

        catch (IOException e)

        {

            e.printStackTrace();

        }

        //Build a response to return

        */

   

        return Response.status(200)

            .entity("uploadFile is called, Uploaded file name : " + fileName).build();

        

   

    }

    

    

}


파일명: MyResources.java



5. 결과


실험1)

-> 문자셋 찾기 실험(UTF-8, Euc-kr, us-ascil, windows-1251, ISO-8851-9? 등)

    (반복문으로 해당 문자인지 찾는 작업을 하였음.)

(실패)


실험2)

-> <form 태그 accept- utf-8> 가능하도록 설정

(실패)


실험3)

-> new String (originalText.getBytes("ISO-8851-9), "UTF-8") 등 변환 작업

(실패)

.......

실험4)

-> public response 함수명(@Context ServletRequest req......)에 req.setCharacterEncoding 설정

(실패)



(다수의 방법을 적용하였음.)


결과는 RESTEasy 프로젝트에서 한글 자체를 해결해줘야 한다. 그렇지 않으면 어렵다.

이 프로그램은 영어로 글을 작성한다고 했을 때는 동작한다.


단순한 영어나 숫자 형태로 전송 작업을 시도하고 싶다면, 해봐도 무방하다. 한글 등은 기대 안 하는 게 좋을 듯 싶다.


RESTEasy 이외에 흥미로운 발견을 한 부분도 있다.

Servlet 생성할 때 셋팅화면에 자세히 보면, doPut, doDelete, doGet, doPost 기능이 있다.

문제는 패턴 등을 잡을 때 한계가 생긴다. (힘들고 무척 어렵다는 이야기이다.)


이 실험은 그런 부분은 해소하였다.




[첨부(Attachments)]

restEasy-한글미지원(Unsupported_Korean_Language).zip

(Spring Tool-Suite 4.4에서 작성함.)





* 참고자료(References)


1. RESTEasy JAX-RS, https://docs.jboss.org/resteasy/docs/4.5.8.Final/userguide/html/, Accessed by 2020-09-29, Last Modified 2020-09-23.

   = (RESTEasy 기술 정보가 해외, 국내에 많이 부족해서 공식 메뉴얼을 참고할 수 밖에 없음)


2. Chapter 3. Installation/Configuration, / 3.3. Deploying to other servlet containers, https://docs.jboss.org/resteasy/docs/4.5.8.Final/userguide/html/Installation_Configuration.html


3. RESTEasy JSON Example with Jackson, https://howtodoinjava.com/resteasy/resteasy-jackson-json-example/, Accessed by 2020-09-29, Last Modified 2013.

   = (RESTEasy에서의 다중 업로드 기능에 대해서는 잘 소개하고 있다.)


4. /resteasy/test/smoke/MyResource.java - Github, https://github.com/resteasy/resteasy-examples/blob/master/jsapi-servlet-test/src/main/java/org/jboss/resteasy/test/smoke/MyResource.java, Accessed by 2020-09-29, Last Modified 2016-08-05.

   = 조금 된 소스코드이나 RESTEasy를 쉽게 빠르게 구축하는 방법이 적혀져 있다.

   = 문제는 저 코드대로 전부 따라해보면, 안 된다. 태스트를 수 차례 각종 URL을 넣어봐서 되는 코드는 살리고 참고를 많이 하였다.


5. JSON Example With RESTEasy + Jackson, https://examples.javacodegeeks.com/enterprise-java/rest/resteasy/json-example-with-resteasy-jackson/, Accessed by 2020-09-29, Last Modified 2013-12-09

   = 구축 원리를 차근차근 화면 그림 위주로 소개하고 있다.


6. RESTEasy File Upload – Html Form Example, https://howtodoinjava.com/resteasy/jax-rs-resteasy-file-upload-html-form-example/, Accessed by 2020-09-29, Last Modified 2013.

   = RESTEasy 2.3 기반으로 작성된 것이라서 다소 일부분만 참고하였다. 동작이 안 되는 코드들도 많다.


7. RESTEasy JAX-RS 4.5.8.Final API, https://docs.jboss.org/resteasy/docs/4.5.8.Final/javadocs/, Accessed by 2020-09-29, Last Modified 2020-09.

   = JAVA API 메뉴얼처럼 RestEasy도 API 메뉴얼이 있다. 변화가 다소 있었다. 2.3버전의 메뉴얼과 현재 버전의 기능 변화가 많이 있었다.

반응형
728x90
300x250

[Spring-Framework] 7. Maven, Hibernate 5.4, Servlet, MySQL 8 연동(CRUD) - (2)


2부 글을 이어서 작성하고자 한다.


[1부] [Spring-Framework] 6. Maven, Hibernate 5.4, Servlet, MySQL 8 연동(CRUD) - (1) , 2020-09-21 14:36
https://yyman.tistory.com/1404



7. 서블렛 만들기


패키지: com.hibernateMaven.web.controller

서블릿명(클래스명):

1. SampleServlet

2. StudentServlet


두 개를 만들어준다.


세부적인 내용은 지금하진 않는다.



8. Model 정의(Entity)


OR-M(Object Relational-Mapping)의 특징을 가지는 Hibernate에서 사용할 수 있도록 DTO 또는 VO(Value Object)를 정의해줘야 한다.


패키지: com.hibernateMaven.web.model

클래스명: 

1. Emptable

2. Student


클래스에 Persistence를 잘 정의해줘야 한다.

@Entity, @Table 등에 대한 Mapping을 클래스에서도 할 수 있다.


package com.hibernateMaven.web.model;


import java.sql.Date;


import javax.persistence.*;


@Entity

@Table(name = "emptable")

public class Emptable

{


@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private int empno;


@Column(name="name")

private String name;


@Column(name="address")

private String address;


@Column(name="createdate")

private Date createdate;

public int getEmpno() {

return empno;

}

public void setEmpno(int empno) {

this.empno = empno;

}

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 Date getCreatedate() {

return createdate;

}

public void setCreatedate(Date createdate) {

this.createdate = createdate;

}

}


코드 1. Emptable.java


package com.hibernateMaven.web.model;


import java.sql.Date;


import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;


@Entity

@Table(name = "student")

public class Student {


@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private int studentno;


@Column(name="name")

private String name;


@Column(name="address")

private String address;


@Column(name="createdate")

private Date createdate;

public int getStudentno() {

return studentno;

}

public void setStudentno(int studentno) {

this.studentno = studentno;

}

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 Date getCreatedate() {

return createdate;

}

public void setCreatedate(Date createdate) {

this.createdate = createdate;

}

}


코드 2. Student.java


이전의 Hibernate 개발을 보면, xml으로 hibernate.cfg.xml에 resource-mapping을 시켜주었다.

물론 현재 XML-Mapping 방법을 사용해도 무방하나, 굳이 번거롭게 2개 이상 수정 작업을 만들어서 일을 크게 만들 필요는 없다고 본다.


<?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name = "com.hibernateMaven2.web.model.Emptable" table = "emptable"> <meta attribute = "class-description"> This class contains the employee detail. </meta> <id name = "empno" type = "int" column = "empno"> <generator class="native"/> </id> <property name = "name" column = "name" type = "string"/> <property name = "address" column = "address" type = "string"/> <property name = "createdate" column = "createdate" type = "date"/> </class>  </hibernate-mapping>

예1) Emptable.hbm.xml


[첨부(Attachments)]

Emptable.hbm-xml.zip


Xml-Mapping 관련 파일이 필요한 이유는 JBoss-Hibernate에서 현재 생성이 되지 않고 있다.
(JBoss의 업데이트 등의 문제) - [2020-09-21 기준]


충분히 태스트를 해보았다. JBoss 기능에도 클래스로 맵핑하는 기능이 있다.



그림 14. Mapping 추가 기능 - STS 4의 JBoss(Hibernate 기능)





9. Hibernate.cfg.xml 파일 수정하기


그림 14의 Add-Mapping 작업을 해줘야 한다.

1부의 그림 9에 있는 첨부 파일의 내용이다.


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

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

                                         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

 <session-factory name="">

  <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

  <property name="hibernate.connection.username">사용자계정</property>

  <property name="hibernate.connection.password">비밀번호</property>

  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/web?serverTimezone=UTC&amp;characterEncoding=utf8</property>

  <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>

  <property name="hibernate.show_sql">true</property>

  <property name="hibernate.hbm2ddl.auto">update</property>

  <property name="hibernate.default_entity_mode">pojo</property>

  <property name="hibernate.current_session_context_class">thread</property>

  

  <mapping class="com.hibernateMaven.web.model.Emptable"/>    <!-- empTable 클래스 맵핑-->

  <mapping class="com.hibernateMaven.web.model.Student"/>

 </session-factory>

</hibernate-configuration>


코드 3) 클래스 맵핑 방법


[첨부(Attachments)]

hibernate.cfg-class-mapping.zip



예1의 형태로도 맵핑을 시도해볼 수 있다.


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

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

                                         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

 <session-factory name="">

  <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

  <property name="hibernate.connection.username">사용자명</property>

  <property name="hibernate.connection.password">비밀번호</property>

  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/web?serverTimezone=UTC&amp;characterEncoding=utf8</property>

  <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>

  <property name="hibernate.show_sql">true</property>

  <property name="hibernate.hbm2ddl.auto">update</property>

  <property name="hibernate.default_entity_mode">pojo</property>

  <property name="hibernate.current_session_context_class">thread</property>

  <mapping class="com.hibernateMaven.web.model.Student"/>


  <!-- XML Resource 자원으로 맵핑 -->

  <mapping resource="com/hibernateMaven/web/model/Emptable.hbm.xml"/>

 </session-factory>

</hibernate-configuration>


코드 4) 클래스, XML 맵핑 방법


[첨부(Attachments)]

hibernate.cfg-xml-mapping.zip



코드 3과 코드 4를 언급한 것은 시중 시판되는 책이나 검색 자료 등에서 언급되고 있는 소스코드의 고정관념을 깨라는 이야기이다.

자유롭게 해도 된다.


 

 

그림 15) 코드 3방식의 클래스 맵핑으로만 구성

그림 16. 코드 4방식을 채택하였을 때의 구조
         (XML-Mapping이라고 흔히 정의함)



10. HibernateUtil.java (이해보다는 복사, 붙여넣기할 것)


HibernateUtil이라는 클래스에 정의된 원형들은 DB의 연결과 종료에 해당되는 부분들이다.

연결 한번 하려고 이걸 다 외우고 작성할 수 없으니 Copy해서 사용하는 걸 추천한다.


package com.hibernateMaven.web.factory;


import org.hibernate.SessionFactory;

import org.hibernate.boot.Metadata;

import org.hibernate.boot.MetadataSources;

import org.hibernate.boot.registry.StandardServiceRegistry;

import org.hibernate.boot.registry.StandardServiceRegistryBuilder;



public class HibernateUtil

{


    private static StandardServiceRegistry registry;

    private static SessionFactory sessionFactory;


    public static SessionFactory getSessionFactory() {

        if (sessionFactory == null) {

            try {

                // Create registry

                registry = new StandardServiceRegistryBuilder().configure().build();


                // Create MetadataSources

                MetadataSources sources = new MetadataSources(registry);


                // Create Metadata

                Metadata metadata = sources.getMetadataBuilder().build();


                // Create SessionFactory

                sessionFactory = metadata.getSessionFactoryBuilder().build();

                

            } catch (Exception e) {

                e.printStackTrace();

                if (registry != null) {

                    StandardServiceRegistryBuilder.destroy(registry);

                }

            }

        }

        return sessionFactory;

    }


    public static void shutdown() {

        if (registry != null) {

            StandardServiceRegistryBuilder.destroy(registry);

        }

    }


}


코드 5) HibernateUtil.java 코드


[첨부(Attachments)]

HibernateUtil.zip



11. Interface 설계


이 글에서는 select, select where cause, insert, update, delete를 위주의 기능을 확인할 수 있도록 작성되었다.


package com.hibernateMaven.web.service;


import java.util.List;


import com.hibernateMaven.web.model.Emptable;


public interface IEmpTable {


public List<Emptable> allList(); // Select * FROM empTable

public Emptable getList(Integer num); // Select * from emptable where empno = ?

public void save(Emptable emptable); // insert into emptable

public int update(Emptable emptable); // update emptable set cause where emp = ? 

public int delete(Integer num); // delete from emptable where empno = ?

public Emptable searchName(Integer num, String name); // 두 가지 조건 동시 만족 조회

}



코드 6) IEmpTable.java (인터페이스 파일)


[첨부(Attachments)]

IEmpTable.zip



package com.hibernateMaven.web.service;


import java.util.List;


import com.hibernateMaven.web.model.Student;


public interface IStudent {


public List<Student> allList(); // Select * FROM student

public Student getList(Integer num); // Select * from student where studentno = ?

}



코드 7) IStudent.java (인터페이스 파일)


[첨부(Attachments)]

IStudent.zip




12. Class 구현


IEmpTable을 바탕으로 EmpTableService.java, StudentService.java 파일을 작성해보았다.


package com.hibernateMaven.web.service;


import java.util.List;


import org.hibernate.query.*;

import org.hibernate.Session;

import org.hibernate.Transaction;


import com.hibernateMaven.web.factory.HibernateUtil;

import com.hibernateMaven.web.model.Emptable;


public class EmpTableService implements IEmpTable {


@Override

public List<Emptable> allList() {


Transaction transaction = null;

List<Emptable> list = null;

try (Session session = HibernateUtil.getSessionFactory().openSession()) {

// start a transaction

transaction = session.beginTransaction();

// get an user object

list = session.createQuery("from Emptable").getResultList();

System.out.println("연습:" + list.get(0).getName());

// commit transaction

transaction.commit();

} catch (Exception e) {

if (transaction != null) {

transaction.rollback();

}

e.printStackTrace();

}

        return list;

}


@Override

public Emptable getList(Integer num) {

Transaction transaction = null;

Emptable emptable = null;

try (Session session = HibernateUtil.getSessionFactory().openSession()) {

transaction = session.beginTransaction();

emptable = session.get(Emptable.class, num);

            

System.out.println("특정 조회:" + emptable.getName());

transaction.commit();


return emptable;

        } catch (Exception e) {

            if (transaction != null) {

                transaction.rollback();

            }

            e.printStackTrace();

            

            return null;

        }

}



@Override

public void save(Emptable emptable) {

Transaction transaction = null;

try (Session session = HibernateUtil.getSessionFactory().openSession()) {

// start a transaction

transaction = session.beginTransaction();

// save the student object

session.save(emptable);

// commit transaction

transaction.commit();

} catch (Exception e) {

if (transaction != null) {

transaction.rollback();

}

e.printStackTrace();

}

}


@Override

public int update(Emptable emptable) {


Transaction transaction = null;

String hql = null;

int result = -1;

try (Session session = HibernateUtil.getSessionFactory().openSession()) {

// start a transaction

transaction = session.beginTransaction();

// save the student object

hql = "UPDATE Emptable set name = :name, "  +

"address = :address, createdate = :createdate " +

             "WHERE empno = :empno";

Query query = session.createQuery(hql);

query.setParameter("name", emptable.getName());

query.setParameter("address", emptable.getAddress());

query.setParameter("createdate", emptable.getCreatedate());

query.setParameter("empno", emptable.getEmpno());

result = query.executeUpdate();


System.out.println("수정결과:" + result);

// commit transaction

transaction.commit();

} catch (Exception e) {

if (transaction != null) {

transaction.rollback();

}

e.printStackTrace();

}

return result;

}


@Override

public int delete(Integer num) {

Transaction transaction = null;

String hql = null;

int result = -1;

try (Session session = HibernateUtil.getSessionFactory().openSession()) {

// start a transaction

transaction = session.beginTransaction();

// save the student object

hql = "Delete from Emptable " +

             "WHERE empno = :empno";

Query query = session.createQuery(hql);

query.setParameter("empno",  num);

result = query.executeUpdate();


System.out.println("삭제결과:" + result);

// commit transaction

transaction.commit();

} catch (Exception e) {

if (transaction != null) {

transaction.rollback();

}

e.printStackTrace();

}

return result;

}


@Override

public Emptable searchName(Integer num, String name) {


Transaction transaction = null;

String hql = null;

Emptable emp = null;

try (Session session = HibernateUtil.getSessionFactory().openSession()) {

// start a transaction

transaction = session.beginTransaction();

// save the student object

hql = "from Emptable " +

             "WHERE empno = :empno and name = :name";

Query query = session.createQuery(hql);

query.setParameter("empno", num);

query.setParameter("name",  name);

emp = (Emptable) query.list().get(0);


System.out.println("번호, 이름 검색");

// commit transaction

transaction.commit();

return emp;

} catch (Exception e) {

if (transaction != null) {

transaction.rollback();

}

e.printStackTrace();

return null;

}

}


}



코드 8) EmpTableService.java


[첨부(Attachments)]

EmpTableService.zip


package com.hibernateMaven.web.service;


import java.util.List;


import org.hibernate.query.*;

import org.hibernate.Session;

import org.hibernate.Transaction;


import com.hibernateMaven.web.factory.HibernateUtil;

import com.hibernateMaven.web.model.Student;


public class StudentService implements IStudent {


@Override

public List<Student> allList() {

return null;

}


@Override

public Student getList(Integer num) {

Student student;

Transaction transaction = null;

        Session session= HibernateUtil.getSessionFactory().openSession();

         try

         {

  transaction = session.beginTransaction();

             student=(Student)session.get(Student.class,num); 

 

             System.out.println("특정 조회:" + student.getName());

             transaction.commit();

             return student;

         }

         catch (Exception e) 

         {

        e.printStackTrace();

            return null;

         }

         finally 

         {

             session.close(); 

         }

         

         /*

Student student = null;

try (Session session = HibernateUtil.getSessionFactory().openSession()) {

transaction = session.beginTransaction();

student = session.get(Student.class, num);

            

System.out.println("특정 조회:" + student.getName());

        } catch (Exception e) {

            if (transaction != null) {

                transaction.rollback();

            }

            e.printStackTrace();

        }

*/

}


}



코드 9) StudentService.java


[첨부(Attachments)]

StudentService.zip




13. Servlet - 완성하기


1부에서 생성한 서블렛의 내용을 구현하였다.


package com.hibernateMaven.web.controller;


import java.io.IOException;

import java.io.PrintWriter;

import java.sql.Date;

import java.util.List;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.hibernateMaven.web.model.Emptable;

import com.hibernateMaven.web.service.EmpTableService;

import com.hibernateMaven.web.service.StudentService;


public class SampleServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

       

    public SampleServlet() {

        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();

// HTML 스타일 정의

out.println("<html><head><title>Hibernate Maven - MySQL 8 실험</title></head><body>");

EmpTableService service = new EmpTableService();


// 1. 전체 조회

List<Emptable> emp1 = service.allList();


// 2. 특정 ID 조회

Emptable emp2 = service.getList(1);

// 3. 삽입 구현

Emptable createEmp = new Emptable();

createEmp.setName("홍길동");

createEmp.setAddress("행복구 행복시");

java.sql.Date sqlDate = java.sql.Date.valueOf("2020-05-20");

createEmp.setCreatedate(sqlDate);

service.save(createEmp);

// 4. 수정

Emptable updateEmp = new Emptable();

updateEmp.setName("동길홍");

updateEmp.setAddress("시복행 구복행");

sqlDate = java.sql.Date.valueOf("1990-09-01");

updateEmp.setCreatedate(sqlDate);

updateEmp.setEmpno(3);

service.update(updateEmp);

// 5. 삭제

service.delete(4);

// 6. 특정 이름, 번호 조회

Emptable query1 = service.searchName(18, "홍길동");

out.println("주소:" + query1.getAddress() + "<br/>" );

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

out.close();

}


/**

* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)

*/

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

}


}



코드 10) SampleServlet.java


[첨부(Attachments)]

SampleServlet.zip



package com.hibernateMaven.web.controller;


import java.io.IOException;

import java.io.PrintWriter;

import java.util.List;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.hibernateMaven.web.model.Student;

import com.hibernateMaven.web.service.StudentService;



public class StudentServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

       

    public StudentServlet() {

        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();

// HTML 스타일 정의

out.println("<html><head><title>Hibernate Maven - MySQL 8 실험(Table:Student)</title></head><body>");

StudentService service2 = new StudentService();


// 1. 전체 조회

//List<Student> student1 = service.allList();

service2.getList(1);

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

}


}



코드 11) StudentServlet.java


[첨부(Attachments)]

StudentServlet.zip



15. 맺음글(Conclusion)


OR-M 프레임워크 중 하나인 Hibernate 5.4 Final 버전을 사용하는 방법에 대해서 소개하였다.


추가적으로 알아보면 도움되는 것: Hibernate HQL
-> SQL언어가 사라진 것이 아니라, 또 Hibernate가 제공하는 HQL이 탄생하게 되었다.
ORM을 맹신하면 안 되는 이유가 있는 것이다.

* Link1: https://howtodoinjava.com/hibernate/complete-hibernate-query-language-hql-tutorial/ (영어), 2014-10-30

  Link2: https://www.tutorialspoint.com/hibernate/hibernate_query_language.htm, (영어)


* 공식 사이트: https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#hql, Hibernate 5.4 Final 메뉴얼

  (조금 공부할 양이 많다.) - 2020-08-27 10:35:21


제대로 사용하기 위해서는 이 밖에도 Hibernate 프레임워크 하나에만 많은 공부가 필요한 것 같다.

물론 전부 학습 할 수는 없다.



* 참고자료(References)


[Hibernate - Example Project]


5. GitHub - RameshMF/Hibernate-ORM-Tutorials: 40+ source code Examples/Tutorials/Guides of Hibernate ORM Framework, https://github.com/RameshMF/Hibernate-ORM-Tutorials, Accessed by 2020-09-21, Last Modified .


-> 추천(43점): 구현하는 예제가 다양하게 이클립스 버전으로 작성되어 있다. 물론 100% 돌아가는 건 아니다. 구현할 때 많은 참고가 된다.


6. Hibernate 5 XML Configuration Example - DZone Java, https://dzone.com/articles/hibernate-5-xml-configuration-example, Accessed by 2020-09-21, Last Modified 2018-11-29.


-> 추천(55점): Web 프로젝트는 아니었지만, 구현에 있어서 큰 도움을 주었다.


[Hibernate HQL]


7. Hibernate HQL - Hibernate Query Language Examples - - HowToDoInJava, https://howtodoinjava.com/hibernate/complete-hibernate-query-language-hql-tutorial/, Accessed by 2020-09-21, Last Modified 2014-10-30.


-> 추천(40점): 기본적인 부분에 대해서 잘 작성되었다.


8. Hibernate ORM 5.4.21.Final User Guide, https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html, Accessed by 2020-09-21, Last Modified 2020-08-27.


-> 추천(40점): 조금 어렵긴 해도 알면 도움이 될 거 같다. 다 활용하진 못할 거 같다는 생각도 든다.


9. Hibernate - Query Language - Tutorialspoint, https://www.tutorialspoint.com/hibernate/hibernate_query_language.htm, Accessed by 2020-09-21, Last Modified .


-> 추천(40점): 기본적인 부분에 대해서 잘 작성되었다.


[Hibernate - XML]


10. java - [Hibernate]Error: entity class not found: - Stack Overflow, https://stackoverflow.com/questions/6692882/hibernateerror-entity-class-not-found/38801518, Accessed by 2020-09-21, Last Modified 2016.


-> XML-Mapping 시연할 때, "[Hibernate]Error: entity class not found:"를 해결하기 위해서 찾아본 것이다.


11. Brain to Blog :: 하이버네이트(Hibernate) 사용하기, https://antop.tistory.com/entry/%ED%95%98%EC%9D%B4%EB%B2%84%EB%84%A4%EC%9D%B4%ED%8A%B8Hibernate-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0, Accessed by 2020-09-21, Last Modified 2009-08-24.

반응형
728x90
300x250

[JSP] 10. JSP 폴더 구성에 대한 것


이전 게시글을 따라 수행하면, 허점이 하나 있다는 것을 알 수 있다.

뷰 파일로 만든 .jsp파일을 직접 주소만 알게 되면, 접근할 수도 있다는 취약점이 있다.


1. [JSP] 9. MVC 디자인 패턴 - 초간단 이해, FrontController 패턴(1), 2020. 9. 20. 17:24

   https://yyman.tistory.com/1401


이러한 점을 설명하면서 알아두면 좋은 폴더의 구성에 대해서 소개하려고 한다.



[JSP 폴더에 대한 설명]


1) 프로젝트명/java resources/src/

   servlet, Class, Interface 등 예를 들면 java파일을 담는 곳

    - src 밑에 폴더 만들어서 작성  

      예) someFolder, SomeClass.java 식으로 사용


프로젝트를 개설해보면, 일부 살짝 차이가 있을 수 있겠으나 통상적으로 비슷하다.


2) 프로젝트명 "webContent"  

   - jsp 문서를 작성하면 된다.


3) 프로젝트명/webContent/WEB-INF/ 

   - 아래는 접근이 안됨, 보안 영역임.

    - 프로젝트명/webContent/WEB-INF/lib/  폴더에 각종

      jar 파일, ojdbc6 등을 붙여 넣어야 실행이 가능함.


※ jsp는 주소가 노출되어 있어서 공격을 받을 수 있다

    그래서, 

    @webServlet("*.do")와  같은 URL Mapping 어노테이션을 사용하여 URL 숨김 효과를 본다.

    또는 web.xml 에 정의하여 사용.





2. 9번 글 - 프로젝트에 적용해보기


WebContest에 있는 addressInsert.jsp와 addressList.jsp를 WEB-INF안에 view 폴더를 만들어서 이동시킨다.



그림 1) WEB-INF\view 폴더에 있는 jsp파일 실행시키기


jsp파일 경로를 입력하였으나 동작되지 않는 것을 확인할 수 있다.



2-1. 소스코드 변경하기


서블릿으로 WEB-INF\View에 있는 jsp파일을 사용하려면, 

AddressInsertController.java와 AddressListController.java의 파일 내용을 수정한다.



그림 2) 수정된 AddressInsert.java 파일



그림 3) 수정된 AddressList.java 파일


package com.eduJsp.controller;


import java.io.IOException;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class AddressInsertController implements Controller {


@Override

public void execute(HttpServletRequest req, HttpServletResponse res) throws

ServletException, IOException{


HttpUtil.forward(req, res, "/WEB-INF/view/addressInsert.jsp");

}


}




package com.eduJsp.controller;


import java.io.IOException;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class AddressListController implements Controller {


@Override

public void execute(HttpServletRequest req, HttpServletResponse res) throws

ServletException, IOException {

HttpUtil.forward(req, res, "/WEB-INF/view/addressList.jsp");

}


}




3. 결과


서블릿을 통해서 결과를 확인해보면, 이해할 수 있을 것으로 보인다.



그림 4) Servlet 파일(*.do) - 호출하기



4. 작업내용 정리해보기


변경작업을 수행한 이력을 체크해본 것이다. 조금 알기 쉽게 표기해보았으니 참고하여 정리해보면 좋을 듯 하다.



그림 5) 프로젝트 구조 - 변경 사항


반응형
728x90
300x250

[Spring-Framework] 6. Maven, Hibernate 5.4, Servlet, MySQL 8 연동(CRUD) - (1)


Hibernate 5.4 이상에서 ORM기반의 데이터베이스를 사용하는 방법에 대해서 소개하겠다.

글을 작성하게 된 계기는 인터넷을 검색해보니깐, 워낙 오래된 Hibernate 버전을 기준으로 현실성이 없는 복잡한 구현의 글이 많아서 쉽고 간단하게 작성할 수 없겠느냐는 생각을 갖고 좀 더 쉽고 적응하기 쉽도록 만들어보고자 작성하게 되었다.


글을 2부로 구성하였다.


조금 태스트를 하면서 느낀 소감은 iBatis나 SQL이 훨씬 사용하기에는 편리하다.

절차지향적인 언어인 SQL 사용하는 게 나쁜 건만 아니라고 본다.


조금 양이 많을 수 밖에 없어서 불가피하게 두 개의 글로 나누었으니 참고하길 바란다.


Hibernate(하이버네이트)란?

하이버네이트 ORM은 자바 언어를 위한 객체 관계 매핑 프레임워크이다.
객체 지향 도메인 모델을 관계형 데이터베이스로 매핑하기 위한 프레임워크를 제공한다.
하이버네이트는 GNU LGPL 2.1로 배포되는 자유 소프트웨어이다.

https://hibernate.org/



ORM(Object-relational mapping)이란?

ORM(Object-relational mapping)을 단순하게 표현하면 객체와 관계와의 설정이라 할 수 있다.
ORM에서 말하는 객체(Object)의 의미는 우리가 흔히 알고 있는 OOP(Object_Oriented Programming)의 그 객체를 의미한다는 것을 쉽게 유추할 수 있을 것이다. 그렇다면 과연 관계라는 것이 의미하는 것은 무엇일까?
지극히 기초적인 이야기지만 개발자가 흔히 사용하고 있는 관계형 데이터베이스를 의미한다.



[환경]

- 운영체제: Microsoft Windows 10


- 웹서버: Apache-tomcat-9.0.37                (http://tomcat.apache.org/)


- IDE: Spring Tool-Suite 4-4.7.2 Releases      (https://spring.io/tools)

  * JBoss -> Hibernate만 설치할 것(필수) - Help->Eclipse Marketplace


- 데이터베이스: MySQL 8.0.21 Windows 64bit  (https://dev.mysql.com/downloads/mysql/)

  * Library: Connector/J 8.0.21


- 개발 라이브러리:

  * Maven

    - https://maven.apache.org/

  * hibernate-entitymanager (5.4.21 Final)

    - https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager

    - https://hibernate.org/

  * javax.inject (1)
  * javax.servlet-api (4.0.1)

    - https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api

  * mysql-connector-java (8.0.21)

    - https://mvnrepository.com/artifact/mysql/mysql-connector-java




1. MySQL Server - 설치하기


아래의 사이트에 접속한다.

https://dev.mysql.com/downloads/mysql/


설치 방법은 워낙 간단하고, 잡음이 적은 프로그램이므로 짧게 정리하였다.




그림 1) MySQL Server 8.0.21 - 설치하기





그림 2) MySQL Server 8.0.21 - 설치하기



2. 테이블 설계 (emptable, student)


dto 또는 model 영역 중 하나의 작업으로 두 개의 테이블을 설계하였다.


"emptable", "student"




그림 3) 데이터베이스 테이블 생성 - emptable






그림 4) 데이터베이스 테이블 생성 - student



CREATE TABLE `emptable` (

  `empno` INT NOT NULL AUTO_INCREMENT,

  `name` VARCHAR(20) NULL,

  `address` VARCHAR(100) NULL,

  `createdate` DATE NULL,

  PRIMARY KEY (`empno`));


INSERT INTO `emptable` (`name`, `address`, `createdate`) VALUES ('하하', '안녕', '20-09-1');



CREATE TABLE `student` (

  `studentno` INT NOT NULL AUTO_INCREMENT,

  `name` VARCHAR(45) NULL,

  `address` VARCHAR(100) NULL,

  `createdate` DATE NULL,

  PRIMARY KEY (`studentno`))

ENGINE = InnoDB

DEFAULT CHARACTER SET = utf8

COLLATE = utf8_unicode_ci;


INSERT INTO `student` (`name`, `address`, `createdate`) VALUES ('홍길동', '연습', '21-3-4');


[첨부(Attachments)]

emptable.zip

student.zip




3. 프로젝트 구성


미리 살펴보는 hibernateMaven2 프로젝트의 구성이다.



그림 5) 프로젝트 구성도 - hibernateMaven2


* Servlet 구성

- /SampleServlet

- /StudentServlet



4. POM.xml 수정하기(Maven 적용된 프로젝트)


pom.xml이 왜 없냐고 생각하는 경우가 있을 수 있다.

알기 쉽게 소개하면, maven이 적용되어있는 프로젝트에서 존재하는 기능이라고 보면 된다.


http://mvnrepository.com에 접속해서 몇 가지 구성을 찾아서 입력해줘야 한다.


(중략)

      <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->

<dependency>

    <groupId>org.hibernate</groupId>

    <artifactId>hibernate-entitymanager</artifactId>

    <version>5.4.21.Final</version>

</dependency>

    <!-- @Inject -->

    <dependency>

        <groupId>javax.inject</groupId>

        <artifactId>javax.inject</artifactId>

        <version>1</version>

    </dependency>

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

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->

<dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <version>8.0.21</version>

</dependency>


(중략)




그림 6) pom.xml 수정하기







5. hibernate 환경설정 - 생성과 수정


이 작업은 "JBoss -> hibernate" 라이브러리를 설치하지 않으면, 의미가 없다고 보면 된다.

수동으로 물론 셋팅할 수는 있으나 권장하진 않는다. (시도해봐도 무방, 처음에 찾는데 시간이 오래 걸린다. 이런 문제)




그림 7) 프로젝트 항목 -> 오른쪽 버튼 메뉴 모습





그림 8) Hibernate Configuration File 선택하기


- Hibernate XML Mapping file 기능은 생성이 되지 않는다.

  (꼭 반드시 XML Mapping으로 hibernate resources를 잡을 필요는 없으며, Class Mapping도 사용된다.)


셋팅에서 필요한 부분들을 정리해보았다.


* hibernate.connection.driver_class = com.mysql.jdbc.Driver

* hibernate.connection.url = jdbc:mysql://localhost:3306/web?serverTimezone=UTC&characterEncoding=utf8

* hibernate.dialect = org.hibernate.dialect.MySQL8Dialect

* hibernate.show_sql = true

* hibernate.hbm2ddl.auto = update

* hibernate.default_entity_mode = pojo

* hibernate.current_session_context_class = thread



문제1. [MySQL 초기 설치 후 작업했을 때, 타임존 문제]


타임존 미설정시

* ERROR: The server time zone value


해결 방법1: serverTime=UTC를 입력해준다.

해결 방법2: 서버 my.cnf 파일에서 timezone을 지정해준다.


* my.cnf 파일 내에 환경 설정을 변경해주는 방법이 있다.
[mysqld]

default-time-zone='+9:00'



문제2. [UTF-8 환경설정 문제]


해결 방법1: characterEncoding=utf8을 입력해준다.

해결 방법2: 서버 my.cnf 파일에서 timezone을 지정해준다.


* my.cnf 파일 내에 환경 설정을 변경해주는 방법이 있다.

[mysqld]

init_connect = SET collation_connection = utf8_general_ci

init_connect = SET NAMES utf8

character-set-server = utf8

collation-server = utf8_general_ci




그림 9) hibernate.cfg.xml


[첨부(Attachments)]

hibernate.cfg.zip


* 경로는 다음과 같다. 참고로 초기에 폴더가 생성되어 있는 것이 아니라서, 수동으로 폴더를 만들어줘야 한다.


폴더: src/main/resources




그림 10) hibernate 모습



물론 공식 메뉴얼만 가지고 이해가 되지 않으면 추가적인 검색을 시도해봐도 된다.





5. 결과 - 미리 살펴보는 결과


완성된 작품은 이러한 모습을 가지고 있다.

무슨 작품을 만들지 생각해보기 위함이다.


그림 11) 출력 결과 - 웹 브라우저




그림 12) 출력 결과 - 웹 브라우저(2)




그림 13) 출력 결과 - 웹 브라우저(3)




6. 2부에서 만나요 


게시글 2부에서 연속 글이 연재된다.


[Spring-Framework] 7. Maven, Hibernate 5.4, Servlet, MySQL 8 연동(CRUD) - (2)

https://yyman.tistory.com/1405




* 참고 자료(References)


1. Hibernate Getting Started Guide, https://docs.jboss.org/hibernate/orm/5.4/quickstart/html_single/, Accessed by 2020-09-21, Last Modified 2020-08-27 10:35.

- 공식적인 Hibernate 메뉴얼이니 이해가 안 되면 읽어보길 바란다.


2. Hibernate 5 Java Configuration Example - DZone Java, https://dzone.com/articles/hibernate-5-java-configuration-example, Accessed by 2020-09-21, Last Modified 2018-12-03

- 추천(70점): 가장 실질적으로 많은 도움을 받았던 글이다. (영어 글)


3. MySQL(MariaDB) 서버 타임존 설정하기, https://offbyone.tistory.com/318, Accessed by 2020-09-21, Last Modified 2018-07-17 23:38.

4. java.sql.SQLException: The server time zone value ‘xx time’ is unrecognized, https://mkyong.com/jdbc/java-sql-sqlexception-the-server-time-zone-value-xx-time-is-unrecognized/, Accessed by 2020-09-21, Last Modified 2019-07-05.

- 비고: (영어 글)이다.

반응형
728x90
300x250

[Spring-Framework] 5. 순정 Maven MVC 웹 프로젝트 - 서블릿, Oracle DB


이번에 소개할 프로젝트는 Maven을 활용하여 Oracle 연동에 대해서 소개하려고 한다.


* 미리 준비해야 할 것: Oracle Database 설치되어 있어야 함.

-> 오라클의 경우에는 오라클 데이터베이스가 설치되어야만, pom.xml에서 <dependency>로 불러올 수가 있음.



[글의 주제]

1. 흥미로운 실험 - Spring Framework가 없는 Maven MVC 웹 프로젝트로 Servlet(서블릿) 구성해보기

2. Oracle Database 연결해보기


글의 주제를 2가지로 설정한 이유는 Spring Framework와 Maven을 동일시하는 경우가 있어서 차이를 알아보기 위해서 작성하게 되었다.


[사용 환경]

1. Oracle Databases 19g (2020-09월 기준: 최신버전)

2. OpenJDK (2020-09월 기준: 최신버전)

3. Apache Tomcat 9

4. SpringToolSuite4 (2020-09월 기준: 최신버전)

5. MS Windows 10



1. MVNRepository가 만능인가?


몇 가지 미지원하는 제품도 존재할 수 있다. 참고하면 도움이 될 것이다.



그림 1) MVNRepository 검색하기


https://mvnrepository.com/


접속하여 "Oracle"이라고 검색한다.

Oracle JDBC 를 클릭한다.

최신버전을 선택해본다.



그림 2) MVNRepository - Oracle JDBC 12.1.0.2


Maven 생성 코드가 나왔다.

해당 코드를 복사, 붙여넣기를 pom.xml에 시도 해본다.



그림 3) pom.xml에 적용했을 때 오류


Multiple problems have occur......

Error reading file - oracle-jdbc-12.1.0.2.jar 파일을 읽어올 수 없다고 에러가 발생한다.


이렇게 에러가 출력되었다면, 정상적으로 코드를 입력한 것이다.

오류가 발생하는 원인으로는 오라클 데이터베이스는 상용 소프트웨어이기 때문이다.



2. 프로젝트에서 Maven -> Add Dependency 기능 활용하기


Maven 플러그인의 Add Dependency 기능으로 적용해보려고 한다.



그림 4) Maven의 프로젝트


작업중인 프로젝트를 클릭한다.

오른쪽 버튼을 누른다.

"Maven"-> "Add Dependency"를 클릭한다.



그림 5) Maven의 프로젝트


oracle을 검색한다.

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



그림 6) Maven의 프로젝트


자동으로 oracle jar파일이 생성되는 것을 확인할 수 있다.

버전을 자세히 보면, 19.3.0.0이라고 적혀져 있다.

오라클 최신 버전이 컴퓨터 내에 설치되어 있어서, 해당 버전을 인식하여 가져온 것으로 보인다.




3. Maven에서의 Java 코드 생성하기


이전의 프로젝트에 비해서 복잡하게 느껴질 수도 있지만, 큰 차이점은 없다고 보면 되겠다.

먼저 AddressDto라는 클래스를 생성해보려고 한다.



그림 7) Class 생성하기


Java Resources에서 오른쪽 버튼을 누른다.

New 항목에서 Class를 클릭한다.



그림 8) AddressDto.java 파일 만들기


Package명을 간단하게 "mavenWeb.db"로 입력하였다.

Name명은 "AddressDto"라고 입력하였다.

다 입력하였으면, "Finish"를 누른다.



그림 9) 코드를 입력한 모습 - AddressDto.java


크게 어렵지 않게 Jsp 프로그래밍에서의 Java 파일 생성한 방법처럼, 동일한 형태로 사용할 수 있다는 것을 알 수 있다.





4. Maven에서의 Servlet 코드 생성하기


이전의 서블릿 작업은 web.xml에서 수정작업을 추가적으로 해줘야만 했었다.

Maven에서 서블릿(Servlet)을 생성하면, 자동으로 web.xml에 입력된다.



그림 10) Java Resources의 오른쪽 버튼 메뉴 모습


Java Resources를 선택한 후 오른쪽 버튼 클릭하여 New->Servlet을 클릭한다.



그림 11) Create Servlet


Java Package명은 "mavenWeb.view"으로 지정하였다.

Class name명은 "BoardListServlet"으로 지정하였다.

완료되었다면, Finish를 누른다.



그림 12) web.xml 파일


파일경로: src/main/webapp/WEB-INF/web.xml


자동으로 <Servlet>과 <Servlet-Mapping>이 등록된 것을 볼 수 있다.



그림 13) BoardListServlet.java 파일


doGet함수와 doPost 등이 자동 생성된 프로그램을 볼 수 있다.

Run을 하여 "아파치 톰캣 서버"를 동작시킨 후 아래처럼 태스트를 해볼 수 있다.



그림 14) Open Browser에서의 서블릿 동작 확인하기


매우 친숙한 화면에서 동작되는 모습을 확인할 수 있다.




5. Oracle DB - 간단하게 연동시키기(프레임워크 X - 순정 JDBC) [소스코드]


JDBC 기반으로 Maven Servlet 프로젝트 작업을 구현하겠다.



그림 15) 프로젝트 구성하기의 예


작업해줄 영역은 크게 mavenWeb.db, mavenWeb.view, WEB-INF내의 web.xml 파일이 되겠다.


* 이전 게시글(동일하거나 참고하면 되는 게시글):

1. [JSP] 영속프레임워크 MyBatis를 활용한 CRUD 구현 - JSP와 Oracle, https://yyman.tistory.com/1390?category=810693, 2020-09-19 01:31

-> 비교해서 읽어 보기: 현재 게시글에서는 프레임워크 없이 JDBC 처리에 대해서 소개하고 있음.




package mavenWeb.db;


import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;


public class SqlMapSessionFactory {


private static SqlMapSessionFactory factory = new SqlMapSessionFactory();

private SqlMapSessionFactory() {}

public static SqlMapSessionFactory getInstance() {

return factory;

}

public Connection connect() {

Connection conn = null;

try {

Class.forName("oracle.jdbc.driver.OracleDriver");

conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "사용자명", "비밀번호");

}

catch(Exception ex) {

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

}

return conn;

}

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 구조 응용(재귀 함수)

}

}

public void close(Connection conn, PreparedStatement ps) {

if (ps != null ) {

try {

ps.close();

}

catch(Exception ex) {

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

}

}

if (conn != null ) {

try {

conn.close();

}

catch(Exception ex) {

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

}

}

}

}



* 파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip


package mavenWeb.db;


import java.sql.Date;


public class AddressDto {


private int num;

private String name;

private String address;

private Date 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 Date getBirthdate() {

return birthdate;

}

public void setBirthdate(Date birthdate) {

this.birthdate = birthdate;

}


}



* 파일명: AddressDto.java


비고: 이전 프로젝트와 동일함. (MyBatis 게시글과 흡사함)

java.sql.Timestamp에서 java.sql.Date로 변경함.


[첨부(Attachments)]

AddressDto.zip


package mavenWeb.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 (인터페이스)


비고: 이전 프로젝트와 동일함. (MyBatis 게시글과 동일함)


[첨부(Attachments)]

Address.zip


package mavenWeb.db;


public class AddressImpl implements Address {


@Override

public AddressDto getAddress(Integer num) {

AddressDao dao = AddressDao.getInstance();

return dao.selectAddress(num);

}


@Override

public int updateAddress(AddressDto addressDTO) {

AddressDao dao = AddressDao.getInstance();

return dao.updateAddress(addressDTO);

}


@Override

public int insertAddress(AddressDto addressDTO) {

AddressDao dao = AddressDao.getInstance();

return dao.insertAddress(addressDTO);

}


@Override

public int deleteAddress(Integer num) {

AddressDao dao = AddressDao.getInstance();

return dao.deleteAddress(num);

}


}



* 파일명: AddressImpl.java


비고: 이전 프로젝트와 동일함. (MyBatis 게시글과 동일함)


[첨부(Attachments)]

AddressImpl.zip


package mavenWeb.db;


import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.text.SimpleDateFormat;

import java.util.Calendar;


public class AddressDao {

private AddressDao() {}

    private static AddressDao dao;

    private static SqlMapSessionFactory session; 


    public static AddressDao getInstance(){


        if(dao == null){

            dao = new AddressDao();

            session = SqlMapSessionFactory.getInstance();

        }


        return dao;

    }

    


    public AddressDto selectAddress(Integer num) {


    Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

   

    AddressDto node = new AddressDto();

   

    String sql = "select NUM, NAME, ADDRESS, BIRTHDATE " +

      " from addressbook" + 

      " where num=?";

    System.out.println(sql);

   

    // 달력 날짜 출력 버그 개선

   

    try {

    conn = session.connect();

    pstmt = conn.prepareStatement(sql);

    pstmt.setInt(1, num);

   

    rs = pstmt.executeQuery();

   

    if ( rs.next() ) {

    node.setNum(rs.getInt(1));

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

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

    node.setBirthdate(rs.getDate(4));

    }

   

   

    }catch(Exception ex) {

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

    }

    finally {

    session.close(conn, pstmt, rs);

    }

   

        return node;


    }

    

    public int updateAddress(AddressDto addressDTO) {


    Connection conn = null;

    PreparedStatement pstmt = null;

    int result = -1;

   

    String sql = "update addressbook set NAME = ?, ADDRESS = ?, BIRTHDATE = ? " + 

      " where num = ?";

    try {

   

    System.out.println(addressDTO.getBirthdate());

   

    conn = session.connect();

    pstmt = conn.prepareStatement(sql);

    pstmt.setString(1, addressDTO.getName());

    pstmt.setString(2, addressDTO.getAddress());

    pstmt.setDate(3, addressDTO.getBirthdate());

    pstmt.setInt(4,  addressDTO.getNum());

   

    result = pstmt.executeUpdate();

   

   

    }catch(Exception ex) {

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

    }

    finally {

    session.close(conn, pstmt);

    }

   

    return result;

   

    }


    public int insertAddress(AddressDto addressDTO) {

   

    Connection conn = null;

    PreparedStatement pstmt = null;

    int result = -1;

   

    String sql = "insert into addressbook (NAME, ADDRESS, BIRTHDATE) " + 

      " values(?,?,?)";

    try {

   

    System.out.println(addressDTO.getBirthdate());

   

    conn = session.connect();

    pstmt = conn.prepareStatement(sql);

    pstmt.setString(1, addressDTO.getName());

    pstmt.setString(2, addressDTO.getAddress());

    pstmt.setDate(3, addressDTO.getBirthdate());

   

    result = pstmt.executeUpdate();

   

   

    }catch(Exception ex) {

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

    }

    finally {

    session.close(conn, pstmt);

    }

   

    return result;

    }

    

    public int deleteAddress(Integer num) {

   

    Connection conn = null;

    PreparedStatement pstmt = null;

    int result = -1;

   

    String sql = "delete from addressbook " + 

      " where num = ?";

    try {

   

    conn = session.connect();

    pstmt = conn.prepareStatement(sql);

    pstmt.setInt(1, num);

   

    result = pstmt.executeUpdate();

   

   

    }catch(Exception ex) {

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

    }

    finally {

    session.close(conn, pstmt);

    }

   

    return result;

    }


    

}



* 파일명: AddressDao.java


비고: 


[첨부(Attachments)]

AddressDao.zip





6. 서블릿 뷰 - [소스코드]


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

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

  

  

<!-- Subject: web.xml     -->

<!-- Filename: web.xml     -->

<!-- Created Date: 2020-09-19     -->

<!-- * Description:     --> 

<!-- 1. Maven 기반의 Servlet 실험(2020-09-20) --> 

  

  <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 Servlet 자동생성됨 -->

  <servlet>

  <servlet-name>BoardListServlet</servlet-name>

  <servlet-class>mavenWeb.view.BoardListServlet</servlet-class>

  </servlet>

  <servlet>

  <servlet-name>BoardInsertServlet</servlet-name>

  <servlet-class>mavenWeb.view.BoardInsertServlet</servlet-class>

  </servlet>

  <servlet>

  <servlet-name>BoardDeleteServlet</servlet-name>

  <servlet-class>mavenWeb.view.BoardDeleteServlet</servlet-class>

  </servlet>

  <servlet>

  <servlet-name>BoardUpdateServlet</servlet-name>

  <servlet-class>mavenWeb.view.BoardUpdateServlet</servlet-class>

  </servlet>

  <servlet-mapping>

  <servlet-name>BoardListServlet</servlet-name>

  <url-pattern>/board/list.do</url-pattern>

  </servlet-mapping>

  <servlet-mapping>

  <servlet-name>BoardInsertServlet</servlet-name>

  <url-pattern>/board/insert.do</url-pattern>

  </servlet-mapping>

  <servlet-mapping>

  <servlet-name>BoardDeleteServlet</servlet-name>

  <url-pattern>/board/delete.do</url-pattern>

  </servlet-mapping>

  <servlet-mapping>

  <servlet-name>BoardUpdateServlet</servlet-name>

  <url-pattern>/board/update.do</url-pattern>

  </servlet-mapping>


</web-app>


* 파일명: web.xml


[첨부(Attachments)]

web.zip


package mavenWeb.view;


import java.io.IOException;

import java.io.PrintWriter;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import mavenWeb.db.AddressDto;

import mavenWeb.db.AddressImpl;


/**

 * Servlet implementation class BoardDeleteServlet

 */

public class BoardDeleteServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

       

    /**

     * @see HttpServlet#HttpServlet()

     */

    public BoardDeleteServlet() {

        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();

int result = address.deleteAddress(5);

AddressDto addressDto = address.getAddress(3);

out.println("<html><head><title>CRUD - Delete(Maven)</title></head>");

out.println("<body><h2>MyBatis - Delete(Maven)</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 request, HttpServletResponse response)

*/

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

doGet(req, res);

}


}



* 파일명: BoardDeleteServlet.java


[첨부(Attachments)]

BoardDeleteServlet.zip


package mavenWeb.view;


import java.io.IOException;

import java.io.PrintWriter;

import java.sql.Date;

import java.text.SimpleDateFormat;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import mavenWeb.db.AddressDto;

import mavenWeb.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 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.setName("도도" + serialVersionUID);

dbNode.setAddress("행복시 행복동");

// 버그1: new Date() 사용안됨. (2020을 3920으로 인식함.) 

// 버그2: new Timestamp() 사용안됨. (2020을 3920으로 인식함.) 

String userDate = "2020-02-01";

java.sql.Date sqlDate = java.sql.Date.valueOf(userDate);

dbNode.setBirthdate(sqlDate);

int result = address.insertAddress(dbNode);

AddressDto addressDto = address.getAddress(1);

out.println("<html><head><title>CRUD - Insert(Maven)</title></head>");

out.println("<body><h2>MyBatis - Insert</h2>");


SimpleDateFormat format1 = new SimpleDateFormat ( "yyyy-MM-dd" );

String birthdate = format1.format(addressDto.getBirthdate());

out.print("<br/>");

out.print("등록여부:" + result + "</br>");

out.print("<br/>");

out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");

out.print(addressDto.getAddress() + "/" + birthdate);

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

out.close();

}


/**

* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)

*/

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// TODO Auto-generated method stub

doGet(request, response);

}


}



* 파일명: BoardInsertServlet.java


[첨부(Attachments)]

BoardInsertServlet.zip


package mavenWeb.view;


import java.io.IOException;

import java.io.PrintWriter;

import java.text.SimpleDateFormat;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import mavenWeb.db.AddressDto;

import mavenWeb.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 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 addressDto = address.getAddress(16);

out.println("<html><head><title>CRUD - List(Maven)</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 request, HttpServletResponse response)

*/

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

doGet(req, res);

}


}



* 파일명: BoardListServlet.java


[첨부(Attachments)]

BoardListServlet.zip


package mavenWeb.view;


import java.io.IOException;

import java.io.PrintWriter;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import mavenWeb.db.AddressDto;

import mavenWeb.db.AddressImpl;


/**

 * Servlet implementation class BoardUpdateServlet

 */

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.Date sqlDate = java.sql.Date.valueOf(userDate);

dbNode.setBirthdate(sqlDate);

int result = address.updateAddress(dbNode);

AddressDto addressDto = address.getAddress(3);

out.println("<html><head><title>CRUD - Update(Maven)</title></head>");

out.println("<body><h2>MyBatis - Update(Maven)</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


[첨부(Attachments)]

BoardUpdateServlet.zip




7. 데이터베이스 설계


예제 데이터베이스를 설계하도록 하겠다. 역설계에 대해서도 생각해보면, 흥미로운 주제가 될 것으로 보인다.


tableName(테이블명): addressbook


 키

 항목명

 속성 

 PK(기본키)

num

인덱스(ID)

 

name

nvarchar

 

address

nvarchar

 

birthdate

date




그림 16) 데이터베이스 테이블 - 설계



8. 결론(Conclusion)


순정 Maven MVC의 사용방법은 JSP/Servlet하고 동일하거나 큰 차이가 없다는 점을 알 수 있었다.

Spring-Framework의 Maven을 사용할 때 기본 원리를 이해하는 데 도움될 수 있을 거 같다.


* 소스코드: 동작 태스트 완료하였음.


Maven을 사용하면, 편해지는 부분이 정말 많아진다.



* 참고자료(Reference)


1. 자바 오라클 연동 데이터 삽입,수정,조회,삭제-1, https://ngg3319.tistory.com/76, Accessed by 2020-09-20, Last Modified 2018-03-12 16:17

2. 자바 오라클 연동 데이터 삽입,수정,조회,삭제-2, https://ngg3319.tistory.com/79, Accessed by 2020-09-20, Last Modified 2018-03-13 22:02

-> 추천(40점): 의외로 쉽게 잘 작성되어 있음.

-> 참고 부분: sqlDate 에 대해서 처리하는 방법 참고함. (String 문자로 java.sql.Date.valueOf()의 아이디어를 얻었음.)


3. maven 이용 spring MVC project 생성 :: Copy Coding, https://copycoding.tistory.com/178, Accessed by 2020-09-20, Last Modified 2019-05-03 12:27

-> 추천(70점): 순수한 Maven 프로젝트에 대해서 잘 설명되어 있음.


반응형
728x90
300x250

[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");


반응형

+ Recent posts