728x90
300x250

[JSP] 19. MyBatis-3.5.5 와 Maven / Servlet 연동하기 (Oracle 19g) - Java 방식


MyBatis 관련 이전의 글을 읽어보고 실습을 해본 다음에 경험해봐도 무방할 것으로 보인다.

이번에 소개할 내용은 조금 세련된 방식으로 MyBatis를 적용하는 방법에 대해서 소개하려고 한다.


이 글을 작성하게 된 계기는 MyBatis 공식 사이트에서 제시하는 방법론에 대해서 실질적으로 어떻게 구현하는지 소개해보고 싶어서 그렇다.


이전 스타일에 익숙하다면, 새로운 스타일을 경험하시어 훨씬 생산성이 있는 방법으로 개발을 시도해보면 좋지 않겠냐는 것이다.


1. [JSP] 8. 영속프레임워크 MyBatis를 활용한 CRUD 구현 - JSP와 Oracle (XML 방식), 2020-9-19
https://yyman.tistory.com/1390 

-> XML 방식으로 구현됨.


- IDE: Spring-Tool-Suite 4-4.7.2 Releases (2020-06 최신)

- DB: Oracle Databases 19g (2020-09 최신)

- Maven 3.6.3/1.16.0.20200610-1735 (2020-09 최신)

- JAR: javax.servlet-api.4.0.1.jar (2020-09 최신)

         ojdbc8-19.7.0.0.jar (2020-09 최신)

         MyBatis 3.5.5 (2020-09 최신)



1. 결과


결과를 바탕으로 살펴보면, 이렇게 출력되면 잘 된 것이다.



그림 1. 결과 - DB 연동 모습



그림 2. 결과 - 프로젝트 구성도


작업을 할 내용이다. 매우 간결한 프로젝트 구성이다.



2. 데이터베이스 설계


Spring Security 5의 사용자 계정 테이블을 인용하여 설계하였다.

테이블의 구조는 간단한 형태이다.



그림 3. Oracle SQL Developer - 데이터베이스 설계





그림 4. Oracle SQL Developer - (데이터 내용)



그림 5. Oracle SQL Developer - COMP_USERS (Model)


CREATE TABLE comp_users (

username VARCHAR(50) NOT NULL,

password VARCHAR(300) NOT NULL,

enabled INT NOT NULL,

PRIMARY KEY (username)

);


-- 계정

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

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


파일명: comp_users.sql


[첨부(Attachments)]

comp_users.zip





3. 프로젝트 생성하기


프로젝트 생성에 대해서 소개하겠다.



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


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




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


프로젝트를 생성할 때 "org.apache.maven.archetype", "maven-archetype-webapp"을 선택한다.

Next를 클릭한다.



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


Group Id, Artifact Id를 입력해준다.

Finish를 누른다.




4. 자바 버전 - Build Path, Project Facets 설정하기


프로젝트를 선택한다. 그리고 Properties에 들어가서 설정할 것이다.



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


프로젝트를 선택한 후 마우스 오른쪽 버튼을 누른다.

Properties를 클릭한다.



그림 10. 프로젝트의 Build Path


Java Build Path를 클릭한다.

JRE System Library를 14버전으로 변경해준다.

Apply를 누른다.




그림 11. 프로젝트의 Project Factes


Project Factes를 클릭한다.

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

Apply를 누른다.



4. MyBatis - 공식 사이트 메뉴얼 읽어보기


공식 사이트에서 지원하는 방식에 대해서 간단하게 소개되어 있다.

아래의 공식 링크를 참고해서 적용할 것이다.


https://mybatis.org/mybatis-3/ko/getting-started.html



그림 12. MyBatis - 시작하기 (Official Site)





5. pom.xml - 설정하기


http://mvnrepository.com에서 Java Servlet API 4.0.1과 MyBatis를 찾아서 추가한다.

Oracle은 Oracle 공식 사이트나 또는 Oracle Databases 19g가 설치되어 있다면, 간단하게 Add Dependency를 통해서 pom.xml에 추가할 수 있다.



그림 13. Servlet API 4.0.1 - Mvnrepository






그림 14. MyBatis 3.5.5 - Mvnrepository



그림 15. Pom.xml 마우스 오른쪽 버튼 메뉴 모습


pom.xml을 마우스 오른쪽 버튼으로 클릭한다.

Maven->Add Dependency를 클릭한다.


(참고로 Oracle Databases 19g가 설치된 경우에서만 가능한 작업이다.)

(설치가 되지 않은 경우라면, Oracle 공식 사이트에서 Oracle JDBC를 내려받기 바란다.

그리고 lib 폴더에 넣어주고 프로젝트에서 셋팅해줘야 한다.)



