내용 정리 겸 지금까지 학습한 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 |