lombok과 Spring을 이용해 게시판을 만들어보자
lombok 이란
일반적으로 자바개발을 하다보면 Model 을 만들고 각 멤버변수를 접근할수 있는 (각 요소들이 private 접근권한을 가지고 있을때) method 를 만들게 된다. 아래처럼 말이다. (윈도우/이클립스 기준)
public class Student {
private int id;
private String name;
private int grade;
private String department;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", grade=" + grade + ", department=" + department + "]";
}
}
이렇게 하는 방법도 있지만 어노테이션 설정으로 적용할수 있는 간단한 라이브러리를 소개하고자 한다. 바로 lombok, 공식 홈페이지 : https://projectlombok.org 설치 및 사용방법은 아주 간단하다. 공식 홈페이지에서 jar를 다운받고 실행, 아래처럼 이클립스 실행파일 경로를 설정해준다음에 인스톨을 누르면 된다. lombok.png maven 환경에서 dependency를 가져오기 위해서는 당연히 추가설정을 해줘야 한다.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version> <!--버전은 그때 맞춰서-->
</dependency>
실제로 코드상에서 사용방법은 다음과 같다. 정말 간단히, 어노테이션만 적용해주면 끝!
lombok 설치 방법중 중요한 부분만 캡쳐해 보았다 자세한 사항은 따로 검색해 보길 바란다.
Db설정
DROP SEQUENCE SIMPLE_SEQ;
CREATE SEQUENCE SIMPLE_SEQ
START WITH 1
INCREMENT BY 1
MAXVALUE 999999
NOCYCLE
NOCACHE;
DROP TABLE SIMPLE;
CREATE TABLE SIMPLE
(
NO NUMBER PRIMARY KEY,
WRITER VARCHAR2(100),
TITLE VARCHAR2(1000),
CONTENT VARCHAR2(4000),
REGDATE DATE
);
DTO 생성
package com.koreait.simple1.dto;
import java.sql.Date;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor // 디폴트 생성자를 자동으로 생성해 줍니다.
@AllArgsConstructor // 필드를 이용한 생성자를 자동으로 생성해 줍니다.
@Data // lombok의 애너테이션, getter/setter등을 자동으로 생성해 줍니다.
// Window - Show View - Outline 에서 확인이 가능합니다.
public class SimpleDto {
// field
private int no;
private String writer;
private String title;
private String content;
private Date regDate;
}
lombok과 애너테이션들을 이용해 생성자를 자동으로 생성!!
DAO
package com.koreait.simple1.dao;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import com.koreait.simple1.dto.SimpleDto;
public class SimpleDao {
// Connection Pool 처리는 DataSource 클래스가 합니다.
// 필요한 설정은 톰캣 내부의 context.xml에 있습니다.
// <Resource name="jdbc/oracle">을 처리하는 Context 클래스가 필요합니다.
// name에 의한 접근: JNDI
private DataSource dataSource;
// singleton
private SimpleDao() {
// context.xml에 있는 설정을 읽어와서 dataSource를 만듭니다.
try {
Context context = new InitialContext();
dataSource = (DataSource)context.lookup("java:comp/env/jdbc/oracle"); // 톰캣이다: java:comp/env/ 나머지는 <Resource>의 name 속성
} catch (NamingException e) {
e.printStackTrace();
}
}
private static SimpleDao simpleDao = new SimpleDao();
public static SimpleDao getInstance() {
return simpleDao;
}
private Connection con;
private PreparedStatement ps;
private ResultSet rs;
private String sql;
private void close(Connection con, PreparedStatement ps, ResultSet rs) {
try {
if (rs != null) { rs.close(); }
if (ps != null) { ps.close(); }
if (con != null) { con.close(); }
} catch (SQLException e) {
e.printStackTrace();
}
}
/***** 1. list *****/
public List<SimpleDto> simpleList() {
List<SimpleDto> list = new ArrayList<SimpleDto>();
try {
con = dataSource.getConnection();
sql = "SELECT NO, WRITER, TITLE, CONTENT, REGDATE FROM SIMPLE";
ps = con.prepareStatement(sql);
rs = ps.executeQuery(); // select문 실행 메소드
while (rs.next()) {
int no = rs.getInt("NO");
String writer = rs.getString("WRITER");
String title = rs.getString("TITLE");
String content = rs.getString("CONTENT");
Date regDate = rs.getDate("REGDATE");
SimpleDto simpleDto = new SimpleDto(no, writer, title, content, regDate);
list.add(simpleDto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close(con, ps, rs);
}
return list;
}
/***** 2. insert *****/
public void simpleInsert(SimpleDto simpleDto) {
try {
con = dataSource.getConnection();
sql = "INSERT INTO SIMPLE VALUES (SIMPLE_SEQ.NEXTVAL, ?, ?, ?, SYSDATE)";
ps = con.prepareStatement(sql);
ps.setString(1, simpleDto.getWriter());
ps.setString(2, simpleDto.getTitle());
ps.setString(3, simpleDto.getContent());
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(con, ps, null);
}
}
/***** 3. view *****/
public SimpleDto simpleView(int no) {
SimpleDto simpleDto = null;
try {
con = dataSource.getConnection();
sql = "SELECT * FROM SIMPLE WHERE NO = ?";
ps = con.prepareStatement(sql);
ps.setInt(1, no);
rs = ps.executeQuery();
if (rs.next()) {
String writer = rs.getString("WRITER");
String title = rs.getString("TITLE");
String content = rs.getString("CONTENT");
Date regDate = rs.getDate("REGDATE");
simpleDto = new SimpleDto(no, writer, title, content, regDate);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close(con, ps, rs);
}
return simpleDto;
}
/***** 4. delete *****/
public void simpleDelete(int no) {
try {
con = dataSource.getConnection();
sql = "DELETE FROM SIMPLE WHERE NO = ?";
ps = con.prepareStatement(sql);
ps.setInt(1, no);
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(con, ps, null);
}
}
/***** 5. update *****/
public void simpleUpdate(SimpleDto simpleDto) {
try {
con = dataSource.getConnection();
sql = "UPDATE SIMPLE SET TITLE = ?, CONTENT = ? WHERE NO = ?";
ps = con.prepareStatement(sql);
ps.setString(1, simpleDto.getTitle());
ps.setString(2, simpleDto.getContent());
ps.setInt(3, simpleDto.getNo());
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(con, ps, null);
}
}
}
기능 추가될 때마다 추가시켜 나간다
Command
첫번째로 Java interface 를 이용해 모든 커멘드에 기본 인터페이스로 참조될 SimpleCommand.java 생성
SimpleCommand
package com.koreait.simple1.command;
import org.springframework.ui.Model;
public interface SimpleCommand {
public void execute(Model model);
}
SimpleListCommand
package com.koreait.simple1.command;
import org.springframework.ui.Model;
import com.koreait.simple1.dao.SimpleDao;
public class SimpleListCommand implements SimpleCommand {
@Override
public void execute(Model model) {
// JSP와 달리 command는 데이터만 처리하면 됩니다.
// VIEW는 컨트롤러가 처리합니다.
model.addAttribute("list", SimpleDao.getInstance().simpleList());
}
}
SimpleInsertCommand
package com.koreait.simple1.command;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.ui.Model;
import com.koreait.simple1.dao.SimpleDao;
import com.koreait.simple1.dto.SimpleDto;
public class SimpleInsertCommand implements SimpleCommand {
@Override
public void execute(Model model) {
// 전달 받은 model에는 request가 들어 있어요.
// 그걸 꺼내야 합니다.
// model에 저장된 속성을 직접 꺼내는 방법은 없어요.
// 대신 model은 Map으로 바꾸는 것이 가능합니다. (asMap() 메소드)
// Map으로 바꾸고 나면 Map에서 꺼내는 메소드인 get() 메소드를 이용해서 꺼내면 됩니다.
Map<String, Object> map = model.asMap();
HttpServletRequest request = (HttpServletRequest) map.get("request"); // model에 저장된 속성(attribute)을 키 값으로 사용하면 됩니다.
String writer = request.getParameter("writer");
String title = request.getParameter("title");
String content = request.getParameter("content");
SimpleDto simpleDto = new SimpleDto();
simpleDto.setWriter(writer);
simpleDto.setTitle(title);
simpleDto.setContent(content);
SimpleDao.getInstance().simpleInsert(simpleDto);
}
}
Controller
@Controller
public class SimpleController {
// 21_simple 프로젝트는 command들을 new로 생성하는 연습입니다.
// field
private SimpleCommand command;
@RequestMapping(value="/", method=RequestMethod.GET)
public String index() {
return "index";
}
@RequestMapping(value="simpleList.do")
public String simpleList(Model model) {
// DB에서 list를 가져와서 simpleListPage.jsp로 이동시킵니다.
// simpleListPage.jsp로 보낼 데이터인 list는 Model에 저장합니다.
// Model에 저장된 데이터를 simpleListPage.jsp으로 보내려면 forward합니다.
/*
SimpleListCommand가 없다면 아래와 같이 작업할 수 있겠습니다.
하지만, 이렇게 하시면 안 됩니다.
SimpleDao simpleDao = SimpleDao.getInstance();
model.addAttribute("list", simpleDao.simpleList());
return "simple/simpleListPage";
*/
command = new SimpleListCommand(); // 개발자 직접 생성
command.execute(model);
return "simple/simpleListPage"; // simple 폴더 아래 simpleListPage.jsp로 forward합니다.
}
@RequestMapping(value="simpleInsertPage.do")
public String simpleInsertPage() {
return "simple/simpleInsertPage"; // simple 폴더 아래 simpleInsertPage.jsp로 forward합니다.
}
@RequestMapping(value="simpleInsert.do")
public String simpleInsert(HttpServletRequest request, Model model) {
// SimpleInsertCommand 가 삽입을 담당합니다.
// 모든 command들은 model이 필요합니다.
// SimpleInsertCommand에게 request를 전달하려면?
// 모든 command들은 실행할 때 model만 전달 받습니다.
// 따라서, model에 request를 저장해 둡니다. 그리고 model을 전달합니다.
model.addAttribute("request", request);
command = new SimpleInsertCommand(); // 개발자가 직접 생성
command.execute(model);
// return "simple/simpleListPage"; // insert 후에는 forward하면 안 됩니다.
return "redirect:simpleList.do"; // insert 후에는 redirect 합니다.
}
}
View
Index.jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8”
pageEncoding=”UTF-8”%>
<!-- 이동합니다 -->
<a href="simpleList.do">간단게시판으로 이동</a>
첫 화면을 먼저 만들어 준다
SimpleListPage
<%@ 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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table border="1">
<thead>
<tr>
<td>번호</td>
<td>작성자</td>
<td>제목</td>
<td>작성일</td>
</tr>
</thead>
<tbody>
<c:if test="${empty list}">
<tr>
<td colspan="4">없음</td>
</tr>
</c:if>
<c:if test="${not empty list}">
<c:forEach var="simpleDto" items="${list}">
<tr>
<td>${simpleDto.no}</td>
<td>${simpleDto.writer}</td>
<td>${simpleDto.title}</td>
<td>${simpleDto.regDate}</td>
</tr>
</c:forEach>
</c:if>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<input type="button" value="새글작성하러가기" onclick="location.href='simpleInsertPage.do'" />
</td>
</tr>
</tfoot>
</table>
</body>
</html>
간단게시판으로 이동하면 보여줄화면이다
SimpleInsertPage
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="simpleInsert.do">
작성자
<input type="text" name="writer" /><br/>
제목
<input type="text" name="title" /> <br/>
내용
<input type="text" name="content" /><br/>
<button>작성완료</button>
</form>
</body>
</html>
새글 작성하러 가기로 가면 보여줄 화면이다