Coding History

국비 지원 IT(웹앱개발) 취업반 강의 48일차 (Spring)

BlackBirdIT 2024. 8. 12. 18:15

그 때 DB가 연결되지 않았던 원인을 찾고 해결했다.

server:
  port: 8080
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/24_08_Spring?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Seoul
    username: root
    password: 1234
mybatis:
  type-aliases-package: com.example.demo.vo

해당 코드가 적힌 application 파일을 yml 파일로 설정했어야했는데 properties 파일로 되어있어서 되지 않았던 것.

두 파일의 차이점은 이렇다.
properties와 yml의 대표적인 차이는 내부 구조에 있다. properties의 경우엔 각 줄마다 key=value의 형태로 이루어져 있지만, yml의 경우엔 들여쓰기로 구분되는 계층 구조 및 key: value의 형태로 이루어져 있다.

설정을 조금 바꾼다고,

package com.example.demo.repository;

import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.example.demo.vo.Article;

@Mapper
public interface ArticleRepository {

    @Insert("INSERT INTO article SET regDate = NOW(), updateDate = NOW(), title = #{title}, `body` = #{body}")
    public Article writeArticle(String title, String body);

    @Delete("DELETE FROM article WHERE id = #{id}")
    public void deleteArticle(int id);

    @Update("UPDATE article SET updateDate = NOW(), title = #{title}, `body` = #{body} WHERE id = #{id}")
    public void modifyArticle(int id, String title, String body);

    @Select("SELECT * FROM article WHERE id = #{id}")
    public Article getArticleById(int id);

    @Select("SELECT * FROM article ORDER BY id DESC")
    public List<Article> getArticles();

    @Select("SELECT LAST_INSERT_ID();")
    public int getLastInsertId();
}

해당 코드가 있는 패키지에 같은 클래스 이름의 xml 파일을 만들었다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.repository.ArticleRepository">
    <update id="modifyArticle">
        UPDATE article SET 
        updateDate = NOW(), 
        title = #{title}, 
        `body` = #{body} 
        WHERE id = #{id}
    </update>

    <insert id="writeArticle">
        INSERT INTO article
        SET regDate = NOW(),
        updateDate = NOW(),
        title = #{title},
        `body` = #{body}
    </insert>

    <select id="getArticles" resultType="Article">
        SELECT *
        FROM article
        ORDER BY
        id DESC
    </select>

    <select id="getArticleById" resultType="Article">
        SELECT *
        FROM article
        WHERE id = #{id}
    </select>
</mapper>

기존 sql을 주석처리하고 해당 메서드를 연결시켜주고 다시 sql문을 xml파일에 넣어줘서 실행되게끔. 잘 작동한다.

여기서 문제점 한가지. modify를 할 때 제목만 수정하고 싶을 수 있다. 하지만 제목만 수정하려고 제목만 써서 넣는다면 body가 null값이라고 오류가 난다. 여기서 mybatis를 사용하는 이유가 나오는데, 동적sql 해당 링크를 참고해서 sql을 짜보도록하자.

<!-- 기존 sql -->
    <update id="modifyArticle">
        UPDATE article SET 
        updateDate = NOW(), 
        title = #{title}, 
        `body` = #{body} 
        WHERE id = #{id}
    </update>
<!-- 동적 sql -->
    <update id="modifyArticle">
        UPDATE article 
        <set>
            <if test="title != null and title != ''">title = #{title},</if>
            <if test="body != null and body != ''">`body` = #{body},</if>
            updateDate = NOW()
        </set>
        WHERE id = #{id}
    </update>

이렇게 하면 오류 없이 하나만 수정할 수 있다!

이제는 회원가입 기능을 만들어보자 article의 형태를 그대로 따라오면서 클래스명과 sql등등만 고쳐보면서 하면 그렇게까지 어렵지 않게 만들 수 있다.

@Controller
public class UsrMemberController {

    @Autowired
    private MemberService memberService;

    @RequestMapping("/usr/member/doJoin")
    @ResponseBody
    public Member doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum,
            String email) {
        int id = memberService.doJoin(loginId, loginPw, name, nickname, cellphoneNum, email);
        Member member = memberService.getMemberById(id);

        return member;
    }

}
@Service
public class MemberService {

