Spring day 07

유요한·2022년 12월 14일
1

Spring

목록 보기
10/15
post-thumbnail

각 영역의 Naming Convention(명명 규칙)

프로젝트를 위와 같이 3-tier로 구성하는 가장 일반적인 설명은 유지보수에 대한 필요성 때문입니다. 각 영역은 독립적으로 설계되어 나중에 특정한 기술이 변하더라도 필요한 부분을 저자제품의 부품처럼 쉽게 교환할 수 있게 하자는 방식입니다. 따라서 각 영역은 설계 당시부터 영역을 구분하고, 해당 연결 부위는 인터페이스를 이용해서 설계하는 것이 일반적인 구성방식입니다.

페키지 이름을 어떻게 지을지 정하는 규칙
패키지명 : com.naver ← 거꾸로 만들면 된다.

요소별 명명

  • config
    프로젝트와 관련된 설정 클래스들의 보관 패키지

  • controller
    스프링 MVC의 Controller들의 보관 패키지

    xxxController
    : 스프링 MVC에서 동작하는 Controller 클래스를 설계할 때 사용

  • service
    스프링의 Service 인터페이스와 구현 클래스 패키지

    xxxService, xxxServiceImpl
    : 비즈니스 영역을 담당하는 인터페이스는 xxxService라는 방식을 사용하고, 인터페이스를 구현한 클래스는 xxxServiceImpl이라는 이름을 사용합니다.

  • domain
    VO, DTO 클래스들의 패키지
    : VO, DTO는 일반적으로 유사한 의미로 사용하는 용어로, 데이터를 담고 있는 객체를 의미한다는 공통점이 있습니다. 다만, VO의 경우는 주로 Read Only의 목적이 강하고, 데이터 자체도 불변하게 설계하는 것이 정석입니다. DTO는 주로 데이터 수집의 용도가 좀 더 강합니다. 예를들어, 웹 화면에서 로그인하는 정보를 DTO로 처리하는 방식을 사용합니다.

  • persistance
    MyBatis Mapper or JPA 등 영속계층을 위한 패키지

  • exception
    웹 관련 예외처리 패키지

  • aop
    스프링의 AOP 관련 패키지

  • security
    스프링 Security 관련 패키지

  • util
    각종 유틸리티 클래스 관련 패키지

  • dao or repository
    : DAO나 Repository(저장소)라는 이름으로 영역을 따로 구성하는 것이 보편적입니다. 다만

  • persistence
    : mybatis mapper 인터페이스 패키지


Service

  • Controller의 요청에 맞추어 Repository에서 받은 정보를 가공하여 Controller에게 넘겨주는 비지니스 로직

  • 흔히 얘기되는, MVC 패턴에서 비즈니스 로직 구성은 Controller, Service, Dao로 역할을 분산시켜 개발한다는 이야기는 일반적이다.

MVC 패턴에서 Service Model의 역할

View는 자신이 요청할 Controller만 알면 되며 Controller는 넘어온 매개변수를 이용해 Service 객체를 호출하기만 하면 된다. DAO는 ibatis / Mybatis 등 데이터베이스 Connection을 통해 데이터를 주고 받는 역할이다.

Service는 POJO객체로 구성된다. Controller처럼 Request / Response를 받지도 않고, DAO처럼 DB와 데이터를 주고받지도 않는다.

여기서 의문이 생긴다. 그러면 Service가 왜 필요할까?

DAO는 단일 데이터 접근 로직이다. 말 그대로 SQL 하나 보내고 결과를 받는 것이 전부인 로직이다. 하지만 비즈니스 로직이 단순이 SQL 하나 보내서 끝나는 것이 아니다. 여러번의 DB 접근이 필요하고, 어떤 서비스는 병렬식으로 동시접근하여 데이터를 가져와야 하는 상황도 발생한다. 그렇기 떄문에 Service라는 개념이 나온 것이다. 하나의 서비스를 위해 여러개의 DAO를 묶은 트랜잭션이 생성되고, Service는 곧 트랜잭션의 단위가 된다. 또 다른 점으로, Controller 내부에서 필요한 여러 Service를 구분하는 필요성을 가진다. 비슷한 요청이더라도 내부 로직이 달라야한다면 Controller는 매우 복잡해질 가능성이 있다. 이러한 점을 분리하여 Controller는 단순이 요청을 받아 해당 요청에 맞는 Service에 데이터를 주입하는 역할이다.

