윈도우 환경에서 자바를 설치하는 방법을 체계적으로 알아본다.

 

혹시 컴퓨터에 자바가 설치되었는지 아닌지 확실하지 않다면 윈도우에서 cmd라고 쳐보자.

 

cmd 창에서 java -version이라고 치면 자바 버전이 나온다.


* 자바 설치 확인

위 메시지는 자바 JDK 1.8버전이 설치되어있다는 뜻입니다.

 

JAVA 8버전이 JDK1.8이고 JAVA 11버전이 JDK 11입니다.

 

JDK의 버전은 오래된 순으로 1.6, 1.7, 1.8, 9, 11, 12, 13, 14, 15 이런식으로 이어집니다.

 

* 자바C 설치 확인 (자바 컴파일러)

 

* 자바설치

아래 링크로 들어가던가, 아니면 구글에 jdk download를 검색한다.

www.oracle.com/kr/java/technologies/javase-downloads.html

 

위는 jdk SE 15버전인데 1.6~1.8버전도 거의 상관이 없다.

window64 installer를 클릭하여 설치해준다. 별도 로그인은 필요없다.

 

잘 설치가 되었다면 프로그램 폴더에 자바가 있을 것이다.

 

 

 

 

 

 

 

 

자바스크립트에서는 setTimeOut 메소드를 이용하여 일정 시간 뒤 로직을 실행시킬 수 있지만,

백단 자바에서는 timeTask를 써야한다.

 

예제는 아래와 같다.

ExampleTimer.java 파일을 만든 뒤 아래의 코드를 작성.

 

package com.timer.ex;

import java.util.Timer;
import java.util.TimerTask;
 
public class ExampleTimer {
 
    private Timer timer;
    
    //task 클래스 생성
    public class TaskToDo extends TimerTask {
        int count=0;
        
        @Override
        public void run() {
            System.out.println(count + "th " + "Task Done!");
            count += 1;
        }
    }
    /////////////////////
    
    
    //setTimer 메소드 선언
    public void setTimer(long delay, long period) {
        timer = new Timer();
        timer.schedule(new TaskToDo(), delay, period);
    }
    //////////////
    
    public static void main(String args[]) {
        
        ExampleTimer exampleTimer = new ExampleTimer();
        exampleTimer.setTimer(2000, 1000); //처음에 2초 뒤에 시작. 1초간격으로 실행
    }
}
 

 

setTimer가 (2000, 1000) 이므로 처음에 2초 있다가 시작하며 console에 초당 카운트가 되는것을 볼수 있다.

0th Task Done!
1th Task Done!
2th Task Done!
3th Task Done!
4th Task Done!
5th Task Done!

 

리스트 페이지가 보여지지만 현재 클릭했을 때 아무 것도 보이지 않는다.

 

클릭하면 제목, 내용, 작성자, 조회수 등이 뜨게끔 수정해보겠다.

 

수정 후 리스트 페이지는 이렇게 떠야 한다.

 

1.  컨트롤러작성

아래 코드를 BController.java에 삽입해 준다.

	@RequestMapping("/contentView")
	public String contentView(HttpServletRequest request, Model model) {
		
		System.out.println("-------- contentView() 호출 ----------");
		
		model.addAttribute("request", request);
		//HttpServletRequest로 전 전 페이지 정보를 가져와 request에 저장함.
		
		cmd = new ContentCmd(); //bbsCommand에 ContentCmd를 불러와 cmd에 저장
		
		cmd.service(model);//model 파라미터를 service메소드에 넣어서 동작
		
		return "contentView";
	}

 

2. list.jsp 파일 수정

위의 ContentCmd.java를 만들어 주기 전에 리스트 페이지를 수정한다.

 

테이블 안에서 내용을 보여주는 td태그 안의 내용만 수정한다.

<table border="1" cellpadding="0" cellspacing="0" width="500">
		<tr>
			<td>번호</td>
			<td>제목</td>
			<td>작성자</td>
			<td>날짜</td>
			<td>조회수</td>
		</tr>
				<!-- 게시글 목록 가져오기 -->
		<c:forEach items="${list}" var="vo">	
		<!-- ListCmd에서 만들었던 모델 list를 컨트롤러를 통해 받아온다.-->
		<tr>
			<td>${vo.bNo}</td>
			<!-- 제목을 클릭하면 페이지가 넘어가면서 번호 정보를 가져온다. -->
			<td><a href="contentView?bNo=${vo.bNo}">${vo.bSubject}</a></td>
			<td>${vo.bName}</td>
			<td>${vo.bDate}</td>
			<td>${vo.bHit}</td>
		</tr>
		</c:forEach>
		<tr>
			<td colspan="5" align="center"><a href="writeForm">글쓰기</a></td>
		</tr>
		
	</table>

 

3. Cmd 작성

bbsCommand 패키지에 ContentCmd.java 파일을 생성

 

그 뒤 아래의 코드를 입력

 

ContentCmd.java

package com.spring.bbsCommand;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.ui.Model;

import com.spring.bbsDAO.BDAO;
import com.spring.bbsVO.BVO;

public class ContentCmd implements Bcmd {

	@Override
	public void service(Model model) {
		//모델을 받아 맵형태로 바꿔줌.
		Map<String, Object> map = model.asMap();
		
		//1번글을 클릭하면 1번, 2번글을 클릭하면 2번을 전달받아야 함. 컨트롤러의 리퀘스트가 맵안에 있다. 이것을  HttpServletRequest로 저장
		HttpServletRequest request = (HttpServletRequest)map.get("request");
		
		String bNo = request.getParameter("bNo");
		
		//dao 불러오기
		BDAO dao = new BDAO();
		
		//조회수증가와 내용가져옴
		BVO bVo = dao.contentView(bNo);
		
		//모델에 추가
		model.addAttribute("contentView", bVo);
	}

}

 

4. BDAO에 contentView 추가

위에서 dao의 contentview() 메소드를 사용하였으므로 BDAO에 그 메소드를 정의해줘야한다.

 

BDAO.java에 contentView메소드를 추가

