728x90
300x250

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

 

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

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

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

 

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

1. 소개

전자식 연구노트이다. 

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

 

package com.stream.digitalnote.dto;

public class MemberDTO {

          private String id;
          private String uuid;

          private String email;
          private String passwd;

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

          private String regidate;

          public String getId() {
                    return id;
          }

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

          public String getUuid() {
                    return uuid;
          }

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

          public String getEmail() {
                    return email;
          }

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

          public String getPasswd() {
                    return passwd;
          }

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

          public String getLevel() {
                    return level;
          }

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

          public String getIpv4() {
                   return ipv4;
          }

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

          public String getIpv6() {
                    return ipv6;
          }

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

          public String getRegidate() {
                    return regidate;
          }

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

}
 

 


2. 첨부(Attachment)

210627_based_web_electronic_write_a_study.zip
0.73MB

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

 


3. 맺음글(Conclusion)

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

 


4. 참고자료(Reference)

1.

반응형
728x90
300x250

[GNU - 리눅스(Linux)] Apache Tomcat 9(아파치 톰캣9), 큐브리드 10.2(Cubrid 11), 전자정부 이클립스, 리눅스민트 20에서 연동하기


이번에 소개할 내용은 아파치 톰캣9, 큐브리드 10.2, 전자정부 이클립스, 리눅스민트 20을 연동하여 개발하는 환경을 설정하는 방법에 대해서 소개하겠다.



1. 전자정부 이클립스 설치 복습


설치 방법을 잊어버린 경우를 대비해서 잠시 소개하였다.


그림 1. 리눅스민트20, 전자정부 이클립스 설치 가이드(1)



그림 2. 리눅스민트20, 전자정부 이클립스 설치 가이드(1)



그림 3. 리눅스민트20, 전자정부 이클립스 설치 가이드(1)




2. 큐브리드 10.2(11)와 아파치 톰캣 9 연동하기


큐브리드와 아파치 톰캣 9를 연동하기 위해서 먼저 전자정부 이클립스를 실행하도록 하겠다.

그림 4. 리눅스민트20, 전자정부 이클립스 실행하기




그림 5. 리눅스민트20, 전자정부 이클립스 실행하기





그림 6. 리눅스민트20, 전자정부 이클립스 / 아파치 톰캣 9 환경설정 확인



4. 큐브리드 10.2(11)와 JSP-Dynamic Web Project 생성하기


프로젝트를 생성하여 큐브리드 JDBC와 JSP, Java를 연동하는 방법에 대해 소개하도록 하겠다.



그림 7. 리눅스민트20, 전자정부 이클립스에서 새 프로젝트 생성하기


그림 8. 리눅스민트20, 전자정부 이클립스에서 새 프로젝트 생성하기




그림 9. 리눅스민트20, 전자정부 이클립스에서 새 프로젝트 생성하기





5. 큐브리드 10.2(11) JDBC, 신규 생성한 JSP 프로젝트에 설치하기


앞에서 생성한 다이나믹 웹 프로젝트에 JDBC-11-0-latest-cubrid.jar 파일을 설치하도록 하겠다.

(2021-02-01 기준으로 JDBC-11-0-latest-cubrid.jar 파일이 최신 버전이다.)


그림 10. 리눅스민트20, 전자정부 이클립스와 큐브리드 JDBC 연동하기




6. 큐브리드 10.2(11), 이클립스 프로젝트 (Java, JSP 코드 작성하기)


큐브리드에 사용되는 Java, JSP코드를 작성하는 방법에 대해 소개하도록 하겠다.




그림 11. 큐브리드 소스코드


https://www.cubrid.org/getting_started 해당 링크에 접속하면 자세한 내용을 확인할 수 있다.



그림 12. 자바 코드 생성하기




그림 13. 자바 코드 생성하기




그림 14. 자바 코드 생성하기




그림 15. 자바 코드 생성하기




그림 16. JSP 코드 생성하기




7. 서버 - 배포하기


서버에 배포하는 방법에 대해 소개하도록 하겠다.



그림 17. 구동중인 큐브리드 DB서버 상태를 확인할 것 (2021-02-01)