재사용이라는 Spring의 큰 장점은 Service가 중요한 작용점이다.

Service를 이해하기 위해 큰 틀

1) Client가 Request를 보낸다.(Ajax, Axios, fetch등..)

2) Request URL에 알맞은 Controller가 수신 받는다. (@Controller , @RestController)

3) Controller 는 넘어온 요청을 처리하기 위해 Service 를 호출한다.

4) Service는 알맞은 정보를 가공하여 Controller에게 데이터를 넘긴다.

5) Controller 는 Service 의 결과물을 Client 에게 전달해준다.

Service가 알맞은 정보를 가공하는 과정을 '비즈니스 로직을 수행한다.' 라고 합니다. Service가 비즈니스 로직을 수행하고 데이터베이스에 접근하는 DAO를 이용해서 결과값을 받아 옵니다.


프로젝트를 위한 요구사항

프로젝트를 진행하기 전에 고객의 요구사항을 인식하고, 이를 설계하는 과정이 필요합니다. 이를 흔히 요구사항 분석 설계라고 하는데, 고객이 원하는 내용이 무엇이고, 어느 정도까지 구현할 것인가에 대한 프로젝트의 범위를 정하는 것을 목적으로 합니다.

요구사항은 실제로 상당히 방대해 질 수 있으므로, 프로젝트에서는 단게를 정확히 구분해주는 것이 좋습니다. 만일 팀원들이 경험이 풍부하다면 초기 버전을 상당히 많은 기능을 포함시켜 개발을 진행할 수 있지만, 그렇지 못하다면 최대한 단순하고 눈에 보이는 결과를 만들어 내는 형태로 진행하는 것이 좋습니다.

요구사항은 온전한 문장으로 정리하는 것이 좋습니다. 주어는 고객이고 목적어는 대상이 됩니다. 여기서의 대상은 결국 데이터의 베이스 설계와 시스템 설계에서 가장 중요한 용어가 됩니다. 예를 들어, 게시판의 경우 다음과 같이 요구사항을 정리할 수 있습니다.

  • 고객은 새로운 게시물을 등록할 수 있어야 한다.
  • 고객은 특정한 게시물을 조회할 수 있어야 한다.
  • 고객은 작성한 게시물을 조회할 수 있어야 한다.
  • 기타 등등

이 경우 대상은 게시물이 되므로, 게시물이라는 용어가 필요하게 되고, 게시물의 구조를 판단해서 데이터베이스 테이블을 설계하게 됩니다. 예를 들어, 게시물의 경우 xxx_board라는 테이블을 설계하게 되고 테이블과 관련된 VO 클래스 역시 com.example.domain.BoardVO와 같은 이름으로 설계될 수 있고 com.example.domain.BoardDTO와 같은 이름으로 설계될 수 있습니다. 게시물과 관련된 로직은 com.example.service.BoardService가 될 수 있고, com.example.controller.BoardController라는 이름의 클래스를 생성하는 연속적인 과정을 거치게 됩니다.

요구사항에 따른 화면 설계

요구사항에서 나오는 용어를 기준으로 테이블이나 클래스 이름들이 정해지듯이 요구사항은 화면에도 영향을 미치게 됩니다. 게시글을 등록할 수 있는 화면을 고객에게 보여주려면 view를 구성하는 것들을 말합니다. 실제 프로젝트에서는 스토리보드를 만들게 됩니다.

이러한 화면을 설계할 때는 주로 Mock-up(목업) 툴을 이용하는 경우가 많습니다. 대표적으로는 PowerPoint를 이용하면 좋습니다.

각 화면을 설게하는 단계에서는 사용자가 입력해야 하는 값과 함께 전체 페이지의 흐름이 설계됩니다. 이 화면의 흐름을 URL로 구성하게 되는데 이 경우 GET/POST 방식에 대해서 같이 언급해두는 것이 좋습니다.


