728x90
300x250

[Spring-Framework] 31. AOP(Aspect-Oriented-Programming) 관점지향 프로그래밍 (Java셋팅) (2)


1부에서는 통상적인 개발 방법으로 간단한 Calculator 클래스에 정의된 sum 함수(또는 매서드)를 출력하는 방법을 살펴보았다.

참고로 앞에 코드는 편집이 불가능한 코드라고 가정하고 접근해야 한다.


1. [Spring-Framework] 31. AOP(Aspect-Oriented-Programming) 관점지향 프로그래밍 (Java셋팅) (1)

https://yyman.tistory.com/1447



8. aop 패키지를 추가로 작성하여 copy & paste하기


aop 패키지를 별도로 둘 것이다.

코드를 따로 작성해야 하는가? 시점 부분만 작성하고 크게 많이 작성하진 않는다.



그림 15. Copy & Paste 하기


태스트 코드를 복사할 것이다.


(1단계) com.local.example.service에 만들어놓았던 Calculator.java를 파일 복사한다. (Ctrl + C)

(2단계) com.local.example.aop 폴더(또는 패키지)를 만든다.

(3단계) com.local.example.aop 폴데 Calculator.java를 붙여넣는다. (Ctrl + V)

(4단계) 소스 코드가 빨간 불이 들어오는 패키지 부분을 com.local.example.aop로 변경해준다.



9. 작업 방법론 - 정리해보기


직관적으로 코드 작성 전략을 소개해주려고 한다.

이런 형태로 작업을 할 것이다.



그림 16. 작업 방법


빌드하는 방법은 웹 서버에 올려서 확인하면 된다.




9. AOP 필수(코어), 핵심사항 - RootConfig.java (환경설정 파일 만들기)


패키지 경로: com.local.example.aop


반드시 만들어야 할 파일이다.

이 셋팅 파일이 없으면 동작 자체를 안 한다.



그림 17. RootConfig.java


이 코드는 AspectJ Proxy의 핵심 환경설정 파일이다.

이걸 정의하지 않으면, 동작이 안 된다.


package com.local.example.aop;


import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;


@Configuration

@ComponentScan(basePackages = {"com.local.example.aop"})

//@ComponentScan(basePackages = {"com.local.example.beans", "com.local.example.advisor"})

@EnableAspectJAutoProxy

public class RootConfig {


}


파일명: RootConfig.java


[첨부(Attachments)]

RootConfig.zip




10. AOP 적용, 핵심사항 - Calculator.java (살짝 수정하기)


패키지 경로: com.local.example.aop


작업 파일 원본의 권한을 가진 사람에게 하나 요청해도 무방하다. (초기 생성자 부분)

여기에서는 그런 거 신경쓰지 않고, 작업하겠다.


package com.local.example.aop;


import org.springframework.stereotype.Service;


@Service("cal")

public class Calculator {


private long x;

private long y;

private long z;

public Calculator() {

this.x = 1;

this.y = 2;

this.z = 3;

}

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

this.x = x;

this.y = y;

this.z = z;

}

// 작업 원본(A 프로그래머 작성함)

public long sum() {

long result = x + y + z;

System.out.println("비즈니스 로직");

// long d = result / 0; - 일부러 만든 코드(After Throws 보여줄려고)

return result;

}

}



파일명: Calculator.java


[첨부(Attachments)]

Calculator-Aspect.zip


(참고)

주석 친 부분을 주석 풀면, After Throws를 정의한 경우라면 메시지가 출력되는 것을 볼 수 있다.


색깔 칠한 코드는 Calculator(long x, long y, long z) 코드 때문에 Calculator.class 파일로 불러오면 Error를 경험할 수 있다.

그래서 파란색깔로 칠한 코드 Calculator()를 정의해서 문제를 해결한 것이다.




11. AOP 구현(시점 구현) - 시점 예제 (Log.java)


패키지 경로: com.local.example.aop


많은 고민을 한 끝에 간단하면서 실용적인 형태로 코드를 작성하였다.

참고로 시점 정의를 안해도 빌드해보면, HomeController.java에 정의가 잘 되어있으면 돌아가긴 돌아간다.

무슨 말인지는 태스트를 해보면 알 수 있다.


package com.local.example.aop;


import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Service;


// 관점, 서비스

@Aspect

@Service


// 콤포넌트 사용하지 말것

public class Log {

Logger logger =  LoggerFactory.getLogger(Log.class);

// 섞어적어놓아도 순서를 찾아서 강제 인식함.

    

// 2단계 - 전 단계 시야)

@Before("execution(* com.local.example.aop.Calculator.*(..))")

// @Before("execution(public void sum())")

// 반환값 없어도 무방

    public void logBefore() { 

logger.info("전 단계 관점 - 구현(Before)");

    }

    

// 1단계 - Before보다 전 단계 실행

    // Calculator 클래스의 모든 메서드

// 무조건 반환값이 지정되어야 함. (ProceedingJoinPoint에 대한 Object 반환값 필수 정의되어야 함)

// @Around 이 친구만 Pjp가 있어야 함.

    @Around("execution(* com.local.example.aop.Calculator.*(..))")

    /*@Around("execution(* com.example.demo.controller..*.*(..))")*/

    /*@Around("execution(* com.example.demo..*.*(..))")*/

    public Object logAround(ProceedingJoinPoint pjp) throws Throwable { 

   

logger.info("Around 단계 - 구현(Around)");

Object result = pjp.proceed();

return result;

    }

    

    // 3단계는 (중간) - 임의로 지정해줄 수 있는 것이 아님.

// 4단계: After advice

//@After("execution(* method1())")  -- method1 함수만 실행 

    // (이렇게 하면 안 됨. sum()을 콜하니깐)

    // @After("execution(* method1())")

    @After("execution(* sum())")

public void afterMethod() {

   

    logger.info( "after Method 호출" );

   

}

    

    // 5단계: 맨 마지막 단계

// after-throwing advice /// 오류가 발생할 때 호출함(무조건 보여지는 영역은 아님

    // 쉽게 비유하면, try to catch finally에서 catch 단계로 보면 됨.

    // 오류도 출력되고 after Throwing 로그 메시지도 출력된다.

    // 이 화면을 보려면, 오류나는 코드에 try to catch finally를 적용하면 안 됨.

    // 원본 비즈니스 로직 코드는 그대로 둘 것

    @AfterThrowing(

        pointcut = "execution(* com.local.example.aop.Calculator.sum(..))", 

        throwing = "ex"

    )

public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex) {

logger.info( "after Throwing 호출" + ex.getMessage());

}


    

}


파일명: Log.java


[첨부(Attachments)]

Log.zip





12. AOP 사용시, 핵심사항 - HomeController.java 변경하기


패키지 경로: com.local.example


HomeController.java 코드를 수정할 것이다.


package com.local.example;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

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 com.local.example.aop.Calculator;

import com.local.example.aop.RootConfig;


/**

 * Handles requests for the application home page.

 */

@EnableAspectJAutoProxy

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

// Java 방식 - AOP

AnnotationConfigApplicationContext context = 

new AnnotationConfigApplicationContext(RootConfig.class);

// 1. 이전 방식

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


// 2. Aspect 적용

// 소문자로 입력(Calculator -> calculator로)

Calculator cal = (Calculator)context.getBean("cal", Calculator.class);

System.out.printf("result of sum: %d", cal.sum());

model.addAttribute("serverTime", formattedDate );

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController-aspect.zip




13. 동작 결과 구경하기


두 가지 결과로 작성하였다. 하나는 오류가 없는 코드이다.

하나는 오류가 있어서 After Throws가 호출되는 코드이다.



