스프링프레임워크MVC5, 마이바티스3.5, 오라클12.2 로그인, 게시판(페이징) 실습, Spring MVC5, MyBatis3.5, Oracle12.2, Login, Board Example
http://ojc.asia/bbs/write.php?w=u&bo_table=LecSpring&wr_id=849&page=
n 실습환경
JDK1.8
STS 4.7.1
Spring-Webmvc 5.2.3
MyBatis 3.5
mybatis-spring 2.0
Lombok 1.16.16
Servlet API 3.1.0
Apache Tomcat 9
Oracle 12.2
n 실행화면
n 프로젝트 구조
n DB 스키마(Oracle12.2에 scott 이라는 계정을 만들어 실행)
-- 아래는 오라클 12C 이상에서 작성된 스크립트 입니다.
DROP TABLE XUSER;
CREATE TABLE XUSER (
EMAIL VARCHAR2(100) NOT NULL PRIMARY KEY,
PASSWORD VARCHAR2(100) DEFAULT '1234'
);
DROP TABLE XBOARD;
CREATE TABLE XBOARD (
ID NUMBER(10,0) GENERATED BY DEFAULT AS IDENTITY,
WRITER VARCHAR2(100) DEFAULT NULL,
TITLE VARCHAR2(255) DEFAULT NULL,
CONTENT VARCHAR2(4000) DEFAULT NULL,
REG_DATE DATE DEFAULT NULL,
HIT_COUNT NUMBER(10,0) DEFAULT 0
);
INSERT INTO XUSER(EMAIL) VALUES('e1@google.com');
INSERT INTO XUSER(EMAIL) VALUES('e2@naver.com');
INSERT INTO XUSER(EMAIL) VALUES('e3@daum.com');
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE1', '내용1', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE2', '내용2', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE3', '내용3', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE4', '내용4', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE5', '내용5', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE6', '내용6', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE7', '내용7', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE8', '내용8', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE9', '내용9', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE10', '내용10', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE11', '내용11', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE12', '내용12', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE13', '내용13', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE14', '내용14', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE15', '내용15', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE16', '내용16', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE17', '내용17', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE18', '내용18', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE19', '내용19', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE20', '내용20', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE21', '내용21', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE22', '내용22', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE23', '내용23', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE24', '내용24', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE25', '내용25', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE26', '내용26', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE27', '내용27', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE28', '내용28', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE29', '내용29', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE30', '내용30', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE31', '내용31', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE32', '내용32', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE33', '내용33', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE34', '내용34', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE35', '내용35', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE36', '내용36', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE37', '내용37', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE38', '내용38', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE39', '내용39', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE40', '내용40', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE41', '내용41', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE42', '내용42', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE43', '내용43', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE44', '내용44', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE45', '내용45', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE46', '내용46', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE47', '내용47', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE48', '내용48', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE49', '내용49', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE50', '내용50', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE51', '내용51', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE52', '내용52', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE53', '내용53', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE54', '내용54', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE55', '내용55', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE56', '내용56', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE57', '내용57', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e2@naver.com', 'TITLE58', '내용58', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e1@google.com', 'TITLE59', '내용59', SYSDATE, 0);
INSERT INTO XBOARD( WRITER, TITLE, CONTENT, REG_DATE, HIT_COUNT) VALUES('e3@daum.com', 'TITLE60', '내용60', SYSDATE, 0);
COMMIT;
n pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>board2</groupId>
<artifactId>board2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<springframework-version>5.2.3.RELEASE</springframework-version>
<oracle.version>12.2.0.1</oracle.version>
<mybatis.spring.version>2.0.5</mybatis.spring.version>
<mybatis.version>3.5.5</mybatis.version>
<jstl.version>1.2</jstl.version>
<servlets.version>3.1.0</servlets.version>
<jsp.version>2.3.1</jsp.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${springframework-version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>${oracle.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis.spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlets.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${jsp.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>oracle</id>
<name>ORACLE JDBC Repository</name>
<url>https://maven.xwiki.org/externals/</url>
</repository>
</repositories>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
n resources/jdbc.properties
# 오라클 접속 설정
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl
jdbc.username=scott
jdbc.password=tiger
n WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<display-name>board2</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
<filter>
<filter-name>encoding-filter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding-filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
n WEB-INF/spring/root-Context.xml
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- web.xml에 정의된 ConterxtLoaderListener가 로딩하는
자바빈(부모컨텍스트)을 정의
DispatcherServlet이 로딩하는 자바빈은 자식 컨텍스트임 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:/mybatis/mybatis-config.xml" />
<property name="mapperLocations" value="classpath:/mybatis/mapper/**/*.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage"
value="ojc.board.repository,ojc.user.repository" />
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"
destroy-method="clearCache">
<constructor-arg name="sqlSessionFactory" ref="SqlSessionFactory" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
n WEB-INF/spring/appServlet/servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 디스패처 서블릿을 위한 설정 파일
정의된 자바빈을 디스패처 서블릿이 관리하는 컨텍스트에 로딩한다 -->
<!-- Spring MVC 컴포넌트들을 디폴트 설정을 통해 활성화.
Spring MVC @Controller에 요청을 보내 처리하기 위한
HandlerMapping과 HandlerAdapter를 빈으로 등록.
컨트롤러(@Controller)에서는 @RequestMapping, @ExceptionHandler
등과 같은 어노테이션을 통해 해당 기능을 사용할 수 있도록 한다. -->
<annotation-driven />
<!-- @Component, @Repository, @Service, @Controller
어노테이션을 가진 자바빈들을 스캐닝하기 위한 기본 패키지 경로 -->
<context:component-scan base-package="ojc" />
<resources mapping="/resources/**" location="/resources/" />
<!-- ViewResilver : 접두어, 접미어로 컨트롤러가 리턴하는 뷰의 이름을 해석 -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- 로그인 여부를 확인하기 위한 인터셉터
게시판쪽으로 들어오는 요청은 로그인이 되지 않았다면
로그인 화면으로 보낸다. -->
<interceptors>
<interceptor>
<mapping path="/boards/**" />
<beans:bean class="ojc.web.interceptor.LoginInterceptor" />
</interceptor>
</interceptors>
</beans:beans>
n ojc.board.dto.Page.java
package ojc.board.dto;
import lombok.Data;
/**
* -------------------------------------
* STS에서 Lombok을 사용하기 위해서는
* -------------------------------------
* 1. pom.xml에 lombok dependency를 추가하고
* 2. .m2 아래 lombok-1.16.16.jar를 복사후 lombok.jar로 이름 변경
* 3. SpringToolSuite4.ini 파일의 맨아래에 -javaagent:lombok.jar 추가
* 4. STS 다시 시작
* @author jclee
*
* 페이징을 위한 클래스
*/
@Data
public class Pager {
private int page; // current page
private int size; // rows per page
private int bsize; // pages per block
private int rows; // total elements
private int pages; // total pages
private int blocks; // total blocks
private int block; // current block
private int bspage; // current block start page
private int bepage; // current block end page
public Pager(int page, int size, int bsize, int rows) {
//현재페이지
this.page = page;
//한페이지당 게시물개수
this.size = size;
//블럭당페이지사이즈(기본5로 되어 있음)
//페이지5개씩 한블럭에 표시되고 넘어가면 >> 표시가 나옴
this.bsize = bsize;
//총게시물건수
this.rows = rows;
//총페이지
pages = (int) Math.ceil((double) this.rows / this.size);
//총블럭
blocks = (int) Math.ceil((double) pages / this.bsize);
//현재블럭
block = (int) Math.ceil((double) this.page / this.bsize);
//현재블럭종료페이지
bepage = block * this.bsize;
//현재페이지시작페이지
bspage = bepage - this.bsize + 1;
}
// 두번째 페이지이고 한페이지에 10개씩 이라면 10을 리턴
public static int seekOffset(int page, int size) {
if (page > 0) {
return (page - 1) * size;
}
return 0;
}
// 두번째 페이지이고 한페이지에 10개씩 이라면 11을 리턴
public static int seekStart(int page, int size) {
return ((page - 1) * size) + 1;
}
// 두번째 페이지이고 한페이지에 10개씩 이라면 20을 리턴
public static int seekEnd(int page, int size) {
return page * size;
}
}
n ojc.board.model.Board.java
package ojc.board.model;
import java.util.Date;
import lombok.Data;
/**
* -------------------------------------
* STS에서 Lombok을 사용하기 위해서는
* -------------------------------------
* 1. pom.xml에 lombok dependency를 추가하고
* 2. .m2 아래 lombok-1.16.16.jar를 복사후 lombok.jar로 이름 변경
* 3. SpringToolSuite4.ini 파일의 맨아래에 -javaagent:lombok.jar 추가
* 4. STS 다시 시작
* @author jclee
*
* 오라클쪽의 XBOARD 테이블에 대응하는 모델 클래스
*/
@Data
public class Board {
private long id; //게시물ID
private String writer; //작성자
private String title; //제목
private String content; //본문내용
private Date regDate; //등록일시
private long hitCount; //조회수
}
n ojc.board.repository.BoardMapper.java
package ojc.board.repository;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import ojc.board.model.Board;
/**
* 매퍼 클래스
* board-mapper.xml의 namespace에 기술됨
* @author jclee
*
*/
@Mapper
public interface BoardMapper {
public int insert(Board board);
public int update(Board board);
public int delete(long id);
@Select("SELECT COUNT(*) FROM xboard")
public int count();
@Select("SELECT * FROM xboard ORDER BY id DESC")
public List<Board> selectAll();
public Board selectById(long id);
// 페이지 나누기 쿼리 : page : 현재페이지, size:페이지당 게시물개수
public List<Board> selectByLimit(@Param("page") int page, @Param("size") int size);
//조회수 증가 쿼리,본인이 쓴 글은 조회수를 증가 안하기 위해 글쓴이(requester)를 넘김
public int increment(@Param("id") long id, @Param("requester") String requester);
}
n ojc.login.dto.Login.java
package ojc.login.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* -------------------------------------
* STS에서 Lombok을 사용하기 위해서는
* -------------------------------------
* 1. pom.xml에 lombok dependency를 추가하고
* 2. .m2 아래 lombok-1.16.16.jar를 복사후 lombok.jar로 이름 변경
* 3. SpringToolSuite4.ini 파일의 맨아래에 -javaagent:lombok.jar 추가
* 4. STS 다시 시작
*
* @author jclee
* 로그인에서 사용되는 DTO
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Login {
private String email;
private String password;
private String error; //오류 메시지 셋팅위한 것 추가됨
}
n ojc.login.service.LoginService.java
package ojc.login.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ojc.login.dto.Login;
import ojc.user.model.User;
import ojc.user.repository.UserMapper;
/**
* 로그인 서비스
* 사용자 인증
* @author jclee
*
*/
@Service
public class LoginService {
@Autowired
private UserMapper userMapper;
public void authenticate(Login login) {
User user = userMapper.selectByEmail(login.getEmail());
if (user == null) {
login.setError("Email does not exist.");
} else {
if (!user.getPassword().equals(login.getPassword())) {
login.setError("Password is not correct.");
} else {
login.setError(null);
}
}
}
}
n ojc.user.model.User.java
package ojc.user.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* -------------------------------------
* STS에서 Lombok을 사용하기 위해서는
* -------------------------------------
* 1. pom.xml에 lombok dependency를 추가하고
* 2. .m2 아래 lombok-1.16.16.jar를 복사후 lombok.jar로 이름 변경
* 3. SpringToolSuite4.ini 파일의 맨아래에 -javaagent:lombok.jar 추가
* 4. STS 다시 시작
* @author jclee
*
* 오라클쪽의 XUSER 테이블에 대응되는 모델 클래스
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String email;
private String password;
}
n UserMapper.java
package ojc.user.repository;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultType;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import ojc.user.model.User;
/**
* 매퍼 클래스
* board쪽고 달리 loign쪽은 매퍼 XML 파일 없이 이 자바 매퍼에서 쿼리 처리 다함
* @return
*/
@Mapper
public interface UserMapper {
@Insert("INSERT INTO xuser(email, password) VALUES(#{email}, #{password})")
public int insert(User user);
@Update("UPDATE xuser SET password = #{password} WHERE email = #{email}")
public int update(User user);
@Delete("DELETE FROM xuser WHERE email = #{email}")
public int delete(String email);
@Select("SELECT COUNT(*) FROM xuser")
public int count();
@Select("SELECT * FROM xuser ORDER BY email ASC")
@ResultType(User.class)
public List<User> selectAll();
@Select("SELECT * FROM xuser WHERE email = #{email}")
// 선언해 놓으면 다른 메소드에서 @ResultMap("userResultMap") 선언으로 이용할 수 있다.
@Results(id = "userResultMap", value = {
@Result(property = "email", column = "email"),
@Result(property = "password", column = "password") })
public User selectByEmail(String email);
}
n Ojc.web.controller.BoardController.java
package ojc.web.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.ModelAttribute;
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 org.springframework.web.servlet.ModelAndView;
import ojc.board.dto.Pager;
import ojc.board.model.Board;
import ojc.board.repository.BoardMapper;
import ojc.user.model.User;
/**
* 게시판 요청 처리를 위한 컨트롤러
* @author jclee
*
*/
@Controller
@RequestMapping("/boards")
public class BoardController {
@Autowired
private BoardMapper boardMapper;
/**
* 게시판 리스트 보기
* @param page : 조회를 원하는 페이지
* @param size : 한페이지당 보여지는 게시물 건수
* @param bsize : 하나의 페이지 블럭에 포함되는 페이지 수(본 예제에서는 5개의 페이지를 보인다)
* @return
*/
@GetMapping()
public ModelAndView getBoardsView(
@RequestParam(name="page", required=false, defaultValue="1") int page,
@RequestParam(name="size", required=false, defaultValue="10") int size,
@RequestParam(name="bsize", required=false, defaultValue="5") int bsize) {
ModelAndView mav = new ModelAndView("board_list");
mav.addObject("boards", boardMapper.selectByLimit(page, size));
mav.addObject("pager", new Pager(page, size, bsize, boardMapper.count()));
return mav;
}
/**
* 게시물 상세보기
* @param id
* @param session
* @param model
* @return
*/
@GetMapping("/view/{id}")
public String getBoardView(@PathVariable long id, HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
if (user == null) {
return session.getServletContext().getContextPath() + "/login";
}
boardMapper.increment(id, user.getEmail());
model.addAttribute("board", boardMapper.selectById(id));
return "board_view";
}
/**
* 글쓰기 화면 board_write.jsp 로딩
* @param session
* @param model
* @return
*/
@GetMapping("/write")
public String getInsertView(HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
if (user == null) {
return session.getServletContext().getContextPath() + "/login";
}
model.addAttribute("user", user);
return "board_write";
}
/**
* 글쓰고 저장 하기
* XBOARD 테이블에 INSERT
* @param board
* @param session
* @param model
* @return
*/
@PostMapping("/write")
public String postInsert(Board board, HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
if (user != null && board != null) {
if (user.getEmail().equals(board.getWriter())) {
boardMapper.insert(board);
return "redirect:/boards";
}
}
return session.getServletContext().getContextPath() + "/boards";
}
/**
* 수정화면 board_update.jsp 로딩
* @param id
* @param session
* @param model
* @return
*/
@GetMapping("/update/{id}")
public String getUpdateView(@PathVariable long id, HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
Board board = boardMapper.selectById(id);
if (user != null && board != null) {
if (user.getEmail().equals(board.getWriter())) {
model.addAttribute("board", board);
return "board_update";
}
}
return session.getServletContext().getContextPath() + "/boards";
}
/**
* 수정후 저장하기 XBOARD 테이블 UPDATE 쿼리 실행
* @param board
* @param session
* @param model
* @return
*/
@PostMapping("/update")
public String postUpdate(Board board, HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
if (user != null && board != null) {
if (user.getEmail().equals(board.getWriter())) {
boardMapper.update(board);
return "redirect:/boards/view/" + board.getId();
}
}
return session.getServletContext().getContextPath() + "/boards";
}
/**
* 게시물 삭제
* @param id : 게시물 ID
* @param session
* @param model
* @return
*/
@GetMapping("/delete/{id}")
public String getDelete(@PathVariable long id, HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
if (user != null) {
Board board = boardMapper.selectById(id);
if (user.getEmail().equals(board.getWriter())) {
boardMapper.delete(id);
return "redirect:/boards";
}
}
return session.getServletContext().getContextPath() + "/boards";
}
}
n ojc.web.controller.ControllerExceptionHandler.java
package ojc.web.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class ControllerExceptionHandler {
/**
* 컨트롤러에서 오류가 발생하면 error.jsp 로딩
*/
@ExceptionHandler(Exception.class)
public ModelAndView handleError(Exception e) {
ModelAndView mav = new ModelAndView("error/error");
mav.addObject("errorMsg", e.getMessage());
return mav;
}
}
n ojc.web.controller.HomeController.java
package ojc.web.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 최초 localhost:8080 으로 요청이 오는 경우 처리
* @author jclee
*
*/
@Controller
@RequestMapping("/")
public class HomeController {
@GetMapping
public String getHomeView(HttpServletRequest request) {
return "home";
}
@GetMapping("/404.html")
public String get404View() {
return "error/404";
}
@GetMapping("/throw")
public String testControllerAdvice() {
throw new RuntimeException("Error Test In Controller.");
}
}
n ojc.web.controller.LoginController.java
package ojc.web.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.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import ojc.login.dto.Login;
import ojc.login.service.LoginService;
import ojc.user.model.User;
/**
* 로그인 처리용 컨트롤러
* @author jclee
*
*/
@Controller
public class LoginController {
@Autowired
private LoginService loginService;
@ModelAttribute("active")
public String active(){
return "login";
}
@GetMapping("/login")
public String getLoginView() {
return "login";
}
/**
* 로그인 처리
* @param login
* @param model
* @param session
* @return
*/
@PostMapping("/login")
public String postLogin(Login login, Model model, HttpSession session) {
loginService.authenticate(login);
if (login.getError() != null) {
model.addAttribute("error", login.getError());
model.addAttribute("login", login);
return "login";
} else {
User user = new User(login.getEmail(), login.getPassword());
session.setAttribute("user", user);
return "redirect:/boards";
}
}
@GetMapping("/logout")
public String getLogout(HttpSession session) {
session.invalidate();
return "login";
}
}
n ojc.web.controller.UserController.java
package ojc.web.controller;
import java.util.List;
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 org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import ojc.user.model.User;
import ojc.user.repository.UserMapper;
/**
* 사용자 등록처리 컨트롤러
* @author jclee
*
*/
@Controller
@RequestMapping("/users")
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping
@ResponseBody
public Object getUsersView() {
List<User> users = userMapper.selectAll();
return users;
}
@PostMapping("/enroll")
public String postUser(User user, Model model, HttpSession session, RedirectAttributes redirectAttributes) {
// 클라이언트 단 또는 서버 단에서 데이터 밸리데이션 체크를 적용하는 것을 권장한다.
User duplicatedUser = userMapper.selectByEmail(user.getEmail());
if (duplicatedUser == null) {
userMapper.insert(user);
redirectAttributes.addFlashAttribute("result", "OK");
} else {
redirectAttributes.addFlashAttribute("result", "FAIL");
redirectAttributes.addFlashAttribute("error", "Fail: Email is duplicated.");
}
return "redirect:/login";
}
}
n ojc.web.interceptor.LoginInterceptor.java
package ojc.web.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import ojc.user.model.User;
/**
* /board**로 진입시 로그인 여부를 체크하기 위한 인터셉터
* 로그인이 안되어 있는 경우 로그인 화면(/login) 으로 보냄
* @author jclee
*
*/
@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
if (user == null) {
String url = session.getServletContext().getContextPath() + "/login";
response.sendRedirect(url);
System.out.println("LoginInterceptor # preHandle() : NO PASS");
return false;
}
System.out.println("LoginInterceptor # preHandle() : PASS");
return true;
}
}
n resources/mybatis/mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="true" />
<setting name="defaultFetchSize" value="100" />
<setting name="defaultStatementTimeout" value="30" />
</settings>
<typeAliases>
<!-- 보통 VO객체여러개이고 한 패키지내에 존재할 때 package 사용.
아래 패키지 아래의 클래스들이 mapper xml에서 type으로 사용됨-->
<package name="ojc.board.model" />
<package name="ojc.user.model" />
</typeAliases>
</configuration>
n resources/mybatis/mapper/board-mapper.xml
<?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 namespace="ojc.board.repository.BoardMapper">
<resultMap type="Board" id="boardResultMap">
<result property="id" column="ID" />
<result property="writer" column="WRITER" />
<result property="title" column="TITLE" />
<result property="content" column="CONTENT" />
<result property="regDate" column="REG_DATE" />
<result property="hitCount" column="HIT_COUNT" />
</resultMap>
<insert id="insert" parameterType="Board">
INSERT INTO xboard(writer, title, content, reg_date, hit_count)
VALUES(#{writer}, #{title}, #{content}, SYSDATE, 0)
</insert>
<update id="update" parameterType="Board">
UPDATE xboard SET title=#{title}, content=#{content} WHERE id=#{id}
</update>
<delete id="delete" parameterType="long">
DELETE FROM xboard WHERE id=#{id}
</delete>
<select id="selectById" parameterType="long" resultMap="boardResultMap">
SELECT * FROM xboard WHERE id=#{id}
</select>
<select id="selectByLimit" resultType="Board">
<bind name="start" value="@ojc.board.dto.Pager@seekStart(page, size)"/>
<bind name="end" value="@ojc.board.dto.Pager@seekEnd(page, size)"/>
<!-- SELECT * FROM (
SELECT ROWNUM AS rnum, b.*
FROM (
SELECT * FROM xboard
ORDER BY id DESC
) b
WHERE ROWNUM <= #{end}
) WHERE rnum >= #{start} -->
-- ORACLE12.1 이상
-- 9999페이지까지는 SKIP하고 그 다음 10000번째 페이지의 10개 추출
SELECT *
FROM xboard
ORDER BY id DESC
OFFSET TO_NUMBER(#{start}) - 1 ROWS FETCH NEXT 10 ROWS ONLY
</select>
<update id="increment">
UPDATE xboard SET hit_count=hit_count+1 WHERE id=#{id} and writer!=#{requester}
</update>
</mapper>
n WEB-INF/views/error/error.jsp
n WEB-INF/views/error/404.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="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
.bs-example {
margin: 20px;
}
</style>
</head>
<body>
<c:import url="../nav_top.jsp"></c:import>
<div class="bs-example">
<h1>404 NOT FOUND</h1>
</div>
</body>
</html>
n WEB-INF/views/board_list.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="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
.bs-example {
margin: 20px;
}
.pagination {
margin: 0px !important;
}
</style>
</head>
<body>
<c:import url="nav_top.jsp"></c:import>
<div class="bs-example">
<h2>Board</h2>
<table class="table table-condensed table-hover table-striped">
<thead>
<tr>
<th class="col-xs-1 col-sm-1 col-md-1 col-lg-1">No</th>
<th class="col-xs-6 col-sm-6 col-md-6 col-lg-6">Title</th>
<th class="col-xs-2 col-sm-2 col-md-2 col-lg-2">Writer</th>
<th class="col-xs-2 col-sm-2 col-md-2 col-lg-2">Date</th>
<th class="col-xs-1 col-sm-1 col-md-1 col-lg-1">Hits</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{boards }" var="board">
<tr>
<td>${board.id }</td>
<td><a href="<c:url value='/boards/view/${board.id }'/>">${board.title }</a></td>
<td>${board.writer }</td>
<td><fmt:formatDate pattern="MM-dd hh:mm" value="${board.regDate }" /></td>
<td>${board.hitCount }</td>
</tr>
</c:forEach>
</tbody>
</table>
<div class="row">
<div class="col-xs-8 col-sm-8 col-md-8 col-lg-8">
<ul class="pagination">
<c:set var="target" value="boards" />
<!-- 게시물이 없는 경우 -->
<c:if test="${pager.rows==0 }">
<li class="active"><a href="#">1</a></li>
</c:if>
<!-- 게시물이 있는 경우 -->
<c:if test="${pager.rows > 0 }">
<!-- common 변수에 한페이지당 레코드건수&블럭당 페이지수 저장 -->
<c:set var="common"
value="size=${pager.size }&bsize=${pager.bsize }" />
<!-- 블럭시작페이지가 블럭당 페이지수 보다 큰 경우
예를들면 6번째 페이지를 보는 경우
Home 및 이전 << 셋팅. -->
<c:if test="${pager.bspage > pager.bsize }">
<c:set var="home" value="page=1&${common }" />
<c:set var="prev" value="page=${pager.bspage-1 }&${common }" />
<li><a href="${target }?${home }">Home</a></li>
<li><a href='<c:url value="${target }?${prev }"/>'>«</a></li>
</c:if>
<!-- 5개의 페이지 번호를 표시 -->
<c:forEach var="pno"
begin="${pager.bspage }"
end="${pager.bepage }">
<c:if test="${pno==pager.page }">
<li class="active"><a href="#">${pno }</a></li>
</c:if>
<c:if test="${pno!=pager.page }">
<c:if test="${pno <= pager.pages }">
<c:set var="page" value="page=${pno }&${common }" />
<li><a href='<c:url value="${target }?${page }"/>'>${pno }</a></li>
</c:if>
</c:if>
</c:forEach>
<!-- 블럭시작페이지가 전체 페이지수 보다 작은 경우
예를들면 전체 페이지수가 6인데 1~5번째 페이지를 보는 경우
Last 및 이후 >> 셋팅. -->
<c:if test="${pager.bepage < pager.pages }">
<c:set var="next" value="page=${pager.bepage+1 }&${common }" />
<c:set var="last" value="page=${pager.pages }&${common }" />
<li><a href='<c:url value="${target }?${next }"/>'>»</a></li>
<li><a href="${target }?${last }">Last</a></li>
</c:if>
</c:if>
</ul>
</div>
<div class="col-xs-4 col-sm-4 col-md-4 col-lg-4">
<span class="pull-right"> <a href="<c:url value='/boards/write'/>" class="btn btn-primary">Write</a>
</span>
</div>
</div>
</div>
</body>
</html>
n WEB-INF/views/board_update.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="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
.bs-example {
margin-bottom: 20px;
margin-left: 20px;
margin-right: 40px;
margin-top: 20px;
}
</style>
</head>
<body>
<c:import url="nav_top.jsp"></c:import>
<div class="bs-example">
<form class="form-horizontal" action="<c:url value='/boards/update'/>" method="post">
<input type="hidden" name="id" value="${board.id }">
<div class="form-group">
<label for="title" class="control-label col-xs-2">Title</label>
<div class="col-xs-10">
<input type="text" class="form-control" id="title" name="title" placeholder="Title" required
value="${board.title }">
</div>
</div>
<div class="form-group">
<label for="writer" class="control-label col-xs-2">Writer</label>
<div class="col-xs-10">
<input type="text" class="form-control" id="writer" name="writer" placeholder="Writer" required
value="${board.writer }" readonly="readonly">
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-2">Content</label>
<div class="col-xs-10">
<textarea class="form-control" rows="20" id="content" name="content" placeholder="Content" required>${board.content }</textarea>
</div>
</div>
<div class="form-group">
<label for="regDate" class="control-label col-xs-2">Date</label>
<div class="col-xs-10">
<input type="text" class="form-control" id="regDate" placeholder="Date" required
value="<fmt:formatDate pattern="yyyy-MM-dd hh:mm:ss" value="${board.regDate }" />" readonly="readonly">
</div>
</div>
<div class="form-group">
<div class="col-xs-offset-2 col-xs-10">
<a href="<c:url value='/boards'/>" class="btn btn-primary">List</a>
<button type="submit" class="btn btn-primary">Update</button>
</div>
</div>
</form>
</div>
</body>
</html>
n WEB-INF/views/board_view.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="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
.bs-example {
margin-bottom: 20px;
margin-left: 20px;
margin-right: 40px;
margin-top: 20px;
}
</style>
</head>
<body>
<c:import url="nav_top.jsp"></c:import>
<div class="bs-example">
<form class="form-horizontal" action="/examples/actions/confirmation.php" method="post">
<div class="form-group">
<label for="title" class="control-label col-xs-2">Title</label>
<div class="col-xs-10">
<input type="text" class="form-control" id="title" name="title" placeholder="Title" required
value="${board.title }" readonly="readonly">
</div>
</div>
<div class="form-group">
<label for="writer" class="control-label col-xs-2">Writer</label>
<div class="col-xs-10">
<input type="text" class="form-control" id="writer" name="writer" placeholder="Writer" required
value="${board.writer }" readonly="readonly">
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-2">Content</label>
<div class="col-xs-10">
<textarea class="form-control" rows="20" id="content" name="content" placeholder="Content" required
readonly="readonly">${board.content }</textarea>
</div>
</div>
<div class="form-group">
<label for="regDate" class="control-label col-xs-2">Date</label>
<div class="col-xs-10">
<input type="text" class="form-control" id="regDate" name="regDate" placeholder="Date" required
value="<fmt:formatDate pattern="yyyy-MM-dd hh:mm:ss" value="${board.regDate }" />" readonly="readonly">
</div>
</div>
<div class="form-group">
<div class="col-xs-offset-2 col-xs-10">
<a href="<c:url value='/boards'/>" class="btn btn-primary">List</a>
<c:if test="${not empty user }">
<c:if test="${user.email == board.writer }">
<a href="<c:url value='/boards/delete/${board.id }'/>" class="btn btn-primary">Delete</a>
<a href="<c:url value='/boards/update/${board.id }'/>" class="btn btn-primary">Update</a>
</c:if>
</c:if>
</div>
</div>
</form>
</div>
</body>
</html>
n WEB-INF/views/board_writer.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="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
.bs-example {
margin-bottom: 20px;
margin-left: 20px;
margin-right: 40px;
margin-top: 20px;
}
</style>
</head>
<body>
<c:import url="nav_top.jsp"></c:import>
<div class="bs-example">
<form class="form-horizontal" action="<c:url value='/boards/write'/>" method="post">
<div class="form-group">
<label for="title" class="control-label col-xs-2">Title</label>
<div class="col-xs-10">
<input type="text" class="form-control" id="title" name="title" placeholder="Title" required>
</div>
</div>
<div class="form-group">
<label for="writer" class="control-label col-xs-2">Writer</label>
<div class="col-xs-10">
<input type="text" class="form-control" id="writer" name="writer" placeholder="Writer" required
value="${user.email }" readonly="readonly">
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-2">Content</label>
<div class="col-xs-10">
<textarea class="form-control" rows="20" id="content" name="content" placeholder="Content" required></textarea>
</div>
</div>
<div class="form-group">
<div class="col-xs-offset-2 col-xs-10">
<a href="<c:url value='/boards'/>" class="btn btn-primary">List</a>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</form>
</div>
</body>
</html>
n WEB-INF/views/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"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Board</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
.bs-example {
margin: 20px;
}
.logo-small {
color: #f4511e;
font-size: 50px;
}
footer .glyphicon {
font-size: 20px;
margin-bottom: 20px;
color: #f4511e;
}
</style>
</head>
<body id="myPage">
<c:import url="nav_top.jsp"></c:import>
<br>
<br>
<br>
<div id="services" class="container-fluid text-center">
<h2>스프링MVC5, 마이바티스3.5, 오라클12 연동 게시판</h2>
<h4>Spring Framework5 + MyBatis3.5 + Oracle12</h4>
<br>
<div class="row slideanim">
<div class="col-sm-4">
<span class="glyphicon glyphicon-off logo-small"></span>
<h4>
<c:if test="${not empty user }">
<a href="logout">LOGOUT</a>
</c:if>
<c:if test="${empty user }">
<a href="login">LOGIN</a>
</c:if>
</h4>
<p>로그인</p>
</div>
<div class="col-sm-4">
<span class="glyphicon glyphicon-heart logo-small"></span>
<h4><a href="boards">BOARD</a></h4>
<p>스프링,마이바티스 게시판</p>
</div>
<div class="col-sm-4">
<span class="glyphicon glyphicon-lock logo-small"></span>
<h4>YOUR TURN</h4>
<p>Lorem ipsum dolor sit amet..</p>
</div>
</div>
</div>
<br>
<br>
<br>
<footer class="container-fluid text-center">
<a href="#myPage" title="To Top"><span class="glyphicon glyphicon-chevron-up"></span></a>
<p>Made By <a href="#" title="#">have a nice day!</a></p>
</footer>
</body>
n </html>WEB-INF/views/login.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>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Board</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Roboto:300);
.login-page {
width: 360px;
padding: 8% 0 0;
margin: auto;
}
.form {
position: relative;
z-index: 1;
background: #FFFFFF;
max-width: 360px;
margin: 0 auto 100px;
padding: 45px;
text-align: center;
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
}
.form input {
font-family: "Roboto", sans-serif;
outline: 0;
background: #f2f2f2;
width: 100%;
border: 0;
margin: 0 0 15px;
padding: 15px;
box-sizing: border-box;
font-size: 14px;
}
.form button {
font-family: "Roboto", sans-serif;
text-transform: uppercase;
outline: 0;
background: #4CAF50;
width: 100%;
border: 0;
padding: 15px;
color: #FFFFFF;
font-size: 14px;
-webkit-transition: all 0.3 ease;
transition: all 0.3 ease;
cursor: pointer;
}
.form button:hover, .form button:active, .form button:focus {
background: #43A047;
}
.form .message {
margin: 15px 0 0;
color: #b3b3b3;
font-size: 12px;
}
.form .message a {
color: #4CAF50;
text-decoration: none;
}
.form .register-form {
display: none;
}
.container {
position: relative;
z-index: 1;
max-width: 300px;
margin: 0 auto;
}
.container:before, .container:after {
content: "";
display: block;
clear: both;
}
.container .info {
margin: 50px auto;
text-align: center;
}
.container .info h1 {
margin: 0 0 15px;
padding: 0;
font-size: 36px;
font-weight: 300;
color: #1a1a1a;
}
.container .info span {
color: #4d4d4d;
font-size: 12px;
}
.container .info span a {
color: #000000;
text-decoration: none;
}
.container .info span .fa {
color: #EF3B3A;
}
</style>
<script type="text/javascript">
$(function() {
$('.message a').click(function() {
$('form').animate({height : "toggle", opacity : "toggle"}, "slow");
$('#result').css('display','none');
});
var result = "${result}";
if(result){
if(result === 'OK'){
$("#myModal").modal('show');
} else {
$('form').animate({height : "toggle", opacity : "toggle"}, "fast");
}
}
});
</script>
</head>
<body>
<c:import url="nav_top.jsp"></c:import>
<div class="login-page">
<div class="form">
<form class="register-form" action="<c:url value='/users/enroll'/>" method="post">
<input type="text" id="email" name="email" placeholder="Email" />
<input type="password" id="password" name="password" placeholder="Password" />
<button type="submit">create</button>
<p class="message">Already registered? <a href="#">Sign In</a></p>
</form>
<form class="login-form" action="<c:url value='/login'/>" method="post">
<input type="text" id="email" name="email" placeholder="Email" value="${login.email }"/>
<input type="password" id="password" name="password" placeholder="Password" />
<button type="submit">login</button>
<p class="message">Not registered? <a href="#">Create an account</a></p>
</form>
<c:if test="${not empty error }">
<br>
<span class="label label-danger" id="result">${error }</span>
</c:if>
</div>
</div>
<div id="myModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Completed Membership</h4>
</div>
<div class="modal-body">
<p>Your registration has been successfully completed.</p>
<p class="text-warning">
<small>Please click the OK button and try logging in.</small>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
</body>
</html>
n WEB-INF/view/nav_top.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="<c:url value='/'/>">Home</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="<c:url value='/boards'/>">Board</a></li>
<li><a href="#">Another action</a></li>
</ul>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<c:if test="${not empty user }">
<li><a href="#"><span class="badge">${user.email }</span></a></li>
</c:if>
<li class="${active=='login'?'active':'' }">
<c:if test="${not empty user }">
<a href="<c:url value='/logout'/>">Logout</a>
</c:if>
<c:if test="${empty user }">
<a href="<c:url value='/login'/>">Login</a>
</c:if>
</li>
<li class="${active=='board'?'active':'' }"><a href="<c:url value='/boards'/>">Board</a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container-fluid -->
</nav>
<script type="text/javascript">
// 화면이 갱신되면 효과를 잃어 버린다.
$('.nav li').click(function(e) {
$('.nav li').removeClass('active');
$(this).addClass('active');
});
</script>
댓글 없음:
댓글 쓰기