[Spring] 004 강의노트

배윤석·2022년 7월 5일
0

Spring

목록 보기
4/6

AOP

Apect Orientd Programming
관점 지향 프로그래밍

Apect

공통 관심 (Cross-Cutting Concern)
➡ 보안 / 무결성 검사

핵심 관심 (Core Concern)
➡ 실행해야될 메서드

Advice

적용 시점(이전, 혹은 이후)

시점의 종류

  • Before Advice : 전처리
  • After Advice : 후처리
  • Around Advice : 전/후처리
    ...

Joinpoint

Point = 위치
따라서 Joinpoint는 적용할 위치라는 뜻이 된다.
어디에? 메서드에.
앞에할 것인가? 뒤에할 것인가?

Pointcut

Advice가 어떤 JoinPoint에 사용될 것인지를 지정하는 PointCut 표현식
정규표현식 ➡ 문자열로 조회

참고 블로그 : Spring AOP PointCut 표현식 정리

Weaving

적용시키는 행위

AOP는 용어가 어렵다...
사유? AspectJ 라는 라이브러리가 학자들이 만든 것이기 때문이라고 한다...

ProxyFactoryBean

org.springframework.aop.framework.ProxyFactoryBean

ProxyFactoryBean 은 자바 클래스를 인터셉트 해서 전처리 및 후처리를 할때 사용한다.

그런데 한 가지 특이사항이 있었다.
인터셉트 하는 클래스가 인터페이스 구현 받았다면? java.lang.ClassCastException 이 밸생하게 된다.

Exception in thread "main" java.lang.ClassCastException: class jdk.proxy2.$Proxy5 cannot be cast to class com.exam.aop01.WriteAction (jdk.proxy2.$Proxy5 is in module jdk.proxy2 of loader 'app'; com.exam.aop01.WriteAction is in unnamed module of loader 'app')
	at com.exam.aop01.App.main(App.java:17)

해당 Exception이 발생한 코드는 다음과 같다.

package com.exam.aop01;

public interface BoardAction {
	void execute();
}
package com.exam.aop01;

public class WriteAction implements BoardAction {
	private String writer;
	
	public WriteAction() {
		// TODO Auto-generated constructor stub
		System.out.println("WriteAction() 실행");
	}
	
	public void setWriter(String name) {
		this.writer = name;
	}

	@Override
	public void execute() {
		// TODO Auto-generated method stub
		System.out.println("execute() 시작");
		System.out.println("execute() 종료");
	}
	
	public void execute1() {
		// TODO Auto-generated method stub
		System.out.println("execute1() 실행");
	}
	
	public void execute2() {
		// TODO Auto-generated method stub
		System.out.println("execute2() 실행");
	}
}
package com.exam.aop01.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class BasicAdvice1 implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// TODO Auto-generated method stub
		
		System.out.println("전처리 : 공통 관심 1");
		
		Object rtnObj = invocation.proceed();
		
		System.out.println("후처리 : 공통 관심 1");
		
		return null;
	}
}
package com.exam.aop01.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class BasicAdvice2 implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// TODO Auto-generated method stub
		
		System.out.println("전처리 : 공통 관심 2");
		
		Object rtnObj = invocation.proceed();
		
		System.out.println("후처리 : 공통 관심 2");
		
		return null;
	}
}
<?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 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	
	<bean id="basicAdvice1" class="com.exam.aop01.advice.BasicAdvice1" />
	
	<bean id="pointcutAdvisor1" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="advice" ref="basicAdvice1" />
		<property name="pointcut">
			<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
				<property name="pattern" value=".*execute*.*"></property>
			</bean>
		</property>
	</bean>
	
	<bean id="basicAdvice2" class="com.exam.aop01.advice.BasicAdvice2" />
	
	<bean id="pointcutAdvisor2" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="advice" ref="basicAdvice2" />
		<property name="pointcut">
			<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
				<property name="pattern" value=".*execute*.*"></property>
			</bean>
		</property>
	</bean>
	
	<!-- <bean id="writeAction" class="com.exam.aop01.WriteAction" scope="prototype"/> -->
	<bean id="writeAction" class="com.exam.aop01.WriteAction" scope="prototype">
		<property name="writer" value="홍길동" />
	</bean>
	
	<!-- AOP 적용 -->
	<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="writeAction"></property>
		<property name="interceptorNames">
			<list>
				<value>pointcutAdvisor1</value>
				<value>pointcutAdvisor2</value>
			</list>
		</property>
	</bean>