public BVO contentView(String bbsNo) {
	//return하는 bVo가 VO에서 가져온 것이므로 BVO를 타입으로 사용함
	//String bbsNo가 	bNo임
	
		//조회수 로직으로
		addHit(bbsNo);
		
		BVO bVo = null;
		
		//많이 보던 형식 커넥션, 프리페어드, 리절트셋.  데이타소스  >> 그뒤 sql
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		
		try {
			connection = dataSource.getConnection();
			
			String sql = "select * from mvc_bbs where bNo = ?";
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setInt(1, Integer.parseInt(bbsNo));
			resultSet = preparedStatement.executeQuery();
			
			if(resultSet.next()) {
				int bNo = resultSet.getInt("bNo");
				String bName = resultSet.getString("bName");
				String bSubject = resultSet.getString("bSubject");
				String bContent = resultSet.getString("bContent");
				Timestamp bDate = resultSet.getTimestamp("bDate");
				
				int bHit = resultSet.getInt("bHit");
				int bGroup = resultSet.getInt("bGroup");
				int bStep = resultSet.getInt("bStep");
				int bIndent = resultSet.getInt("bIndent");
				
				//값을 가져왔으니 bVo에
				
				bVo = new BVO(bNo, bName, bSubject, bContent, bDate, bHit, bGroup, bStep, bIndent);
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			//finally에 클로즈 처리
			
			try {
				if(resultSet != null) resultSet.close();
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close();
				
				
			} catch (Exception e2) {
				e2.printStackTrace();
			}
			
			
		}
		
		return bVo;
	}//contentView()

 

5. BDAO에 클릭하면 조회수가 증가 하는 메소드를 만든다.

 

BDAO.java에 아래 코드 입력

//조회수 늘어나는 로직
	private void addHit(String bNo) {
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		
		try {
			connection = dataSource.getConnection();
			String sql = "update mvc_bbs set bHit = bHit + 1 where bNo = ?";
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setString(1, bNo); //1은 첫번째 물음표 값을 입력
			
			int n = preparedStatement.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close();
				
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}//addHit()

 

6. contentView.jsp 생성

그 뒤 view폴더에 contentView.jsp를 만들어 아래코드를 입력

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>글내용 보기</title>
</head>
<body>
		<div align="center">
			<h2>글내용 확인</h2>
			<hr width="500" color="green" />
			<table width="500" cellpadding="0" cellspacing="0" border="1">
			<form action="" method="post">
			<tr>
				<td>번호</td>
				<td>${contentView.bNo}</td>
			</tr>
			<tr>
				<td>조회수</td>
				<td>${contentView.bHit}</td>
			</tr>
						<tr>
				<td>작성자</td>
				<td><input type="text" name="bName" value="${contentView.bName }"></td>
			</tr>
						<tr>
				<td>제목</td>
				<td><input type="text" name="bSubject" value="${contentView.bSubject}"></td>
			</tr>
						<tr>
				<td>내용</td>
				<td><textarea rows = "10" name="bContent">${contenctView.bContent}</textarea></td>
			</tr>
			<tr>
				<td colspan="2" align="center"><input type="submit" value="수정하기" />
								&nbsp;&nbsp;&nbsp;<a href="list">목록보기</a>
								&nbsp;&nbsp;&nbsp;<a href="#">삭제</a>
								&nbsp;&nbsp;&nbsp;<a href="#">답변</a>
				</td>
			</tr>
			
			
			</form>
			
			
			</table>
			
			
		</div>
		</body>
</html>

 

수정하기는 아직 만들지 않았다.

클릭하면 조회수가 1씩 증가하는 것을 볼 수 있다.

 

내용 보여주는 곳 까지 파일로 저장해놨으니 아래 참조

 

springBBS 내용보여주는 곳 까지.zip
0.06MB

스프링 프레임워크에서 myBatis사용하여 mySQL db연동하는 방법

 

결론적으로 아래와 같이 파일구성이 되야한다.

 

 

예제파일-----

 

jdbcTest2.zip
0.03MB

--------

 

그럼 차근차근 진행해본다.

 

 

1. src/main/resources에 파일 생성

 

1) mybatis-config.xml 파일 생성

 

아래 코드를 mybatis-config.xml에 넣는다.

 

이 파일을 생성하여야 log dependency를 넣었을 때 오류가 나지 않는다.

 

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>

</configuration>

 

2) log4jdbc.log4j2.properties 파일 생성

 

아래코드를 log4jdbc.log4j2.properties에 넣는다.

log4jdbc에 접속시켜주는 역할을 한다.

 

log4jdbc.log4j2.properties

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

 

3) logback.xml 생성

 

레벨을 설정해주는 파일이다.

 

아래코드를 logback.xml에 넣는다.

 

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>

    log4jdbc-log4j2
	<logger name="jdbc.sqlonly"        level="DEBUG"/>
    <logger name="jdbc.sqltiming"      level="INFO"/>
    <logger name="jdbc.audit"          level="WARN"/>
    <logger name="jdbc.resultset"      level="ERROR"/>
    <logger name="jdbc.resultsettable" level="ERROR"/>
    <logger name="jdbc.connection"     level="INFO"/>
</configuration>

 

아래와 같이 파일들이 생성된다.

2. dependency 주입

 

pom.xml에 스프링, jdbc, 로그 관련 의존성을 주입한다.

 

아래 코드를 pom.xml에 붙여넣기한다.

<!-- db 연결 관련 -->
		<!-- spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
			<!-- mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.38</version>
		</dependency>
			<!-- MyBatis 관련 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.3.1</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.2.5</version>
		</dependency>
				<!-- log 관련 -->
		<dependency>
			<groupId>org.bgee.log4jdbc-log4j2</groupId>
			<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
			<version>1.16</version>
		</dependency>	
        
        				<!-- sprint-test 관련-->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.2.5.RELEASE</version>
		</dependency>

 

그리고 <properties>태그안에 org.springframework-version을 4.2.3으로 변경시킨다.

	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>4.2.3.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>

 

 

3. VO와 DAO 생성

 

1) VO 생성

com.mysql.domain에 memberVO.java를 생성하여 아래 코드들을 넣는다.

 

MemberVO.java

package com.mysql.domain;

import java.sql.Date;

public class memberVO {

	String userid;
	String userpw;
	String username;
	String email;
	Date regdate;
	Date updatedate;
	
	public String getUserid() {
		return userid;
	}
	public void setUserid(String userid) {
		this.userid = userid;
	}
	public String getUserpw() {
		return userpw;
	}
	public void setUserpw(String userpw) {
		this.userpw = userpw;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public Date getRegdate() {
		return regdate;
	}
	public void setRegdate(Date regdate) {
		this.regdate = regdate;
	}
	public Date getUpdatedate() {
		return updatedate;
	}
	public void setUpdatedate(Date updatedate) {
		this.updatedate = updatedate;
	}
	@Override
	public String toString() {
		return "MemberVO [userid=" + userid + ", userpw=" + userpw + ", username=" + username + ", email=" + email
				+ ", regdate=" + regdate + ", updatedate=" + updatedate + "]";
	}
}

 

2) DAO 생성

 

DAO는 데이터베이스와 연결시켜주는 역할을 한다.

 

1) com.mysql.persistence에 memberDAO.java를 생성하여 아래 코드들을 넣는다.

 

MemberDAO.java

package com.mysql.persistence;

import com.mysql.domain.MemberVO;

// 타입만 명세
	public interface MemberDAO extends GenericDAO<MemberVO, String> {

	}// interface


 

2) com.mysql.persistence에 memberDAOImpl.java를 생성하여 아래 코드들을 넣는다.

 

MemberDAOImpl.java

package com.mysql.persistence;

import org.springframework.stereotype.Repository;
import com.mysql.domain.MemberVO;


@Repository
public class MemberDAOImpl extends GenericDAOImpl<MemberVO, String> implements MemberDAO {

}

 

3) com.mysql.persistence에 GenericDAO.java를 생성하여 아래 코드들을 넣는다.

 

GenericDAO.java

package com.mysql.persistence;

import java.util.List;

public interface GenericDAO<E, K> {

