본문 바로가기
Spring

[Spring] 파일 업로드(1) 세팅

by moca7 2024. 10. 23.

 

 

ㅁ 5번째 프로젝트

- 다 써볼 예정. + 파일 업로드

 

 

 

 

ㅁ sql develoer

- sbatis 계정으로 테이블 2개, 시퀀스 2개를 더 만든다.

- 총 테이블 3개(NOTICE, BOARD, ATTACHMENT)와 시퀀스 3개(seq_notice, seq_bno, weq_fno)가 있다.

 

 

create table board
(
  board_no number primary key
, board_title varchar2(100) not null
, board_content varchar2(4000) 
);

create table attachment
(
  file_no number primary key
, file_path varchar2(200)
, original_name varchar2(200)
, filesystem_name varchar2(100)
, ref_board_no number references board
);

create sequence seq_bno;
create sequence seq_fno;

 

 

 

 

 

 

 

 

 

 

ㅁ 안쓰는 프로젝트 닫기

- 버벅이니까 안쓰는 프로젝트는 우클릭 - close project로 닫는다. 

- 그냥 닫히는것 뿐이고 더블클릭하면 다시 오픈된다.

 

 

 

ㅁ Spring Legacy Project 생성

 

 

- 프로젝트명을 입력하고, Spring MVC Project 선택하고, next를 누른다.

 

- 베이스 패키지는 com.br.file로 한다. 이러면 컨텍스트 패스는 /file이 된다.

 

 

 

 

ㅁ 베이스 패키지의 Homecontroller랑 views의 home.jsp 삭제

 

 

 

 

ㅁ pom.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>
 
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.br</groupId>
  <artifactId>sbatis</artifactId>
  <name>04_Spring_MyBatis_AOP</name>
  <packaging>war</packaging>
  <version>1.0.0-BUILD-SNAPSHOT</version>
 
  <properties>
    <java-version>11</java-version>
    <org.springframework-version>5.3.27</org.springframework-version>
    <org.aspectj-version>1.9.19</org.aspectj-version>
    <org.slf4j-version>2.0.7</org.slf4j-version>
  </properties>
 
  <dependencies>
 
    <!-- Spring -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${org.springframework-version}</version>
      <exclusions>
        <!-- Exclude Commons Logging in favor of SLF4j -->
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
         </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
       
    <!-- AspectJ (AOP를 위한 라이브러리)-->
    <dependency> <!-- 원래 있던 것. 이게 있어야 "Advice 동작 시점"의 어노테이션들을 사용할 수 있다. -->
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${org.aspectj-version}</version>
    </dependency>
   
    <!-- 위빙 : Advice(공통로직)를 PointCut(핵심로직)에 로딩되도록 함 -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>${org.aspectj-version}</version>
      <scope>runtime</scope>
    </dependency>  
   
   
   
   
    <!-- Logging (logback) -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.4.14</version>
      <!-- <scope>test</scope> 이건 지워야 함 -->
    </dependency>

    <!-- (2) slf4j -->
    <dependency> <!-- 기존 dependency 중 이것만 남기고 다 지운다.-->
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${org.slf4j-version}</version>
    </dependency>
   
    <!-- (3) log4jdbc -->
    <dependency>
      <groupId>org.bgee.log4jdbc-log4j2</groupId>
      <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
      <version>1.16</version>
    </dependency>


   

    <!-- @Inject -->
    <dependency>
      <groupId>javax.inject</groupId>
      <artifactId>javax.inject</artifactId>
      <version>1</version>
    </dependency>
       
    <!-- Servlet -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.3</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
 
    <!-- Test -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>        
   
   
    <!-- Lombok 라이브러리 추가 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>provided</scope>
    </dependency>

    <!-- Jackson 라이브러리 추가 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.14.2</version>
    </dependency>


    <!-- db관련 라이브러리 -->
    <!-- (1) ojdbc8 -->
    <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc8</artifactId>
      <version>23.2.0.0</version>
    </dependency>

    <!-- (2) spring-jdbc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>

    <!-- (3) mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.14</version>
    </dependency>

    <!-- (4) mybatis-spring -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.6</version>
    </dependency>

    <!-- (5) commons-dbcp -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.9.0</version>
    </dependency>

   

  </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java-version}</source>
                    <target>${java-version}</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

 

