스프링(서버)
1. mapper
- namespace를 지정하여 다른 mapper와 구분지어준다.
<?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="com.example.mapper.BookMapper">
<insert id="insert">
insert into books(title,price,author,image) values (#{title},#{price},#{author},#{image})
</insert>
2. BookVO 생성하기
- DB의 테이블 컬럼명과 동일하게 주는 것이 좋다
- getter, setter 메소드 생성해서 외부 파일에서 사용할 수 있도록 해줌
private int code;
private String title;
private int price;
private String author;
private String image;
private int viewcnt;
private String content;
3. BookDAO 생성
- 인터페이스로 만든다
public interface BookDAO {
public void insert(BookVO vo);
}
4. BookDAOImpl 생성
- DAO 구현체
@Repository
public class BookDAOImpl implements BookDAO{
@Autowired
SqlSession session;
String namespace="com.example.mapper.BookMapper";
@Override
public void insert(BookVO vo) {
session.insert(namespace+".insert",vo);
}
}
- 해당 mapper의 namespace를 지정하여 id가 Insert인 sql문을 실행하여 vo값을 넘겨준다
5. BookController 생성
- 데이터 처리만 하기 위해 @RestController 어노테이션을 지정해준다.
- 기본 경로는 books로 @RequestMapping 어노테이션으로 지정
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
BookDAO dao;
@RequestMapping(value="/insert", method=RequestMethod.POST)
public void insert(BookVO vo, MultipartHttpServletRequest multi) {
try {
if(multi.getFile("file")!=null) {
MultipartFile file = multi.getFile("file");
String path = "/Users/sy/images/books/";
String fileName = System.currentTimeMillis()+".jpg";
file.transferTo(new File(path+fileName));
vo.setImage(fileName);
}
dao.insert(vo);
}catch(Exception e) {
System.out.println("도서등록오류"+e.toString());
}
}
}
- MultipartHttpServletRequest는 멀티파트 요청에서 전송된 데이터를 처리하기 위한 클래스로 파일데이터를 가져온다.
- MultipartFile로 멀티파트 요청에서 file필드를 가져온다
* getFile로 가져온 file필드는 은 요청 보내줄 때 이름을 동일하게 file로 작성해야함
- try~catch문으로 등록 오류시 메세지 출력
- path변수에는 파일을 저장할 폴더 경로 지정, fileName에는 저장할 파일 이름 지정
* System.currentTimeMillis()는 1970.1.1~현재까지의 시간을 밀리초 단위로 반환해주는 메소드, 파일 식별자 생성시 주로 사용됨
- vo의 image필드에 새로 생성한 fileName으로 이미지를 저장한다.
리액트
1. 폼 상태변수 생성 & 비구조화 할당
const [form, setForm] = useState({
title:"",
author:"",
price: "",
file: null
});
const {title, author, price, file} = form;
- 폼 안에 있는 각각의 input태그에다 각각의 속성을 value값으로 담아주고 동일한 이름을 name="속성명"으로 작성한다
2. 폼내용 변경함수 onChange
const onChange = (e) => {
setForm({
...form,
[e.target.name]: e.target.value
})
}
- value값을 준 input상자는 값이 변하지 않기 때문에 함수를 만들어주어야 한다.
- setForm으로 기존 폼 데이터를 복사하고 (...form), 여러 input중 해당 이름과 동일한 value값을 현재 입력한 값으로 변경해준다.
3. 등록버튼 눌렀을 때 실행할 함수 onClickInsert
const onClickInsert = (e) => {
e.preventDefault();
if (!title || !author || !price || !file) {
setBox({
show: true,
message: "모든 필드를 채워주세요"
})
return;
}
setBox({
show: true,
message: "도서를 등록하시겠습니까?",
action: onInsert
})
}
- 각각의 input 상자가 공백일 경우 유효성 체크를 해준 다음 Insert 작업을 해준다
4. 도서등록 함수 onInsert
* 업로드할 파일이 없을 경우는 axios에 form객체만 넘겨주면 된다.
const onInsert = async () => {
const formData = new FormData();
formData.append("title", title);
formData.append("price", price);
formData.append("author", author);
formData.append("file", file);
const config = {
headers: { "content-type": "multipart/form-data" }
}
await axios.post('/books/insert', formData, config);
setBox({
show: true,
message: "도서 한권이 등록되었습니다"
})
history.push("/");
}
- HTML폼 데이터를 생성하기 위한 FormData 객체 생성 (키-값 쌍의 데이터를 담을 수 있다)
- append()메서드를 사용해 도서정보를 formData에 추가
- HTTP요청 헤더를 설정하기 위한 config변수 생성, 타입은 multipart/form-data로 지정
- 데이터등록을 처리해주는 Url에 데이터 담은 formData와 config를 넘겨주면 된다.
* config 생략시 axios.post 메서드에서 요청헤더 기본값이 application/json으로 설정되기 때문에 오류가 날 수 있어 명시해줘야함
5. return문 작성
return (
<Row className="justify-content-center my-5">
<Col md={8}>
<Card>
<h1 className="mt-3">도서정보</h1>
<Form className="px-5 py-5 text-center" onSubmit={onClickInsert}>
<InputGroup className='my-2'>
<InputGroup.Text className='px-5'>제목</InputGroup.Text>
<Form.Control value={title} onChange={onChange} name="title" />
</InputGroup>
<InputGroup className='my-2'>
<InputGroup.Text className='px-5'>가격</InputGroup.Text>
<Form.Control name="price" value={price} onChange={onChange} />
</InputGroup>
<InputGroup className='my-2'>
<InputGroup.Text className='px-5'>저자</InputGroup.Text>
<Form.Control name="author" value={author} onChange={onChange} />
</InputGroup>
<div className='my-3'>
<img src={fileName} width="30%" />
<Form.Control type="file" className="my-2" onChange={onChangeFile} />
</div>
<div className='mt-3 text-center'>
<Button className='me-2' type="submit">등록하기</Button>
<Button variant='secondary'>취소</Button>
</div>
</Form>
</Card>
</Col>
</Row>
)
'FE > React' 카테고리의 다른 글
리액트로 에디터 생성하기 (CKEditor 라이브러리) + 부트스트랩 Tap (0) | 2023.05.09 |
---|---|
리액트 구글 차트 사용법 (react google charts 라이브러리) (0) | 2023.05.08 |
React Context API 사용법 및 Props와 Context차이점 (0) | 2023.03.16 |
리액트로 라우터 생성하기 (react-router-dom & qs 라이브러리) (0) | 2023.03.09 |
React - 카카오 API를 이용한 도서검색 (axios라이브러리, async, await) (0) | 2023.03.06 |