Spring Boot 게시판 CRUD 실습

장준휴·2024년 1월 11일
1

Spring Boot

목록 보기
2/4

Spring Boot는 앞에서 했던 기본 Spring과 유사하지만 일부 기능들이 더 간단해졌다.

전체적으로 게시판 CRUD(Create, Read, Update, Delete)를 진행하면서 익숙해져보자.

우선, 우리는 jsp를 사용할 예정이기 때문에 viewname을 결정하는 preffix와 serffix를 설정해줘야한다. (참고로 maven을 활용해 필요한 라이브러리들을 다 받아주고 시작해야한다)

Jsp 사용을 위해 application.properties 파일 내부 작성

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

Tbl_Member


일종의 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 를 설계하기만 해도 테이블이 자동으로 생성된다.

FK 설정코드


	@OneToMany(mappedBy = "writer")
	private List<Tbl_board> board;

1대 다 구조인지 , 다대 1 구조인지 잘 파악해서 작성해야한다.

또한 여기서 중요한게 pk나 fk 처럼 관계가 정립되면 toString 메소드를 오버라이딩 해줘야한다. (안그럼 오류가 발생함)

	@Override
	public String toString() {
		return "Tbl_Member";
	}

MemberRepository


Spring Boot에서 DB와 연결하는 DAO 역할을 하는것이 repository이다.
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 문을 쓰지 않기 위해 메소드 이름을 이용하여 직접 구현한다.

  • hibernate 라는 구현체가 테이블과, ID에 맞춰서 자동으로 구현한다.

어노테이션을 이용하여 직접 sql문을 작성하는 경우 JPA에서는 꼭 변수명을 다 작성해줘야한다.


MemberController


전체코드

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

  • Spring Boot에게 Controller 라는 것을 알려주기 위해 클래스 바로 위에 작성

@RequestMapper("/guest")

  • 이 컨트롤러에 접근하는 모든 Mapping은 '/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를 사용하여 해당 기능을 사용한다.


일반적으로 이렇게 Controller, DTO, Repository 이 3개를 한번에 생성해서 기능을 구현한다.


Main


전체코드

<%@ 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>&copy; 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>

부분코드 1

<%@ 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를 저장한다.


부분코드 2

<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문법을 사용하여 로그인 상황을 확인한 뒤 이에 맞는 버튼을 출력한다.

profile
나는야 토마토

0개의 댓글