danbibibi
article thumbnail
Published 2023. 4. 24. 00:40
Spring MVC 실습 WEB/back-end

내용 정리 겸 지금까지 학습한 Spring, JSP, MVC 패턴 등을 적용한 간단한 실습을 해보자!!

 

DB 만들기

아주 간단한 table 2가지를 만들어서 진행!

drop database if exists animal;
create database if not exists animal DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs ;
use animal;

drop table if exists user;
create table if not exists user(
	id varchar(10) primary key,
    pw varchar(10) not null,
    name varchar(20) not null
);

insert into user values
('danbi', '1234', '홍길동'),
('admin', '1234', '관리자');

select * from user;

drop table if exists cat;
create table if not exists cat(
	code varchar(10) primary key,
    nickname varchar(20) not null,
    price int not null,
    id varchar(10),
    foreign key (id) references user(id)
);

insert into cat values
('101', '야옹이', 1000, 'danbi'),
('102', '꽁냥이', 2000, 'danbi'),
('103', '꼬물이', 3000, 'admin');

select * from cat;

 

 

DTO 만들기

앞서 만들어둔 스키마를 보고 DTO를 만들어 준다!!

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
	private String id;
	private String pw;
	private String name;
}

 

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Cat {
	private String code;
	private String nickname;
	private int price;
	private String id;
	private User user;
}

 

 

DAO 만들기 (@Repository)

먼저 다음과 같이 Interface를 만들어 준다!

import java.sql.SQLException;

import com.danbi.cat.dto.User;

public interface UserRepo {
	User select(User user) throws SQLException;	
}

 

import java.sql.SQLException;
import java.util.List;

import com.danbi.cat.dto.Cat;

public interface CatRepo {
	int insert(Cat cat) throws SQLException;
	int delete(String code) throws SQLException;
	int update(Cat cat) throws SQLException;
	Cat select(String code) throws SQLException;
	List<Cat> selectAll() throws SQLException;
}

 

그리고, 위에서 만들어 둔 Interface를 구현해준다!

후에 servlet-context.xml과 root-context.xml에서 component-scan을 통해 의존성 주입을 할 것이므로!

객체를 별도로 생성하지 않고, annotation을 이용하여 의존성 주입을 하고 있는 것을 확인할 수 있다.

 

User 객체를 받아서, 아이디와 비밀번호가 DB에 저장된 경우 해당 객체를, 저장되지 않은 경우에는 null을 반환해준다!

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.stereotype.Repository;

import com.danbi.cat.dto.User;

@Repository
public class UserRepoImpl implements UserRepo {
	
    @Autowired
    private DataSource dataSource;

    @Override
    public User select(User user) throws SQLException {

        User selected  = null;
        String sql = "select * from user where id = ?";

        try(Connection conn = dataSource.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql)){

            ps.setString(1, user.getId());

            try(ResultSet rs = ps.executeQuery()){
                if(rs.next() && user.getPw().equals(rs.getString("pw"))) {
                    selected =  new User(rs.getString("id"), rs.getString("pw"), rs.getString("name"));
                }
            }
        }
        return selected;
    }
	
    // test
    public static void main(String[] args) throws SQLException {
        ApplicationContext ctx = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/root-context.xml");
        UserRepo repo = ctx.getBean(UserRepoImpl.class);
        System.out.println(repo.select(new User("danbi", "1234", "")));
    }

}

 

 

Service 만들기 (@Service)

service도 DAO처럼 먼저 interface를 만들어 준다!!

import java.sql.SQLException;

import com.danbi.cat.dto.User;

public interface UserService {
	User select(User user) throws SQLException;	
}

 

import java.sql.SQLException;
import java.util.List;

import com.danbi.cat.dto.Cat;

public interface CatService {
	int insert(Cat cat) throws SQLException;
	int delete(String code) throws SQLException;
	int update(Cat cat) throws SQLException;
	Cat select(String code) throws SQLException;
	List<Cat> selectAll() throws SQLException;
}

 

그리고 만든 interface를 구현해 주는데, 이때 앞서 만들어 둔 DAO를 이용해서 데이터 로직을 처리해준다!

import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.stereotype.Service;

import com.danbi.cat.dto.User;
import com.danbi.cat.model.repo.UserRepo;

@Service
public class UserServiceImpl implements UserService {
	
	@Autowired
	UserRepo userRepo;

	@Override
	public User select(User user) throws SQLException {
		return userRepo.select(user);
	}
	
    // test
	public static void main(String[] args) throws SQLException {
		ApplicationContext ctx = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/root-context.xml");
		UserService svc = ctx.getBean(UserService.class);
		System.out.println(svc.select(new User("danbi", "1234", "")));
	}
}

 

select 시 user 정보를 얻기 위해 join을 했다!