그림 16. Add-Dependency


Oracle을 검색한다.

com.oracle.database.jdbc  "ojdbc8"을 선택한다.

OK를 누른다.



그림 17. STS 4.4 - 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.examplebatis</groupId>

  <artifactId>web</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


  <name>web Maven Webapp</name>

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

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


  <properties>

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

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

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

  </properties>


  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.11</version>

      <scope>test</scope>

    </dependency>

    <!-- 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/org.mybatis/mybatis -->

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.5.5</version>

</dependency>


<dependency>

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

<artifactId>ojdbc8</artifactId>

<version>19.7.0.0</version>

</dependency>

  </dependencies>


  <build>

    <finalName>web</finalName>

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

      <plugins>

        <plugin>

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

          <version>3.1.0</version>

        </plugin>

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

        <plugin>

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

          <version>3.0.2</version>

        </plugin>

        <plugin>

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

          <version>3.8.0</version>

        </plugin>

        <plugin>

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

          <version>2.22.1</version>

        </plugin>

        <plugin>

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

          <version>3.2.2</version>

        </plugin>

        <plugin>

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

          <version>2.5.2</version>

        </plugin>

        <plugin>

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

          <version>2.8.2</version>

        </plugin>

      </plugins>

    </pluginManagement>

  </build>

</project>



파일명: pom.xml


[첨부(Attachments)]

pom.zip




6. SqlMapSessionFactory.java - 자바 방식 연결부


자바 방식 연결부를 작성하도록 하겠다.



그림 18. Java Resources의 마우스 오른쪽 클릭 메뉴 모습


Java Resources를 마우스 오른쪽 버튼으로 클릭한다.

New->Class를 클릭한다.




그림 19. SqlMapSessionFactory.java 만들기


Package명과 Name을 입력한다. 

(예: package: com.exmple.web.db)    //    탈자(exmple로 만들었으니 알아서 참고할 것.)

(예: Name: SqlMapSessionFactory)


Finish를 누른다.



그림 20. SqlMapSessionFactory.java


코드를 수정해준다.


package com.exmple.web.db;


import java.io.IOException;

import java.io.InputStream;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;


import javax.sql.DataSource;


import org.apache.ibatis.io.Resources;

import org.apache.ibatis.mapping.Environment;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.apache.ibatis.transaction.TransactionFactory;

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


import com.exmple.web.mapper.CompUsersMapper;


import oracle.jdbc.pool.OracleDataSource;


public class SqlMapSessionFactory {


private static SqlMapSessionFactory factory = new SqlMapSessionFactory();


private SqlMapSessionFactory() {}


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

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

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

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


public static SqlMapSessionFactory getInstance() {

return factory;

}


public static SqlSessionFactory ssf;


    static{


    DataSource dataSource = getOracleDataSource();

    TransactionFactory transactionFactory = new JdbcTransactionFactory();

   

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

    Configuration configuration = new Configuration(environment);

   

    configuration.addMapper(CompUsersMapper.class); // Mapper 클래스

   

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

        

    }

    

// iBatis(MyBatis 반환)

public static SqlSessionFactory getSqlSessionFactory(){

        return ssf;

    }


/*


*     public static DataSource getMySQLDataSource() {

        Properties props = new Properties();


        FileInputStream fis = null;

        MysqlDataSource mysqlDS = null;

        

        try {

            fis = new FileInputStream("db.properties");


            props.load(fis);

            mysqlDS = new MysqlDataSource();

            mysqlDS.setURL(props.getProperty("MYSQL_DB_URL"));

            mysqlDS.setUser(props.getProperty("MYSQL_DB_USERNAME"));

            mysqlDS.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));

            

        } catch (IOException e) {

            e.printStackTrace();

        }

        return mysqlDS;

        

    }

    */

/*

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

*/

    private static DataSource getOracleDataSource(){

        

    OracleDataSource oracleDS = null;

        

    try {

            oracleDS = new OracleDataSource();

            oracleDS.setURL(dbUrl);

            oracleDS.setUser(userName);

            oracleDS.setPassword(userPassword);

            

        } catch (SQLException e) {

            e.printStackTrace();

        }

        return oracleDS;


    }


public Connection connect() {


Connection conn = null;


try {

Class.forName(driverName);

conn = DriverManager.getConnection(dbUrl, userName, userPassword);

}

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

} // end of if


}


public void close(Connection conn, PreparedStatement ps) {


if (ps != null ) {

try {

ps.close();

}

catch(Exception ex) {

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

}

} // end of if


if (conn != null ) {


try {

conn.close();

}

catch(Exception ex) {

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

}


} // end of if


}


}