- 기존 4번째 프로젝트의 pom.xml에서 전부 가져오지 않고, <properties> 태그부터 끝까지를 복사해서

5번째 프로젝트의 pom.xml에 붙여넣는다.

- 라이브러리가 계속 추가되고 있는데 결국에는 다 쓸 예정이다.

 

- 라이브러리들 설명.

 

- 저장한다. 자바 버전은 바로 바뀌지 않는다. 프로젝트 우클릭 - Maven - update project한다.

 

 

 

 

ㅁ web.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"

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

  <!-- 인코딩 필터 등록 -->
  <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>
  </filter>
 
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
 
</web-app>

 

 

- 4번째 프로젝트의 web.xml에서 인코딩 필터 등록 부분의 <filter>, <filter-mapping> 태그를 복사해서

5번째 프로젝트의web.xml에 붙여넣는다.

 

 

 

 

ㅁ src/main/resources

- log4j.xml 삭제

- 4번째 프로젝트에서 log4jdbc.log4j2.properties과 logback.xml을 파일을 그대로 복사해서 가져온다.

 

 

 

 

ㅁ logback.xml 수정

 

 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


  <appender class="ch.qos.logback.core.ConsoleAppender" name="consoleLog">
    <encoder>
      <pattern>%-5level: [%date{yyyy-MM-dd HH:mm:ss}] [%logger:%line] - %msg%n</pattern>
    </encoder>
  </appender>

 
  <logger name="org.springframework" level="INFO" />
  <logger name="com.br.file" level="DEBUG" />


  <logger name="jdbc.sqlonly" level="off" />           <!-- 쿼리문만 -->
  <logger name="jdbc.sqltiming" level="INFO" />        <!-- 쿼리문 + 실행시간 -->
  <logger name="jdbc.audit" level="off" />             <!-- JDBC 호출 정보  -->
  <logger name="jdbc.resultset" level="off" />         <!-- ResultSet 호출 정보 -->
  <logger name="jdbc.resultsettable" level="off" />    <!-- ResultSet 결과 (조회결과 테이블) -->
  <logger name="jdbc.conntection" level="off" />       <!-- Connection 호출 정보 -->
 

 
  <root level="WARN">
    <appender-ref ref="consoleLog" />
  </root>  
     
   

</configuration>
 

 

- com.br.sbatis를 com.br.file로 바꾼다.

- sqltiming을 INFO로 바꾼다.

 

 

 

 

 

ㅁ 패키지 생성

 

- com.br.file.controller

- com.br.file.service

- com.br.file.dao

- com.br.file.dto

- com.br.file.util

 

- 서비스가 좀 많다면 도메인형 구조가 좋지만 이런 계층형 구조로도 해본다. 

계층형 구조로 패키지를 두는 회사도 많다.

- 패키지를 만들었다면 dto 클래스부터 생성한다.

 

 

 

 

 

ㅁ com.br.file.dto 패키지에 BoardDto 클래스 생성

 

 
package com.br.file.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@Builder
public class BoardDto {

  private int boardNo;
  private String boardTitle;
  private String boardContent;
 
}

 

- db를 참고해서 필드를 만든다.

- 이제부터 필드명은 소문자 하나 + 대문자로 노노. 최소 소문자 2개 다음에 대문자가 오게끔 필드명을 작성한다.

- 저 어노테이션들을 이제 기본으로 다 깔고간다.

- import할 때 Getter와 Setter는 lombok 패키지 걸로 고른다.

 

 

 

 

ㅁ com.br.file.dto 패키지에 AttachDto 클래스 생성

 

 
package com.br.file.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@Builder
public class AttachDto {

  private int fileNo;
  private String filePath;
  private String originalName;
  private String filesystemName;
  private int refBoardNo;
 
}

 

 

 

 

ㅁ 클래스 생성

- com.br.file.controller