	public K getTime();
	public void register(E vo);
	public E get(K userid);
	public List<E> getList();
	// 아래는 등록, 조회 구현 이후에 할 것임..
	//public void update();
	//public void delete();
	
}// interface

 

4) com.mysql.persistence에 GenericDAOImpl.java를 생성하여 아래 코드들을 넣는다.

 

GenericDAOImpl.java

package com.mysql.persistence;


import java.util.List;
import javax.inject.Inject;
import org.apache.ibatis.session.SqlSession;

// GenericDAO 인터페이스의 추상클래스들을 오버라이딩 해주어야 한다.
// 즉, 여기서 DB와 연결을 하고 SQL문을 처리해주어야 하므로 sessionTemplate을 인스턴스 변수로 갖고서 
// 이를 통해 CRUD 작업을 처리해주면 된다.
public abstract class GenericDAOImpl<E, K> implements GenericDAO<E, K> {

	@Inject
	private SqlSession sqlSession;
	
	private static final String namespace = 
			"com.mysql.mapper.MemberMapper";
	
	@Override
	public K getTime() {
		return sqlSession.selectOne(namespace + ".getNow");
	}

	@Override
	public void register(E vo) {
		sqlSession.insert(namespace + ".register", vo);
	}

	@Override
	public E get(K userid) {
		return sqlSession.selectOne(namespace + ".get", userid);
	}

	@Override
	public List<E> getList() {
		return sqlSession.selectList(namespace + ".getList");
	}

}// class

 

5) com.mysql.persistence에 TimeDao.java를 생성하여 아래 코드들을 넣는다.

 

TimeDAO.java

package com.mysql.persistence;


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

import javax.inject.Inject;
import javax.sql.DataSource;

import org.springframework.stereotype.Repository;


@Repository
public class TimeDAO {

	@Inject
	private DataSource ds;
	
	
	public String getTime() throws Exception{
		
		Connection conn = ds.getConnection();
		PreparedStatement pstmt = conn.prepareStatement("select now()");
		
		ResultSet rs = pstmt.executeQuery();
		
		rs.next();
		return rs.getString(1);
		
	}// getTime()
	
	
}

 

4. root-context 코드 추가

 

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: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.2.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
		
		
	<!-- JDBC의 연결을 처리하는 기능을 가진 DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
		<property name="url" value="jdbc:log4jdbc:mysql://127.0.0.1:3306/book_ex"></property>
		<property name="username" value="zerock"></property>
		<property name="password" value="12351235"></property>
	</bean>

	<!-- SqlSessionFactoryBean 생성 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 		<!-- mybatis-config.xml 파일이 스프링이 동작할 때 같이 동작하도록 설정한 것. -->
		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
		<property name="dataSource" ref="dataSource"></property>
		<property name="mapperLocations" value="classpath:mappers/**/*.xml"></property>
	</bean>

	<!-- sqlSession 을 SqlSessionTemplate으로 만든다. -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory" />
	</bean>


	<!-- 스프링이 관리하는 패키지에 com.mysql.persistence 를 추가한다. -->
	<context:component-scan base-package="com.mysql.persistence" />
	
</beans>

 

5. mapper 추가

 

resources에 mappers라는 패키지를 추가한 뒤에 memberMapper.xml 파일을 만든다.

 

그 뒤 아래 코드를 붙여넣는다.

 