파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip


비고: MySQL의 지원에 대해서 코드를 적어놓았다.




7. Servlet - 생성하기(Controller)


서블릿을 생성해줄 것이다.


그림 21. Java Resources의 오른쪽 버튼 메뉴 모습


Java Resources를 마우스 오른쪽 버튼으로 클릭한다.

New->Servlet을 클릭한다.



그림 22. Servlet 만들기


Package명은 "com.exmple.web.controller"로 한다.

Class Name은 "FrontController"로 한다.


Finish를 누른다.


(Exmple 오타 -> Example이 맞지만, 이미 생성했으니 그냥 따르는 걸로 하겠음.)



8. web.xml - 수정 작업


Servlet 경로를 살짝 수정해주겠다.



그림 23. web.xml - 수정하기



<!DOCTYPE web-app PUBLIC

 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

 "http://java.sun.com/dtd/web-app_2_3.dtd" >


<web-app>

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

  <servlet>

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

  <display-name>FrontController</display-name>

  <description></description>

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

  </servlet>

  <servlet-mapping>

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

  <url-pattern>/sample</url-pattern>

  </servlet-mapping>

</web-app>



파일명: web.xml


[첨부(Attachments)]

web.zip





9. CompUsers.java - Model(모델)


앞서 설계한 DB Model을 코드로 구현할 것이다.



그림 24. CompUsers.java


package com.exmple.web.model;


public class CompUsers {


private String username;

private String password;

private int enabled;

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public int getEnabled() {

return enabled;

}

public void setEnabled(int enabled) {

this.enabled = enabled;

}

}



파일명: CompUsers.java


[첨부(Attachments)]

CompUsers.zip




10. CompUsersMapper.java - Mapper(DAO)


이전 글과는 달리 공식 메뉴얼에서 제시하는 방법을 적용하도록 하겠다.



그림 25. Mapper 클래스 가이드



그림 26. Mapper 클래스 가이드 - 현실의 문제에 맞게 적용하기


package com.exmple.web.mapper;


import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Select;


import com.exmple.web.model.CompUsers;


@Mapper

public interface CompUsersMapper {

  @Select("SELECT * FROM comp_users WHERE username = #{username}")

  public CompUsers findByUsername(String username);

  

}



파일명: CompUsersMapper.java


[첨부(Attachments)]

CompUsersMapper.zip


대응하는 방식에는 XML Mapper를 적용하는 방법도 있다.
(참고로 자바방식으로 구현했다면, XML Mapper는 사용할 수 없다.)

(DB를 설계하면서 View도 만들 수도 있고 각종 조합을 할 수도 있는데, 엔터티를 잘 파악해서 구현하면 될 것 같다.)


[Spring Boot 버전의 MyBatis 핵심 사용법]


@Mapper

public interface StudentMyBatisRepository {


@Select("select * from student")

public List<Student> findAll();


@Select("SELECT * FROM student WHERE id = #{id}")

public Student findById(long id);


@Delete("DELETE FROM student WHERE id = #{id}")

public int deleteById(long id);


@Insert("INSERT INTO student(id, name, passport) VALUES (#{id}, #{name}, #{passport})")

public int insert(Student student);


@Update("Update student set name=#{name}, passport=#{passport} where id=#{id}")

public int update(Student student);


}




11. FrontController.java - Controller


FrontController의 내용을 수정하도록 하겠다.



그림 27. FrontController.java - 수정하기


package com.exmple.web.controller;


import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;


import com.exmple.web.db.SqlMapSessionFactory;

import com.exmple.web.mapper.CompUsersMapper;

import com.exmple.web.model.CompUsers;


public class FrontController extends HttpServlet {

private static final long serialVersionUID = 1L;

    SqlSessionFactory factory = SqlMapSessionFactory.getSqlSessionFactory();


/**

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

*/

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

doAction(request, response);

}


/**

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

*/

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

doAction(request, response);

}


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

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

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

  CompUsers user = mapper.findByUsername("user");

  

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

  

}

}


}



파일명: FrontController.java


[첨부(Attachments)]

FrontController.zip




12. 맺음글(Conclusion)


MyBatis 3.5.5와 Maven, JSP/Servlet 그리고 Oracle Databases를 쉽고 빠르게 연동하는 방법에 대해서 소개하였다.


1. [JSP] 20. MyBatis-3.5.5, HikariCP 3.4.2 연동 - Maven(Servlet) Spring 제거버전 (Oracle 19g) - Java 방식, 2020-10-01

https://yyman.tistory.com/1435





* 참고 자료(References)