import java.sql.SQLException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.danbi.cat.dto.Cat;
import com.danbi.cat.model.repo.CatRepo;

@Service
public class CatServiceImpl implements CatService {
	
	@Autowired
	CatRepo catRepo;
	
	@Override
	@Transactional
	public int insert(Cat cat) throws SQLException {
		return catRepo.insert(cat);
	}

	@Override
	@Transactional
	public int delete(String code) throws SQLException {
		return catRepo.delete(code);
	}

	@Override
	@Transactional
	public int update(Cat cat) throws SQLException {
		return catRepo.update(cat);
	}

	@Override
	public Cat select(String code) throws SQLException {
		return catRepo.select(code);
	}

	@Override
	public List<Cat> selectAll() throws SQLException {
		return catRepo.selectAll();
	}
	
    // test
	public static void main(String[] args) throws Exception{
		ApplicationContext ctx = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/root-context.xml");
		CatService svc = ctx.getBean(CatService.class);
		
		svc.insert(new Cat("104", "길냥이", 4000, "admin", null));
		svc.update(new Cat("104", "업데이트 완료", 5000, "admin", null));
		System.out.println(svc.select("104"));
		svc.delete("104");
		for(Cat c : svc.selectAll()) System.out.println(c);
	}
}

 

 

JSP 페이지 만들기

다음과 같이 간단한 페이지를 몇개 만들어 주었다!

 

헤더이다!

<!-- include/header.jsp -->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="root" value="${pageContext.request.contextPath}"></c:set>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache">
<title>Spring MVC 실습</title>
</head>
<body>
<h1>Spring MVC 실습</h1>
<div>
	
	<c:if test="${empty loginUser}">
		<a href="${root}/login">로그인</a>
	</c:if>
	
	<c:if test="${not empty loginUser}">
		[${loginUser.name}] 님 반갑습니다. 
		<a href="${root}/logout">로그아웃</a>
	</c:if>
	
</div>
<hr>

<script>
let msg="${msg}";
if(msg) alert(msg);
</script>

 

메인 페이지이다!

<!-- index.jsp -->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="/WEB-INF/views/include/header.jsp" %>
<h2> CAT HOUSE </h2>
<%@include file="/WEB-INF/views/include/footer.jsp" %>

 

푸터이다!

<!-- include/footer.jsp -->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

    <p>
    <hr>
    <a href="${root}/">홈으로</a>
    <a href="${root}/regist">등록</a>
    <a href="${root}/list">목록</a>
</body>
</html>

 

에러가 발생하면 보여질 페이지이다!

<!-- error/error.jsp -->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="/WEB-INF/views/include/header.jsp" %>
<h2>오류 </h2>
잠시 후 다시 시도해 주세요.
${errmsg}
<%@include file="/WEB-INF/views/include/footer.jsp" %>

 

로그인 페이지이다!

<!-- user/login.jsp -->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="/WEB-INF/views/include/header.jsp" %>
<h2> 로그인 </h2>

<form action="${root}/login" method="post">
	아이디  : <input type="text" name="id" value="danbi"> <br>
	패스워드  : <input type="password" name="pw" value="1234"> <br>
	<input type="submit" value="로그인">
</form>

<%@include file="/WEB-INF/views/include/footer.jsp" %>

 

cat들의 리스트를 보여주는 페이지이다!

<!-- cat/list.jsp -->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="/WEB-INF/views/include/header.jsp" %>
<h2> 목록 </h2>

<c:if test="${not empty cats}">
<form action="${root}/delm" method="post">
	<table border="1" style="border-collapse: collapse;">
		<tr>
			<th>코드</th>
			<th>애칭</th>
			<th>가격</th>
			<th>삭제</th>
		</tr>
		<c:forEach var="cat" items="${cats}">
			<tr>
				<td><a href="${root}/detail?code=${cat.code}">${cat.code}</a></td>
				<td>${cat.nickname}</td>
				<td>${cat.price}</td>
				<th><input type="checkbox" name="codes" value="${cat.code}"></th>
			</tr>
		</c:forEach>
	</table>
	<input type="submit" value="삭제">
</form>
</c:if>

<c:if test="${empty cats}">
	<p> 등록된 정보가 없습니다.</p>
</c:if>


<%@include file="/WEB-INF/views/include/footer.jsp" %>

 

새로운 cat을 등록하는 페이지이다!

<!-- cat/regist.jsp -->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="/WEB-INF/views/include/header.jsp" %>
<h2> 등록 </h2>
<form action="${root}/regist" method="post">
	코드: <input type="text" name="code" value="104" > <br>
	애칭: <input type="text" name="nickname" value="길냥이" > <br>
	가격: <input type="text" name="price" value="4000" > <br>
	아디: <input type="text" name="id" value="${loginUser.id}" <c:if test="${not empty loginUser}">readonly </c:if>> <br>
	<input type="submit" value="등록">
