728x90
300x250

[JSP] 29. 프로젝트 구성 방법 - Eclipse로 살펴보는 보안 프로젝트 구성


오랜만에 글을 작성한다.

이번에 소개할 내용은 시큐어코딩에 대해서 몇 가지 주제를 가지고 소개하려고 한다.

프로젝트 생성 방법에 대해서 몇 가지 소개하려고 한다.


장점: 정보를 보호할 수 있음.

단점: 정보를 보호하는 대신에 개발 메뉴얼 등이 요구됨.

       오류가 나면, 코어 소스를 가지고 있는 인원에 대응해야 하는 한계가 있음.


* 규모가 큰 프로젝트에 적합할 수 있다.

* 갈등이 많은 작은 규모에서도 고려할 수 있다.



1. 프로젝트 생성 방법


기존의 코딩 방법과는 몇 가지 차이가 있을 수 있다.


 


그림 1. 프로젝트 구성의 예1) 보안이 적용된 모습

그림 2. 프로젝트 구성의 예2 - 보안이 적용되지 않는 모습


일반적인 경우라고 하면, 그림 2처럼 프로젝트를 생성하고 개발할 것이다.

그림 1의 방법으로 하면 무엇이 장점이 되는지 소개하도록 하겠다.



2. 불필요한 정보 - 은닉하기


예를 들어서 개발자가 있다고 가정하자.

개발자와 DBA의 권한은 또 한 차원 다른 문제가 된다.

불필요하게 개발자가 DBMS에 접근하여 정보를 조작하는 행위를 가급적 안 하는 것이 좋을 수 있다.

이러한 문제에 직면했을 때, 실질적인 이론 말고 코드와 프로젝트 구성으로서 어떻게 방어해야 할지 알아두면 좋을 듯싶다.


 


그림 3. 정보 은닉이 완료된 시큐어코드


그림 3은 정보 은닉이 완료된 시큐어코드이다.

무슨 이야기인지 그림 4를 살펴 보면서 소개하도록 하겠다.


 

그림 4. jar 파일로 컴파일하기


그림 4는 jar 파일로 공통 함수를 컴파일된 Library를 불러온 것이다.

이렇게 해버리면, 개발자는 제공된 공통함수만 가지고 코딩을 해야 하므로, "서버 계정", "DB 정보" 등 불필요한 요소들에 대해서

접근할 필요가 없어진다.


개발자는 설계된 테이블에 대해서 SELECT, INSERT, DELETE, UPDATE 기능만 구현해주면 된다.


물론 이게 전부 시큐어코딩이라고는 볼 수 없다. 해독하는 프로그램도 종종 있을 수 있기 때문이다.

다만, 정보 노출을 최소화하는 역할을 한다고 보면 된다.



3. 사용 방법(Jar - Export하기)


"Dodo_SmartCoreWeb" 프로젝트를 마우스 오른쪽 버튼을 누른다.

"Export"를 클릭한다.


 

 그림 5. Export 하기


그리고 Jar 파일로 Export할 대상을 선택한다.


 

 그림 6. Jar 파일 - Export하기


JAR file 경로를 "Browse"를 눌러서 지정해준 다음에 "Finish"를 누른다.



4. 사용 방법(Jar - Properties의 Java Build-Path의 Libraries에 User Libraries 등록하기)


프로젝트를 마우스 오른쪽 버튼으로 클릭한다.



그림 7. 프로젝트 속성 - Properties


프로젝트를 클릭한다.

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

Properties를 클릭한다.



그림 8. 프로젝트 속성 - Properties


Java Build Path를 클릭한다.

Libraries 탭을 클릭한다.

Add Library를 클릭한다.



그림 9. Add Library


User Library를 선택한다.

Next를 누른다.




그림 10. Add Library - User Libraries...


User Library를 선택한다.

Next를 누른다.



그림 11. Properties의 User Libraries


New를 클릭한다.



그림 12. New User Library


예를 들면 "HelloCore"라고 입력한다.

OK를 누른다.



그림 13. JAR Selection 모습


Add Jars를 누른다.

예를 들면, SmartWorkJar.jar를 선택한다.

OK를 누른다.



그림 14. Preferences의 모습


등록된 HelloCore의 User Libraries 모습을 확인할 수 있다.

Apply and Close를 누른다.



그림 15. Add Library 창


HelloCore를 선택하고 Finish를 누른다.



그림 16. Java Build Path에 등록된 Hello Core


Java Build Path에 등록된 "HelloCore"를 살펴볼 수 있다.



5. 기대효과


불필요한 소스 코드를 줄이고, 개발자, 관리자, DBA 등 업무 분담 형태의 개발을 구성할 수 있다.

물론, 보안코드를 요구하는 곳에는 이런 형태로 구성할 수 있다.

반응형
728x90
300x250

[JSP] 28. Maven (Jaxb-runtime, activation, Jaxb Api, JSTL)을 활용한 XML 생성하기


JSP/Servlet으로도 Jaxb2와 각종 Library를 활용하여 XML을 생성할 수 있다.

일반 프로그래밍은 많이 접하였으나, XML은 잘 접해보지 않을 수도 있다.






1. XML을 JSP 파일에 수작업으로 입력하기


XML을 만드는 방법에는 수작업으로 하는 방법이 있겠다.


<xml>

<hama>

     <board>

     </board>

     <board>

     </board>

     <board>

     </board>

</hama>


예를 들면 이런 형태를 JSP에서 for문 등으로 VO를 읽어와서 뿌려주는 방법이 있겠다.

원시적인 방법이고, 자료가 3중, 4중으로 된 것을 처리하고자 했을 때는 수행빈도가 높아지는 단점이 있다.

코드도 복잡해진다.


물론 DB형태에 보관된 자료로 뿌릴 수도 있다.



<%@ page language="java" contentType="text/xml"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!-- 수작업으로 XML 규격을 만들어야 함. -->
<boardList>
 <board>
  <hello>asdf</hello>
 </board>
</boardList>


파일명: xml.jsp


[첨부(Attachments)]

xml.zip




2. JSP/Servlet - Maven Project


org.apache.maven.archetypes    |  maven-archetype-webapp    | 1.4(1.0)를 선택한다.


그림 1. JSP/XML 프로젝트 구성도




3. Java Compiler, Build Path, Project Factes


* Java Compiler - compiler compliance level 1.8
* Build Path -> JRE System Library 1.8
* Project Factes - Java : 1.8



4. Pom.xml 설정


Spring Framework에서도 <dependency>부분은 그대로 사용이 가능하다. (태스트 완료함)

pom.xml에 정의했던 라이브러리를 그대로 사용하는 것이다.

단, 출력하려고 했을 때, Jaxb에 대한 직접 출력을 정의하냐 안 하느냐 이런 차이가 있다.


 <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
 <dependency>
     <groupId>javax.servlet</groupId>
     <artifactId>servlet-api</artifactId>
     <version>2.5</version>
     <scope>provided</scope>
 </dependency>
 
 <!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
 <dependency>
     <groupId>javax.xml.bind</groupId>
     <artifactId>jaxb-api</artifactId>
     <version>2.3.0-b170201.1204</version>
 </dependency>
 
 <!-- https://mvnrepository.com/artifact/javax.activation/activation -->
 <dependency>
     <groupId>javax.activation</groupId>
     <artifactId>activation</artifactId>
     <version>1.1</version>
 </dependency>
 
 <!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
 <dependency>
     <groupId>org.glassfish.jaxb</groupId>
     <artifactId>jaxb-runtime</artifactId>
     <version>2.3.0-b170127.1453</version>
 </dependency>

 
 <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
 <dependency>
     <groupId>javax.servlet</groupId>
     <artifactId>jstl</artifactId>
     <version>1.2</version>
 </dependency>


파일명: pom.xml


[첨부(Attachments)]

pom.zip



5. BoardVO.java (com.website.example.vo)


package com.website.example.vo;

import java.sql.Date;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlTransient;


@XmlAccessorType(XmlAccessType.FIELD)
public class BoardVO {


        @XmlAttribute   // 보여줄 항목이다. 이런 뜻
         private int id;
         private String title;
         private String writer;
         private String content;
         private Date regDate;
 
        @XmlTransient    // 출력하지 않겠다.
         private String searchCondition;
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getTitle() {
  return title;
 }
 public void setTitle(String title) {
  this.title = title;
 }
 public String getWriter() {
  return writer;
 }
 public void setWriter(String writer) {
  this.writer = writer;
 }
 public String getContent() {
  return content;
 }
 public void setContent(String content) {
  this.content = content;
 }
 public Date getRegDate() {
  return regDate;
 }
 public void setRegDate(Date regDate) {
  this.regDate = regDate;
 }
 public String getSearchCondition() {
  return searchCondition;
 }
 public void setSearchCondition(String searchCondition) {
  this.searchCondition = searchCondition;
 }
 
 
 
}


파일명: BoardVO.java


[첨부(Attachments)]

BoardVO.zip


- 게시판 DB에서도 사용한다고 가정하자.



6. BoardListVO.java (com.website.example.vo)


package com.website.example.vo;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "boardList")
@XmlAccessorType(XmlAccessType.FIELD)
public class BoardListVO {


         @XmlElement(name = "board")
         private List<BoardVO> boardList;
 
         public List<BoardVO> getBoardList(){
               return this.boardList;
         }
 
         public void setBoardList(List<BoardVO> boardList) {
               this.boardList = boardList;
         }
 
}


파일명: BoardListVO.java


[첨부(Attachments)]

BoardListVO.zip


루트 RootElement를 정의해줘야 XML 출력을 할 수 있는데, 출력을 그냥하는 건 아니고, List 형태로 구성된 VO(Value Object)를 출력하는 것이다.




7. HomeController.java (com.website.example.controller)


밑줄 친 부분들이 중요한 부분이다.


package com.website.example.controller;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import com.website.example.vo.BoardListVO;
import com.website.example.vo.BoardVO;


public class FrontController extends HttpServlet {
 private static final long serialVersionUID = 1L;
      
 
 protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
  
            res.setContentType("text/xml;charset=utf-8");
    
            String result = setXmlData();
            PrintWriter out = res.getWriter();
  
            out.println(result);
  