</beans>
package com.exam.aop01;

import org.springframework.context.support.GenericXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		GenericXmlApplicationContext ctx
		= new GenericXmlApplicationContext("classpath:com/exam/aop01/context.xml");
		
		// 인터셉터 하지 않으면 전처리 및 후처리가 들어가지 않는다.
		//BoardAction action = (BoardAction)ctx.getBean("writeAction");
		
		// 인터셉터 해주면 전처리 및 후처리가 들어간다.
		//BoardAction action = (BoardAction)ctx.getBean("proxy");
		
		//WriteAction  action = (WriteAction)ctx.getBean("writeAction");
		WriteAction  action = (WriteAction)ctx.getBean("proxy");
		
		// Java Source로 처리
		System.out.println("전처리 구간");
		action.execute1();
		action.execute2();
		System.out.println("후처리 구간");
		
		ctx.close();
	}
}

execute1() 과 execute2() 메서드를 추가한 후 App.java에서 ProxyFactoryBean으로 코드를 실행시키면 Exception 이 발생했다.
물론 전처리 및 후처리를 안하는 단순 writeAction으로 실행시키면 Exception 발생이 안되고 정상적으로 실행되긴 한다.

형변환 문제라고 한다.
인터페이스 구현받았을 경우에는 인터페이스로 객체 생성을 해주어야 한다.


Aspect

메서드 실행 속도를 측정

실행속도 측정 예제 - 10:14 경

메서드 System / Date / Calendar
1 ~ 100,000,000의 반복을 수행하는 메서드

package com.exam.aop01;

public class App {
	public static void main(String[] args) {
		long beforeTime = System.currentTimeMillis();
		System.out.println(beforeTime);
		for(int i=1; i<=100000000; i++) {
        	flag
		}
		long afterTime = System.currentTimeMillis();
		System.out.println((afterTime - beforeTime) + " ms");
	}
}

StopWatch

org.springframework.util.StopWatch

Spring에서 지원해주는 속도 측정 기능이 있다.

package com.exam.aop01.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.util.StopWatch;

public class BasicAdvice1 implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// TODO Auto-generated method stub
		
		// 전처리 구간
		String methodName = invocation.getMethod().getName();
		System.out.println(methodName + " 호출 시작");
		
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		
		Object rtnObj = invocation.proceed();
		
		// 후처리 구간
		stopWatch.stop();
		
		System.out.println("처리시간 : " + stopWatch.getTotalTimeSeconds() + " 초");
		
		return null;
	}
}
package com.exam.aop01;

public class ForAction{
	
	public ForAction() {
		// TODO Auto-generated constructor stub
		System.out.println("ForAction() 실행");
	}
	
	public void execute() {
		// TODO Auto-generated method stub
		System.out.println("execute() 실행");
	}
}
<?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 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	
	<bean id="basicAdvice" class="com.exam.aop01.advice.BasicAdvice1" />
	
	<bean id="pointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="advice" ref="basicAdvice" />
		<property name="pointcut">
			<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
				<property name="pattern" value=".*execute.*"></property>
			</bean>
		</property>
	</bean>
	
	<bean id="forAction" class="com.exam.aop01.ForAction" scope="prototype" />
	
	<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="forAction"></property>
		<property name="interceptorNames">
			<list>
				<value>pointcutAdvisor</value>
			</list>
		</property>
	</bean>
</beans>
package com.exam.aop01;