그림 17. 결과1의 오류 없는 코드(1)



그림 18. 결과1의 오류 없는 코드(2)




그림 19. 결과2의 오류 있는 코드(1)



그림 20. 결과2의 오류 있는 코드(2)





* 맺음글(Conclusion)


AOP 프로그래밍을 실질적으로 쉽게 사용하는 방법에 대해서 소개하였다.



* 참고자료(References)


1. [스프링] Error creating bean with name '***Controller': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named '***Service' is defined 에러 해결방법, https://zzznara2.tistory.com/275, Accessed by 2020-10-04, Last Modified 2015-06-18.


참고: 시중에 있는 AOP 자료를 보고 따라하다보면, 오류 먼저 구경할 것이다. AOP는 조금 어느 정도 프로그래밍 지식이 있을 때 사용하는 걸 권장하고 싶다. (쉽지 않은 부분이다.)


2. Spring : AOP with Java Config - 설정하기와 @Before advice, https://kogle.tistory.com/51, Accessed by 2020-10-04, Last Modified 2020-05-11.


추천(40점): 구축 원리에 대해서 매우 잘 나와있다. 그러나 몇 가지는 수정작업을 해줘야 한다.


3. AspectJ Weaver를 사용한 애노테이션 기반의 스프링 AOP 구현 방법, https://atoz-develop.tistory.com/entry/AspectJ-Weaver%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%95%A0%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EA%B8%B0%EB%B0%98%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-AOP-%EA%B5%AC%ED%98%84-%EB%B0%A9%EB%B2%95, Accessed by 2020-10-04, Last Modified 2020-04-27.


추천(25점): 구축 원리를 잘 정리해놨다. 2번 참고자료하고 같이 보는 것을 권장한다. (예제가 살짝 아쉬움)


4. Spring AOP 스프링이 해줄건데 너가 왜 어려워 해? Spring boot에서 aop logging 사용법 제일 쉽게 알려드립니다!, https://jeong-pro.tistory.com/171, Accessed by 2020-10-04, Last Modified 2018-11-23.

반응형
728x90
300x250

[Spring-Framework] 30. AOP(Aspect-Oriented-Programming) 관점지향 프로그래밍 (Java셋팅) (1)


참고로 AOP는 Spring-Framework에만 적용되는 방법론이다.

새로 만들어진 개념은 아니고, 자바의 Proxy(패턴 아님. 탈취기법이 있음.)에서 핵심 영역의 관점으로 진화한 개념이다.


교과서나 시중 책 등에서는 이런 표현은 안 쓰긴 하지만, "탈취 방법"이라고 하는 게 적절하다고 주장하다.


해당 작업은 Spring Framework에서만 가능한 작업이다.



IDE: Spring Tool-Suite 4-4.7.2 Release(2020-08월)
Library: 

- Spring Framework 5.2.9.RELEASE (2020-09-15)

- Java Version: 14

- AspectJ: 1.9.6 (2020-07-22)

- AspectJ Weaver: 1.9.6 (2020-07-22)

- javax.servlet-api 4.0.1 (2018-04-20)


(순정 상태로 셋팅하였음.)



Project: Spring Legacy Project로 생성할 것


-> 안 보이는 사람들은 Help->Eclipse Marketplace -> STS 검색 후 "Spring Tools 3 Add-On for Spring Tools 4 3.9.14.RELEASE" 설치할 것



그림 1. STS-Addon (Eclipse Marketplace)



1. 이전의 개발 방법론(Proxy)


지금도 물론 이런 방법은 안 쓰일 수는 없다.

AOP가 먼저 나온 것이 결코 아니다. 아마 c#에도 이런 게 있는 걸로 알고 있다. (오래되서)


프로그래밍 개발을 하다보면, 로직을 구현하는데 있어서 코어 코드를 수정해서 작업을 하는 일이 많이 있다.

핵심 규칙은 x, y, z만 더해서 결과만 출력하면 되는 요구사항을 가진 문제인데 구현을 하다보면, 현실적인 문제라는 게 발생하게 된다.


그림 2. 이전의 로직 구현 방법 - 개발


그림 1과 같은 문제는 자주 생기는 문제이기도 하다.

이런 방법으로 구현하는 것이 아예 사라졌다는 게 아니다.


그림 1에서 (1단계)의 핵심 규칙을 재사용할 기회를 상실해버리는 문제가 발생하게 된다.



그림 3. 문제 인식


그림 2처럼 문제가 생겼다고 하자.

물론 머리가 조금 좋은 분들은 객체의 상속 관계로 처리해도 해결할 수 있지 않겠냐고 할 수도 있다. 

(객체지향 프로그래밍에서도 설계를 다시 해서 이런 문제를 나눠볼 수도 있겠음.)


허나 쉬운 일이 결코 아니다. 코드라는 게 이쪽에서 사용되고 있는지, 저기에서 사용되고 있는지 작성을 하게 되면 수정이 정말 어렵다는 것이다.


물론 C#을 논하는 자리가 아니어서 자바를 예로 들면, Proxy 탈취 방법이 존재한다.




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


자바에서는 