            out.flush();
            out.close();

 }

 /**
  * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
  */
 protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
  
 }
 
        public String setXmlData(){
  
                 JAXBContext jc = null;
                 Marshaller marshaller = null;
   
                 List<BoardVO> boardList = new ArrayList<BoardVO>();
                 BoardListVO boardListVO = new BoardListVO();
  
                 OutputStream os = new ByteArrayOutputStream();

                 BoardVO vo = new BoardVO();
  
                 try {
                      jc = JAXBContext.newInstance(BoardListVO.class);
    
                 } catch (JAXBException e) {
                      e.printStackTrace();
                 }

                 vo.setId(1);
                 vo.setTitle("야야야1");
                 vo.setSearchCondition("하후");
                 vo.setWriter("홍길동");
                 vo.setRegDate(java.sql.Date.valueOf("2010-02-01"));
  
  boardList.add(vo);
  
  vo = new BoardVO();
  vo.setId(2);
  vo.setTitle("야야야2");
  vo.setSearchCondition("하후");
  vo.setWriter("홍길동");
  vo.setRegDate(java.sql.Date.valueOf("2010-03-01"));

               boardList.add(vo);

               boardListVO.setBoardList(boardList);
  
                try {
                       marshaller = jc.createMarshaller();
                       marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
                       marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
   
                       // marshaller.marshal(boardListVO, System.out);
                       marshaller.marshal(boardListVO, os);
   
                } catch (JAXBException e) {
                       e.printStackTrace();
    
                }

  
                // System.out.println("XML출력:" + os.toString());
   
                return os.toString();

  
        }

}


파일명: FrontController.java


[첨부(Attachments)]

FrontController.zip




8. web.xml (/src/main/webapp/WEB-INF/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.website.example.controller.FrontController</servlet-class>
  </servlet>
  <servlet-mapping>
           <servlet-name>FrontController</servlet-name>
           <url-pattern>/dataTransform.do</url-pattern>
  </servlet-mapping>
</web-app>


파일명: web.java


[첨부(Attachments)]

web.zip



9. 출력 결과


완성된 결과물이다.



그림 2. XML.jsp 파일 (수작업 방법)



그림 3. Jaxb2 외 다수 라이브러리로 적



* 맺음글(Conclusion)


JSP/Servlet 기반에서 XML 출력하는 방법에 대해서 살펴보았다.

반응형
728x90
300x250

[JSP] 27. Java 스타일의 트랜젝션 구현하기(은행 계좌)


트랜젝션 처리에 대해서 소개하려고 한다.

이 주제는 사실 몇 가지 키워드가 있다.


ACID(원자성, 일관성, 고립성, 지속성)을 만족해야 한다.


기본적인 DML만 조작하다가 갑자기 접근하게 되면, 이 내용은 조금 난해할 수도 있다.


1. 자료처리에 있어서 4가지를 모두 충족해야 한다.


원자성(Atomicity)
트랜젝션은 분해가 불가능한 최소의 단위인 하나의 원자처럼 동작한다는 의미. 

트랜젝션 내의 모든 연산들은 반드시 한꺼번에 완전하게 전체가 정상적으로 수행이 완료되거나 아니면 연산자체를 수행하지 않음.


일관성(Consistency)
트랜잭션 작업이 시작되지 전에 데이터베이스 상태가 일관된 상태였다면 트랜잭션 작업이 종료된 후에도 일관성 있는 데이터 베이스 상태를 유지해아한다.

예를 들어서 게시판에 글을 쓰는데 제목의 글자 제한이 255자라고 하자.

트랜잭션이 일어나면 이러한 조건을 만족해야하는 것이다. 만약 이를 위반하는 트랜잭션이 있다면 롤백 처리해야 한다.

(문제가 있는 작업이라면, 입력자체를 시키면 안 되는 것이다.)


고립성(Isolation)
트랜잭션 작업 수행 중에는 다른 트랜잭션에 영향을 주어서도 안 되고, 다른 트랜잭션들에 의해 간섭을 받아서도 안 된다는 것을 의미. 


다른 트랜잭션의 영향을 받게 되면 영향을 주는 트랜잭션에 의해 자신의 동작이 달라 질 수 있기 때문이다.

트랜젝션 자신은 고립된 상태에서 수행되어야 한다는 것을 의미. 즉 다수의 트랜잭션이 동시에 수행중인 상황에서 하나의 트랜잭션이 완료될 때까지는 현재 실행 중인 트랜잭션의 중간 수행결과를 다른 트랜잭션에서 보거나 참조 할 수 없다.


지속성(Durablility)
일련의 데이터 조작(트렌젝션 조작)을 완료 하고 완료 통지를 사용자가 받는 시점에서 그 조작이 영구적이 되어 그 결과를 잃지 않는 것을 나타낸다. 시스템이 정상일 때 뿐 아니라 데이터베이스나 OS의 이상 종료, 즉 시스템 장애도 견딜 수 있다는 것을 말한다.




2. "은행 계좌"라는 주제


은행 계좌 구현의 문제를 놓고 보면, 돈을 이체시켰는데 시스템 장애로 돈이 빠져나가고 이체가 되지 않아버리면 입금자는 돈을 잃어버리게 된다.

물론 트랜젝션만 가지고 은행 시스템이 구축된 것은 아닐 것이다.


이런 경우를 컴퓨터 프로그래밍으로 표현해보려고 한다.




3. JSP/Servlet으로 구현해도 되고, JUnit 태스트 도구로 접근해도 상관없다.


이 프로젝트를 자습하는 데 있어서, 자유롭게 원하는 형식에서 태스트해도 무방하다.

자바 기반이면, 스프링프레임워크에서도 가능하고, Dynamic Web Project를 생성해도 무방하고 Java Project로 따라해도 괜찮다는 이야기를 하고 소개하겠다.


[태스트 환경]

IDE: Eclipse 2020-06

DB: Oracle 11g XE(Express Edition)
- Maven Projects(Spring 포함)

- JUnit 5



4. 데이터베이스 설계


-- Transaction 실습 DB (은행 - Account)
-- Oracle 11 - 자동번호 생성 테이블 정의
-- Table 생성 (FOODMENU_TBL)
-- NEW.ID (Table의 id를 가리킴)

CREATE TABLE account_tbl
(
    idx NUMBER PRIMARY KEY,
    name VARCHAR2(30),
    balance NUMBER,
    regidate TIMESTAMP
);


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


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


트리거 작성과 스퀀스 번호 생성에 대해서도 적혀져 있으니깐, 잘 사용해도 무방하다.


파일명: account_tbl.sql


[첨부(Attachments)]

AccountTbl.zip




5. 프로젝트 구성도


아래 그림은 프로젝트 구성도이다.

HomeController.java 등은 생략해도 된다.



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



6. AccountVO.java(com.website.example.vo)


package com.website.example.vo;

import java.sql.Timestamp;

public class AccountVO {

 private int idx;
 private String name;
 private int balance;
 private Timestamp regidate;
 
 public int getIdx() {
      return idx;
 }
 
 public void setIdx(int idx) {
     this.idx = idx;
 }
 
 public String getName() {
     return name;
 }
 
 public void setName(String name) {
     this.name = name;
 }
 
 public int getBalance() {
     return balance;
 }

 public void setBalance(int balance) {
     this.balance = balance;
 }

 public Timestamp getRegidate() {
     return regidate;
 }
 
 public void setRegidate(Timestamp regidate) {
     this.regidate = regidate;
 }
 
}


파일명: AccountVO.java


[첨부(Attachments)]

AccountVO.zip




6-1. db.properties (/src/main/resources)


MYSQL_DB_URL=jdbc:mysql://localhost:3306/dbanme?useUnicode=true&characterEncoding=utf8
MYSQL_DB_USERNAME=
MYSQL_DB_PASSWORD=
ORACLE_DB_URL=jdbc:oracle:thin:@127.0.0.1:1521:xe
ORACLE_DB_USERNAME=HR
ORACLE_DB_PASSWORD=1234


파일명: db.properties


[첨부(Attachments)]

db.zip




7. JDBCUtil.java(com.website.example.common)


이 프로젝트에서는 close()만 사용하였다. 예비 태스트 용도로 자바 표준의 SQL 방식도 두고 있다.


package com.website.example.common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import javax.sql.DataSource;


public class JDBCUtil {
 
      private static final String driverName = "oracle.jdbc.driver.OracleDriver";
      private static final String jdbcUrl = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
      private static final String userId = "{사용자 계정명}";
      private static final String userPwd = "{비밀번호}";
 
 public static Connection getConnection() {


  try {
   
       Class.forName(driverName); 
        return DriverManager.getConnection(jdbcUrl, userId, userPwd);
   
  } catch (Exception e) {
        e.printStackTrace();
  }
  
  return null;
  
 }


 public static void close(PreparedStatement stmt, Connection conn) {
  
  if (stmt != null) {
   
   try {
    
    if (!stmt.isClosed())
     
       stmt.close();
    
   } catch (Exception e) {
    
        e.printStackTrace();
    
   } finally {
    
        stmt = null;
    
   }
   
  } // end of if
  
  if (conn != null) {
   
   try {
    
    if (!conn.isClosed())
         conn.close();
    
   } catch (Exception e) {
    
    e.printStackTrace();
    
   } finally {
    
    conn = null;
    
   }
   
  } // end of if
  
 }

 public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
  
  if (rs != null) {
   
   try {
    
    if (!rs.isClosed())
     rs.close();
    
   } catch (Exception e) {
    
    e.printStackTrace();
    
   } finally {
    
    rs = null;
    
   }
   
  } // end of if
  
  if (stmt != null) {
   
   try {
    
    if (!stmt.isClosed())
     stmt.close();
    
   } catch (Exception e) {
    
    e.printStackTrace();
    
   } finally {
    stmt = null;
   }
   
  } // end of if
  
  if (conn != null) {
   
   try {
    
    if (!conn.isClosed())
     conn.close();
    
   } catch (Exception e) {
    
    e.printStackTrace();
    
   } finally {
    
    conn = null;
    
   }
   
  } // end of if
    
 }

}



파일명: JDBCUtil.java


[첨부(Attachments)]

JDBCUtil.zip

AccountVO.zip




8. MyDataSourceFactory.java(com.website.example.common)


DataSourceFactory이다.



package com.website.example.common;

import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import com.mysql.cj.jdbc.MysqlDataSource;

import oracle.jdbc.pool.OracleDataSource;

public class MyDataSourceFactory {
 
 private InputStream is = null;
 
 public MyDataSourceFactory()  {
  
        String resource = "db.properties";
        is = getClass().getClassLoader().getResourceAsStream(resource);
 }
 
 public DataSource getMySQLDataSource() {
  
        Properties props = new Properties();
       
        MysqlDataSource mysqlDS = null;
       
        try {
         
            props.load(is);
            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;
       
    }
    
    public DataSource getOracleDataSource(){
     
        Properties props = new Properties();
        OracleDataSource oracleDS = null;
       
        try {
         
            props.load(is);
            oracleDS = new OracleDataSource();
            oracleDS.setURL(props.getProperty("ORACLE_DB_URL"));
            oracleDS.setUser(props.getProperty("ORACLE_DB_USERNAME"));
            oracleDS.setPassword(props.getProperty("ORACLE_DB_PASSWORD"));
           
        } catch (IOException e) {
         
            e.printStackTrace();
           
        } catch (SQLException e) {
         
            e.printStackTrace();
           
        }
       
        return oracleDS;
       
    }

}


파일명: MyDataSourceFactory.java


[첨부(Attachments)]

MyDataSourceFactory.zip


JDBCUtil.zip

AccountVO.zip



9. AccountDAO.java (com.website.example.dao)


AccountDAO에 대한 명세이다. DAO는 Data Access Object의 약자이다.


package com.website.example.dao;

import java.sql.SQLException;

import com.website.example.vo.AccountVO;

public interface AccountDAO {