memberMapper.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="com.mysql.mapper.MemberMapper">

	<!-- 이거에 접근할 때 namespace.id 로 접근한다. -->
	<!-- resultType은 자바의 타입과 매핑되는 것이 있다. 여기선 string이 java.lang.String과 매핑 -->
	<select id="getNow" resultType="string">
		select now()   <!-- 세미콜론 쓰면 안됨 -->
	</select>
	
	<insert id="register">
		insert into tbl_member(userid, userpw, username, email)
		values( #{userid} , #{userpw}, #{username}, #{email} );
	</insert>
	
	<!-- 
			XML Mapper를 작성할 때 매번 resultType을 패키지까지 포함된 클래스명을 작성하는 일이 번거롭다면
			MyBatis의 설정 파일인 mybatis-config.xml을 사용해서 다음과 같이 <typeAliases>를 작성하면된다.
			<typeAliases>
				<package name = "org.zerock.domain"/>
			</typeAliases>		
	-->
	<select id="get" resultType="com.mysql.domain.MemberVO">
		select *
		from tbl_member
		where userid = #{userid}
	
	</select>
	
	<select id="getList" resultType="com.mysql.domain.MemberVO">
		select *
		from tbl_member;
	</select>
</mapper>

 

 

6. src/test/java 폴더의 controller 패키지에 자바파일들 추가

 

AbstractTest.java

package com.mysql.controller;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/* 모든 테스트 파일이 상속할 추상클래스
 * - 어노테이션 자동 추가
 * - Logger 
 * */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
public abstract class AbstractTest {

	protected static final Logger logger = 
			LoggerFactory.getLogger(AbstractTest.class);

}

 

ApplicationContextTest.java

package com.mysql.controller;
/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */

import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public class ApplictationContextTest extends AbstractTest{

	@Inject
	private ApplicationContext ctxt;
	
	
	@Test
	public void test() {
		logger.info(""+ctxt);
		
	}// test()

}// class

 

DataSourceConnectionTest.java

/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */
package com.mysql.controller;

import static org.junit.Assert.fail;

import java.sql.SQLException;

import javax.inject.Inject;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public class DataSourceConnectionTest extends AbstractTest{
	
	@Inject
	private DataSource ds;
	
	@Test
	public void test() throws SQLException {
		logger.info(""+ds.getConnection());
	}// test()

}// class

 

MemberDAOImplTest.java

/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */
package com.mysql.controller;

import javax.inject.Inject;

import org.junit.Test;
import com.mysql.domain.MemberVO;
import com.mysql.persistence.MemberDAO;

public class MemberDAOImplTest extends AbstractTest{

	@Inject
	private MemberDAO dao;
	
	@Test
	public void test() {
		logger.info(""+dao);
	}
	
	@Test
	public void getTimeTest() {
		logger.info(""+dao.getTime());
	}
	
	@Test
	public void registerTest(){
		MemberVO vo = new MemberVO();
		vo.setUserid("fff");
		vo.setUserpw("cccc");
		vo.setUsername("ejg");
		vo.setEmail("ej@g.com");
		
		// DB에 넣고 DB테이블에서 직접 확인해봐야 한다.
		dao.register(vo);
	}
	
//	@Test
//	public void getTest(){
//		logger.info(""+dao.get("wjheoid"));
//	}
//	
//	@Test
//	public void getListTest(){
//		logger.info(""+dao.getList());
//	}
	
}// class

 

SqlSessionFactoryBeanTest.java

/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */
package com.mysql.controller;

import javax.inject.Inject;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public class SqlSessionFactoryBeanTest extends AbstractTest{

	@Inject
	SqlSessionFactoryBean factoryBean;
	
	@Test
	public void test(){
		logger.info(""+factoryBean);
	}// test()
	
	@Test
	public void sesseionTest(){
		try {
			logger.info(""+factoryBean.getObject().openSession().toString());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}// test()
	
}// class

 

TimeDAOTest.java

package com.mysql.controller;
/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */

import static org.junit.Assert.fail;

import javax.inject.Inject;

import org.junit.Test;
import com.mysql.persistence.TimeDAO;

public class TimeDAOTest extends AbstractTest{

	@Inject
	private TimeDAO dao;
	
	@Test
	public void test() throws Exception {
		logger.info(""+dao.getTime());
		
	}// test()
}// class

 

아래와 같이 파일들이 구성되어야 함

 

이후 MemberDAOImplTest에서 테스트를 하면 db에 값이 저장됨

 

위에 값들은 vo를 참조하여 만들면 된다.

앞서 작성했던 게시판 페이지이다.

 

이번 포스팅에서 구현할 기능은 아래와 같다.

 

1. 글쓰기를 누르면 글쓰기 페이지로 넘어감

2. 글쓰기 페이지에서 제목과 내용 등을 입력하여 submit해주면 db에 입력이 됨

3. 리스트 페이지로 리다이렉트로 되어 업데이트된 페이지를 보여줌

 

1. 글쓰기 JSP파일 만들기

 

list.jsp와 같은 경로에 writeForm.jsp를 만들어 아래와 같이 코딩을 해준다.

 

writeForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<div align="center">
	<h2>글쓰기 페이지</h2>
	<hr width="500" />
	<table width="500" cellpadding="0" cellspacing="0" border="1">
		<form:form commandName="_BVO" action="writeOK" method="post">
			<tr>
				<td>작성자</td>
				<td><form:input path="bName" size="20" /></td>
			</tr>
			<tr>
				<td>제목</td>
				<td><form:input path="bSubject" size="50" /></td>
			</tr>
			<tr>
				<td>내용</td>
				<td><form:textarea path="bContent" cols="60" rows="8" /></td>
			</tr>
			<tr>
				<td colspan="2" align="center"><input type="submit" value="등록" /></td>
			</tr>
		</form:form>
	
	</table>
</div>

</body>
</html>

아까는 prefix="c"를 사용하였지만 여기에서는 태그라이브러리 prefix="form"을 사용하였다. 

 

<form:form> 태그안에 commandName은 modelAttribute로 바꾸어 사용해도 된다. 컨트롤러에서 BVO()를 리턴하게끔 모델을 정해주는 역할이다.

 

그리고 action은 어떤 url로 이동할지 정해주고, 이를 컨트롤러에서 받아와서 처리해준다.

method는 post이다.

 

그리고 <form:input>태그안에는 path 구문을 넣어 입력값이 어떤 객체로 들어갈 것인지 정해준다.

 

2. VO 작성

VO는 한번 작성하면 db의 항목이 변동되지 않는 이상 바꾸는 경우는 잘 없다.

아까 변수 선언 구문 아래에 주석 처리 되있었던  public BVO() { }만 주석을 해제해준다.

 

3. Controller 작성

여기서 작성해야 될 것은 2가지 메소드이다.

하나는 글쓰기 작성 jsp파일로 이동시키는 writeForm() 메소드이고, 하나는 글쓰기 form을 submit했을 때 처리되게끔 하는 writeOk()메소드이다.

 

구문에 대한 상세설명은 주석에 적어 놓았다.

 

Bcontroller.java

package com.spring.bbsController;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import com.spring.bbsCommand.Bcmd;
import com.spring.bbsCommand.ListCmd;
import com.spring.bbsCommand.WriteCmd;
//import com.spring.bbsCommand.WriteCmd;
import com.spring.bbsVO.BVO;

@Controller
public class BController {
	Bcmd cmd = null; //Bcmd 인터페이스를 불러와서 cmd에 저장해준다.

	
	@RequestMapping("/list")
	public String list(Model model) {
		//String으로 list 메소드를 생성했으니 리턴값도 String이다. RequestMapping의 아래는 대부분 String메소드이다.
		//파라미터형태로 모델 생성
		//모델의 역할은 뷰에게 데이터를 전달하기 위한 객체
		//여기서는 모델활용안하고 Bcmd.class에서 모델을 활용함.
		
		System.out.println("------------------list() 호출-------------");//에러날때를 대비해서 써줌
		//Model은 뷰에 데이터를 전달하기 위한 방법
		cmd = new ListCmd(); 	//Bcmd 인터페이스를 가져온 녀석에다 ListCmd()를 넣어줌
		//위에서 Bcmd cmd = null;을 안해주고 곧바로 이것을 해줘도 되지만 의존성을 낮추기 위해서 이렇게 해줌
		
		cmd.service(model);	//모델을 인자로 넘겨줌. 서비스를 시행
		
		return "list";
	}
	
	
	@RequestMapping("/writeForm")
	public String writeForm(Model model) {
		System.out.println("----------writeForm() 호출----------");
		
		return "writeForm";
	}
//	
//	//write폼 >>BController >> WriteCmd로 전달
	@RequestMapping("/writeOK")
	public String writeOk(HttpServletRequest request, Model model) {
		//데이터를 컨트롤러로 보냈을때, HttpServletRequest 객체안에 모든 데이터들이 들어가게 된다. 출처: https://hongku.tistory.com/118
		//String id = httpServletRequest.getParameter("id"); <<id를 불러옴
		
		System.out.println("----------writeOk() 호출-------------");
		
		model.addAttribute("request_ctrl", request); //이 request값에 formWrite에서 적었던 내용이 들어있음
		
		//서비스객체 불러옴
		cmd = new WriteCmd();
		cmd.service(model);
		
		return "redirect:list"; //등록한글을 리스트로 보여줌
	}
	
	//commandName="_BVO"와 관계 있음
	@ModelAttribute("_BVO") 
	public BVO formBacking() {
		
		return new BVO(); //BVO 안에 빈메소드로 연결됨
	}
}

 

/writeOK 리퀘스트 매핑에서는 HttpServletRequest라는 객체가 새로 생겼다.

 

그 이유는 /writeOK는 페이지를 보여주는 것이 아닌 form에서 submit된 데이터를 처리하는 용도이기 때문이다.

 

writeForm.jsp에서 submit하면 맨 끝 주소가 /writeForm에서 /writeOk로 주소가 변경되며, 컨트롤러에선 이를 받아온다.

이 때, 데이터들이 HttpServletRequest의 request안에 저장된다.

 

이 저장된 정보들을 꺼내오면 되는 것이다.

 

컨트롤러에서는 modelAttribute까지만 해주고, 데이터 저장 작업은 Service 클래스에서 해준다.

 

4. Service 작성

request에 모델 형태로 저장되었지만 이를 맵형태(키, 밸류)로 저장해준다.

 

위에서 모델을 잡아줄 때 왜 request_ctrl로 명했냐면, 그냥 request라고 할 경우 이것이 어디서 왔는지 헷갈린다.

 

실무에서야 그냥 쓰면 된다지만, 배우는 사람 입장에서는 이것이 어디서 왔는지 명확히 짚고 넘어가는 것이 중요하다.

 

블로그나 책에 req라고 나왔다고 그대로 req라고 쓰고 con이라고 나왔다고 con이라고 쓰는 것이 아니라 이것이 무엇을 의미하고 어느 클래스에서 왔는지, 또 내가 지정한 임의의 이름으로 넣었을 때 실행되는지 실험하면서 진행해가는 것이 실력향상에 도움이 된다.

 

WriteCmd.java

package com.spring.bbsCommand;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.ui.Model;

import com.spring.bbsDAO.BDAO;

public class WriteCmd implements Bcmd {

	@Override
	public void service(Model model) {
		
		System.out.println("model: "+model);
		//모델의 정보 model: {_BVO=com.spring.bbsVO.BVO@788ca69c, request_ctrl=org.apache.catalina.connector.RequestFacade@764b47fd}
		//아까 컨트롤러에서 정의해줬던 모델명 request_ctrl를 그대로 가져오는 것을 볼수 있다.
		
		Map<String, Object> map = model.asMap(); //모델객체를 맵으로 받음. 해쉬맵을 사용해도 무방
		//_BVO
		
		HttpServletRequest request = (HttpServletRequest)map.get("request_ctrl");		
		//map에 저장된 request_ctrl의 밸류값을 request에 저장
		//request_ctrl은 컨트롤러에서 모델어트리뷰트 해준 것임
		
		
		String bName = request.getParameter("bName");
		String bSubject = request.getParameter("bSubject");
		String bContent = request.getParameter("bContent");
		
		//db접속
		BDAO dao = new BDAO();
		dao.write(bName, bSubject, bContent);
	}
}

 

request에서 getParameter로 값을 가져와서 원하는 객체에 저장해준다.

 

그 다음 DAO클래스에서 write()메소드를 작성해준다.

 

5. DAO 작성

 

굳이 Controller > Service > DAO 순서대로 작성안하고 취향대로 작성해도 된다.

 

리스트 페이지를 만들 때는 DAO > Service > Controller 순으로 작성했지만 이번에는 반대로 한 이유는 어떤 순서로 보는 것이 이해하기 쉽고 내가 코드를 직접 작성할 때 좀 편할지 간접적으로 체험하라는 뜻도 있다.

 

점진적 구체화라는 용어가 있듯이 대개의 경우에는 VO > Controller > Service > DAO 순서가 편하다.

 

그럼 다시 돌아와서 write()메소드를 작성해본다.

 

윗코드내용은 아까 작성했던 부분이므로 write()메소드 시작부터 보면된다.

 

BDAO.java

package com.spring.bbsDAO;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;

//import javax.activation.DataSource; 액티베이션 아님
import javax.naming.Context; //JNDI
import javax.naming.InitialContext; //JNDI
import javax.naming.NamingException; //JNDI
import javax.sql.DataSource;

import com.spring.bbsVO.BVO;

public class BDAO {
	DataSource dataSource; //데이타소스를 가져오는 구문
	
	//생성자
	public BDAO() {
		//JNDI 를 사용한다. JNDI란 자바에서 객체를 네이밍 서비스에 등록, 삭제, 검색을 할 수 있는 방법
		
		try{
			
			Context ctx = new InitialContext(); //JNDI 네이밍 서비스 컴파일해줌
			dataSource = (DataSource)ctx.lookup("java:comp/env/jdbc/Oracle11g");
			//lookup으로 데이타소스의 객체를 얻어온다. java:comp/env/는 기본이며 그뒤의 이름은 톰캣서버 context.xml의 name을 참조한다.
			
	} catch(NamingException e) {
		e.printStackTrace();
	}
		
}
	//리스트 보여주기 위한 메소드 list()
	public ArrayList<BVO> list() {
		//DB에 있는 글목록들을 가져오는 역할 형식은 ArrayList이고 BVO타입. 칼럼정보가 BVO에 있다.
		
		ArrayList<BVO> bVOs = new ArrayList<BVO>(); //ArrayList형태의 bVOs 객체 생성
		
		//////연결을 위한 3구문/////
		Connection connection = null; //커넥션 javax
		PreparedStatement preparedStatement = null; //프리패어드 스테이트먼트 javax		
		ResultSet resultSet = null;  //데이터를 가져오는 기능의 리절트셋 javax
		//////////////
		
		
		try {
		connection = dataSource.getConnection();
		
		
		
		//쿼리문을 만들어줌
		String sql = "select bNo, bName, bSubject, bContent, bDate, bHit, bGroup, bStep, bIndent from mvc_bbs"
					+ " order by bGroup desc, bStep asc";
		
		
		preparedStatement = connection.prepareStatement(sql); //preparedStatement에 전송
		
		resultSet = preparedStatement.executeQuery(); //result값 데이터를 가져오는 것
		
		while(resultSet.next()) {
			//Resultset 다음행에 데이터가 있으면 while 문으로 반복 작업을 함		
			
			//vo의 9인자를 참조해서 작성
			int bNo = resultSet.getInt("bNo");
			String bName = resultSet.getString("bName");
			String bSubject = resultSet.getString("bSubject");
			String bContent = resultSet.getString("bContent");
			Timestamp bDate = resultSet.getTimestamp("bDate");
			
			int bHit = resultSet.getInt("bHit");
			int bGroup = resultSet.getInt("bgroup");
			int bStep = resultSet.getInt("bStep");
			int bIndent = resultSet.getInt("bIndent");
			///////
			
			//인자생성자
			BVO bVO = new BVO(bNo, bName, bSubject, bContent, bDate, bHit, bGroup, bStep, bIndent);
			
			bVOs.add(bVO); //bVOs라는 어레이에 bVO 추가함
		}
		

		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			
			//finally 안에 있는 구문
			try {
				//null이면 구문들을 다 안쓰는 것
				if(resultSet !=null) {resultSet.close();}
				if(preparedStatement != null) {preparedStatement.close();}
				if(connection != null) {connection.close();}
				
			} catch (Exception e2) {	
				e2.printStackTrace();
			}
	
		}
		
		return bVOs;	
	}//list() 메소드 종료
	
	
	
	//write() 메소드 시작
	public void write(String bName, String bSubject, String bContent) {
		//글쓴이, 글제목, 글내용을 인자로 써줌.
		
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		
		try {
			connection = dataSource.getConnection();
			System.out.println("---------Connection 확보 -----------");
			
			String sql = "insert into mvc_bbs(bNo, bName, bSubject, bContent, bHit, bGroup, bStep, bIndent) " 
			+ "values(seq_bbs.nextval, ?, ?, ?,0,seq_bbs.currval,0,0)";
			//? 밸류는 사용자가 넣어줘야 될 것임. ?가 아닌 다른것을 쓰면 작동이 안된다. 공란도 안된다.
			
			preparedStatement = connection.prepareStatement(sql);
			
			preparedStatement.setString(1, bName); //첫번째 들어갈값 bName
			preparedStatement.setString(2, bSubject); //두번째 들어갈값 bSubject
			preparedStatement.setString(3, bContent); //세번째 들어갈값 bContent
			
			int n = preparedStatement.executeUpdate(); //select문은 executeQuery(), Update문은 executeUpdate()
			//변수n이 아닌 아무거나 써도 된다.
            
		} catch(SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if(preparedStatement != null) {preparedStatement.close();}
				if(connection != null) {connection.close();}
				
			} catch(Exception e2) {
				e2.printStackTrace();
			}	
		}
		
	}//write
	
}

 

그럼 이제 글작성 기능이 끝났다.

 

부가적으로 회원가입기능, 글에 비번넣기 기능도 추가할 수 있지만 우선은 CRUD 기본만 하도록 한다.

 

여기까지 실습한 내용은 첨부파일에 올려놓았다.

CRUD(글작성 까지).zip
0.03MB

아래는 서버폴더의 context.xml과 server.xml파일

서버와 콘텍스트 파일.zip
0.00MB

 

이번에는 db를 불러와서 리스트로 보여주기 위해 필요한 과정이다.

아래와 같은 파일들을 만들어 주어야한다. (WriteCmd.java 제외)

 

1. VO 클래스 만들기

Value Object로 가장 기초가 되는 객체들을 정의 해놓는 클래스이다.

SQL문에서 지정해놓았던 것들과 이름을 같게 해준다.

 

BVO.java

package com.spring.bbsVO;

import java.sql.Timestamp;

public class BVO {
	
	//db에서의 인덱스를 변수로 지정해준다. 각자의 형식에 맞춰서 형식을 지정해준다.
	//VO클래스는 변수선언, 인자생성자, setter getter 이렇게 3개로 나뉜다.
	
	//1.변수 선언
	int bNo;
	String bName;
	String bSubject;
	String bContent;
	Timestamp bDate;  //timestamp는 sql에서 불러오면됨
	int bHit;
	int bGroup;
	int bStep;
	int bIndent;
	
//	public BVO() {
//		
//	}
	
	
	//2.인자생성자
	public BVO(int bNo, String bName, String bSubject, String bContent, Timestamp bDate, int bHit, int bGroup, int bStep, int bIndent) {
		this.bNo = bNo;
		this.bName = bName;
		this.bSubject = bSubject;
		this.bContent = bContent;
		this.bDate = bDate;
		this.bHit = bHit;
		this.bGroup = bGroup;
		this.bStep = bStep;
		this.bIndent = bIndent;
	}
	
	
	//3.setter getter
	public int getbNo() {
		return bNo;
	}

	public void setbNo(int bNo) {
		this.bNo = bNo;
	}

	public String getbName() {
		return bName;
	}

	public void setbName(String bName) {
		this.bName = bName;
	}

	public String getbSubject() {
		return bSubject;
	}

	public void setbSubject(String bSubject) {
		this.bSubject = bSubject;
	}

	public String getbContent() {
		return bContent;
	}

	public void setbContent(String bContent) {
		this.bContent = bContent;
	}

	public Timestamp getbDate() {
		return bDate;
	}

	public void setbDate(Timestamp bDate) {
		this.bDate = bDate;
	}

	public int getbHit() {
		return bHit;
	}

	public void setbHit(int bHit) {
		this.bHit = bHit;
	}

	public int getbGroup() {
		return bGroup;
	}

	public void setbGroup(int bGroup) {
		this.bGroup = bGroup;
	}

	public int getbStep() {
		return bStep;
	}

	public void setbStep(int bStep) {
		this.bStep = bStep;
	}

	public int getbIndent() {
		return bIndent;
	}

	public void setbIndent(int bIndent) {
		this.bIndent = bIndent;
	}
	
}

 

2. DAO 클래스 만들기

DAO는 Database access object의 약자로 말그대로 SQL에 접근시켜주는 역할을 맡는다.

쿼리문도 여기다 작성한다.

 

많은 방법이 있지만 JNDI 네이밍 서비스를 활용하여 오라클을 LOOKUP해주는 것으로 시작한다.

 

BDAO.java

package com.spring.bbsDAO;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;

//import javax.activation.DataSource; 액티베이션 아님
import javax.naming.Context; //JNDI
import javax.naming.InitialContext; //JNDI
import javax.naming.NamingException; //JNDI
import javax.sql.DataSource;

import com.spring.bbsVO.BVO;

public class BDAO {
	DataSource dataSource; //데이타소스를 가져오는 구문
	
	//생성자
	public BDAO() {
		//JNDI 를 사용한다. JNDI란 자바에서 객체를 네이밍 서비스에 등록, 삭제, 검색을 할 수 있는 방법
		
		try{
			
			Context ctx = new InitialContext(); //JNDI 네이밍 서비스 컴파일해줌
			dataSource = (DataSource)ctx.lookup("java:comp/env/jdbc/Oracle11g");
			//lookup으로 데이타소스의 객체를 얻어온다. java:comp/env/는 기본이며 그뒤의 이름은 톰캣서버 context.xml의 name을 참조한다.
			
	} catch(NamingException e) {
		e.printStackTrace();
	}
		
}
	//리스트 보여주기 위한 메소드 list()
	public ArrayList<BVO> list() {
		//DB에 있는 글목록들을 가져오는 역할 형식은 ArrayList이고 BVO타입. 칼럼정보가 BVO에 있다.
		
		ArrayList<BVO> bVOs = new ArrayList<BVO>(); //ArrayList형태의 bVOs 객체 생성
		
		//////연결을 위한 3구문/////
		Connection connection = null; //커넥션 javax
		PreparedStatement preparedStatement = null; //프리패어드 스테이트먼트 javax		
		ResultSet resultSet = null;  //데이터를 가져오는 기능의 리절트셋 javax
		//////////////
		
		
		try {
		connection = dataSource.getConnection();
		
		//쿼리문을 만들어줌
		String sql = "select bNo, bName, bSubject, bContent, bDate, bHit, bGroup, bStep, bIndent from mvc_bbs"
					+ " order by bGroup desc, bStep asc";
		
		preparedStatement = connection.prepareStatement(sql); //preparedStatement에 전송
		
		resultSet = preparedStatement.executeQuery(); //result값 데이터를 가져오는 것
		
		while(resultSet.next()) {
			//Resultset 다음행에 데이터가 있으면 while 문으로 반복 작업을 함		
			
			//vo의 9인자를 참조해서 작성
			int bNo = resultSet.getInt("bNo");
			String bName = resultSet.getString("bName");
			String bSubject = resultSet.getString("bSubject");
			String bContent = resultSet.getString("bContent");
			Timestamp bDate = resultSet.getTimestamp("bDate");
			
			int bHit = resultSet.getInt("bHit");
			int bGroup = resultSet.getInt("bgroup");
			int bStep = resultSet.getInt("bStep");
			int bIndent = resultSet.getInt("bIndent");
			///////
			
			//인자생성자
			BVO bVO = new BVO(bNo, bName, bSubject, bContent, bDate, bHit, bGroup, bStep, bIndent);
			
			bVOs.add(bVO); //bVOs라는 어레이에 bVO 추가함
		}
				
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			
			//finally 안에 있는 구문
			try {
				//null이면 구문들을 다 안쓰는 것
				if(resultSet !=null) resultSet.close();
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close();
				
			} catch (Exception e2) {	
				e2.printStackTrace();
			}
	
		}
		
		return bVOs;	
	}//list() 메소드 중료
}

 

3. service 클래스 만들기

여기서는 cmd라고 한다. 인터페이스 형태로 만들어져 컨트롤러에서 service 클래스를 호출하게 된다.

(클라이언트 > 디스패처 > 컨트롤러 > service 클래스 순으로 요청이 된다.)

 

우선 com.spring.bbsCommand 패키지 안에 Bcmd라는 인터페이스를 만든다.

 

Bcmd.java  (인터페이스 형식)

package com.spring.bbsCommand;

import org.springframework.ui.Model;

//데이터를 가져오는 역할
public interface Bcmd {
	void service(Model model);
	//파라미터를 생성하는 방법 또는 리턴타입을 생성하는 경우가 있음
}

 

 

컨트롤러에서 Model을 불러옴. 위에 것은 인터페이스이기에 Overriding 해줘야함.

 

모델을 불러오는 방법에는 두가지가 있다.

1. 파라미터 이용

2. 리턴타입 이용

위는 파라미터 형태로 불러왔다.

 

그리고 실제로 db를 받아서 저장하는 ListCmd.java를 com.spring.bbsCommand 패키지 안에 만든다.

 

ListCmd.java

package com.spring.bbsCommand;

import java.util.ArrayList;

import org.springframework.ui.Model;

import com.spring.bbsDAO.BDAO;
import com.spring.bbsVO.BVO;

//이 객체의 목적: 데이터베이스를 받아 모델로 만들어줌

public class ListCmd implements Bcmd {
	//Bcmd 인터페이스를 가져와서 오버라이드함.
	//이 객체를 만들고 컨트롤러에서 활용하면 됨
	

	@Override
	public void service(Model model) {
		
		BDAO dao =new BDAO(); //BDAO.class를 불러온 dao 변수 생성
		
		ArrayList<BVO> bVOs = dao.list();  //dao의 list를 bVOs에 저장함
		
		//model.addAttribute("test01", "컨트롤러에서 받아오는지 테스트하는 용도");
		
		model.addAttribute("list", bVOs); //list 변수에 bvos 추가, 이 "list"는 return 값을 할 수 있음
		//JSP에서 ${list}를 입력하면 bVOs를 가져옴. 컨트롤러에 cmd.service(model)이  이 모델을 가져오기 때문

	}

}

 

 

4. Controller 만들기

 

컨트롤러는 페이지 매핑을 주로 담당한다. 

아래와 같이 Bcontroller.java를 생성한다.

 

주저리 주저리 말안하고 자세한 것은 아래 코드 주석으로 설명한다.

 

Bcontroller.java

package com.spring.bbsController;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import com.spring.bbsCommand.Bcmd;
import com.spring.bbsCommand.ListCmd;
//import com.spring.bbsCommand.WriteCmd;
import com.spring.bbsVO.BVO;

@Controller
public class BController {
	Bcmd cmd = null; //Bcmd 인터페이스를 불러와서 cmd에 저장해준다.

	
	@RequestMapping("/list")
	public String list(Model model) {
		//String으로 list 메소드를 생성했으니 리턴값도 String이다. RequestMapping의 아래는 대부분 String메소드이다.
		//파라미터형태로 모델 생성
		//모델의 역할은 뷰에게 데이터를 전달하기 위한 객체
		//여기서는 모델활용안하고 Bcmd.class에서 모델을 활용함.
		
		System.out.println("------------------list() 호출-------------");//에러날때를 대비해서 써줌
		//Model은 뷰에 데이터를 전달하기 위한 방법
		cmd = new ListCmd(); 	//Bcmd 인터페이스를 가져온 녀석에다 ListCmd()를 넣어줌
		//위에서 Bcmd cmd = null;을 안해주고 곧바로 이것을 해줘도 되지만 의존성을 낮추기 위해서 이렇게 해줌
		
		cmd.service(model);	//모델을 인자로 넘겨줌. 서비스를 시행
		
		return "list";
	}
}

 

5. view 페이지 만들기

앞 컨트롤러에서 list로 리턴을 해주었으니 파일명을 list.jsp를 만들어 준다.

viewResolver 설정을 확장자가 저절로 생기게끔 했기 때문에 "list"만 적어주면된다.

 

프론트로 보여주는 것은 태그라이브러리를 사용한다.

 

list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <% request.setCharacterEncoding("utf-8"); %>
<%@ taglib prefix = "c" uri="http://java.sun.com/jsp/jstl/core" %>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" http-equiv="Content-Type" content="text/html;">
<title>게시판 리스트</title>
</head>
<body>
<div align="center">
	<h2>게시판 글목록</h2>
	<hr width="400" color="red" />
	
	<table border="1" cellpadding="0" cellspacing="0" width="500">
		<tr>
			<td>번호</td>
			<td>제목</td>
			<td>작성자</td>
			<td>날짜</td>
			<td>조회수</td>
		</tr>
				<!-- 게시글 목록 가져오기 -->
		<c:forEach items="${list}" var="vo">	
		<!-- ListCmd에서 만들었던 모델 list를 컨트롤러를 통해 받아온다.-->
		<tr>
			<td>${vo.bNo}</td>
			<td>${vo.bSubject}</td>
			<td>${vo.bName}</td>
			<td>${vo.bDate}</td>
			<td>${vo.bHit}</td>
		</tr>
		</c:forEach>
		<tr>
			<td colspan="5" align="center"><a href="writeForm">글쓰기</a></td>
		</tr>
		
	</table>

</div>
<div>
</div>

</body>
</html>

 

 

실행 결과

톰캣을 가동한 뒤 localhost:8080/list를 들어가보면 아래와 같이 뜸을 확인할 수 있다.

값은 미리 sql문을 통해서 넣은 것이다.

 

localhost:8080/list

노캐쉬 설정을 안하면 컴퓨터를 껐다 킬때마다 시쿼스가 20씩 증가해서 번호가 이상해지는데 그것을 방지하기 위해 아까 시퀀스를 만들때 nocache 구문을 넣어준 것이다.

 

"ALTER SEQUENCE seq_bbs nocache"로도 캐쉬미사용 설정을 할 수 있다.

 

아직 글쓰기 부분은 코딩하지 않았으니 글쓰기를 누르면 실행안되는 것이 맞다.

 

글쓰기 기능 작성으로 넘어가기전에 다음 포스팅에서는 어떻게 해서 리스트를 보여주는지 절차를 한번 짚고 넘어가도록한다.

 

저게 단순해서 몇번 반복하면 알아 들을것 같지만 세세하게 복기를 안하면 알기 힘들다.

※ 자주 쓰이는 어노테이션

 

@ModelAttribute

- view에서 전달해주는 파라미터를 클래스(VO/DTO)의 멤버 변수로 binding 해주는 애노테이션

바인딩 기준은 <input name="id" /> 처럼 어떤 태그의 name값이 해당 클래스의 멤버 변수명과 일치해야하고 set메서드명도 일치해야한다.

 

ex)