    @Autowired
    private MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public int doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum, String email) {
        memberRepository.doJoin(loginId, loginPw, name, nickname, cellphoneNum, email);
        return memberRepository.getLastInsertId();
    }

    public Member getMemberById(int id) {
        return memberRepository.getMemberById(id);
    }

}
@Mapper
public interface MemberRepository {

    @Select("SELECT LAST_INSERT_ID();")
    public int getLastInsertId();

    @Insert("INSERT INTO `member` SET regDate = NOW(), updateDate = NOW(), loginId = #{loginId}, loginPw = #{loginPw}, `name` = #{name}, nickname = #{nickname}, cellphoneNum = #{cellphoneNum}, email = #{email}")
    public void doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum, String email);

    @Select("SELECT * FROM `member` WHERE id = #{id}")
    public Member getMemberById(int id);

}

일단 이렇게 만들었고 확인을 해보면,


데이터 상으로도 문제 없이 회원가입이 된다.

다만 예외처리, loginId, nickname, email. 이 중복이 되어도 회원가입이 가능하기에 이를 에외처리 해주어야한다.

한참 구현중에 강사님이 데이터베이스 구조를 약간 수정하셨다.

CREATE TABLE `member`
(
    id         int(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    regDate    DATETIME         NOT NULL,
    updateDate DATETIME         NOT NULL,
    loginId   char(30)        not null,
    loginPw   char(100)        not null,
    `authLevel` SMALLINT(2) UNSIGNED DEFAULT 3 COMMENT '권한레벨 (3=일반, 7=관리자)',
    `name`      char(100)        NOT NULL,
    nickname    char(20)        NOT NULL,
    cellphoneNum char(20)         NOT NULL,
    email         char(100)        NOT NULL,
    delStatus TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '탈퇴여부 (0=탈퇴 전, 1=탈퇴 후)',
    delDate DATETIME COMMENT '탈퇴 날짜'
);

-- 회원 테스트데이터.
# 관리자.
INSERT INTO `member`
SET regDate = NOW(),
    updateDate = NOW(),
    loginId = 'admin',
    loginPw = 'admin',
    `authLevel` = 7,
    `name` = '관리자',
    nickname = '관리자',
    cellphoneNum = '01012341234',
    email = 'abcddd@gmail.com';


INSERT INTO `member`
SET regDate = NOW(),
    updateDate = NOW(),
    loginId = 'test1',
    loginPw = 'test1',
    `name` = '김철수',
    nickname = '김철수 닉네임',
    cellphoneNum = '01011312242',
    email = 'abcddd@gmail.com';

관리자 권한에 대한 것과 탈퇴시 데이터 관리를 위해 데이터 칼럼을 조금 더 추가했다.(원래는 훨씬 더 많다고 한다.)
관리자에 대한 것은 권한 레벨을 부여하는 것으로 차별을 준다. DEFAULT는 말 그대로 디폴트 값. 일반 유저는 3으로 주기 때문에 따로 데이터상의 삽입이 필요없고, 탈퇴도 마찬가지로 탈퇴전의 상태는 0이기 때문에 따로 삽입하지 않아도 된다.

아무튼 예외처리 코드를 한번 살펴보자

@Controller
public class UsrMemberController {

    @Autowired
    private MemberService memberService;

    @RequestMapping("/usr/member/doJoin")
    @ResponseBody
    public Object doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum,
            String email) {
        int id = memberService.doJoin(loginId, loginPw, name, nickname, cellphoneNum, email);
        Member member = memberService.getMemberById(id);

        if (id == -1) {
            return "이미 사용중인 아이디";
        }
        if (id == -2) {
            return "이미 사용중인 닉네임";
        }
        if (id == -3) {
            return "이미 사용중인 이메일";
        }
        return member;
    }

}

service에서 Member member = memberService.getMemberById(id); 해당 코드로 받은 매개변수를 넘겨주니까.

public int doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum, String email) {
//        if (getMemberByLoginId(loginId) != null) {
//            throw new IllegalArgumentException("이미 사용 중인 로그인 아이디입니다.");
//        }
//
//        if (getMemberByNickname(nickname) != null) {
//            throw new IllegalArgumentException("이미 사용 중인 닉네임입니다.");
//        }
//
//        if (getMemberByEmail(email) != null) {
//            throw new IllegalArgumentException("이미 사용 중인 이메일입니다.");
//        }

        Member existMemeber = memberRepository.getMemberByLoginId(loginId);
        if (existMemeber != null) {
            return -1;
        }
        existMemeber = memberRepository.getMemberByNickname(nickname);
        if (existMemeber != null) {
            return -2;
        }
        existMemeber = memberRepository.getMemberByEmail(email);
        if (existMemeber != null) {
            return -3;
        }

        memberRepository.doJoin(loginId, loginPw, name, nickname, cellphoneNum, email);
        return memberRepository.getLastInsertId();
    }

받은 매개 변수가 만약 존재한다면 return 값을 -1, -2, -3으로 전환하게끔 한다.(무엇이 중복인가? 에 대한 것.) 그렇다면 해당하는 것을 검증하는 쿼리 메서드를 또 따로 만들어준다.

    @Select("SELECT * FROM `member` WHERE loginId = #{loginId}")
    public Member getMemberByLoginId(String loginId);

    @Select("SELECT * FROM `member` WHERE nickname = #{nickname}")
    public Member getMemberByNickname(String nickname);

    @Select("SELECT * FROM `member` WHERE email = #{email}")
    public Member getMemberByEmail(String email);

이렇게 하면 이런 결과가 나온다. 현재 abc로 모든 값을 통일한 회원 데이터를 넣은 상태고,
아이디가 존재할 때,

닉네임이 존재할 때,

이메일이 존재할 때 이렇게 doJoin을 할 수 없게 막아준다.

다음은 이 입력란이 공란일 때나 입력을 아예 하지 않았을 경우에 오류가 나는 것을 해결해보자.

        if (loginId == null || loginId.trim().isEmpty()) {
            return "아이디를 입력해주세요.";
        }
        if (loginPw == null || loginPw.trim().isEmpty()) {
            return "비밀번호를 입력해주세요.";
        }
        if (name == null || name.trim().isEmpty()) {
            return "이름을 입력해주세요.";
        }
        if (nickname == null || nickname.trim().isEmpty()) {
            return "닉네임를 입력해주세요.";
        }
        if (cellphoneNum == null || cellphoneNum.trim().isEmpty()) {
            return "전화번호를 입력해주세요.";
        }
        if (email == null || email.trim().isEmpty()) {
            return "이메일을 입력해주세요.";
        }

이렇게 리턴으로 막으면 되지만 이러면 너무 줄이 길어지고 비효율적인 느낌이 드니까 클래스를 하나 만들어주자.

    @RequestMapping("/usr/member/doJoin")
    @ResponseBody
    public Object doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum,
            String email) {
        if (ut.isEmptyOrNull(loginId)) {
            return "아이디를 입력해주세요.";
        }
        if (ut.isEmptyOrNull(loginPw)) {
            return "비밀번호를 입력해주세요.";
        }
        if (ut.isEmptyOrNull(name)) {
            return "이름을 입력해주세요.";
        }
        if (ut.isEmptyOrNull(nickname)) {
            return "닉네임를 입력해주세요.";
        }
        if (ut.isEmptyOrNull(cellphoneNum)) {
            return "전화번호를 입력해주세요.";
        }
        if (ut.isEmptyOrNull(email)) {
            return "이메일을 입력해주세요.";
        }
package com.example.demo.util;

import java.lang.reflect.Array;
import java.util.Map;

public class Ut {
    public boolean isEmptyOrNull(String str) {

        return str == null || str.trim().isEmpty();
    }

    public static boolean isEmpty(Object obj) {
        if(obj == null) return true;

        if(obj instanceof String) return ((String)obj).trim().isEmpty();

        if (obj instanceof Map) return ((Map<?, ?>) obj).isEmpty();

        if (obj.getClass().isArray())return Array.getLength(obj) == 0;

        return false;
    }
}

이렇게 매개변수로 받아서 검증하고 리턴하는 식으로 만들었다.

다음은 두가지를 동시에 확인할 때, 즉 이름과 이메일을 확인하는 경우로 만들어보자면

@Controller
public class UsrMemberController {

    @Autowired
    private MemberService memberService;
    private Ut ut;

    @RequestMapping("/usr/member/doJoin")
    @ResponseBody
    public Object doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum,
            String email) {
        if (ut.isEmptyOrNull(loginId)) return "아이디를 입력해주세요.";

        if (ut.isEmptyOrNull(loginPw)) return "비밀번호를 입력해주세요.";

        if (ut.isEmptyOrNull(name)) return "이름을 입력해주세요.";

        if (ut.isEmptyOrNull(nickname)) return "닉네임를 입력해주세요.";

        if (ut.isEmptyOrNull(cellphoneNum)) return "전화번호를 입력해주세요.";

        if (ut.isEmptyOrNull(email)) return "이메일을 입력해주세요.";


        int id = memberService.doJoin(loginId, loginPw, name, nickname, cellphoneNum, email);
        Member member = memberService.getMemberById(id);

        if (id == -1) return "이미 사용중인 아이디";
        if (id == -2) return "이미 사용중인 닉네임";
        if (id == -3) return "이미 사용중인 이메일";
        if (id == -4) return "이미 사용중인 이름과 이메일";

        return member;
    }

}
@Service
public class MemberService {

    @Autowired
    private MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public int doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum, String email) {

        Member existMemeber = memberRepository.getMemberByLoginId(loginId);
        if (existMemeber != null) return -1;

        existMemeber = memberRepository.getMemberByNickname(nickname);
        if (existMemeber != null) return -2;

        existMemeber = memberRepository.getMemberByEmail(email);
        if (existMemeber != null) return -3;


        existMemeber = memberRepository.getMemberByNameAndEmail(name, email);
        if (existMemeber != null) return -4;

        memberRepository.doJoin(loginId, loginPw, name, nickname, cellphoneNum, email);
        return memberRepository.getLastInsertId();
    }

    public Member getMemberById(int id) {
        return memberRepository.getMemberById(id);
    }

}
@Mapper
public interface MemberRepository {

    @Select("SELECT LAST_INSERT_ID();")
    public int getLastInsertId();

    @Insert("INSERT INTO `member` SET regDate = NOW(), updateDate = NOW(), loginId = #{loginId}, loginPw = #{loginPw}, `name` = #{name}, nickname = #{nickname}, cellphoneNum = #{cellphoneNum}, email = #{email}")
    public void doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum, String email);

    @Select("SELECT * FROM `member` WHERE id = #{id}")
    public Member getMemberById(int id);

    @Select("SELECT * FROM `member` WHERE loginId = #{loginId}")
    public Member getMemberByLoginId(String loginId);

    @Select("SELECT * FROM `member` WHERE nickname = #{nickname}")
    public Member getMemberByNickname(String nickname);

    @Select("SELECT * FROM `member` WHERE email = #{email}")
    public Member getMemberByEmail(String email);

    @Select("SELECT * FROM `member` WHERE email = #{email} AND `name` = #{name}")
    public Member getMemberByNameAndEmail(String name, String email);

}

결국 하고자 하는 것은 똑같다. 매개변수를 두개를 받았냐 하나를 받았냐의 차이다.

        if (id == -5) return "이미 사용중인 이름과 전화번호";

        existMemeber = memberRepository.getMemberByNameAndCellphoneNum(name, cellphoneNum);
        if (existMemeber != null) return -5;

           @Select("SELECT * FROM `member` WHERE cellphoneNum = #{cellphoneNum} AND `name` = #{name}")
    public Member getMemberByNameAndCellphoneNum(String name, String cellphoneNum);

이름과 전화번호를 동시 확인하려면 이렇게 만들면 된다. 위에서부터 컨트롤러, 서비스, 리포지터리에 추가한다.

여기서 또 문장을 효율적으로 다루기 위해서 util에 Ut.f 메서드를 추가했다.

public static Object f(String format, Object... args) {
        return String.format(format, args); 
    }
        if (id == -1) return Ut.f("%s(은)는 이미 사용중인 아이디입니다.", loginId);
        if (id == -2) return Ut.f("%s(은)는 이미 사용중인 닉네임입니다.", nickname);
        if (id == -3) return Ut.f("%s(은)는 이미 사용중인 이메일입니다.", email);
        if (id == -4) return Ut.f("%s(은)는 이미 사용중인 이메일과 이름입니다.", email, name);
        if (id == -5) return Ut.f("%s와 %s(은)는 이미 사용중인 전화번호와 이름입니다.", cellphoneNum, name);

이렇게 문구도 잘 뜬다.

        if (id == -1) return Ut.f("%s(은)는 이미 사용중인 아이디입니다.", loginId);
        if (id == -2) return Ut.f("%s(은)는 이미 사용중인 닉네임입니다.", nickname);
        if (id == -3) return Ut.f("%s(은)는 이미 사용중인 이메일입니다.", email);
        if (id == -4) return Ut.f("%s(은)는 이미 사용중인 이메일과 이름입니다.", email, name);
        if (id == -5) return Ut.f("%s와 %s(은)는 이미 사용중인 전화번호와 이름입니다.", cellphoneNum, name);

코드를 고치면서 안건데 -1 -2 등등으로는 뭐가 틀렸는지 한눈에 보이지 않는다.(내가 문장으로 써 놓아서 그렇지 없다고 생각해보면 뭐가 문제인지 모를 것이다.) 그래서 클래스를 왔다갔다 하면서 이걸 고쳤는데 이럴 경우를 대비해서 오류 코드를 만든다고 하셨다.

이를 표준보고서라고 표현하고 살펴보자.
표준 보고서가 지켜야할 사항 or 있어야할 기능

  • 성공, 실패 여부를 쉽게 파악할 수 있도록
  • 관련 데이터를 주고 받을 수 있도록
  • 관련 메세지를 포함
package com.example.demo.vo;

import lombok.Getter;

public class ResultData {
    @Getter
    private String ResultCode;
    @Getter
    private String msg;
    @Getter
    private Object data1;

    public static ResultData from(String ResultCode, String msg) {

        return from(ResultCode, msg, null);
    }

    public static ResultData from(String ResultCode, String msg, Object data1) {
        ResultData rd = new ResultData();
        rd.ResultCode = ResultCode;
        rd.msg = msg;
        rd.data1 = data1;

        return rd;
    }
    public boolean isSuccess() {
        return ResultCode.startsWith("S-");
    }

    public boolean isFail() {
        return isSuccess() == false;
    }

}

이렇게 해서 이제 모든 컨트롤러를 ResultData로 만들어준다.

@Controller
public class UsrArticleController {

    @Autowired
    private ArticleService articleService;

    @RequestMapping("/usr/article/getArticle")
    @ResponseBody
    public ResultData getArticle(int id) {

        Article article = articleService.getArticleById(id);

        if (article == null) {
            return ResultData.from("F-1", Ut.f("%d번 게시물은 없습니다.", id));
        }

        return ResultData.from("S-1", Ut.f("%d번 게시물입니다.", id), article);
    }

    @RequestMapping("/usr/article/doModify")
    @ResponseBody
    public ResultData doModify(int id, String title, String body) {
        System.out.println("id : " + id);
        System.out.println("title : " + title);
        System.out.println("body : " + body);

        Article article = articleService.getArticleById(id);

        if (article == null) {
            return ResultData.from("F-1", Ut.f("%d번 게시물은 없습니다.", id));
        }

        articleService.modifyArticle(id, title, body);

        return ResultData.from("S-2", Ut.f("%d번 게시물 수정되었습니다.", id), article);
    }

    @RequestMapping("/usr/article/doDelete")
    @ResponseBody
    public ResultData doDelete(int id) {

        Article article = articleService.getArticleById(id);

        if (article == null) {
            return ResultData.from("F-1", Ut.f("%d번 게시물은 없습니다.", id));
        }

        articleService.deleteArticle(id);

        return ResultData.from("S-3", Ut.f("%d번 게시물 삭제되었습니다.", id));
    }

    @RequestMapping("/usr/article/doWrite")
    @ResponseBody
    public ResultData doWrite(String title, String body) {
        int id = articleService.writeArticle(title, body);
        Article article = articleService.getArticleById(id);
        return ResultData.from("S-4", Ut.f("%d번 게시물 작성되었습니다.", id), article);
    }

    @RequestMapping("/usr/article/getArticles")
    @ResponseBody
    public List<Article> getArticles() {
        return articleService.getArticles();
    }

}
@Controller
public class UsrMemberController {

    @Autowired
    private MemberService memberService;

    @RequestMapping("/usr/member/doJoin")
    @ResponseBody
    public ResultData doJoin(String loginId, String loginPw, String name, String nickname, String cellphoneNum,
            String email) {
        if (Ut.isEmptyOrNull(loginId))
            return ResultData.from("F-1", Ut.f("아이디를 입력해주세요."));

        if (Ut.isEmptyOrNull(loginPw))
            return ResultData.from("F-1", Ut.f("비밀번호를 입력해주세요."));

        if (Ut.isEmptyOrNull(name))
            return ResultData.from("F-1", Ut.f("이름을 입력해주세요."));

        if (Ut.isEmptyOrNull(nickname))
            return ResultData.from("F-1", Ut.f("닉네임를 입력해주세요."));

        if (Ut.isEmptyOrNull(cellphoneNum))
            return ResultData.from("F-1", Ut.f("전화번호를 입력해주세요."));

        if (Ut.isEmptyOrNull(email))
            return ResultData.from("F-1", Ut.f("이메일을 입력해주세요."));

        int id = memberService.doJoin(loginId, loginPw, name, nickname, cellphoneNum, email);
        Member member = memberService.getMemberById(id);

        if (id == -1)
            return ResultData.from("F-1", Ut.f("%s(은)는 이미 사용중인 아이디입니다.", loginId));
        if (id == -2)
            return ResultData.from("F-1", Ut.f("%s(은)는 이미 사용중인 닉네임입니다.", nickname));
        if (id == -3)
            return ResultData.from("F-1", Ut.f("%s(은)는 이미 사용중인 이메일입니다.", email));
        if (id == -4)
            return ResultData.from("F-1", Ut.f("%s(은)는 이미 사용중인 이메일과 이름입니다.", email, name));
        if (id == -5)
            return ResultData.from("F-1", Ut.f("%s와 %s(은)는 이미 사용중인 전화번호와 이름입니다.", cellphoneNum, name));

        return ResultData.from("S-1", Ut.f("회원가입 완료. %s님 환영합니다.", nickname));
    }

    @RequestMapping("/usr/member/doLogin")
    @ResponseBody
    public Object doLogin(String loginId, String loginPw) {
        int id = memberService.doLogin(loginId, loginPw);

        Member member = memberService.getMemberById(id);
        return member;
    }

}

모두 정상작동한다.

이런 식이다.

게시물이 존재한다면 이렇게.

난 이걸 좀 빠르게 해서 로그인 기능까지 먼저 만들어봤다.

    @RequestMapping("/usr/member/doLogin")
    @ResponseBody
    public ResultData doLogin(String loginId, String loginPw) {

        if (Ut.isEmptyOrNull(loginId))
            return ResultData.from("F-1", Ut.f("아이디를 입력해주세요."));

        if (Ut.isEmptyOrNull(loginPw))
            return ResultData.from("F-1", Ut.f("비밀번호를 입력해주세요."));

        int id = memberService.doLogin(loginId, loginPw);
        Member member = memberService.getMemberById(id);
        if (member == null) {
            return ResultData.from("F-2", "아이디 또는 비밀번호가 일치하지 않습니다.");
        }

        member = memberService.getMemberById(id);

        return ResultData.from("F-1", Ut.f("%s님 환영합니다.", memberService.getNickname(id)), member);
    }
    public int doLogin(String loginId, String loginPw) {

        if (memberRepository.doLogin(loginId, loginPw) == 0) return 0;


        return memberRepository.getMemberByLoginId(loginId);
    }

    public String getNickname(int id) {

        return memberRepository.getNickname(id);
    }
    @Select("SELECT COUNT(*) FROM `member` WHERE loginId = #{loginId} AND loginPw = #{loginPw}")
    public int doLogin(String loginId, String loginPw);

    @Select("SELECT nickname FROM `member` WHERE id = #{id}")
    public String getNickname(int id);

아이디 비번이 일치하지 않을 때,

닉네임을 가져오고 싶어서 닉네임을 찾는 메서드도 하나 더 만들었다. 2번 회원으로 로그인을 하면,

잘뜬다.

근데 뭔가 좀 고쳐야될 것들이 있어서 일단은 제쳐두고

제네릭에 대해서 배웠다.

제네릭: 제네릭 상자는 특정 타입의 물건만 넣을 수 있도록 만들어진 상자입니다. 예를 들어, AppleBox는 사과만 담을 수 있고, BookBox는 책만 담을 수 있습니다. 이 상자는 꺼낼 때도 사과나 책으로 바로 꺼낼 수 있어 타입을 변환할 필요가 없습니다.

이런건데, 이걸로 우리는 코드의 안정성을 높힐 수 있다.

package com.example.demo.vo;

import lombok.Getter;

public class ResultData<DT> {
    @Getter
    private String ResultCode;
    @Getter
    private String msg;
    @Getter
    private DT data1;

    public static <DT> ResultData<DT> from(String ResultCode, String msg) {

        return from(ResultCode, msg, null);
    }

    public static <DT> ResultData<DT> from(String ResultCode, String msg, DT data1) {
        ResultData<DT> rd = new ResultData<DT>();
        rd.ResultCode = ResultCode;
        rd.msg = msg;
        rd.data1 = data1;

        return rd;
    }
    public boolean isSuccess() {
        return ResultCode.startsWith("S-");
    }

    public boolean isFail() {
        return isSuccess() == false;
    }

    public static <DT> ResultData<DT> newData(ResultData rd, DT newData) {
        return from(rd.getResultCode(), rd.getMsg(), newData);
    }


}
package com.example.demo.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.example.demo.service.ArticleService;
import com.example.demo.util.Ut;
import com.example.demo.vo.Article;
import com.example.demo.vo.ResultData;

@Controller
public class UsrArticleController {

    @Autowired
    private ArticleService articleService;

    @RequestMapping("/usr/article/getArticle")
    @ResponseBody
    public ResultData<Article> getArticle(int id) {

        Article article = articleService.getArticleById(id);

        if (article == null) {
            return ResultData.from("F-1", Ut.f("%d번 게시물은 없습니다.", id));
        }

        return ResultData.from("S-1", Ut.f("%d번 게시물입니다.", id), article);
    }

    @RequestMapping("/usr/article/doModify")
    @ResponseBody
    public ResultData<Article> doModify(int id, String title, String body) {
        System.out.println("id : " + id);
        System.out.println("title : " + title);
        System.out.println("body : " + body);

        Article article = articleService.getArticleById(id);

        if (article == null) {
            return ResultData.from("F-1", Ut.f("%d번 게시물은 없습니다.", id));
        }

        articleService.modifyArticle(id, title, body);

        article = articleService.getArticleById(id);//수정 후 데이터 새로 가져오기.
        return ResultData.from("S-2", Ut.f("%d번 게시물 수정되었습니다.", id), article);
    }

    @RequestMapping("/usr/article/doDelete")
    @ResponseBody
    public ResultData<Integer> doDelete(int id) {

        Article article = articleService.getArticleById(id);

        if (article == null) {
            return ResultData.from("F-1", Ut.f("%d번 게시물은 없습니다.", id));
        }

        articleService.deleteArticle(id);

        return ResultData.from("S-1", Ut.f("%d번 게시물 삭제되었습니다.", id));
    }

    @RequestMapping("/usr/article/doWrite")
    @ResponseBody
    public ResultData doWrite(String title, String body) {

        if (Ut.isEmptyOrNull(title)) {
            return ResultData.from("F-1", "제목을 입력해주세요");
        }
        if (Ut.isEmptyOrNull(body)) {
            return ResultData.from("F-2", "내용을 입력해주세요");
        }

        ResultData writeArticleRd = articleService.writeArticle(title, body);

        int id = (int) writeArticleRd.getData1();

        Article article = articleService.getArticleById(id);

        return ResultData.from(writeArticleRd.getResultCode(), writeArticleRd.getMsg(), article);
    }

    @RequestMapping("/usr/article/getArticles")
    @ResponseBody
    public ResultData<List<Article>> getArticles() {
        List<Article> articles = articleService.getArticles();
        return ResultData.from("S-1", "Article List", articles);
    }

}

제네릭을 적용한 모습이다.

반환할 것을 정해서 그것만 반환할 수 있도록 한다.

제네릭을 사용해서 로그인을 조금 더 수월하게 만들어볼 수 있을 것 같다.

일단은 여기까지.