Day 07 정리

Mybatis

Mybatis XML을 사용한 코딩 순서

  • 테이블 생성 및 설정
  • 도메인 객체의 설계 및 클래스 작성
  • DAO 인터페이스 / 실행 기능 인터페이스 정의
  • XML Mapper 생성 및 SQL문 작성
  • XML 작성
  • MyBatis에 작성한 XML Mapper 인식 설정
  • DAO 인터페이스 구현한 클래스 작성
  • 스프링에 DAO 등록

Spring에서 Mybatis사용

스프링 프레임워크의 특징 중 하나는 다른 프레임워크들과 연동을 쉽게 하는 추가적인 라이브러리들이 많다는 점입니다. Mybatis 역시 mybatis-spring이라는 라이브러리를 통해 쉽게 연동할 수 있습니다.

  1. Spring에 Mybatis 라이브러리 추가

pom.xml에 적어준다.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.koreait</groupId>
  <artifactId>controller</artifactId>
  <name>ex00</name>
  <packaging>war</packaging>
  <version>1.0.0-BUILD-SNAPSHOT</version>
  <properties>
    <java-version>11</java-version>
    <org.springframework-version>5.0.7.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</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>
    <!-- HikariCP -->
    <!-- https://mvnrepository.com.artifiact/com.zaxxer/HikariCP -->
    <dependency>
      <groupId>com.zaxxer</groupId>
      <artifactId>HikariCP</artifactId>
      <version>3.4.5</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
      <version>8.0.28</version>
    </dependency>

    <!-- AspectJ -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${org.aspectj-version}</version>
    </dependency>

    <!-- JSON -->
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.6</version>
    </dependency>

    <dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-xml</artifactId>
      <version>2.9.6</version>
    </dependency>

    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.8.2</version>
    </dependency>

    <!-- Logging -->

    <!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2 -->
    <dependency>
      <groupId>org.bgee.log4jdbc-log4j2</groupId>
      <artifactId>log4jdbc-log4j2-jdbc4</artifactId>
      <version>1.16</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${org.slf4j-version}</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${org.slf4j-version}</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${org.slf4j-version}</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.0</version>
      <scope>1.2.17</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</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>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!-- Test -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </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.5.1</version>
        <configuration>
          <source>11</source>
          <target>11</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>

1-2. DBCP를 설정해준다.

pool이란곳에 넣어두고 꺼내 쓴다고 생각하면 된다.

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig" >
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/web0315" />
        <property name="username" value="root" />
        <property name="password" value="1234" />
    </bean>
  1. SQLSessionFactory 설정

Mybatis에서 가장 핵심 객체는 SQLSession하고 SQLSessionFactory입니다.

SQLSessionFactory는 내부적으로 SQLSession을 생성하는데 개발에서는 SQLSession을 통해 Connection을 생성하거나 원하는 SQL을 전달하고 결과를 리턴받는 구조로 작성하게 됩니다.

root-context.xml 설정
sqlSessionFactory 객체(Bean)을 설정합니다. sqlSessionFactory 설정 이전에 커넥션 풀과 dataSource가 세팅되어 있어야 합니다.

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
        <constructor-arg ref="hikariConfig" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
        <property name="dataSource" ref="dataSource" />
    </bean>

그리고 mybatis를 적용하려는 패키지를 스캔하려면 다음과 같은 코드를 적어야한다.

 <mybatis-spring:scan base-package="com.example.mapper" />

스프링에서 sqlSessionFactory를 등록하는 작업은 sqlSessionFactoryBean을 이용합니다. 패키지명을 보면 Mybatis의 패키지가 아니라 스프링과 연동작업을 처리하는 mybatis-spring 라이브러리의 클래스임을 알 수 있다.

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"
    xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
   xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
	http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig" >
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/web0315" />
        <property name="username" value="root" />
        <property name="password" value="1234" />
    </bean>

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
        <constructor-arg ref="hikariConfig" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
        <property name="dataSource" ref="dataSource" />
    </bean>

    <mybatis-spring:scan base-package="com.example.mapper" />
    <context:component-scan base-package="com.example.controller" />
</beans>