class Person{

String id;

public void setId(String id){ this.id = id;}

}

 

 

@RequestMapping

- URL을 컨트롤러의 메서드와 매핑할 때 사용하는 스프링 프레임워크의 어노테이션이다.

클래스나 메서드 선언부에 @RequestMapping과 함께 URL을 명시하여 사용한다. URL외에도 HTTP 요청 메서드나 헤더값에 따라 매핑되도록 -0=옵션을 제공한다. 메서드 레벨에서 정의한 @RequestMapping은 타입 레벨에서 정의된 @RequestMapping의 옵션을 상속받는다.

 

참고로, 메서드 내에서 viewName을 별도로 설정하지 않으면 @RequestMapping의 path로 설정한 URL이 그대로 viewName으로 설정된다.

 

 

@Configuration

- Configuration을 클래스에 적용하고 @Bean을 해당 클래스의 메소드에 적용하면 @Autowired로 빈을 부를 수 있다.

 

 

@Resource

- @Autowired와 마찬가지로 빈 객체를 주입해주는데 차이점은 Autowired는 타입으로, Resource는 이름으로 연결해준다.

 

@Controller

- spring MVC의 Controller 클래스 선언을 단순화시켜준다. 스프링 컨트롤러, 서블릿을 상속할 필요가 없으며,   @Controller로 등록된 클래스 파일에 대한 bean을 자동으로 생성해준다.