 // 계좌 생성
 public void create(AccountVO vo) throws SQLException;
 
 // 잔액 조회
 public int getBalance(String name) throws SQLException;
 
 // 플러스 계좌
 public void plus(String name, int money) throws SQLException;
 
 // 마이너스 계좌
 public void minus(String name, int money) throws SQLException;
 
 // 거래
 public void transfer(String sender, String receiver, int money) throws SQLException;
 
}


파일명: AccountDAO.java


[첨부(Attachments)]

AccountDAO.zip


JDBCUtil.zip

AccountVO.zip



10. AccountDAOImpl.java (com.website.example.dao)


AccountDAO에 대한 명세이다. DAO는 Data Access Object의 약자이다.


package com.website.example.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.website.example.common.JDBCUtil;
import com.website.example.vo.AccountVO;

// Transaction - 자바
public class AccountDAOImpl implements AccountDAO {


 private final String CREATE_ACCOUNT = "insert into account_tbl" +
        "(name, balance, regidate) values(?, ?, ?)";
 
 private final String SELECT_BALANCE = "select * from account_tbl where name = ?";
 
 private final String UPDATE_MINUS = "update account_tbl set balance = (select balance from account_tbl where name = ?) - ? " +
          "where name = ?";
 
 private final String UPDATE_PLUS = "update account_tbl set balance = (select balance from account_tbl where name = ?) + ? " +
            "where name = ?";
 
 private DataSource ds = null;
 
 public AccountDAOImpl(DataSource ds) {
       this.ds = ds;
 }
 
 // 단일 쿼리에서의 트랜젝션 방법
 @Override
 public void create(AccountVO vo) throws SQLException {


       Connection conn = ds.getConnection();
       PreparedStatement pstmt = null;
  
  try {
   conn.setAutoCommit(false); // 트랜젝션 시작
   
   pstmt = conn.prepareStatement(CREATE_ACCOUNT);
   pstmt.setString(1, vo.getName());
   pstmt.setInt(2, vo.getBalance());
   pstmt.setTimestamp(3, vo.getRegidate());
   
   pstmt.executeUpdate();
   
   conn.commit();
   
  }catch(SQLException e) {
   
   conn.rollback();
   e.getMessage();
   
  }finally {
   JDBCUtil.close(pstmt, conn);
  }
  
 }

 @Override
 public int getBalance(String name) throws SQLException {
  
  Connection conn = ds.getConnection();
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  
  int result = 0;
  
  try {
        conn.setAutoCommit(false); // 트랜젝션 시작
        pstmt = conn.prepareStatement(SELECT_BALANCE);
   
   pstmt.setString(1, name);
   
   rs = pstmt.executeQuery();
   
   if ( rs.next() ) {
         result = rs.getInt(3);
   }
   
   conn.commit();
   
  }catch(SQLException e) {
   
   conn.rollback();
   e.getMessage();
   
  }finally {
   JDBCUtil.close(pstmt, conn);
  }
  
  return result;
 }

 @Override
 public void plus(String name, int money) throws SQLException {


      Connection conn = ds.getConnection();
      PreparedStatement pstmt = null;
  
  try {
   
   conn.setAutoCommit(false);
   
   // plus, minus 다 확인 후에 commit처리 해야 함.
   // 그래서 지금 바로 트랜젝션을 구현하면 안 됨
   pstmt = conn.prepareStatement(UPDATE_PLUS);
   pstmt.setString(1, name);
   pstmt.setInt(2, money);
   pstmt.setString(3, name);
   
   pstmt.executeUpdate();
      System.out.println(money);

   conn.commit();
   
  }catch(SQLException e) {
   System.out.println(e.getMessage());
   conn.rollback();
   
  }finally {
   JDBCUtil.close(pstmt, conn);
  }
  
 }

 @Override
 public void minus(String name, int money) throws SQLException {
  

       Connection conn = ds.getConnection();
       PreparedStatement pstmt = null;
  
  try {
   
   conn.setAutoCommit(false);

      // 예외 발생시키기(트랜젝션 의도적 발생)
      if(true){
             throw new SQLException(); // 의도적 예외 발생
       }
        
   // plus, minus 다 확인 후에 commit처리 해야 함.
   // 그래서 지금 바로 트랜젝션을 구현하면 안 됨
   pstmt = conn.prepareStatement(UPDATE_MINUS);
   pstmt.setString(1, name);
   pstmt.setInt(2, money);
   pstmt.setString(3, name);
   
   pstmt.executeUpdate();
   
   conn.commit();
   
  }catch(SQLException e) {
   
        conn.rollback();
        System.out.println(e.getMessage());
    
  }finally {
        JDBCUtil.close(pstmt, conn);
  }
  
  
 }

 @Override
 public void transfer(String sender, String receiver, int money) throws SQLException {

  Connection conn = ds.getConnection();
  PreparedStatement pstmt = null;
  
  try {
   
   conn.setAutoCommit(false);

   /*
      // 예외 발생시키기(트랜젝션 의도적 발생)
      if(true){
       throw new SQLException(); // 의도적 예외 발생
         }
         */
        
   // plus, minus 다 확인 후에 commit처리 해야 함.
   // 그래서 지금 바로 트랜젝션을 구현하면 안 됨
   pstmt = conn.prepareStatement(UPDATE_MINUS);
   
   // 주는 분
   pstmt.setString(1, sender);
   pstmt.setInt(2, money);
   pstmt.setString(3, sender);
   
   pstmt.executeUpdate();
   
   // 받는 분
   pstmt = conn.prepareStatement(UPDATE_PLUS);
   pstmt.setString(1, receiver);
   pstmt.setInt(2, money);
   pstmt.setString(3, receiver);
   
   pstmt.executeUpdate();
   
        conn.commit();
   
  }catch(SQLException e) {
   
        conn.rollback();
        System.out.println(e.getMessage());
   
  }finally {
       JDBCUtil.close(pstmt, conn);
  }
  
 }

}


파일명: AccountDAOImpl.java


[첨부(Attachments)]

AccountDAOImpl.zip



JDBCUtil.zip

AccountVO.zip



11. AccountService.java (com.website.example.service)


AccountService에 대한 명세이다.

서비스에 대한 정의이다. DB를 정의하는 영역은 아니다.

하지만, Spring Framework로 구현할 때, Spring JDBC 등을 적용하여 트랜젝션 동기화 기능을 구현부에 구현하면, Connection을 사용할 수도 있다.

질의문을 정의하는 영역은 아니다.


package com.website.example.service;

import java.sql.SQLException;

import com.website.example.vo.AccountVO;


public interface AccountService {
 
     public void accountCreate(AccountVO vo) throws SQLException;
     public void accountTransfer(String sender, String receiver, int money) throws SQLException;
 
}


파일명: AccountService.java


[첨부(Attachments)]

AccountService.zip



12. AccountServiceImpl.java (com.website.example.service)


AccountServiceImpl.java는 AccountService의 구현부이다.

인터페이스의 역할을 정의해보면, 하나의 통로와 같은 역할을 한다고 볼 수 있다.


package com.website.example.service;

import java.sql.SQLException;

import javax.sql.DataSource;

import com.website.example.dao.AccountDAO;
import com.website.example.dao.AccountDAOImpl;
import com.website.example.vo.AccountVO;

public class AccountServiceImpl implements AccountService {


     private AccountDAO accountDAO;
     private DataSource ds = null;
 
 public AccountServiceImpl(DataSource ds) {
  
        accountDAO = new AccountDAOImpl(ds);
        this.ds = ds;
 }

 @Override
 public void accountCreate(AccountVO vo) throws SQLException {
  
        accountDAO.create(vo);
  
 }
 
    public void accountTransfer(String sender, String receiver, int money) throws SQLException{
       
     int balance = accountDAO.getBalance(sender); // 보내는 사람 잔액 체크
     
        if(balance >= money){ // 보내는 돈이 잔액보다 많으면
 
                   accountDAO.transfer(sender, receiver, money);
         
        } else{
                   System.out.println("돈 없음");
                   //throw new NoMoneyException();
        }
       
    }

 
}


파일명: AccountServiceImpl.java


[첨부(Attachments)]

AccountServiceImpl.zip




13. TestMain.java (com.website.example.unit)


JUnit의 태스트 영역이다.


package com.website.example.unit;

import static org.junit.jupiter.api.Assertions.*;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.jupiter.api.Test;

import com.website.example.common.MyDataSourceFactory;
import com.website.example.service.AccountService;
import com.website.example.service.AccountServiceImpl;
import com.website.example.vo.AccountVO;

class TestMain {


