[Spring] 게시판 만들기

Use_Silver·2022년 1월 3일
0

Spring

목록 보기
5/10
post-thumbnail
post-custom-banner

Spring 게시판 만들기 예제
증말 벨로그 불편하다 -_- 노션쓰고싶다!

패키지 구성

  • com.enc.biz.board : 부모 클래스 + client 클래스 구성
  • com.enc.biz.board.impl : 상속받은 클래스 구성(?) '구현했다'는 의미로 많이 명명한다고 한다.
  • com.enc.biz.common : 공통 클래스 구성

com.enc.biz.board

BoardService.java

- CRUD 기능 구현 Interface
    package com.enc.biz.board;
   
    public interface BoardService {
        // CRUD 기능의 메소드 구현
        // 글 등록
        void content(BoardVO vo);

        // 글 수정
        void updateBoard(BoardVO vo);

        // 글 삭제
        void deleteBoard(BoardVO vo);

        // 글 상세 조회
        BoardVO getBoard(BoardVO vo);

        // 글 목록 조회
        List<BoardVO> getBoardList(BoardVO vo);

        void insertBoard(BoardVO vo);
    }

BoardServiceClient.java

AOP 예제 
	1. BoardServiceClient.java
	2. applicationContextBoard11.xml 
   	 (해당 예제에서 메소드 실행 전 log 남기는 용도로 사용)
* AOP 
: 관점지향 프로그래밍 
: 높은 응집도와 관련 
: 코드 중 필요하고 공통화 할 수 있는 부분을 따로 관리하는 것 (횡단 분리)
* AOP 용어
: 조인 포인트 - 모든 비즈니스 메소드, 포인트컷의 후보 
: 포인트 컷 - 조인포인트 중 특정 메소드에서만 횡단 공통기능 수행 위해 사용
: 어드바이스 - 횡단관심에 해당하는 공통 기능 코드 

참고

package com.enc.biz.board;
...

public class BoardServiceClient {
	public static void main(String[] args) {
    
	// 1. Spring Container 구동
	AbstractApplicationContext container 
	= new GenericXmlApplicationContext("applicationContextBoard11.xml"); // 참조

	// 2. Spring Container로부터 BoardServiceImpl 객체 LookUp
	BoardService boardService = (BoardService) container.getBean("boardService");

	// 3. 글 게시, 조회 Test 
	BoardVO vo = new BoardVO();
	vo.setTitle("임시 제목");
	vo.setWriter("홍길동");
	vo.setContent("임시 내용 ~~~");
	boardService.insertBoard(vo);
	List<BoardVO> boardList = boardService.getBoardList(vo);
	
	for(BoardVO board : boardList) {
		System.out.println("---> " + board.toString());}
	container.close();
	}
}
<context:component-scan base-package="com.enc.biz">
</context:component-scan>
	
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<context:property-placeholder location="classpath:config/database.properties"/>

<bean id="log" class="com.enc.biz.common.LogAdvice" ></bean>
<bean id="log4j" class="com.enc.biz.common.Log4jAdvice" ></bean>

<aop:aspectj-autoproxy />
	
<aop:config>
  <!-- pointcut = 어떤 메소드를 대상으로 할지 결정  -->
  <aop:pointcut id="allPointcut"
                expression="execution(* com.enc.biz..*Impl.*(..))" />
			
  <aop:aspect ref="log4j">		
    <aop:before pointcut-ref="allPointcut" method="printLogging" />
  </aop:aspect> 	
	     
  <!--log method example -->

  <aop:pointcut id="getPointcut"
		expression="execution(* com.enc.biz..*Impl.get*(..))"/>	 
  <aop:aspect ref="log">
   <aop:after pointcut-ref="getPointcut" method="printLog" />
  </aop:aspect>
  
</aop:config>	

</beans>

BoardServiceClientJDBC.java

Spring DataBase 연결 예제 	
-------------------------------------------------
1. BoardServiceClientJDBC.java
2. applicationContextJDBC.xml
-------------------------------------------------
	1)  DataSource 사용 예제 -> Placeholder 사용 
		- config/database.properties
		- applicationContextJDBC.xml
        -----------------------------------------
	2) JDBC 사용 예제 -> JDBCTemplate 사용
    		- applicationContextJDBC.xml

참고