- com.br.file.service

- com.br.file.dao

- com.br.file.dto

 

 

ㅁ src/main/resources

- config, mappers 일반 폴더 생성

- mappers 폴더 우클릭 - new - xml file - board-mapper.xml 입력후 finish 말고 next - 

 

 

 

- User Specified Entries에서 저걸 선택하고 next, 그 다음창에서 아무것도 안건들고 바로 finish.

 

 

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="boardMapper">
 
</mapper>
 

 

- <cache-ref> 태그는 반드시 지워야 한다.

- <mapper> 태그에 namespace 속성을 준다.

 

 

 

 

 

 

 

 

 

- config 우클릭 - new - xml file - mybatis-config.xml 입력후 finish 말고 next - 위와 똑같이 한다.

 

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" >
<configuration>

  <settings>
    <setting name="jdbcTypeForNull" value="NULL" />
  </settings>


  <typeAliases>
    <typeAlias type="com.br.file.dto.BoardDto" alias="BoardDto" />  
    <typeAlias type="com.br.file.dto.AttachDto" alias="AttachDto" />  
  </typeAliases>

  <mappers>
    <mapper resource="mappers/board-mapper.xml" />
  </mappers>

</configuration>
 

 

 

- 지금 이 문서들은 서버 구동과 동시에 읽혀져서 오류가 있으면 안된다.

- 클래스도 실제로 존재해야 한다. dto 클래스도 먼저 만들고 등록을 해야 한다.

- 매퍼 파일들도 실제로 존재해야 한다. 또 매퍼 파일들 마다 별칭도 있어야 한다. 매퍼 파일을 먼저 만들고 별칭도 namespace로 부여하고 등록한다.

 

 

 

 

 

ㅁ root-context.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>
 
  <!-- mybatis 사용을 위한 빈 3개 -->
  <bean class="org.apache.commons.dbcp2.BasicDataSource" id="dataSource" destroy-method="close">
    <!-- <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
         <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" /> -->
    <property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy" />
    <property name="url" value="jdbc:log4jdbc:oracle:thin:@localhost:1521:xe" />
    <property name="username" value="sbatis" />
    <property name="password" value="sbatis" />
  </bean>


  <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
    <property name="configLocation" value="classpath:config/mybatis-config.xml" />
    <property name="dataSource" ref="dataSource" />
  </bean>


  <bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSession">
    <constructor-arg ref="sqlSessionFactory" />
  </bean>  
 
 
 
  <!-- 트랜잭션 처리용 aop를 위한 구문 3개 -->
  <!-- AOP를 이용한 트랜잭션 처리 -->
  <!-- 1) 트랜잭션 매니저 빈으로 등록 (dataSource 객체 필요함) -->
  <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="txManager">
    <property name="dataSource" ref="dataSource" />
  </bean>
 
 
  <!-- 2) 트랜잭션 Advice 등록 -->
  <tx:advice transaction-manager="txManager" id="txAdvice">
    <tx:attributes>
      <tx:method name="*" /> <!-- pointcut의 모든 메소드에서 실행하겠다. (삽입, 수정, 삭제, 목록조회, 상세조회 등의 메소드가 있음) -->
      <tx:method name="select*" read-only="true" />  <!-- 단, select로 시작하는 메소드는 실행하지 않는다. (삽입, 수정, 삭제 메소드만 실행됨) -->
    </tx:attributes>
  </tx:advice>
 
 
  <!-- 3) AOP 등록 -->
  <aop:config>
    <aop:pointcut expression="execution(* com.br.sbatis.file.*Impl.*(..))" id="txPointcut" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
  </aop:config>
 
</beans>
 

 

- 4번째 프로젝트의 root-context.xml에서 <beans>~</beans> 부분에서 <breans>와 </beans> 태그는 빼고 그 안의 내용을 다 복사해서 5번째 프로젝트의 root-context.xml에 붙여넣는다.

- xml에 주석은 최대한 없는게 좋다. 오류를 많이 발생시킨다. 태그 안에 주석도 안주는게 좋다.

 

