먼저, 블로그 주인은 Java 개발 하급 실력이고 Spring은 이번에 처음 접해보는 것임을 알린다!!
최근 Spring을 이용해서 서버와 DB를 관리하고 Html과 Javascript로 웹으로의 구현을 연습하고 있다. (개발 선생님은 Chat GPT다.)
이미지 input, output 연습중에 만난 문제점과 그 해결법에 대해서 공유해보도록 하겠다.
목표
서버에 저장해 놓은 이미지 file을 ajax를 이용해서
버튼 click시 이미지를 웹에 출력하는것이 목표. (비동기적인 방법)
문제상황
1. 코드
<SaveImageService.java> 중 Html로부터 입력받은 file을 저장하는 saveImage 함수
public void saveImage(MultipartFile file, String sessionAttribute) throws IOException {
String fileName = file.getOriginalFilename();
if (fileName == null || fileName.isEmpty()) {
// 에러 처리 또는 기본값 설정
throw new IllegalArgumentException("파일 이름이 유효하지 않습니다.");
// 또는 fileName = "defaultFileName.jpg";
}
//이미지 저장할 경로 지정.
//static 하위에 Uploads/BackGroundImage폴더를 만들어두고 준비
Path uploadPath = Paths.get("src", "main", "resources", "static", "Uploads", "BackGroundImage").toAbsolutePath();
//ImageEntity를 만들어서 DB에 저장
ImageEntity imageEntity = new ImageEntity();
imageEntity.setFileName(fileName);
imageEntity.setFilePath(uploadPath.toString() + "/" + fileName);
imageEntity.setFileSize(file.getSize());
imageEntity.setUserName(sessionAttribute);
// 파일 복사 -> path에 저장
Path destinationPath = uploadPath.resolve(fileName);
System.out.println(destinationPath);
Files.copy(file.getInputStream(), destinationPath, StandardCopyOption.REPLACE_EXISTING);
//ImageEntity정보를 DB에 저장
bgRepository.saveToDB(imageEntity);
}
-Html로부터 받은 이미지 file을 서버에 저장한다.
-ImageEntity를 setter를 통해서 만들어주고 -> DB에 저장한다.
<ImageController.java> 중 Js ajax에 File url을 전송해주는 handleFileUpload 함수
@PostMapping("/BgImgMenu/inputImg")
@ResponseBody
//html상에서 name이 "Fileinput"인 요소를 통해 가져옴
public List<String> handleFileUpload(@RequestParam("Fileinput") MultipartFile file, HttpServletRequest request) {
//현재 로그인 된 세션
String sessionAttribute = memberService.getSessionAttribute(request, "userID");
try {
saveimageService.saveImage(file, sessionAttribute);
} catch (IOException e) {
e.printStackTrace(); // 실제 상황에 따라 적절한 예외 처리 로직을 추가해야 함.
}
//이미지 등록한 user기준으로 DB에서 imageEntity 정보를 모두 가져옴.
List<ImageEntity> ImageList = saveimageService.findImagesById(sessionAttribute);
//ajax를 이용해서 비동기적으로 전송하기 때문에 model로 보낼 필요가 없다.
//model.addAttribute("images", ImageList);
//list 형태로 ajax에 전달
List<String> imagePathsOrUrls = ImageList.stream()
.map(ImageEntity::getFilePath)//html에 출력하기 위해 이미지파일의 Url을 담음
.collect(Collectors.toList());
System.out.println("image-list!!!!");
System.out.println(imagePathsOrUrls);
//이미지 경로를 담은 list 반환
return imagePathsOrUrls;
}
-DB에서 원하는 ImageEntity를 가져와서 List에 담아준다.
-ImageEntity중에 path정보(url에 해당)를 추출해서 List에 담아준다.
-Javascript의 ajax에서 사용할 수 있도록 path(url) List를 전송한다.
<ImageInput.html>의 Javascript 일부분
function uploadFile(){
var fileInput = $('#Fileinput')[0];
var file = fileInput.files[0];
if (file) {
var formData = new FormData();
formData.append('Fileinput', file);
$.ajax({
type: 'POST',
url: '/BgImgMenu/inputImg',
data: formData,
contentType: false,
processData: false,
success: function(response) {
// 처리 완료 후의 동작을 여기에 추가할 수 있습니다.
//기존 데이터 지우고 새로 로드해야함.
$(".imageContainer").empty();
console.log(response);
for (var i = 0; i < response.length; i++) {
var imageUrl = response[i].replace(/\\/g, "/");
console.error('이미지 url : ' + imageUrl)
// 이미지가 존재하는지 확인
$.get(imageUrl)
.done(function() {
//새로 로드
$(".imageContainer").append('<img src="' + imageUrl + '" alt="Image" width=300 height=300>')
})
.fail(function() {
// 이미지가 존재하지 않으면 오류 메시지 출력
console.error('Image not found: ' + imageUrl);
});
}
},
error: function(error) {
console.log(error);
}
});
} else {
alert('파일을 선택하세요.');
}
}
-웹에서 특정 버튼을 누르면 수행된다.
-handleFileUpload 함수로부터 이미지 path(url) List를 받아 화면에 출력한다.
-포문을 통해 List를 돌면서 해당되는 파일을 전부 출력할 수 있도록 했다.
-class이름이 imageContainer인 요소를 찾아서 img 태그를 이용해 이미지를 넣도록 한다.
2. 결과
-파일 경로는 정확히 나오지만 이미지가 출력되지 않는 오류가 발생했다.
-Not allowed to load local resource 오류가 발생
-파랑색으로 하이퍼링크 걸린 주소를 복붙해서 주소창에 붙여보면 내가 업로드 한 사진이 나온다. (=경로를 잘못 지정한 상황은 아님)
해결방법
저번 포스팅에서도 비슷한 문제가 나타났었는데, 기본적으로 Static이 기본 경로이기 때문에 Static 이후부터 경로에 포함시켜야 한다. 따라서 JavaScrpit에서 받을 List 형식이['/Uploads/BackGroundImage/파일명.확장자명'] 이런식으로 온다면 해결 될 가능성이 높을것이라고 생각했다.
Controller에서 ImageEntity의 path를 가져올 때 DB에서 가져오므로, 애초에 DB에 저장 할 때 경로를 "C:~~"로 저장하지 말고 Static이후의 "/Uploads~~"로 저장하기로 결정
1. 수정
<SaveImageService.java> 중 Html로부터 입력받은 file을 저장하는 saveImage 함수
public void saveImage(MultipartFile file, String sessionAttribute) throws IOException {
//생략
//이미지 저장할 경로 지정.
Path uploadPath = Paths.get("src", "main", "resources", "static", "Uploads", "BackGroundImage").toAbsolutePath();
//DB 저장 할 때 파일 저장 할 때 사용하는 path 이용하지 말고 직접 지정
String str_path = "/Uploads/BackGroundImage";
//ImageEntity를 만들어서 DB에 저장
ImageEntity imageEntity = new ImageEntity();
imageEntity.setFileName(fileName);
//객체에 저장할 때 만들어뒀던 path이용
imageEntity.setFilePath(str_path + "/" + fileName);
imageEntity.setFileSize(file.getSize());
imageEntity.setUserName(sessionAttribute);
// 파일 복사 -> path에 저장
//저장 할 때는 기존에 사용하던 자료형이 Path인 uploadPath이용.
Path destinationPath = uploadPath.resolve(fileName);
System.out.println(destinationPath);
Files.copy(file.getInputStream(), destinationPath, StandardCopyOption.REPLACE_EXISTING);
//ImageEntity정보를 DB에 저장
bgRepository.saveToDB(imageEntity);
}
-내 코드는 객체 정보를이용해서 DB에 저장하는데, 이때 Path를 파일 저장경로와 동일하게 하지 않고
static 이후의 경로를 사용할 수 있도록 조작했다.
-근본적인 해결이 아닐 수 있음에 주의..!
2. 결과
결론
이미지 경로를 static 폴더 이후로 지정하니 해결 할 수 있었다.
또다른 문제점
그러나...
내가 만든 ajax에 뭔가 잘못된 것이 있는지, 동일한 상태에서 한번 더 파일 선택을 하면 이미지가 나오지 않는..오류가 있다..^^
이 상황에서, 폴더와 DB에는 정상적으로 데이터가 존재하는 반면,
Html에서 다시 가져오지를 못하는것 같다.
이미지들이 동일한 경로에 있는데도.. url을 직접 주소창에 넣어보면 고양이 사진(맨 처음에 input한 사진)만 열린다.
(http://localhost:8080/Uploads/BackGroundImage/160634_60486ffa40ba9.jpg 는 열리는데
http://localhost:8080/Uploads/BackGroundImage/KakaoTalk_20231211_125748013.jpg 는 안열림)ㅎㅎ;;
다음 게시물에서는 이 현상에 대한 원인과 해결방법을.. 찾아오도록 하겠다!!
어렵다 어려워
'IT > Web' 카테고리의 다른 글
[에러] Spring에 MySQL 연결하기 (Gradle) (2) | 2024.01.03 |
---|---|
[에러]Html, Javascript에서 ajax로 이미지 안열림 해결(2/2) - for문을 이용해 여러 이미지 동시 출력하기 (1) | 2023.12.13 |
[에러] Html에서 CSS link 안됨 해결 (1) | 2023.12.05 |
[python] 웹페이지 크롤링 - selenium에서 자주 사용하는 함수(1) (find_element) (0) | 2023.09.21 |
[python] 웹페이지 크롤링 - selenium 시작하기 (1) | 2023.09.18 |