404, static에 upload라는 폴더가 존재하지 않아서
따라서 static 내부가 아닌 외부의 upload 폴더를 찾게 바꿔주기
package coffee.pastry.joshuablog.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
WebMvcConfigurer.super.addResourceHandlers(registry);
registry.addResourceHandler("/upload/**") // 이렇게 오면
.addResourceLocations("file:" + "./upload/") // 이거를 찾을께
.setCachePeriod(60 * 60) // 1시간
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
}
sessionUser 이부분은 로그인하고 강제로 1개더 만든 것
선택된 파일 없음
이 부분이 변하게 되면 chooseImage
발동
<script>
function chooseImage(obj){
//console.log(obj);
//console.log(obj.files);
let f = obj.files[0];
if(!f.type.match("image.*")){ // MIME validation
alert("이미지를 등록해야 합니다.");
return;
}
let reader = new FileReader();
reader.readAsDataURL(f); // IO 발생 (내부적으로 Promise 처리)
// 콜스택이 다 비워지고, 이벤트 루프로 가서 readAsDataURL 이벤트가 끝나면 콜백시켜주는 함수
reader.onload = function (e){ // 할일이 없을 떄 function 발동 -> 파일 다 읽었나 -> check
console.log(e);
console.log(e.target.result);
$("#imagePreview").attr("src", e.target.result); // 읽은 사진을 바꿔지치
}
}
</script>
@PostMapping("/s/user/{id}/updateProfile")
public String profileUpdate(
@PathVariable Long id,
MultipartFile profile,
@AuthenticationPrincipal MyUserDetails myUserDetails) {
if (id != myUserDetails.getUser().getId()) {
throw new Exception403("권한이 없습니다");
}
if (profile.isEmpty()) {
throw new Exception400("profile", "사진이 전송되지 않았습니다");
}
User userPS = userService.프로필사진수정(profile, id);
myUserDetails.setUser(userPS);
session.setAttribute("sessionUser", userPS);
return "redirect:/";
}
package coffee.pastry.joshuablog.core.util;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import org.springframework.web.multipart.MultipartFile;
import coffee.pastry.joshuablog.core.exception.ssr.Exception500;
public class MyFileUtil {
public static String write(String uploadFolder, MultipartFile file) {
// 롤링기법 (사진명 : 랜덤_사진이름.png)
UUID uuid = UUID.randomUUID();
String originalFilename = file.getOriginalFilename();
String uuidFilename = uuid + "_" + originalFilename;
try {
// 파일 사이즈 줄이기
Path filePath = Paths.get(uploadFolder + uuidFilename);
Files.write(filePath, file.getBytes());
} catch (Exception e) {
throw new Exception500("파일 업로드 실패 : " + e.getMessage());
}
return uuidFilename;
}
}
UUID -> 랜덤값(난수),
@Transactional
public User 프로필사진수정(MultipartFile profile, Long id) {
try {
String uuidImageName = MyFileUtil.write(uploadFolder, profile);
User userPS = userRepository.findById(id)
.orElseThrow(() -> new Exception500("로그인 된 유저가 DB에 존재하지 않음"));
userPS.changeProfile(uuidImageName);
return userPS;
} catch (Exception e) {
throw new Exception500("프로필 사진 등록 실패 : " + e.getMessage());
}
} // 더티채킹(업데이트)
return을 받고 세션 동기화(컨트롤러), 왜냐하면 사진이 바뀌었으니까 동기화 떄문에
세션 2개 동기화(SecurityContextHolder의 UserDetails랑 내가 강제로 만든 session 동기화)
왜 2개를 동기화?? -> 내가 강제로 만든 세션은 VIEW 까지 들고가야하니까!!