imsapi 프로젝트 - imsfront 리액트
이클립스의 imsapi프로젝트와 리액트의 ims front 연결하기
1. 서로 다른 사이트간의 통신
- imsapi -> http://localhost:9001
- ims front -> http://localhost:3000
- imsapi 프로젝트의 기본패키지에 WebMvcConfigurer를 상속하는 클래스 생성
@Configuration
public class WebMvcConfiguerImpl implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true) //인증정보 허용
.maxAge(3600); //초 단위고 3600초 1시간동안 열어두겠다는 뜻
}
}
2. App.js
- Route 사용방법: 터미널을 열고 react-router-dom 설치
- npm install react-router-dom 입력 후 엔터
function App() {
return (
<BrowserRouter>
<div className="App">
<Routes>
<Route path="/" Component={ItemList}/>
<Route path="/detail/:id" Component={ItemDetail}/>
<Route path="/update/:id" Component={ItemUpdate}/>
<Route path="/create" Component={ItemCreate}/>
<Route path="/*" Component={EmptyPage}/>
</Routes>
</div>
</BrowserRouter>
);
}
export default App; // 이하 생략
3. EmptyPage.js
import React from 'react' // 이하 import는 생략
function EmptyPage() {
return (
<div>
지원하지 않는 서비스입니다.
</div>
)
}
4. ItemList.js
- 아이템 목록 가져오기
function ItemList() {
const [items, setItems] = useState([]);
function getItemAll() {
let url = "http://localhost:9001/item/all";
let options = {
method: "GET",
headers: {
"Content-Type": "application/json",
},
};
fetch(url, options)
.then((res) => {
if (!res.ok) {
alert("실패");
throw new Error("자료를 못 가져왔음.");
}
return res.json();
})
.then((data) => {
setItems(data.list)
})
}
useEffect(getItemAll, [])
return (
<div>
{
items.length > 0 &&
items.map(item =>
<ItemComp key={item.id} item={item} />)
}
</div>
)
}
- useEffect : 컴포넌트가 처음 렌더링 될 때, 업데이트로 렌더링 될 때, 종료될 때 실행되는 기능
- 구조 : useEffect(콜백함수명, 디펜던시 어레이)
- useEffect(콜백함수, );-> 해당 컴포넌트가 렌더링 될 때마다 콜백함수가 실행됨.
- useEffect(콜백함수, [ ]);-> 해당 컴포넌트가 처음 렌더링 될 때만 콜백함수가 실행됨. 딱 한 번만
- useEffect(콜백함수, [a, b]);-> a 또는 b에 의해서 해당 컴포넌트가 렌더링 될 때마다 콜백함수가 실행됨.
5. ItemComp.js
- 아이템목록에 표시되는 형태
function ItemComp(props) {
return (
<div>
<div className="item">
<p>{props.item.id}</p>
<p>
<Link to={`detail/${props.item.id}`}>
{props.item.itemName}
</Link>
</p>
<p>{props.item.price}</p>
<p>{props.item.discount}</p>
<p>{props.item.price * (100 - props.item.discount) / 100}</p>
<p>{props.item.updateDate}</p>
</div>
</div>
)
}
6. ItemDetail.js
- 아이템 자세히 보기, 아이템 삭제
function ItemDetail() {
const [item, setItem] = useState(null)
const [id] = useState(useParams().id)
const navigate = useNavigate()
function getItemById() {
let url = `http://localhost:9001/item/id/${id}`;
let options = {
method: "GET",
headers: {
"Content-Type": "application/json",
},
};
fetch(url, options)
.then((res) => {
if (!res.ok) {
alert("실패");
throw new Error("자료를 못 가져왔음.");
}
return res.json();
})
.then((data) => {
setItem(data.dto)
})
}
useEffect(getItemById, [id])
function processDeleteFn() { // 삭제 이벤트 함수
let yes = window.confirm("정말로 삭제할래요?")
if(yes){
let url = "http://localhost:9001/item"
let options = {
method: "DELETE",
headers:{
"Content-Type" : "application/json"
},
body:JSON.stringify({
id:id
})
}
fetch(url, options)
.then(res =>{
if(!res.ok){
alert("삭제 실패")
throw new Error("삭제 중 에러 발생")
}
return res.json();
})
.then(data =>{
// window.location.assign("/")
navigate("/")
});
}
}
return (
<div>
<h2>아이템 상세히 보기</h2>
{
item !== null &&
<><div className="item">
<p>{item.id}</p>
<p>{item.itemName}</p>
<p>{item.price}</p>
<p>{item.discount}</p>
<p>{item.salePrice}</p>
<p>{item.itemDescribe}</p>
<p>{item.staff}</p>
<p>{moment(item.updateDate).format("YYYY-MM-DD HH:mm:ss")}</p>
</div>
<Link to={"/"}>HOME</Link> |
<Link to={ `/update/${item.id}` }>수정</Link> |
<Link onClick={processDeleteFn}>삭제</Link> |
<Link to={"/create"}>등록</Link>
</>
}
</div>
)
}
7. ItemCreate.js
- 아이템 생성
1) form태그 안에 있는 input태그의 값 가져오기
- useRef사용
- 렌더링을 유발하지 않는 훅.
- 사용방법 : const idRef = useRef( );
<input ref={idRef} />
2) useRef에 데이터를 저장하면, current라는 속성명으로 값이 저장됨.
따라서 useRef에 저장된 값을 사용하려면 아래와 같이 사용
let id = idRef.current.value;
3) 화면에 들어왔을 때, 첫 번째 input태그에서 커서가 깜빡거리게 하기 위해 useRef와 useEffect 훅 사용
function ItemCreate() {
const navigate = useNavigate(); // 등록 성공하면, item 자세히 보기로 가게 하기 위해서 등록
const [staff] = useState("m1000");
//시작: useRef 등록 시작
const itemNameRef = useRef();
const priceRef = useRef();
const discountRef = useRef();
const eaRef = useRef();
const itemDescribeRef = useRef();
//끝: useRef 등록 끝
//시작: 아이템 등록 시작
function onSubmitHandler(event) {
event.preventDefault();
// 각각의 input 태그에 입력된 값 가져오기
let itemName = itemNameRef.current.value
let price = priceRef.current.value;
let discount = discountRef.current.value;
let ea = eaRef.current.value;
let itemDescribe = itemDescribeRef.current.value;
let url = "http://localhost:9001/item"
let options = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({//속성명과 속성값이 들어 있는 변수명이 같으면 이렇게 사용 가능
itemName,
price,
discount,
ea,
itemDescribe,
staff
})
}
fetch(url, options)
.then(res => {
if (!res.ok) {
alert("등록 실패");
throw new Error("등록 중 에러가 발생했습니다.");
}
return res.json();
})
.then(data => {
alert("입력 성공");
// window.location.href="/detail/"+data.dto.id;
navigate(`/detail/${data.dto.id}`)// 등록 성공하면 아이템 자세히 보기로 이동
})
}
//끝: 아이템 등록 끝
// 커서 깜빡거리는 코드
useEffect(() => {
itemNameRef.current.focus();
}, [])
return (
<div>
<h2>아이템 등록</h2>
<form action='#' onSubmit={onSubmitHandler}>
itemName: <input ref={itemNameRef} /><br />
price: <input type='number' ref={priceRef} /><br />
discount: <input type='number' ref={discountRef} /><br />
ea: <input ref={eaRef} /><br />
itemDescribe: <input ref={itemDescribeRef} /><br />
staff: <input value={staff} readOnly /><br />
<button>등록</button>
</form>
</div>
)
}
8. ItemUpdate.js
- 아이템 수정
- onSubmitHandler : 수정된 값을 db에 저장하는 함수
(다음에 formData 객체를 이용해서도 해봐야 함 -> 첨부파일 전송 가능)
- onInputHandler : input창에 뭔가를 입력할 때마다 호출되는 콜백함수
- formData와 다른점
: value값을 넣고 oninput핸들러를 만들어주면, 원래 저장된 값(value)가 그대로 출력돼있다.
따라서 아이템 정보 수정과 같은것들은 이런 방식으로 하고,
비밀번호 수정과 같은 것들은 formData를 활용한다.
- 리액트에서는 input태그에 value속성에 값을 입력하면, 어떤 값도 입력되지 않는다.
따라서 값을 입력할 수 있도록 onInput이벤트를 걸어줬고=(이벤트가 발생할 때마다 그 값이 변하도록 state관리),
그에 대한 콜백함수로 onInputHandler함수를 지정했다.
let name = event.target.name; // 어떤 속성이 바뀌었는지 알기 위한 속성명 획득 목적의 코드
let val = event.target.value; // input태그에 입력된 값을 받아 옴.
// 기존 item 객체의 정보를 복사해서 newItem 객체에 넣고
// 속성명이 담긴 name 변수와 바뀐 속성값이 담긴 val을 이용해서
// newItem의 특정 속성을 변경한다.
// 주의사항: 속성명 입력 시, [ ](대괄호)에 넣어야 인식됨.
let newItem = {...item,[name]:val};
setItem(newItem);
function ItemUpdate() {
const navigate = useNavigate();
const [item, setItem] = useState(null);
const [id] = useState(useParams().id);
function getItemById() {
let url = `http://localhost:9001/item/id/${id}`;
let options = {
method: "GET",
headers: {
"Content-Type": "application/json",
},
};
fetch(url, options)
.then((res) => {
if (!res.ok) {
alert("실패");
throw new Error("자료를 못 가져왔음.");
}
return res.json();
})
.then((data) => {
setItem(data.dto)
})
}
useEffect(getItemById,[id]);
// 수정된 값을 db에 저장하는 코드
function onSubmitHandler(e){
e.preventDefault();
let url = "http://localhost:9001/item"
let options = {
method : "PUT",
headers : {
"Content-Type" : "application/json"
},
body : JSON.stringify({
id: item.id,
itemName: item.itemName,
price: item.price,
discount: item.discount,
ea: item.ea,
itemDescribe: item.itemDescribe,
staff: item.staff
})
}
fetch(url, options)
.then(res=>{
if(!res.ok){
alert("수정 실패")
throw new Error("에러 발생")
}
return res.json();
})
.then(data=>{
alert("수정 성공");
navigate(`/detail/${id}`);
})
.catch(error=>{
console.log(error.message);
})
}
function onInputHandler(event){
let name = event.target.name;
let val = event.target.value;
let newItem = {...item,[name]:val};
setItem(newItem);
}
return (
<div>
<h2>아이템 수정</h2>
{
item !== null &&
<form action='#' onSubmit={onSubmitHandler}>
itemName : <input onInput={onInputHandler} name='itemName' value={item.itemName} /><br/>
price : <input onInput={onInputHandler} name='price' value={item.price} /><br/>
discount : <input onInput={onInputHandler} name='discount' value={item.discount} /><br/>
salePrice : <input value={item.price*(100-item.discount)/100} disabled /><br/>
ea : <input onInput={onInputHandler} name='ea' value={item.ea} /><br/>
itemDescribe : <input onInput={onInputHandler} name='itemDescribe' value={item.itemDescribe} /><br/>
<button>수정 완료</button>
</form>
}
</div>
)
}