Главная » Spring » Прием выгружаемых файлов Spring

0

Как и прежде, данные формы будет обрабатывать метод addSpitter- FromForm(). Но нам нужно добавить в него обработку выгруженного изображения. В листинге 8.13 представлена новая версия метода addSpitterFromForm(), принимающая выгруженное изображение.

Листинг 8.13. Метод addSpitterFromForm(), принимающий параметр типа MultipartFile

@RequestMapping(method=RequestMethod.POST)

public String addSpitterFromForm(@Valid Spitter spitter, BindingResult bindingResult,

@RequestParam(value="image", required=false)       // Прием файла MultipartFile   image)   {

if(bindingResult.hasErrors()) { return    "spitters/edit";

}

spitterService.saveSpitter(spitter); try {

if(!image.isEmpty())   {

validateImage(image);                         // Проверить изображение

saveImage(spitter.getId()  +  ".jpg",  image);  //  Сохранить  файл

}

} catch (ImageUploadException e) { bindingResult.reject(e.getMessage()); return     "spitters/edit";

}

return  "redirect:/spitters/"  +  spitter.getUsername();

}

Первое изменение в методе addSpitterFromForm() касается добавле- ния нового параметра. Параметр image имеет тип MultipartFile и от- мечен аннотацией @RequestParam, указывающей, что этот параметр не является обязательным (то есть пользователь может не отправлять изображение аватара при регистрации).

Чуть ниже в этом методе проверяется наличие изображения и, если оно имеется, – передается сначала методу validateImage(), а за- тем методу saveImage(). Метод validateImage(), представленный ниже, проверяет соответствие файла изображения предъявляемым требо- ваниям:

private  void  validateImage(MultipartFile  image)  { if(!image.getContentType().equals("image/jpeg"))    {

throw  new  ImageUploadException("Only  JPG  images  accepted");

}

}

Мы не должны позволять пользователям выгружать файлы .zip или .exe. Поэтому метод validateImage() проверяет, является ли вы- груженный файл изображением в формате JPEG. Если файл не соответствует требованиям, возбуждается исключение ImageUpload- Exception (расширяющее исключение RuntimeException).

Убедившись, что выгруженный файл является изображением, его можно сохранить, вызвав метод saveImage(). Фактически метод saveImage() мог бы сохранить изображение в любом месте, доступном для браузера. Чтобы не усложнять, для начала напишем реализацию метода saveImage(), сохраняющую изображение в локальной файло- вой системе.

Сохранение файлов в файловой системе

Даже при том, что доступ к нашему приложению будет осуществ- ляться через сеть, его ресурсы в конечном итоге будут храниться в файловой системе сервера. Поэтому выглядит вполне естествен- ным сохранять пользовательские файлы с изображениями в локаль- ной файловой системе, там, где они будут доступны веб-серверу. Именно это и делает следующая реализация метода saveImage:

private   void   saveImage(String   filename,   MultipartFile   image) throws ImageUploadException {

try  {

File  file  =  new  File(webRootPath  +  "/resources/"  +  filename); FileUtils.writeByteArrayToFile(file,      image.getBytes());

} catch (IOException e) {

throw new ImageUploadException("Unable to save image", e);

}

}

Сначала метод saveImage() создает объект java.io.File, определяя путь к файлу, исходя из значения webRootPath. Здесь преднамеренно не раскрывается значение этой переменной, так как оно зависит от сервера, где выполняется приложение. Достаточно будет сказать, что получение этого значения можно организовать через внедрение ли- бо с помощью метода setWebRootPath(), либо за счет чтения значения из конфигурационного файла с помощью выражения на языке SpEL и аннотации @Value.

После подготовки объекта File изображение записывается в файл с помощью FileUtils из Apache Commons IO1. Если что-то пойдет не так, будет возбуждено исключение ImageUploadException.

Хранение файлов изображений в файловой системе прекрасно подходит для целей приложения, но влечет за собой необходимость следить за файловой системой. Вам придется гарантировать наличие достаточного свободного пространства, создавать резервные копии на случай отказа аппаратных средств, а также обеспечить синхрони- зацию файлов изображений между несколькими серверами в клас- тере.

Другой вариант заключается в том, чтобы позволить кому-то другому избавить вас от всех этих неприятностей. Добавив немно- го программного кода, можно организовать хранение изображений в облаке. Давайте освободим себя от необходимости управлять фай- лами изображений, переписав метод saveFile() так, чтобы он сохра- нял их в хранилище Amazon S3.