package com.enc.biz.board;
...
public class BoardServiceClientJDBC {
	public static void main(String[] args) {
	
    	// 1. Spring Container 구동 
	AbstractApplicationContext container 
	= new GenericXmlApplicationContext("applicationContextJDBC.xml"); 

	// 2. Spring Container로부터 BoardServiceImpl 객체 LookUp
	BoardService boardService = (BoardService) container.getBean("boardServiceJDBC");

	// 3. 글 게시, 조회 Test 
	BoardVO vo = new BoardVO();
	...
}
1. DataSource 사용 예제
	- Placeholder 사용 
	1) config/database.properties    
	2) applicationContextJDBC.xml
db.driverClassName =com.mysql.cj.jdbc.Driver
db.url =jdbc:mysql://localhost:3306/uboard?serverTimezone=UTC
db.username =root
db.password =1234
<context:property-placeholder location = "classpath:config/database.properties"/>		 

<!-- 1. DataSource 설정 - config/database.properties 읽어오기  -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"  
      destroy-method="close"
      p:driverClassName="${db.driverClassName}"
      p:url="${db.url}"
      p:username="${db.username}"
      p:password="${db.password}"
/>	
2. JDBC 사용 예제 
    - JDBCTemplate 사용
	<!-- Spring JDBC 설정 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource" />
	</bean>
	 		 

BoardServiceClientTX.java

Transaction 예제 	
-------------------------------------------------
Transaction?
    : 작업 진행 중 문제가 발생했을 경우 이전상태로 롤백(Rollback)하기 위해 사용  
    : 다 성공하거나(commit) 다 실패해야 함(실패 이후 이전 상태로 rollback)
    : 트랜잭션 커밋 - 작업 마무리
    : 트랜잭션 롤백 - 작업 취소 후 이전 상태로 변경 
-------------------------------------------------
Spring Transaction 3가지 핵심 기술 
    1. 트랜잭션 동기화
    2. 트랜잭션 추상화
    3. AOP이용한 트랜잭션 분리 (이번 예제에서 사용)
    	- BoardServiceClientTX.java
  	- applicationContextTX.xml

참고
예제가 잘 되어있는설명

public class BoardServiceClientTX {
	public static void main(String[] args) {
		
	AbstractApplicationContext container 
	= new GenericXmlApplicationContext("applicationContextTX.xml"); 
...
<!-- Transaction 설정 -->
<!-- 	txmanager -> db에 연결할때 사용  -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 	advice : 대상 특정 (전체 중 get 함수에서 읽기만 가능), 그 나머지에는 transactinon을 넣겠다 -->	
<tx:advice id="txAdvice" transaction-manager="txManager">
  <tx:attributes>
    <tx:method name="get*" read-only="true"/>
    <tx:method name="*"/>
  </tx:attributes>
</tx:advice>
	
<!-- pointCut : 트랜잭션을 넣기 가능, 
  sqlSeqNum : db에서 중복됐다 말할 수 있음 but Spring, Tomcat에서 원인을 모름 
   ->> pointCUT 이용해 처리 가능 
  	aop:pointcut advice 대상으로 함 
	 -->
<aop:config>
  <aop:pointcut id="txPointcut"  expression="execution(* com.enc.biz..*(..))"/>
  <aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice"/>
</aop:config>

BoardVO.java

BoardVO 
- Board 변수들 private 지정 seq, title, writer , content, regdate, cnt
- Getter/Setter 지정 
- toString 오버라이드 : 멤버필드 출력
- 코드 생략

com.enc.biz.board.impl

BoardDAO.java

BoardDAO 
- CRUD 기능의 메소드 구현 
	1) Repository("boardDAO")
    	2) JDBC 관련 변수 선언
    	3) SQL 명령어 정의(BOARD_INSERT, BOARD_UPDATE, BOARD_DELETE, BOARD_GET, BOARD_LIST)
    	4) 메소드 구현 
1) Repository("boardDAO")
2) JDBC 관련 변수 선언
@Repository("boardDAO") 
public class BoardDAO {
	// JDBC 관련 변수
        private Connection conn = null;
        private PreparedStatement stmt = null;
        private ResultSet rs = null;
3) SQL 명령어 정의(INSERT, UPDATE, DELETE, GET, LIST)
	// SQL 명령어
	private final String BOARD_INSERT = "insert into board(seq, title, writer, content) "
			+ "values(null,?,?,?)";

	private final String BOARD_UPDATE = "update board set title=?, content=? where seq=?";
	private final String BOARD_DELETE = "delete from board where seq=?";
	private final String BOARD_GET = "select * from board where seq=?";
	private final String BOARD_LIST = "select * from board order by seq desc";