1. MyBatis - 마이바티스 3 | 시작하기, https://mybatis.org/mybatis-3/ko/getting-started.html, Accessed by 2020-10-01, Last Modified 2020-06-05.

- 비고: 사용 방법이 담겨있음.


2. [JSP] 8. 영속프레임워크 MyBatis를 활용한 CRUD 구현 - JSP와 Oracle (XML 방식), https://yyman.tistory.com/1390, Accessed by 2020-10-01, Last Modified 2020-09-19.

- 비고: MyBatis 셋팅 방법을 참고하였으며, XML 방식을 시도하였으나 안 되었다. (Spring Beans가 안 되는 것을 알게 되었음.)


3. [Spring-Framework] 22(번외). STS 4.4 - Spring Boot Starter - MyBatis(Boot용), HikariCP 3.4 사용하기, https://yyman.tistory.com/1432, Accessed by 2020-10-01, Last Modified 2020-10-01.

- 비고: HikariCP의 properties 방식에 대해서 다시 살펴보았다.

반응형
728x90
300x250

[Spring-Framework] 19. Spring MVC - Spring Framework 5 REST, Jackson, Commons-FileUpload - (1)


프로젝트 위주로 불필요한 라이브러리는 전부 다 제거하고 순정으로 REST를 이해할 수 있도록 프로젝트를 기획하게 되었다.

REST를 제대로 소개하는 분들이 조금 적어서 간단하면서도 알기 쉽게 소개하려고 한다.

Spring Boot 위주의 REST가 많이 있는데, Spring Framework 5로 구현해도 무방하다.

결론부터 이야기하자면, 매우 잘 된다고 할 수 있다.


REST 이론부터 프로젝트까지 실질적으로 소개하려고 한다.


[사전 배경 지식]

- HTML, 간단한 폼 전송 방식 이해
- 자료구조(Data Structures)
  (DB 이런 거 전부 제거함.)


[기타]

복잡하게 SOA 등 어렵고 관련 없는 주제는 다 제거하였다.

실질적으로 사용될 수 있는 수준의 REST에 대해서 소개해보려고 한다.



작업 환경

- IDE: Spring-tool-suite 4-4.7.2. Releases. / 최신(2020-09-29)

- Maven 3.6.3/1.16.0.20200610-1735 / 최신(2020-09-29)

- Java Version: 14이상 (OpenJDK 15) / 최신(2020-09-29)

pom - maven

- Spring Framework 5.2.9. RELEASES. / 최신(2020-09-29)

- javax.servlet-api 4.0.1 (2018-04-20) / 최신(2020-09-29)

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

- jackson-core 2.11.2  - XML (2020-08-02) / 최신(2020-09-29)

- jackson-databind 2.11.2 - XML (2020-08-02) / 최신(2020-09-29)

- commons-fileupload 1.4  (Apache Commons, 2018-12-24) / 최신(2020-09-29)

- WAS: Apache-tomcat-9.0.37-windows-x64 / 최신(2020-09-29)



1. 실험 결과


(1차)

- Maven Project (webapp)

  Resteasy(JBoss 기반)

  -> 웹 브라우저로 출력을 시도했을 때, XML 변환이 안 됨. (GET, POST, PUT, PATCH, DELETE)는 동작함.

     (자료가 많이 부족함.)


  [첨부(Attachments)] (영어)

resteasy-reference-guide-en-US.pdf


결론: 동작은 되나 XML 변환 도구를 찾을 수 없음. (실패)


(2차)

- Maven Project (webapp)

  Jersay (4~5개 이상 POM 요구됨.)

  

과거에는 호환성이 나름대로 있었다고 하나, 현재에는 버전이 전부 제각각이고 사용하기에 부적합하다고 주장함.

(2020-09-28)

참고: 과거에는 com.sun..... jersey 형태의 패키지에서 현재는 "Jersey"가 독립 프로젝트로 분리되었음.

   javax가 일부 명칭이 변경되었음.


  [첨부(Attachments)] (영어)

jersey-documentation-3.0.0-M1-user-guide.pdf


결론: 동작 자체가 안 됨. (실패)


(3차)

- Spring Framework 5.4

  - Spring Legacy Project -> Spring MVC Project

    -> Pom(Maven) : 

        Spring Framework 5.4 - 2020-09-28일 기준 최신

        Servlet 4.0.1 - 2020-09-28일 기준 최신

        Jackson(core, bind) = 용도: XML Parser 2.11.2 - 2020-09-28일 기준 최신

        Apache Commons-FileUpload


결론: 성공





2. REST - 구현 관점에서 이론 소개


