
로깅과 같은 기본적인 기능에서부터 트랜잭션이나 보안과 같은 기능에 이르기까지 어플리케이션 전반에 걸쳐 적용되는 공통기능을 핵심 기능과 분리해서 모듈로 구현한 뒤 핵심 기능이 수행될 때 필요로 하는 곳에 공통기능이 적용되게 하는 기능이다.
AOP(Aspect Oriented Programming)는 문제를 바라보는 관점을 기준으로 프로그래밍하는 기법. 공통 관심 사항을 구현한 코드를 핵심 로직을 구현한 코드 안에 삽입하는 것을 의미.
| 용어 | 뜻 |
|---|---|
| Advice | 언제 공통 관심 기능을 핵심 로직에 적용할 지를 정의. |
| Joinpoint | Advice를 적용 가능한 지점을 의미. 메서드 호출, 필드 값 변경 등이 Joinpoint에 해당 |
| Pointcut | Joinpoint의 부분 집합으로서 실제로 Advice가 적용되는 Joinpoint를 나타냄. |
| Weaving | Advice를 핵심 로직 코드에 적용하는 것을 weaving이라고 함. |
| Aspect | 여러 객체에 공통으로 적용되는 공통 관심 사항 |
| 종류 | 설명 |
|---|---|
| Before Advice | 대상 객체의 메서드 호출 전에 공통 기능을 실행 |
| After Returning Advice | 대상 객체의 메서드가 예외 없이 실행한 이후에 공통 기능을 실행 |
| After Throwing Advice | 대상 객체의 메서드를 실행하는 도중 예외가 발생한 경우에 공통 기능을 실행 |
| After Advice | 대상 객체의 메서드를 실행하는 도중에 예외가 발생했는지의 여부와 상관없이 메서드 실행 후 공통 기능을 실행. |
| Around Advice | 대상 객체의 메서드 실행 전, 후 또는 예외 발생 시점에 공통 기능을 실행하는데 사용 |
<!-- Aspect 설정 : Advice를 어떤 Pointcut에 적용할지 설정 -->
<aop:config>
<aop:aspect id="traceAspect1" ref="performanceTraceAdvice">
<aop:pointcut expression="execution(public * com.spring.board..*(..))" id="publicMethod"/>
<aop:around method="trace" pointcut-ref="publicMethod"/>
</aop:aspect>
</aop:config>
<bean id="writeArticleService" class="com.spring.board.service.WriteArticleServiceImpl">
<constructor-arg>
<ref bean="articleDao"/>
</constructor-arg>
</bean>
<bean id="articleDao" class="com.spring.board.dao.WriteArticleDao"/>
| 태그 | 뜻 |
|---|---|
| <aop:config> | AOP 설정 정보임을 나타냄 |
| <aop:aspect> | Aspect를 설정함 |
| <aop:pointcut> | Pointcut을 설정함 |
| <aop:around> | Around Advice를 설정함 |
| 종류 | 설명 |
|---|---|
| <aop:before> | 메서드 실행 전에 적용되는 Advice를 정의한다. |
| <aop:after-returning> | 메서드 정상적으로 실행된 후에 적용되는 Advice를 정의한다. |
| <aop:after-throwing> | 메서드가 예외를 발생시킬 때 적용되는 Advice를 정의한다. try-catch블록에서 catch 블록과 비슷하다. |
| <aop:after> | 메서드가 적상적으로 실행되느니지 또는 예외를 발생시키는지 여부에 상관없이 적용되는 Advice를 정의한다. try-catch-finally에서 finally 블록과 비슷하다. |
| <aop:around> | 메서드 호출 이전, 이후, 예외 발생 등 모든 시점에 적용 가능한 Advice를 정의한다. |
<aop:aspect id="traceAspect1" ref="performanceTraceAdvice">
<aop:pointcut expression="execution(public * com.spring.board..*(..))" id="publicMethod"/>
<aop:around method="trace" pointcut-ref="publicMethod"/>
</aop:aspect>
execution 명시자는 Advice를 적용할 메서드를 명시할 때 사용됨
execution(식어패턴 리턴타입패턴 클래스이름패턴 이름패턴(파라미터패턴)
@Aspect
public class ProfilingAspect {
@Pointcut("execution(public * com.spring.board..*(..))")
private void profileTarget(){}
@Around("profileTarget()")
public Object trace(ProceedingJoinPoint joinPoint)
throws Throwable{
String signatureString =
joinPoint.getSignature().toShortString();
System.out.println(signatureString + " 시작");
long start = System.currentTimeMillis();
Object result = null;
try{
//핵심 비지니스 로직을 수행
result = joinPoint.proceed();
}catch(Exception e){
e.printStackTrace();
}finally{
//메서드 실행 직후의 시간을 저장
long finish = System.currentTimeMillis();
System.out.println(signatureString + "종료");
System.out.println(signatureString + " 실행 시간 : " + (finish-start)+"ms");
}
return result;
}
}
| 구성요소 | 설명 |
|---|---|
| DispatcherServlet | 클라이언트의 요청을 전달받는다. 컨트롤러에게 클라이언트의 요청을 전달하고, 컨트롤러가 리턴한 결과값을 View에 전달하여 알맞은 응답을 생성하도록 한다. |
| HandlerMapping | 클라이언트의 요청 URL을 어떤 컨트롤러가 처리할지를 결정한다. |
| 컨트롤러(Controller) | 클라이언트의 요청을 처리한 뒤, 그 결과를 DispatcherServlet에 알려준다. 스트럿츠의 Action과 동일한 역할을 수행한다. |
| ModelAndView | 컨트롤러가 처리한 결과 정보 및 뷰 선택에 필요한 정보를 담는다. |
| ViewResolver | 컨트롤러의 처리 결과를 생성할 뷰를 결정한다. |
| 뷰(View) | 컨트롤러의 처리 결과 화면을 생성한다. JSP나 Velocity 템플릿 파일 등을 뷰로 사용한다. |

maven 설정 pom.xml 파일에서 jar 파일 설정
web.xml 설정 DispatcherServlet 매핑
root-context.xml 파일에 데이터베이스 연동 설정
servlet-context.xml에 bean 설정
DispatcherServlet의 설정은 웹 어플리케이션의 /WEB-INF/web.xml 파일에 추가
<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>*.do</url-pattern>
</servlet-mapping>
@Controller
public class HelloController {
@RequestMapping("/hello.do")
public ModelAndView hello() {
ModelAndView mav = new ModelAndView();
//뷰 이름 지정
mav.setViewName("hello");
//뷰에서 사용할 데이터 셋팅
mav.addObject("greeting", "Hello World!!");
return mav;
}
}
bean 설정 및 viewResolver 설정
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
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.xsd">
<!-- bean 설정 -->
<beans:bean id="helloController" class="kr.spring.ch01.controller.HelloController" />
<!-- viewResolver 설정 -->
<beans:bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
</beans:beans>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>인사</title>
</head>
<body>
인사말: <strong>${greeting}</strong>
</body>
</html>
핵심 기능을 담고 있는 코드
package kr.spring.product;
public class Product {
// 핵심 기능 수행
public String launch() {
System.out.println("launch() 메서드 출력하기");
return "[상품 출시]";
}
}
package kr.spring.ch20.pojo;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyFirstAdvice {
// 공통 기능 수행
public void before() {
// 메서드 시작 직전에 동작하는 어드바이스
System.out.println("Hello Before! ** 메서드가 호출되기 전에 나온다!");
}
public void afterReturning(String msg) {
// 핵심 기능이 동작된 후에 반환하는 데이터를 받아 출력하기
// 메서드 호출이 예외를 내보내지 않고 종료했을 때 동작하는 어드바이스
System.out.println("Hello After Returning! ** 메서드가 호출한 후 발생! 전달된 객체 : " + msg);
}
public void afterThrowing(Exception ex) {
// 메서드 호출이 예외를 던졌을 때 동작하는 어드바이스
System.out.println("Hello After Throwing ** 예외가 생겼을 때 출력! 예외 : " + ex);
}
public void after() {
// 메서드 종료 후에 동작하는 어드바이스(예외가 발생해도 실행된다)
System.out.println("Hello After ** 메서드 호출 된 후 출력!");
}
public String around(ProceedingJoinPoint joinPoint) throws Throwable {
// 메서드 호출 전 후에 동작하는 어드바이스
// 핵심 기능 동작 전에 호출
System.out.println("Hello Around Before! ** 메서드 호출 전 출력!");
// 핵심 기능 부분
String s = null;
// try ~ catch ~ finally 구조로 명시해야 예외가 발생하더라도 메서드 실행 후 공통 기능 수행
try {
// 핵심 기능이 수행 된 후 데이터 반환
s = (String)joinPoint.proceed(); // 핵심 기능을 갖고 있는 메서드가 실행
} catch (Exception e) {
e.printStackTrace();
} finally {
// 핵심 기능 이후의 동작(공통 기능)
System.out.println("Hello Around After! ** 메서드 호출 후 출력! 반환된 객체 : " + s);
}
return s;
}
}
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 공통 기능을 갖고 있는 클래스 빈 객체 설정 -->
<bean id="myFirstAdvice" class="kr.spring.ch20.pojo.MyFirstAdvice"/>
<!-- 핵심 기능을 구현한 클래스 빈 객체 설정 -->
<bean id="product" class="kr.spring.product.Product"/>
<!-- AOP 설정 -->
<aop:config>
<!-- 공통기능을 갖고 있는 클래스 지정 -->
<aop:aspect id="aspect" ref="myFirstAdvice">
<!-- 핵심 기능을 실행할 때 어느 시점에 공통 기능을 적용할지 지정 -->
<!-- 핵심 기능 지정 -->
<aop:pointcut expression="execution(public String launch())" id="publicMethod"/>
<!-- 공통 기능 지정 -->
<!-- Advice 종류 - before -->
<!-- <aop:before method="before" pointcut-ref="publicMethod"/> -->
<!-- Advice 종류 - after-returning -->
<!-- 반환하는 데이터를 msg에 넣어서 넘겨라 -->
<!-- <aop:after-returning method="afterReturning" pointcut-ref="publicMethod"
returning="msg"/> -->
<!-- Advice 종류 - after-throwing -->
<!-- <aop:after-throwing method="afterThrowing" pointcut-ref="publicMethod"
throwing="ex"/> -->
<!-- Advice 종류 - after -->
<!-- <aop:after method="after" pointcut-ref="publicMethod" /> -->
<!-- Advice 종류 - Around After -->
<aop:around method="around" pointcut-ref="publicMethod"/>
</aop:aspect>
</aop:config>
</beans>
package kr.spring.ch20.pojo;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.spring.product.Product;
public class SpringMain {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContextAOP.xml");
context.registerShutdownHook();
Product p = (Product)context.getBean("product");
p.launch();
//어플리케이션 종료시 컨테이너에 존재하는 모든 빈(객체)를 종료
context.close();
}
}
Advice 종류별 실행 결과
Before를 사용했을 때