그림 17처럼 큐브리드 DB서버 상태를 제일 먼저 확인해야 한다.



그림 18. 초록색 (재생)버튼 누르기 (Run On Server 버튼 찾아서 클릭)


톰캣 9.0 서버로 배포 태스트를 할 것이다.




그림 19. 빌드 결과 (2021-02-01)


정상적으로 동작한 것을 확인할 수 있다.



* 첨부(Attachment)


210201_LinuxMint20_Cubrid_10_2_eGovFramework_Eclipse_Cubrid_JDBC_guide.zip

[Apache Licence v2.0을 적용 받는다]



* 맺음글(Conclusion)


리눅스민트20과 전자정부 이클립스, 아파치 톰캣 9를 연동하는 방법에 대해서 소개하였다.



* 참고 자료(Reference)


1. CUBRID Foundation: Getting Started, https://www.cubrid.org/getting_started, Accessed by 2021-02-01, Last Modified 2021-02-01.

-> GNU/GPL v3 License로 배포하고 있음.

2. eGovFrame Portal 온라인 지원 포탈, https://www.egovframe.go.kr, Accessed by 2021-02-01, Last Modified 2021-02-01.

-> 전자정부 이클립스(미리 SVN 배포 기능, 각종 셋팅이 미리 다 되어 있음.) / 전자정부 프레임워크만 사용하지 않았음. 

    (스프링프레임워크의 "외부 접속" 의존성 문제)

-> Apache License v2.0로 배포하고 있음.

3. Main Page - Linux Mint, https://linuxmint.com, Accessed by 2021-02-01, Last Modified 2021-02-01.

-> GNU/GPL v3 License로 배포하고 있음.

4. Oracle VM VirtualBox, https://www.virtualbox.org, Accessed by 2021-02-01, Last Modified 2021-02-01.

-> GNU/GPL v3 License로 배포하고 있음.

5. Enabling Open Innovation & Collaboration | The Eclipse Foundation, https://www.eclipse.org, Accessed by 2021-02-01, Last Modified 2021-02-01

반응형
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
[Spring-Framework] 42. Spring Framework에서 (Jaxb-runtime, activation, Jaxb Api, JSTL)을 활용한 XML 생성하기


이번에 소개할 방법은 Spring Framework에서 Jaxb-runtime, activation, Jaxb Api, JSTL을 활용하여 XML을 생성하는 방법에 대해서 소개하겠다.


JSP/Servlet 방식하고는 차이가 있는 점이 있다면, @(어노테이션)을 사용할 것이다.


* IDE: Eclipse 2020-06
* Library: Maven Project / Spring Framework 4.2.4 Releases.

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

   javax.servlet 2.5

2. https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api

   jaxb-api 2.3.0-b170201.1204

3. https://mvnrepository.com/artifact/javax.activation/activation

   activation 1.1

4. https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime

   jaxb-runtime 2.3.0-b170127.1453

5. https://mvnrepository.com/artifact/javax.servlet/jstl

   jstl 1.2



1. 프로젝트 구성도


실제로는 코드가 몇 줄 되지는 않지만, 문제는 라이브러리 셋팅 등에서 오류를 많이 경험할 수 있다.



그림 1. 프로젝트 구성도




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



3. pom.xml

이 셋팅이 매우 무척 많이 중요하다.


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.website</groupId>
 <artifactId>example</artifactId>
 <name>Spring-XML-Jaxb</name>
 <packaging>war</packaging>
 <version>1.0.0-BUILD-SNAPSHOT</version>
 <properties>
  <java-version>1.8</java-version>
  <org.springframework-version>4.2.4.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 -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</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>
 
  <!-- 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>
 

  <!-- Test -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </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




4. HomeController.java (com.website.example)


package com.website.example;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

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

/**
 * Handles requests for the application home page.
 */

@Controller
public class HomeController {
 
 private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
 