Type of Classes username new Proxy.newProxyInstance(Classes.class.getClassLoader(), new Class[] { classes.class } , 

new InvocationHandler(){

          public Object invoke(Object proxy, Method method, Object args[] throws Throwable{

                     

                  // 전단계 호출

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

                  // 후단계 호출

         }


     }


};


슈도 코드(Pseudo Code) 1. 자바의 Proxy 호출 방법


이런 방법으로 핵심 로직을 탈취하는 방법이 있다.

기본적인 원리는 이런 원리에 입각해서 만들어졌다고 보면 된다.


AOP의 용어 설명은 나중에 할 것이다. 절대로 지금 바로 알면 안 된다고 생각한다.


3단계를 기본으로 한다. "전 단계, 핵심 로직, 후 단계"

이 단계의 확장적인 개념이다.


Spring AOP에서는 5단계로 확장되었다.


전단계:    {Around 단계, Before 단계}, 

핵심로직:         핵심 로직(중간)

후단계:    {after Method 호출, AfterThrowing(선택 - 예외 처리 발생 때만)}


조금 더 이해하기 쉬워졌을 것으로 보인다.


[첨부(Attachments)]

background-aop.zip





2. 코드로 살펴보는 AOP


AOP를 이론으로만 봐서는 이해가 무척 안 될 것이다. 구현을 통해서 단계적으로 살펴보도록 하겠다.

프로젝트 생성부터 단계적으로 소개하겠다.



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


File을 클릭한다.

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



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


Spring MVC Project를 선택한다.

Project name을 입력한다.

Next를 누른다.




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


Top-level-package를 입력한다. (예: com.local.example)

Finish를 누른다.



3. POM.xml 설정하기


http://mvnrepository.com 사이트에 접속한다.

검색 키워드에 "aspectj"라고 입력한다. (세 가지 검색을 해서 버전을 획득해야 함)

검색 키워드에 "spring"라고 입력한다.

검색 키워드에 "servlet"이라고 입력한다.


두 가지의 Maven 주소를 획득해야 한다.



그림 8. MVNRepository 검색 결과의 예 (1) - AspectJ



그림 9. MVNRepository 검색 결과의 예 (1) - AspectJ


버전을 클릭하면, Maven Pom이 나온다.

이걸 복사 붙여넣기를 해도 된다.


다만 <version>만 복사해서 관리하는 방법도 있으니 자세한 건 POM.xml 소스를 참고하면 좋겠다.



그림 10. pom.xml - 변경 작업 모습(1)


<java-version>14</java-version>으로 변경한다.

<org.springframework-version>5.2.9.RELEASE</org........>로 변경한다.

<org.aspectj-version>1.9.6</org......>으로 변경한다.


<?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.local</groupId>

<artifactId>example</artifactId>

<name>springAOP-javaConfig</name>

<packaging>war</packaging>

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

<properties>

<!-- 자바 버전 변경함 -->

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

<!-- 스프링프레임워크 버전 변경함 -->

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

<!-- AspectJ 변경함 -->

<org.aspectj-version>1.9.6</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>

<!-- AspectJWeaver 추가 -->

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjweaver</artifactId>

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

</dependency>


<!-- Logging -->

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

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

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

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

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

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-log4j12</artifactId>

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

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.15</version>

<exclusions>

<exclusion>

<groupId>javax.mail</groupId>

<artifactId>mail</artifactId>

</exclusion>

<exclusion>

<groupId>javax.jms</groupId>

<artifactId>jms</artifactId>

</exclusion>

<exclusion>

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

<artifactId>jmxtools</artifactId>

</exclusion>

<exclusion>

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

<artifactId>jmxri</artifactId>

</exclusion>

</exclusions>

<scope>runtime</scope>

</dependency>


<!-- @Inject -->

<dependency>

<groupId>javax.inject</groupId>

<artifactId>javax.inject</artifactId>

<version>1</version>

</dependency>

      <!-- Servlet -->

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

            <dependency> 

                  <groupId>javax.servlet</groupId>

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

                  <version>4.0.1</version>

                  <scope>provided</scope> 

            </dependency>

<dependency>

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

<artifactId>jsp-api</artifactId>

<version>2.1</version>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

<version>1.2</version>

</dependency>

<!-- Test -->

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.7</version>

<scope>test</scope>

</dependency>        

</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. Project의 Properties - Build Path, Project Factes 설정하기 (Java Version 변경)


프로젝트의 자바 버전을 변경할 것이다.



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


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

Properties를 클릭한다.




그림 12. Java Build Path


Java Build Path를 클릭한다.

JRE System Library를 [JavaSE-14]로 변경한다.




그림 13. Project Factes


Project Factes를 클릭한다.

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




5. web.xml - 서블릿 스팩 (2.5에서 4.0으로 변경)


서블릿 스팩을 변경할 것이다.

web.xml에서 변경해주면 된다.



그림 14. web.xml (servlet 4.0 스팩으로 변경)



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


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>

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

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

</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->

<listener>

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

</listener>


<!-- Processes application requests -->

<servlet>

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

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

<init-param>

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

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

</init-param>

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

</servlet>

<servlet-mapping>

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

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

</servlet-mapping>


</web-app>



파일명: web.xml


[첨부(Attachments)]

web.zip



6. service - Calculator.java


복잡한 설명을 적기보다는 작업화면하고 코드를 소개하겠다.



그림 15. Calculator.java


package com.local.example.service;


public class Calculator {


private long x;

private long y;

private long z;

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

this.x = x;

this.y = y;

this.z = z;

}

// 작업 원본(A 프로그래머 작성함)

public long sum() {

long result = x + y + z;

return result;

}


}


파일명: Calculator.java


[첨부(Attachments)]

 Calculator-original.zip


참고로 지금 코드로는 AspectJ가 동작되지 않는 코드이다.
이유는 초기 매개변수가 없는 생성자가 없어서 그렇다.

(다음 페이지에서 소개하겠음.)



7. Controller - HomeController.java


아마 순정 코드에 Calculator의 sum()를 호출한 것을 보면, 다음과 같이 되어있다.


package com.local.example;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

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 com.local.example.aop.Calculator;

import com.local.example.aop.RootConfig;


/**

 * Handles requests for the application home page.

 */

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


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

System.out.printf("result of sum: %d", cal.sum());

model.addAttribute("serverTime", formattedDate );

return "home";

}

}



파일명: HomeController.java


이렇게 하면, 잘 동작할 것이다.

결과가 "result of sum: 6"이 출력될 것이다.



* 2부에서 AOP 사용 코드로 전환하는 방법에 대해서 소개하겠다.


1. [Spring-Framework] 30. AOP(Aspect-Oriented-Programming) 관점지향 프로그래밍 (Java셋팅) (2), 2020-10-04

https://yyman.tistory.com/1448


반응형
728x90
300x250

[Spring-F.] 28. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법4(SqlMap Spring전용)


소스 코드 위주로 소개하도록 하겠다.


[실험 결과]

1. [Spring-Framework] Spring Framework 5.4, MyBatis 3.5 연동 방법 - 실험 결과, 2020-10-02

   - https://yyman.tistory.com/1437


[이전 게시글]

1. [Spring-F.] 27. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법3(SqlMap-XML-Class)     // 결과: 지원, 2020-10-02

    - https://yyman.tistory.com/1440



33. 결과


작업한 내용을 출력한 결과는 다음과 같다.



그림 23. 결과 모습(Java 방식) - XML Mapper - Spring Beans 객체 방식 적용 (Spring 전용)



그림 24. 프로젝트 구성도




34. web.xml (기본값) - 변동없음


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


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

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

version="3.1">


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>

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

<param-value>

/WEB-INF/spring/root-context.xml

</param-value>

</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->

<listener>

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

</listener>


<!-- Processes application requests -->

<servlet>

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

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

<init-param>

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

<param-value>

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

</param-value>

</init-param>

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

</servlet>

<servlet-mapping>

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

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

</servlet-mapping>


</web-app>





35. com.example.spbatis.db - SqlMapSessionFactory.java


package com.example.spbatis.db;



import java.io.IOException;

import java.io.InputStream;

import java.sql.SQLException;


import javax.sql.DataSource;


import org.apache.ibatis.io.Resources;

import org.apache.ibatis.mapping.Environment;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.apache.ibatis.transaction.TransactionFactory;

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

import org.mybatis.spring.SqlSessionFactoryBean;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;


import com.example.spbatis.mapper.CompUsersMapper;

import com.example.spbatis.model.CompUsers;


import oracle.jdbc.pool.OracleDataSource;


public class SqlMapSessionFactory {


private static SqlMapSessionFactory factory = new SqlMapSessionFactory();

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

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

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

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

public static SqlSessionFactory ssf;


public static SqlMapSessionFactory getInstance() {

return factory;

}

private SqlMapSessionFactory () {    }

static {

/* 방법1

DataSource dataSource = getOracleDataSource();

TransactionFactory transactionFactory = new JdbcTransactionFactory();

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

Configuration configuration = new Configuration(environment);

configuration.addMapper(CompUsersMapper.class);

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

*/

}

    

    public static SqlSessionFactory getSqlSessionFactory(){

   


/* 방법2: 공식 메뉴얼 참고 */

DataSource dataSource = getOracleDataSource();


SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); // Spring Framework만 지원

factoryBean.setDataSource(dataSource);

try {

//쿼리가 정의된 xml 파일들의 위치 지정

/*

        factoryBean.setMapperLocations(

                new PathMatchingResourcePatternResolver().getResources("com/example/spbatis/mapper/*.xml")

        );

        */

    

ssf = factoryBean.getObject();

// 클래스 등록

ssf.getConfiguration().addMapper(CompUsersMapper.class);

} catch (Exception e) {

e.printStackTrace();

}

   

    // 방법 1, 방법 2 공통

        return ssf;

    }

    

    /*

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

*/

    private static DataSource getOracleDataSource(){


    OracleDataSource oracleDS = null;


    try {

            oracleDS = new OracleDataSource();

            oracleDS.setURL(dbUrl);

            oracleDS.setUser(userName);

            oracleDS.setPassword(userPassword);


        } catch (SQLException e) {

            e.printStackTrace();

        }


        return oracleDS;


    }

    

}