After-Returning 사용했을 때

에외 발생시키는 코드를 넣었을 때

after-throwing 사용했을 때

after 사용했을 때

around 사용했을 때

package kr.spring.ch21.annot;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
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.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyFirstAspect {
/*
@Before
@AfterReturning
@AfterThrowing
@After
@Around
*/
@Pointcut("execution(public String launch())")
// 주의 ! 메서드명이 getPointcut으로 정해져 있기 때문에 변경할 수 없다.
public void getPointcut() {
}
//@Before("getPointcut()")
public void before() {
// 메서드 시작 직전에 동작하는 어드바이스
System.out.println("Hello Before! ** 메서드가 호출되기 전에 나온다!");
}
//@AfterReturning(value = "getPointcut()", returning = "msg")
public void afterReturning(String msg) {
// 핵심 기능이 동작된 후에 반환하는 데이터를 받아 출력하기
// 메서드 호출이 예외를 내보내지 않고 종료했을 때 동작하는 어드바이스
System.out.println("Hello After Returning! ** 메서드가 호출한 후 발생! 전달된 객체 : " + msg);
}
// @AfterThrowing(value = "getPointcut()", throwing="ex")
public void afterThrowing(Exception ex) {
// 메서드 호출이 예외를 던졌을 때 동작하는 어드바이스
System.out.println("Hello After Throwing ** 예외가 생겼을 때 출력! 예외 : " + ex);
}
// @After("getPointcut()")
public void after() {
// 메서드 종료 후에 동작하는 어드바이스(예외가 발생해도 실행된다)
System.out.println("Hello After ** 메서드 호출 된 후 출력!");
}
@Around("getPointcut()")
public String around(ProceedingJoinPoint joinPoint) throws Throwable {
// 메서드 호출 전 후에 동작하는 어드바이스
// 핵심 기능 동작 전에 호출
System.out.println("Hello Around Before! ** 메서드 호출 전 출력!");
// 핵심 기능 부분
String s = null;
// try ~ catch ~ finally 구조로 명시해야 예외가 발생하더라도 메서드 실행 후 공통 기능 수행
try {
// 핵심 기능이 수행 된 후 데이터 반환
s = (String)joinPoint.proceed(); // 핵심 기능을 갖고 있는 메서드가 실행
} catch (Exception e) {
e.printStackTrace();
} finally {
// 핵심 기능 이후의 동작(공통 기능)
System.out.println("Hello Around After! ** 메서드 호출 후 출력! 반환된 객체 : " + s);
}
return s;
}
}
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 어노테이션 방식으로 AOP 구현할 때 명시 -->
<aop:aspectj-autoproxy/>
<!-- 공통 기능을 구현된 클래스 빈 객체 설정 -->
<bean id="myFirstAspect" class="kr.spring.ch21.annot.MyFirstAspect"/>
<!-- 핵심 기능이 구현된 클래스 빈 객체 설정 -->
<bean id="product" class="kr.spring.product.Product"/>
</beans>
package kr.spring.ch21.annot;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.spring.product.Product;
public class SpringMain {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContextAOP2.xml");
context.registerShutdownHook();
Product p = (Product)context.getBean("product");
p.launch();
//어플리케이션 종료시 컨테이너에 존재하는 모든 빈(객체)를 종료
context.close();
}
}
@Before("getPointcut()") 결과