</form>

<c:if test="${not empty err}"> 
	<fieldset>
		<legend>등록오류</legend>
		${err}
	</fieldset>
</c:if>

<%@include file="/WEB-INF/views/include/footer.jsp" %>

 

cat 정보를 상세하게 볼 수 있는 페이지이다!

<!-- cat/detail.jsp -->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@include file="/WEB-INF/views/include/header.jsp" %>
<h2> 상세 </h2>
<table>
	<tr> <th>아디</th> <td>${cat.id}</td></tr>
	<tr> <th>이름</th> <td>${cat.user.name}</td></tr>
	<tr> <th>코드</th> <td>${cat.code}</td></tr>
	<tr> <th>애칭</th> <td>${cat.nickname}</td></tr>
	<tr> <th>가격</th> <td>${cat.price}</td></tr>
</table>
<a href="${root}/dele?code=${cat.code}"> 삭제</a>
<%@include file="/WEB-INF/views/include/footer.jsp" %>

 

 

servlet-context.xml, root-xml 수정

annotation을 사용하기 위해 다음과 같이 component-scan을 해준다!

또 Database를 사용하기 위해 bean으로 등록해준다!! (여기서는 mysql을 사용했다.)

# servlet-context.xml
<context:component-scan base-package="com.danbi.cat.controller" />
	
    
# root-context.xml
<context:component-scan base-package="com.danbi.cat.model"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> 
    <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/animal?serverTimezone=UTC"/>
    <property name="username" value="아이디"/>
    <property name="password" value="비밀번호"/>
</bean>

 

 

Controller 만들기 (@Controller)

import java.net.BindException;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;

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.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import com.danbi.cat.dto.Cat;
import com.danbi.cat.dto.User;
import com.danbi.cat.model.service.CatService;
import com.danbi.cat.model.service.UserService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class CatController {
	
	@Autowired
	private UserService us;
	
	@Autowired
	private CatService cs;
	
	
	@ExceptionHandler(Exception.class)
	public String handler(Model m, Exception e) {
		e.printStackTrace();
		m.addAttribute("errmsg", e.getMessage());
		
		if(e instanceof BindException) {
			m.addAttribute("errmsg", "중복 등록 오류");
		}
		return "error/error";
	}
	
	@GetMapping({"/", "/index"})
	public String index() {
		return "index";
	}
	
	@GetMapping("/login")
	public String login() {
		return "user/login";
	}
	
	@PostMapping("/login")
	public String login(User user, Model model, HttpSession session) throws SQLException {
		User loginUser = us.select(user);
		
		if(loginUser!=null) {
			session.setAttribute("loginUser", loginUser);
			return "redirect:/";
		}
		else {
			model.addAttribute("msg", "아이디와 패스워드를 확인해주세요!");
			return "user/login";
		}
	}
	
	@GetMapping("/logout")
	public String logout(HttpSession session) {
		session.invalidate();
		return "redirect:/";
	}
	
	@GetMapping("/regist")
	public String regist() {
		return "cat/regist";
	}
	
	@PostMapping("/regist")
	public String regist(Cat cat, Model model) throws SQLException {
		try {
			cs.insert(cat);
			model.addAttribute("msg", "등록되었습니다.");
		} catch (SQLIntegrityConstraintViolationException e) {
			model.addAttribute("msg", "등록 중 오류가 발생했습니다.");
			e.printStackTrace();
		}
		return "cat/list";
	}
	
	@GetMapping("/list")
	public String list(Model model) throws SQLException {
		model.addAttribute("cats", cs.selectAll());
		return "cat/list";
	}
	
	@GetMapping("/detail")
	public String detail(String code, Model model) throws SQLException {
		model.addAttribute("cat", cs.select(code));
		return "cat/detail";
	}
	
	@GetMapping("/dele")
	public String dele(String code) throws SQLException {
		cs.delete(code);
		return "redirect:/list";
		
	}
	
	@PostMapping("/delm")
	public String delm(String[] codes) throws SQLException {
		for(String code : codes) cs.delete(code);
		return "redirect:/list";
	}
}

 

 

최종 프로젝트 구조는 다음과 같다!

'WEB > back-end' 카테고리의 다른 글

MyBatis, MyBatis-Spring 설정  (0) 2023.04.24
Spring File Upload (Apache Commons FileUpload)  (1) 2023.04.24
Interceptor  (0) 2023.04.22
AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)  (0) 2023.04.22
Spring  (0) 2023.04.21
profile

danbibibi

@danbibibi

꿈을 꾸는 시간은 멈춰 있는 것이 아냐 두려워하지 마 멈추지 마 푸른 꿈속으로