복잡하게 다른 걸 알 필요는 없다고 보고, HTTP 프로그램 작성해봤으면 POST/GET 이걸 다뤄본 경험들이 있을 것이다.

해외에 있는 "(Ph.D / 공학/이학 계통의 박사) 로이 필딩이 발표하신 학위 논문이 전 세계에 널리 알려진 거라고 보는 게 좋겠다.


https://roy.gbiv.com/


관심이 있는 분들은 로이 필딩 박사 홈페이지에서 대략적인 이력을 살펴봐도 무방하다.

로이 필딩 박사의 주요 업적은 "Apache Web Server", "REST(학위 논문)" 두 가지라고 보면 된다.


웹 분야에서는 매우 권위있는 분 중 하나라고 생각하면 된다.


전송 방식의 문제인데 "POST/GET"만 웹에서는 가능하다. (HTML5 현재까지도)


REST의 약자인 REST(Representational State Transfer)는 GET/POST의 한계를 현실세계의 상태 개념과 접목 시켜서 고민을 한 모양이다.

(필자는 비록 논문을 읽어보진 못했지만, 작업을 하면서 느껴본 견해이다.)


핵심을 요약하면,


표 1. 다양한 전송방식(REST)


번호 

작업

전송 방식

1

Create

POST

2

Read

GET

3

Update

PUT 또는 Patch

4

Delete

DELETE


REST는 4가지 전송 방식으로 확장되었다.


* 자바스크립트의 (Ajax)로 REST를 전송할 수 있는가?

-> 구현되었다고 주장하는 시중 코드들이 있을 수는 있겠으나 안 될 수도 있다.
   (= 국제 웹 관련 표준기구(W3C) REST를 GET, POST 이외에도 표준으로 인정해주지 않는 이상 어렵다고 본다.)


표 2. 회원(Member) 자원에 대한 전송 방식 정의


작업

전송방식 

URI 

생성

POST

/member/new 

조회(전체)

GET

/member

조회(특정)

GET

/member/{id}

수정

PUT or PATCH

/member/{id}

삭제

DELETE

/member/{id}


꼭 이런 정의가 반드시 표준이라는 건 아니다. 일부 책들을 많이 대조해보고, 인터넷 검색 등을 해봤으나 "이런 형태로 쓸 수 있다." 이렇게 생각하면 좋겠다.

도메인이 달라지면, 달라지는 데로 바꿔서 사용해야 한다.




3. REST - 웹 표준 관점에서 무엇이 문제가 되는가?


코드 구현으로 이러한 기술적 문제를 소개해주려고 한다.


<form method="PUT">

~~~(중략)

</form>


코드 1) 이론적으로는 이렇게 되어야 함. (미지원)


<form method="POST">

<input type="hidden" name="_method" value="PUT"> 

~~~(중략)

</form>


코드 2) 과거 잠시 표준 규격에서 예외를 해주었던 규격 (미지원)


코드 2 형태로 구현하면, 동작될 수도 있었던 잠시 과거가 있긴 있었다.

표준 기구 등에서 제한에 걸어서 동작하지 않은 코드들이다.


(슈도 코드)
<script>

    .....

   


    ajax{

           contents/json

           method = "PUT" action=......


           sucessed{

           }

           failed{



           }

    }

</script>
~~~(중략)

<form method="POST">

<input type="hidden" name="_method" value="PUT"> 

~~~(중략)

</form>


코드 3) ajax 자바스크립트 - 슈도 코드 (미지원)


이러한 코드 형태도 태스트해본 결과로는 동작하지 않는다.



그림 1. RequestMethod.PATCH, RequstMethod.PUT (Spring-Framework 5.4)


그림 1의 코드 형태로 정의했을 때, 전송이 되냐는 것이다.

결론부터 이야기하면, 안 된다.


다 안 된다고 적었으니, 그러면 "REST는 전혀 사용할 수 없는 건가요?"라는 물음이 들 수 있다.

이야기하면, 사용할 수 있다.


그런데 사용할 수 있는 용도가 있다는 것이다.


예1) 안드로이드 - 게시판 개발, 

예2) 각종 규격 문서 또는 메시지 전달


(이런 부분에서 사용하면 적합하다고 본다.)


-> 원격지에서의 파일 전송과 내려받기는 괜찮을까요?

   결론부터 놓고 보면, 안 된다. (원격지 REST를 활용해서 전송할 수 있는가?)

   이론적으로는 Multipart로 해서 하면 될 것 같은데 POST에서는 처리될 수도 있겠으나, 어려울 수 있다.

   = 표 2의 명세에서는 "등록(POST 방식)", "수정(PUT)" 방식을 소개하고 있는데, 다소 어렵다고 하는 이야기가 이런 부분이다.


