Отправка изображения в серверную часть. Spring + Js
Перерыл множество мест, но увы, так и не понял, в чём моя ошибка. Ситуация следующая: Необходимо отправить изображение на сервер в специальной форме. Пользователь выбирает файл и нажимает отправить. Картинка отправляется на сервер, сохраняется в папке, а в бд прописывается путь к этой картинке.
С последним пунктом проблем нет, но есть проблема с получением на сервере самого изображения.
Реализация на Spring Boot и чистом Js.
Js
function updphoto() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "api/select/user/change/photo");
xhr.setRequestHeader("Content-type", "image/jpg");
var file = document.getElementById("updatePhoto");
let formData = new FormData(file);
xhr.send(formData);
}
HTML
<form onsubmit="updphoto()" name="updatePhoto" id="updatePhoto">
<div class="form-updatePhoto">
<label for="file">Загрузите тут:</label>
<input type="file" required class="form-control" id="file" name="file">
<button type="submit" id="updatePhotoSubmit" >Отправить</button>
</div>
</form>
Controller
@RequestMapping(value = "change/photo", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Boolean> changePhotoByUser (MultipartFile image, HttpServletRequest request) {
String name = SecurityContextHolder.getContext().getAuthentication().getName();
String dir = request.getSession().getServletContext().getRealPath("/");
Boolean bool = some_class.photoChanger(name, image, dir);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<>(bool, headers, HttpStatus.OK);
Собственно, проблема требующая решения - нет передачи в контроллер самого изображения из js запроса. Внятного ответа на этот вопрос я не нашёл. Я не особо хорошо знаю именно Spring, но реализация нужна.
Серверную часть проверял, она точно рабочая (написание маршрута, создания там изображения и внесение в бд).
При передаче из контроллера в сервис выкидывает ошибку:
2020-04-30 17:10:20.050 [http-nio-40001-exec-8] ERROR org.apache.juli.logging.DirectJDKLog:175 - Servlet.service() for servlet [dispatcherServlet] in context with path [/some_app] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause java.lang.NullPointerException: null
Ответы (1 шт):
КЭП в комментариях ответа толкового не дал, и с такими знаниями в области чтения последней строки советовал бы идти на ответы мейл ру.
А теперь к сути решения данной проблемы:
Передать файл (как файл данным методом), увы не получилось, однако получилось передать его в виде хэша Base64. Данный метод решения написан на чистом Js и Spring без каких либо подключений.
Код на Js:
function updphoto() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "api/select/user/change/photo");
xhr.setRequestHeader("Content-type", "application/json");
var file = document.getElementById("file").files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (function (f) {
return function (e) {
xhr.send(JSON.stringify({"image": this.result}));
};
})(file);
}
Кусок html страницы:
<form onsubmit="updphoto()" name="updatePhoto">
<input type="file" required class="form-control" id="file" name="file">
<button type="submit" id="updatePhotoSubmit" class="btn btn-primary btn-lg">Отправить</button>
</form>
Такая передача позволила передать в контроллер, но сразу оговорка!
Из кода выше было видно, что использовался MultipartFile, но был изменён на строку в классе UserChangePhotoRequest, и имеющий поле String image и сеттеры и геттер к нему. Специально покажу на всякий случай:
public class UserChangePhotoRequest {
private String image;
public String getImage() {return image;}
public void setImage(String image) {this.image = image;}
}
Именно поле image гарантирует нам передачу из реквеста в контроллер (с этой проблемой дня 2 возился).
Конечный вариант контроллера выглядит следующим образом:
@RequestMapping(value = "/api/select/user/change/photo", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Boolean> changePhotoUser (@RequestBody UserChangePhotoRequest imageBase64) {
// получение имени пользователя из нынешней сессии
String username = SecurityContextHolder.getContext().getAuthentication().getName();
Boolean bool = some_class.photoChanger(username, imageBase64);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<>(bool, headers, HttpStatus.OK);
}
И уже в самом классе some_class занимаемся обработкой данной информации. Лично я решил просто добавлять в бд и не придумывать танцев с бубном.