       @Test
       void test() throws SQLException {
   
                 DataSource ds = new MyDataSourceFactory().getOracleDataSource();
                 AccountService service = new AccountServiceImpl(ds);
  
  // 1. 계정 생성 (계정이 없는 경우라면, 주석 풀고 작업해보면 됨.
  /*
  AccountVO vo = new AccountVO();
  vo.setName("홍길동");
  vo.setBalance(10000);
  vo.setRegidate(Timestamp.valueOf("2020-10-01 10:30:00"));
  
  service.accountCreate(vo);

  vo.setName("홍길자");
  vo.setBalance(0);
  vo.setRegidate(Timestamp.valueOf("2020-10-04 23:20:00"));

  service.accountCreate(vo);
  */
  
  // 2. 금전 거래
  service.accountTransfer("홍길동", "홍길자", 500);
  
 }

}


파일명: TestMain.java


[첨부(Attachments)]

TestMain.zip




14. 태스트 해보기 - 결과


코드로 구현하여 태스트를 해봐도 좋을 듯 싶다.



그림 3. 태스트 하기



그림 4. 태스트 하기


트랜젝션을 한번 해보면, 무슨 일이 일어나는지 구경을 조금해보면 좋을 듯 싶다.




15. 맺음글(Conclusion)


setAutoCommit(), conn.commit(), conn.rollback() 사소해보이는 이 코드가 반응하는 것을 관찰해보면, 트랜젝션이 중요하다는 사실을 알 수 있다.



* 참고자료(References)


1. JDBC 트랜젝션 동기화, https://joont.tistory.com/158, Accessed by 2020-10-09, Last Modified 2016-07-11.

-> 추천(50점): 정말 잘 설명해주고 있다.

2. Data Access - Transaction, https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#transaction, Accessed by 2020-10-09, Last Modified 2020-09-15.


3. 

반응형
728x90
300x250

[JSP] 26. JSP/Servlet - InvocationHandler와 Proxy를 이용하여 관점 구현하기


Spring Framework가 아닌 경우에는 AOP 프로그래밍과 같은 프로그래밍을 할 수 있는지 방법에 대해서 소개하려고 한다.

참고로 AOP는 Spring Framework 안에서만 동작한다.


5단계 관점은 아니어도, "전 단계", "핵심 결과" , "후 단계" 이렇게 구현하는 것은 가능하다.



* 관점 프로그래밍의 시작 배경


이전의 로직 구현 방법에 관한 것이다.



그림 1. 이전의 개발 로직 방법


그림 1의 방법은 현재에도 사용되고 있지만, 흔히 로직 하나 구현하면, 이렇게 매서드 내에 다 넣어보는 것이 일반적인 프로그래밍을 할 때 사용하는 방법이다.



그림 2. 문제 인식


문제는 공통 로직을 가지고도 요구사항이 시점에 따라서 달라질 수도 있다.

이럴 때 문제가 생길 수도 있다.




그림 3. Proxy 탈취방법 - 자바


그림 3처럼 핵심 메서드는 그대로 두고, 시점의 시야만 분리하여 프로그래밍을 하는 방법에 대해서도 생각해볼 수도 있다.

이 개념이 추후 Spring AOP에도 확장되어 적용이 된다. (3단계에서 5단계로 확장됨)




1. 결과


작업할 결과물의 결과이다.



그림 4. Proxy 구현으로 관점 프로그래밍



그림 5. 프로젝트 구성도



2. 프로젝트 생성하기


Maven Project로 작업하면 된다.



그림 6. 프로젝트 생성하기


File->New->Maven Project로 생성할 수 있다.




그림 7. 프로젝트 생성하기


org.apache.maven.archetypes    |  maven-archetype-webapp    | 1.4를 선택한다.

Next를 누른다.




그림 8. 프로젝트 생성하기


Group Id, Artifact Id를 입력한다.

Finish를 누른다.



3. Project의 Build Path, Project Factes


Project 선택한 후, 마우스 오른쪽 버튼을 눌러서 Properties에 들어간다.




그림 9. Build Path 설정하기


JRE System Library 버전을 JavaSE-14로 변경한다.




그림 10. Project Factes


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





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.webedu</groupId>

  <artifactId>proxy</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


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

  </dependencies>


  <build>

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




5. /src/main/webapp/index.jsp 수정


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

    pageEncoding="UTF-8"%>

<jsp:forward page="index.do" />


파일명: index.jsp


[첨부(Attachments)]

index.zip



6. /src/main/webapp/WEB-INF/views/index.jsp 만들기


폴더를 만들어줘야 한다. views 폴더

views 폴더 내에 index.jsp 파일도 생성해줘야 한다.


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

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

</head>

<body>


</body>

</html>


파일명: index.jsp


[첨부(Attachments)]

views-folder-index.zip




7. Servlet 만들기


패키지 경로: com.example.controller

서블릿 명: FrontController



8. 환경설정 - 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_4_0.xsd"

    version="4.0">


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

  <welcome-file-list>

   <welcome-file>index.jsp</welcome-file>

  </welcome-file-list>

  

  <servlet>

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

   <servlet-class>com.example.controller.FrontController</servlet-class>

   <init-param>

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

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

</init-param>

  </servlet>

  <servlet-mapping>

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

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

  </servlet-mapping>

</web-app>



파일명: web.xml


[첨부(Attachments)]

web.zip




9. Interface 만들기(Proxy 작업하려면 필수) - service/Calculator.java


인터페이스를 안 만들고, 클래스로 해버리면 오류 발생한다.


package com.example.service;


public interface Calculator {

public long sum();

}



파일명: Calculator.java


[첨부(Attachments)]

Calculator.zip




10. CalculatorImpl.java 만들기 (Calculator 인터페이스 적용함)


package com.example.service;


public class CalculatorImpl implements Calculator {


private long x;

private long y;

private long z;

public CalculatorImpl(long x, long y, long z) {

this.x = x;

this.y = y;

this.z = z;

}

public long sum() {

long result = x + y + z;

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

return result;

}

}



파일명: CalculatorImpl.java


[첨부(Attachments)]

CalculatorImpl.zip




11. Util - HttpUtil.java


package com.example.util;


import java.io.IOException;

import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class HttpUtil extends HttpServlet {


private static final long serialVersionUID = 1L;

public static void forward(HttpServletRequest req, HttpServletResponse res,

String path) throws ServletException, IOException {


try {

RequestDispatcher dispatcher = req.getRequestDispatcher(path);

dispatcher.forward(req, res);


}catch(Exception e) {

e.printStackTrace();

}

}

}


파일명: HttpUtil.java


[첨부(Attachments)]

HttpUtil.zip




12. Controller.java - Interface 만들기


package com.example.controller;


import java.io.IOException;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public interface Controller {


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

}



파일명: Controller.java


[첨부(Attachments)]

Controller.zip



13. FrontController.java - Servlet 수정하기(MVC2 패턴 - FrontController, Command 패턴 적용됨)


지금 작업에서는 실질적으로 Proxy를 다루는 방법에 대해서 정의할 것이다.


package com.example.controller;


import java.io.IOException;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;


import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.example.service.Calculator;

import com.example.service.CalculatorImpl;

import com.example.util.HttpUtil;


/**

 * Servlet implementation class FrontController

 */

public class FrontController extends HttpServlet {

private static final long serialVersionUID = 1L;

private String charset = null;

    

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

doAction(req, res, "GET");

}


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

doAction(req, res, "POST");

}


protected void doAction(HttpServletRequest req, 

HttpServletResponse res,

String flag) 

throws ServletException, IOException {

ServletConfig sc = this.getServletConfig();

charset = sc.getInitParameter("charset");


req.setAttribute("charset", charset);

req.setCharacterEncoding(charset);

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


String uri = req.getRequestURI();

String conPath = req.getContextPath();

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


Controller subController = null;


// GET 전송방식만

if(command.equals("/board/write.do") &&

flag.contentEquals("GET")) {

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

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

}

// POST 전송방식만

else if(command.equals("/board/write_result.do") && 

flag.contentEquals("POST")){

}

else if (command.equals("/index.do")){


System.out.println("index.do");

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

Calculator cal = new CalculatorImpl(1, 2, 3);

Calculator proxy  = (Calculator) Proxy.newProxyInstance(Calculator.class.getClassLoader(),

new Class[] { Calculator.class }, 

new InvocationHandler() {


@Override

public Object invoke(Object proxy, Method method, Object[] args) 

throws Throwable {

long start = System.currentTimeMillis();

System.out.println("시작:" + start );

Object result = method.invoke(cal, args);

Thread.sleep(200);

long end = System.currentTimeMillis();

System.out.println("종료:" + end );

return result;

}

}

);

long result = proxy.sum();

System.out.printf("proxy:%d\n", result);

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

}

}


}



파일명: FrontController.java


[첨부(Attachments)]

FrontController.zip


파란색 코드가 조금 어려울 것으로 보이나 몇 개 만들면, 마우스 가져다되면, unImplemented.... 이런 메시지가 올라오면서

하나 만들거냐고 뜬다.

그걸 잘 활용해야 코드 작성이 조금 수월할 것이다.




* 맺음글(Conclusion)


매우 간단한 형태로 자바 프록시 사용방법에 대해서 소개하였다.

일반 Java 프로젝트에서도 동일하게 사용가능하다.


공용 패키지를 활용한 기능이기 때문이다.

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;


반응형
728x90
300x250

[JSP] 25. jQuery와 Ajax 멀티 파일 업로드(개선), POST전송, JSON - 구성하기(2)


1부에 이어서 계속 소개하도록 하겠다.


1. [JSP] 24. jQuery와 Ajax 멀티 파일 업로드(개선), POST전송, JSON - 구성하기(1), 2020-10-03

https://yyman.tistory.com/1445



12. jQuery 다운받기


https://jquery.com/download/


사이트에 접속한다.



그림 19. jQuery 다운로드 사이트 (2020-10-03 현재 모습)


이 글에서는 "Download the uncompressed development jQuery 3.5.1"을 사용하였다.



그림 20. jQuery 다운로드 위치


1단계: 프로젝트 폴더를 찾는다.

2단계: /src/main/webapp/에 들어간다.

3단계: js폴더를 만든다.

4단계: /src/main/webapp/js/jquery-3.5.1.js를 넣어준다.




13. Controller - /board/ListJSONController.java


경로: /src/main/java/com/example/web/controller/board/ListJSONController.java


package com.example.web.controller.board;


import java.io.IOException;

import java.io.PrintWriter;

import java.util.ArrayList;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.json.JSONArray;

import org.json.JSONObject;


import com.example.web.controller.Controller;

import com.example.web.model.CompUsers;


public class ListJSONController implements Controller {


@Override

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

// 1. 공통 선언

res.setCharacterEncoding("UTF-8");

        res.setContentType("application/json");

        

        // 1-1. ArrayList만 사용할 경우의 반응(방법 1)

        /*

        //  컬렉션 타입

        ArrayList<CompUsers> list = new ArrayList<CompUsers>();

        list.add(new CompUsers("user","mole", 1));

        list.add(new CompUsers("sumin", "pass", 0));

        list.add(new CompUsers("smkim", "php", 1));

      

        PrintWriter out = res.getWriter();


        // 

        JSONObject jsonList = new JSONObject();

        JSONArray itemList = new JSONArray();

        

        jsonList.put("list", list);

        

        out.println(jsonList);

        */

        

        // 1-2. ArrayList와 itemList(JSONArray) 적용

        JSONObject jsonList = new JSONObject();

        JSONArray itemList = new JSONArray();

        

        CompUsers reqUser = new CompUsers();

        

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

        reqUser.setUsername(req.getParameter("username"));

        System.out.println("참" + reqUser.getUsername());

        }

        

        if ( req.getParameter("password") != null)

        reqUser.setPassword(req.getParameter("password"));

        

        if ( req.getParameter("enanbled") != null)

        reqUser.setEnabled(Integer.valueOf( req.getParameter("enabled")) );

        

        PrintWriter out = res.getWriter();


        ArrayList<CompUsers> list = new ArrayList<CompUsers>();

        list.add(new CompUsers("user","mole", 1));

        list.add(new CompUsers("sumin", "pass", 0));

        list.add(new CompUsers("smkim", "php", 1));

        

        for (CompUsers user:list) {

       

        JSONObject node = new JSONObject();

        node.put("enabled", user.getEnabled());

        node.put("password", user.getPassword());

        node.put("username", user.getUsername());


        itemList.put(node);

        

        }

        

        jsonList.put("list", itemList);

        jsonList.put("command", "바둑이");

        

        // DTO(또는 Model) 단독으로 입력불가

        // jsonList.put("paramUser", reqUser);

        ArrayList<CompUsers> list2 = new ArrayList<CompUsers>();

        list2.add(reqUser);

        //jsonList.put("paramUser", reqUser);

        jsonList.put("paramUser", list2);

        

        out.println(jsonList);

        

        out.flush();

        out.close();


}


}



