20220830_Tue
- 1. 스프링이 프로젝트 시작과 동시에 필요한 객체를 먼저 생성할 수 있도록 설정해야한다.
- 1) 객체를 생성하고자 하는 클래스는 반드시 기본 패키지 내에 선언되어야한다. :기본패키지는 최초 프로젝트 생성시 만들어지는 최초의 패키지를 의미함
(cf. 우리가 만든 프로젝트 board 의 기본패키지도 kh.study.board이기때문에 board패키지 내 클래스에서 선언되어있어야한다 )- 2) 객체를 만들고자 하는 클래스에 객체생성 코드를 작성한다. -> 객체를 만들고자 하는 클래스 위에(밖에) 어노테이션을 사용해야한다.
- 객체생성 어노테이션 4가지
- @Component : 초창기사용.요즘은 사용x 사용해도 오류발생x
- @Controller : 컨트롤러에 대한 객체생성
- @Service : 서비스에 대한 객체생성
- @Repository: 나중에 배울것!
: 위 4개의 어노테이션을 사용하면 객체를 생성하는데, 생성되는 개체명은 클래스명의 앞글자만 소문자로 바꾼 이름으로 자동으로 객체명 정의된다.
- ex1) 자동 객체명 생성(소문자)
@Controller pulbic class TestController{} 자동 객체명 소문자로 생성 -> TestController **testController** = new TestController();
- ex2) 수동 객체명 생성(괄호안 별도 지정)
@Controller("controller") pulbic class TestController{} 별도 객체명 지정시,괄호 안 객체명으로 생성-> TestController **controller** = new TestController();
- 2.프로젝트 생성과 동시에 만들어진 객체를 적절하게 "의존성 주입"(DI)시키는 코드를 작성해야한다.
- 1) 의존성 주입이 필요한 객체명 위에 어노테이션을 적용하여 코드를 작성한다(만들어진 객체를 가지고 내가 필요한 객체를 넣어준다)
- @Autowired : 자료형을 기준으로 의존성 주입을 시킬 객체를 판단한다.
- @Resource : name값 기준으로 의존성 주입을 시킬 객체를 판단한다.
- 2) 상황을 들어 예시를 들어보자.
프로젝트 시작과 동시에 자동으로 내부적으로 만들어진 객체 정보는 다음과 같다.
- a. BoardController controller = new BoardController();
- b. BoardService service = new BonardService();
- c. BoardDTO board = new BoardDTO();
- d. BoardService service1 = new BonardService();public class Test1{ @autowired -> 해석하자면 내부적으로 private BoardDTO dto = board; 진행된다. private BoardDTO dto;
* 오류발생코드: b,d의 자료형 중복 @autowired private BoardService service;
* 오류발생 x : @Resource를 사용하면 실제로 우리가 만들어진 객체 중에 (a~d) service 로 만들어진 객체에 넣어주세요! @Resource(name="service") private BoardService service;
* 오류발생코드: controller 이름의 객체명은 있지만 자료형 불일치!!! @Resource(name="controller") private BoardService service;
* 오류발생코드: 만들어진 객체 중에(a~d) 없기때문 @autowired private MemberDTO member; }
실습내용
- 게시글 목록페이지에 게시글 목록 데이터를 표로 띄우세요
- 게시글 목록페이지 하단에 글쓰기 버튼 생성
- 글쓰기 버튼 클릭 시 글쓰기 양식페이지로 이동
- 글 데이터를 적절히 입력 후 '등록' 버튼 클릭하면 실제 디비 insert 진행
- insert 성공시, alert으로 '글등록' 띄고, 게시글 목록페이지로 이동
- 제목을 클릭하면 게시글 정보에 대한 모든 정보를 띄우는 상세보기 페이지로 이동
- 생성 파일 목록
- board_list.html
- reg_board.html
- detail_board.html
- BoardController
- BoardService
- BoardServiceImpl
- board-mapper
DB_스퀀스(Sequence)
- 스퀀스(Sequence)
CREATE SEQUENCE TEST_SEQ START WITH 1 -- 1부터 시작 INCREMENT BY 1; -- 1씩 증가
- 테이블 생성 SPRING_BOARD
CREATE TABLE SPRING_BOARD ( BOARD_NUM NUMBER PRIMARY KEY-- 1,2,3,4,5.. , TITLE VARCHAR2(100) NOT NULL , CONTENT VARCHAR2(100) , WRITER VARCHAR2(100) NOT NULL , CREATE_DATE DATE DEFAULT SYSDATE );
- 테이블 조회
SELECT * FROM SPRING_BOARD ORDER BY BOARD_NUM DESC;
- 스퀀스(Sequence)
CREATE SEQUENCE TEST_SEQ START WITH 1 -- 1부터 시작 INCREMENT BY 1; -- 1씩 증가
- NEXT 먼저 실행 후, CURR 실행해야 값이 뜬다!
SELECT TEST_SEQ.NEXTVAL FROM DUAL; -- 조회실행할때마다 1씩 증가됨 SELECT TEST_SEQ.CURRVAL FROM DUAL; -- 현재 VALUE 조회
- 스퀀스 값을 초기화 시키는 코드
ALERT SEQUENCE TEST_SEQ INCREMENT BY 1;
- 스퀀스 생성 (BAORD_NUM)
CREATE SEQUENCE BOARD_NUM_SEQ START WITH 1 INCREMENT BY 1;
- 테이블 데이터 삽입(게시글 등록)
INSERT INTO SPRING_BOARD ( BOARD_NUM , TITLE , CONTENT , WRITER ) VALUES( TEST_SEQ.NEXTVAL , '제목1' , '내용1' , '작성자1' ) ;
- 상세조회 쿼리문
SELECT BOARD_NUM , TITLE , WRITER , CONTENT , CREATE_DATE FROM SPRING_BOARD WHERE TITLE = '제목1';
board_list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
table{
width: 800px;
margin: 0 auto;
border-collapse: collapse;
border: 1px solid black;
}
table>thead>tr:first-child{
margin-bottom: 10px;
}
tr,td{
border-collapse: collapse;
border: 1px solid black;
}
</style>
</head>
<body>
<table border="1">
<thead>
<tr>
<td>게시글 번호</td>
<td>제목</td>
<td>작성자</td>
<td>작성일</td>
<!-- 리스트크기 데이터 갖고오는 방법 2가지-->
<!-- <td th:text="${#lists.size(boardList)}"></td>
<td th:text="${boardList.size()}"></td> -->
</tr>
</thead>
<tbody>
<th:block th:if="${#lists.size(boardList) == 0}">
<tr>
<td colspan="4">게시글이 없습니다.</td>
</tr>
</th:block>
<th:block th:unless="${#lists.size(boardList) == 0}">
<tr th:each="board : ${boardList}"><!-- 컨트롤러에서 넘긴 그대로:boardList -->
<td th:text="${board.boardNum}"></td>
<td>
<a th:href="@{'/board/detail/' + ${board.boardNum}}">
<span th:text="${board.title}"></span>
</a>
</td>
<td th:text="${board.writer}"></td>
<td th:text="${board.createDate}"></td>
</tr>
</th:block>
</tbody>
</table>
<div align="center">
<!-- location.href 이동시, /board/... 식으로(컨트롤러이동) 작성해야한다! -->
<input class="btn" type="button" value="글쓰기" onclick ="location.href='/board/regBoard';">
</div>
</body>
</html>
reg_board.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"><!-- jsp에서 foreach문 사용할때 lib태그 사용하는 것과 같다.앞으로 html 만들때는 사용해야한다. 원래 html만들때 next누르고 별도로 생성한 htnl_thymeleaf를 선택하면 자동생성된다-->
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/board/regBoard" method="post"><!--form 하면 반드시 submit 필요 (onclick삭제) -->
<table>
<tr>
<td>제목</td>
<td><input name="title" type="text" ></td>
</tr>
<tr>
<td>작성자</td>
<td><input name="writer" type="text" ></td>
</tr>
<tr>
<td>내용</td>
<td><textarea rows="3" cols="50" name="content"></textarea></td>
</tr>
</table>
<div align="center">
<input type = "submit" value = "글등록" >
</div>
</form>
</body>
</html>
detail_board.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"><!-- jsp에서 foreach문 사용할때 lib태그 사용하는 것과 같다.앞으로 html 만들때는 사용해야한다. 원래 html만들때 next누르고 별도로 생성한 htnl_thymeleaf를 선택하면 자동생성된다-->
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
상세보기 페이지입니다.
<div>
<input type="button" class="btn" value="글쓰기 수정"> <!--> -->
<input type="button" class="btn" value="글쓰기 삭제"> <!--> -->
</div>
</body>
</html>
BoardController
package kh.study.board.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import kh.study.board.service.BoardService;
import kh.study.board.vo.BoardVO;
@Controller
@RequestMapping("/board")// "/board"로 시작하면 무조건 컨트롤러 실행하겠다
public class Boardcontroller {
//boardService 라는 이름으로 만들어진 개체를 로드해서
//"의존성 주입"을 실행한다
//@Resource는 @autoWired와 비슷하지만 자료형이 같은 객체가 아니라
//name값이 같은 변수명을 가져와서 데이터를 넣어준다
//1-1.의존성 주입
@Resource(name = "boardService")//boardService라는 이름의 객체를 가져오겠습니다!
private BoardService boardService;//스프링에서는 선언만!
//게시글 목록 페이지
@GetMapping("/list")
public String selectBoardList(Model model) {
//1.게시글 목록 조회(한줄요약)
model.addAttribute("boardList",boardService.selectBoardList());
return "board/board_list";//어디로 이동할래?
}
//(양식)글등록하는 페이지로 이동: Form양식페이지로 안가는 이유가 있다!!
///regBoard 컨트롤러로 넘어올 때 중복인데 어노테이션이 다르기때문 괜찮다!
@GetMapping("/regBoard")//a태그,href일경우...
public String regBoard() {
return "board/reg_board";
}
//글 등록
@PostMapping("/regBoard")//form태그로 넘어올땐!
public String regBoard(BoardVO boardVO) {
boardService.insertBoard(boardVO);
return "board/reg_board_result";
}
//상세보기
@GetMapping("/detail/{boardNum}")
public String detailBoard(@PathVariable("boardNum") int boardNum,Model model) {
model.addAttribute("boardList", boardService.selectDetailBoard(boardNum));
return "board/detail_board";
}
//글수정 양식
@GetMapping("/update/{boardNum}")
public String update(@PathVariable("boardNum") int boardNum, Model model) {
// model.addAttribute("boardList", boardService.updateBoard(boardNum));
return "board/update_board";
}
//글수정
@PutMapping("/update/{boardNum}")
public String update(BoardVO boardVO) {
// boardService.updateBoard(boardVO);
return "redirect:/";
}
//글 삭제
@DeleteMapping("/delete/{boardNum}")
public String delete(@PathVariable("boardNum") int boardNum) {
boardService.deleteBoard(boardNum);
return "redirect:/";
}
}
package kh.study.board.service;
import java.util.List;
import kh.study.board.vo.BoardVO;
public interface BoardService {
//게시글 목록조회
List<BoardVO> selectBoardList();
//글쓰기 등록
void insertBoard(BoardVO boardVO);
//상세보기
BoardVO selectDetailBoard(int boardNum);
//글 수정
void updateBoard(BoardVO boardVO);
//글 삭제
void deleteBoard(int boardNum);
}
package kh.study.board.service;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import kh.study.board.vo.BoardVO;
@Service("boardService")//괄호안에 빈값이면 클래스명 소문자로 BoardServiceImpl 객체자동생성되기 때문에
public class BoardServiceImpl implements BoardService {
//쿼리 실행하는 객체
// SqlSessionFactory sqlSessionFactory = SqlSessionManager.getSqlSession();
// SqlSession sqlSession;//생성이 아닌 선언만
//@Autowired어노테이션은 미리 생성한 객체를 의존성 주입 시킬 때 사용한다.
//아래코드가 진행이 된다는 것은, 프로젝트 실행 시
// 스프링이 내부적으로 sqlSessionTemplate 자료형으로 객체를 미리 만들어 놓기 때문에 사용가능하다.
//@Autowired는 그래서 동일한 자료형으로 객체가 미리 2개 이상 생성되어있다면,
//프로젝트 실행과 동시에 오류 발생
//-> DB로 이동
@Autowired//자동연결 (기준 자료형이 같은 객체만)
SqlSessionTemplate sqlSession;
//게시글 목록조회
@Override
public List<BoardVO> selectBoardList() {
//원래 이클립스에서 하는 방식
// List<BoardVO> list = sqlSession.selectList("boardMapper.selectBoardList");
// return list;
// sqlSession.commit();(스프링은 자동 커밋)
//->(스프링) 그래서 이제 부터 한 줄로 작성 가능해짐
return sqlSession.selectList("boardMapper.selectBoardList");
}
//글쓰기 등록
@Override
public void insertBoard(BoardVO boardVO) {
sqlSession.insert("boardMapper.insertBoard",boardVO);
}
//상세보기
@Override
public BoardVO selectDetailBoard(int boardNum) {
return sqlSession.selectOne("boardMapper.selectDetailBoard",boardNum);
}
//글 수정
@Override
public void updateBoard(BoardVO boardVO) {
sqlSession.update("boardMapper.updateBoard",boardVO);
}
//글 삭제
@Override
public void deleteBoard(int boardNum) {
sqlSession.delete("boardMapper.insertBoard",boardNum);
}
}
<?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="boardMapper">
<resultMap type="kh.study.board.vo.BoardVO" id="board">
<id column="BOARD_NUM" property="boardNum"/>
<result column="TITLE" property="title"/>
<result column="WRITER" property="writer"/>
<result column="CONTENT" property="content"/>
<result column="CREATE_DATE" property="createDate"/>
</resultMap>
<!-- 목록조회 -->
<select id="selectBoardList" resultMap="board">
SELECT BOARD_NUM
, TITLE
, WRITER
, CREATE_DATE
FROM SPRING_BOARD
ORDER BY BOARD_NUM DESC
</select>
<!-- 게시글등록 -->
<insert id="insertBoard">
INSERT INTO SPRING_BOARD (
BOARD_NUM
, TITLE
, CONTENT
, WRITER
) VALUES(
BOARD_NUM_SEQ.NEXTVAL
, #{title}
, #{content}
, #{writer}
)
</insert>
<!-- 상세보기 -->
<select id="selectDetailBoard" resultMap="board">
SELECT BOARD_NUM
, TITLE
, WRITER
, CONTENT
, CREATE_DATE
FROM SPRING_BOARD
WHERE BOARD_NUM = #{boardNum}
</select>
</mapper>