굳이 어렵게 "전송 해더(Header)" 찾고 등의 고도의 작업을 시도해도 안 되는 이유가 보안이라는 주제 때문에 웹 브라우저 등에서 제약이 되어 버린다.



[호기심 자극하기]

안드로이드 어플을 사용하다 보면, 업로드 기능이 있는 경우에는 순수한 안드로이드 기술로 개발한 게 아니라 다른 웹 사이트를 호출해서 사용한 것이다.

개발 관점에서는 안 된다가 타당하다고 본다.


JSP, PHP, ASPX, ASP 등의 개발이 되니깐 그걸 그냥 그대로 활용한 것이다.




4. URI, URL에 대해서


* URI(Uniform Resource Identifier) : 자원의 식별자라는 의미
* URL(Uniform Resource Location) : 주소


URL은 URI의 하위개념이므로 혼용해도 무방할 수 있다.

이론적으로도 비슷하게 취급될 여지도 있어서 크게 용어를 따로 이중으로 외워둘 필요까진 없겠다.




5. REST의 실질적인 기능 (서버, 클라이언트 관계)


REST는 XML-RPC처럼 통신 계열로 보는 게 적합하다고 본다.

태스트를 하다보면, 육감적으로 왜 그렇게 보는 게 타당한지 이해할 수 있을 것으로 보인다.



그림 2. REST 전용 태스트 도구 - 브라우저 내 추가한 앱스(YARC! Yet Another REST Client)


가장 사용하기에 좋은 REST 태스트 도구라고 본다.

이 방식을 흔히 많이 소개하고 있는데, 코드로도 서버를 하나 구축해서 사용할 수 있다.




그림 3. RestTemplate를 이용한 Server 만들기 - 자바(스프링 프레임워크 5.4)



그림 4. Spring MVC Controller를 이용한 Client 만들기(RestController 등) - 자바(스프링 프레임워크 5.4)


정리를 해보면, 아래의 도식처럼 요약해볼 수 있다.




그림 5. REST Client와 Server 관계


이런 느낌으로 사용하게 된다.

이런 관계인 이유는 메시지 형태로 데이터를 반환하면, "객체, 메시지" 등의 정보를 송/수신 할 수가 있다.


어노테이션 

기능 

@RestController

Controller가 REST 방식을 처리하기 위해 명시한 것 

@ResponseBody

일반적인 JSP와 같은 뷰로 전달되는 게 아니라 데이터 자체를 전달하기 위한 용도 

@PathVariable

URL 경로에 있는 값을 파라미터로 추출하려고 할 떄 사용 

@CrossOrigin

Ajax의 크로스 도메인 문제를 해결해주는 어노테이션  

@RequestBody

JSON 데이터를 원하는 타입으로 바인딩 처리 


실질적으로 @RestController는 필수 정의이다.

@PathVariable과 함께 조합해서 가장 많이 사용할 것으로 보인다.


운이 나쁘면, 크로스 오리진 등은 접할 수도 있고, 안 접할 수도 있다.



6. 프로젝트 - 소개


복잡한 주제는 조금 정리하고 실질적으로 꼭 필요한 형태로 이러한 기능들을 모두 담고 있는 종합적인 REST만 전문으로 하는 프로젝트를 작성하였다.



그림 6. 프로젝트 구성도


다른 프로젝트 등에 비해서 매우 깔끔하고 간단한 형태로 REST를 취급할 수 있도록 신경을 조금 써서 작성한 것이다.

데이터베이스 지식, MyBatis(iBatis) 등 그런 거 일절 신경 안 쓰고 다뤄볼 수 있으니 참고하면 되겠다.



그림 7. 결과 1(client/listMapDelete/{id})



그림 8. 결과 2(/v1/api/board)의 JSON



그림 9. 결과 3(/v1/api/board)의 JSON (결과 출력)




그림 10. 결과 4(/v1/api/board/new)의 JSON(POST 전송)



그림 11. REST 전송 방식들


굉장히 많은 전송 방식이 있다는 것을 알 수 있다.



그림 12. 다중 업로드 프로젝트 (1) - REST 활용



그림 13. 다중 업로드 프로젝트 (2) - REST 활용



그림 14. 다중 업로드 프로젝트 (3) - 업로드 반응



그림 15. 다중 업로드 프로젝트 (4) - 업로드 반응



그림 15. 다중 업로드 프로젝트 (4) - 실제 업로드 모습





7. 프로젝트 생성


프로젝트 생성부터 단계적으로 아주 친절하게 하도록 하겠다.


