Learn & Record
Spring (다양한 리턴 타입, 스프링 MVC에서 주로 사용하는 어노테이션, 스프링 MVC 예외 처리, 404에러 페이지와 @ResponseStatus, 프로젝트의 구현 목표와 준비, 화면 디자인 - 부트스트랩, Log4j2, Log4js) 본문
Spring (다양한 리턴 타입, 스프링 MVC에서 주로 사용하는 어노테이션, 스프링 MVC 예외 처리, 404에러 페이지와 @ResponseStatus, 프로젝트의 구현 목표와 준비, 화면 디자인 - 부트스트랩, Log4j2, Log4js)
Walker_ 2024. 4. 24. 12:381. 다양한 리턴 타입
- void, 문자열, 객체나 배열, 기본 자료형, ResponseEntry
- 일반 웹서버 역할 : html을 response
- RESTfull or RESTAPI : json을 response > 공공API에서 사용해본 방식.
- 최근에 MSA가 인기를 끌면서 rest 방식이 인기를 끌고 있음
- 주로 redirect 사용
2. 스프링 MVC에서 주로 사용하는 어노테이션
- @Controller : 스프링 빈의 처리됨을 명시
- @RestController : REST 방식의 처리를 위한 컨트롤러임을 명시
- @RequestMapping : 특정한 URL 패턴에 맞는 컨트롤러인지를 명시
- @GetMapping / @PostMapping / @DeleteMapping / @PutMapping
- HTTP 전송방식 method에 따라 메서드를 지정하는 경우에 사용
- @RequestParam : Request에 있는 특정한 이름의 데이터를 파라미터로 받아서 처리하는 경우
- @PathVariable : URL 경로의 일부를 변수로 삼아서 처리하기 위해서 사용
- @ModelAttribute : 해당 파라미터는 반드시 Mdoel에 포함되어서 다시 뷰 View로 전달됨을 명시
- 기타 : @SessionAttribute, @Valid 등
3. 스프링 MVC 예외 처리
- controller 아래에 패키지와 파일 추가
package com.example.spring_project_02.controller.exception;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.ControllerAdvice;
@ControllerAdvice
@Log4j2
public class CommonException {
}
- 코드 (어노테이션) 추가
@GetMapping("/ex7")
public void ex7(String p1, int p2) {
log.info("p1...." + p1);
log.info("p2...." + p2);
}
- SampleController에 코드 추가
- URL 작성하면 예외 발생
- p2에 정수를 기입하면 에러가 발생하지않음
- 즉, p2에 정수가 아니라서 에러가 난 것
package com.example.spring_project_02.controller.exception;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
@Log4j2
public class CommonExceptionAdvice {
@ResponseBody
@ExceptionHandler(NumberFormatException.class)
public String excepNumber(NumberFormatException numberFormatException) {
log.error("...");
log.error(numberFormatException.getMessage());
return "NUMBER FORMAT EXCEPTION";
}
}
- CommonExceptionAdvice에 위 코드 작성
- 서버 재실행 후 똑같이 URL 작성하면 예외처리
package com.example.spring_project_02.controller.exception;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.reflect.Array;
import java.util.Arrays;
@ControllerAdvice
@Log4j2
public class CommonExceptionAdvice {
@ResponseBody
@ExceptionHandler(NumberFormatException.class)
public String excepNumber(NumberFormatException numberFormatException) {
log.error("...");
log.error(numberFormatException.getMessage());
return "NUMBER FORMAT EXCEPTION";
}
@ResponseBody
@ExceptionHandler(Exception.class)
public String exceptCommon(Exception exception) {
log.error("...");
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();
}
}
- CommonExceptionAdvice에 위 코드 추가
- 에러 메세지
4. 404에러 페이지와 @ResponseStatus
- 에러 확인
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String notFound() {
return "custom404";
}
- CommonExceptionAdvice에 위 코드 추가
- view 패키지 안에 custom404.jsp 파일 생성
<%--
Created by IntelliJ IDEA.
User: 평일 오전 계정
Date: 2024-04-24
Time: 오전 9:51
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>페이지를 찾을 수 없습니다</h1>
</body>
</html>
- 코드 추가
<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/servlet-context.xml</param-value>
</init-param>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
- web.xml에 throwExceptionIfNoHandlerFound 파라미터 추가
- 다시 없는 URL을 접속하면 나오는 페이지 확인
5. 프로젝트의 구현 목표와 준비
- 스프링과 MyBatis, 스프링 MVC를 모두 결합하는 구조
- todo를 CRUD 기능을 개발하고 목록은 페이징 처리와 검색 기능을 구현
- 1) 프로젝트 준비
implementation 'org.springframework:spring-core:5.3.30'
implementation 'org.springframework:spring-context:5.3.30'
implementation 'org.springframework:spring-test:5.3.30'
implementation 'org.springframework:spring-webmvc:5.3.30'
implementation 'org.springframework:spring-jdbc:5.3.30'
implementation 'org.springframework:spring-tx:5.3.30'
// https://mvnrepository.com/artifact/org.projectlombok/lombok
compileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
testCompileOnly 'org.projectlombok:lombok:1.18.22'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
implementation 'org.apache.logging.log4j:log4j-core:2.17.2'
implementation 'org.apache.logging.log4j:log4j-api:2.17.2'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.2'
// https://mvnrepository.com/artifact/javax.servlet/jstl
implementation 'javax.servlet:jstl:1.2'
// https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client
implementation 'org.mariadb.jdbc:mariadb-java-client:3.1.4'
// https://mvnrepository.com/artifact/com.zaxxer/HikariCP
implementation 'com.zaxxer:HikariCP:5.0.1'
// https://mvnrepository.com/artifact/org.mybatis/mybatis
implementation 'org.mybatis:mybatis:3.5.9'
// https://mvnrepository.com/artifact/org.mybatis/mybatis-spring
implementation 'org.mybatis:mybatis-spring:2.0.7'
// https://mvnrepository.com/artifact/org.modelmapper/modelmapper
implementation 'org.modelmapper:modelmapper:3.0.0'
// https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator
implementation 'org.hibernate.validator:hibernate-validator:6.2.1.Final'
- build.gradle에 관련 라이브러리 있는 지 확인
- Database Drivers > + MariaDB 추가 > port 번호와 비밀번호 입력 후 > Test Connection 클릭 > 성공 확인
- Database 선택 > OK
- 쿼리 작성해서 테이블 생성, ` ` 백틱 사용해서 문자 감싸줘야 함
- service 패키지 추가
- dto : 컨트롤러와 서비스에서 사용
- vo : 서비스와 dao에서 사용
- 즉 서비스는 컨트롤러에서 dto를 받아서 vo로 변환한 후 dao에 전달
- 혹은 dao에서 vo를 받아 dto로 변환 후 컨트롤러에 전달
- config 패키지 생성 후 자바 클래스 생성
package com.example.spring_project_02.config;
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.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;
}
}
- ModelMapperConfig 파일에 위 코드 추가
<context:component-scan base-package="com.example.spring_project_02.config"/>
- root-context.xml에 위 코드 추가
6. 화면 디자인 - 부트스트랩 사용
- webapp > resources > test.html 생성
https://getbootstrap.com/docs/5.1/getting-started/introduction/
Introduction
Get started with Bootstrap, the world’s most popular framework for building responsive, mobile-first sites, with jsDelivr and a template starter page.
getbootstrap.com
- 공식 문서를 보고 추가
- 페이지 속 Starter Template 카피
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<h1>Hello, world!</h1>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body>
</html>
- test.html에 붙여넣기 ( 주석 삭제 )
- 프로젝트 재실행 후 주소로 접속
- 마우스 올려서 라이브러리 다운로드
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<div class="container-fluid">
<div class="row">
<h1>Header</h1>
</div>
<div class="row content">
<h1>Content</h1>
</div>
<div class="row footer">
<h1>Footer</h1>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body>
</html>
- 코드 추가
- 3) MyBatis와 스프링을 이용한 처리
- domain 패키지와 자바 파일 생성
package com.example.spring_project_02.domain;
import lombok.*;
import java.time.LocalDate;
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TodoVO {
private Long tno;
private String title;
private LocalDate dueDate;
private String writer;
private boolean finished;
}
- TodoVO에 위 코드 작성
- vo : getter와 생성자 작성
- dto : getter와 setter, 생성자 작성
- TodoMapper 인터페이스 생성
- resources > mapper 디렉토리와 > TodoMapper.xml 파일 생성
- 4) XML로 SQL 분리하기
- 매퍼 인터페이스를 정의하고 메소드를 선언
- 해당 XML 파일을 작성 (파일 이름과 매퍼 인터페이스 이름을 같게) 하고 <select>와 같은 태그를 이용해서 SQL 작성
- <select>, <insert> 등의 태그에 id 속성 값을 매퍼 인터페이스의 메소드 이름과 같게 작성
- TimeMapper2 만들고 코드 작성
- 리소스 > mapper > TimeMapper2.xml 만들고 코드 작성
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:/mapper/**/*.xml"/>
</bean>
<mybatis:scan base-package="com.example.spring_project_02.mapper"/>
- root-context.xml에 위 코드 추가
- TimeMapperTest에서 위 코드 작성 후 테스트 했을 때, 아래 시간이 출력되면 정상작동
- TodoMapperTest 만들어서 TodoMapper 또한 테스트해서 정상 작동 확인
<loggers>
<logger name="com.example.spring_project_02.mapper" level="TRACE" additivity="false">
<appender-ref ref="console"/>
</logger>
<root level="INFO" additivity="false">
<AppenderRef ref="console"/>
</root>
</loggers>
- log4j2.xml에 위 코드 추가
- 다시 Test 하면 Log 추가 출력
7. Log4js와 @Log4j2
- 레벨 LEVEL은 로그의 '중요도' 개념
레벨 | 처리 메서드 |
FATAL | 가장 심각한 오류 |
ERROR | 일반적인 오류 |
WARN | 오류는 아니지만 주의는 요구하는 경우, 더 이상 쓸모없는 api사용 등이 해당 |
INFO | 런타임 시 관심 있는 이벤트 |
DEBUG | 시스템 흐름과 관련된 상세 정보 |
TRACE | 가장 상세한 형태의 정보 |
공부 과정을 정리한 것이라 내용이 부족할 수 있습니다.
부족한 내용은 추가 자료들로 보충해주시면 좋을 것 같습니다.
읽어주셔서 감사합니다 :)