여기까지가 Spring에서 Mybatis를 사용하기 위한 설정이다.
이제 본격적으로 오늘 배운 것을 정리해보자!

  1. SQL 테이블 생성
use web0315;

create table spring_user(
    userid varchar(300) primary key ,
    userpw varchar(300) not null ,
    username varchar(300) not null
);

create table spring_board(
    boardnum bigint primary key auto_increment,
    boardtitle varchar(300) not null ,
    boardcontents varchar(6000) not null ,
    userid varchar(300),
    regdate datetime default now(),
    updatedate datetime default now(),
    constraint board_user_fk foreign key (userid) references  spring_user(userid)
);
  1. view를 작성

index.jsp

<%@page contentType="text/html; charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Spring Board</title>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
    <link rel="shortcut icon" href="#">
    <meta name="description" content=""/>
    <meta name="keywords" content=""/>
    <link rel="stylesheet" href="/resources/assets/css/main.css"/>
</head>
<body class="is-preload">

<!-- Header -->
<header id="header" class="alt">
    <a class="logo" href="/">Spring <span>Board</span></a>
    <nav id="nav">
        <ul>
            <c:choose>
                <c:when test="${loginUser == null}">
                    <li class="current"><a href="/">Home</a></li>
                    <li><a href="/user/join">Join</a></li>
                    <li><a href="/user/login">Login</a></li>
                </c:when>
                <c:otherwise>
                    <li>${loginUser}님 환영합니다!</li>
                    <li class="current"><a href="/">Home</a></li>
                    <li><a href="/board/list">Board</a></li>
                    <li><a href="/user/logout">Logout</a></li>
                </c:otherwise>
            </c:choose>
        </ul>
    </nav>
</header>

<!-- Banner -->
<div id="banner">
    <div class="wrapper style1 special">
        <div class="inner">
            <h1 class="heading alt">스프링 게시판</h1>
            <p>스프링 최종 예제</p>
            <div class="image fit special">
                <img src="https://images.unsplash.com/photo-1657497850516-de7b59ac243b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1160&q=80" alt="" />
            </div>
        </div>
    </div>
</div>

<!-- Scripts -->
<script src="/resources/assets/js/jquery.min.js"></script>
<script src="/resources/assets/js/jquery.dropotron.min.js"></script>
<script src="/resources/assets/js/browser.min.js"></script>
<script src="/resources/assets/js/breakpoints.min.js"></script>
<script src="/resources/assets/js/util.js"></script>
<script src="/resources/assets/js/main.js"></script>
</body>
</html>

여기서 외부 css나 js를 연결해줄 때 <link rel="stylesheet" href="/resources/assets/css/main.css"/> /resources는 src/main/resources가 아니라 webapp안에 있는 resources다. 이렇게 설정하려면 servlet-context.xml에 한가지 추가 설정을 넣어야 한다.

<resources mapping="/resources/**" location="/resources/" />

그러면 css가 잘 먹는 걸 확인할 수 있다!
그리고 <li class="current"><a href="/">Home</a></li>에서 /의 의미는 스프링에서는 기본적으로 controller를 지나치기 때문에 HomeController에서 /로 되어있는것을 가져온다. 거기서 return으로 index.jsp를 반환하기 때문에 기본 페이지로 와진다.

join.jsp

<%@page contentType="text/html; charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Spring Board</title>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
    <link rel="shortcut icon" href="#">
    <meta name="description" content=""/>
    <meta name="keywords" content=""/>
    <link rel="stylesheet" href="/resources/assets/css/main.css"/>
    <style>
        .heading {
            color: white;
        }

        .joinForm {
            width: 50%;
            margin: 0 auto;
        }
        .joinForm h3 {
            float: left;
            width: 30%;
            color: white;
            line-height: 3.24rem;
        }
        .joinForm input[type=text], .joinForm input[type=password] {
            float: right;
            width: 70%;
        }
        .joinForm>.col-12::after{
            display: block;
            content: '';
            height: 50px;
            clear: both;
        }
    </style>
</head>
<body class="is-preload">