import org.springframework.context.support.GenericXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		GenericXmlApplicationContext ctx
		= new GenericXmlApplicationContext("classpath:com/exam/aop01/context.xml");

		ForAction action = (ForAction)ctx.getBean("proxy");
		
		action.execute();
		
		ctx.close();
	}
}
10:47:42.058 [main] DEBUG o.s.b.f.xml.XmlBeanDefinitionReader - Loaded 4 bean definitions from class path resource [com/exam/aop01/context.xml]
10:47:42.060 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@1d7acb34
10:47:42.096 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'basicAdvice'
10:47:42.107 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'pointcutAdvisor'
10:47:42.153 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'proxy'
ForAction() 실행
10:47:42.187 [main] DEBUG o.s.aop.framework.ProxyFactoryBean - Advice has changed; re-caching singleton instance
execute 호출 시작
execute() 실행
처리시간 : 0.016309210:47:42.283 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@1d7acb34, started on Tue Jul 05 10:47:42 KST 2022

AspectJ

AspectJ를 사용해보자.
선언이 더 간단해진다

시작 전에 라이브러리 추가를 해주자.
나는 Maven으로 프로젝트를 생성했기 때문에

pom.xml 내부, dependencies 에 아래 내용을 추가했다.

<!-- AspectJ -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>1.9.2</version>
</dependency>

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.9.2</version>
</dependency>

Maven Dependencies 에 라이브러리가 추가된 것을 꼭 확인하자.

context.xml에 aop를 사용하기 위한 설정을 해주어야 한다.

<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
</beans>

AspectJ를 활용한 코드 작성

package com.exam.aop01.advice;

import org.aspectj.lang.ProceedingJoinPoint;

public class BasicAdvice1 {
	public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
		
		System.out.println("전처리 : 공통 관심 1");
		
		Object rtnObj = joinPoint.proceed();
		
		System.out.println("후처리 : 공통 관심 1");
		
		return rtnObj;
	}
}

BasicAdvice2는 1과 크게 다를 바가 없기 때문에 패스한다.

package com.exam.aop01;

public class WriteAction{
	
	public WriteAction() {
		// TODO Auto-generated constructor stub
		System.out.println("WriteAction() 실행");
	}
	
	public void execute1() {
		// TODO Auto-generated method stub
		System.out.println("WriteAction execute1() 실행");
	}
	
	public void execute2() {
		// TODO Auto-generated method stub
		System.out.println("WriteAction execute2() 실행");
	}
}

ListAction 또한 WriteAction 과 크게 다를 바가 없어서 패스한다.

<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	<bean id="writeAction" class="com.exam.aop01.WriteAction" scope="prototype"/>
	<bean id="ListAction" class="com.exam.aop01.ListAction" scope="prototype"/>
	
	<bean id="basicAdvice1" class="com.exam.aop01.advice.BasicAdvice1" scope="prototype"/>
	<bean id="basicAdvice2" class="com.exam.aop01.advice.BasicAdvice2" scope="prototype"/>
	
	<!-- AOP 연결 설정 -->
	<aop:config>
		<aop:aspect ref="basicAdvice1">
			<aop:around method="logAround" pointcut="execution(* execute1())"/>
		</aop:aspect>
		
		<aop:aspect ref="basicAdvice2">
			<aop:around method="logAround" pointcut="execution(* execute2())"/>
		</aop:aspect>
	</aop:config>
	
</beans>
package com.exam.aop01;

