[Spring] Spring MVC 응용

young-gue Park·2023년 10월 19일
0

Spring

목록 보기
9/14
post-thumbnail

⚡ Spring MVC 응용


📌 Spring MVC 요청/응답

1. 클라이언트에서 서버에 Request(요청)

  • GET(주십쇼) 혹은 POST(해주십쇼)

2. 요청 Filter를 지나 Dispatcher Servlet에 도착

  • 필터에서는 문자 인코딩 등의 작업

3. Dispatcher Servlet에서 핸들러(컨트롤러) 매핑 뒤 반환

  • servlet-context.xml(web), root-context.xml(그 외) 설정
  • 여기서는 servlet-context

4. Dispatcher Servlet에서 매핑하여 반환한 컨트롤러로 인터셉터를 거쳐 요청 전달, 컨트롤러에서 의존성 주입을 위한 xxService 접근

  • preHandler
  • @RequestMapping(경로/메서드), @GetMapping(경로), @PostMapping(경로)
  • 메서드(Model/DTO)
  • return (forward / redirect: 요청 이름)
  • xxService는 사용자 친화적
  • 의존성 주입은 @Autowired(필드, 생성자, 설정자 주입)
  • 여기서는 root-context

5. DB 접근을 위해 xxDao(Repository)로 접근

  • 여기서는 root-context

6. JDBC 또는 MyBatis를 이용해 DB 접근

  • Interface + xml(mapper) => namespace: 풀패키지명
  • CRUD 및 동적 쿼리 적용
  • 여기서는 root-context

7. 값을 가지고 다시 쭉쭉 뒤로 돌아오다가 Controller에서 ModelAndView 혹은 String(viewName)으로 반환

  • 여기서는 servlet-context

8. Dispatcher Servlet으로 반환 도중 또 한번 인터셉터를 거친다.

  • post, after

9. viewResolver로 요청 후 Dispatcher Servlet으로 응답 반환

  • prefix, suffix
  • 여기서는 servlet-context

10. Model을 가지고 view로 이동, 가져올 view를 찾아 Dispatcher Servlet으로 반환

  • page, request, session, application 순서

11. 마지막으로 서버에서 필터를 거쳐 클라이언트로 Response(응답)

👍 ViewResolver와 View를 거치는 대신 REST API를 뽑아내는 과정을 조만간 할 것이다.


📌 Board 완성하기

👍 기존의 Board에 User와 관련된 기능들을 덧붙였다. 예를 들어 Login이나 유저를 확인하는 관리자 페이지 등이 있다.

👍 기존의 user 테이블에 curriculum 테이블을 추가하며 데이터베이스를 수정하였다.

CREATE TABLE board (
	id INT AUTO_INCREMENT,
    writer VARCHAR(20) NOT NULL,
    title VARCHAR(50) NOT NULL,
    content TEXT,
    view_cnt INT DEFAULT 0,
    reg_date TIMESTAMP DEFAULT now(),
    PRIMARY KEY(id)
);

INSERT INTO board(title, writer, content) 
VALUES ("BackEnd easy해","박씨","너도 할 수 있어"),
	   ("누르지마시오", "따봉맨", "아무내용없음"),
       ("나는 원딜장인", "bzeromo", "근데 탑을 더 좋아해");


CREATE TABLE `curriculum` (
	`code` INT NOT NULL PRIMARY KEY,
    `name` VARCHAR(40) NOT NULL
)ENGINE=InnoDB;


