코딩항해기
[Spring] 파일 입출력 MultipartFile 본문
MultipartFile을 사용해 이미지 파일을 업로드할 수 있다.
먼저 MultipartFile로 이미지 파일을 업로드 받기 위해서는 몇 가지 환경을 조성해야한다.
DTO에 MultipartFile을 타입으로 갖는 필드 추가
해당 필드를 통해 view로부터 전송되는 MultipartFile을 자동 주입 받을 수 있게 된다.
@Getter @Setter @ToString
public class ImageDTO {
private int imageId;
private String path;
private int bid;
private MultipartFile image;
}
이때 MultipartFile를 자동으로 import하지 못하는 경우 의존성을 추가한다.
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
ImageDAO, ImageServiceImpl
더보기
@Repository
public class ImageDAO {
private final String SELECTONE = "SELECT IMAGEID, PATH, BID FROM IMAGE WHERE BID=? ORDER BY IMAGEID DESC LIMIT 1";
private final String INSERT = "INSERT INTO IMAGE (PATH,BID) VALUES(?,?)";
@Autowired
private JdbcTemplate jdbcTemplate;
private List<ImageDTO> selectAll(ImageDTO imageDTO){
List<ImageDTO> datas = new ArrayList<ImageDTO>();
return datas;
}
public ImageDTO selectOne(ImageDTO imageDTO) {
Object[] args = {imageDTO.getBid()};
return jdbcTemplate.queryForObject(SELECTONE, args, new ImageMapper());
}
public boolean insert(ImageDTO imageDTO) {
return jdbcTemplate.update(INSERT, imageDTO.getPath(), imageDTO.getBid())>0;
}
private boolean update(ImageDTO imageDTO){
return false;
}
private boolean delete(ImageDTO imageDTO){
return false;
}
}
class ImageMapper implements RowMapper<ImageDTO>{
@Override
public ImageDTO mapRow(ResultSet rs, int i) throws SQLException {
ImageDTO data = new ImageDTO();
data.setImageId(rs.getInt("IMAGEID"));
data.setPath(rs.getString("PATH"));
data.setBid(rs.getInt("BID"));
return data;
}
}
@Service
public class ImageServiceImpl implements ImageService {
@Autowired
private ImageDAO imageDAO;
@Override
public List<ImageDTO> selectAll(ImageDTO imageDTO) {
return List.of();
}
@Override
public ImageDTO selectOne(ImageDTO imageDTO) {
return imageDAO.selectOne(imageDTO);
}
@Override
public boolean insert(ImageDTO imageDTO) {
return imageDAO.insert(imageDTO);
}
@Override
public boolean update(ImageDTO imageDTO) {
return false;
}
@Override
public boolean delete(ImageDTO imageDTO) {
return false;
}
}
View에 이미지 파일을 받을 form태그 추가
<%--MultipartFile을 다룰 것임을 알려주는 enctype 속성--%>
<form action="updateBoard.do" method="POST" enctype="multipart/form-data">
<%--현재 게시글 번호--%>
<input type="hidden" name="bid" value="${data.bid}">
<%--입력받을 이미지--%>
이미지 <input type="file" name="image" onchange="preview(event)"> <br>
<%--입력받은 이미지를 미리 보여줄 이미지 태그--%>
<img id="previewImage" style="display:none;margin:5px;" alt="미리보기 이미지"><br>
<%--전송--%>
<input type="submit" value="이미지 변경">
</form>
이제 이미지를 입력받는 부분과 DB를 처리하는 부분이 완성됐다.
받은 파일을 서버에 저장하고, DB에게 파일명을 전달하는 역할을 수행하는 Controller 파트를 작업하면된다.
Controller
@RequestMapping("/updateBoard.do")
public String updateBoard(BoardDTO boardDTO, ImageDTO imageDTO) throws IOException {
//boardService.update(boardDTO); //이미지 수정만 진행할 예정
log.info("log: /updateBoard.do updateBoard start");
MultipartFile file = imageDTO.getImage(); //MultipartFile타입을 가진 필드에 자동 주입된 데이터를 저장
String fileName = file.getOriginalFilename(); //MultipartFile의 이름 추출
log.info("path : [{}]", PATH+fileName);
file.transferTo(new File(PATH+fileName)); //지정된 경로에 추출한 이름으로 저장
imageDTO.setPath(fileName); //해당 이름을 DB로 전달하기 위해 저장
imageService.insert(imageDTO); //DB에 추가
//수정한 글 상세 페이지로 이동
return "redirect:/boardInfo.do?bid="+boardDTO.getBid();
}
저장한 이미지를 다시 출력할 때는 DB에서 저장한 파일명을 불러와 전달하기만하면 된다.
@RequestMapping("/boardInfo.do")
public String boardInfo(BoardDTO boardDTO, Model model, ImageDTO imageDTO) {
ImageDTO image = imageService.selectOne(imageDTO);
//만약 이미지가 존재한다면
if(image != null) { //NPE방지
//이미지 경로 전달
model.addAttribute("imgPath", image.getPath());
}
model.addAttribute("data", boardService.selectOne(boardDTO));
return "boardInfo";
}
추가로 이미지 미리보기 JS
function preview(event) {
console.log("js/preview.js");
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = function() {
const imgPreview = document.getElementById('previewImage');
imgPreview.src = reader.result;
imgPreview.style.display = 'block';
};
if (file) {
reader.readAsDataURL(file);
}
}
코드를 정상적으로 입력했는데도 오류가 발생할 때 context.xml에 속성추가하는 법
Multipart 메서드
메서드 | input | output | 설명 |
getName() | 없음 | String | 파일 필드 이름을 반환 |
getOriginalFilename() | 없음 | String | 업로드된 파일의 원본 이름 반환 |
getContentType() | 없음 | String | 파일의 MIME 타입 반환 (예: image/jpeg, text/plain) |
getSize() | 없음 | long | 파일의 크기를 바이트 단위 반환 |
isEmpty() | 없음 | boolean | 파일이 비어 있는지 여부 반환 (파일이 없거나 크기가 0일 때 true) |
getBytes() | 없음 | byte[] | 파일 내용을 바이트 배열 반환 |
getInputStream() | 없음 | InputStream | 파일의 내용을 읽을 수 있는 InputStream 반환 |
transferTo(File dest) | File | void | 업로드된 파일을 지정한 파일 경로 저장 |
transferTo(Path dest) | Path | void | 업로드된 파일을 지정한 경로(Path) 저장 |
*mkdirs같은 기능은 없음 File사용
'Spring' 카테고리의 다른 글
[Spring] JDBCTemplate : KeyHolder (0) | 2024.10.28 |
---|---|
[Spring] 경로 메서드 기록 (ServletContext, request, System) (0) | 2024.10.22 |
[Spring] AOP @Order 실행 우선 순위 설정 (0) | 2024.10.20 |
[Spring] AOP @AfterThrowing (0) | 2024.10.20 |
[Spring] springframework 트랜잭션 설정 (0) | 2024.10.18 |