 /**
  * Simply selects the home view to render by returning its name.
  */
 @RequestMapping(value = "/", method = RequestMethod.GET)
 public String home(Locale locale, Model model) {
  logger.info("Welcome home! The client locale is {}.", locale);
  
  Date date = new Date();
  DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
  
  String formattedDate = dateFormat.format(date);
  
  model.addAttribute("serverTime", formattedDate );
  
  return "home";
 }
 
         @RequestMapping(value = "/dataTransform", produces="application/xml")
         @ResponseBody
         public BoardListVO dataTransform(Locale locale, Model model) {

  
              List<BoardVO> boardList = new ArrayList<BoardVO>();
              BoardVO vo = new BoardVO();
             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 boardListVO = new BoardListVO();
            boardListVO.setBoardList(boardList);
  
            System.out.println("가동중");
  
             return boardListVO;
        }
  
}


파일명: HomeController.java


[첨부(Attachments)]

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

HomeController.zip



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



7. 출력 결과


스프링에서 출력한 XML이다.



그림 2. 출력 결과


BoardVO.zip

HomeController.zip



*음글(Conclsuion)


스프링 프레임워크로 Jaxb2 외 다수 라이브러리를 활용하여 XML을 생성하였다.



* 참고자료(References)


1. A Guide to JAXB Annotations - HowToDoInJava, https://howtodoinjava.com/jaxb/jaxb-annotations/, Accessed by 2020-10-11, Last Modified 2019-02.


2. [Java] JAXB 활용한 Java 객체의 XML 변환 방법, https://haenny.tistory.com/8, Accessed by 2020-10-11, Last Modified 2019-07-09.


반응형
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
[Spring Framework] 33. AOP(Aspect-Oriented-Programming) - XML 방식


XML 기반으로 작성된 AOP 구현 방법에 대해서 소개하려고 한다.

AOP의 관점에 대한 5가지 방식을 모두 적용해보았다.


[태스트 환경]

* IDE: Eclipse 2020-06

* Spring Framework 4.2.4.RELEASE
* Aspectjweaver 1.6.10
* Spring-aop 4.2.4.RELEASE
* JUnit 5




1. 프로젝트 구성도


프로젝트 구성도이다.



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




2. 프로젝트 생성


Spring Legacy Project로 프로젝트를 생성한다.

참고로 Spring MVC Project로 선택하고 생성해야 한다.



3. Build Path, Java Compiler, Project Factes 버전 맞춰주기


* Build Path: JRE 버전을 1.8로 변경해준다.
               - Add Library로 JUnit 5를 등록해준다.

* Java Compiler: Compiler compliance level - 1.8로 변경해준다.

* Project Factes: Java 버전을 1.8로 변경해준다.




4. POM.xml 설정하기


(중략)
 <properties>
  <java-version>1.8</java-version>
  <org.springframework-version>4.2.4.RELEASE</org.springframework-version>
  <org.aspectj-version>1.6.10</org.aspectj-version>
  <org.slf4j-version>1.6.6</org.slf4j-version>
 </properties>

~~~

(중략)
    <!-- AspectJ -->
    <dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjrt</artifactId>
     <version>${org.aspectj-version}</version>
    </dependency>
   
    <!-- AspectJWeaver -->
    <dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjweaver</artifactId>
     <version>${org.aspectj-version}</version>
    </dependency>
   
    <!-- Spring AOP 추가(Java) --> 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${org.springframework-version}</version>
    </dependency> 
(중략)