파일명: ListJSONController.java


[첨부(Attachments)]

ListJSONController.zip




14. Controller - /board/MultiUploadController.java


경로: /src/main/java/com/example/web/controller/board/MultiUploadController.java


package com.example.web.controller.board;


import java.io.IOException;

import java.io.PrintWriter;

import java.util.List;

import java.util.Map;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.example.web.controller.Controller;

import com.example.web.util.HttpUtil;


public class MultiUploadController implements Controller {


@Override

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

HttpUtil.uploadFile(req, res);

/*

res.setCharacterEncoding("UTF-8");

        res.setContentType("application/json");

        

        @SuppressWarnings("unchecked")

List<Object> fileInfoList = (List<Object>) req.getAttribute("fileInfoList");

        @SuppressWarnings("unchecked")

List<String> reqInfoList = (List<String>) req.getAttribute("reqInfoList");

        

        // Model 구성해서 만들어도 무방

        HttpUtil.getFileinfoParser(fileInfoList, null);

        HttpUtil.getReqinfoParser(reqInfoList, null);

*/


res.setCharacterEncoding("UTF-8");

PrintWriter out = res.getWriter();

out.print("success");

out.flush();

out.close();

}


}



파일명: MultiUploadController.java


[첨부(Attachments)]

MultiUploadController.zip




14. View 화면 구성하기 - index.jsp (index.do 파일 시작페이지 만들기)


Index.jsp 파일을 시작페이지로 만드는 작업이다.


경로: /src/main/webapp/index.jsp


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

    pageEncoding="UTF-8"%>

<jsp:forward page="index.do" />


파일명: index.jsp


[첨부(Attachments)]

index.zip


FrontController.java 파일에 index.do를 command에서 식별할 수 있도록 해준다.

그리고 forward로 redirect처리하여 시작페이지로 보여지게 하는 원리이다.


-> 연계 작업: web.xml, FrontController.java 변경 작업을 해줘야 한다.



그림 21. index.jsp의 위치



15. View - /webapp/WEB-INF/views/index.jsp - 실제 시작 페이지


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


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

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

</head>

<body>


</body>

</html>


파일명: index.jsp


[첨부(Attachments)]

index.zip





16. Controller(Servlet) - FrontController


경로: /src/main/java/com/example/web/controller/FrontController.java


package com.example.web.controller;


import java.io.IOException;


import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.json.JSONArray;

import org.json.JSONObject;


import com.example.web.controller.board.InsertController;

import com.example.web.controller.board.ListJSONController;

import com.example.web.controller.board.MultiUploadController;

import com.example.web.util.HttpUtil;


public class FrontController extends HttpServlet {

private static final long serialVersionUID = 1L;

private String charset = null;

       

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

doAction(req, res, "GET");

}


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

doAction(req, res, "POST");

}


protected void doAction(HttpServletRequest req, 

HttpServletResponse res,

String flag) 

throws ServletException, IOException {

ServletConfig sc = this.getServletConfig();

charset = sc.getInitParameter("charset");


req.setAttribute("charset", charset);

req.setCharacterEncoding(charset);

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


String uri = req.getRequestURI();

String conPath = req.getContextPath();

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


Controller subController = null;


// GET 전송방식만

if(command.equals("/board/write.do") &&

flag.contentEquals("GET")) {

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

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

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

}

// POST 전송방식만

else if(command.equals("/board/write_result.do") && 

flag.contentEquals("POST")){


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

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

subController = new InsertController();

subController.execute(req, res);

}

else if(command.equals("/board/list_json.do") &&

flag.contentEquals("POST")) {

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

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

subController = new ListJSONController();

subController.execute(req, res);

}

else if(command.equals("/board/upload.do") &&

flag.contentEquals("POST")) {

System.out.println("multipart/form - upload");

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

subController = new MultiUploadController();

subController.execute(req, res);

}

else if (command.equals("/index.do")){


System.out.println("index.do");

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

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

}

}

}



파일명: FrontController.java


[첨부(Attachments)]

FrontController.zip





17. View - /board/insert.jsp


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


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

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>jQuery.post demo</title>

<script src="../js/jquery-3.5.1.js"></script>

<script>

$(document).ready(function(){


// 1. Ajax - Post 결과 출력

$( "#searchForm" ).submit(function( event ) {

 

  // Stop form from submitting normally

  event.preventDefault();

 

// Get some values from elements on the page:

  var $form = $( this ),

    term = $form.find( "input[name='s']" ).val(),

    url = $form.attr( "action" );

 

  // Send the data using post

  var posting = $.post( url, { s: term } );

 

  // Put the results in a div

  posting.done(function( data ) {

    alert( "Data Loaded: " + data );

    var content = data ;

    $( "#result1" ).html( content );

   

});

// Attach a submit handler to the form

});

// 2. Ajax 버튼(수작업 쿼리 - 보내기)

$('#check').click(function(){

    alert('특정 파라메터 보내기\n------------');

var query = {username:'한글', password:1234, enabled:1};

   

    $.ajax({

    url : "list_json.do",

    type : "POST",

    dataType : "json",

    data : jQuery.param(query),

    success : function(data) {

    $.each(data, function(key, value) { //  { logList:[{}], command:{} } 이런구조임


        //alert('성공');

    if (key == "list") {

       

    for (var i = 0; i < value.length; i++) {

       

    // alert(value[i].username);

   

    }

   

    } else if (key == "command") {

       

    $('#result2').html(value);

   

    }else if(key=="paramUser"){


// ArrayList로 받아서 처리함.

    alert(value[0].username + "/" + value.username);


// 인식 여부 (ArrayList로 안 하면, 알수없는 객체로 인식함)

/*

    for (var i = 0; i < value.length; i++) {

    alert(i + "/" + value[i].username);

    }

    */

        } // end of if

   

    });

   

    },

    error : function(msg) {

    alert("error" + msg);

    }

    });

   

});


// 4. 다중 업로드 기능

$(function(){

 

    $('#uploadBtn').on('click', function(){

        uploadFile();

    });

 

});

 

function uploadFile(){

    

    var form = $('#uploadForm')[0];

    var formData = new FormData(form);

 

    $.ajax({

        url : 'upload.do',

        type : 'POST',

        data : formData,

        contentType : false,

        processData : false,

    success : function(data) {

alert('성공');

alert(data);

    },

    error : function(msg) {

    alert("error" + msg);

    }

        

    }).done(function(data){

        callback(data);

    });

}

});

</script>

</head>

<body>

 

 <h3>Ajax - 전송</h3>

<form action="write_result.do" id="searchForm">

  <input type="text" name="s" placeholder="Search...">

  <input type="submit" value="Search">

</form>

<div id="result1"></div>


<h3>JSON 전송 확인(jQuery 미적용)</h3>

<form action="list_json.do" method="POST">

  <input type="text" name="keyword" placeholder="Search...">

  <input type="submit" value="Search">

</form>


<h3>JSON 가져오기(jQuery 적용)</h3>

<label for="userid">USER ID</label>

<input type="text" id="userid">

<button id="check">버튼 누르기</button>

<p id="result2"></p>


<h3>Ajax 기반 - 다중 업로드</h3>

<form id="uploadForm" enctype="multipart/form-data">

<input type="hidden" name="token" value="2">

<input type="text" name="usrID" size="10">

<input type="file" name="uploadFile" multiple>

    <button type="button" id="uploadBtn">Save</button>

</form>

 

</body>

</html>


파일명: insert.jsp


[첨부(Attachments)]

insert.zip




18. View - /board/result.jsp


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


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

    pageEncoding="UTF-8"%>

<%

String text = (String)request.getParameter("s");

%>

<%= text %>


파일명: result.jsp


[첨부(Attachments)]

result.zip




19. View - /board/uploadResult.jsp


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


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

    pageEncoding="UTF-8"%>

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

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>업로드 - 결과</title>

</head>

<body>

<h3>업로드 결과</h3>

<%


//Object name = request.getAttribute("usrID");

//Object login = request.getAttribute("login");

Object obj = request.getAttribute("reqMap");

Map<String, Object> map = null;

if(obj != null){

map = (HashMap<String, Object>)obj;

}


%>


<table style="width:700px;border:1px solid #e2e2e2;">

<tr>

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

<%

        out.println("name : " + map.get("usrID") + "<br />");

%>

</td>

<td style="width:20%;border-left:1px solid #e2e2e2;">

<%

out.println("login : " + map.get("usrPasswd") + "<br />");

%>

</td>

</tr>

<tr>

<td>

</td>

<td>

</td>

</tr>

</table>


</body>

</html>


파일명: uploadResult.jsp


[첨부(Attachments)]

uploadResult.zip





* 맺음글(Conclusion)


jQuery, Ajax, 멀티 파일 업로드, POST 전송, JSON 구성에 대해서 살펴보았다.



* 참고 자료(References)


1. jsp json 데이터 받기, https://happy-hs.tistory.com/16, Accessed by 2020-10-03, Last Modified 2018-09-20.

2. [Java] JSP - JSON 데이터 주고 받기 - JSONParser, https://kiwinam.com/posts/11/jsp-json-parser/, Accessed by 2020-10-03, Last Modified 2017-05-03.

3. jQuery.post() | jQuery API Documentation, https://api.jquery.com/jquery.post/, Accessed by 2020-10-03, Last Modified .

4. [Servlet] JSON 문자열로 응답하기, https://noritersand.github.io/servlet/servlet-json-%EB%AC%B8%EC%9E%90%EC%97%B4%EB%A1%9C-%EC%9D%91%EB%8B%B5%ED%95%98%EA%B8%B0/, Accessed by 2020-10-03, Last Modified 2014-01-14.

5. Java File Upload Example with Servlet, JSP and Apache Commons FileUpload, https://www.codejava.net/java-ee/servlet/apache-commons-fileupload-example-with-servlet-and-jsp, Accessed by 2020-10-03, Last Modified 2019-06-25.

반응형
728x90
300x250

[JSP] 24. jQuery와 Ajax 멀티 파일 업로드(개선), POST전송, JSON - 구성하기(1)


이번에 게시할 프로젝트는 jQuery, Ajax, 파일 업로드, POST전송, JSON 구성하기라는 거창한 제목이긴 하지만, 실제로는 기능별로 분리하여 작업한 결과이다.

이 글은 기존에 게시글에서 작성한 업로드 기능에 "토큰 인증 방식", "파라메터 문자열 분석 및 분리" 등의 기능을 추가하였다.