@AfterReturning(value="getPointcut()", returning="msg") 결과

@AfterThrowing(value = "getPointcut()", throwing="ex") 결과

@After("getPointcut()") 결과

@Around("getPointcut()") 결과

package kr.spring.ch01.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
// 요청 URL과 실행 메서드 연결
@RequestMapping("/hello.do")
public ModelAndView hello() {
// model = 데이터(request) view = 뷰(viewResolver)
ModelAndView mav = new ModelAndView();
// 뷰 이름 지정 -> hello가 어딨는지 찾고, 확장자도 알려주기 때문에 이름만 명시
mav.setViewName("hello"); // /WEB-INF/views/ -> prefix hello. jsp->s
// 뷰에서 사용할 데이터 세팅
// request에 저장되기 때문에 el을 이용하여 데이터 출력할 수 있음
mav.addObject("greeting","안녕하세요!");
return mav;
}
}
<beans:bean id="helloController" class="kr.spring.ch01.controller.HelloController"/>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>인사</title>
</head>
<body>
인사 : <b>${greeting}</b>
</body>
</html>
hello.do에 그냥 접근 할 수 없기 때문에 index에 링크를 걸어서 열 수 있도록 설정
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring MVC</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/hello.do">Hello Controller</a>
</body>
</html>

Hello Controller에
mav.addObject("lunch","곧 점심시간입니다!");
추가해본다면
hello.jsp 도 변경
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>인사</title>
</head>
<body>
인사말 <b>${greeting}</b> <br>
점심시간 <b>${lunch}</b>
</body>
</html>