파일명: SqlSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip





36. com.example.spbatis.mapper - CompUsersMapper.java


package com.example.spbatis.mapper;


import java.util.List;


import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Select;


import com.example.spbatis.model.CompUsers;


@Mapper

public interface CompUsersMapper {

@Select("SELECT * FROM comp_users")

List<CompUsers> selectAll();

}


파일명: CompUsersMapper.java


[첨부(Attachments)]

CompUsersMapper.zip





37. com.example.spbatis.dao - CompUsersDao.java


package com.example.spbatis.dao;


import java.util.List;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.springframework.beans.factory.annotation.Autowired;


import com.example.spbatis.db.SqlMapSessionFactory;

import com.example.spbatis.mapper.CompUsersMapper;

import com.example.spbatis.model.CompUsers;



public class CompUsersDao {


    SqlSessionFactory factory = SqlMapSessionFactory.getSqlSessionFactory();

    

    public CompUsersDao() {

        

    }

    

    // SQL 세션 열기

    public List<CompUsers> selectAddress() {


    List<CompUsers> user = null;

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

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

user = mapper.selectAll();

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


}

return user;


    }

    

}



파일명: CompUsersDao.java


[첨부(Attachments)]

CompUsersDao.zip





38. com.example.spbatis.service - CompUsersService.java


package com.example.spbatis.service;


import java.util.List;


import com.example.spbatis.dao.CompUsersDao;

import com.example.spbatis.model.CompUsers;


public class CompUsersService {


private CompUsersDao dao = null;

public CompUsersService() {

dao = new CompUsersDao();

}

public List<CompUsers> getAllCompUsers() {

return dao.selectAddress();

}

 

}



파일명: CompUsersService.java


[첨부(Attachments)]

CompUsersService.zip





39. com.example.spbatis - HomeController.java


package com.example.spbatis;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

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 com.example.spbatis.service.CompUsersService;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

private CompUsersService compUserService;

@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home4(Class Mappers) - Java! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

compUserService = new CompUsersService();

model.addAttribute("serverTime", formattedDate );

model.addAttribute("list", compUserService.getAllCompUsers()) ;

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController.zip



40. View - Home.jsp


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

    pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page session="false" %>


<html>

<head>

<title>Home</title>

</head>

<body>

<h1>

Hello world!  

</h1>


<P>  The time on the server is ${serverTime}. </P>

<h3>SqlMapSessionFactory 방식(Java - Mapper - Spring 전용 버전)</h3>

<c:forEach items="${list }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list }">

    ${"데이터가 존재하지않아요."}

</c:if>


</body>

</html>



파일명: home.jsp


[첨부(Attachments)]

home.zip




* 5부에서 만나요.


1. [Spring-F.] 29. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법5(SqlMap Spring전용)  // 결과: 지원, 2020-10-02

    - https://yyman.tistory.com/1442



반응형
728x90
300x250

[Spring-F.] 26. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법2(SqlMap-XML-XML 맵핑)


소스 코드 위주로 소개하도록 하겠다.


[실험 결과]

1. [Spring-Framework] Spring Framework 5.4, MyBatis 3.5 연동 방법 - 실험 결과, 2020-10-02

https://yyman.tistory.com/1437


[이전 게시글]

1. [Spring-F.] 25. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법1(web.xml-Beans), 2020-10-02

https://yyman.tistory.com/1438



15. 결과


2번째 실험에 대한 결과이다.



그림 19. 동작 결과



그림 20. 프로젝트 구성도


완성한 프로젝트의 구성도이다. 소스코드를 작성하는데 참고하면 도움이 될 것으로 보인다.



16. web.xml - 설정 (기본값)


기본값 소스코드로 두었다.


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


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

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

version="3.1">


<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>

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

<param-value>

/WEB-INF/spring/root-context.xml

</param-value>

</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->

<listener>

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

</listener>


<!-- Processes application requests -->

<servlet>

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

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

<init-param>

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

<param-value>

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

</param-value>

</init-param>

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

</servlet>

<servlet-mapping>

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

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

</servlet-mapping>


</web-app>





17. view - home.jsp


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

    pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@ page session="false" %>


<html>

<head>

<title>Home</title>

</head>

<body>

<h1>

Hello world!  

</h1>


<P>  The time on the server is ${serverTime}. </P>

<h3>SqlMapSessionFactory 방식(XML - 환경설정 - XML-Mappers)</h3>

<c:forEach items="${list }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list }">

    ${"데이터가 존재하지않아요."}

</c:if>


<h3>XML - web.xml 설정방식</h3>

<c:forEach items="${list2 }" var="val" >

    ${val.username} / 

    ${val.password} /

    ${val.enabled }<br>

</c:forEach>

<c:if test="${empty list2 }">

    ${"데이터가 존재하지않아요."}

</c:if>


</body>

</html>



파일명: home.jsp


[첨부(Attachments)]

home.zip




18. com.example.spbatis.mapper - mybatis-config.xml


Spring Boot가 아닌 이상, 참고로 해당 위치에 xml파일을 넣어줘야 한다.
예를 들면, the.getClass().getResources() 이런 함수를 활용해서 /src/main/resources 폴더를 생성하고 작업을 시도하려고 한다면, 

실패할 것이다. 운이 좋아서 경로를 찾아서 빌드했을 때 동작이 되었다고 해도, 톰캣 서버에 올려버리면 경로를 못 찾아버리는 현상이 발생한다.


충분히 시간을 가지고, 태스트를 거친 후에 작성한 글이다.


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


<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 

"http://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>


<environments default="development">

    <environment id="development">

      <transactionManager type="JDBC"/>

      <!-- 커넥션 풀(MyBatis) -->

      <dataSource type="POOLED">

        <property name="driver" value="oracle.jdbc.driver.OracleDriver" />

        <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>

        <property name="username" value="UserName"/>

        <property name="password" value="Password"/>

        <property name="poolMaximumActiveConnections" value="20"/>

        <property name="poolMaximumIdleConnections" value="20"/>

        <property name="poolMaximumCheckoutTime" value="20000"/>

        <property name="poolPingEnabled" value="true"/>

        <property name="poolPingQuery" value="select 1"/>

        <property name="poolPingConnectionsNotUsedFor" value="10000"/>

        <property name="poolTimeToWait" value="15000"/>

      </dataSource>

    </environment>

</environments>


<mappers>

  <mapper resource="com/example/spbatis/mapper/CompUsersMapper.xml"/>

</mappers>


</configuration>


파일명: mybatis-config.xml


[첨부(Attachments)]

mybatis-config.zip





19. com.example.spbatis.mapper - CompUsersMapper.xml


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

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.example.spbatis.mapper">


<select id="allCompUsers" resultType="com.example.spbatis.model.CompUsers">

select * from comp_users

</select>

<!-- 

<select id="allAddress" resultType="com.edu.db.AddressDto">

select * from addressbook

</select>

<select id="selectAddress" parameterType="Integer" resultType="com.edu.db.AddressDto">

select NUM, NAME, ADDRESS, BIRTHDATE

from addressbook

  where num=#{num}

</select>

<insert id="insertAddress" parameterType="com.edu.db.AddressDto">

insert into

addressbook(NAME, ADDRESS, BIRTHDATE)

values