5. applicationContext.xml (src/main/resources/applicationContext.xml)


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"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
 
 <!-- 방법1 - JAVA -->
 <!-- JAVA 방식(어노테이션)의 AOP - AspectJ Weaver -->
 <!--  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>  어노테이션 작업시 필수 선언해야 함. -->
 
 <!--  XML 방식의 AOP - AsepectJ Weaver -->
 <bean id="resultAOP" class="com.website.example.test.ResultAOP"></bean>
 <bean id="txAdviceXML" class="com.website.example.aop.LogAdvisorXML"></bean>

 <aop:config>
  <!-- txAdviceXML 하나 영역임 -->
  <aop:aspect ref='txAdviceXML'>

   <!-- 진입영역 -->
   <!-- 1개만 가능함 -->
   <!-- <aop:pointcut id="point1" expression="execution(* com.website.example.test..*())"/> -->
   <aop:pointcut id="point1" expression="execution(* com.website.example.test.ResultAOP..*())"/>           
          
          <!-- before -->
          <aop:before method="beforeAdvice" pointcut-ref="point1"/>
          <!-- after -->
          <aop:after method="afterAdvice" pointcut-ref="point1"/>
          
          <!-- around(메서드 자체를 가로채기) -->
          <aop:around method="aroundAdvice" pointcut-ref="point1"/>
          
          <!-- afterThrowing -->
          <aop:after-throwing method="afterThrowing" pointcut-ref="point1"/>
          
          <!-- afterReturning -->
          <aop:after-returning method="afterReturning" pointcut-ref="point1"/>
          
        </aop:aspect>
       
        <!-- 2번째 선언자 -->
 </aop:config>
 
</beans>


파일명: applicationContext.xml


[첨부(Attachments)]

applicationContext.zip



6. ResultAOP.java - com.website.example.text


핵심 로직에 해당되는 부분이다. 이 부분을 비즈니스 로직이라고 표현하기도 한다.


package com.website.example.test;


public class ResultAOP {


     public void method1() {
           System.out.println("[중간]:");
  
           // afterThrowing 유발 코드
           // int d = 2/0;
  
           System.out.println("결과: 메서드");
     }
 
}


파일명: ResultAOP.java


[첨부(Attachments)]

ResultAOP.zip


applicationContext.zip



7. LogAdvisor.java - com.website.example.aop


인터페이스 정의이다.

package com.website.example.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public interface LogAdvisor {

        public void beforeAdvice();
        public void afterAdvice();
        public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable;
        public void afterThrowing();
        public void afterReturning();
 
}


파일명: LogAdvisor.java


[첨부(Attachments)]

LogAdvisor.zip




8. LogAdvisorXML.java - com.website.example.aop


package com.website.example.aop;

import org.aspectj.lang.ProceedingJoinPoint;


public class LogAdvisorXML implements LogAdvisor{
  
       // around advice
       @Override
       public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
  
               System.out.println("2단계A?:");
               System.out.println("aroundMethod 호출 1");
  
               // 원래의 메소드를 호출한다.
               Object obj = pjp.proceed();

               System.out.println("2단계B?:");
               System.out.println("aroundMethod 호출 2");
  
               return obj;
       }


       // before advice
       @Override
       public void beforeAdvice() {
              System.out.println("1단계:");
              System.out.println("beforeMethod 호출");
  
       }


       // after
       @Override
       public void afterAdvice() {
              System.out.println("5단계:");
              System.out.println("afterMethod 호출");
  
       }


       // afterThrowing
      @Override
      public void afterThrowing() {
              System.out.println("4단계:");
              System.out.println("afterThrowing 호출");
      }

      // afterReturning
      @Override
      public void afterReturning() {
              System.out.println("3단계:");
              System.out.println("afterReturning 호출");
  
      }
 
}


파일명: LogAdvisorXML.java


[첨부(Attachments)]

LogAdvisorXML.zip


LogAdvisor.zip




9. TestMain.java - com.website.example.unit


package com.website.example.unit;


import org.junit.jupiter.api.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.website.example.test.ResultAOP;


public class TestMain {

      
       // 사용방법1
       @Test
       public void sample() {

                AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
   
                ResultAOP rAOP = (ResultAOP) factory.getBean("resultAOP");

                rAOP.method1();
  
                factory.close();
       }
 

       // 사용방법2
       @Test
       public void sample2() {

               ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
               ResultAOP rAOP = ctx.getBean("resultAOP", ResultAOP.class);
               //rAOP.method1();
  
               ctx.close();
       }
 
}


파일명: TestMain.java


[첨부(Attachments)]

TestMain.zip




10. 동작 결과


구현한 코드의 동작 결과이다.



그림 3. 출력 결과 1



그림 4. 출력 결과 2




11. 맺음글(Conclusion)


직관적으로 AOP를 아주 쉽게 이해할 수 있도록 작성하였다.

반응형
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;


반응형

+ Recent posts