Controller로 사용하고자 하는 클래스에 @Controller 어노테이션을 명시하면 component-scan으로 자동 등록된다.

 

 

@Repository

일반적으로 DAO에 사용되며 DB Exception을 DataAccessException으로 변환한다.

 


※ 그 외 어노테이션

 

@ResponseBody

- view가 아닌 JSON 형식의 값을 응답할 때 사용하는 애노테이션으로 문자열을 리턴하면 그 값을 http response header가 아닌 response body에 들어간다.

만약 객체를 return하는 경우 JACKSON 라이브러리에 의해 문자열로 변환되어 전송된다.

context에 설정된 resolver를 무시한다고 보면된다. (viewResolver)

 

 

@RequestBody

- 요청이 온 데이터(JSON이나 XML형식)를 바로 클래스나 model로 매핑하기 위한 애노테이션

 


@RequestParam

- @PathVariable과 비슷하다. request의 parameter에서 가져오는 것이다. 메소드의 파라미터에 사용됨

 

단일 파라미터 변환

private ModelAndView request_TEST(@RequestParam("test") int num,
@RequestParam("test2") String str)){
        //위처럼 하나이상의 타입을 적용할수 있습니다. 스프링에서 지원하는 변환기에서 지원되는 모든타입을 변환가능합니다.
        //RequestParam은 하나이상 파라미터에서 사용가능합니다.
    }

