Transfert des fichiers

Envoi des fichiers à travers les formulaires Spring

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Les formulaires qui ne pourraient échanger que les données textuelles ne trouveraient pas leur utilité dans le monde des applications. C'est pourquoi nous allons aborder maintenant une partie consacrée au formulaire qui permet de transférer les fichiers.

Upload des fichiers sous Spring

Cependant, il n'y a que les valeurs textuelles qu'on peut envoyer via les formulaires dans Spring. Il y a aussi les fichiers qui peuvent être traités par les formulaires. Tout cela grâce au bean qui s'appelle multipartResolver. Au titre de rappel, on voici sa définition :

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="100000"/>
        <property name="maxInMemorySize" value="100000"/>
        <property name="defaultEncoding" value="utf-8"/>
    </bean>

Dès que multipartResolver va détecter que la requête contient des fichiers, il va le signaler au DispatcherServlet. Ce dernier se chargera alors de rediriger la tâche à l'implémentation de l'interface HttpServletRequest adaptée à ce type de traitement. Ensuite dans le contrôleur on peut la caster en MultipartHttpServletRequest pour récupérer les fichiers transférés. Ces fichiers se cachent sous instances de la classe MultipartFile.

Cependant, dans notre exemple on utilisera une approche légèrement différente. Il s'agira du transfert d'un avatar. Il sera attaché à l'entité Subscriber qui contiendra un attribut annoté avec @Transient, comme ci-dessous :

public class Subscriber extends ParentEntity implements Serializable {
    // other code omitted
    @Transient
    public CommonsMultipartFile getAvatarFile() {
        return avatarFile;
    }
}

L'avatar sera l'instance de la classe org.springframework.web.multipart.commons.CommonsMultipartFile. Elle implémente l'interface évoquée ci-dessus, MultipartFile. Regardons comment intercepter cet objet dans le contrôleur :

@Controller
public class SubscriberController extends FrontendController {
    // only this method interests us
    @RequestMapping(value = "/account/avatar", method = RequestMethod.POST)
    public String modifyAvatarHandle(@ModelAttribute("subscriber") @Validated({SubscriberAvatarCheck.class}) 
    Subscriber subscriber, BindingResult binRes, @LoggedUser AuthenticationFrontendUserDetails user, 
    Model layout, RedirectAttributes redAtt) {
        logger.info("Received POST request " + subscriber);
        if (binRes.hasErrors()) {
            redAtt.addFlashAttribute("error", true);
            redAtt.addFlashAttribute("subscriber", subscriber);
            redAtt.addFlashAttribute("errors", binRes);
        } else {
            try {
                Subscriber subFromUser = conversionService.convert(user, Subscriber.class);
                subFromUser.setAvatarFile(subscriber.getAvatarFile());
                subscriberService.addAvatar(subFromUser);
                redAtt.addFlashAttribute("success", true);
            } catch (Exception e) {
                binRes.addError(getExceptionError("subscriber"));
                redAtt.addFlashAttribute("error", true);
                redAtt.addFlashAttribute("subscriber", subscriber);
                redAtt.addFlashAttribute("errors", binRes);
            }
        }
        return "redirect:/account/avatar";
    }
}

La récupération de l'image rajoutée se fait donc sans aucun souci, via le getter adéquat. Ensuite l'instance MultipartFile est passée au service qui s'occupe de transférer l'image physiquement sur le serveur ainsi que marquer ce fait dans la base de données :

public class SubscriberServiceImpl implements SubscriberService {

    @Override
    public Subscriber addAvatar(Subscriber subscriber) throws Exception {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(def);
        try {
            Map<String, Object> uploadResult = imageTool.uploadFile("avatar", subscriber.getAvatarFile(), subscriber.getLogin());
            if (((Boolean)uploadResult.get("uploadResult")) == true) {
                subscriber.setAvatar((String)uploadResult.get("fileBasename"));
                subscriber = subscriberRepository.save(subscriber);
            
                transactionManager.commit(status);
            } else {
                subscriber = null;
            }
        } catch(Exception e) {
            logger.error("An error occured on adding subscriber avatar", e);
            transactionManager.rollback(status);
            subscriber = null;
            throw new Exception(e);
        }
        return subscriber;
    }

}

Dans la transaction on tente d'abord de transférer l'instance MultipartFile sur le serveur. Si le résultat d'upload est positif, on récupère le nom du fichier envoyé et on met à jour le champ avatar de l'entité Subscriber. Après on sauvegarde les modifications dans la base de données. Actuellement on ne va pas entrer dans les détails concernant le transfert de l'image sur le serveur. Ce sera le sujet de l'article consacré au transfert des images dans Spring.

Bartosz KONIECZNY Formulaires

Une question ? Une remarque ?

*

*

Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil PHP

Comment créer un base string pour OAuth

Création d'un base string pour OAuth consiste à récupérer 3 éléments et les concaténer. Il s'agit de : - la méthode HTTP d'appel de la ressource (GET ou POST) - l'url de l'appel (sans paramètres) - les paramtères utilisés dans la requête (il ne faut pas inclure oauth_signature car elle n'est pas encore générée) Tous les 3 éléments doivent être normalisés et concaténés avec un ampersand (&). L'ampersand ne peut pas subir l'encodage. Une méthode pour générer un base string peut se présenter ainsi :

function setBaseString($method, $url, $paramsList)
{
  $paramsString = array();
  foreach($paramsList as $p => $param)
  {
    $paramsString[] = $p.'='.$param;
  }
  return str_replace('%7E', '~', rawurlencode($method)).'&'.str_replace('%7E', '~', rawurlencode($url)).'&'.str_replace('%7E', '~', rawurlencode(implode('&', $paramsString)));
}