import org.springframework.context.support.GenericXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		GenericXmlApplicationContext ctx
		= new GenericXmlApplicationContext("classpath:com/exam/aop01/context.xml");
		
		WriteAction writeAction = (WriteAction)ctx.getBean("writeAction");
		ListAction listAction = (ListAction)ctx.getBean("ListAction");

		writeAction.execute1();
		writeAction.execute2();
		
		listAction.execute1();
		listAction.execute2();
		
		ctx.close();
	}
}
11:41:33.909 [main] DEBUG o.s.b.f.xml.XmlBeanDefinitionReader - Loaded 7 bean definitions from class path resource [com/exam/aop01/context.xml]
11:41:33.912 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@4b9e255
11:41:33.936 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
11:41:34.006 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0'
11:41:34.135 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#1'
WriteAction() 실행
ListAction() 실행
전처리 : 공통 관심 1
WriteAction execute1() 실행
후처리 : 공통 관심 1
전처리 : 공통 관심 2
WriteAction execute2() 실행
후처리 : 공통 관심 2
전처리 : 공통 관심 1
ListAction execute1() 실행
후처리 : 공통 관심 1
전처리 : 공통 관심 2
ListAction execute2() 실행
후처리 : 공통 관심 2
11:41:34.263 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@4b9e255, started on Tue Jul 05 11:41:33 KST 2022

AspectJ 전처리와 후처리

package com.exam.aop01;

public class WriteAction {
	
	public WriteAction() {
		// TODO Auto-generated constructor stub
		System.out.println("WriteAction() 실행");
	}
	
	public void execute() {
		// TODO Auto-generated method stub
		System.out.println("WriteAction execute() 실행");
	}
}
package com.exam.aop01.advice;

public class BasicAdvice {
	
	public void before() throws Throwable {
		System.out.println("before() 실행");
	}
	
	public void after() throws Throwable {
		System.out.println("after() 실행");
	}
}
<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	<bean id="writeAction" class="com.exam.aop01.WriteAction" scope="prototype"/>
	
	<bean id="basicAdvice" class="com.exam.aop01.advice.BasicAdvice" scope="prototype"/>
	
	<!-- AOP 연결 설정 -->
	<aop:config>
		<aop:aspect ref="basicAdvice">
			<aop:before method="before" pointcut="execution(* execute())"/>
			<aop:after method="after" pointcut="execution(* execute())"/>
		</aop:aspect>
	</aop:config>
	
</beans>
package com.exam.aop01;

import org.springframework.context.support.GenericXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		GenericXmlApplicationContext ctx
		= new GenericXmlApplicationContext("classpath:com/exam/aop01/context.xml");
		
		WriteAction writeAction = (WriteAction)ctx.getBean("writeAction");

		writeAction.execute();
		
		ctx.close();
	}
}
14:55:30.482 [main] DEBUG o.s.b.f.xml.XmlBeanDefinitionReader - Loaded 5 bean definitions from class path resource [com/exam/aop01/context.xml]
14:55:30.484 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@4b9e255
14:55:30.508 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
14:55:30.578 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0'
14:55:30.695 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#1'
WriteAction() 실행
before() 실행
WriteAction execute() 실행
after() 실행
14:55:30.806 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@4b9e255, started on Tue Jul 05 14:55:30 KST 2022

어노테이션을 사용한 Spring AOP

어노테이션을 사용하려면 POJO 시스템이 있어야한다.
POJO 자바가 뭐나면 advice에 기술을 한다.

그냥 AspectJ 대비 변동사항이 있는데, 라이브러리 수정을 해줘야 한다.

pom.xml에서 수정을 해주자.
아래 내용을 삭제해주면 된다.

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>1.9.2</version>
</dependency>

package com.exam.aop01;

public class WriteAction {
	
	public WriteAction() {
		// TODO Auto-generated constructor stub
		System.out.println("WriteAction() 실행");
	}
	
	public void execute() {
		// TODO Auto-generated method stub
		System.out.println("WriteAction execute() 실행");
	}
}
package com.exam.aop01.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class BasicAdvice1 {
	
	@Around("execution(* execute())")
	public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("전처리 : 공통 관심 1");
		Object rtnObj = joinPoint.proceed();
		System.out.println("후처리 : 공통 관심 1");
		return rtnObj;
	}
}
<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	<bean id="writeAction" class="com.exam.aop01.WriteAction" scope="prototype"/>
	
	<bean id="basicAdvice" class="com.exam.aop01.advice.BasicAdvice1" scope="prototype"/>
	
	<!-- AOP 연결 설정 -->
	<aop:aspectj-autoproxy />