(#{name},#{address},#{birthdate})

</insert>

<delete id="deleteAddress" parameterType="Integer">

DELETE FROM AddressBook

WHERE NUM = #{num}

</delete>

<update id="updateAddress" parameterType="com.edu.db.AddressDto" >

update addressbook

set birthdate = #{birthdate}, name = #{name}, address =#{address}

where num = #{num}

</update>

 -->

</mapper>


파일명: CompUsersMapper.xml


[첨부(Attachments)]

CompUsersMapper.zip




20. com.example.spbatis.db - SqlMapSessionFactory.java


package com.example.spbatis.db;



import java.io.IOException;

import java.io.InputStream;


import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;


public class SqlMapSessionFactory {

public SqlSessionFactory ssf;

public SqlMapSessionFactory () {


        String resource = "com/example/spbatis/mapper/mybatis-config.xml";

        InputStream is = null;


        try {

            is = Resources.getResourceAsStream(resource);

        } catch (IOException e) {

            e.printStackTrace();

        }


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


    }

    

    public SqlSessionFactory getSqlSessionFactory(){

        return ssf;

    }

    

}



파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip




21. com.example.spbatis.dao - CompUsersDao.java


package com.example.spbatis.dao;


import java.util.List;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.springframework.beans.factory.annotation.Autowired;


import com.example.spbatis.db.SqlMapSessionFactory;

import com.example.spbatis.model.CompUsers;



public class CompUsersDao {

    private SqlMapSessionFactory ssfc;

    private SqlSessionFactory factory;

    

    public CompUsersDao() {

   

        ssfc = new SqlMapSessionFactory();

        factory = ssfc.getSqlSessionFactory();

        

    }

    

    // SQL 세션 열기

    public List<CompUsers> selectAddress() {


        SqlSession session = factory.openSession();


        List<CompUsers> compDTO = session.selectList("com.example.spbatis.mapper.allCompUsers");

        session.close();

        return compDTO;


    }

    

}



파일명: CompUsersDao.java


[첨부(Attachments)]

CompUsersDao.zip




22. com.example.spbatis.service - CompUsersService.java


package com.example.spbatis.service;


import java.util.List;


import com.example.spbatis.dao.CompUsersDao;

import com.example.spbatis.model.CompUsers;


public class CompUsersService {


private CompUsersDao dao = null;

public CompUsersService() {

dao = new CompUsersDao();

}

public List<CompUsers> getAllCompUsers() {

return dao.selectAddress();

}

 

}



파일명: CompUsersService.java


[첨부(Attachments)]

CompUsersService.zip




23. com.example.spbatis - HomeController.java


package com.example.spbatis;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

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 com.example.spbatis.service.CompUsersService;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

private CompUsersService compUserService;

@RequestMapping(value = "/", method = RequestMethod.GET)

public String home(Locale locale, Model model) {

logger.info("Welcome home2! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

compUserService = new CompUsersService();

model.addAttribute("serverTime", formattedDate );

model.addAttribute("list", compUserService.getAllCompUsers()) ;

return "home";

}

}



파일명: HomeController.java


[첨부(Attachments)]

HomeController.zip



* 방법 3에 대한 글로 이동하기


3. [Spring-F.] 27. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법3(SqlMap-XML-Class)

https://yyman.tistory.com/1440


반응형
728x90
300x250

[Spring-Framework] Spring Framework 5.4, MyBatis 3.5 연동 방법 - 실험 결과


아마 이런 실험을 시도한 인터넷 글은 최초가 되지 않을까 싶다.

현재에 떠돌아 다니는 정보들을 충분한 시간을 가지고 실험한 결과이다.


필자가 구독자들에게 한 가지 약속한다면, 검증을 확실히 완료하고 작성한 글이다.

이 글을 어떻게 전달해야 할지 고민을 충분히 하고 작성하게 되었다.


@Autowired 방식과 @Beans 방식을 사용하는 유저가 있다면, 사용하지 않아야 한다.



1. 결과


엄격한 태스트를 거쳐서 완료한 결과이다. 개발 환경을 구축하는데 있어서 삽질을 하지 않았으면 하는 바람이다.



그림 1. 실험 결과


[첨부(Attachments)]

MyBatis-Complete-summary.zip




2. 5가지 방법 - 정리


정리가 완료되는데로 공개하도록 하겠다.


1. [Spring-F.] 25. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법1(web.xml-Beans)            // 결과: 미지원, 2020-10-02

   - https://yyman.tistory.com/1438

2. [Spring-F.] 26. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법2(SqlMap-XML-XML 맵핑)   // 결과: 지원, 2020-10-02

   - https://yyman.tistory.com/1439

3. [Spring-F.] 27. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법3(SqlMap-XML-Class)    // 결과: 지원, 2020-10-02

   - https://yyman.tistory.com/1440

4. [Spring-F.] 28. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법4(SqlMap Spring전용)   // 결과: 지원, 2020-10-02

   - https://yyman.tistory.com/1441

5. [Spring-F.] 29. MyBatis 3.5, Spring Framework 5.4, Oracle 19g - 방법5(SqlMap Spring전용)  // 결과: 지원, 2020-10-02

   - https://yyman.tistory.com/1442


= (기타: 표준 지원에 대한 4, 5번 소스코드도 주석으로 포함 처리함.)




3. 실험 조건


실험 조건은 다음과 같다.


* IDE: Spring Tool-Suites 4-4.7.2 (Releases)

* Library:

- Spring-Framework 5.2.9.RELEASE (2020-09-15)

javax.servlet-api 4.0.1 (2018-04-20)

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

- mybatis-spring (2020-06-05) // Spring Framework만 사용가능함.

   - https://mvnrepository.com/artifact/org.mybatis/mybatis-spring/2.0.5

- mybatis 3.5.5 (2020-06-04)

   - https://mvnrepository.com/artifact/org.mybatis/mybatis/3.5.5

- Spring JDBC 

   - https://mvnrepository.com/artifact/org.springframework/spring-jdbc/5.2.9.RELEASE

- ojdbc8 (ojdbc8)

- mariadb-java-client 2.7.0 (2020-09-24)

   - https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client/2.7.0

- mysql-connector-java 8.0.21 (2020-07-12)


* DB:

- Oracle Databases 19g




4. 실험 결과 - 동작 영상


입증하기 위해서 영상을 준비하였다.



영상 1. Spring Framework 5.4, Oracle 19g, Mybatis 3.5 연동하기



영상 2. Spring Framework 5.4, Oracle 19g, Mybatis 3.5 연동하기(실험 1 - 영상 [예])


이런 형태로 프로젝트를 구성한 것이다.



5. 공통 - 프로젝트 생성 방법


5가지 방법에 관한 프로젝트 생성에 관한 것이다.

1~5번의 셋팅은 Build Path, Project Factes, POM.xml은 동일하다.



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


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



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


Spring MVC Project를 선택한다.

Next를 클릭한다.



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


top-level package 경로를 입력한 후 Finish를 누른다.



5-1. Build-Path, Project Factes 설정하기


자바 버전을 변경해줄 것이다.

초기 Spring Legacy Project로 Spring MVC Project를 생성하면, 1.6 버전으로 셋팅되어 생성될 것이다.

이러한 것을 변경해줄 것이다.



그림 4. 프로젝트 속성 들어가기


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

Properties를 클릭한다.




그림 5. Build-path 버전 바꾸기


Java-Build Path를 클릭한다.

JRE System Library을 선택한다.

Edit 클릭하고 변경하면 된다.

(JRE -> JavaSE 14로 변경할 것)

Apply를 누른다.



그림 6. Project - Factes 설정하기


Project Factes를 클릭한다.

Java 버전을 14로 변경해준다.


Apply를 누른다.



5-2. Pom.xml 설정하기


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



그림 7. pom.xml 설정하기(1)


<org.springframework-version>을 5.2.9.RELEASE로 변경하였다.



그림 8. pom.xml 설정하기(2)


javax.servlet-api 버전을 4.0.1로 변경하였다.




그림 9. pom.xml 설정하기(3)


mybatis-spring, mybatis를 추가하였다.




그림 10. pom.xml - 오라클이 설치된 경우에만 따라하기(1)


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

Maven->Add Dependency를 클릭한다.




그림 11. pom.xml - 오라클이 설치된 경우에만 따라하기(2)


oracle이라고 검색한다.

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

OK를 누른다.




그림 12. pom.xml - mariadb, mysql-connector 추가하기


추가로 몇 개의 DB 드라이버(MariaDB, MySQL-Connector)를 부착시켰다. 


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

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

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

<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>

<artifactId>spbatis</artifactId>

<name>Spring-MVC-mybatis</name>

<packaging>war</packaging>

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

<properties>

<java-version>1.6</java-version>

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

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

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

</properties>

<dependencies>

<!-- Spring -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

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

<exclusions>

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

<exclusion>

<groupId>commons-logging</groupId>

<artifactId>commons-logging</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-webmvc</artifactId>

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

</dependency>

<!-- AspectJ -->

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjrt</artifactId>

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

</dependency>

<!-- Logging -->

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

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

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

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

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

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-log4j12</artifactId>

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

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.15</version>

<exclusions>

<exclusion>

<groupId>javax.mail</groupId>

<artifactId>mail</artifactId>

</exclusion>

<exclusion>

<groupId>javax.jms</groupId>

<artifactId>jms</artifactId>

</exclusion>

<exclusion>

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

<artifactId>jmxtools</artifactId>

</exclusion>

<exclusion>

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

<artifactId>jmxri</artifactId>

</exclusion>

</exclusions>

<scope>runtime</scope>

</dependency>


<!-- @Inject -->

<dependency>

<groupId>javax.inject</groupId>

<artifactId>javax.inject</artifactId>

<version>1</version>

</dependency>

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

<dependency>

    <groupId>javax.servlet</groupId>

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

    <version>4.0.1</version>

    <scope>provided</scope>

</dependency>


<dependency>

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

<artifactId>jsp-api</artifactId>

<version>2.1</version>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

<version>1.2</version>

</dependency>

<!-- Test -->

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.7</version>

<scope>test</scope>

</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis-spring</artifactId>

    <version>2.0.5</version>

</dependency>

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

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.5.5</version>

</dependency>

<!-- 스프링에서 JDBC 를 사용하기 위한 라이브러리 입니다. -->

<dependency>

   <groupId>org.springframework</groupId>

   <artifactId>spring-jdbc</artifactId>

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

</dependency>


<dependency>

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

<artifactId>ojdbc8</artifactId>

<version>19.7.0.0</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->

<dependency>

    <groupId>org.mariadb.jdbc</groupId>

    <artifactId>mariadb-java-client</artifactId>

    <version>2.7.0</version>

</dependency>

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

<dependency>

    <groupId>mysql</groupId>

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

    <version>8.0.21</version>

</dependency>

</dependencies>

    <build>

        <plugins>

            <plugin>

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

                <version>2.9</version>

                <configuration>

                    <additionalProjectnatures>

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

                    </additionalProjectnatures>

                    <additionalBuildcommands>

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

                    </additionalBuildcommands>

                    <downloadSources>true</downloadSources>

                    <downloadJavadocs>true</downloadJavadocs>

                </configuration>

            </plugin>

            <plugin>

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

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

                <version>2.5.1</version>

                <configuration>

                    <source>1.6</source>

                    <target>1.6</target>

                    <compilerArgument>-Xlint:all</compilerArgument>

                    <showWarnings>true</showWarnings>

                    <showDeprecation>true</showDeprecation>

                </configuration>

            </plugin>

            <plugin>

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

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

                <version>1.2.1</version>

                <configuration>

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

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>



파일명: pom.xml


[첨부(Attachments)]

pom.zip



6. DB - Table 설계


Spring Security에서 사용자 계정의 테이블 설계를 사용하였다.



그림 13. 테이블 모습


CREATE TABLE comp_users (

username VARCHAR(50) NOT NULL,

password VARCHAR(300) NOT NULL,

enabled INT NOT NULL,

PRIMARY KEY (username)

);


-- 계정

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

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


파일명: Comp_users.sql


[첨부(Attachments)]

comp_user.zip





6-1. Model - CompUsers.java


공통으로 1~5 프로젝트에서 사용되는 부분이다.


package com.example.spbatis.model;


public class CompUsers {

private String username;

private String password;

private int enabled;

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public int getEnabled() {

return enabled;

}

public void setEnabled(int enabled) {

this.enabled = enabled;

}


}



파일명: CompUsers.java


[첨부(Attachments)]

CompUsers.zip




* 맺음글(Conclusion)


1~5개의 글을 추가로 살펴보면 되겠다.

반응형
728x90
300x250

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


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

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

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

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


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


[사전 배경 지식]

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


[기타]

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

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



작업 환경

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

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

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

pom - maven

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

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

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

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

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

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

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



1. 실험 결과


(1차)

- Maven Project (webapp)

  Resteasy(JBoss 기반)

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

     (자료가 많이 부족함.)


  [첨부(Attachments)] (영어)

resteasy-reference-guide-en-US.pdf


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


(2차)

- Maven Project (webapp)

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

  

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

(2020-09-28)

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

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


  [첨부(Attachments)] (영어)

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


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


(3차)

- Spring Framework 5.4

  - Spring Legacy Project -> Spring MVC Project

    -> Pom(Maven) : 

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

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

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

        Apache Commons-FileUpload


결론: 성공





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


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

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


https://roy.gbiv.com/


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

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


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


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


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

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


핵심을 요약하면,


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


번호 

작업

전송 방식

1

Create

POST

2

Read

GET

3

Update

PUT 또는 Patch

4

Delete

DELETE


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


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

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


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


작업

전송방식 

URI 

생성

POST

/member/new 

조회(전체)

GET

/member

조회(특정)

GET

/member/{id}

수정

PUT or PATCH

/member/{id}

삭제

DELETE

/member/{id}


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

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




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


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


<form method="PUT">

~~~(중략)

</form>


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


<form method="POST">

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

~~~(중략)

</form>


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


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

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


(슈도 코드)
<script>

    .....

   


    ajax{

           contents/json

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


           sucessed{

           }

           failed{



           }

    }

</script>
~~~(중략)

<form method="POST">

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

~~~(중략)

</form>


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


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



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


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

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


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

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


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


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

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


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


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

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

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

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


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



[호기심 자극하기]

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

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


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




4. URI, URL에 대해서


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


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

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




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


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

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



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


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

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




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



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


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




그림 5. REST Client와 Server 관계


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

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


어노테이션 

기능 

@RestController

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

@ResponseBody

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

@PathVariable

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

@CrossOrigin

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

@RequestBody

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


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

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


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



6. 프로젝트 - 소개


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



그림 6. 프로젝트 구성도


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

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



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



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



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




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



그림 11. REST 전송 방식들


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



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



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



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



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



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





7. 프로젝트 생성


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


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

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

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


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



그림 16. Help의 Eclipse Marketplace



그림 17. Help의 Eclipse Marketplace


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

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


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




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


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



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


Spring MVC Project를 선택한다.

Project Name을 입력한다.

Next를 누른다.



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


패키지명을 입력한다.

Finish를 누른다.




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


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

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



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


프로젝트를 선택한다.

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

"Properties"를 클릭한다.



그림 22. Properties - Build Path


JRE System Library를 선택한다.

Edit를 누른다.

JRE를 클릭한다.

14버전으로 바꿔준다.

Apply를 누른다.



그림 23. Properties - Project Factes


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

Apply를 누른다.

Apply and Close를 누른다.



9. pom.xml 환경설정하기


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

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


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



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


Spring Framework를 클릭한다.



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


5.2.9.RELEASE를 선택한다.




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


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



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


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

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


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



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


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




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


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


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

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

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

<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>

<artifactId>restexample2</artifactId>

<name>restExample2</name>

<packaging>war</packaging>

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

<properties>

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

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

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

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

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

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

</properties>

<dependencies>

<!-- Spring -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

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

<exclusions>

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

<exclusion>

<groupId>commons-logging</groupId>

<artifactId>commons-logging</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-webmvc</artifactId>

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

</dependency>

<!-- AspectJ -->

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjrt</artifactId>

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

</dependency>

<!-- Logging -->

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

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

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

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

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

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-log4j12</artifactId>

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

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.15</version>

<exclusions>

<exclusion>

<groupId>javax.mail</groupId>

<artifactId>mail</artifactId>

</exclusion>

<exclusion>

<groupId>javax.jms</groupId>

<artifactId>jms</artifactId>

</exclusion>

<exclusion>

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

<artifactId>jmxtools</artifactId>

</exclusion>

<exclusion>

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

<artifactId>jmxri</artifactId>

</exclusion>

</exclusions>

<scope>runtime</scope>

</dependency>


<!-- @Inject -->

<dependency>

<groupId>javax.inject</groupId>

<artifactId>javax.inject</artifactId>

<version>1</version>

</dependency>

<!-- Servlet -->

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

<dependency>

    <groupId>javax.servlet</groupId>

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

    <version>4.0.1</version>

    <scope>provided</scope>

</dependency>

<dependency>

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

<artifactId>jsp-api</artifactId>

<version>2.1</version>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

<version>1.2</version>

</dependency>

<!-- Test -->

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.7</version>

<scope>test</scope>

</dependency>       

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

<dependency>

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

    <artifactId>jackson-core</artifactId>

    <version>2.11.2</version>

</dependency>

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

<dependency>

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

    <artifactId>jackson-databind</artifactId>

    <version>2.11.2</version>

</dependency>

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

<dependency>

    <groupId>commons-fileupload</groupId>

    <artifactId>commons-fileupload</artifactId>

    <version>1.4</version>

</dependency>

 

</dependencies>

    <build>

        <plugins>

            <plugin>

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

                <version>2.9</version>

                <configuration>

                    <additionalProjectnatures>

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

                    </additionalProjectnatures>

                    <additionalBuildcommands>

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

                    </additionalBuildcommands>

                    <downloadSources>true</downloadSources>

                    <downloadJavadocs>true</downloadJavadocs>

                </configuration>

            </plugin>

            <plugin>

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

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

                <version>2.5.1</version>

                <configuration>

                    <source>1.6</source>

                    <target>1.6</target>

                    <compilerArgument>-Xlint:all</compilerArgument>

                    <showWarnings>true</showWarnings>

                    <showDeprecation>true</showDeprecation>

                </configuration>

            </plugin>

            <plugin>

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

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

                <version>1.2.1</version>

                <configuration>

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

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>



파일명: pom.xml


[첨부(Attachments)]

pom.zip




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


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

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


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




그림 30. web.xml


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

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

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

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

  <context-param>

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

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

  </context-param>

  <listener>

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

  </listener>

  <servlet>

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

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

    <init-param>

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

      <param-value>

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

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

      </param-value>

    </init-param>

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

  </servlet>

  <servlet-mapping>

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

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

  </servlet-mapping>

  <servlet>

    <description></description>

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

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

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

  </servlet>

  <servlet-mapping>

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

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

  </servlet-mapping>

</web-app>


파일명: web.xml


[첨부(Attachments)]

web.zip



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


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


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



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


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

New-> File을 클릭한다.


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




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


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

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

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

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

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

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

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

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

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

</bean>

</beans>



파일명: spring-file-config.xml


[첨부(Attachments)]

spring-file-config.zip




* 2부에서 만나요.


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


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

https://yyman.tistory.com/1426


반응형
728x90
300x250

[Spring-Framework] 18. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-Java) (3)