하지만 단점이 있다.

위처럼 사용하게 된다면 만약에 넘어오는 requestParam중에

@RequestParam 지정한 키값이 존재하지 않다면

BadRequest로 http 4** 에러가 발생한다.

 

 

2. 이를 방지하기 위하여 필수적이지 않도록 

그리고 존재하지 않다면 DefaultValue를 지정할수 있다.

private ModelAndView request_TEST(@RequestParam(value="test", required=false, defaultValue= "0") int num,
                                                   @RequestParam("test2") String str)){
        //required=false로 지정하면 해당 키값이 존재하지 않다고 해서 BadRequest가 발생하지 않게 됩니다.
                //그리고 존재하지 않다면 num변수에 default로 0이 들어가게됩니다.
}

 

 

3. RequestParam을 map에 지정하여 사용하기.

private ModelAndView request_TEST(@RequestParam HashMap<string,string> paramMap)){
        String data = paramMap.get("testParam");
    }
</string,string>

 

위의 예시처럼 map을 통해서도 파라미터를 컨트롤 할수 있습니다.

대규모의 파라미터를 받는데 map을 사용하기엔 편하지만

개발한 이외의 사람들이 유지보수하기에는 어려운 점이 있습니다.

그래서 주로 "커맨드패턴"인 데이터커맨드를 만들서 사용하는데요.

 

