본문 바로가기
IT/Web

[에러] Html, Javascript에서 ajax로 이미지 안열림 해결(1/2) - 파일 경로를 이용해서 이미지 열기

by 한동두 2023. 12. 13.
반응형

먼저, 블로그 주인은 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. 결과

이미지가 저장되는 경로.(C:\Users\xxxx\xxxx\make_site\jungsu_tutorial\jungsu_tutorial\src\main\resources\static\Uploads\BackGroundImage)하위에 저장되는 모습

 

DB(h2 database)에 저장된 모습
Html에서 Not allowed to load local resources

-파일 경로는 정확히 나오지만 이미지가 출력되지 않는 오류가 발생했다.

-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. 결과

이미지가 저장되는 경로.(C:\Users\xxxx\xxxx\make_site\jungsu_tutorial\jungsu_tutorial\src\main\resources\static\Uploads\BackGroundImage)하위에 저장되는 모습
DB(h2 database)에 저장된 모습. 경로가 바뀌었다.
Html에서 잘 출력되는 모습.
Html Elements에서 보이는 이미지 Url의 형태

 

 

결론 

이미지 경로를 static 폴더 이후로 지정하니 해결 할 수 있었다.


또다른 문제점

그러나...

내가 만든 ajax에 뭔가 잘못된 것이 있는지, 동일한 상태에서 한번 더 파일 선택을 하면 이미지가 나오지 않는..오류가 있다..^^

오류 상황들..

 

이 상황에서, 폴더와 DB에는 정상적으로 데이터가 존재하는 반면,

Html에서 다시 가져오지를 못하는것 같다.

 

개발자도구(f12) Networks를 보면.. 이런상태다.(그리고 왜 마지막 사진은 자꾸 2장씩 출력하려고하는거냐..)

 

이미지들이 동일한 경로에 있는데도.. url을 직접 주소창에 넣어보면 고양이 사진(맨 처음에 input한 사진)만 열린다.

(http://localhost:8080/Uploads/BackGroundImage/160634_60486ffa40ba9.jpg 는 열리는데 

http://localhost:8080/Uploads/BackGroundImage/KakaoTalk_20231211_125748013.jpg 는 안열림)ㅎㅎ;;

 

다음 게시물에서는 이 현상에 대한 원인과 해결방법을.. 찾아오도록 하겠다!!

어렵다 어려워

반응형