Сохранение файлов в хранилище Amazon S3

Служба Simple Storage Service компании Amazon, или S3, как ее часто называют, представляет собой недорогой способ хранения файлов в инфраструктуре серверов компании Amazon. Используя службу S3, можно просто передавать ей файлы и переложить всю рутинную работу на системных администраторов Amazon.

Самый простой способ взаимодействий со службой S3 в програм- мах на языке Java обеспечивает библиотека JetS3t2. JetS3t – это от- крытая библиотека функций, реализующих запись и чтение файлов в облаке S3. Мы можем задействовать библиотеку JetS3t для сохра- нения аватаров пользователей. В листинге 8.14 представлена новая версия метода saveImage().

1   http://commons.apache.org/io/.

2   http://bitbucket.org/jmurty/jets3t/wiki/Home.

Листинг 8.14. Версия метода saveImage(), сохраняющая файлы изображений в облаке Amazon S3

private   void   saveImage(String   filename,   MultipartFile   image) throws ImageUploadException {

try  {

AWSCredentials  awsCredentials  =

new  AWSCredentials(s3AccessKey,  s3SecretKey);

S3Service  s3  =  new  RestS3Service(awsCredentials);  // Настройка  S3

// Создать объекты, представляющие хранилище и изображение S3Bucket  imageBucket  =  s3.getBucket("spitterImages"); S3Object imageObject = new S3Object(filename);

// Скопировать данные изображения в объект imageObject.setDataInputStream(

new   ByteArrayInputStream(image.getBytes())); imageObject.setContentLength(image.getBytes().length); imageObject.setContentType("image/jpeg");

// Определить разрешения

AccessControlList  acl  =  new  AccessControlList(); acl.setOwner(imageBucket.getOwner()); acl.grantPermission(GroupGrantee.ALL_USERS,

Permission.PERMISSION_READ); imageObject.setAcl(acl);

// Сохранить изображение s3.putObject(imageBucket, imageObject);

}  catch  (Exception  e)  {

throw new ImageUploadException("Unable to save image", e);

}

}

В первую очередь метод saveImage() настраивает параметры аутен- тификации в службе Amazon Web Service. Для этого необходимо иметь ключ доступа к службе S3 и секретный ключ S3. Их выдает компания Amazon после подписки на пользование услугами служ- бы S3. Они передаются контроллеру SpitterController посредством механизма внедрения.

После настройки параметров аутентификации метод saveImage()

создает экземпляр объекта RestS3Service, посредством которого бу-

дут осуществляться взаимодействия с файловой системой S3. За- тем он получает ссылку на хранилище spitterImages, создает объект S3Object для изображения и затем копирует в этот объект данные изображения.

Непосредственно перед вызовом метода putObject(), выполняюще- го запись изображения в S3, метод saveImage() устанавливает в объ- екте S3Object разрешения, позволяющие пользователям просматри- вать его. Это очень важно – в противном случае изображения будут недоступны пользователям нашего приложения.

Как и в предыдущей версии метода saveImage(), в случае каких- либо проблем возбуждается исключение ImageUploadException.

Мы практически закончили реализацию выгрузки файлов изо- бражений. Осталось лишь связать все вместе.

Настройка Spring для выгрузки файлов

Сам по себе контроллер DispatcherServlet понятия не имеет, что делать с формами, состоящими из нескольких частей. Поэтому мы должны реализовать механизм извлечения данных из запросов POST, чтобы контроллер DispatcherServlet смог передать их нашему контроллеру.

Чтобы зарегистрировать этот механизм в Spring, необходимо объ- явить компонент, реализующий интерфейс MultipartResolver. Выбор реализации не составляет затруднений, так как в состав фреймворка Spring входит только одна: CommonsMultipartResolver. Ниже показано, как настроить этот механизм в Spring:

<bean   id="multipartResolver"   class= "org.springframework.web.multipart.commons.CommonsMultipartResolver" p:maxUploadSize="500000" />

Имейте в виду, что идентификатор этого компонента играет очень важную роль. Когда контроллеру DispatcherServlet потребуется за- действовать механизм извлечения частей формы, он будет искать компонент с идентификатором multipartResolver. Если искомый ком- понент будет иметь другой идентификатор, DispatcherServlet просто не найдет его.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии