Spring Boot는 앞에서 했던 기본 Spring과 유사하지만 일부 기능들이 더 간단해졌다.
전체적으로 게시판 CRUD(Create, Read, Update, Delete)를 진행하면서 익숙해져보자.
우선, 우리는 jsp를 사용할 예정이기 때문에 viewname을 결정하는 preffix와 serffix를 설정해줘야한다. (참고로 maven을 활용해 필요한 라이브러리들을 다 받아주고 시작해야한다)
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
일종의 DTO 이다.
package com.smhrd.entity;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity //이게 있어야 jpa가 인식해서 테이블을 만들어줌
@AllArgsConstructor // 전체 필드를 초기화하는 생성자
@NoArgsConstructor //기본생성자
@Data //Getter/Setter
public class Tbl_Member {
// email
// @Column의 매개변수를 이용해서 컬럼의 상세한 내용 설정 가능
// insertable
// updatable >> insert문 또는 update문이 자동완성 될 때, 포함할건지
// insert into Tbl_member(email,pw,tel,address) values ...
@Id
@Column(length=50, updatable = false)
private String email;
// pw
@Column(length=50, nullable=false)
private String pw;
// tel
private String tel;
// address
private String address;
@OneToMany(mappedBy = "writer")
private List<Tbl_board> board;
//pk나 fk 처럼 관계가 정립되면 toString을 오버라이딩 해줘야함 (안그럼 오류!)
@Override
public String toString() {
return "Tbl_Member";
}
}
이 클래스는 유저 맴버의 정보가 담길 클래스이다.
따라서 DB의 테이블에서 꺼낸 데이터를 담을 수 있도록 설계를 해야한다.
무조건 컬럼 명과 이 DTO의 필드명이 동일해야한다.
여기서 Spring Boot의 신기한 기능이 추가된다.
이전까지는 직접 DB에 쿼리문으로 테이블을 작성했다면, 이제는 OMR 방식이라 하여 이렇게 DTO 를 설계하기만 해도 테이블이 자동으로 생성된다.
@OneToMany(mappedBy = "writer")
private List<Tbl_board> board;
1대 다 구조인지 , 다대 1 구조인지 잘 파악해서 작성해야한다.
또한 여기서 중요한게 pk나 fk 처럼 관계가 정립되면 toString 메소드를 오버라이딩 해줘야한다. (안그럼 오류가 발생함)
@Override
public String toString() {
return "Tbl_Member";
}
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.smhrd.entity.Tbl_Member;
// MyBatis >> MyBatis:scan
@Repository //이 파일이 JPA Repository임을 명시, Scan되도록 함
public interface MemberRepository extends JpaRepository<Tbl_Member, String> {
// Repository는 반드시 JpaRepository Interface를 상속 받아야함
// < > == 제네릭 문법
// JpaRepository<T, ID>
// T : Table과 연결된 Entity
// ID : Entity 내 PK(ID)의 자료형
//JPA : No SQL, SQL문을 쓰지 말자
//JpaRepository 안에 기본 CRUD 메소드가 정의 되어있음
//hibernate라는 구현체가 테이블과, ID에 맞춰서 자동으로 구현
// 특별한 조건을 가지는 메소드는 직접 구현
// 1. 메소드 이름 규칙을 이용한 구현
public Tbl_Member findByEmailAndPw(String email, String pw);
// 2.@Query 어노테이션을 이용하여 직접SQL문을 작성하는 방법
// 복잡한 쿼리문 작성하기 힘듦(join, 서브쿼리)
// JPA 단일보다는 MYBatis를 겸용하는 경우가 많다
//@Query("select * from dbl_member where email = :email and pw = :pw")
//public Tbl_Member login(String email, String pw); //JPA 에서는 변수 하나하나 따로따로 넣어줘야함
}
@Repository 를 사용하여 이 파일이 Respository임을 명시하고 메모리에 scan 되도록 한다.
JPA는 sql 문을 쓰지 않기 위해 메소드 이름을 이용하여 직접 구현한다.
어노테이션을 이용하여 직접 sql문을 작성하는 경우 JPA에서는 꼭 변수명을 다 작성해줘야한다.
package com.smhrd.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.smhrd.entity.Tbl_Member;
import com.smhrd.repository.MemberRepository;
@Controller
@RequestMapping("/guest")
public class MemberController {
//Repository 주입
//Interface > 추상메소드 밖에 없음 >> 객체 생성 불가
@Autowired // Spring 메모리(Spring Container) 내에서 넣어줄 수 있는 객체를 알아서 찾아서 넣어달라
private MemberRepository repo;
//http://localhost:8088/{contextPath}/{URLMapping}
// http://localhost:8088/boot/main
// ~~~/main 이라고 요청했을 때, main.jsp로 이동
@RequestMapping("/main")
public String goMain() {
return "guest/main";
}
@RequestMapping("/join")
public String join(Tbl_Member member) {
//1. 데이터 수집
//2. 로직 실행
// 수집한 정보를 DB에 저장하는 코드
//Jpa의 save
// 1. id를 기준으로 select
//2. 있으면 >> update
// 없으면 >> insert
repo.save(member);
//3. View 선택 / 데이터 응답
return "guest/join_success";
}
@RequestMapping("/login")
public String login(Tbl_Member member, HttpSession session) {
//1. 데이터 수집
//2. 로직 실행
Tbl_Member result = repo.findByEmailAndPw(member.getEmail(), member.getPw());
if(result != null) {
session.setAttribute("user", result);
}
//3. view 선택
return "redirect:/guest/main"; //http:// ~~~/{contextPath}/ + "redirect"
}
}
@controller
@RequestMapper("/guest")
//Repository 주입
//Interface > 추상메소드 밖에 없음 >> 객체 생성 불가
@Autowired // Spring 메모리(Spring Container) 내에서 넣어줄 수 있는 객체를 알아서 찾아서 넣어달라
private MemberRepository repo;
DB와 연결하기 위한 인터페이스 객체를 미리 불러들인다.
이후 메모리 내에서 알아서 찾아서 넣어주는 @Autowired 를 위에 작성한다.
이렇게 해두면 나중에 DB에서 데이터를 가져올때
Tbl_Member result = repo.findByEmailAndPw(member.getEmail(), member.getPw());
이런식으로 사용할수 있다.
@RequestMapping("/main")
public String goMain() {
return "guest/main";
}
"/guest/main" 이라는 요청이 들어왔을 때 guest 폴더에 존재하는 main 페이지로 forword 된다.
@RequestMapping("/join")
public String join(Tbl_Member member) {
repo.save(member);
return "guest/join_success";
}
위에 @RequestMapping("/join")이라 작성되어있지만 class 부분에서 @RequestMapping("/guest")를 선언했기 때문에 실제로 작동은 /guest/join을 해야 로그인 기능으로 들어갈 수 있다.
그리고 이번 실습은 jpa로 진행하기 때문에 repo라는 인터페이스에서 save() 메소드를 사용하여 수집한 정보를 DB에 저장한다.
@RequestMapping("/login")
public String login(Tbl_Member member, HttpSession session) {
Tbl_Member result = repo.findByEmailAndPw(member.getEmail(), member.getPw());
if(result != null) {
session.setAttribute("user", result);
}
return "redirect:/guest/main";
이 mapping 은 매개변수로 Tbl_Member객체를 받아오고 계정을 session에 저장하기 위해 session 객체를 받아온다.
findByEmailAndPw()메소드를 통해 사용자가 입력한 email과 pw값을 이용하여 Tbl_Member 객체를 받는다.
만약 받아온 Tbl_Member 객체가 Null값이 아니라면 session에 'user' 이름으로 저장한다.
session에 저장했으면 다시 mainview로 이동해야하는데 이미 main으로 넘어가는 기능은 구현해놨기 때문에 redirect를 사용하여 해당 기능을 사용한다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!-- Context path 값을 받아올 수 있도록 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<% String cpath = request.getContextPath();
pageContext.setAttribute("cpath", cpath);
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Forty by HTML5 UP</title>
<meta charset="UTF-8" />
<!--
href나 src 속성안에서 폴더 명으로 시작하는 경우
>> http://localhost:8088/{ContextPath}/{mapping}/ + "herf||src"
>> 잘못된 경로
http://localhost:8088/{ContextPath} == static 파일을 지정함
/로 시작하는 경우
>> http://localhost:8088/ + "href||src"
-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="${cpath}/assets/css/main.css" />
</head>
<body>
<!-- Wrapper -->
<div id="wrapper">
<!-- Header -->
<header id="header" class="alt">
<a href="index.html" class="logo"><strong>Forty</strong> <span>by HTML5 UP</span></a>
<nav>
<c:if test="${empty user}">
<a href="#menu">로그인</a>
</c:if>
<c:if test="${!empty user}">
<a href="${cpath}/member/list">게시판</a>
<a href="#">개인정보 수정</a>
<a href="#">로그아웃</a>
</c:if>
<!--Ex07. 로그인 한 상태라면 '게시판'버튼과 '개인정보수정', '로그아웃' 버튼을 출력하시오. -->
</nav>
</header>
<!-- Menu -->
<nav id="menu">
<ul class="links">
<%--Ex07. 로그인 기능 만들기 : 사용자에게 정보를 입력받아 회원인지 아닌지 조회하는 기능을 만들어 봅시다. --%>
<li><h5>로그인</h5></li>
<form action = "${cpath}/guest/login" method="post">
<li><input name = "email" type="text" placeholder="Email을 입력하세요"></li>
<li><input name = "pw" type="password" placeholder="PW를 입력하세요"></li>
<li><input type="submit" value="LogIn" class="button fit"></li>
</form>
</ul>
<ul class="actions vertical">
<%--Ex06. 회원가입 기능 만들기 : 사용자에게 정보를 입력받아 저장하는 기능을 만들어 봅시다. --%>
<li><h5>회원가입</h5></li>
<!-- boot/guest/join -->
<form action="${cpath}/guest/join" method="post">
<li><input name="email" type="text" placeholder="Email을 입력하세요"></li>
<li><input name="pw" type="password" placeholder="PW를 입력하세요"></li>
<li><input name="tel" type="text" placeholder="전화번호를 입력하세요"></li>
<li><input name="address" type="text" placeholder="집주소를 입력하세요"></li>
<li><input type="submit" value="JoinUs" class="button fit"></li>
</form>
</ul>
</nav>
<!-- Banner -->
<section id="banner" class="major">
<div class="inner">
<header class="major">
<%--Ex07. 로그인 후 로그인 한 사용자의 세션아이디로 바꾸시오. ex)smart님 환영합니다 --%>
<h1>로그인 한 세션아이디를 출력해주세요</h1>
</header>
<div class="content">
<p>아래는 지금까지 배운 웹 기술들입니다.<br></p>
<ul class="actions">
<li><a href="#one" class="button next scrolly">확인하기</a></li>
</ul>
</div>
</div>
</section>
<!-- Main -->
<div id="main">
<!-- One -->
<section id="one" class="tiles">
<article>
<span class="image">
<img src="${cpath}/images/pic01.jpg" alt="" />
</span>
<header class="major">
<h3><a href="#" class="link">HTML</a></h3>
<p>홈페이지를 만드는 기초 언어</p>
</header>
</article>
<article>
<span class="image">
<img src="${cpath}/images/pic02.jpg" alt="" />
</span>
<header class="major">
<h3><a href="#" class="link">CSS</a></h3>
<p>HTML을 디자인해주는 언어</p>
</header>
</article>
<article>
<span class="image">
<img src="${cpath}/images/pic03.jpg" alt="" />
</span>
<header class="major">
<h3><a href="#" class="link">Servlet/JSP</a></h3>
<p>Java를 기본으로 한 웹 프로그래밍 언어/스크립트 언어</p>
</header>
</article>
<article>
<span class="image">
<img src="${cpath}/images/pic04.jpg" alt="" />
</span>
<header class="major">
<h3><a href="#" class="link">JavaScript</a></h3>
<p>HTML에 기본적인 로직을 정의할 수 있는 언어</p>
</header>
</article>
<article>
<span class="image">
<img src="${cpath}/images/pic05.jpg" alt="" />
</span>
<header class="major">
<h3><a href="#" class="link">MVC</a></h3>
<p>웹 프로젝트 중 가장 많이 사용하는 디자인패턴</p>
</header>
</article>
<article>
<span class="image">
<img src="${cpath}/images/pic06.jpg" alt="" />
</span>
<header class="major">
<h3><a href="#" class="link">Web Project</a></h3>
<p>여러분의 최종프로젝트에 웹 기술을 활용하세요!</p>
</header>
</article>
</section>
<!-- Two -->
<section id="two">
<div class="inner">
<header class="major">
<h2>메세지 확인하기</h2>
</header>
<%-- chatting 기능을 만들어 봅시다! --%>
<div class="container chat">
<div class="other">
<p>보낸사람 이름 :</p>
<p>다른사람에게서 온 메세지</p>
</div>
<div class="mychat">
<p>내가보낸 채팅</p>
</div>
<div class="other">
<p>보낸사람 이름2 :</p>
<p>다른사람에게서 온 메세지2</p>
</div>
</div>
<%-- 채팅창 끝! --%>
</div>
</section>
</div>
<!-- Contact -->
<section id="contact">
<div class="inner">
<section>
<form>
<div class="field">
<label for="message">Message</label>
<textarea id="message" rows="6"></textarea>
</div>
<ul class="actions">
<li><input type="button" value="Send Message" class="special" /></li>
<li><input type="reset" value="Clear" /></li>
</ul>
</form>
</section>
<%--Ex07. 로그인 한 사용자의 정보로 변경해 봅시다. --%>
<section class="split">
<section>
<div class="contact-method">
<span class="icon alt fa-envelope"></span>
<h3>Email</h3>
<a href="#">로그인 한 사람의 이메일을 출력</a>
<!-- 로그인 한 사용자의 이메일을 출력하시오 -->
</div>
</section>
<section>
<div class="contact-method">
<span class="icon alt fa-phone"></span>
<h3>Phone</h3>
<span>로그인 한 사람의 전화번호를 출력</span>
<!-- 로그인 한 사용자의 전화번호를 출력하시오 -->
</div>
</section>
<section>
<div class="contact-method">
<span class="icon alt fa-home"></span>
<h3>Address</h3>
<span>로그인 한 사람의 집주소를 출력</span>
<!-- 로그인 한 사용자의 집주소를 출력하시오 -->
</div>
</section>
</section>
</div>
</section>
<!-- Footer -->
<footer id="footer">
<div class="inner">
<ul class="icons">
<li><a href="#" class="icon alt fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="icon alt fa-facebook"><span class="label">Facebook</span></a></li>
<li><a href="#" class="icon alt fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="icon alt fa-github"><span class="label">GitHub</span></a></li>
<li><a href="#" class="icon alt fa-linkedin"><span class="label">LinkedIn</span></a></li>
</ul>
<ul class="copyright">
<li>© Untitled</li><li>Design: <a href="https://html5up.net">HTML5 UP</a></li>
</ul>
</div>
</footer>
</div>
<!-- Scripts -->
<script src="${cpath}/assets/js/jquery.min.js"></script>
<script src="${cpath}/assets/js/jquery.scrolly.min.js"></script>
<script src="${cpath}/assets/js/jquery.scrollex.min.js"></script>
<script src="${cpath}/assets/js/skel.min.js"></script>
<script src="${cpath}/assets/js/util.js"></script>
<!--[if lte IE 8]><script src="${cpath}/assets/js/ie/respond.min.js"></script><![endif]-->
<script src="${cpath}/assets/js/main.js"></script>
</body>
</html>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<% String cpath = request.getContextPath();
pageContext.setAttribute("cpath", cpath);
%>
jstl 을 사용하기위해 taglib을 가져오는 코드와 이후 jsp 링크에 편하게 설정하기위해 ContextPath를 cpath변수에 저장한다.
이후 page에서 사용할 수 있도록 pageContext에 setAttribute메소드를 사용하여 cpath를 저장한다.
<c:if test="${empty user}">
<a href="#menu">로그인</a>
</c:if>
<c:if test="${!empty user}">
<a href="${cpath}/member/list">게시판</a>
<a href="#">개인정보 수정</a>
<a href="#">로그아웃</a>
</c:if>
jstl을 사용하여 if문을 사용하였으며, EL문법을 사용하여 로그인 상황을 확인한 뒤 이에 맞는 버튼을 출력한다.