1. Spring AOP(Aspect Oriented Programming)
1) 핵심관점(=핵심기능)
: 객체지향 프로그래밍에서 각 객체안에는 중요한 기능들로 구성되어 있고
AOP에서는 이러한 주요기능을 핵심관점(=핵심기능)이라고 한다.
2) Cross-Cutting Concern(횡단관점, 공통기능)
: 핵심기능들을 잘 살펴보면 각 핵심기능들 전반에 걸쳐있는 공통적인 기능들이 있고
AOP에서는 이러한 공통적인 것들을 횡단관점, 횡단관심사, Aspect라고 한다.
2. AOP(Aspect Oriented Programming)의 목적
: 프로그래머 들의 관심(concern)사를 핵심기능으로부터 분리
즉, Separation of Cross-Cutting Concern
결국, AOP는 개발자의 염두(concern)사항을 별도의 관심사(Aspect)로 분리해내어
코드 개발시 핵심기능에 더 집중할 수 있게 한다.
3. 간단한 AOP 용어 정리
1) AOP
** 기존의 코드(핵심코드)를 수정하지 않고도 원하는 공통관심사(cross-concern)와 핵심코드를 엮는(weaving) 기술
** 즉 엮는다(weaving)는 AOP의 기본 동작
2) Target
** 공통코드와 관심코드가 분리된 핵심코드를 가지고 있는 객체
** 스프링 AOP에서 실체는 클래스
3) Proxy
** Target을 감싸고 있다
** Target 호출 코드가 수행될 때면, Target을 호출하기 전이나 후, 혹은 중간에 Advice를 weaving하여 실행
** 스프링AOP 에서 실체는 객체(수동생성, 혹은 Auto-proxy 자동생성)
4) JoinPoint
** Target 객체가 가진 메소드
** Proxy가 Advice를 weaving 주는 대상
** 스프링 AOP에서 실체는 메소드
5) Advice
** 삽입되어 엮어지는 코드
** 즉, 공통코드와 관심코드
** 스프링 AOP에서 실체는 메소드
6) Weaving
** Proxy가 PointCut 설정에 따라 JoinPoint가 호출될 때마다 Advice를 엮어서 실행해주는 동작
** 스프링 AOP에서 실체는 Proxy의 동작
7) Pointcut
** Advice가 어느 JoinPoint(들)에 적용될지 설정
** 스프링 AOP에서 실체는 설정(@어노테이션 혹은 XML)
8) Advisor
** Advice + Pointcut
** 스프링 AOP에서 실체는 메소드 + @어노테이션
9) Aspect
** 공통관점 사항들의 집합
** 즉, Advisor들을 모아놓은 객체
** 스프링 AOP에서 실체는 클래스
4. Spring에서 AOP 프로그래밍 구현 방법
방법1) XML 설정으로 구현
방법2) @Aspect 와 같은 어노테이션들로 구현 (*추천*)
5. STS07_AOP1, [방법1] XML 설정으로 구현
** AOP 관련 dependency 설정 필요 : pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>STS07_AOP</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>3.2.3.RELEASE</spring-framework.version>
<!-- Hibernate / JPA -->
<hibernate.version>4.2.1.Final</hibernate.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<!-- Test -->
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- spring AOP -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
</dependencies>
</project>
[추가] 직접 타이핑해도 되나 https://mvnrepository.com 사이트의 도움 받아도 된다.
1) spring-context-support
2) spring-aop
3) aspectjweaver
[추가] spring-context-support, spring-aop는 spring-core와 버전이 같아야 한다.
만약 버전이 다르면 ClassNotFoundException 발생
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>
** pom.xml 선택 후 우클릭 > Maven > Update Maven Project
** [src/main/java] com.lec.beans > abstract Service.java
package com.lec.beans;
public abstract class Service {
public abstract void doAction(); // 추상메소드
// 테스트용 : 메소드 호출정보 출력
public void printInfo() {
String className = this.getClass().getSimpleName();
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
String methodName = stackTrace[1].getMethodName();
System.out.println(className + " 의 " + methodName + "() 호출");
}
}
** [src/main/java] com.lec.beans > Logger.java
package com.lec.beans;
// log in / log out 동작과 같은
// 공통기능 / 관심기능(concern) 이 담긴 객체
// 나중에 Advice 로 사용되는 코드
public class Logger {
public void logIn() {
System.out.println("## 로그인 처리 ##");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void logOut() {
System.out.println("## 로그아웃 처리 ##");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
** [src/main/java] com.lec.spring.aop01 > MyService11.java
package com.lec.spring.aop01;
import com.lec.beans.Logger;
import com.lec.beans.Service;
public class MyService11 extends Service {
// 관심사(공통기능) 코드가 함께 섞여 있는 경우.
@Override
public void doAction() {
new Logger().logIn(); // 공통기능
// 핵심기능
System.out.println("MyService11 의 doAction()");
new Logger().logOut(); // 공통기능
}
}
** [src/main/java] com.lec.spring.aop01 > MyService12.java
package com.lec.spring.aop01;
import com.lec.beans.Logger;
import com.lec.beans.Service;
public class MyService12 extends Service {
// 관심사(공통기능) 코드가 함께 섞여 있는 경우.
@Override
public void doAction() {
new Logger().logIn(); // 공통기능
// 핵심기능
System.out.println("MyService12 의 doAction()");
new Logger().logOut(); // 공통기능
}
}
** [src/main/resources] aopCtx1.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="service1" class="com.lec.spring.aop01.MyService11"/>
<bean name="service2" class="com.lec.spring.aop01.MyService12"/>
</beans>
** [src/main/java] com.lec.spring.aop01 > AopMain01.java
package com.lec.spring.aop01;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.lec.beans.*;
public class AopMain01 {
public static void main(String[] args) {
System.out.println("Main 시작");
AbstractApplicationContext ctx =
new GenericXmlApplicationContext("classpath:aopCtx1.xml");
System.out.println("ctx생성");
Service service1 = ctx.getBean("service1", Service.class);
Service service2 = ctx.getBean("service2", Service.class);
service1.doAction(); // 핵심코드
System.out.println();
service2.doAction(); // 핵심코드
System.out.println();
ctx.close();
System.out.println("Main 종료");
} // end main()
} // end class
** [src/main/java] com.lec.spring.aop02 > MyService21.java
package com.lec.spring.aop02;
import com.lec.beans.Service;
public class MyService21 extends Service {
@Override
public void doAction() {
// 공통 기능 없다??
printInfo(); // 핵심 기능
}
public void hahaha() {
System.out.println("hahaha");
}
}
** [src/main/java] com.lec.spring.aop02 > MyService22.java
package com.lec.spring.aop02;
import com.lec.beans.Service;
public class MyService22 extends Service {
@Override
public void doAction() {
// 공통 기능 없다??
printInfo(); // 핵심 기능
}
}
** [src/main/java] com.lec.spring.aop02 > LogAspect.java
package com.lec.spring.aop02;
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;
import com.lec.beans.Logger;
// Aspect : Advisor 들을 모아놓은 객체
// Advisor : Advice + Pointcut
// Advice : 공통 기능
// 첫번째 방법. 어노테이션 사용
// ↓ 이 클래스가 Aspect 역할을 할 클래스 임을 명시
@Aspect
public class LogAspect {
@Pointcut("within(com.lec.spring.aop02.*)")
public void pc1() {}
@Pointcut("within(com.lec.spring.aop02.*)")
public void pc2() {}
//@Before("within(com.lec.spring.aop02.*)") // Pointcut
@Before("pc1()")
public void beforAdvice() {
System.out.print("[Before] ");
new Logger().logIn(); // 공통코드. Advice!
}
//@After("within(com.lec.spring.aop02.*)") // Pointcut
//@After("execution(* com.lec.spring.aop02.MyService22.*(..))")
//@After("pc2()")
@After("execution(* com.lec.spring.aop02.*2.*(..))")
public void afterAdvice() {
System.out.print("[After] ");
new Logger().logOut();
}
// Around advice : 메소드 실행을 제어하는 가장 강력한 코드
// 직접 해당 메소드를 호출하고 결과나 예외처리도 가능.
@Around("within(com.lec.spring.aop02.*)")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
// joinPoint 메소드 이름
String signatureStr = joinPoint.getSignature().toShortString();
// joinPoint 메소드 수행전
System.out.println("[Around] " + signatureStr + " 시작");
long st = System.currentTimeMillis(); // 시작시간 기록
try {
// joinPoint 메소드 수행
Object obj = joinPoint.proceed();
return obj;
} finally {
// joinPoint 메소드 수행후
long et = System.currentTimeMillis(); // 종료시간 기록
System.out.println("[Around] " + signatureStr + " 종료, 경과시간: " + (et - st));
}
} // end aroundAdvice()
}
** [src/main/resources] aopCtx2.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- Proxy 객체 자동생성, @Aspect 있는 빈 객체들을 찾아서 공통 기능으로 등록 -->
<aop:aspectj-autoproxy/>
<bean id="logAop" class="com.lec.spring.aop02.LogAspect"/>
<bean name="service21" class="com.lec.spring.aop02.MyService21"/>
<bean name="service22" class="com.lec.spring.aop02.MyService22"/>
</beans>
[추가] Namespaces에서 aop와 context 추가하기
** [src/main/java] com.lec.spring.aop02 > AopMain02.java
package com.lec.spring.aop02;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.lec.beans.*;
public class AopMain02 {
public static void main(String[] args) {
System.out.println("Main 시작");
AbstractApplicationContext ctx =
new GenericXmlApplicationContext("classpath:aopCtx2.xml");
System.out.println("ctx 생성");
Service service21 = ctx.getBean("service21", Service.class);
Service service22 = ctx.getBean("service22", Service.class);
service21.doAction();
System.out.println();
service22.doAction();
System.out.println();
((MyService21)service21).hahaha();
ctx.close();
System.out.println("Main 종료");
} // end main
} // end class
** [src/main/java] com.lec.beans > abstract ServiceEx.java
package com.lec.beans;
public abstract class ServiceEx extends Service {
public abstract void doWorking();
public abstract void quitAction();
}
** [src/main/java] com.lec.spring.aop03 > MyServiceEx31.java
package com.lec.spring.aop03;
import com.lec.beans.ServiceEx;
public class MyServiceEx31 extends ServiceEx {
@Override
public void doWorking() {printInfo();}
@Override
public void quitAction() {printInfo();}
@Override
public void doAction() {printInfo();}
}
** [src/main/java] com.lec.spring.aop03 > MyServiceEx32.java
package com.lec.spring.aop03;
import com.lec.beans.ServiceEx;
public class MyServiceEx32 extends ServiceEx {
@Override
public void doWorking() {printInfo();}
@Override
public void quitAction() {printInfo();}
@Override
public void doAction() {printInfo();}
}
** [src/main/java] com.lec.spring.aop03 > LogAspect3.java
package com.lec.spring.aop03;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class LogAspect3 {
@Pointcut("within(com.lec.spring.aop03.*)")
public void pc1() {}
@Pointcut("within(com.lec.spring.aop02.*)")
public void pc2() {}
@Pointcut("execution(* com.lec.spring.aop*.My*.*Action(..))")
public void pc3() {}
@Pointcut("execution(* com.lec.spring.*3.My*.do*(..))")
public void pc4() {}
//@Before("pc1()") // 3, 4, 5, 6, 7, 8
//@Before("pc2()") // 1, 2
//@Before("pc3()") // 1, 2, 3, 5, 6, 8
//@Before("pc4()") // 3, 4, 6, 7
//@Before("pc1() || pc2()") // 1, 2, 3, 4, 5, 6, 7, 8
//@Before("pc1() && pc2()") // 없음
//@Before("!pc1()") // 1, 2
//@Before("pc3() && !pc4()") // 1, 2, 5, 8
@Before("!(pc3() && pc4())") // 1, 2, 4, 5, 7, 8
public void beforeAdvice() {
System.out.print("[Advice] ");
}
}
** [src/main/resources] aopCtx3.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<aop:aspectj-autoproxy/>
<bean id="logAop" class="com.lec.spring.aop03.LogAspect3"/>
<bean name="service21" class="com.lec.spring.aop02.MyService21"/>
<bean name="service22" class="com.lec.spring.aop02.MyService22"/>
<bean name="serviceEx31" class="com.lec.spring.aop03.MyServiceEx31"/>
<bean name="serviceEx32" class="com.lec.spring.aop03.MyServiceEx32"/>
</beans>
** [src/main/java] com.lec.spring.aop03 > AopMain03.java
package com.lec.spring.aop03;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.lec.beans.*;
public class AopMain03 {
public static void main(String[] args) {
System.out.println("Main 시작");
AbstractApplicationContext ctx =
new GenericXmlApplicationContext("classpath:aopCtx3.xml");
System.out.println("ctx생성");
Service service21 = ctx.getBean("service21", Service.class);
Service service22 = ctx.getBean("service22", Service.class);
ServiceEx serviceEx31 = ctx.getBean("serviceEx31", ServiceEx.class);
ServiceEx serviceEx32 = ctx.getBean("serviceEx32", ServiceEx.class);
service21.doAction(); // 1
service22.doAction(); // 2
serviceEx31.doAction(); // 3
serviceEx31.doWorking(); // 4
serviceEx31.quitAction(); // 5
serviceEx32.doAction(); // 6
serviceEx32.doWorking(); // 7
serviceEx32.quitAction(); // 8
ctx.close();
System.out.println("Main 종료");
} // end main
} // end class
6. PointCut expression
: PointCut 설정에 사용되는 구문을 PointCut 표현식(expression)이라 하며 다양한 방법으로 지정 가능하다.
7. PointCut 표현식 구문
: PCD(AspectJ 표현식)
8. PCD(PointCut Designator)의 종류
** execution : 메소드를 기준으로 PointCut 설정
** within : 특정한 클래스 기준으로 PointCut 설정
** this : 주어진 인터페이스를 구현한 객체를 대상으로 PointCut 설정
** args : 특정한 매개변수를 가지는 대상으로 PointCut 설정
** @annotation : 특정한 어노테이션이 적용된 대상으로 PointCut 설정
** @target : 클래스에 특정 어노테이션이 있는 경우 PointCut 설정
** @args : 매개변수에 특정 어노테이션이 적용된 경우 PointCut 설정
9. STS08_AOP2[방법2] @Aspect 와 같은 어노테이션들로 구현 (*추천*)
** AOP 관련 dependency 설정 : pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>STS08_AOP2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>3.2.3.RELEASE</spring-framework.version>
<!-- Hibernate / JPA -->
<hibernate.version>4.2.1.Final</hibernate.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<!-- Test -->
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- spring AOP -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
</dependencies>
</project>
** pom.xml 선택 후 우클릭 > Maven > Update Maven Project 클릭
** [arc/main/java] com.lec.beans > Logger.java
package com.lec.beans;
// log in / log out 동작과 같은
// 공통기능 / 관심기능(concern) 이 담긴 객체
// 나중에 Advice 로 사용되는 코드
public class Logger {
public void logIn() {
System.out.println("## 로그인 처리 ##");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void logOut() {
System.out.println("## 로그아웃 처리 ##");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void logAdvice() {
System.out.print("[Advice]");
}
}
** [arc/main/java] com.lec.beans > Service.java
package com.lec.beans;
public abstract class Service {
public abstract void doAction(); // 추상메소드
// 테스트용 : 메소드 호출정보 출력
public void printInfo() {
String className = this.getClass().getSimpleName();
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
String methodName = stackTrace[1].getMethodName();
System.out.println(className + " 의 " + methodName + "() 호출");
}
}
** [arc/main/java] com.lec.spring.sop01 > MyService11.java
package com.lec.spring.aop01;
import com.lec.beans.Logger;
import com.lec.beans.Service;
public class MyService11 extends Service {
// 관심사(공통기능) 코드가 함께 섞여 있는 경우.
@Override
public void doAction() {
new Logger().logIn(); // 공통기능
// 핵심기능
System.out.println("MyService11 의 doAction()");
new Logger().logOut(); // 공통기능
}
}
** [arc/main/java] com.lec.spring.sop01 > MyService12.java
package com.lec.spring.aop01;
import com.lec.beans.Logger;
import com.lec.beans.Service;
public class MyService12 extends Service {
// 관심사(공통기능) 코드가 함께 섞여 있는 경우.
@Override
public void doAction() {
new Logger().logIn(); // 공통기능
// 핵심기능
System.out.println("MyService12 의 doAction()");
new Logger().logOut(); // 공통기능
}
}
** [arc/main/resources] aopCtx1.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="service1" class="com.lec.spring.aop01.MyService11"/>
<bean name="service2" class="com.lec.spring.aop01.MyService12"/>
</beans>
** [arc/main/java] com.lec.spring.aop01 > AopMain01.java
package com.lec.spring.aop01;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.lec.beans.*;
public class AopMain01 {
public static void main(String[] args) {
System.out.println("Main 시작");
AbstractApplicationContext ctx =
new GenericXmlApplicationContext("classpath:aopCtx1.xml");
System.out.println("ctx생성");
Service service1 = ctx.getBean("service1", Service.class);
Service service2 = ctx.getBean("service2", Service.class);
service1.doAction(); // 핵심코드
System.out.println();
service2.doAction(); // 핵심코드
System.out.println();
ctx.close();
System.out.println("Main 종료");
} // end main()
} // end class
** [src/main/java] com.lec.spring.aop02 > MyService21.java
package com.lec.spring.aop02;
import com.lec.beans.Service;
public class MyService21 extends Service {
@Override
public void doAction() {
// 공통 기능 없다??
printInfo(); // 핵심 기능
}
public void hahaha() {
System.out.println("hahaha");
}
}
** [src/main/java] com.lec.spring.aop02 > MyService22.java
package com.lec.spring.aop02;
import com.lec.beans.Service;
public class MyService22 extends Service {
@Override
public void doAction() {
// 공통 기능 없다??
printInfo(); // 핵심 기능
}
}
** [src/main/resources] aopCtx2.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- 공통 기능 클래스를 빈 객체로 생성 -->
<bean id="logger" class="com.lec.beans.Logger"/>
<bean name="service21" class="com.lec.spring.aop02.MyService21"/>
<bean name="service22" class="com.lec.spring.aop02.MyService22"/>
<aop:config>
<!-- config 안에 aspect 들을 설정 -->
<aop:aspect id="logAspect1" ref="logger">
<!-- aspect의 pointcut 설정 -->
<aop:pointcut expression="within(com.lec.spring.aop02.*)" id="pc1"/>
<!-- aspect의 advice 설정 -->
<aop:before pointcut-ref="pc1" method="logIn"/>
</aop:aspect>
<aop:aspect id="logAspect2" ref="logger">
<aop:after pointcut-ref="pc1" method="logOut"/>
</aop:aspect>
</aop:config>
</beans>
** [src/main/java] com.lec.spring.aop02 > AopMain02.java
package com.lec.spring.aop02;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.lec.beans.*;
public class AopMain02 {
public static void main(String[] args) {
System.out.println("Main 시작");
AbstractApplicationContext ctx =
new GenericXmlApplicationContext("classpath:aopCtx2.xml");
System.out.println("ctx 생성");
Service service21 = ctx.getBean("service21", Service.class);
Service service22 = ctx.getBean("service22", Service.class);
service21.doAction();
System.out.println();
service22.doAction();
System.out.println();
((MyService21)service21).hahaha();
ctx.close();
System.out.println("Main 종료");
} // end main
} // end class
** [src/main/java] com.lec.beans > ServiceEx.java
package com.lec.beans;
public abstract class ServiceEx extends Service {
public abstract void doWorking();
public abstract void quitAction();
}
** [src/main/java] com.lec.spring.aop03 > MyService31.java
package com.lec.spring.aop03;
import com.lec.beans.ServiceEx;
public class MyServiceEx31 extends ServiceEx {
@Override
public void doWorking() {printInfo();}
@Override
public void quitAction() {printInfo();}
@Override
public void doAction() {printInfo();}
}
** [src/main/java] com.lec.spring.aop03 > MyService32.java
package com.lec.spring.aop03;
import com.lec.beans.ServiceEx;
public class MyServiceEx32 extends ServiceEx {
@Override
public void doWorking() {printInfo();}
@Override
public void quitAction() {printInfo();}
@Override
public void doAction() {printInfo();}
}
** [src/main/resources] aopCtx03.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<bean id="logger" class="com.lec.beans.Logger"/>
<bean name="service21" class="com.lec.spring.aop02.MyService21"/>
<bean name="service22" class="com.lec.spring.aop02.MyService22"/>
<bean name="serviceEx31" class="com.lec.spring.aop03.MyServiceEx31"/>
<bean name="serviceEx32" class="com.lec.spring.aop03.MyServiceEx32"/>
<aop:config>
<aop:pointcut expression="within(com.lec.spring.aop03.*)" id="pc1"/>
<aop:pointcut expression="within(com.lec.spring.aop02.*)" id="pc2"/>
<aop:pointcut expression="execution(* com.lec.spring.aop*.My*.*Action(..))" id="pc3"/>
<aop:pointcut expression="execution(* com.lec.spring.*3.My*.do*(..))" id="pc4"/>
<aop:aspect id="logAspect3" ref="logger">
<!-- pc1 ~ pc4까지 적용해보기 -->
<!--
<aop:before method="logAdvice" pointcut-ref="pc4"/>
-->
<!-- pointcut-ref 대신 pointcut으로 직접 지정 가능 -->
<aop:after method="logOut" pointcut="within(com.lec.spring.aop03.*)"/>
</aop:aspect>
</aop:config>
</beans>
** [src/main/java] com.lec.spring.aop03 > AopMain03.java
package com.lec.spring.aop03;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.lec.beans.*;
public class AopMain03 {
public static void main(String[] args) {
System.out.println("Main 시작");
AbstractApplicationContext ctx =
new GenericXmlApplicationContext("classpath:aopCtx3.xml");
System.out.println("ctx생성");
Service service21 = ctx.getBean("service21", Service.class);
Service service22 = ctx.getBean("service22", Service.class);
ServiceEx serviceEx31 = ctx.getBean("serviceEx31", ServiceEx.class);
ServiceEx serviceEx32 = ctx.getBean("serviceEx32", ServiceEx.class);
service21.doAction(); // 1
service22.doAction(); // 2
serviceEx31.doAction(); // 3
serviceEx31.doWorking(); // 4
serviceEx31.quitAction(); // 5
serviceEx32.doAction(); // 6
serviceEx32.doWorking(); // 7
serviceEx32.quitAction(); // 8
ctx.close();
System.out.println("Main 종료");
} // end main
} // end class
10. Spring MVC 구조
1) Spring MVC Project
: 스프링 프레임워크에서 제공하는 프로젝트 중에 MVC 웹어플리케이션 개발용 프로젝트
2) JSP MVC model2와 구조상으로 많이 비슷하나
스프링에서 제공하는 다양한 메커니즘들로 인해, 개발과 유지보수에 더 좋다.
그러한 이유로 오늘날 대부분의 기업용 웹 어플리케이션은 스프링 웹어플리케이션으로 작성된다.
11. STS09_MVC
** Spring MVC Project 생성
: 우클릭 > New > Spring Legacy Proejct 클릭
> 프로젝트 이름 설정, pring MVC Project 템플릿 선택 > Next 클릭
> 최초인 경우 다운로드(Maven 필요 라이브러리) 여부 확인창 뜸, Yes 클릭
> base-package명 지정(반드시 3단계 이상 작성, base-package 명을 3단계로 하면 3번째가 컨텍스트 이름이 된다)
> 하단 부분의 Maven 필요 라이브러리 다운로드됨, 다 다운 받으면 작업하면 됨...!!
** 프로젝트 폴더 구성
[컨트롤러] Dispatcher에서 전달된 요청을 처리
[DispatcherServlet] 클라이언트의 요청을 최초에 받아 컨트롤러에게 전달
[src/main/webapp] 웹 root
[webapp/resources] 리소스
[스프링 설정파일 *.xml] 스프링 컨테이너 설정 파일
[뷰 *.jsp]
[web.xml] DispatcherServlet 서블릿 맵핑, 스프링 설정 파일 위치 정의
[pom.xml] Maven 설정 파일
** src > main > webapp > WEB-INF > web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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 https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 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>
<!-- [주의!] 반드시 filter를 해야 한글 인코딩이 깨지지 않는다! -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
** src > main > webapp > WEB-INF > spring > sppServlet > servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<!--
/resources/** 로 요청들어오는 건 DispatcherServlet 이 처리하지 말고
/resources/ 폴더에서 찾게 하기
-->
<resources mapping="/resources/**" location="/resources/" />
<resources mapping="/myRes/**" location="/myRes/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.lec.sts09_mvc" />
</beans:beans>
** [src/main/java] com.lec.sts09_mvc > HomeController.java
package com.lec.sts09_mvc;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
}
** src > main > webapp > Hello.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>hello</title>
</head>
<body>
안녕하세요
</body>
</html>
** src > main > webapp > WEB-INF > views > home.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The time on the server is ${serverTime}. </P>
<img src="<%= request.getContextPath() %>/myRes/img/bgdesert.jpg"/><br><br>
<img src="/sts09_mvc/resources/img/bgdesert.jpg"/><br><br>
<img src="<%= request.getContextPath() %>/resources/img/bgdesert.jpg"/><br><br>
<img src="${pageContext.request.contextPath }/resources/img/bgdesert.jpg"/><br><br>
</body>
</html>
12. 스프링 MVC 동작 흐름
1) 모든 Request는 DispatcherServlet이 받아서 일괄 관리하거나 처리
2) DispatcherServlet은 request를 처리할 컨트롤러 선택(Handler Mapping)
: reqeust 한 URL을 분석하여, 어떤 컨트롤러 클래스에서 처리할지 선택(이 일을 수행하는 것은 HandlerMapping 객체)
3) request 처리, 결과는 ModelAndView
: Spring MVC에서는 handler 수행결과(model, view)를 HandlerAdapter를 통해
ModelAndView 객체에 담아 DiapatcherServlet에 넘긴다.
[참고! JSP MVC Model2의 request 결과는 request의 attribute에 넣어서 컨트롤러에 넘김]
4) ViewResolver 뷰(jsp) 선택
: 컨트롤러의 수행 결과는 Model과 View이다.
예시에서 메소드는 Model은 Model 객체에 담았고 View는 "home"을 리턴,
DispatcherServlet은 View 결과를 ViewResolver에게 넘겨주어 "/WEB-INF/views/home.jsp"라는 결과를 받아 온다.
5) view에 model을 넘겨주어 response
: DispatcherServlet은 webapp(웹 루트) 밑에서 뷰를 찾고 그 view에 model을 넘겨 주어 response한다.
12. 한글 깨짐(스프링 인코딩 문제)
: web.xml에 <filter> 추가
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
13. 웹 어플리케이션은..?
1) 원하는 형태의 request URL을 받아서
2) 그 URL에 따른 동작(handler)를 찾아서 (mapping) 수행하고
3) 원하는 뷰로 response한다.
14. @Controller 클래스 안의 @RequestMapping 지정된 메소드를 핸들러(Handler)라고도 한다.
15. STS10_Request
[프로젝트명] STS10_Request
[프로젝트] Spring Legacy Project
[템플릿] Spring MVC Project
[base-package] com.lec.sts10_request
** src > main > webapp > WEB-INF > web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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 https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 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>
<!-- 스프링 컨테이너 인코딩 설정 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
** [src/main/java] com.lec.sts10_request > HomeController 서블릿
package com.lec.sts10_request;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
@RequestMapping(value="/common") // /common 으로 요청이 오면
public String cccmmm() { // cccmmm() 핸들러가 수행되고,
return "comn"; // --> /WEB-INF/views/comn.jsp 를 리턴하면서 response 되게 한다.
}
}
** [src/main/java] com.lec.sts10_request.controller > MemberController 서블릿
package com.lec.sts10_request.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value = "/member") // -> /member 로 시작하는 request 만 처리
public class MemberController {
@RequestMapping(value = "/save") // -> /member + /save => /member/save
public String saveMember() {
return "member/save";
}
@RequestMapping(value = "/load") // -> /member/load
public String loadMember() {
return "member/load";
}
// @RequestMapping(value = "/search") // -> /member/search (중복!)
// public String searchMember() {
// return "member/search";
// }
}
** src > main > webapp > WEB-INF > views > comn.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String servlet_request_uri = (String)request.getAttribute("javax.servlet.forward.request_uri");
String conPath = request.getContextPath();
//System.out.println(servlet_request_uri);
//System.out.println(conPath);
String servlet_reqpath = servlet_request_uri.substring(conPath.length());
String uri = request.getRequestURI();
String reqPath = uri.substring(conPath.length());
String url = request.getRequestURL().toString();
// jsp 파일명
String jspFile = uri.substring(uri.lastIndexOf("/") + 1, uri.length());
String jspName = uri.substring(uri.lastIndexOf("/") + 1, uri.length() - 4);
request.setAttribute("jspName", jspName);
%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= jspName %></title>
<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath }/CSS/sts_common.css">
</head>
<body>
<hr>
<div class="sts">
<b>Servlet</b><br>
request URI : <span><%= servlet_request_uri %></span><br>
context path : <span><%= conPath %></span><br>
request path : <span><%= servlet_reqpath %></span><br>
VIEW file : <span><%= jspFile %></span><br>
<hr>
<b>VIEW(JSP)</b><br>
url : <span><%= url %></span><br>
VIEW Path : <span><%= reqPath %></span><br>
uri : <span><%= uri %></span><br>
</div>
</body>
</html>
** src > main > webapp > WEB-INF > views > home.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
${serverTime}
<jsp:include page="/common"/>
** src > main > webapp > WEB-INF > views > member > search.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:include page="/common"/>
** src > main > webapp > WEB-INF > views > member > info.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
${mbAge }<br>
${mbName }<br>
<jsp:include page="/common"/>
** src > main > webapp > WEB-INF > views > member > find.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
${mbName }<br>
${mbDate }<br>
<jsp:include page="/common"/>
** src > main > webapp > WEB-INF > views > member > doMember.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:include page="/common"/>
** src > main > webapp > WEB-INF > views > member > save.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:include page="/common"/>
** src > main > webapp > WEB-INF > views > member > load.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:include page="/common"/>
** src > main > webapp > WEB-INF > spring > sppServlet > servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<resources mapping="/CSS/**" location="/CSS/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.lec.sts10_request" />
</beans:beans>
** src > main > webapp > CSS > sts_common.css
@charset "UTF-8";
div.sts span {
color: blue;
}
16. 기본적인 Controller 클래스 제작 흐름
1) @Controller를 이용한 클래스 생성
2) @RequestMapping을 이용한 요청 경로 지정
3) 요청 처리 메소드(handler) 구현
4) 뷰 이름 혹은 ModelAndView 리턴
17. 핸들러 메소드 동작
1) @RequestMapping으로 request를 받아서
2) 필요한 동작들(ex: 트랜잭션) 수행, DAO 혹은 Command 등의 객체 사용
3) 결과는 Model에 담고 뷰 지정 > 합해서 ModelAndView로 담아 리턴 가능
18. jsp:include page의 주소 부분이 일반적인 jsp 주소로 기재되어 있지 않아서 에러 발생(이클립스 문제)
: JSP 에러 검사 중 파일이 있는지를 캐치해주는 부분을 꺼주면 됨
원하는 프로젝트 선택 후 우클릭 > Properties 클릭
> Validation > JSP Syntax
> Enable project specific Settings 선택, included fragment file not found > Ignore 세팅
'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글
2020.06.29 (0) | 2020.06.29 |
---|---|
2020.06.23 (0) | 2020.06.23 |
2020.06.19 (0) | 2020.06.19 |
2020.06.18 (0) | 2020.06.18 |
2020.06.17 (0) | 2020.06.17 |