4) 메소드 구현
	// CRUD 기능의 메소드 구현
	// 글 등록
	public void insertBoard(BoardVO vo) {
		System.out.println("===> JDBC로 insertBoard() 기능 처리");
		try {
			conn = JDBCUtil.getConnection(); // JDBCUtill에서 connection get
			stmt = conn.prepareStatement(BOARD_INSERT);
			stmt.setString(1, vo.getTitle());
			stmt.setString(2, vo.getWriter());
			stmt.setString(3, vo.getContent());
			stmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(stmt, conn); // JDBCUtill에서 connection close
		}
	}
    // 글 수정 ...
    // 글 삭제 ...
    // 글 상세 조회 ...
    // 글 목록 조회
	public List<BoardVO> getBoardList(BoardVO vo) {
		System.out.println("===> JDBC로 getBoardList() 기능 처리");
		List<BoardVO> boardList = new ArrayList<BoardVO>();
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_LIST);
			rs = stmt.executeQuery();
			while (rs.next()) {
				BoardVO board = new BoardVO();
				board.setSeq(rs.getInt("SEQ"));
				board.setTitle(rs.getString("TITLE"));
				board.setWriter(rs.getString("WRITER"));
				board.setContent(rs.getString("CONTENT"));
				board.setRegDate(rs.getDate("REGDATE"));
				board.setCnt(rs.getInt("CNT"));
				boardList.add(board);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(rs, stmt, conn);
		}
		return boardList;
	}

BoardDAOSpring.java

BoardDAOSpring 
- CRUD 기능의 메소드 구현 
	1) Repository
    	2) Autowired JdbcTemplate
        - Autowired 
        	: new 객체생성 없이 호출 하기 위함
        	: 이와 같이 자동적으로 객체를 만들고 사용하게 O => 의존성 주입
    	3) JDBC 관련 변수 선언(필요X)
    	4) SQL 명령어 정의(BOARD_INSERT, BOARD_UPDATE, BOARD_DELETE, BOARD_GET, BOARD_LIST)
    	5) 메소드 구현 

annotation 설명(전체적 MVC 패턴 잘 설명)

1) Repository
2) Autowired JdbcTemplate        
//DAO(Data Access Object)
@Repository
public class BoardDAOSpring {
	@Autowired // 객체 생성 없이 가져옴 
	private JdbcTemplate jdbcTemplate;
3) JDBC 관련 변수 선언 (X)
4) SQL 명령어 정의(INSERT, UPDATE, DELETE, GET, LIST) (생략)
5) 메소드 구현
	// 글 등록
	public void insertBoard(BoardVO vo) {
		System.out.println("===> Spring JDBC로 insertBoard() 기능 처리");
		jdbcTemplate.update(BOARD_INSERT, vo.getSeq(), vo.getTitle(), vo.getWriter(), vo.getContent());
	}

	// 글 수정
	public void updateBoard(BoardVO vo) {
		System.out.println("===> Spring JDBC로 updateBoard() 기능 처리");
		jdbcTemplate.update(BOARD_UPDATE, vo.getTitle(), vo.getContent(), vo.getSeq());
	}

	// 글 삭제
	public void deleteBoard(BoardVO vo) {
		System.out.println("===> Spring JDBC로 deleteBoard() 기능 처리");
		jdbcTemplate.update(BOARD_DELETE, vo.getSeq());
	}

	// 글 상세 조회
	public BoardVO getBoard(BoardVO vo) {
		System.out.println("===> Spring JDBC로 getBoard() 기능 처리");
		Object[] args = { vo.getSeq() };
		return jdbcTemplate.queryForObject(BOARD_GET, args, new BoardRowMapper());
	}

	// 글 목록 조회
	public List<BoardVO> getBoardList(BoardVO vo) {
		System.out.println("===> Spring JDBC로 getBoardList() 기능 처리");
		return jdbcTemplate.query(BOARD_LIST, new BoardRowMapper());
	}

BoardRowMapper.java