이전 글을 보지 않았다면, 꼭 진행해보고 오길 권장한다.


[이전 글]

1. [Spring-Framework] 16. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-Java) (1)
https://yyman.tistory.com/1422


2. [Spring-Framework] 17. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-Java) (2)

https://yyman.tistory.com/1423




22. View - home.jsp


사용자 인터페이스는 아래의 그림처럼 표현하였다.



그림 26. 로그인 전 - "/" 페이지



그림 27. 로그인 후 - "/" 페이지



그림 28. 로그인 후 - 권한별 기능 표시, 계정 정보 출력



그림 29. 로그인 후 - 권한별 기능 표시, 계정 정보 출력



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



<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

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

<%@ page session="false" %>

<html>

<head>

<title>Spring-Security 5 (Java 방식)</title>

<meta charset="UTF-8">

<style>

body{

font-family:'Arial';

font-size:12px;

}


a{

text-decoration:none;

color:#666;

}

</style>

</head>

<body>

<h1>

Hello world!(Spring-Security 5(Java 방식)) - DB연동(Oracle)

</h1>

<hr />

<sec:authorize access="isAnonymous()">

<!-- 로그인 전 -->

<p>

<a href="<c:url value="/member/loginForm" />">로그인</a>

</p>

</sec:authorize> 