package kr.spring.ch02.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class SearchController {
// 요청 URL과 실행 메서드 연결
@RequestMapping("/search/internal.do")
public ModelAndView searchInternal(String query) {
System.out.println("query = " + query);
// ModelAndView mav = new ModelAndView();
// 뷰 이름 지정
// mav.setViewName("search/internal");
return new ModelAndView("search/internal");
}
}
<beans:bean id="searchController" class="kr.spring.ch02.controller.SearchController"/>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>내부 검색</title>
</head>
<body>
<b>내부 검색</b>
</body>
</html>


코드 추가
@RequestMapping("/search/external.do")
public ModelAndView searchExternal(@RequestParam String query, @RequestParam("p") int pageNumber) {
System.out.println("query = " + query);
System.out.println("p = " + pageNumber);
ModelAndView mav = new ModelAndView();
// 뷰 이름 지정
mav.setViewName("search/external");
return mav;
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>외부 검색</title>
</head>
<body>
외부 검색
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring MVC</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/hello.do">Hello Controller</a>
<a href="${pageContext.request.contextPath}/search/internal.do">Search Controller(Internal)</a>
<a href="${pageContext.request.contextPath}/search/external.do?query=여름&p=10">Search Controller(External)</a>
</body>
</html>


package kr.spring.ch03.vo;
public class NewArticleVO {
private String title;
private String name;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "NewArticleVO [title=" + title + ", name=" + name + ", content=" + content + "]";
}
}
package kr.spring.ch03.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.spring.ch03.vo.NewArticleVO;
@Controller
public class NewArticleController {
// get 요청이 들어올 때 호출
@GetMapping("/article/newArticle.do")
public String form() {
// 뷰 이름 지정
return "article/newArticleForm";
}
// post 요청이 들어올 때 호출
@PostMapping("/article/newArticle.do")
public String submit(@RequestParam String title,
@RequestParam String name,
@RequestParam String content ) {
NewArticleVO vo = new NewArticleVO();
vo.setTitle(title);
vo.setName(name);
vo.setContent(content);
System.out.println(vo);
// 뷰 이름 지정
return "article/newArticleSumitted";
}
}
<!-- @Autowired 사용을 위해서 -->
<context:annotation-config/>
<!-- 전송된 데이터 자바빈(VO)에 담기 -->
<beans:bean id="newArticleController" class="kr.spring.ch03.controller.NewArticleController"/>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시글 쓰기</title>
</head>
<body>
게시글 쓰기 입력 폼
<form action="newArticle.do" method="post">
제목 : <input type="text" name="title"><br>
작성자 : <input type="text" name="name"><br>
작성자 : <textarea rows="5" cols="30" name="content"></textarea><br>
<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>게시글 쓰기 완료</title>
</head>
<body>
게시글이 등록되었습니다.
</body>
</html>

