[Spring] Spring Legacy Project 생성 (IntelliJ)

dondonee·2023년 12월 22일
3
post-thumbnail

인텔리제이에서 Spring Legacy Project 생성하기



⚠️ 빌드 과정을 자세하게 다시 포스팅했다. (링크)



지금까지 스프링 부트의 Starter를 사용해서 편리한 빌드만 해 봤는데 이번에 듣게 된 강의에서 스프링 부트 없는 스프링 프로젝트인 Spring legacy proejct로 빌드를 해보게 되었다.

강의에서는 전자정부 표준프레임워크를 통해 쉽게 레거시 프로젝트의 기본적인 구조를 만들었는데, 나는 M2 맥북이라 전자정부 프레임워크를 설치할 수 없었다. 대신 이클립스에 STS4를 설치해 보았지만 어쩐지 레거시 프로젝트 생성 버튼은 뜨지 않았고 ... 어차피 나는 인텔리제이를 쓰고 싶었기 때문에 인텔리제이를 통한 레거시 프로젝트 빌드를 시도해 보았다.

  • STS(Spring Tool Suite)는 자바 엔터프라이즈 애플리케이션 개발에 최적화된 이클립스 기반 자바 IDE이다. 전자정부 표준프레임워크도 STS를 사용한다.


Maven 디렉토리 구조

.      
├── pom.xml        
├── src
│   ├── main
│   │   ├── java      
│   │   │   └── kr
│   │   │       └── board
│   │   ├── resources        
│   │   └── webapp         
│   │       ├── WEB-INF
│   │       │   ├── spring                      
│   │       │   │   ├── appServlet
│   │       │   │   │   └── servlet-context.xml
│   │       │   │   └── root-context.xml
│   │       │   └── views
│   │       ├── resources   
│   │       └── web.xml                                               
│   └── test          
│       ├── java
│       └── resources
└── target            

만들어야 할 기본 구조는 위와 같다.

처음에는 이 구조가 스프링에서 정의한 표준이라고 생각해서 열심히 스프링 문서를 뒤졌는데 아무리 뒤져보아도 내가 원하는 설명이 없었다. 알고보니 이것은 스프링이라기 보다는 메이븐의 구조라고 보는 것이 더 적절했다.

메이븐은 약속된 디렉토리 구조와 pom.xml라는 핵심 설정 파일을 기반으로 프로젝트를 빌드해주는 빌드 자동화 도구이다.


핵심 디렉토리 및 파일

핵심 디렉토리와 설정 파일들을 살펴보자. 참고로 이 프로젝트는 게시판을 만드는 프로젝트이며 MyBatis를 사용한다.

.
├── SpringMVC01.iml   //IntelliJ
├── mvnw              //Maven
├── mvnw.cmd          //Maven
├── pom.xml           --> Maven 프로젝트 설정 파일
├── src
│   ├── main
│   │   ├── java         --> Java 소스 코드
│   │   │   └── kr
│   │   │       └── board
│   │   │           ├── controller
│   │   │           │   └── BoardController.java
│   │   │           ├── entity
│   │   │           │   └── Board.java
│   │   │           └── mapper      --> 매퍼 인터페이스 & 매핑 XML
│   │   │               ├── BoardMapper.java
│   │   │               └── BoardMapper.xml
│   │   ├── resources            --> 설정 파일
│   │   └── webapp               --> 웹 애플리케이션 관련
│   │       ├── WEB-INF
│   │       │   ├── spring                         --> 스프링 설정
│   │       │   │   ├── appServlet
│   │       │   │   │   └── servlet-context.xml
│   │       │   │   └── root-context.xml
│   │       │   └── views
│   │       │       └── template.jsp    
│   │       ├── resources    --> 웹앱 정적 리소스(js, css)
│   │       └── web.xml      --> 웹앱 배포 설명자 파일 
│   └── test              --> 테스트 코드 및 리소스
│       ├── java
│       └── resources
└── target             --> 빌드, 패키징 관련 (빌드 도구에 의해 자동 생성)       

기본 디렉토리

  • pom.xml :
    • POM(Project Object Model)은 Maven의 핵심 작업 단위인데, 이에 대한 정보를 담고있는 것이 pom.xml이다. 프로젝트 정보, 의존성, 플러그인 등의 정보를 갖고 있다.
    • <properties>, <dependencies>, <plugins>
    • 🔗 [Maven docs.] Introduction to the POM
  • src/main/java : 소스 코드(.java)
    • src/main/java/kr/board/mapper 디렉토리의 경우 매퍼 인터페이스 소스 코드와 매핑 XML 파일이 위치할 수 있다.
  • src/main/resources
    • 주로 환경 설정 파일(profile)이 위치한다. 개발 서버나 운영 서버 등 서버마다 필요한 환경이 다를 수 있기 때문이다.

