





파일 -> new -> 프로젝트 -> spring Legacy project

Spring MVC Project

Finish

Tomcat Server에 SimpleBoardCRUD를 드래그엔 드롭합니다.





Git

Clone Git Repository


프로젝트 우클릭 -> Share Project Git


team commit -> add All -> commit and Push





<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
</dependency>
<!-- Spring JDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.1</version>
</dependency>
<!-- @Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- HikariConfig -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl"
value="jdbc:mysql://localhost:3306/com?serverTimezone=UTC" />
<property name="username" value="com" />
<property name="password" value="com01" />
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
<!-- MyBatis -->
<mybatis-spring:scan base-package="kr.board.mapper" />
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- JdbcTemplate -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- JPA
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.syh.entity" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
-->
</beans>

DB 테이블 생성 및 테스트 데이터 입력, 출력 테스트


@Mapper
public interface SimpleBoardMapper {
public List<SimpleBoard> getAllBoard();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper>
<select id ="getAllBoards" resultType="entity.SimpleBoard">
select * from simpleBoard
</select>
</mapper>
결과를 보여줄 JSP 파일 생성 ( Home.jsp )
부트 스트랩의 코드를 참고해서 기본 템플렛 생성 ( Template.jsp )
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri = "http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Simple Board</h2>
<div class="panel panel-default">
<div class="panel-heading">BOARD</div>
<div class="panel-body">Panel Content</div>
<div class="panel-footer">SYH </div>
</div>
</div>
</body>
</html>
Home.jsp 생성 ( 글 작성 버튼 + 글 상세보는 기능 )
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="fn" uri = "http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Simple Board</h2>
<div class="panel panel-info">
<div class="panel-heading">BOARD</div>
<div class="panel-body">
<table class="table table-bordered table-hover">
<tr>
<td>번호</td>
<td>제목</td>
<td>작성자</td>
<td>작성일</td>
<td>조회수</td>
</tr>
<c:forEach var="vo" items="${list}">
<tr>
<td>${vo.id}</td>
<td><a href="simpleBoardContent?id=${vo.id}">${vo.title}</a></td>
<td>${vo.writer}</td>
<td>${vo.indate}</td>
<td>${vo.count}</td>
</tr>
</c:forEach>
</table>
</div>
<div class="panel-footer">SYH</div>
</div>
</div>
</body>
</html>
Controller ( SimpleBoardController.java )


// SimpleBoardController
@GetMapping("/simpleBoardForm")
public String boardForm() {
return "simpleBoardForm";
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Simple Board</h2>
<div class="panel panel-info">
<div class="panel-heading">Simple Board</div>
<div class="panel-body">
<form action="simpleBoardInsert" method="post">
<table class="table">
<tr>
<td>제목</td>
<td><input type="text" name="title" class="form-control"></td>
</tr>
<tr>
<td>내용</td>
<td><textarea rows="7" class="form-control" name="content"></textarea></td>
</tr>
<tr>
<td>작성자</td>
<td><input type="text" name="writer" class="form-control"></td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit" class="btn btn-success btn-sm">등록</button>
<button type="reset" class="btn btn-warning btn-sm">취소</button>
</td>
</tr>
</table>
</form>
</div>
<div class="panel-footer">SYH</div>
</div>
</div>
</body>
</html>
SimpleBoardController
simpleBoardInsert로 전달된 HTTP Post 요청을 처리하기 위해 메서드를 매핑하여 처리합니다.
mapper를 통해 sql 쿼리를 보내 DB에 Insert한 이후 home으로 HTTP Get 요청을 보내 사용자에게 결과가 반영된 home.jsp 를 보여줍니다.
@PostMapping("/simpleBoardInsert")
public String boardInsert(SimpleBoard vo) {
simpleBoardMapper.simpleBoardInsert(vo);
return "redirect:/home";
}
mapper(SimpleBoardMapper)

결과


home.jsp에서 게시글의 제목을 클릭하였을때 해당 내용으로 보내지도록 설정해야합니다. 동시에 해당 게시글을 들어갈 때마다 조회수에 + 1 기능도 구현하고자 합니다.

SimpleBoardController

SimpleBoardMapper

SimpleBoardContent.jsp
상세 내용 확인 페이지 에서는 게시글 수정, 삭제, Home으로 돌아가는 기능을 추가할려구 합니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Simple Board</h2>
<div class="panel panel-info">
<div class="panel-heading">BOARD</div>
<div class="panel-body">
<table class="table">
<tr>
<td>제목</td>
<td>${vo.title}</td>
</tr>
<tr>
<td>내용</td>
<td>${fn:replace(vo.content,newLineChar,"<br/>")}</td>
</tr>
<tr>
<td>작성자</td>
<td>${vo.writer}</td>
</tr>
<tr>
<td>작성일</td>
<td>${fn:split(vo.indate," ")[0]}</td>
</tr>
<tr>
<td colspan="2" align="center">
<a href="simpleBoardUpdateForm/${vo.id}" class="btn btn-primary btn-sm">수정</a>
<a href="simpleBoardDelete/${vo.id}" class="btn btn-warning btn-sm">삭제</a>
<a href="home" class="btn btn-info btn-sm">목록</a>
</td>
</tr>
</table>
</div>
<div class="panel-footer">SYH</div>
</div>
</div>
</body>
</html>
게시글 상세 페이지에서 수정 버튼을 클릭하면 simpleBoardUpdateForm으로 HTTP GET 요청이 전달됩니다. pojo에서 해당 요청을 받아서 수정 페이지로 전달하고 수정페이지에서 수정을 누르면 home으로 가도록 설계합니다
@GetMapping("/simpleBoardUpdateForm/{id}")
public String simpleBoardUpdateForm(@PathVariable("id") int id,Model model) {
SimpleBoard vo = simpleBoardMapper.simpleBoardContent(id);
model.addAttribute("vo",vo);
return "simpleBoardUpdateForm";
}
@PostMapping("/simpleBoardUpdate")
public String simpleBoardUpdate(SimpleBoard vo) {
simpleBoardMapper.simpleBoardUpdate(vo);
return "redirect:/home";
}
SimpleBoardMapper

simpleBoardForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Simple Board</h2>
<div class="panel panel-info">
<div class="panel-heading">Simple Board</div>
<div class="panel-body">
<form action="simpleBoardInsert" method="post">
<table class="table">
<tr>
<td>제목</td>
<td><input type="text" name="title" class="form-control"></td>
</tr>
<tr>
<td>내용</td>
<td><textarea rows="7" class="form-control" name="content"></textarea></td>
</tr>
<tr>
<td>작성자</td>
<td><input type="text" name="writer" class="form-control"></td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit" class="btn btn-success btn-sm">등록</button>
<button type="reset" class="btn btn-warning btn-sm">취소</button>
</td>
</tr>
</table>
</form>
</div>
<div class="panel-footer">SYH</div>
</div>
</div>
</body>
</html>
테스트


게시글 상세 페이지에서 삭제 버튼을 클릭하면 simpleBoardUpdateForm으로 HTTP GET 요청이 전달됩니다. pojo에서 해당 요청을 받아서 MyBatis Mapper를 이용해서 삭제합니다. 그 이후 다시 Home으로 가도록 합니다.
SimpleBoardController

SimpleBoardMapper

Test


좀 더 MyBatis를 찾아보니 xml파일이 아닌 애노테이션을 통해 SQL 쿼리를 실행가능하다는 것을 알게되었습니다.






CRUD 전부 정상적으로 동작한다는 것을 알 수 있습니다.
애노테이션 기반 매핑을 사용하면 XML 매핑 파일을 관리할 필요가 없어져 코드의 간결성이 높아지고, 매퍼 인터페이스와 SQL 쿼리가 같은 위치에 있어 유지보수가 용이해집니다.
그러나 복잡한 쿼리나 동적 SQL의 경우, XML 매핑이 더 적합할 수 있다는 생각이 들었습니다.
JDBC는 빠른 구현을 위해 Controller, Service, Repository로 나누지 않고 Controller에 한번에 구현 하였습니다.
package com.syh.controller;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.sql.PreparedStatement;
import com.mysql.jdbc.Statement;
import com.syh.entity.SimpleBoard;
import com.syh.mapper.SimpleBoardMapper;
import lombok.RequiredArgsConstructor;
@Controller
@RequiredArgsConstructor
public class SimpleBoardController {
// // MyBatis 기반 CRUD
// @Autowired
// private SimpleBoardMapper simpleBoardMapper;
//
// @GetMapping("/home")
// public String Home(Model model) {
// List<SimpleBoard> list = simpleBoardMapper.getAllBoards();
// model.addAttribute("list",list);
//
// return "home";
// }
// @GetMapping("/simpleBoardForm")
// public String boardForm() {
// return "simpleBoardForm";
// }
//
// @PostMapping("/simpleBoardInsert")
// public String boardInsert(SimpleBoard vo) {
// simpleBoardMapper.simpleBoardInsert(vo);
// return "redirect:/home";
// }
//
// @GetMapping("/simpleBoardContent")
// public String simpleBoardContent(@RequestParam("id") int id , Model model) {
// SimpleBoard vo = simpleBoardMapper.simpleBoardContent(id);
// simpleBoardMapper.simpleBoardCount(id);
// model.addAttribute("vo",vo);
// return "simpleBoardContent";
// }
//
// @GetMapping("/simpleBoardUpdateForm/{id}")
// public String simpleBoardUpdateForm(@PathVariable("id") int id,Model model) {
// SimpleBoard vo = simpleBoardMapper.simpleBoardContent(id);
// model.addAttribute("vo",vo);
// return "simpleBoardUpdateForm";
// }
//
// @PostMapping("/simpleBoardUpdate")
// public String simpleBoardUpdate(SimpleBoard vo) {
// simpleBoardMapper.simpleBoardUpdate(vo);
// return "redirect:/home";
// }
//
// @GetMapping("/simpleBoardDelete/{id}")
// public String boardDelete(@PathVariable int id) {
// simpleBoardMapper.simpleBoardDelete(id);
// return "redirect:/home";
// }
// JdbcTemplate를 통한 CRUD
private final JdbcTemplate jdbcTemplate;
@GetMapping("/home")
public String Home(Model model) {
String sql = "select * from simpleBoard";
List<SimpleBoard> list =jdbcTemplate.query(sql, new RowMapper<SimpleBoard>() {
@Override
public SimpleBoard mapRow(ResultSet rs, int rowNum) throws SQLException {
SimpleBoard board = new SimpleBoard();
board.setId(rs.getInt("id"));
board.setTitle(rs.getString("title"));
board.setContent(rs.getString("content"));
board.setWriter(rs.getString("writer"));
board.setIndate(rs.getDate("indate").toString());
board.setCount(rs.getInt("count"));
return board;
}
});
model.addAttribute("list",list);
return "home";
}
@GetMapping("/simpleBoardForm")
public String boardForm() {
return "simpleBoardForm";
}
@PostMapping("/simpleBoardInsert")
public String boardInsert(SimpleBoard vo) {
String sql = "insert into simpleBoard(title,content,writer) values (?, ?, ?)";
jdbcTemplate.update(con->{
PreparedStatement preparedStatement =con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, vo.getTitle());
preparedStatement.setString(2, vo.getContent());
preparedStatement.setString(3, vo.getWriter());
return preparedStatement;
});
return "redirect:/home";
}
@GetMapping("/simpleBoardContent")
public String simpleBoardContent(@RequestParam("id") int id , Model model) {
String sql = "select * from simpleBoard";
List<SimpleBoard> list =jdbcTemplate.query(sql, new RowMapper<SimpleBoard>() {
@Override
public SimpleBoard mapRow(ResultSet rs, int rowNum) throws SQLException {
SimpleBoard board = new SimpleBoard();
board.setId(rs.getInt("id"));
board.setTitle(rs.getString("title"));
board.setContent(rs.getString("content"));
board.setWriter(rs.getString("writer"));
board.setIndate(rs.getDate("indate").toString());
board.setCount(rs.getInt("count"));
return board;
}
});
model.addAttribute("vo",list.get(0));
String countPlusSql = "update simpleBoard set count = count + 1 where id = ?";
jdbcTemplate.update(countPlusSql, id);
return "simpleBoardContent";
}
@GetMapping("/simpleBoardUpdateForm/{id}")
public String simpleBoardUpdateForm(@PathVariable("id") int id,Model model) {
String sql = "select * from simpleBoard";
List<SimpleBoard> list =jdbcTemplate.query(sql, new RowMapper<SimpleBoard>() {
@Override
public SimpleBoard mapRow(ResultSet rs, int rowNum) throws SQLException {
SimpleBoard board = new SimpleBoard();
board.setId(rs.getInt("id"));
board.setTitle(rs.getString("title"));
board.setContent(rs.getString("content"));
board.setWriter(rs.getString("writer"));
board.setIndate(rs.getDate("indate").toString());
board.setCount(rs.getInt("count"));
return board;
}
});
model.addAttribute("vo",list.get(0));
return "simpleBoardUpdateForm";
}
@PostMapping("/simpleBoardUpdate")
public String simpleBoardUpdate(SimpleBoard vo) {
String sql = "update simpleBoard set title=?,content=? where id=?";
jdbcTemplate.update(sql,vo.getTitle(),vo.getContent(),vo.getId());
return "redirect:/home";
}
@GetMapping("/simpleBoardDelete/{id}")
public String boardDelete(@PathVariable int id) {
String sql = "delete from simpleBoard where id = ?";
jdbcTemplate.update(sql,id);
return "redirect:/home";
}
}




환경구축에 예상보다 많은 시간이 소요되서 다음 포스트에 마무리 해보도록 하겠습니다!!
https://github.com/songyuheon98/simpleBoardCRUD