[선수 준비되어야 할 부분]

- 필자의 글을 보면, 이 부분이 아주 자세히 소개되고 있는데 잊어버리기 쉬워서 다시 계속 강조하는 것이다.

한 번 셋팅해놓으면 크게 무방한데, 안 될 경우 등 문제를 충분히 고민한 후에 포함시킨 것이니깐 이해 해주었으면 좋겠다.


Help-> Eclipse Marketplace -> STS 검색 -> Spring-Tool Add-on



그림 16. Help의 Eclipse Marketplace



그림 17. Help의 Eclipse Marketplace


Spring Tools 3 Add-On for Spring Tools 4 3.9.14 Release를 선택한 후 Install을 해준다.

-> Spring Framework 3.2인가 "Spring Legacy Project" 기능을 최신 버전에서도 사용할 수 있도록 도와주는 도구이다.


Spring Legacy Project만 동작되어도 기본 셋팅하는 데 있어서 매우 수월해진다.




그림 18. Eclipse의 파일 메뉴 모습


File->New->Spring Legacy Project를 클릭한다.



그림 19. Spring MVC Project 생성하기 - Spring Legacy Project 기능


Spring MVC Project를 선택한다.

Project Name을 입력한다.

Next를 누른다.



그림 20. 패키지 정보 입력 - Spring MVC Project 생성하기


패키지명을 입력한다.

Finish를 누른다.




8. 자바 버전 바꾸기 - 프로젝트 Properties의 Build Path, Project-Factes


자바 버전을 바꿔줘야 한다.

이유는 Spring Legacy Project의 기본 셋팅이 하위버전으로 되어있기 때문이다.



그림 21. 프로젝트의 Properties 클릭하기 (프로젝트 마우스 오른쪽 버튼의 메뉴 모습)


프로젝트를 선택한다.

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

"Properties"를 클릭한다.



그림 22. Properties - Build Path


JRE System Library를 선택한다.

Edit를 누른다.

JRE를 클릭한다.

14버전으로 바꿔준다.

Apply를 누른다.



그림 23. Properties - Project Factes


Java의 버전을 14버전으로 바꿔준다.

Apply를 누른다.

Apply and Close를 누른다.



9. pom.xml 환경설정하기


꼭 열어봐야 할 사이트가 있다.

http://mvnrespository.com 사이트에 접속해서 버전 등을 확인해줘야 한다.


검색 방법을 잊어버린 사람들을 위해서 특별히 다시 언급하겠다.



그림 24. Spring Framework 검색 결과 - mvnrepository


Spring Framework를 클릭한다.



그림 25. Spring Framework 검색 결과 - mvnrepository


5.2.9.RELEASE를 선택한다.




그림 26. Spring Framework 검색 결과 - mvnrepository


Maven의 POM 배포 코드를 복사한다.



그림 27. pom.xml 수정작업(1) - 자바 버전과 스프링 프레임워크 버전 업그레이드


자바 버전과 Spring-Framework 버전을 변경해준다.

참고로 Spring-Framework의 경우에는 일명 "깔맞춤"으로 자동 버전 셋팅이 되는 경우가 있다.


다 되는 건 아니니깐 찾아보는 작업을 잊지 않아야 한다.



그림 28. pom.xml 수정작업(2)


javax.servlet 버전도 업그레이드 해준다.




그림 29. pom.xml 수정작업(3)


jackon-core, jackson-databind, commons-fileupload를 각각 검색해서 "복사, 붙여넣기"를 해준다.


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

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>

<artifactId>restexample2</artifactId>

<name>restExample2</name>

<packaging>war</packaging>

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

<properties>

<!-- 자바 버전(14로 작성) -->

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

<!-- 스프링 프레임워크 - 최신 버전 적용함 -->

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

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

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

</properties>

<dependencies>

<!-- Spring -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

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

<exclusions>

<!-- Exclude Commons Logging in favor of SLF4j -->

<exclusion>

<groupId>commons-logging</groupId>

<artifactId>commons-logging</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-webmvc</artifactId>

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

</dependency>

<!-- AspectJ -->

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjrt</artifactId>

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

</dependency>

<!-- Logging -->

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

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

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>jcl-over-slf4j</artifactId>

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

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-log4j12</artifactId>

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

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.15</version>

<exclusions>

<exclusion>

<groupId>javax.mail</groupId>

<artifactId>mail</artifactId>

</exclusion>

<exclusion>

<groupId>javax.jms</groupId>

<artifactId>jms</artifactId>

</exclusion>

<exclusion>

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

<artifactId>jmxtools</artifactId>

</exclusion>

<exclusion>

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

