Spring 게시판 만들기 예제
증말 벨로그 불편하다 -_- 노션쓰고싶다!
- 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);
}
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>
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>
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 - Board 변수들 private 지정 seq, title, writer , content, regdate, cnt - Getter/Setter 지정 - toString 오버라이드 : 멤버필드 출력 - 코드 생략
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 - 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) 메소드 구현
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 - 원하는 형태의 결과값 반환
// 쿼리 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 - 인터페이스를 구현하는 클래스 - 인터페이스를 오버라이드해서 메소드를 작성함 - 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 - 위와 동일(BoardServiceClientJDBC, BoardDaoSpring 실습 위한 코드)
@Service("boardServiceJDBC")
public class BoardServiceImplJDBC implements BoardService {
@Autowired
private BoardDAOSpring boardDAO;
...
BoardServiceImplTX - 위와 동일(BoardServiceClientTX, BoardDaoSpring 위한 코드)
@Service("boardServiceTX")
public class BoardServiceImplTX implements BoardService {
@Autowired
private BoardDAOSpring boardDAO;
...
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;
}
}
}
}
MVC 패턴 및 Annotation 설명 예제
https://m.blog.naver.com/scw0531/220988401816
트랜잭션 설명
https://blog.outsider.ne.kr/870 (예제 - AOP와 연계)
https://mangkyu.tistory.com/154 (개념 설명)
RowMapper 설명 예제
https://velog.io/@seculoper235/RowMapper%EC%97%90-%EB%8C%80%ED%95%B4
Spring JDBC 설명 예제
https://gmlwjd9405.github.io/2018/05/15/setting-for-db-programming.html