</beans>
package com.exam.aop01;

import org.springframework.context.support.GenericXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		GenericXmlApplicationContext ctx
		= new GenericXmlApplicationContext("classpath:com/exam/aop01/context.xml");
		
		WriteAction writeAction = (WriteAction)ctx.getBean("writeAction");

		writeAction.execute();
		
		ctx.close();
	}
}
14:23:01.561 [main] DEBUG o.s.b.f.xml.XmlBeanDefinitionReader - Loaded 3 bean definitions from class path resource [com/exam/aop01/context.xml]
14:23:01.563 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@1e4a7dd4
14:23:01.584 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
14:23:01.717 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice1.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
WriteAction() 실행
14:23:01.721 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice1.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
14:23:01.722 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice1.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
전처리 : 공통 관심 1
WriteAction execute() 실행
후처리 : 공통 관심 1
14:23:01.960 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@1e4a7dd4, started on Tue Jul 05 14:23:01 KST 2022

어노테이션에서 PointCut을 사용하는 방법

BasicAdvice1로 가자.
아래와 같이 수정해주면 된다.

package com.exam.aop01.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class BasicAdvice1 {
	
	@Pointcut("execution(* execute())")
	private void myTarget() {}
	
	@Around("myTarget()")
	public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("전처리 : 공통 관심 1");
		Object rtnObj = joinPoint.proceed();
		System.out.println("후처리 : 공통 관심 1");
		return rtnObj;
	}
}

어노테이션에서 Advice 여러 개 사용하기

BasicAdvice2 생성 후 context.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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	<bean id="writeAction" class="com.exam.aop01.WriteAction" scope="prototype"/>
	
	<bean id="basicAdvice1" class="com.exam.aop01.advice.BasicAdvice1" scope="prototype"/>
	<bean id="basicAdvice2" class="com.exam.aop01.advice.BasicAdvice2" scope="prototype"/>
	
	<!-- AOP 연결 설정 -->
	<aop:aspectj-autoproxy />
</beans>

어노테이션에서 전처리와 후처리 동시에 해주기

BasicAdvice2 를 아래와 같이 수정하자

package com.exam.aop01.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class BasicAdvice2 {
	
	@Pointcut("execution(* execute())")
	private void myTarget() {}
	
	@Around("myTarget()")
	public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("전처리 : 공통 관심 2");
		Object rtnObj = joinPoint.proceed();
		System.out.println("후처리 : 공통 관심 2");
		return rtnObj;
	}
	
	@Before("execution(* execute())")
	public void before() {
		System.out.println("전처리");
	}
	
	@After("execution(* execute())")
	public void after() {
		System.out.println("후처리");
	}
}

실행 결과는 다음과 같다.

14:34:37.295 [main] DEBUG o.s.b.f.xml.XmlBeanDefinitionReader - Loaded 4 bean definitions from class path resource [com/exam/aop01/context.xml]
14:34:37.299 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@1e4a7dd4
14:34:37.324 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
14:34:37.482 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice1.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
14:34:37.490 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice2.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
14:34:37.491 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.exam.aop01.advice.BasicAdvice2.before()
14:34:37.491 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.exam.aop01.advice.BasicAdvice2.after()
WriteAction() 실행
14:34:37.493 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice1.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
14:34:37.497 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice2.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
14:34:37.497 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.exam.aop01.advice.BasicAdvice2.before()
14:34:37.497 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.exam.aop01.advice.BasicAdvice2.after()
14:34:37.498 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice1.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
14:34:37.498 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice2.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
14:34:37.499 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.exam.aop01.advice.BasicAdvice2.before()
14:34:37.499 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.exam.aop01.advice.BasicAdvice2.after()
전처리 : 공통 관심 1
전처리 : 공통 관심 2
전처리
WriteAction execute() 실행
후처리
후처리 : 공통 관심 2
후처리 : 공통 관심 1
14:34:37.700 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@1e4a7dd4, started on Tue Jul 05 14:34:37 KST 2022