<!-- Header -->
<header id="header" class="alt">
    <a class="logo" href="/">Spring <span>Board</span></a>
    <nav id="nav">
        <ul>
            <li class="current"><a href="/">Home</a></li>
            <li><a href="/user/join">Join</a></li>
            <li><a href="/user/login">Login</a></li>
        </ul>
    </nav>
</header>

<div id="main">
    <div class="wrapper style1 special">
        <div class="inner">
            <h2 class="heading alt">회원가입</h2>
            <br />
            <form class="joinForm" name="joinForm" id="joinForm" action="/user/join" method="post">
                <div class="col-12">
                    <h3>아이디</h3>
                    <input type="text" name="userId" />
                </div>
                <div class="col-12">
                    <h3>비밀번호</h3>
                    <input type="password" name="userPw"/>
                </div>
                <div class="col-12">
                    <h3>이름</h3>
                    <input type="text" name="userName"/>
                </div>
                <div class="col-12" style="text-align: center">
                    <input type="submit"  value="회원가입" class="primary"/>
                </div>
            </form>
        </div>
    </div>
</div>

<!-- Scripts -->
<script src="/resources/assets/js/jquery.min.js"></script>
<script src="/resources/assets/js/jquery.dropotron.min.js"></script>
<script src="/resources/assets/js/browser.min.js"></script>
<script src="/resources/assets/js/breakpoints.min.js"></script>
<script src="/resources/assets/js/util.js"></script>
<script src="/resources/assets/js/main.js"></script>
</body>
</html>

login.jsp

<%@page contentType="text/html; charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
  <title>Spring Board</title>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
  <link rel="shortcut icon" href="#">
  <meta name="description" content=""/>
  <meta name="keywords" content=""/>
  <link rel="stylesheet" href="/resources/assets/css/main.css"/>
  <style>
    .heading {
      color: white;
    }

    .loginForm {
      width: 50%;
      margin: 0 auto;
    }
    .loginForm h3 {
      float: left;
      width: 30%;
      color: white;
      line-height: 3.24rem;
    }
    .loginForm input[type=text], .loginForm input[type=password] {
      float: right;
      width: 70%;
    }
    .loginForm>.col-12::after{
      display: block;
      content: '';
      height: 50px;
      clear: both;
    }
  </style>
</head>
<body class="is-preload">

<!-- Header -->
<header id="header" class="alt">
  <a class="logo" href="/">Spring <span>Board</span></a>
  <nav id="nav">
    <ul>
      <li class="current"><a href="/">Home</a></li>
      <li><a href="/user/join">Join</a></li>
      <li><a href="/user/login">Login</a></li>
    </ul>
  </nav>
</header>

<div id="main">
  <div class="wrapper style1 special">
    <div class="inner">
      <h2 class="heading alt">로그인</h2>
      <br />
      <form class="loginForm" name="loginForm" id="loginForm" action="" method="post">
        <div class="col-12">
          <h3>아이디</h3>
          <input type="text" name="userId" />
        </div>
        <div class="col-12">
          <h3>비밀번호</h3>
          <input type="password" name="userPw"/>
        </div>
        <div class="col-12" style="text-align: center">
          <input type="submit"  value="로그인" class="primary"/>
        </div>
      </form>
    </div>
  </div>
</div>

<!-- Scripts -->
<script src="/resources/assets/js/jquery.min.js"></script>
<script src="/resources/assets/js/jquery.dropotron.min.js"></script>
<script src="/resources/assets/js/browser.min.js"></script>
<script src="/resources/assets/js/breakpoints.min.js"></script>
<script src="/resources/assets/js/util.js"></script>
<script src="/resources/assets/js/main.js"></script>
</body>
</html>

css & 이미지 등등

  1. UserController 생성

view를 만들어줬으면 그것을 안내해줄 controller가 필요하다. 지금 만든 view들은 user하고 관련된거기 때문에 UserController로 만들어준다.

UserController.java

package com.example.controller;

import com.example.domain.UserDTO;
import lombok.extern.log4j.Log4j;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
@Log4j
@RequestMapping("/user/*")
public class UserController {
    // a태그이니까 GetMapping
//    @GetMapping("/join")
//    public void join() {
//    }
//
//    @GetMapping("/login")
//    public void login() {
//    }