<artifactId>jmxri</artifactId>

</exclusion>

</exclusions>

<scope>runtime</scope>

</dependency>


<!-- @Inject -->

<dependency>

<groupId>javax.inject</groupId>

<artifactId>javax.inject</artifactId>

<version>1</version>

</dependency>

<!-- Servlet -->

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

<dependency>

    <groupId>javax.servlet</groupId>

    <artifactId>javax.servlet-api</artifactId>

    <version>4.0.1</version>

    <scope>provided</scope>

</dependency>

<dependency>

<groupId>javax.servlet.jsp</groupId>

<artifactId>jsp-api</artifactId>

<version>2.1</version>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

<version>1.2</version>

</dependency>

<!-- Test -->

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.7</version>

<scope>test</scope>

</dependency>       

<!-- https://mvnrepository.com/artifact/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-databind -->

<dependency>

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

    <artifactId>jackson-databind</artifactId>

    <version>2.11.2</version>

</dependency>

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

<dependency>

    <groupId>commons-fileupload</groupId>

    <artifactId>commons-fileupload</artifactId>

    <version>1.4</version>

</dependency>

 

</dependencies>

    <build>

        <plugins>

            <plugin>

                <artifactId>maven-eclipse-plugin</artifactId>

                <version>2.9</version>

                <configuration>

                    <additionalProjectnatures>

                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>

                    </additionalProjectnatures>

                    <additionalBuildcommands>

                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>

                    </additionalBuildcommands>

                    <downloadSources>true</downloadSources>

                    <downloadJavadocs>true</downloadJavadocs>

                </configuration>

            </plugin>

            <plugin>

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

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

                <version>2.5.1</version>

                <configuration>

                    <source>1.6</source>

                    <target>1.6</target>

                    <compilerArgument>-Xlint:all</compilerArgument>

                    <showWarnings>true</showWarnings>

                    <showDeprecation>true</showDeprecation>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.codehaus.mojo</groupId>

                <artifactId>exec-maven-plugin</artifactId>

                <version>1.2.1</version>

                <configuration>

                    <mainClass>org.test.int1.Main</mainClass>

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>



파일명: pom.xml


[첨부(Attachments)]

pom.zip




10. web.xml - 환경설정하기


web.xml 파일 셋팅은 무척 중요하다고 볼 수 있다.

반드시 해야 하는 작업이다.


경로명: /src/main/webapp/web.xml




그림 30. 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">

  <context-param>

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

    <param-value>/WEB-INF/spring/root-context.xml</param-value>

  </context-param>

  <listener>

    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

  </listener>

  <servlet>

    <servlet-name>appServlet</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>

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

      <param-value>

      /WEB-INF/spring/appServlet/servlet-context.xml

      /WEB-INF/spring/spring-file-config.xml

      </param-value>

    </init-param>

    <load-on-startup>1</load-on-startup>

  </servlet>

  <servlet-mapping>

    <servlet-name>appServlet</servlet-name>

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

  </servlet-mapping>

  <servlet>

    <description></description>

    <display-name>RestController</display-name>

    <servlet-name>RestController</servlet-name>

    <servlet-class>com.example.restexample2.controller.RestController</servlet-class>

  </servlet>

  <servlet-mapping>

    <servlet-name>RestController</servlet-name>

    <url-pattern>/RestController</url-pattern>

  </servlet-mapping>

</web-app>


파일명: web.xml


[첨부(Attachments)]

web.zip



11. spring-file-config.xml - 파일 생성하기


생성경로: /src/main/webapp/WEB-INF/spring/spring-file-config.xml


왜 작업을 해주냐면, Apache Commons-Fileupload를 사용하기 위해서이다.



그림 31. spring 폴더의 오른쪽 버튼 메뉴 모습


spring 폴더를 마우스 오른쪽 버튼으로 클릭한다.

New-> File을 클릭한다.


"spring-file-config.xml" 파일을 만들어준다.




그림 32. spring-file-config.xml - 작업 모습


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

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

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

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

<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

    <property name="maxUploadSize" value="10485760"/>

    <property name="maxUploadSizePerFile" value="10485760"/>

    <property name="maxInMemorySize" value="0"/>

</bean>

</beans>



파일명: spring-file-config.xml


[첨부(Attachments)]

spring-file-config.zip




* 2부에서 만나요.


2부에서는 Controller와 Model, View, Util의 주제를 다뤄보겠다.


1. [Spring-Framework] 19. Spring MVC - Spring Framework 5 REST, Jackson, Commons-FileUpload - (1), Accessed by 2020-09-28

https://yyman.tistory.com/1426


반응형

+ Recent posts