어노테이션 예제 - 14:21 경

BasicAdvice1 ➡ ListAction(execute)
BasicAdvice2 ➡ WriteAction(execute)

package com.exam.aop01;

public class ListAction {
	
	public ListAction() {
		// TODO Auto-generated constructor stub
		System.out.println("ListAction() 실행");
	}
	
	public void execute() {
		// TODO Auto-generated method stub
		System.out.println("ListAction execute() 실행");
	}
}

WriteAction 은 ListAction 과 구성이 비슷해서 패스.

package com.exam.aop01.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class BasicAdvice1 {
	
	@Pointcut("execution(* com.exam.aop01.ListAction.execute())")
	private void myTarget() {}
	
	@Around("myTarget()")
	public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("전처리 : 공통 관심 1");
		Object rtnObj = joinPoint.proceed();
		System.out.println("후처리 : 공통 관심 1");
		return rtnObj;
	}
}

BasicAdvice2는 Pointcut 부분만 아래와 같이 수정해주면 된다.

@Pointcut("execution(* com.exam.aop01.WriteAction.execute())")
<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	<bean id="writeAction" class="com.exam.aop01.WriteAction" scope="prototype"/>
	<bean id="listAction" class="com.exam.aop01.ListAction" scope="prototype"/>
	
	<bean id="basicAdvice1" class="com.exam.aop01.advice.BasicAdvice1" scope="prototype"/>
	<bean id="basicAdvice2" class="com.exam.aop01.advice.BasicAdvice2" scope="prototype"/>
	
	<!-- AOP 연결 설정 -->
	<aop:aspectj-autoproxy />
</beans>
package com.exam.aop01;

import org.springframework.context.support.GenericXmlApplicationContext;

public class App {
	public static void main(String[] args) {
		GenericXmlApplicationContext ctx
		= new GenericXmlApplicationContext("classpath:com/exam/aop01/context.xml");
		
		ListAction listAction = (ListAction)ctx.getBean("listAction");
		WriteAction writeAction = (WriteAction)ctx.getBean("writeAction");
		
		listAction.execute();
		writeAction.execute();
		
		ctx.close();
	}
}

어노테이션에서 xml 사용안해보기?

package com.exam.aop01.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Scope;

import com.exam.aop01.WriteAction;
import com.exam.aop01.advice.BasicAdvice1;
import com.exam.aop01.advice.BasicAdvice2;

@Configuration
@Scope("prototype")
@EnableAspectJAutoProxy
public class BeanConfig {
	
	@Bean
	public WriteAction writeAction() {
		return new WriteAction();
	}
	
	@Bean
	public BasicAdvice2 basicAdvice2() {
		return new BasicAdvice2();
	}
}
package com.exam.aop01;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.exam.aop01.config.BeanConfig;

public class App02 {
	public static void main(String[] args) {
		
		AnnotationConfigApplicationContext ctx
		= new AnnotationConfigApplicationContext(BeanConfig.class);

		WriteAction writeAction = (WriteAction)ctx.getBean("writeAction");

		writeAction.execute();
		
		ctx.close();
	}
}
15:25:52.440 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5e57643e
15:25:52.455 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
15:25:52.575 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
15:25:52.577 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
15:25:52.579 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
15:25:52.580 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.aop.config.internalAutoProxyCreator'
15:25:52.655 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'writeAction'
15:25:52.678 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object com.exam.aop01.advice.BasicAdvice2.logAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
WriteAction() 실행
15:25:52.792 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'basicAdvice2'
전처리 : 공통 관심 2
WriteAction execute() 실행
후처리 : 공통 관심 2
15:25:52.821 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5e57643e, started on Tue Jul 05 15:25:52 KST 2022

Spring MVC

참고 블로그 : 스프링 MVC