웹 관련

  • /src/main/webapp : 웹 애플리케이션 관련 디렉토리
  • /src/main/webapp/WEB-INF : 웹 애플리케이션 관련 메타 데이터와 리소스 포함
    • 참고) 클라이언트는 컨트롤러를 통해서만 WEB-INF 내부에 접근할 수 있다.
    • /src/main/webapp/WEB-INF/spring : 스프링 관련 디렉토리
    • root-context.xml : 루트 웹 애플리케이션 컨텍스트에 관한 스프링 빈 설정을 포함한다. 데이터소스, 서비스, 리포지토리 등 애플리케이션 전반에 걸친 설정과 관련이 있다.
    • ./appServlet/servlet-context.xml : 웹 계층(서블릿 컨텍스트)에 관한 스프링 빈 설정을 포함한다. 대표적으로 뷰 리졸버가 있다.
  • /src/main/webapp/WEB-INF/views : 뷰 디렉토리
    • 뷰를 구성하는 JSP 파일이 위치한다.
  • /src/main/webapp/resources : 웹 애플리케이션의 정적 리소스 파일
    • 주로 .js, .css 파일을 포함한다.
  • /src/main/webapp/web.xml : 웹 애플리케이션의 배포 설명자 파일
    • 톰캣 등이 웹 서버를 초기화 할때 사용
    • 특히 스프링 MVC의 DispatcherServlet 설정이 들어간다.

빌드/배포 관련

  • src/target : 빌드, 배포 관련 디렉토리
    • Maven에서 배포를 위한 빌드 출력물을 저장하는 디렉토리이다.
    • 특히 소스 코드(.java) 컴파일된 자바 바이트코드 파일(.class)이 위치한다.


인텔리제이로 빌드하기

프로젝트 생성

New Project에서 Jakarta EE를 선택한다.

  • TemplateWeb application
  • LanguageJava
  • Build systemMaven
  • JDKJDK 1.8

참고) Jakarta EE는 자바의 엔터프라이즈 에디션(EE) 플랫폼이다. 표준인 SE보다 확장된 범위를 다루며 이전에는 J2EE, Java EE라고 불렸으나 2017년 오라클에서 이클립스 재단으로 관할이 넘어가면서 Jakarta EE로 명칭이 변경되었다.

  • Java라는 이름의 라이센스는 오라클이 가지고 있으므로 이클립스 재단은 자바 섬에서 가장 큰 도시이자 인도네시아의 수도인 자카르타의 이름을 따왔다.

나는 Java 8(JDK 1.8)을 사용했으므로 VersionJava EE 8을 선택했다. Dependencies에 기본 선택되어 있는 Servlet 설정 그대로 생성해준다.


Tomcat 연결

이렇게 webapp, WEB-INF 디렉토리를 가진 올드한 구조가 만들어졌다. 톰캣 WAS 연결은 이전에 해둔게 있어서 자동 연결되었다.

만약 연결해 둔 것이 없다면 Run/Debug Configuration에서 + 버튼 → Tomcat Server - local 선택하고 톰캣이 설치된 경로를 찾아 libexec 디렉토리를 선택해주면 된다.

  • 나는 Homebrew로 톰캣을 설치했기 때문에 $ brew info tomcat@8 명령어로 설치 경로를 조회했다.

포트 충돌

한 번 실행해 보니 다음과 같은 오류가 뜬다. IDE에서 포트가 충돌했을 수 있다고 경고가 나온다. 터미널에서 $ sudo lsof -i :8080로 8080 포트를 사용하고 있는 프로세스를 조회해 보았더니 java *:http-alt에서 사용중이라고 한다.

$ kill -9 PID로 포트를 강제 종료해보아도 계속 다시 생성된다. 🤔 아마도 다른 프로젝트에서 사용한 스프링 부트에 내장된 톰캣인 것 같다.

톰캣 연결 설정에서 포트를 80808081로 변경해보았다.

프로젝트를 생성할 때 만들어져 있던 기본 파일인 index.jsp가 실행되었다.

그런데 경로가 /가 아니라 /demo_war_exploded이다.


컨텍스트 루트 변경

톰캣 연결 설정의 Deployment - Application contextSpringMVC01_war_exploded/로 바꿔준다.

잘 적용되었다.



스프링 MVC 프레임워크

아직 스프링 프레임워크는 추가한 적이 없기 때문에 라이브러리를 확인해보면 처음 프로젝트 생성 때 기본으로 삽입된 것만 존재한다.