아무래도 업로드 기능이니깐 그냥 업로드 하는 것보다는 토큰 하나 넣어주는 게 좋지 않겠냐는 생각이다.


1. [JSP] 12. Jsp/Servlet(MVC) Maven 기반의 다중 파일 업로드, 다운로드 구현(1), 2020-09-24

https://yyman.tistory.com/1414

2. [JSP] 13. Jsp/Servlet(MVC) Maven 기반의 다중 파일 업로드, 다운로드 구현(2), 2020-09-24
https://yyman.tistory.com/1415

3. [JSP] 21. Jsp/Servlet(MVC) Maven 기반의 다중 업로드, 다운로드, 삭제 구현(1), 2020-10-01

https://yyman.tistory.com/1436




그림 1. COS(Servlet)


이거는 오래되서 미지원이다. (일부 인터넷 글에 따르면, 사용중이더라 이런 글들이 있는데 태스트를 해본 바로는 오류가 발생하고 안 된다.

(구체적으로 servlet 패키지에서 충돌남)


* IDE: Spring Tool-Suite 4.4 4-4.7.2. RELEASE (Eclipse)

* MVN(pom.xml)

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

   - json - 20200518 (https://mvnrepository.com/artifact/org.json/json)

   - commons-io - 2.8.0 (https://mvnrepository.com/artifact/commons-io/commons-io)

   - commons-fileupload - 1.4 (https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload)

* Javascript: jquery-3.5.1.js


DB 자체를 제거했으며, 이해를 돕기 위해서 매우 순수한 구조로 작성되었다.


자료구조에서 LinkedList에 해당하는 자바의 ArrayList와 Map를 파일 업로드 부분에 적용하였음.



1. 결과


이번에 만들 작업에 관한 결과이다. 결과를 보고 무엇을 만들지 생각하는 방법을 터득했으면 좋겠다.



그림 1. 작업 결과



그림 2. 작업 결과 - 출력된 HTML 소스(1)



그림 3. 작업 결과 - 출력된 HTML 소스(2)



그림 4. 작업 결과(2) - ListJSONController.java



그림 5. 작업결과(3) - 파일 업로드 기능(1)



그림 6. 작업결과(4) - 파일 업로드 기능(2)



그림 6-1. JSON - 결과(1)



그림 6-2. JSON - 결과(2)



그림 6-3. JSON - 결과(3)



그림 6-4. JSON - 결과(4)




2. 프로젝트 구성도


만들어야 할 프로그램들이다. 조금 양이 많다.



그림 7. 프로젝트 구성




3. 프로젝트 생성


프로젝트 생성하는 방법에 대해서 소개하도록 하겠다.



그림 8. 프로젝트 생성하기(1)


File을 누른다.

New-> Maven Project를 클릭한다.

(1단계 중략 - Next만 눌러도 되는 부분)



그림 9. 프로젝트 생성하기(2)


webapp를 검색한다.

org.apache.maven.archetypes    |  maven-archetype-webapp  1.4을 선택한다.

Next를 누른다.



그림 10. 프로젝트 생성하기(3)


Group Id와 Artifact Id를 입력한다.

Finish를 누른다.



4. 프로젝트 속성 - Build Path, Project Factes 설정하기


자바 버전을 변경할 것이다.



그림 11. 프로젝트 선택 후의 마우스 오른쪽 버튼 메뉴


프로젝트를 선택한 후, 마우스 오른쪽 버튼으로 클릭한다.

Properties를 클릭한다.



그림 12. Java Build Path


Java Build Path를 클릭한다.

JRE System Library 버전을 14로 바꿔준다. [Edit 클릭 -> JRE -> Java SE -14]




그림 13. Project Factes


Project Factes를 클릭한다.

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



5. pom.xml 수정하기


pom.xml 수정에 관한 것이다.


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


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

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

  <modelVersion>4.0.0</modelVersion>


  <groupId>com.webedu</groupId>

  <artifactId>exampleAjax</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


  <name>exampleAjax 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.json/json -->

<dependency>

    <groupId>org.json</groupId>

    <artifactId>json</artifactId>

    <version>20200518</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>

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

<dependency>

    <groupId>commons-fileupload</groupId>

    <artifactId>commons-fileupload</artifactId>

    <version>1.4</version>

</dependency>

  </dependencies>


  <build>

    <finalName>exampleAjax</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. Servlet 생성하기


서블렛 생성에 대한 것이다.



그림 14. Java Resources 폴더의 마우스 오른쪽 버튼 모습


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

New->Servlet을 클릭한다.



그림 15. Create Servlet


Java package를 입력해준다. (예: com.example.web.controller)

Class Name을 입력해준다. (예: FrontController)


Finish를 누른다.




7. Web.xml 수정하기


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


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

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

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

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

id="WebApp_ID" version="3.0">

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

  <welcome-file-list>

  <welcome-file>index.jsp</welcome-file>

  </welcome-file-list>

  <servlet>

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

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

  <init-param>

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

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

</init-param>

  </servlet>

  <servlet-mapping>

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

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

  </servlet-mapping>

</web-app>


파일명: web.xml


[첨부(Attachments)]

web.zip



8. Controller - Interface 생성하기


경로: /src/main/java/com/example/web/controller/Controller.java


package com.example.web.controller;


import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public interface Controller {


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


}




파일명: Controller.java


[첨부(Attachments)]

Controller.zip



9. Controller - board/InsertController.java


경로: /src/main/java/com/example/web/controller/board/InsertController.java


package com.example.web.controller.board;


import java.io.IOException;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.example.web.controller.Controller;

import com.example.web.util.HttpUtil;


public class InsertController implements Controller {


@Override

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

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


}


}


파일명: InsertController.java


[첨부(Attachments)]

InsertController.zip




10. Util - util/HttpUtil.java (업로드 개선 및 문자열 구분 처리)


토큰, 업로드 개선, 문자열 구분 처리 등을 추가적으로 담아보았다.


경로: /src/main/java/com/example/web/util/HttpUtil.java


package com.example.web.util;


import java.io.File;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;


import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import org.apache.commons.fileupload.servlet.ServletFileUpload;


public class HttpUtil extends HttpServlet {


private static final long serialVersionUID = 1L;


private static String charset = null; // 문자열


    private static final int MEMORY_THRESHOLD   = 1024 * 1024 * 3;  // 3MB // 

    private static final long MAX_FILE_SIZE      = 1024 * 1024 * 40; // 40MB

    private static final long MAX_REQUEST_SIZE   = 1024 * 1024 * 50; // 50MB

 

private static String UPLOAD_FOLDER = "upload";

private static String UPLOAD_TMP_FOLDER = File.separator + "WEB-INF" + File.separator + "temp";

private static List<String> reqInfoList = null; // req 정보(MultiRequest) - 문맥 방식

private static List<Object> fileInfoList = null; // 다중 파일 지원 - 문맥 방식

private static Map<String, Object> reqInfoMap = null; // req 정보(MultiRequest) - Map 자료구조

private static Map<Integer, Map<String, Object>> fileInfoMap = null; // 다중 파일 지원 - Map 자료구조

private static boolean FILE_TOKEN_CHECK = false; // req 토큰 체크하기 

private static String FILE_AUTH_TOKEN_KEY = null; // req 인증키 추가

private static String FILE_RESTRICT_EXT = ".jpg.jpeg.bmp.png.gif.txt"; // 파일 확장자 제한

private static int reqNum = 0; // reqNum

private static int fileNum = 0; // fileNum


public static void forward(HttpServletRequest req, HttpServletResponse res,

String path) throws ServletException, IOException {


try {

RequestDispatcher dispatcher = req.getRequestDispatcher(path);

dispatcher.forward(req, res);


}catch(Exception e) {

e.printStackTrace();

}

}

public static void uploadFile(HttpServletRequest req, HttpServletResponse res) throws

ServletException, IOException {


reqInfoList = new ArrayList<String>();

fileInfoList = new ArrayList<Object>();


fileInfoMap = new HashMap<Integer, Map<String, Object>>(); 

reqInfoMap = new HashMap<>();

// 파일 인증키 인증 완료 후 업로드

List<FileItem> tmpItems = new ArrayList<FileItem>();

FILE_AUTH_TOKEN_KEY = "1";

reqNum = 1;

fileNum = 1;

    

    PrintWriter out = res.getWriter();

    //out.println("<HTML><HEAD><TITLE>Multipart Test</TITLE></HEAD><BODY>");

try {

        

        //디스크상의 프로젝트 실제 경로얻기

        //String contextRootPath = "c:" + File.separator + "upload";

String dirName = UPLOAD_FOLDER ; 

// String dirName = "upload"; 

String contextRootPath = req.getSession().getServletContext().getRealPath("/") + dirName;

        System.out.println("실제경로:" + contextRootPath);

        

        //1. 메모리나 파일로 업로드 파일 보관하는 FileItem의 Factory 설정

        DiskFileItemFactory diskFactory = new DiskFileItemFactory(); // 디스크 파일 아이템 공장

        diskFactory.setSizeThreshold(MEMORY_THRESHOLD); // 업로드시 사용할 임시 메모리

        // diskFactory.setSizeThreshold(4096); // 업로드시 사용할 임시 메모리

        diskFactory.setRepository(new File(contextRootPath + UPLOAD_TMP_FOLDER)); // 임시저장폴더

        // diskFactory.setRepository(new File(contextRootPath + UPLOAD_TMP_FOLDER)); // 임시저장폴더

        

        //2. 업로드 요청을 처리하는 ServletFileUpload생성

        ServletFileUpload upload = new ServletFileUpload(diskFactory);

        // upload.setSizeMax(3 * 1024 * 1024); //3MB : 전체 최대 업로드 파일 크기

        upload.setSizeMax(MAX_REQUEST_SIZE);

        

        // sets maximum size of upload file(파일 단위 업로드 크기)

        upload.setFileSizeMax(MAX_FILE_SIZE);

        

        //3. 업로드 요청파싱해서 FileItem 목록구함​​

        List<FileItem> items = upload.parseRequest(req); 

        Iterator<FileItem> iter = items.iterator(); //반복자(Iterator)로 받기​            

        while(iter.hasNext()) { //반목문으로 처리​    

            FileItem item = (FileItem) iter.next(); //아이템 얻기

             //4. FileItem이 폼 입력 항목인지 여부에 따라 알맞은 처리

            

            if(item.isFormField()){ 

            //파일이 아닌경우

                processFormField(out, item);

                

            } else {

            //파일인 경우

            // System.out.println("오류:" + item.getName());

           

            // 버그 개선 item 이름값 비어있을 때

            if ( item.getName() != "") {

            tmpItems.add(item);

            // processUploadFile(out, item, contextRootPath);

            }

            // System.out.println("오류2:");

            }

        }

        

        // 파일 토큰 확인될 경우

        if ( FILE_TOKEN_CHECK ) {

       

        // 파일 업로드 처리

        for (FileItem readyItem: tmpItems)

        {

        processUploadFile(out, readyItem, contextRootPath);

        }

       

        }

        

        

        

    } catch(Exception e) {

        e.printStackTrace(out);

    }

//out.println( "usrID(Map): " + reqMap.get("usrID") );

//out.println( "usrPasswd(Map):" + reqMap.get("usrPasswd") );

    

    // out.println("</BODY></HTML>");

// req.setAttribute("usrID", reqMap.get("usrID"));

// req.setAttribute("login", 1);//Object Type으로 넘어감

    req.setAttribute("reqInfoMap", reqInfoMap);

    req.setAttribute("fileInfoMap", fileInfoMap);

    req.setAttribute("reqInfoList", reqInfoList);

    req.setAttribute("fileInfoList", fileInfoList);

    

// System.out.println("오류3:" + reqMap.get("usrID"));

    

}

//업로드한 정보가 파일인경우 처리

private static void processUploadFile(PrintWriter out, FileItem item, String contextRootPath)

throws Exception {

Map<String, Object> fileMapNode = new HashMap<String, Object>();

List<String> fileListNode = new ArrayList<String>();

boolean resultUpload = false;

String dirName = UPLOAD_FOLDER ; 

String name = item.getFieldName(); // 파일의 필드 이름 얻기

String fileName = item.getName(); // 파일명 얻기

// 임시 - 실제 원본 이름 추출

File originalFile = new File(fileName);

String originalFileName = originalFile.getName();

System.out.println("임시:" + originalFileName );

String contentType = item.getContentType(); // 컨텐츠 타입 얻기

long fileSize = item.getSize(); // 파일의 크기 얻기

// 업로드 파일명을 현재시간으로 변경후 저장

String fileExt = fileName.substring(fileName.lastIndexOf("."));

String uploadedFileName = System.currentTimeMillis() + ""; 

System.out.println(fileExt);

System.out.println(uploadedFileName);

// 저장할 절대 경로로 파일 객체 생성

String realUploadFile = File.separator + dirName + File.separator + uploadedFileName;

System.out.println("실제 저장직전폴더:" + contextRootPath + realUploadFile);

File uploadedFile = new File(contextRootPath + realUploadFile);

if ( FILE_RESTRICT_EXT.contains(fileExt.toLowerCase()) ) {

item.write(uploadedFile); // 파일 저장

resultUpload = true; // 파일 업로드 완료

}

//========== 뷰단에 출력 =========//

//out.println("<P>");

//out.println("파라미터 이름:" + name + "<BR>");

//out.println("파일 이름:" + fileName + "<BR>");

//out.println("콘텐츠 타입:" + contentType + "<BR>");

//out.println("파일 사이즈:" + fileSize + "<BR>");

//확장자가 이미지인겨우 이미지 출력

/*

if(".jpg.jpeg.bmp.png.gif".contains(fileExt.toLowerCase())) {

out.println("<IMG SRC='upload/" 

+ uploadedFileName 

+ "' width='300'><BR>");

}

*/

// out.println("</P>");

// out.println("<HR>");

// out.println("실제저장경로 : "+uploadedFile.getPath()+"<BR>");

// out.println("<HR>");

// 파일 전송이 완료되었을 때

if ( resultUpload == true ) {

// 파일 정보(Map 자료구조 방식)

fileMapNode.put("name", name);

fileMapNode.put("fileName", originalFileName);

fileMapNode.put("contentType", contentType);

fileMapNode.put("fileSize", fileSize);

fileMapNode.put("fileExt", fileExt);

fileMapNode.put("uploadedFileName", uploadedFileName);

fileMapNode.put("realName", uploadedFile.getName());

fileMapNode.put("realPath", uploadedFile.getPath());

// 파일 정보(문자열 구분 방식)

fileListNode.add( "id:" + fileNum + ",name:name,value:" + name + "/" );

fileListNode.add( "id:" + fileNum + ",name:filename,value:" + originalFileName + "/" );

fileListNode.add( "id:" + fileNum + ",name:contentType,value:" + contentType + "/" );

fileListNode.add( "id:" + fileNum + ",name:fileSize,value:" + fileSize + "/" );

fileListNode.add( "id:" + fileNum + ",name:fileExt,value:" + fileExt + "/" );

fileListNode.add( "id:" + fileNum + ",name:uploadedFileName,value:" + uploadedFileName + "/" );

fileListNode.add( "id:" + fileNum + ",name:realName,value:" + uploadedFile.getName() + "/" );

fileListNode.add( "id:" + fileNum + ",name:realPath,value:" + uploadedFile.getPath() + "/" );

fileInfoList.add(fileListNode);

fileNum++;

}

}

private static void processFormField(PrintWriter out, FileItem item) 

throws Exception{

String name = item.getFieldName(); //필드명 얻기

Object value = item.getString("UTF-8"); //UTF-8형식으로 필드에 대한 값읽기

//out.println(name + ":" + value + "<BR>"); //출력

// 파일 토큰 인증 여부

if ( name.contentEquals("token")

&& value.equals(FILE_AUTH_TOKEN_KEY) ) {

System.out.println("참 - 인증");

FILE_TOKEN_CHECK = true;

}

// Map 자료구조 저장

reqInfoMap.put(name, value);

// 문자열 구문 저장 - 문자열 검색원리 적용 (검색 기법 적용)

reqInfoList.add( "id:" + reqNum + ",name:" + name + ",value:" + value + "/" );

reqNum++;

}

// FileInfoList 내용 - 문맥 문석기(임시)

public static void getFileinfoParser(List<Object> fileParser, String tarName) {

// 분석 시작

if ( fileParser != null ) {

for ( Object fileNode : fileParser ) {

@SuppressWarnings("unchecked")

List<String> sep = (List<String>) fileNode;

// 문자열 분석 반환 받기 (id = 0, name = 1, value = 2)

Object result = getFileAttrAnal(sep, tarName);

}

}

}


// FileInfoList 내용 - 문자열 구분

private static Object getFileAttrAnal(List<String> fileNode, String tarName) {

int pId = -1;

String pName = null;

Object pValue = null;

String trashTxt = null;

if ( fileNode != null) {

for ( String usrTxt : fileNode  ) {

trashTxt = usrTxt.substring(usrTxt.indexOf("id:") + 3, usrTxt.indexOf(",name") );

pId = Integer.valueOf(trashTxt);

// System.out.print("ID:" + pId);


trashTxt = usrTxt.substring(usrTxt.indexOf("name:") + 5, usrTxt.indexOf(",value") );

pName = trashTxt;

// System.out.print(",name:" + pName);

trashTxt = usrTxt.substring(usrTxt.indexOf("value:") + 6, usrTxt.indexOf("/") );

pValue = trashTxt;

// System.out.println(",value:" + pValue);

}

}

return null;

}


// ReqInfoList 내용 - 문맥 문석기(임시)

public static Object getReqinfoParser(List<String> reqNode, String tarName) {

int pId;

String pName ;

Object pValue ;

String trashTxt;

if ( reqNode != null) {

for ( String usrTxt : reqNode  ) {

trashTxt = usrTxt.substring(usrTxt.indexOf("id:") + 3, usrTxt.indexOf(",name") );

pId = Integer.valueOf(trashTxt);

System.out.print("ID:" + pId);


trashTxt = usrTxt.substring(usrTxt.indexOf("name:") + 5, usrTxt.indexOf(",value") );

pName = trashTxt;

System.out.print(",name:" + pName);

trashTxt = usrTxt.substring(usrTxt.indexOf("value:") + 6, usrTxt.indexOf("/") );

pValue = trashTxt;

System.out.println(",value:" + pValue);

}

}

return null;

}

}


파일명: HttpUtil.java


[첨부(Attachments)]

HttpUtil.zip




11. Model - CompUsers.java


모델은 DB의 테이블 설계를 생각해서 하는 것이 좋다고 본다. (꼭 그렇다는 건 아님.)


아래의 그림 16, 그림 17, 그림 18은 결국은 같은 Table에 대한 것이다.

하나를 바라보는 것이 다양할 수 있다는 이야기를 하는 것이다.



그림 16. Oracle SQL Developer - COMP_USERS (Tables)



그림 17. Oracle SQL Developer - COMP_USERS (Tables)



그림 18. Oracle SQL Developer - COMP_USERS (Tables)


비고: 이 글에서는 DB 설계는 하지 않았음.



경로: /src/main/java/com/example/web/model/CompUsers.java


package com.example.web.model;


public class CompUsers {


private String username;

private String password;

private int enabled;

public CompUsers(String username, String password, int enabled) {

this.username = username;

this.password = password;

this.enabled = enabled;

}


public CompUsers() {

}


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



* 2부에서는 Jquery 다운받기, JSON, MultiUploadController, View 화면, Index 페이지 구성에 대해서 소개하겠다.


1. [JSP] 25. jQuery와 Ajax 멀티 파일 업로드(개선), POST전송, JSON - 구성하기(2), 2020-10-03

https://yyman.tistory.com/1446


반응형
728x90
300x250

[JSP] 23(번외). JSP/Servlet - MVC2 index.do 시작페이지 만들기 (FrontController, Command패턴)



index.html이나 index.jsp 페이지처럼 시작페이지를 index.do로 할 수 없는지에 대한 글이다.




1. /src/main/webapp/index.jsp - 수정하기


<jsp:forward page="index.do" />를 넣어준다.



그림 1. index.jsp 수정하기


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

    pageEncoding="UTF-8"%>

<jsp:forward page="index.do" />


파일명: index.jsp



2. web.xml - 수정하기


web,xml에 <welcome-file-list><welcome-file>을 만들어준다.



그림 2. web.xml 수정하기


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

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

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

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

id="WebApp_ID" version="3.0">

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

  <welcome-file-list>

  <welcome-file>index.jsp</welcome-file>

  </welcome-file-list>

  <servlet>

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

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

  <init-param>

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

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

</init-param>

  </servlet>

  <servlet-mapping>

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

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

  </servlet-mapping>

</web-app>


파일명: web.xml


[첨부(Attachments)]

web.zip




3. FrontController.java - 수정하기


서블릿으로 작성한 FrontController.java를 수정해준다.



그림 3. FrontController.java


아래의 소스 코드는 HttpUtil.java에 관한 코드이다.


package com.example.web.util;


import java.io.IOException;


import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class HttpUtil extends HttpServlet {


private static final long serialVersionUID = 1L;


private static String charset = null;


public static void forward(HttpServletRequest req, HttpServletResponse res,

String path) throws ServletException, IOException {


try {

RequestDispatcher dispatcher = req.getRequestDispatcher(path);

dispatcher.forward(req, res);


}catch(Exception e) {

e.printStackTrace();

}

}

}


파일명: HttpUtil.java


[첨부(Attachments)]

HttpUtil.zip





* 맺음글(Conclusion)


간단한 형태로 시작페이지를 지정하는 방법에 대해서 소개하였다.

반응형
728x90
300x250

[JSP] 22. JSP/Servlet MVC2 - jQuery기반의 Ajax POST 전송 및 MVC패턴 Action 식별자


jQuery를 활용하는 방법에 대해서 소개하려고 한다.

그림 일기 수준으로 매우 편안한 마음으로 입문할 수 있는 학습 기반을 제공해주려고 한다.

심도적인 부분은 전문서적 등도 찾아보기도 하고, 검색도 많이 해보시면 좋을 듯 싶다. (변화가 워낙 빠른 분야인 만큼)



1. 결과


동적인 부분인 관계로 영상으로 올려주도록 하겠다.



영상 1. 출력 결과


jQuery가 어떤 결과물을 만들어 내는 도구인지 이해가 되었으면 하는 바램이다.

원래는 jQuery가 먼저 나온 것이 아니고, Javascript가 먼저이다.


그리고 2006년도에 약 Ajax라는 규격이 나왔는데, Javascript 파일 형태로 ajax 파일을 배포하여 동적인 처리에 대해서 접근하게 되었다.


그리고 조금 시간이 지나서 jQuery라는 게 나왔는데, 분명한 건 이건 표준은 아니다.

다만, 편하게 사용하도록 도와주는 오픈소스 진형의 library이다.




2. 프로젝트 생성하기


이러한 저차원 수준으로 작성한 이유는 프로그래밍에 겁먹지 말라는 것이다.



그림 1. 프로젝트 생성하기


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



그림 2. 프로젝트 생성하기


org.apache.maven.archetypes | maven-archetype-webapp를 선택한다.

Next를 클릭한다.


검색 키워드로 검색할 때, "webapp"로 하면, 조금 찾는데 시간이 절약될 수 있다.

다만, HDD 사용자는 조금 버벅될 가능성이 있다. (검색 기능이 매우 느림.)




그림 3. 프로젝트 생성하기


GroupId, Artifact Id를 적당히 입력한 후 Finish를 누른다.



3. Pom.xml - 설정하기


http://mvnrepository.com에 들어가서 "servlet"을 검색해서 최신 버전으로 해준다.

Maven Project를 아끼고 있는 이유는 정말 사용하기가 편리하다.


셋팅하는데, /src/main/webapp/WEB-INF/lib인가 폴더에 넣고, 프로젝트 속성에 들어가서 BuildPath 클릭하고 Add External Library 등록하고 

확인 몇 번하고 복잡했는데, Maven을 알게 되면서 많이 좋아진 것 같다.



그림 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.webedu</groupId>

  <artifactId>exampleAjax</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


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

  </dependencies>


  <build>

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




4. Project Factes와 Build Path - 자바 버전 바꿔주기


자바 버전을 변경해줘야 한다. Maven Project 초기 셋팅이 현재 1.6으로 잡혀서 생성되기 때문이다.



그림 5. 프로젝트의 오른쪽 메뉴 모습


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

Properties를 클릭한다.



그림 6. Build-Path


JRE System Library [JavaSE-14]로 바꿔준다.

Edit 버튼을 누르면 바꿀 수 있다.



그림 7. Project Factes


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




5. jQuery 사이트 - 접속하기


인터넷 웹 브라우저를 켠다.


그림 8. 윈도우 10 - 엣지 클릭하기


웹 브라우저 아이콘을 못 찾는 경우에는 그림처럼 생긴 거 클릭하면 된다. 

(그 옆에도 비슷하게 생긴 e자 아이콘을 클릭해도 무방하다.)



그림 11. jQuery 웹 사이트 접속하기


https://jquery.com/download


링크를 웹 주소창에 입력해서 접속한다.

또는 클릭해도 무방하다.


표기해놓은 것 5개 중 하나만 잘 다운로드 받으면 된다.




그림 12. jQuery 다운받기


문서 클릭\workspace-spring-tool-suite-4-4.7.2.RELEASE\{프로젝트명}\src\main\webapp\js에 저장해준다.

js폴더가 없으니깐 하나 만들어준다.

js폴더 안에 저장해준다.



영상 2. jQuery 다운로드 받는 모습



6. jQuery - ajaxPost - API 접속하기


https://api.jquery.com/jquery.post/


사이트에 접속해준다.



그림 13. jQuery 예제


이렇게 생긴 HTML태그를 복사하여 Eclipse에 옮겨갈 것이다.

참고로 이 코드가 완벽한 코드는 절대 아니다. (태스트 해 봤음.)




그림 14. index.jsp 파일에 복사 붙여넣기 해주기


그림 14와는 다르게 태스트를 완료한 코드는 아래에 있으니 참고하면 되겠다.

WEB-INF내에 views폴더 생성해준다.

그리고 index.jsp 파일을 views 폴더 안으로 이동해준다.



영상 3. views 폴더 생성 방법 및 파일 이동 시키기



그림 15. 이동을 완료한 모습 - views 폴더 내용


<!doctype html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>jQuery.post demo</title>

<script src="js/jquery-3.5.1.js"></script>


</head>

<body>

 

<form action="board/insert.do" id="searchForm">

  <input type="text" name="s" placeholder="Search...">

  <input type="submit" value="Search">

</form>

<div id="result"></div>


<script type="text/javascript">

// Attach a submit handler to the form

$( "#searchForm" ).submit(function( event ) {

 

  // Stop form from submitting normally

  event.preventDefault();

 

// Get some values from elements on the page:

  var $form = $( this ),

    term = $form.find( "input[name='s']" ).val(),

    url = $form.attr( "action" );

 

  // Send the data using post

  var posting = $.post( url, { s: term } );

 

  // Put the results in a div

  posting.done(function( data ) {

    alert( "Data Loaded: " + data );

    var content = data ;

    $( "#result" ).html( content );

   

  });

 

});


</script>

<!-- the result of the search will be rendered inside this div --> 

 

</body>

</html>


파일명: index.jsp


[첨부(Attachments)]

index.zip




7. Servlet 작성하기


MVC2 패턴을 만들거니깐 서블렛을 잘 따라 해야 한다.



그림 16. Java Resources 폴더 - 마우스 오른쪽 버튼 메뉴 모습


Java Resources 폴더를 선택한 후, 마우스 오른쪽 버튼으로 클릭한다.

New-> Servlet을 클릭한다.



그림 17. Servlet 생성 작업창 - 모습 (Create Servlet)


Java Package명을 입력한다. (예: com.example.web.controller)

Class Name명을 입력한다. (예: FrontController)


Finish를 누른다.



8. web.xml 파일 - 수정작업하기


경로 위치: /src/main/webapp/WEB-INF/web.xml


문자열하고, FrontController의 *.do로 변경 작업을 해주면 된다.



그림 18. web.xml - 수정작업하기


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

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

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

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

id="WebApp_ID" version="3.0">

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

  <servlet>

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

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

  <init-param>

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

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

</init-param>

  </servlet>

  <servlet-mapping>

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

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

  </servlet-mapping>

</web-app>



파일명: web.xml


[첨부(Attachments)]

web.zip




9. Class 만들기 - HttpUtil


HttpUtil 클래스를 만들어주려고 한다.



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


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

New->Class를 클릭한다.



그림 20. 클래스 생성 마법사 모습


Package명은 com.example.web.util

Name은 HttpUtil로 한다.


Finish를 누른다.





그림 21. 코드를 입력한 모습 - HttpUtil.java


package com.example.web.util;


import java.io.IOException;


import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class HttpUtil extends HttpServlet {


private static final long serialVersionUID = 1L;


private static String charset = null;


public static void forward(HttpServletRequest req, HttpServletResponse res,

String path) throws ServletException, IOException {


try {

RequestDispatcher dispatcher = req.getRequestDispatcher(path);

dispatcher.forward(req, res);


}catch(Exception e) {

e.printStackTrace();

}

}

}


파일명: HttpUtil.java


[첨부(Attachments)]

HttpUtil.zip



10. Controller - Interface 만들기


Controller 인터페이스를 하나 만들 것이다.



그림 22. Controller.java


package com.example.web.controller;


import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public interface Controller {


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


}




파일명: Controller.java


[첨부(Attachments)]

Controller.zip



11. InsertController.java - Class


앞서 만든 Interface(Controller)로 InsertController.java를 작성할 것이다.



그림 23. InsertController.java


Package 명은 com.example.web.board라고 입력한다.

Name명은 InsertController라고 입력한다.


Interfaces의 Add버튼을 누른다.



그림 24. Implemented Interfaces.......


Controller를 입력한 후 작성한 Controller 인터페이스를 선탁한다.

OK를 누른다.

Finish를 누른다.


package com.example.web.controller.board;


import java.io.IOException;


import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.example.web.controller.Controller;

import com.example.web.util.HttpUtil;


public class InsertController implements Controller {


@Override

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

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


}


}



파일명: InsertController.java


[첨부(Attachments)]

InsertController.zip



13. FrontController - 코드 작성하기 (수정)


코드를 자세히 보면, flag가 추가되었다.

doAction에서 POST, GET 등을 인식할 수 있게 되었다.


package com.example.web.controller;


import java.io.IOException;


import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.example.web.controller.board.InsertController;

import com.example.web.util.HttpUtil;


public class FrontController extends HttpServlet {

private static final long serialVersionUID = 1L;

private String charset = null;

       

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

doAction(req, res, "GET");

}


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

       doAction(req, res, "POST");

}


protected void doAction(HttpServletRequest req, 

HttpServletResponse res,

String flag) 

throws ServletException, IOException {

ServletConfig sc = this.getServletConfig();

charset = sc.getInitParameter("charset");


req.setAttribute("charset", charset);

req.setCharacterEncoding(charset);

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


String uri = req.getRequestURI();

String conPath = req.getContextPath();

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


Controller subController = null;


// POST 전송방식만

if(command.equals("/board/insert.do") && 

flag.contentEquals("POST")){


System.out.println("insert");

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

subController = new InsertController();

subController.execute(req, res);

}else if (command.equals("/index.do")){

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

}

}

}



파일명: FrontController.java


[첨부(Attachments)]

FrontController.zip



14. View - webapp/WEB-INF/views/board/insert.jsp


POST처리 후에 출력할 페이지를 작성하도록 하겠다.

PrintWriter out으로 해도 무방하지만, MVC패턴을 적용했으니 뷰 파일에서 작성하겠다.


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

    pageEncoding="UTF-8"%>

<%

String text = (String)request.getParameter("s");

%>

<%= text %>


파일명: insert.jsp


[첨부(Attachments)]

insert.zip



* 맺음글(Conclusion)


jQuery를 통해서 ajax 전송에 대해서 간단한 형태로 살펴보았다.

반응형

+ Recent posts