Spring MVC 만드는 법

  1. Dynamic Web Project + Spring Framework
  2. Maven
  3. Spring Boot
    ➡ 1번과 2번의 관리가 불편하다~ 해서 나온것이다.
    ➡ 편하기는 하지만 생략된 것이 워낙 많기 때문에 스프링 구조를 잘 이해하고 있어야 한다.

각자 사용하는 의도가 있다.
뭐는 절대적으로 쓰이고 어떤 것은 안쓰이고 이러는 것이 아니다.

※ 특이사항 ※
1번은 기존꺼를 스프링 방식으로 변경할 때,
2번과 3번은 처음부터 스프링 방식으로 사용할 때,
사용한다.

list.do ➡ listview1.jsp

<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	<bean name="/list1.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
		<property name="viewName" value="listview1.jsp"></property>
	</bean>
	
</beans>

Back-End Controller

list1.do ➡ ListAction1 ➡ listview1.jsp
list2.do ➡ ListAction2 ➡ listview2.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>
listview1.jsp

<br> <br>

<form action="list2.do" method="get">
데이터 <input type="text" name="data">
<input type="submit" value="전송">
</form>

<form action="list2.do" method="post">
데이터 <input type="text" name="data">
<input type="submit" value="전송">
</form>

</body>
</html>
<%@ 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>
listview2.jsp
<br>
data : <%=request.getAttribute("data") %>
data : ${ data }
</body>
</html>
<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	
	<bean name="/list1.do" class="model2.ListAction1"></bean>
	<bean name="/list2.do" class="model2.ListAction2"></bean>
	 
	 
	<!-- 통합해서 사용하기 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />
	</bean>
	
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
	id="WebApp_ID" version="4.0">
	<display-name>SpringEx01</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.jsp</welcome-file>
		<welcome-file>default.htm</welcome-file>
	</welcome-file-list>
	
	<!-- 각 model2 Page 마다 문자열 인코딩 형식 지정해주는 것보다는 xml에서 한번에 필터처리하는 것이 편하다. -->
	<!-- 다국어 필터 적용! -->
	<!-- 일반적인 MVC 모델에서는 필터를 만들어줘야 한다. -->
	<!-- 그런데 Spring에서는 필터가 이미 만들어져 있다. 따라서 적용만 해주면 된다. -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>
	
	<!-- DispatcherServlet(Front Controller) -->
	<servlet>
		<servlet-name>servlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>servlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>
package model2;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class ListAction1 implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("ListAction1 호출");
		
		//return new ModelAndView("listview1");
		
		// 인스턴스화 해서 넘겨줄 수도 있다.
		//ModelAndView modelAndView = new ModelAndView("listview1");
		//return modelAndView;
		
		// 이렇게 사용해도 된다.
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("listview1");
		return modelAndView;
	}

}
package model2;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class ListAction2 implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		arg0.setCharacterEncoding("UTF-8");
		
		System.out.println("ListAction2 호출");
		
		System.out.println(arg0.getParameter("data"));
		
		//return new ModelAndView("listview2");
		
		ModelAndView modelAndView = new ModelAndView();
		// 전통적으로 데이터를 옮기는 방식
		//arg0.setAttribute("data", arg0.getParameter("data"));
		
		// ModelAndView로 데이터를 옮기는 방식
		modelAndView.addObject("data", arg0.getParameter("data"));
		
		modelAndView.setViewName("listview2");
		return modelAndView;
	}
}

실행결과


데이터 전송

write.do ➡ WriteAction ➡ /WEB-INF/views/write.jsp
write_ok.do ➡ WriteOkAction ➡ /WEB-INF/views/write_ok.jsp