MVN Repository에 가서 Sring Web MVC를 검색한다. 나는 최신 릴리즈 버전인 5.2.25.RELEASE로 선택했다.

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.25.RELEASE</version>
</dependency>

복사한 코드를 pom.xml에 붙여넣기 해 주고 빌드를 해 준다.

빌드가 완료된 뒤 라이브러리를 확인해보면 spring-webmvc 뿐 아니라 core와 기타 필요한 스프링 프레임워크가 들어와있는 것을 확인할 수 있다.


webapp 디렉토리

스프링 프레임워크가 성공적으로 추가되면 Spring Config 파일을 추가할 수 있게 된다.

웹 애플리케이션 디렉토리인 webapp을 만들어주고 하위 디렉토리와 XML 설정 파일들을 만들어주자.

  • resources, spring, WEB-INF 디렉토리
  • spring/appServlet 디렉토리, spring/root-context.xml
    • appServlet/servlet-context.xml
  • WEB-INF/views 디렉토리, WEB-INF/web.xml
    • 참고) template.jsp는 강의에서 만든 JSP 템플릿 파일이다.

설정 파일

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

        <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>

        <!-- 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>
</web-app>

디스패처 서블릿 관련 설정과 root-context.xml, servlet-context.xml 경로에 관한 설정이 있다.

root-context.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">

</beans>

아직 추가한 설정은 없다.

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/" />

    <!-- 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="kr.board.controller" />



</beans:beans>

뷰 리졸버와 컴포넌트 스캔 설정이 있다.



테스트

이제 프로젝트가 MVC 구조에 따라 잘 동작하는지 테스트해보자.

도메인 & 컨트롤러

게시글의 정보를 담는 객체인 Board를 만들고 getter, setter도 만들어준다. 아직 DB 연결은 하지 않았으므로 컨트롤러에서 모델에 전달한 값인 List<Board> list를 만들어준다. 그리고 list를 모델에 담아 boardList 뷰에 전달하자.

@Controller  //스프링에게 이 클래스가 컨트롤러임을 알려줌
public class BoardController {

    @RequestMapping("/boardList.do")
    public String boardList(Model model) {

        System.out.println("boardList.do 실행");

        Board vo = new Board();  //getter, setter 필수
        vo.setIdx(1);
        vo.setTitle("제목");
        vo.setContent("내용");
        vo.setWriter("작성자");
        vo.setIndate("2021-01-01");
        vo.setCount(0);

        List<Board> list = new ArrayList<>();  //임의 리스트 
        list.add(vo);
        list.add(vo);
        list.add(vo);

        model.addAttribute("list", list); //모델에 넣기

        return "boardList";  //뷰의 논리적 이름
    }

}

모델 & 뷰

모델을 받아서 출력할 뷰 파일(JSP)을 작성해준다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Spring MVC 01</title>
    <meta charset="utf-8">
    <%--  디바이스 크기 별로 화면 조정  --%>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <%--  부트스트랩 제공 CSS 사용  --%>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container">
    <h2>Panel Heading</h2>
    <div class="panel panel-default">
        <div class="panel-heading">Spring MVC 01</div>
        <div class="panel-body">
            <table class="table table-bordered table-hover">
                <tr>
                    <td>번호</td>
                    <td>제목</td>
                    <td>작성자</td>
                    <td>작성일</td>
                    <td>조회수</td>
                </tr>
                <c:forEach var="vo" items="${list}">
                    <tr>
                        <td>${vo.idx}</td>
                        <td>${vo.title}</td>
                        <td>${vo.writer}</td>
                        <td>${vo.indate}</td>
                        <td>${vo.count}</td>
                    </tr>
                </c:forEach>
            </table>
        </div>
        <div class="panel-footer">SP 1 </div>
    </div>
</div>

모델에 list라는 이름으로 담아 전달한 값을 ${list}로 받아 반복문으로 필드 값을 출력한다. 디자인은 부트스트랩을 사용했다.


결과

컨트롤러에서 지정한 @RequestMapping URL을 입력해보면 위와 같이 잘 출력된다. 적용한 스프링 MVC 프레임워크가 정상적으로 동작하는 것을 확인할 수 있다. 👍




후기

시간이 꽤 많이 걸려서 그냥 이클립스로 방법을 찾는게 빨랐겠다 싶어서 후회할 뻔 했지만... 이 삽질 속에서 배운게 많았다. 스트링 부트로 쉽게 빌드할 때는 전혀 신경쓰지 않았던 것들이었는데 직접 하나하나 세팅하려니 '이거는 왜 필요한 거지?' 라는 궁금증이 들 수밖에 없었다. 덕분에 스프링을 더 잘 이해할수 있게 된 것 같다. 😀



🔗 References

0개의 댓글