package kr.spring.ch03.service;
import kr.spring.ch03.vo.NewArticleVO;
public class NewArticleService {
public void writeArticle(NewArticleVO vo) {
System.out.println("신규 게시글 등록 : " + vo);
}
}
수정하기
package kr.spring.ch03.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.spring.ch03.service.NewArticleService;
import kr.spring.ch03.vo.NewArticleVO;
@Controller
public class NewArticleController {
// autowired가 set을 자동으로 만들어주기 때문에 굳이 만들 필요가 없다
@Autowired
private NewArticleService newArticleService;
// get 요청이 들어올 때 호출
@GetMapping("/article/newArticle.do")
public String form() {
// 뷰 이름 지정
return "article/newArticleForm";
}
// post 요청이 들어올 때 호출
@PostMapping("/article/newArticle.do")
public String submit(@RequestParam String title,
@RequestParam String name,
@RequestParam String content ) {
NewArticleVO vo = new NewArticleVO();
vo.setTitle(title);
vo.setName(name);
vo.setContent(content);
newArticleService.writeArticle(vo);
// 뷰 이름 지정
return "article/newArticleSumitted";
}
}
추가하기
<beans:bean id="newArticleService" class="kr.spring.ch03.service.NewArticleService"/>

@ModelAttribute("command") NewArticleVO vo 형식
@ModelAttribute(속성명) NewArticleVO vo
지정한 속성명으로 JSP에서 request에 접근하여 자바빈(VO) 호출 가능
ex) ${속성명.title} , ${속성명.name}, ${속성명.content}
package kr.spring.ch03.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.spring.ch03.service.NewArticleService;
import kr.spring.ch03.vo.NewArticleVO;
@Controller
public class NewArticleController {
// autowired가 set을 자동으로 만들어주기 때문에 굳이 만들 필요가 없다
@Autowired
private NewArticleService newArticleService;
// get 요청이 들어올 때 호출
@GetMapping("/article/newArticle.do")
public String form() {
// 뷰 이름 지정
return "article/newArticleForm";
}
// post 요청이 들어올 때 호출
@PostMapping("/article/newArticle.do")
public String submit(@ModelAttribute("command") NewArticleVO vo) {
newArticleService.writeArticle(vo);
// 뷰 이름 지정
return "article/newArticleSumitted";
}
}

@ModelAttribute NewArticleVO vo 형식
@ModelAttribute를 명시할 때 속성명을 생략할 수 있다.
속성명을 생략하면 클래스명의 첫 글자를 소문자로 속성명을 자동 생성한다.
ex) @ModelAttribute NewArticleVO vo
${newArticleVO.title} , ${newArticleVO.name},${newArticleVO.content}
package kr.spring.ch03.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.spring.ch03.service.NewArticleService;
import kr.spring.ch03.vo.NewArticleVO;
@Controller
public class NewArticleController {
// autowired가 set을 자동으로 만들어주기 때문에 굳이 만들 필요가 없다
@Autowired
private NewArticleService newArticleService;
// get 요청이 들어올 때 호출
@GetMapping("/article/newArticle.do")
public String form() {
// 뷰 이름 지정
return "article/newArticleForm";
}
// post 요청이 들어올 때 호출
@PostMapping("/article/newArticle.do")
public String submit(@ModelAttribute NewArticleVO vo) {
newArticleService.writeArticle(vo);
// 뷰 이름 지정
return "article/newArticleSumitted";
}
}