<sec:authorize access="isAuthenticated()">

<!-- 로그인 성공 -->

<form:form action="${pageContext.request.contextPath}/logout" method="POST">

<input type="submit" value="로그아웃" />

</form:form>

<p>

<!-- 방법1. Sec 적용(이름 출력) -->

방법(sec 태그)1: <sec:authentication property="name" />

</p>

<p>

<!-- 방법2. c태그, Controller에서 가져오기 -->

방법(Model 정의)2: ${username}

</p>

</sec:authorize> 


<h3>

<!-- 관리자 권한을 가진 경우만 보이기 -->

<sec:authorize access="hasRole('ROLE_ADMIN')" >

<a href="<c:url value="/admin/home" />">관리자 홈</a>&nbsp;&nbsp;

</sec:authorize>

<a href="<c:url value="/encode-password?password=pass" />">비밀번호</a>

</h3>


<!-- 비밀번호 생성기 -->

<c:set var="gene_pwd" value="${encode}" />

<c:if test="${gene_pwd != null}">

    <c:out value="${gene_pwd}" />

</c:if>


</body>

</html>


파일명: home.jsp


[첨부(Attachments)]

home.zip





23. View - admin/home.jsp


관리자 페이지에 관한 것이다.



그림 30. 관리자 페이지


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ page session="false" %>

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

<html>

<head>

<meta charset="UTF-8">

<title>Admin - Page(관리자 - 페이지)</title>

<meta charset="UTF-8">

</head>

<body>

<h1>

Hello world!

</h1>


<P>

<h3>[<a href="<c:url value="/" />">홈으로(Home)</a>]</h3>

</P>

</body>

</html>



파일명: home.jsp


[첨부(Attachments)]

home.zip




24. View - member/loginForm.jsp


로그인 폼에 대한 사용자 인터페이스이다.



그림 31. 로그인 폼 - 로그인 전



그림 32. 로그인 폼 - 로그인 시도(아이디 또는 비밀번호 틀렸을 때)


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

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<!DOCTYPE html>

<html lang="ko">

<head>

<meta charset="UTF-8">

    <title>로그인 - 페이지(Login - Page)</title>

    <style>

    body{

    font-family:'Arial';

    font-size:12px;

    }

    a{

    text-decoration:none;

    color:#666;

    }

    </style>

</head>

<body>


<h1>아이디와 비밀번호를 입력해주세요.</h1>

