Dev/Spring

Spring (다양한 리턴 타입, 스프링 MVC에서 주로 사용하는 어노테이션, 스프링 MVC 예외 처리, 404에러 페이지와 @ResponseStatus, 프로젝트의 구현 목표와 준비, 화면 디자인 - 부트스트랩, Log4j2, Log4js)

Walker_ 2024. 4. 24. 12:38

1. 다양한 리턴 타입

 - 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 가장 상세한 형태의 정보

 

 


공부 과정을 정리한 것이라 내용이 부족할 수 있습니다.

부족한 내용은 추가 자료들로 보충해주시면 좋을 것 같습니다.

읽어주셔서 감사합니다 :)