링크는 아래

https://heavenly-appear.tistory.com/44

 

 

@JsonProperty

- Jackson 라이브러리를 참조하는 어노테이션이다.

getter/setter 의 이름을 property 와 다른 이름을 사용할 수 있도록 설정한다. Database 를 자바 클래스로 매핑하는데 DB의 컬럼명이 알기 어려울 경우등에 유용하게 사용할 수 있다.

 

다음과 같은 테이블이 있을 경우

CREATE TABLE Users (
  u INT NOT NULL,
  a INT NOT NULL,
  e VARCHAR(80) NOT NULL
);

 

다음과 같이 JsonProperty 를 사용하면 DB 의 컬럼명을 변경하지 않아도 가독성을 높일 수 있다.

public class User
{
    @JsonProperty("userId");
    public Integer u;
  
    @JsonProperty("age");
    public Integer a;
  
    @JsonProperty("email");
    public String e;
}

 

json 으로 변환된 결과

{
    "userId": 1,
    "age": 13,
    "email": "user@host.com"
}

이외에 @JsonIgnoreProperties, @JsonInclude 등이 있다.

 

Jackson 라이브러리에 관한 자세한 내용:

https://www.lesstif.com/pages/viewpage.action?pageId=24445183#JavaJsonlibraryjackson%EC%82%AC%EC%9A%A9%EB%B2%95-%EA%B0%9C%EC%9A%94

 

 

@CrossOrigin

- CORS 보안상의 문제로 브라우저에서 리소스를 현재 origin에서 다른 곳으로의 AJAX요청을 방지하는 것이다.

@RequestMapping이 있는 곳에 사용하면 해당 요청은 타 도메인에서 온 ajax요청을 처리해준다.

@CrossOrigin(origins = "http://jeong-pro.tistory.com", maxAge = 3600)

-> 기본 도메인이 http://jeong-pro.tistory.com 인 곳에서 온 ajax요청만 받아주겠다.

 

 

@CachePut

- 캐시를 업데이트하기 위해서 메서드를 항상 실행하게 강제하는 애노테이션

해당 애노테이션이 있으면 메서드호출을 항상한다. 그러므로 @Cacheable과 상충되어 같이 사용하면 안된다.

 

 

@Lazy

- 지연로딩을 지원한다.

 @Component나 @Bean 애노티에션과 같이 쓰는데 클래스가 로드될 때 스프링에서 바로 bean등록을 마치는 것이 아니 라 실제로 사용될 때 로딩이 이뤄지게 하는 방법이다.

 

 

@Scheduled

- 스프링 스케줄러이다. Unix의 cron처럼 특정시간 혹은 몇분 혹은 몇시간마다 동작하는 스케쥴러를 구현한다.

 

...더보기

사용 예시)

 @Scheduled(fixedDelay=1000)
    public void TestScheduler(){
        System.out.println("스케줄링 테스트");
    }

3가지 밸류가 존재한다.

cron은 CronTab에서의 설정과 같이 cron="0/10 * * * * ?" 과 같은 설정이 가능하고

fixedDelay은 이전에 실행된 Task의 종료시간으로 부터 정의된 시간만큼 지난 후 Task를 실행한다.(밀리세컨드 단위)

fixedRate은 이전에 실행된 Task의 시작시간으로 부터 정의된 시간만큼 지난 후 Task를 실행한다.(밀리세컨드 단위)

 

 

 

 

 

+ Recent posts