<hr />


<c:url value="/member/loginForm" var="loginUrl" />

<form:form name="f" action="${loginUrl}" method="POST">

    <p>

        <label for="username">아이디</label>

        <input type="text" id="id" name="id" />

    </p>

    <p>

        <label for="password">비밀번호</label>

        <input type="password" id="password" name="password"/>

    </p>

    <p>

        <label for="remember-me">Remember-me(로그인 상태 유지)</label>

        <input type="checkbox" id="remember-me" name="remember-me"/>

    </p>

    

    <%-- <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> --%>

    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

    <button type="submit" class="btn">로그인</button>

    

    <!-- 에러 메시지 영역 -->

    <c:if test="${param.error != null}">

        <p>아이디와 비밀번호가 잘못되었습니다.</p>

    </c:if>

    <c:if test="${param.logout != null}">

        <p>로그아웃 하였습니다.</p>

    </c:if>


</form:form>

<h3>[<a href="<c:url value="/" />">홈으로(Home)</a>]</h3>


</body>

</html>


파일명: loginForm.jsp


[첨부(Attachments)]

loginForm.zip




25. View - member/accessDenied.jsp


접근 제한 페이지에 관한 소스이다.



그림 33. 접근 제한된 페이지


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

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<!DOCTYPE html>

<html lang="ko">

<head>

    <meta charset="UTF-8">

    <title>Access Denied</title>

</head>

<body>

<h1>Access Denied!</h1>

<h3>[<a href="<c:url value="/" />">홈</a>]</h3>

</body>

</html>


파일명: accessDenied.jsp


[첨부(Attachments)]

accessDenied.zip



26. 맺음글(Conclusion)


Spring Framework 5.4, Spring Security 5.4, Oracle 19g를 활용하여 보안 영역에 대해서 자세하게 살펴보았다.



* 참고 자료(References)


1. Hello Spring Security Java Config, https://docs.spring.io/spring-security/site/docs/5.0.16.RELEASE/guides/html5/helloworld-javaconfig.html#setting-up-the-sample, Accessed by 2020-09-27, Last Modified 2020-05-06.


추천(30점): 공식 사이트에서 제공하는 메뉴얼인데, 제작 흐름을 파악할 수 있다.


2. Tomcat ->Multiple Contexts have a path of 에러, https://kkangdda.tistory.com/12, Accessed by 2020-09-27, Last Modified 2019-11-06.


3. Spring Security 5 – Java Config, https://howtodoinjava.com/spring5/security/security-java-config-enablewebsecurity-example/, Accessed by 2020-09-27, Last Modified 2020-06-19.


추천(50점): June 19, 2020

- 1. @EnableWebSecurity is not found in any of the 3 jars. 

= 2. "spring-security-config-5.0.7.RELEASE", "spring-security-core-5.0.7.RELEASE", "spring-security-web-5.0.7.RELEASE", 

     - June 19, 2020, Spring version is 5.2.5


4. Spring 4.0 + Java Config - web.xml 없애기..., https://tiveloper.tistory.com/entry/Spring-40-Java-Config-webxml-없애기, 2014-10-24

추천(20점): 조금 코드가 바뀐 부분이 있다. 

public class WebInitializer implements WebApplicationInitializer { }
= 이 부분 클래스가 동작하지 않음. (변동 사항이 있었음.)
   - 2013년 12월 정도에 Spring 4.0이 출시되었으니깐 오래되었다고 봐도 됨.


5.Spring Security : Web MVC + Security - Custom Login Form 만들기, https://kogle.tistory.com/78?category=870263, Accessed by 2020-09-27, Last Modified 2020-05-16.


추천(25점): 커스텀 로그인 페이지 java 버전에 대해서 간결하게 잘 작성되어 있음. (그러나 태스트를 해본 바로는 완벽하게 동작하진 않음.)


6. Spring Security Authentication Provider, https://www.baeldung.com/spring-security-authentication-provider, Accessed by 2020-09-27, Last Modified 2020-08-19.


추천(40점): 국내 자료에는 "CustomAuthenticationProvider()"에 대해서 자세히 잘 적어놓은 글을 찾기 힘들었음.

- shouldAuthenticateAgainstThirdPartySystem()가 동작되지는 않았지만, 많은 도움이 되었음.


6.Spring Security - 인증 절차 인터페이스 구현 (1) UserDetailsService, UserDetails, https://to-dy.tistory.com/86?category=720806, Accessed by 2020-09-27, Last Modified 2018.


추천(25점): 인증 절차(쉽게 소개하면, "DB처리에 대한 방법과 과정")에 대해서 잘 작성하였음.

- iBatis(MyBatis)로 작성되어 있긴 한데, 구현 원리를 살펴볼 수 있었음.


7.How to refer brcypt encoder to customized authentication provider?, https://stackoverflow.com/questions/35900053/how-to-refer-brcypt-encoder-to-customized-authentication-provider, Accessed by 2020-09-27, Last Modified 2016.


추천(13점): customized authentication provider에 대해서 구현 원리와 암호 처리 등에 대해서 소개하고 있다.

이 글에서 알 수 있었던 중요한 부분은 Spring Security 5.4로 구현하면서 암호가 랜덤으로 처리되는 것을 확인하였는데, 암호 확인하는 방법을 찾던 도중에 Bcrypt 함수 내에 확인하는 함수가 있는 것을 알게 되었다.


8. [Spring/Security] 초보자가 이해하는 Spring Security, https://postitforhooney.tistory.com/entry/SpringSecurity-%EC%B4%88%EB%B3%B4%EC%9E%90%EA%B0%80-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-Spring-Security-%ED%8D%BC%EC%98%B4, Accessed by 2020-09-27, Last Modified 2017-03-31.


9. [SPRING SECURITY] 4.스프링 시큐리티 로그인 커스터마이징, https://debugdaldal.tistory.com/89, Accessed by 2020-09-27, Last Modified 2016.

추천(15점): 자바 기반으로 커스터마이징 구현하는 방법에 대해서 소개되어 있다.


10. Spring Security Custom AuthenticationProvider example, https://javaengine.tistory.com/entry/Spring-Security-Custom-AuthenticationProvider-example, Accessed by 2020-09-27, Last Modified 2017-02-06.

추천(20점): Spring Security with Java 프로젝트 환경설정만 잘 되어 있다면, 시도해봐도 괜찮은 글이다.


11. Spring Security Remember Me, https://www.baeldung.com/spring-security-remember-me, Accessed 2020-09-27, Last Modified 2020-08-15.

추천(15점): 로그인 유지 및 자동 로그인에 관한 자바 버전으로 구현하는 방법에 대해서 소개하고 있다.
쿠키 제거하고 몇 가지 간단한 사용방법만 소개하고 있다.


12. 6 Spring Security - Access Denied Handler(error page 처리), https://jungeunlee95.github.io/java/2019/07/18/6-Spring-Security-Access-Denied-Handler(errorpage-%EC%B2%98%EB%A6%AC)/, Accessed by 2020-09-27, Last Modified 2019-7-18.

-> 비고: 접근 제어 페이지에 대해서 소개하고 있음.


13. 3 Spring Security - Authorization(권한) 설정(ROLE), TagLib authorize 추가, https://jungeunlee95.github.io/java/2019/07/18/3-SpringSecurity-Authorization(%EA%B6%8C%ED%95%9C)-%EC%84%A4%EC%A0%95(ROLE),-TagLib-authorize-%EC%B6%94%EA%B0%80/, Accessed by 2020-09-27, Last Modified 2020-07-18.

-> 비고: 권한별 페이지 꾸리는 방법에 대해서 소개하고 있음.

반응형

+ Recent posts