CREATE TABLE IF NOT EXISTS `users` (
  `id` varchar(40) NOT NULL,
  `password` varchar(40) NOT NULL,
  `name` varchar(40) NOT NULL,
  `curriculum_code` INT NOT NULL,
  CONSTRAINT `curriculum_fk` FOREIGN KEY (`curriculum_code`) REFERENCES `curriculum`(`code`),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET = utf8mb4;

INSERT INTO `curriculum` 
VALUES (100, 'Python'), (200, 'Java'), (300, 'Embedded'), (400, 'Mobile');

INSERT INTO users
VALUES ("bzeromo", "1234", "박영규", 200);


commit;

SELECT * FROM users;

🖥 userList.jsp (관리자 페이지)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>관리자 페이지</title>
<%@ include file="../common/bootstrap.jsp" %>
</head>
<body>
	<div class="container">
		<h2>회원 목록</h2>
		<hr>
		
		<table class="table text-center">
			<tr>
				<th>ID</th>
				<th>PW</th>
				<th>NAME</th>
				<th>CURRICULUM</th>
			</tr>
			<c:forEach items="${userList }" var="user">
				<tr>
					<td>${user.id }</td>
					<td>${user.password }</td>
					<td>${user.name }</td>
					<td>${user.curriculumName }</td>
				</tr>
			</c:forEach>
		</table>
		<div class="d-flex justify-content-end">
			<a href="${pageContext.request.contextPath }" class="btn btn-outline-warning">홈으로</a>
		</div>
	</div>
</body>
</html>

🖥 loginform.jsp (로그인 페이지)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인</title>
<%@ include file="../common/bootstrap.jsp" %>
</head>
<body>
	<div class="container">
		<h2>로그인</h2>
		<form action="login" method="POST">
			<div class="mb-3">
				<label for="id" class="form-label">ID</label>
				<input type="text" class="form-control" id="id" name="id">
			</div>
			<div class="mb-3">
				<label for="password" class="form-label">PW</label>
				<input type="password" class="form-control" id="password" name="password">
			</div>
			<button class="btn btn-primary">로그인</button>
		</form>
	</div>
</body>
</html>

🖥 header.jsp (로그인 여부에 따라 헤더가 달라진다)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<div>
	<c:if test="${empty loginUser }"> 
		<a href="login" class="btn btn-outline-primary">login</a>
		<a href="signup" class="btn btn-outline-secondary">sign up</a>
	</c:if>
	<c:if test="${not empty loginUser }"> 
		${loginUser }님 환영합니다.
		<a href="logout" class="btn btn-outline-danger">logout</a>
		<c:if test="${'admin' eq loginUser }">
			<a href="users">관리자 페이지</a>
		</c:if>
	</c:if>
</div>

Header는 다른 페이지들 상단에 위치하도록 모든 페이지에 해당 코드를 추가하였다.

<%@ include file ="../common/header.jsp" %>

View 추가는 이정도고, 다음은 user 관련 마이바티스 및 자바 로직이다.

🖥 userMapper.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.ssafy.board.model.dao.UserDao">
	<!-- 커리큘럼 이름을 가지고 오려면 조인이 필요하다 -->
	<select id="selectAll" resultType="User">
		SELECT id, password, u.name AS name,
			   curriculum_code AS curriculumCode,
			   c.name AS curriculumName
		FROM users u, curriculum c
		WHERE curriculum_code = code
	</select>

	<insert id="insertUser" parameterType="User">
		INSERT INTO users
		VALUES(#{id}, #{password}, #{name}, #{curriculumCode})
	</insert>
 
 	<select id="selectOne" parameterType="String" resultType="User">
 		SELECT id, password, name
 		FROM users
 		WHERE id = #{id}
 	</select>
 
</mapper>

🖥 com.bzeromo.board.model.dto.User

package com.bzeromo.board.model.dto;

public class User {
	private String id;
	private String password;
	private String name;
	private int curriculumCode;
	private String curriculumName;

	public User() {
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getCurriculumCode() {
		return curriculumCode;
	}

	public void setCurriculumCode(int curriculumCode) {
		this.curriculumCode = curriculumCode;
	}

	public String getCurriculumName() {
		return curriculumName;
	}

	public void setCurriculumName(String curriculumName) {
		this.curriculumName = curriculumName;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", password=" + password + ", name=" + name + ", curriculumCode=" + curriculumCode
				+ ", curriculumName=" + curriculumName + "]";
	}

}

🖥 com.bzeromo.board.controller.UserController

package com.bzeromo.board.controller;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import com.bzeromo.board.model.dto.User;
import com.bzeromo.board.model.service.UserService;

@Controller
public class UserController {
	
	//UserService 주입
	@Autowired
	private UserService userService;
	
	@GetMapping("users")
	public String userList(Model model) {
		model.addAttribute("userList", userService.getUserList());
		return "/user/userList";
	}
	
	@GetMapping("signup")
	public String signupForm() {
		return "/user/signupform";
	}
	
	@PostMapping("signup")
	public String signup(User user) {
		userService.signup(user);
		return "redirect:list";
	}
	
	@GetMapping("login")
	public String loginForm() {
		return "/user/loginform";
	}
	
	@PostMapping("login")
	public String login(User user, HttpSession session) {
		User tmp = userService.login(user);
		
		//로그인 실패 시
		if(tmp == null)
			return "redirect:login";
		
		session.setAttribute("loginUser", tmp.getName());
		
		return "redirect:list";
	}
	
	@GetMapping("logout")
	public String logout(HttpSession session) {
		session.invalidate();
		
		return "redirect:list";
	}
}

🖥 com.bzeromo.board.model.dao.userDao

package com.bzeromo.board.model.dao;

import java.util.List;

import com.bzeromo.board.model.dto.User;

public interface UserDao {
	List<User> selectAll();

	void insertUser(User user);

	User selectOne(String id);
}

🖥 com.bzeromo.board.model.service.userService

package com.bzeromo.board.model.service;

import java.util.List;

import com.bzeromo.board.model.dto.User;

public interface UserService {
	List<User> getUserList();

	void signup(User user);

	User login(User user);
}

🖥 com.bzeromo.board.model.service.userServiceImpl

package com.bzeromo.board.model.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bzeromo.board.model.dao.UserDao;
import com.bzeromo.board.model.dto.User;

@Service
public class UserServiceImpl implements UserService{

	@Autowired
	private UserDao userDao;
	
	@Override
	public List<User> getUserList() {
		
		return userDao.selectAll();
	}
	
	@Override
	public void signup(User user) {
		userDao.insertUser(user);
	}

	@Override
	public User login(User user) {
		//DB 해당 ID만 넘겨서 데이터 가지고 오고 가지고 온 User 데이터와 내가 현재 가진 user의 비밀번호 비교
		User tmp = userDao.selectOne(user.getId());
		
		if(tmp != null && tmp.getPassword().equals(user.getPassword()))
			return tmp;
		
		return null;
	}
}

🙋‍♀️ 이 외에 더 자세히 보고 싶으면 깃허브로

🖨 결과물

로그인을 하면

헤더가 바뀌며 현재 로그인한 유저의 이름과 로그아웃 버튼이 뜬다.

다음은 회원가입이다.

admin 계정으로 로그인하면 헤더에서 관리자페이지를 확인할 수 있다.

관리자 페이지에서 유저 정보를 확인할 수 있다.


REST API를 어서 배우고 싶다.
View 작업을 프론트엔드 선생님들에게 던지고 싶은 마음이 굴뚝같다. 정말.
맞다 나 프론트 출신이지...

profile
Hodie mihi, Cras tibi

0개의 댓글