write.do ➡ write_ok.do 데이터 보내는 순서

  1. index.jsp 에서 들어갈 URL 경로를 링크로 지정해준다.
    해당 항목은 없어도 무방하며 주소창에 직접 입력해도 상관없음.
  2. write.do 라는 경로가 주소창에 입력된다.
  3. dispatcher-servlet.xml 에서 write.do 라는 주소가 입력된걸 감지하면 model2 패키지의 WriteAction 클래스를 실행시킨다.
  4. WriteAction.java 에서 전처리 및 후처리를 해주고 ModelAndView 객체를 사용하여 write를 리턴한다.
  5. Bean에 의해 리턴된 write 에 property의 suffix를 사용하여 후미에 .jsp를 붙여준다.
    실행 경로는 property의 prefix에 나와있는 /WEB-INF/views/ 를 가져오도록 한다.
  6. write.jsp 가 실행되기 전, web.xml에 의해서 .do 로 끝나는 주소는 필터가 적용된다.
    필터의 내용은, 문자열을 UTF-8 방식으로 인코딩해주는 것이다.(다국어 필터)
  7. 이제 실행된 write.jsp 파일의 form에 데이터를 입력하고 전송을 눌러준다.
    이때, 데이터를 get 방식으로 보낼지? post 방식으로 보낼지는 사용자가 선택하여 보낸다.
  8. submit 이 활성화되면, form의 action에 입력된 write_ok.do 주소로 data라는 이름으로 데이터를 보내고 화면을 이동시킨다.
  9. dispatcher-servlet.xml 에서 write_ok.do 라는 주소가 입력된걸 감지하면 model2 패키지의 WriteOkAction 클래스를 실행시킨다.
  10. WriteOkAction.java 에서 전처리 및 후처리를 해주고 ModelAndView 객체를 사용하여 write_ok를 리턴한다.
  11. Bean에 의해 리턴된 write_ok 에 property의 suffix를 사용하여 후미에 .jsp를 붙여준다.
    실행 경로는 property의 prefix에 나와있는 /WEB-INF/views/ 를 가져오도록 한다.
  12. write_ok.jsp 가 실행되기 전, web.xml에 의해서 .do 로 끝나는 주소는 필터가 적용된다.
    필터의 내용은, 문자열을 UTF-8 방식으로 인코딩해주는 것이다.(다국어 필터)
  13. JSP의 자바 스크립틀릿으로 data라는 이름의 데이터를 받아 표시한다.
  14. 이때의 출력은 브라우저 상에 표시된다.
package model2;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class WriteAction implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("WriteAction 호출");
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("write");
		return modelAndView;
	}
}
package model2;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class WriteOkAction implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		arg0.setCharacterEncoding("UTF-8");
		
		System.out.println("WriteOkAction 호출");
		
		System.out.println(arg0.getParameter("data"));
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("data", arg0.getParameter("data"));
		modelAndView.setViewName("write_ok");
		return modelAndView;
	}
}
<%@ 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>
write.jsp

<br> <br>

<form action="write_ok.do" method="get">
데이터 <input type="text" name="data">
<input type="submit" value="전송">
</form>

<form action="write_ok.do" method="post">
데이터 <input type="text" name="data">
<input type="submit" value="전송">
</form>

</body>
</html>
<%@ 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>
write_ok.jsp
<br>
<hr>
data : <%=request.getAttribute("data") %>
<br>
data : ${ data }
<br>
<a href="javascript:history.back()">index.jsp</a>
</body>
</html>
<%@ 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>
Hello Spring MVC
<br><br>
<ul>
	<li><a href="write.do">write.do</a></li>
</ul>
</body>
</html>
<?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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	
	<bean name="/write.do" class="model2.WriteAction"></bean>
	<bean name="/write_ok.do" class="model2.WriteOkAction"></bean>
	 
	<!-- 통합해서 사용하기 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />
	</bean>
	
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
	id="WebApp_ID" version="4.0">
	<display-name>SpringEx01</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.jsp</welcome-file>
		<welcome-file>default.htm</welcome-file>
	</welcome-file-list>
	
	<!-- 다국어 필터 적용! -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>
	
	<!-- DispatcherServlet(Front Controller) -->
	<servlet>
		<servlet-name>servlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>servlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>

결과는 다음과 같다.

profile
차근차근 한 걸음씩 걸어나가는 개발자 꿈나무.

0개의 댓글