BoardRowMapper 
- 원하는 형태의 결과값 반환
// 쿼리 
ResultSet rs = stat.excuteQuery("SELECT * FROM USER");
// 결과값 가져오기
while(rs.next()) {
     // user 객체에 값 저장
     user = new User();
     user.setId(rs.getInt(1));
     user.setName(rs.getString(2));
     user.setDescription(rs.getString(3));    
     // 리스트에 추가
     userList.add(user);
}
 ResultSet을 사용했을 때,
	1) ResultSet으로 쿼리를 수행한 result를 받고 
	2) 객체에 담아서(set)
	3) 리스트에 추가해 반환한 절차와 동일

참고

// ResultSet에 값을 담아와 BoardVO 객체에 저장
// rowNum만큼 반복
public class BoardRowMapper implements RowMapper<BoardVO> {
	public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException {
		BoardVO board = new BoardVO();
		board.setSeq(rs.getInt("SEQ"));
		board.setTitle(rs.getString("TITLE"));
		board.setWriter(rs.getString("WRITER"));
		board.setContent(rs.getString("CONTENT"));
		board.setRegDate(rs.getDate("REGDATE"));
		board.setCnt(rs.getInt("CNT"));
		return board;
	}
}

BoardServiceImpl.java

BoardServiceImpl 
- 인터페이스를 구현하는 클래스 
- 인터페이스를 오버라이드해서 메소드를 작성함 
	- dao, service는 인터페이스와 클래스 파일이 한 세트로 구성됨  
- Service라는걸 알리기 위해 @Service 어노테이션 작성 
@Service("boardService") // Service Annotation
public class BoardServiceImpl implements BoardService {
	@Autowired // DAO 등록
	private BoardDAO boardDAO; 

	public void insertBoard(BoardVO vo) {
		boardDAO.insertBoard(vo);
	}

	public void updateBoard(BoardVO vo) {
		boardDAO.updateBoard(vo);
	}

	public void deleteBoard(BoardVO vo) {
		boardDAO.deleteBoard(vo);
	}

	public BoardVO getBoard(BoardVO vo) {
		return boardDAO.getBoard(vo);
	}

	public List<BoardVO> getBoardList(BoardVO vo) {
		return boardDAO.getBoardList(vo);
	}

}

BoardServiceImplJDBC.java

BoardServiceImplJDBC 
- 위와 동일(BoardServiceClientJDBC, BoardDaoSpring 실습 위한 코드) 
@Service("boardServiceJDBC")
public class BoardServiceImplJDBC implements BoardService {
	@Autowired
	private BoardDAOSpring boardDAO; 
    ...

BoardServiceImplTX.java

BoardServiceImplTX 
- 위와 동일(BoardServiceClientTX, BoardDaoSpring 위한 코드) 
@Service("boardServiceTX")
public class BoardServiceImplTX implements BoardService {
	@Autowired
	private BoardDAOSpring boardDAO; 
    ...

com.enc.biz.common

JDBCUtill.java

JDBCUtill 
- DataBase 연결 
- DataBase 연결 해제 
package com.enc.biz.common;
public class JDBCUtil {
	// Mysql DB 
	public static Connection getConnection() {
		try {
			String jdbcDriver = "com.mysql.cj.jdbc.Driver";
			String jdbcUrl = "jdbc:mysql://localhost:3306/uboard?serverTimezone=UTC";
			String dbUser  = "유저명";
			String dbPwd   = "패스워드";
			
			Class.forName(jdbcDriver);
			return DriverManager.getConnection(jdbcUrl, dbUser, dbPwd); // spring container에 싣기 ==> spring jdbc module에 있음 
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	// Query (insert, update, delete)
	public static void close(PreparedStatement stmt, Connection conn) {
		if (stmt != null) {
			try {
				if (!stmt.isClosed())
					stmt.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				stmt = null;
			}
		}
		if (conn != null) {
			try {
				if (!conn.isClosed())
					conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				conn = null;
			}
		}
	}

	// Query (select)
	public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
		if (rs != null) {
			try {
				if (!rs.isClosed())
					rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				rs = null;
			}
		}
		if (stmt != null) {
			try {
				if (!stmt.isClosed())
					stmt.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				stmt = null;
			}
		}
		if (conn != null) {
			try {
				if (!conn.isClosed())
					conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				conn = null;
			}
		}
	}
}

[참조]

profile
과정은 힘들지만😨 성장은 즐겁습니다🎵
post-custom-banner

0개의 댓글