NewArticleVO vo 형식
@ModelAttribute 생략
호출 메서드에 인자명만 명시
ex) NewArticleVO vo와 같이 인자명만 명시
request에 저장되는 속성명은 newArticleVO로 저장됨
package kr.spring.ch03.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.spring.ch03.service.NewArticleService;
import kr.spring.ch03.vo.NewArticleVO;
@Controller
public class NewArticleController {
// autowired가 set을 자동으로 만들어주기 때문에 굳이 만들 필요가 없다
@Autowired
private NewArticleService newArticleService;
// get 요청이 들어올 때 호출
@GetMapping("/article/newArticle.do")
public String form() {
// 뷰 이름 지정
return "article/newArticleForm";
}
// post 요청이 들어올 때 호출
@PostMapping("/article/newArticle.do")
public String submit(NewArticleVO vo) {
newArticleService.writeArticle(vo);
// 뷰 이름 지정
return "article/newArticleSumitted";
}
}

package kr.spring.ch04.controller;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CookieController {
@RequestMapping("/cookie/make.do")
public String make(HttpServletResponse response) {
// 쿠키를 생성해서 클라이언트에 전송
response.addCookie(new Cookie("auth", "10"));
return "cookie/make";
}
}
<!-- @CookieValue 어노테이션을 이용한 쿠키 매핑 -->
<beans:bean id="cookieController" class="kr.spring.ch04.controller.CookieController"/>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>쿠키 값 생성하기</title>
</head>
<body>
쿠키를 생성함
</body>
</html>

package kr.spring.ch04.controller;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CookieController {
@RequestMapping("/cookie/make.do")
public String make(HttpServletResponse response) {
// 쿠키를 생성해서 클라이언트에 전송
response.addCookie(new Cookie("auth", "10"));
return "cookie/make";
}
@RequestMapping("/cookie/view.do")
public String view(@CookieValue("auth") String auth) {
// 쿠키명 지정하고 쿠키 불러오기
System.out.println("auth 쿠키 : " + auth);
return "cookie/view";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>쿠키 확인</title>
</head>
<body>
쿠키 확인
</body>
</html>

package kr.spring.ch04.controller;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CookieController {
@RequestMapping("/cookie/make.do")
public String make(HttpServletResponse response) {
// 쿠키를 생성해서 클라이언트에 전송
response.addCookie(new Cookie("auth", "10"));
return "cookie/make";
}
@RequestMapping("/cookie/view.do")
public String view(@CookieValue String auth) {
// 쿠키명 지정하고 쿠키 불러오기
System.out.println("auth 쿠키 : " + auth);
return "cookie/view";
}
}
package kr.spring.ch04.controller;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CookieController {
@RequestMapping("/cookie/make.do")
public String make(HttpServletResponse response) {
// 쿠키를 생성해서 클라이언트에 전송
response.addCookie(new Cookie("auth", "10"));
return "cookie/make";
}
@RequestMapping("/cookie/view.do")
public String view(String auth) {
// 쿠키명 지정하고 쿠키 불러오기
System.out.println("auth 쿠키 : " + auth);
return "cookie/view";
}
}

package kr.spring.ch04.controller;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CookieController {
@RequestMapping("/cookie/make.do")
public String make(HttpServletResponse response) {
// 쿠키를 생성해서 클라이언트에 전송
response.addCookie(new Cookie("auth", "10"));
return "cookie/make";
}
@RequestMapping("/cookie/view.do")
public String view(@CookieValue(value="auth", required=false) String auth) {
// 쿠키명 지정하고 쿠키 불러오기
System.out.println("auth 쿠키 : " + auth);
return "cookie/view";
}
}
package kr.spring.ch04.controller;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CookieController {
@RequestMapping("/cookie/make.do")
public String make(HttpServletResponse response) {
// 쿠키를 생성해서 클라이언트에 전송
response.addCookie(new Cookie("auth", "10"));
return "cookie/make";
}
@RequestMapping("/cookie/view.do")
public String view(@CookieValue(value="auth", defaultValue="0") String auth) {
// 쿠키명 지정하고 쿠키 불러오기
System.out.println("auth 쿠키 : " + auth);
return "cookie/view";
}
}
