퍼사드(Facade) 패턴
소프트웨어 설계 패턴 중 하나로, 복잡한 시스템에 대한 단순화된 인터페이스를 제공합니다. 이 패턴의 주요 목적은 서브시스템의 복잡성을 숨기고, 클라이언트가 사용하기 편리한 고수준의 인터페이스를 제공함으로써 클라이언트와 복잡한 서브시스템 간의 의존성을 줄이는 것입니다.
퍼사드 패턴 특징
단순화된 접근: 클라이언트는 복잡한 서브시스템을 직접 다루지 않고, 퍼사드를 통해 간접적으로 접근합니다. 이를 통해 사용법이 간단해지고, 구현 세부 사항에 대한 이해 없이도 서브시스템의 기능을 사용할 수 있습니다.
시스템 분리: 퍼사드는 시스템의 구성 요소를 분리하여, 서브시스템의 변경이 클라이언트에 미치는 영향을 최소화합니다. 이로 인해 시스템의 유지보수성과 확장성이 향상됩니다.
인터페이스 통합: 복잡한 서브시스템에 여러 인터페이스가 존재할 경우, 퍼사드는 이들 인터페이스를 통합하여 단일 인터페이스를 제공합니다. 이는 클라이언트가 서브시스템을 더 쉽게 사용할 수 있게 해줍니다.
Front Controller: 모든 요청을 처음 받는 중앙 진입점입니다. 이 컴포넌트는 요청을 적절한 핸들러나 컨트롤러로 전달하기 전에 필요한 사전 처리(인증 검사, 로깅, 요청 데이터의 사전 처리 등)를 수행합니다.
Handler Mapping: 요청 URL과 처리할 수 있는 컨트롤러 간의 매핑을 관리합니다. Front Controller는 이 매핑 정보를 사용하여 각 요청을 처리할 적절한 컨트롤러를 결정합니다.
Controller: 실제 비즈니스 로직을 처리하는 컴포넌트입니다. 요청에 따라 데이터를 처리하고, 처리 결과를 바탕으로 사용자에게 보여줄 뷰를 결정합니다.
View: 사용자에게 응답을 보여주는 역할을 합니다. 컨트롤러로부터 받은 모델 데이터를 사용하여 사용자가 볼 수 있는 형태로 렌더링합니다.
Dispatcher: Controller가 처리한 결과와 선택된 View를 연결하고, 최종적으로 사용자에게 응답을 보내는 역할을 합니다.
작동 방식
요청 수신: 사용자의 요청은 먼저 Front Controller에 도달합니다. 이는 대개 웹 애플리케이션에서 단일 서블릿(예: 스프링의 DispatcherServlet)이 이 역할을 수행합니다.
요청 분석 및 전처리: Front Controller는 요청의 URL, HTTP 메소드, 헤더 등을 분석하여 어떤 컨트롤러가 요청을 처리할 수 있는지 결정합니다. 필요한 경우, 인증 검사, 로깅, 요청 데이터의 사전 처리와 같은 전처리 작업을 수행합니다.
컨트롤러 실행: Handler Mapping을 사용하여 결정된 컨트롤러를 호출합니다. 컨트롤러는 비즈니스 로직을 실행하고, 결과 데이터를 모델에 저장한 후, 응답으로 사용할 뷰를 결정합니다.
뷰 렌더링: 결정된 뷰는 모델 데이터를 사용하여 최종 사용자 응답을 생성합니다. 이 과정에서 HTML, JSON, XML 등 다양한 형식의 응답을 준비할 수 있습니다.
응답 반환: 최종적으로 생성된 응답은 사용자에게 반환됩니다. 이 과정은 Dispatcher에 의해 수행될 수 있습니다.
@GetMapping
스프링 부트(Spring Boot)에서 @GetMapping 어노테이션은 프론트 컨트롤러 패턴의 일환으로 사용되며, HTTP GET 요청을 특정 메소드에 매핑하기 위해 사용됩니다. 스프링 MVC 프레임워크 내에서, @GetMapping은 @RequestMapping 어노테이션의 특수한 형태로, method = RequestMethod.GET을 기본값으로 사용하는 것과 동일합니다. 이를 통해 웹 애플리케이션의 특정 경로에 대한 GET 요청을 처리할 메소드를 지정할 수 있습니다.
프론트 컨트롤러와 @GetMapping
프론트 컨트롤러 패턴에서는 모든 요청이 단일 진입점을 통해 처리됩니다. 스프링 MVC에서는 DispatcherServlet이 이 역할을 수행하며, 모든 웹 요청을 적절한 핸들러(컨트롤러)에 전달합니다. @GetMapping을 사용하는 컨트롤러 메소드는 DispatcherServlet에 의해 관리되는 요청 처리 흐름의 일부입니다.
-> 원래는 기능별로 컨트롤러 jsp 파일 하나 이어붙였지만 그래서 이거 이용하면 이전과 다르게 하나의 컨트롤러에 다 작성가능하네
최종결론 프론트컨트롤러를 설명
스프링 MVC에서는 DispatcherServlet이 이 역할을 합니다. 클라이언트는 단순히 URL을 요청합니다. 그러면 프론트 컨트롤러(DispatcherServlet)는 요청의 유형(GET, POST 등)을 판단하고, 적절한 컨트롤러 메서드에 요청을 전달하며, 최종적으로 어떤 뷰를 보여줄지 결정합니다
스프링 웹 MVC에서 컨트롤러
상속이나 인터페이스를 구현하는 방식을 사용하지 않고 어노테이션만으로 처리가 가능
오버라이드 없이 필요한 메서드들을 정의
메서드의 파라미터를 기본자료형이나 객체자료형을 마음대로 지정
메서드의 리턴타입도 void, String,객체등 다양한 타입을 사용할 수 있음
@Controller// 컨트롤러 역할
@Log4j2
public class SampleController {
@GetMapping("/hello") // doPost 이런거 안함 , GetMapping PostMaping 으로
// 스프링의 빈으로 처리되기 위해 어노테이션을 달았다.
//hello()라는 기능을 가지고 있는데 get 방식으로 들어오는 hello라는 요청을 처리하는 기능이다.
public void hello(){
log.info("hello~~~~");
}
}
컨트롤러 어노테이션이 된애들 빈으로 만들기 위해 sevelet-context.xml에 추가
해당경로에 컴포넌트 스캔해라!
<context:component-scan base-package="com.ssg.springex.controller"/>
jsp파일 만들기
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello JSP !</h1>
</body>
</html>
/hello 로 접속
@RequestMapping과 파생 어노테이션들
특정경로를 지정하는 어노테이션
@RequestMapping은 경로를 처리하기 위한 용도로 사용
스프링 MVC의 경우 하나의 클래스로 여러 경로를 처리
4버전 이후 @GetMapping, @PostMapping 등이 추가
TodoContllor
@Controller
@RequestMapping("/todo") // 경로지정
@Log4j2
public class TodoController {
@RequestMapping("/list") // /todo/list로 요청
public void list(){
log.info("todo list........") ;
}
@RequestMapping(value = "/register", method = RequestMethod.GET)
// 얘는 get방식
public void register(){
log.info("todo register.....");
}
}
list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>todo List!</h1>
</body>
</html>
/todo/list 로 접속
/todo/register 로 접속
@RequestMapping 이용하면, 여러개의 컨트롤러를 하나의 클래스로 묶을 수 있고, 각 기능을 메소드 단위로 설계할 수 있다는 장점이 있다. 많은 양의 코드를 줄일 수 있다.
//@RequestMapping(value = "/register", method = RequestMethod.GET)
@GetMapping("/register")
public void register(){
log.info("todo register.....");
}
@PostMapping("/register")
public void registerPost(){
log.info("post todo register ....");
}
같은경로를 각각 get과 post로 요청받는다.
@GetMapping("ex1")
public void ex1(String name, int age){
log.info("ex1");
log.info("name : "+name);
log.info("age : "+age);
}
/ex1?name=JKY&age=20 로 접속
파라미터의 자동 수집과 변환
DTO나 VO등으로 자동으로 HttpServletRequest의 파라미터 수집
기본자료형의 경우는 자동으로 형 변환처리가 가능
객체자료형의 경우는 setXXX( )의 동작을 통해서 처리
객체자료형의 경우 생성자가 없거나 파라미터가 없는 생성자가 필요
@RequestParam: 파라미터의 이름을 지정하거나 기본값(defaultValue)를 지정할 수 있음
@ModelAttribute를 이용해서 명시적으로 해당 파라미터를 view까지 전달하도록 구성할 수 있음
파라미터 기본값 지정:
@GetMapping("ex2")
public void ex2(@RequestParam(name = "name", defaultValue = "SSG") String name,
@RequestParam(name = "age", defaultValue = "20") int age){
// 디폴트밸류 만들어주기
// 값 전달해 주지 않아도 디폴트 밸류로 처리
log.info("ex1");
log.info("name : "+name);
log.info("age : "+age);
}
/todo/ex2 로 접속, 전달값 없이 하니까 디폴트값 나옴
Formatter를 이용한 커스텀 처리
날짜나 형 변환을 커스터마이징 해야 하는 경우 주로 사용
컨트롤러는 다 String 사용
@GetMapping("ex3")
public void ex3(LocalDate dueDate){
log.info("ex3 ...");
log.info("dueDate "+dueDate);
}
/todo/ex3?dueDate=2024-03-10 접속하면 400에러뜸
Formatter 등록
날짜 변환
public class LocalDateFormatter implements Formatter<LocalDate> {
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
@Override
public String print(LocalDate object, Locale locale) {
return DateTimeFormatter.ofPattern("yyyy-MM-dd").format(object);
}
}
servlet-context.xml에 빈등록
//추가
<mvc:annotation-driven conversion-service="conversionService"/>
//추가
<bean id = "conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="com.ssg.springex.controller.formatter.LocalDateFormatter"></bean>
</set>
</property>
</bean>
다시 접속 404 에러
이제 나온다.
객체 자료형 파라미터 수집
Java Beans 형식으로 만들어진 클래스 타입은 자동으로 객체가 생성되고 setXXX( )등을 자동으로 호출
Lombok의 @Setter 혹은 @Data를 활용
TodoDTO를 받는 포스트방식
@PostMapping("/register")
public void registerPost(TodoDTO todoDTO){
log.info("post todo register ....");
log.info(todoDTO);
}
register.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/todo/register" method="post">
<div>
Title: <input type="text" name="title" placeholder="INSERT TITLE">
</div>
<div>
DueDate: <input type="date" name="dueDate" value="2024-03-01">
</div>
<div>
Writer: <input type="text" name="writer">
</div>
<div>
Finished: <input type="checkbox" name="finished">
</div>
<div>
<button type="reset">RESET</button>
<button type="submit">REGISTER</button>
</div>
</form>
레지스터 버튼 누르면 콘솔 찍힘
포메터가 날짜 변환 해줌
Model이라는 특별한 파라미터
예전 서블릿에서 request.setAttribute( )로 처리했던 모델대신 사용
메소드의 파라미터에 Model을 선언하면 자동으로 객체 생성
addAttribute( ) 를 이용해서 view까지 전달할 객체 저장
@GetMapping("ex4")
public void ex4(Model model){ // 파라미터를 다 모델로
log.info("=======ex4=========");
model.addAttribute("message","Hello Spring MVC");
}
ex4.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>es4</title>
</head>
<body>
<h1>${message}</h1>
<h1><c:out value="${message}"> </c:out> </h1>
</body>
</html>
/todo/ex4로 접속 , 모델에 담아서 전달해줌
dto 라는 이름으로 todoDTO 전달
@GetMapping("/ex4_1")
public void ex4Extra(@ModelAttribute("dto") TodoDTO todoDTO, Model model){
log.info(todoDTO);
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>es4</title>
</head>
<body>
<h1>${dto}</h1>
<h1><c:out value="${dto}"> </c:out> </h1>
</body>
</html>
RedirectAttributes 와 리다이렉션
스프링 MVC의 경우 반환타입이 문자열이고 redirect: 로 시작하는 경우 리다이렉트 처리
RedirectAttributes는 리다이렉트시에 필요한 쿼리 스트링을 구성하기 위한 객체
addFlashAttribute( ): 일회성으로 전달되는 값 전달을 위해 사용
addAttribute( ): 리다이렉트시에 쿼리 스트링으로 작성되는 값
@GetMapping("/ex5")
public String ex5(RedirectAttributes redirectAttributes){ // String으로 반환타입
redirectAttributes.addAttribute("name","aaa");
redirectAttributes.addFlashAttribute("result","success");
return "redirect:/todo/ex6"; // 리다이렉트
}
@GetMapping("/ex6")
public void ex6(){}
ex6.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>ex6 message print</title>
</head>
<body>
<h1>${result}</h1>
<h1><c:out value="${result}"> </c:out> </h1>
</body>
</html>
/todo/ex5 로 접속 -> /ex6?name=aaa 로 바뀜
새로고침하면 없어짐 1회성임
어노테이션 정리
컨트롤러 선언부에 사용하는 어노테이션
@Controller : 스프링 빈의 처리됨을 명시
@RestController : REST 방식의 처리를 위한 컨트롤러로 명시
@RequestMapping : 특정한 URL 패턴에 맞는 컨트롤러로 명시
메소드 선언부에 사용하는 어노테이션
@GetMapping / @PostMapping / @DeleteMapping / @PutMapping
@RequestMapping : Get/Post 방식 모두 지원하는 경우 사용
@ResponseBody : REST 방식에서 사용
메소드의 파라미터에 사용하는 어노테이션
@RequestParam
@ModelAttribute
@PathVariable
@SessionAttribute
@Valid
@RequestBody
다양한 리턴 타입
상속이나 인터페이스와 달리 다양한 리턴 타입을 사용할 수 있다.
void
String
사용자 정의 타입
배열/컬렉션
ResponseEntity 등
스프링 MVC의 예외처리
@ControllerAdvice를 이용해서 처리
예외에 따라서 @ExceptionHandler를 메서드에 활용
@GetMapping("/ex7")
public void ex7(String p1, int p2){
log.info("p1"+p1);
log.info("p2"+p2);
}
http://localhost:8090/ex7?p1=AAAA&p2=BBB
p2는 int인데 String 전달 -> 400 에러
예외처리 클래스
@ControllerAdvice
@Log4j2
public class CommonExceptionAdvice {
@ResponseBody // 내가받은 문자열 브라우저에 그대로보냄.. /??
@ExceptionHandler(NumberFormatException.class) //
public String exceptionNumber(NumberFormatException numberFormatException){
log.info("----------------");
log.error(numberFormatException.getMessage());
return "NUMBER FORMAT EXECEPTION";
}
}
범용적인 예외처리
예외 발생시 상위 타입인 Exception을 이용해서 예외 메시지를 구성
디버깅 용도로 활용
이렇게 해주면 자세한 내용 다 나옴
@ControllerAdvice
@Log4j2
public class CommonExceptionAdvice {
@ResponseBody // 내가받은 문자열 브라우저에 그대로보냄.. /??
@ExceptionHandler(Exception.class) //
public String exceptionCommon(Exception exception){
log.info("----------------");
log.error(exception.getMessage());
StringBuffer buffer = new StringBuffer("<ul>");
buffer.append("<li>" + exception.getMessage()+"<li>");
Arrays.stream(exception.getStackTrace()).forEach(stackTraceElement -> {
buffer.append("<li>"+stackTraceElement+"</li>");
});
buffer.append("</ul>");
return buffer.toString();
}
}
404에러
예외처리 notFound 메서드
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND) // NOT_FOUND가 발생하면
public String notFound(){
return "custom404"; // 여기로 이동하라
}
custom404.jsp를 만들었다.
<%@ page contentType="text/html;charset=UTF-8"
language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1> 페이지를 찾을 수 없습니다!</h1>
</body>
</html>
web.xml에 추가해준다.
<init-param>
<param-name>throwExceptionIfNoHandlerFound</paramname>
<param-value>true</param-value>
</init-param>
아무거나 치면 다음과 같이 출력된다.
Model Mapper 사용
build.gradle에 추가
implementation group: 'org.modelmapper', name:'modelmapper' , version : '3.0.0'
implementation group: 'org.hibernate', name : 'hibernate-validator' , version : '6.2.1.Final'
ModelMapperConfig
@Configuration // 해당 클래스가 스프링 빈에 대한 설정을 (@Configuration) 명시하는 클래스
public class ModelMapperConfig {
@Bean // 해당메소드의 실행 결과로 반환 된 객체를 스프링의 빈으로 등록시키는 역할
public ModelMapper getMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setFieldMatchingEnabled(true)
.setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE)
.setMatchingStrategy(MatchingStrategies.STRICT);
return modelMapper;
}
}
root-context.xml에 추가
Mapper 빈으로 등록할 수 있도록
<context:component-scan base-package="com.ssg.todo.config" />
mybatis 이용하는 개발 단계
1.VO선언
2.Mapper 인터페이스 개발
3.XML 쿼리문
4.테스트 코드 개발(tdd)
TodoMapper
public interface TodoMapper {
String getTime();
}
보통 MyBatis나 Spring Data 등의 ORM 프레임워크에서 매퍼 인터페이스는 데이터베이스와 상호 작용하는 메소드를 정의하는 데 사용
데이터베이스에서 시간 정보를 가져오는 메소드인 getTime()을 선언
resources - mappers - TodoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace=“com.ssg.springex.mapper.TodoMapper">
<select id="getTime" resultType="string">
select now()
</select>
</mapper>
<select> 요소는 SQL 쿼리를 정의하는 데 사용됩니다. 여기서는 getTime이라는 메서드를 나타내며, 이는 TodoMapper 인터페이스의 getTime() 메서드와 매핑됩니다. SQL 쿼리는 select now()로 지정되어 있으며, 현재 시간을 가져오는 쿼리입니다.
<select> 요소의 resultType 속성은 결과를 매핑할 Java 타입을 지정합니다. 여기서는 문자열 타입으로 설정되어 있으므로 SQL 결과가 문자열로 반환될 것으로 예상됩니다.
선언은 이 XML이 사용하는 DTD(Document Type Definition)을 지정합니다. MyBatis의 매퍼 파일은 주로 이러한 DTD를 사용하여 유효성을 검사하고 XML 문서를 파싱합니다.
TodoMapeprTests
@Log4j2
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")
public class TodoMapeprTests {
@Autowired(required = false)
private TodoMapper todoMapper;
@Test
public void testGetTimeNow(){
log.info(todoMapper.getTime());
}
}
'신세계 - Spring 공부' 카테고리의 다른 글
15주차 배운점 - Spring mybatis Todo 프로그램 (테이블 페이징) (0) | 2024.09.24 |
---|---|
15주차 배운점 - Spring mybatis Todo 프로그램 (CRUD) (0) | 2024.09.24 |
15주차 배운점 - 스프링, MyBatis, 스프링 Web MVC (2) | 2024.09.23 |
14주차 배운점 - Session, 쿠키, 필터 (1) | 2024.09.23 |
14주차 배운점 - Todo프로그램, ModelMapper, log4j2 (0) | 2024.09.23 |