- namespace탭에서 aop와 tx를 선택한다.

 

 

 

- 위가 4번째 프로젝트의 root-context.xml이고, 아래가 지금 만드는 5번째 프로젝트의 root-context.xml이다.

- 'file'로 수정한다.

수정하지 않으면 오류가 발생하진 않는데 트랜잭션 처리가 안된다.

 

 

 

 

 

ㅁ BoardDao

 

 
package com.br.file.dao;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Repository
public class BoardDao {

  private final SqlSessionTemplate sqlSession;
 
}
 

 

 

- Service에서 dao 객체를 필요로 한다. 그러려면 dao가 빈으로 등록되어 있어야 한다.

- @Repository 어노테이션을 붙인다. 롬복이 아닌 스프링에서 제공한다.

 

 

 

ㅁ BoardService

 

 
package com.br.file.service;

public interface BoardService {
 
 
}
 

 

- 확인 필요

 

 

ㅁ BoardServiceImpl

 
package com.br.file.service;

import org.springframework.stereotype.Service;

import com.br.file.dao.BoardDao;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Service
public class BoardServiceImpl implements BoardService {

  private final BoardDao boardDao;
 
}
 

 

 

- 컨트롤러에서 서비스 객체를 필요로 한다. 그러려면 빈으로 등록되어 있어야 한다. @Service 어노테이션을 붙인다.

 

 

 

ㅁ BoardController

 

 
package com.br.file.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.br.file.service.BoardService;

import lombok.RequiredArgsConstructor;

@RequestMapping("/board")
@RequiredArgsConstructor
@Controller
public class BoardController {
 
    private final BoardService boardService;
   
}

 

- @Controller 어노테이션을 붙인다.

- @RequestMapping을 붙인다.

 

 

 

ㅁ 여기가 기본적인 세팅 끝이다.

 

 

- 서버에 add and remove로 현재 프로젝트를 올린다.

- 서버를 스타트해서 오류가 없는지 확인한다.

 

 

 

ㅁ 프로젝트 생성 후 세팅

 

 

0. 버전 및 라이브러리 등록 : pom.xml

1. 인코딩필터 등록 : web.xml
2. 로그관련 문서 세팅 
   1) logback.xml 복사 후 base package 수정 
   2) log4jdbc properties 복사 
3. 계층형 패키지 생성
4. Dto 클래스 먼저 만들기
5. mybatis 관련 문서 세팅
   1) mappers 폴더 만들어서 *-mapper.xml 파일 만들기 (반드시 namespace 까지 지정해둘것)
   2) config 폴더 만들어서 mybatis-config.xml 파일 만들기 
      ㄴ setting 태그 작성
      ㄴ typeAlias로 Dto 클래스들 alias 등록해두기
      ㄴ mapper파일들 등록해두기 
6. DB관련 빈 등록, 트랜잭션 관련 구문 작성 : root-context.xml
   1) mybatis 사용을 위한 빈 3개 등록
   2) 트랜잭션 처리를 위한 aop 등록 (base package 수정) 

   3) 첨부파일 업로드를 위한 빈 등록
7. MVC 패턴의 클래스 만들기
   1) controller, service<I>, serviceImpl, dao 만들기
   2) controller, serviceImpl, dao 에 어노테이션 붙여서 빈등록하기
   3) 각 클래스마다 필요한 필드 추가해서 DI 진행시키기
8. Server Start 해보기 (오류안나야됨)

 

 

===============================================================================

 

 


ㅁ views에 main.jsp 생성

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
   
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

    메인페이지

</body>
</html>
 

 

 

 

ㅁ controller에 MvcController 생성

 

 
package com.br.file.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MvcController {

  @GetMapping("/")
  public String mainPage() {
    return "main";
  }
 
}
 

 

- MvcController에는 항상 메인 페이지를 응답하는 메소드만 둔다.

- @Controller 어노테이션을 붙여서 빈으로 등록한다.

 

 

 

 

ㅁ 서버 스타트 후 메인페이지 접속

 

 

- http://localhost:8888/file를 입력하면 메인페이지가 응답된다.