    @GetMapping({"/join","/login"})
    public void replace() {}

    @PostMapping("/join")
    public String join(UserDTO user, HttpServletRequest req) {
    }
}

다음 작업은 UserDTO를 만들어야 한다. 그 이유는 회원가입할 때 하나의 데이터가 오는것이 아니라 여러개의 데이터가 오기 때문이다.

src/main/java에 com.example.domain 패키지를 만들고 UserDTO를 만든다.

UserDTO.java

package com.example.domain;

import lombok.Data;

@Data
public class UserDTO {
    private String userId;
    private String userPw;
    private String userName;;
}

이제 mybatis를 사용하기 위해 mapper을 해줘야 한다. xml로 관리하고자 한다. src/main/java에 com.example.mapper 패키지 생성 후 UserMapper을 만든다. 그리고 src/main/resources에 com.example.mapper 패키지를 만들어서 UserMapper을 만든다.

UserMapper.java → 인터페이스

package com.example.mapper;

import com.example.domain.UserDTO;
import org.apache.ibatis.annotations.Param;

public interface UserMapper {
    int join(UserDTO user);
    // MyBatis는 두개 이상의 데이터를 파라미터로 넘길 때 객체나 Map, List 등 혹은 @Param을 이용한다.
    // 정해진 파라미터는 MyBatis에서 #{param명}으로 사용 가능하다.
    UserDTO login(@Param("userId")String userId, @Param("userPw")String userPw);
}

UserMapper.xml

<?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="com.example.mapper.UserMapper">
    <insert id="join">
        insert into spring_user values(#{userId}, #{userPw}, #{userName})
    </insert>
    <select id="login" resultType="com.example.domain.UserDTO">
        select * from spring_user where userid=#{userId} and userpw=#{userPw}
    </select>
</mapper>

스프링에서 작업할 때는 하나하나 테스트해주는 것이 좋은 개발자다. 테스트를 해주자!

src/test/java에 com.example.mapper 패키지를 만들고 UserMapperTest을 만든다.

UserMapperTest.java

package com.example.mapper;

import com.example.domain.UserDTO;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@Log4j
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
public class UserMapperTest {
    @Setter(onMethod_ = @Autowired)
    private UserMapper mapper;

//    @Test
//    public void joinTest() {
//        UserDTO user = new UserDTO();
//        user.setUserId("testId");
//        user.setUserPw("testPw");
//        user.setUserName("testName");
//
//        boolean result = 1 == mapper.join(user);
//        log.info("Result : " + result);
//    }

    @Test
    public void loginTest() {
        UserDTO loginUser = mapper.login("testid", "testpw");
        log.info(loginUser);
        System.out.println(loginUser);
    }
}

테스트는 하나하나 해줘야 한다.

여기까지 해줬으면 Mybatis는 끝난것이다.

service를 구성해야한다.

service는 비즈니스 로직이다.

src/main/java에 com.example.service패키지를 만들고 UserService를 만든다.

userService.java →인터페이스

package com.example.service;

import com.example.domain.UserDTO;

public interface UserService {
    boolean join(UserDTO user);
    UserDTO login(String userId, String userPw);
}

UserServiceImpl

package com.example.service;

import com.example.domain.UserDTO;
import com.example.mapper.UserMapper;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Log4j
public class UserServiceImpl implements UserService {
    @Setter(onMethod_ = @Autowired)
    private UserMapper mapper;

    @Override
    public boolean join(UserDTO user) {
        return mapper.join(user) == 1;
    }

    @Override
    public UserDTO login(String userId, String userPw) {
        UserDTO loginUser = mapper.login(userId, userPw);
        return loginUser;
    }
}

여기서 작성한 것을 보면 test했던 것들과 같은걸 확인할 수 있는데 테스트에서 성공했기 때문에 에러 걱정없이 바로 쓸 수 있다. 차이점은 여기가 service라고 어노테이션으로 @Service로 알려줘야 한다. 그리고 root-context에 <context:component-scan base-package="com.example.service" />적어서 안내해줘야 한다.

profile
발전하기 위한 공부

0개의 댓글