spring22rest에
BookDto 생성
@Schema ( description = "도서 정보 객체" )
@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class BookDto {
private int bookId , bookPageCount ;
@ Builder . Default
private float bookPrice = - 1f ; //절대로 들어올 수 없는 값
private String bookTitle , bookAuthor , bookPublicationDate , bookPublisher , bookGenre ;
}
mybatis 폴더에 book-mapper.xml 생성
<? xml version = "1.0" encoding = "UTF-8" ?>
<! DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd " >
< mapper namespace = "book" >
<!-- 등록, 목록, 검색, 상세, 수정(일부/전체), 삭제 -->
< select id = "findAll" resultType = "BookDto" >
select * from book order by book_id asc
</ select >
< select id = "findByBookId" resultType = "BookDto" >
select * from book where book_id = #{bookId}
</ select >
<!-- 도서명 검색 -->
< select id = "findByBookTitle" resultType = "BookDto" >
<!-- select * from book where book_title = #{bookTitle} -->
<!-- select * from book where book_title like = #{bookTitle} || '%' -->
<!-- select * from book where book_title like concat (#{bookTitle} || '%') -->
select * from book where instr (book_title, #{bookTitle}) > 0
</ select >
< insert id = "save" >
insert into book(
book_id, book_title, book_author, book_publication_date,
book_price, book_publisher, book_page_count, book_genre
)
values(
book_seq.nextval, #{bookTitle}, #{bookAuthor}, #{bookPublicationDate},
#{bookPrice}, #{bookPublisher}, #{bookPageCount}, #{bookGenre}
)
</ insert >
< delete id = "deleteByBookId" >
delete book where book_id = #{bookId}
</ delete >
<!--
(참고) JPA에서는 등록과 수정 명령이 같다 - 둘다 save
- 변경 시 변경할 PK와 변경할 정보(DTO)가 전달
- PK는 bookId, DTO는 bookDto
-->
< update id = "change" >
update book
< set >
< if test = "bookDto.bookTitle != null" >
book_title = #{bookDto.bookTitle},
</ if >
< if test = "bookDto.bookAuthor != null" >
book_author = #{bookDto.bookAuthor},
</ if >
< if test = "bookDto.bookPublicationDate != null" >
book_publication_date = #{bookDto.bookPublicationDate},
</ if >
< if test = "bookDto.bookPrice >= 0" >
book_price = #{bookDto.bookPrice},
</ if >
< if test = "bookDto.bookPublisher != null" >
book_publisher = #{bookDto.bookPublisher},
</ if >
< if test = "bookDto.bookPageCount > 0" >
book_page_count = #{bookDto.bookPageCount},
</ if >
< if test = "bookDto.bookGenre != null" >
book_genre = #{bookDto.bookGenre},
</ if >
</ set >
where book_id = #{bookId}
</ update >
</ mapper >
BookDao 인터페이스 생성
public interface BookDao {
List < BookDto > selectList () ;
BookDto selectOne ( int bookId ) ;
List < BookDto > searchList ( String bookTitle ) ;
void insert ( BookDto bookDto ) ;
void edit ( int bookId , BookDto bookDto ) ;
void delete ( int bookId ) ;
}
BookDaoImpl 생성
@Slf4j
@Repository
public class BookDaoImpl implements BookDao {
@Autowired
private SqlSession sqlSession ;
@Override
public List < BookDto > selectList () {
return sqlSession . selectList ( "book.findAll" ) ;
}
@Override
public BookDto selectOne ( int bookId ) {
return sqlSession . selectOne ( "book.findByBookId" , bookId ) ;
}
@Override
public List < BookDto > searchList ( String bookTitle ) {
return sqlSession . selectList ( "book.findByBookTitle" , bookTitle ) ;
}
@Override
public void insert ( BookDto bookDto ) {
sqlSession . insert ( "book.save" , bookDto ) ;
}
@Override
public void edit ( int bookId , BookDto bookDto ) {
Map < String , Object > param = Map . of ( "bookId" , bookId , "bookDto" , bookDto ) ;
sqlSession . update ( "book.change" , param ) ;
}
@Override
public void delete ( int bookId ) {
sqlSession . delete ( "book.deleteByBookId" , bookId ) ;
}
}
BookRestController 생성
@Tag ( name = "도서 관리" , description = "도서 정보 관리를 위한 컨트롤러" )
@CrossOrigin
@RestController
@RequestMapping ( "/book" ) //주소는 반드시 테이블명(테이블명을 노출시키고 싶지 않다면 그와 비슷한 유사 이름)
public class BookRestController {
@Autowired
private BookDao bookDao ;
@GetMapping ( "/" ) //자원 설계 방식이 기능이 아니라서 주소 이름이 list가 아님
public List < BookDto > list (){
return bookDao . selectList () ;
}
@GetMapping ( "/bookId/{bookId}" )
public BookDto find ( @PathVariable int bookId ) {
return bookDao . selectOne ( bookId ) ;
}
@GetMapping ( "/bookTitle/{bookTitle}" )
public List < BookDto > search ( @PathVariable String bookTitle ) {
return bookDao . searchList ( bookTitle ) ;
}
@PostMapping ( "/" )
public void insert ( @RequestBody BookDto bookDto ) {
bookDao . insert ( bookDto ) ;
}
@PutMapping ( "/{bookId}" )
public void update ( @RequestBody BookDto bookDto , @PathVariable int bookId ) {
//bookDto에 모든 항목이 있는지 검사해야함
bookDao . edit ( bookId , bookDto ) ;
}
@PatchMapping ( "/{bookId}" )
public void update2 ( @RequestBody BookDto bookDto , @PathVariable int bookId ) {
//bookDto에 항목이 하나라도 있는지 검사해야함
bookDao . edit ( bookId , bookDto ) ;
}
@DeleteMapping ( "/{bookId}" )
public void delete ( @PathVariable int bookId ) {
bookDao . delete ( bookId ) ;
}
}
RequestBody와 ModelAttribute의 차이점은 받는 데이터가 다르다는 것
controller와 restController 차이?
rest가 붙으면 데이터를 반환하는 것이다.
error 패키지 생성 후 ExceptionControllerAdvice 생성
@Slf4j
@RestControllerAdvice ( basePackages = { "com.kh.spring22.restcontroller" })
//@RestControllerAdvice(annotations = {RestController.class})
public class ExceptionControllerAdvice {
//[1] NoTargetException이 발생하면 사용자에게 404를 반환
@ExceptionHandler ( NoTargetException . class )
public ResponseEntity <?> error404 ( Exception e ) {
log . warn ( "404 발생" , e ) ;
return ResponseEntity . notFound () . build () ;
}
//[2] 그 외 예외가 발생하면 사용자에게 500을 반환
@ExceptionHandler ( Exception . class )
public ResponseEntity < String > error500 ( Exception e ) {
log . error ( "오류 발생" , e ) ;
return ResponseEntity . internalServerError () . body ( "server error" ) ;
}
}
BookDaoImpl 구문 수정
@Override
public BookDto selectOne ( int bookId ) {
BookDto bookDto = sqlSession . selectOne ( "book.findByBookId" , bookId ) ;
if ( bookDto == null ) throw new NoTargetException () ;
return bookDto ;
}
Map < String , Object > param = Map . of ( "bookId" , bookId , "bookDto" , bookDto ) ;
int result = sqlSession . update ( "book.change" , param ) ;
if ( result == 0 ) throw new NoTargetException () ;
@ Override
public void delete ( int bookId ) {
int result = sqlSession . delete ( "book.deleteByBookId" , bookId ) ;
if ( result == 0 ) throw new NoTargetException () ;
}
React와 백엔드 연결 시키기
demo05 프로젝트 생성
npx create-react-app demo05 --skip-git
부트스트랩, 부츠워치 다운
npm i bootstrap npm i bootswatch 설치 후 import
프로젝트에 Ctrl + shiht + c = 외부 터미널 열기'
react-router 다운
npm install react-router
npm install react-router-dom
npm install react-router npm install react-router-dom : 한 번에 다운로드 하기
npm list : 설치 목록 보기
index.js 구문 수정
import React from 'react' ;
import ReactDOM from 'react-dom/client' ;
//link 대신 import를 통해 설치한 라이브러리 CSS를 불러오도록 처리
//- node_modules에 설치한 요소들은 바로 이름을 사용하여 접근 가능
import 'bootstrap/dist/css/bootstrap.min.css' ;
//이곳에 bootswatch css파일을 불러오는 구문을 작성
import 'bootswatch/dist/lumen/bootstrap.min.css' ;
import App from './App' ;
import reportWebVitals from './reportWebVitals' ;
//Router는 React 앱을 여러 페이지로 분할하여 사용하도록 만드는 기술
//- HashRouter는 주소에 해시(#)가 포함된다.
//- BrowserRouter는 주소에 해시(#)가 포함되지 않는다.
import { BrowserRouter , HashRouter } from 'react-router-dom' ;
const root = ReactDOM . createRoot ( document . getElementById ( 'root' ));
root . render (
< HashRouter >
< App />
</ HashRouter >
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
reportWebVitals ();
App.js 구문 수정
import { NavLink , Route , Routes } from "react-router-dom" ;
import Pocketmon from "./components/Pocketmon" ;
import Book from "./components/Book" ;
import Home from "./components/Home" ;
function App () {
return (
< div className = "container-fluid" >
{ /* 상단 메뉴 영역 */ }
< div >
{ /* a링크 쓸 수 없음 화면이 동기화 되어서 */ }
< NavLink to = "/" > 홈 </ NavLink >
< NavLink to = "/pocketmon" > 포켓몬스터 </ NavLink >
< NavLink to = "/book" > 도서 </ NavLink >
</ div >
{ /* 본문 영역 */ }
< div >
< Routes >
< Route exact path = "/" element = { < Home /> } ></ Route >
< Route path = "/pocketmon" element = { < Pocketmon /> } ></ Route >
< Route path = "/book" element = { < Book /> } ></ Route >
</ Routes >
</ div >
</ div >
);
}
export default App ;
Home.js 생성
const Home = ( props ) => {
return (
<>
< h1 > 메인 페이지 </ h1 >
</>
);
};
export default Home ;
Pocketmon.js 생성
const Pocketmon = ( props ) => {
return (
<>
< h1 > 포켓몬 관리화면 </ h1 >
</>
);
};
export default Pocketmon ;
Book.js 생성
const Book = ( props ) => {
return (
<>
< h1 > 도서 관리 화면 </ h1 >
</>
);
};
export default Book ;
index.js 구문 추가
import React from 'react';
import ReactDOM from 'react-dom/client';
//link 대신 import를 통해 설치한 라이브러리 CSS를 불러오도록 처리
//- node_modules에 설치한 요소들은 바로 이름을 사용하여 접근 가능
import "bootstrap/dist/css/bootstrap.min.css";
//이곳에 bootswatch css파일을 불러오는 구문을 작성
import "bootswatch/dist/lumen/bootstrap.min.css";
import "bootstrap";
import App from './App';
import reportWebVitals from './reportWebVitals';
//Router는 React 앱을 여러 페이지로 분할하여 사용하도록 만드는 기술
//- HashRouter는 주소에 해시(#)가 포함된다.
//- BrowserRouter는 주소에 해시(#)가 포함되지 않는다.
import {HashRouter} from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<HashRouter>
<App />
</HashRouter>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
App.js 구문 수정
import { NavLink , Route , Routes } from "react-router-dom" ;
import Pocketmon from "./components/Pocketmon" ;
import Book from "./components/Book" ;
import Home from "./components/Home" ;
import Menu from "./components/Menu.js" ;
function App () {
return (
< div className = "container-fluid" >
{ /* 상단 메뉴 영역 */ }
< Menu />
{ /* 본문 영역 */ }
< div >
< Routes >
< Route exact path = "/" element = { < Home /> } ></ Route >
< Route path = "/pocketmon" element = { < Pocketmon /> } ></ Route >
< Route path = "/book" element = { < Book /> } ></ Route >
</ Routes >
</ div >
</ div >
);
}
export default App ;
Menu.js 생성
import { NavLink , useLocation } from "react-router-dom" ;
import "bootstrap/dist/js/bootstrap.js" ;
const Menu = props => {
const location = useLocation ();
//console.log(location.pathname);
return (
<>
< nav className = "navbar navbar-expand-lg bg-dark" data-bs-theme = "dark" >
< div className = "container-fluid" >
< NavLink className = "navbar-brand" to = "/" > KH정보교육원 </ NavLink >
< button className = "navbar-toggler" type = "button" data-bs-toggle = "collapse" data-bs-target = "#navbarColor02" aria-controls = "navbarColor02" aria-expanded = "false" aria-label = "Toggle navigation" >
< span className = "navbar-toggler-icon" ></ span >
</ button >
< div className = "collapse navbar-collapse" id = "navbarColor02" >
< ul className = "navbar-nav me-auto" >
< li className = "nav-item" >
< NavLink className = { `nav-link ${ location . pathname === '/pocketmon' ? 'active' : '' } ` } to = "/pocketmon" > 포켓몬 </ NavLink >
</ li >
< li className = "nav-item" >
< NavLink className = { `nav-link ${ location . pathname === '/book' ? 'active' : '' } ` } to = "/book" > 도서 </ NavLink >
</ li >
</ ul >
</ div >
</ div >
</ nav >
</>
);
};
export default Menu ;
이런 식으로
npm install axios : axios 라이브러리 다운
Pocketmon.js 구문 수정
import { useEffect , useState } from "react" ;
import axios from "axios" ;
const Pocketmon = ( props ) => {
const [ pocketmonList , setPocketmonList ] = useState ([]);
useEffect (() => {
//서버에서 pocketmon list를 불러와서 state에 설정하는 코드
axios ({
url : "http://localhost:8080/pocketmon/" ,
method : "get"
})
. then ( response => {
// console.log(response);
setPocketmonList ( response . data );
})
. catch ( err => {});
}, []);
return (
<>
< div className = "row" >
< div className = "col" >
< h1 > 포켓몬 관리 </ h1 >
< p > React CRUD 연습 예제 </ p >
</ div >
</ div >
< div className = "row mt-4" >
< div className = "col" >
< table className = "table" >
< thead >
< tr >
< th > 번호 </ th >
< th > 이름 </ th >
< th > 속성 </ th >
< th ></ th >
</ tr >
</ thead >
< tbody >
{ pocketmonList . map ( pocketmon => (
< tr key = { pocketmon . no } >
< td > { pocketmon . no } </ td >
< td > { pocketmon . name } </ td >
< td > { pocketmon . type } </ td >
</ tr >
)) }
</ tbody >
</ table >
</ div >
</ div >
</>
);
};
export default Pocketmon ;
Book.js 구문 수정
import axios from "axios" ;
import { useEffect , useState } from "react" ;
import { FaXmark } from "react-icons/fa6" ;
import { FaRegEdit } from "react-icons/fa" ;
import "./Book.css" ;
const Book = ( props ) => {
const [ bookList , setBookList ] = useState ([]);
useEffect (() => {
//서버에 있는 도서 정보를 불러와서 state에 반영하는 코드
axios ({
url : "http://localhost:8080/book/" ,
method : "get"
})
. then ( response => {
setBookList ( response . data );
})
. catch ( err => {
window . alert ( "통신 오류 발생!" )
});
}, []);
return (
<>
< div className = "row" >
< div className = "col" >
< h1 > 도서 관리 </ h1 >
< p > React CRUD 연습 예제 </ p >
</ div >
</ div >
< div class = "row mt-4" >
< div className = "col" >
< table className = "table" >
< thead className = "table-info" >
< tr >
< th className = "pc-only" > 번호 </ th >
< th > 제목 </ th >
< th > 저자 </ th >
< th className = "pc-only" > 출간일 </ th >
< th > 가격 </ th >
< th > 출판사 </ th >
< th className = "pc-only" > 페이지수 </ th >
< th className = "pc-only" > 장르 </ th >
< th > 관리 </ th >
</ tr >
</ thead >
< tbody >
{ bookList . map ( book => (
< tr key = { book . bookId } >
< td className = "pc-only" > { book . bookId } </ td >
< td > { book . bookTitle } </ td >
< td > { book . bookAuthor } </ td >
< td className = "pc-only" > { book . bookPublicationDate } </ td >
< td > { book . bookPrice } </ td >
< td > { book . bookPublisher } </ td >
< td className = "pc-only" > { book . bookPageCount } </ td >
< td className = "pc-only" > { book . bookGenre } </ td >
< td >
{ /* 수정버튼 */ }
< FaRegEdit
className = "text-warning ms-1"
/>
{ /* 삭제버튼 */ }
< FaXmark
className = "text-danger"
/>
</ td >
</ tr >
)) }
</ tbody >
</ table >
</ div >
</ div >
</>
);
};
export default Book ;
Book.css 생성
@media screen and ( max-width : 768px ) {
.pc-only {
display : none ;
}
}
화면이 작아지면 항목이 줄어든다.
App.js 수정
import { NavLink , Route , Routes } from "react-router-dom" ;
import Pocketmon from "./components/Pocketmon" ;
import Book from "./components/Book" ;
import Home from "./components/Home" ;
import Menu from "./components/Menu.js" ;
function App () {
return (
< div className = "container-fluid my-5 py-5" >
{ /* 상단 메뉴 영역 */ }
< Menu />
{ /* 본문 영역 */ }
< div className = "row" >
< div className = "col-sm-10 offset-sm-1" >
< Routes >
< Route exact path = "/" element = { < Home /> } ></ Route >
< Route path = "/pocketmon" element = { < Pocketmon /> } ></ Route >
< Route path = "/book" element = { < Book /> } ></ Route >
</ Routes >
</ div >
</ div >
</ div >
);
}
export default App ;
Pocketmon.js 삭제 구문 추가
import { useState , useEffect } from "react" ;
import axios from "axios" ;
import { LiaEdit } from "react-icons/lia" ;
import { AiFillDelete } from "react-icons/ai" ;
const Pocketmon = ( props ) => {
const [ pocketmonList , setPocketmonList ] = useState ([]);
//서버에서 pocketmon list를 불러와서 state에 설정하는 코드
const loadPocketmon = () => {
axios ({
url : "http://localhost:8080/pocketmon/" ,
method : "get"
})
. then ( response => {
//console.log(response);
setPocketmonList ( response . data );
})
. catch ( err => {});
};
useEffect (() => {
loadPocketmon ();
}, []);
//포켓몬스터 삭제
//- 이제는 state에서 삭제하는 것이 아니라 서버에 통신을 보낸 뒤 목록을 갱신하면 된다
const deletePocketmon = ( pocketmon ) => {
const choice = window . confirm ( "정말 삭제하시겠습니까?" );
if ( choice === false ) return ;
//axios({옵션}).then(성공시 실행할 함수).catch(실패시 실행할 함수);
axios ({
url : `http://localhost:8080/pocketmon/ ${ pocketmon . no } ` ,
method : "delete"
})
. then ( response => {
loadPocketmon (); //목록 갱신
})
. catch ( err => {});
};
return (
<>
< div className = "row" >
< div className = "col" >
< h1 > 포켓몬스터 관리 </ h1 >
< p > React CRUD 연습 예제 </ p >
</ div >
</ div >
< div className = "row mt-4" >
< div className = "col" >
< table className = "table" >
< thead >
< tr >
< th > 번호 </ th >
< th > 이름 </ th >
< th > 속성 </ th >
< th ></ th >
</ tr >
</ thead >
< tbody >
{ pocketmonList . map ( pocketmon => (
< tr key = { pocketmon . no } >
< td > { pocketmon . no } </ td >
< td > { pocketmon . name } </ td >
< td > { pocketmon . type } </ td >
< td >
{ /* 아이콘 자리 */ }
< LiaEdit className = "text-warning" />
< AiFillDelete className = "text-danger"
onClick = { e => deletePocketmon ( pocketmon ) } />
</ td >
</ tr >
)) }
</ tbody >
</ table >
</ div >
</ div >
</>
);
};
export default Pocketmon ;
Pocketmon.js 등록 구문 모달로 추가 (구현중)
import { useState , useEffect , useRef } from "react" ;
import axios from "axios" ;
import { LiaEdit } from "react-icons/lia" ;
import { AiFillDelete , AiOutlinePlus } from "react-icons/ai" ;
import { Modal } from "bootstrap" ;
const Pocketmon = ( props ) => {
const [ pocketmonList , setPocketmonList ] = useState ([]);
//서버에서 pocketmon list를 불러와서 state에 설정하는 코드
const loadPocketmon = () => {
axios ({
url : "http://localhost:8080/pocketmon/" ,
method : "get"
})
. then ( response => {
//console.log(response);
setPocketmonList ( response . data );
})
. catch ( err => {});
};
useEffect (() => {
loadPocketmon ();
}, []);
//포켓몬스터 삭제
//- 이제는 state에서 삭제하는 것이 아니라 서버에 통신을 보낸 뒤 목록을 갱신하면 된다
const deletePocketmon = ( pocketmon ) => {
const choice = window . confirm ( "정말 삭제하시겠습니까?" );
if ( choice === false ) return ;
//axios({옵션}).then(성공시 실행할 함수).catch(실패시 실행할 함수);
axios ({
url : `http://localhost:8080/pocketmon/ ${ pocketmon . no } ` ,
method : "delete"
})
. then ( response => {
loadPocketmon (); //목록 갱신
})
. catch ( err => {});
};
//modal 관련된 처리
const bsModal = useRef ();
const openModal = () => {
const modal = new Modal ( bsModal . current );
modal . show ();
};
const closeModal = () => {
const modal = Modal . getInstance ( bsModal . current );
modal . hide ();
};
//등록과 관련된 state
const [ pocketmon , setPocketmon ] = useState ({ name : "" , type : "" });
const changePocketmon = ( e ) => {
setPocketmon ({
... pocketmon ,
[ e .target.name] : e . target . value
});
};
return (
<>
< div className = "row" >
< div className = "col" >
< h1 > 포켓몬스터 관리 </ h1 >
< p > React CRUD 연습 예제 </ p >
</ div >
</ div >
{ /* 추가 버튼 */ }
< div className = "row mt-4" >
< div className = "col text-end" >
< button className = "btn btn-success" onClick = { openModal } >
< AiOutlinePlus />
추가
</ button >
</ div >
</ div >
{ /* 출력 위치 */ }
< div className = "row mt-4" >
< div className = "col" >
< table className = "table" >
< thead >
< tr >
< th > 번호 </ th >
< th > 이름 </ th >
< th > 속성 </ th >
< th ></ th >
</ tr >
</ thead >
< tbody >
{ pocketmonList . map ( pocketmon => (
< tr key = { pocketmon . no } >
< td > { pocketmon . no } </ td >
< td > { pocketmon . name } </ td >
< td > { pocketmon . type } </ td >
< td >
{ /* 아이콘 자리 */ }
< LiaEdit className = "text-warning" />
< AiFillDelete className = "text-danger"
onClick = { e => deletePocketmon ( pocketmon ) } />
</ td >
</ tr >
)) }
</ tbody >
</ table >
</ div >
</ div >
{ /* Modal */ }
< div className = "modal fade" ref = { bsModal }
data-bs-backdrop = "static" tabIndex = "-1" role = "dialog" aria-hidden = "true" >
< div className = "modal-dialog" role = "document" >
< div className = "modal-content" >
< div className = "modal-header" >
< h5 className = "modal-title" > 제목 </ h5 >
< button type = "button" className = "close" data-dismiss = "modal" aria-label = "Close" >
< span aria-hidden = "true" > × </ span >
</ button >
</ div >
< div className = "modal-body" >
< div className = "row" >
< div className = "col" >
< label className = "form-label" > 이름 </ label >
< input type = "text" name = "name" className = "form-control"
value = { pocketmon . name } onChange = { changePocketmon } />
</ div >
</ div >
< div className = "row mt-4" >
< div className = "col" >
< label className = "form-label" > 속성 </ label >
< input type = "text" name = "type" className = "form-control"
value = { pocketmon . type } onChange = { changePocketmon } />
</ div >
</ div >
</ div >
< div className = "modal-footer" >
< button className = "btn btn-secondary" onClick = { closeModal } > 닫기 </ button >
< button className = "btn btn-success" > 저장 </ button >
</ div >
</ div >
</ div >
</ div >
</>
);
};
export default Pocketmon ;
pocketmon-mapper.xml
<? xml version = "1.0" encoding = "UTF-8" ?>
<! DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd " >
< mapper namespace = "pocketmon" >
< select id = "list" resultType = "PocketmonDto" >
select * from pocketmon order by no asc
</ select >
< insert id = "save" >
insert into pocketmon (no, name, type) values(pocketmon_seq.nextval, #{name}, #{type})
</ insert >
< delete id = "remove" >
delete pocketmon where no = #{no}
</ delete >
< select id = "find" resultType = "PocketmonDto" >
select * from pocketmon where no = #{no}
</ select >
< update id = "edit" >
update pocketmon
set
< if test = "dto.no > 0" >
no=#{dto.no},
</ if >
name=#{dto.name}, type=#{dto.type}
where no = #{no}
</ update >
< update id = "editUnit" >
update pocketmon
< set >
< if test = "dto.no > 0" > no = #{dto.no}, </ if >
< if test = "dto.name != null" > name = #{dto.name}, </ if >
< if test = "dto.type != null" > type = #{dto.type}, </ if >
</ set >
where no = #{no}
</ update >
</ mapper >