web-dev-qa-db-fra.com

Ajouter des attributs au modèle de tous les contrôleurs dans Spring 3

Chaque vue de mon application Spring 3 possède un ensemble d'attributs sur lesquels elle peut s'appuyer. Ainsi, la première ligne de chaque contrôleur est quelque chose comme:

ControllerHelper.addDefaultModel(model, personManager, request);

J'y ajouterai

  • objet utilisateur et nom complet récupérés de la base de données si une personne est connectée
  • ensemble de variables qui sont généralement définies une fois (par exemple imagesHost)
  • ensemble de langues dans lesquelles un visiteur peut basculer
  • langue courante
  • quelques statistiques (par exemple, le nombre total de personnes dans notre système)

Tout cela permet à chaque vue d'afficher le nom de l'utilisateur connecté, de référencer facilement un emplacement d'image, une liste de langues et des statistiques générales sur le site.

La question est donc de savoir si l'objet du modèle de contrôleur est le meilleur endroit pour stocker toutes les données ou existe-t-il un endroit plus pratique qui facilite l'accès aux informations à ces vues?

Et deuxièmement, j'aimerais vraiment ne pas avoir la ligne ControllerHelper au-dessus comme première ligne de chaque contrôleur. En fait, ce n'est pas toujours la première ligne, parfois je vérifie d'abord si je dois rediriger dans ce contrôleur, car je ne veux pas gaspiller des ressources en remplissant le modèle sans raison. Peut-être qu'un filtre ou une annotation ou un mécanisme de rappel Spring pourrait s'assurer que le code ControllerHelper est appelé après le contrôleur est terminé mais à droite avant la vue est rendue, sauter ceci si une redirection a été retournée?

52
at.

Vous pouvez écrire un org.springframework.web.servlet.HandlerInterceptor . (ou sa sous-classe de commodité HandlerInterceptorAdapter )

@See: Chapitre de référence Spring: 15.4.1 Interception de requêtes - l'interface HandlerInterceptor

Il a la méthode:

void postHandle(HttpServletRequest request,
                HttpServletResponse response,
                Object handler,
                ModelAndView modelAndView) throws Exception;

Cette méthode est invoquée une fois le contrôleur terminé et avant le rendu de la vue. Vous pouvez donc l'utiliser pour ajouter des propriétés à ModelMap

Un exemple:

/**
 * Add the current version under name {@link #VERSION_MODEL_ATTRIBUTE_NAME}
 * to each model. 
 * @author Ralph
 */
public class VersionAddingHandlerInterceptor extends HandlerInterceptorAdapter {

    /**
     * The name under which the version is added to the model map.
     */
    public static final String VERSION_MODEL_ATTRIBUTE_NAME =
                "VersionAddingHandlerInterceptor_version";

    /**        
     *  it is my personal implmentation 
     *  I wanted to demonstrate something usefull
     */
    private VersionService versionService;

    public VersionAddingHandlerInterceptor(final VersionService versionService) {
        this.versionService = versionService;
    }

    @Override
    public void postHandle(final HttpServletRequest request,
            final HttpServletResponse response, final Object handler,
            final ModelAndView modelAndView) throws Exception {

        if (modelAndView != null) {
            modelAndView.getModelMap().
                  addAttribute(VERSION_MODEL_ATTRIBUTE_NAME,
                               versionService.getVersion());
        }
    }
}

webmvc-config.xml

<mvc:interceptors>
    <bean class="demo.VersionAddingHandlerInterceptor" autowire="constructor" />
</mvc:interceptors>
57
Ralph

Vous pouvez également utiliser @ModelAttribute sur des méthodes, par exemple.

@ModelAttribute("version")
public String getVersion() {
   return versionService.getVersion();
}

Cela l'ajoutera à tous les mappages de demandes dans un contrôleur. Si vous mettez cela dans une super classe, il pourrait être disponible pour tous les contrôleurs qui l'étendent.

32
blank

Vous pouvez utiliser une classe de contrôleur annotée avec @ControllerAdvice

"@ControllerAdvice a été introduit dans la version 3.2 pour les méthodes @ExceptionHandler, @ModelAttribute et @InitBinder partagées entre tous ou un sous-ensemble de contrôleurs."

pour en savoir plus, jetez un œil à cette partie de la vidéo enregistrée pendant SpringOne2GX 2014 http://www.youtube.com/watch?v=yxKJsgNYDQI&t=6m33s

11
mickthompson

comme @blank répondre à ce travail pour moi:

@ControllerAdvice(annotations = RestController.class)
public class AnnotationAdvice {

    @Autowired
    UserServiceImpl userService;

    @ModelAttribute("currentUser")
    public User getCurrentUser() {
       UserDetails userDetails = (UserDetails) 
       SecurityContextHolder.getContext().getAuthentication().getPrincipal();
       return userService.findUserByEmail(userDetails.getUsername());
}
}
4
badou

Un problème se produit avec la redirection lors de l'utilisation de l'approche @ModelAttribute ou HandlerInterceptor. Lorsque le gestionnaire renvoie la vue Rediriger, les attributs de modèle ajoutés de cette façon sont ajoutés en tant que paramètres de requête.

Une autre façon de gérer cette situation consiste à créer un bean à portée de session, qui peut être câblé automatiquement dans le contrôleur d'application de base, ou explicitement dans chaque contrôleur où l'accès est nécessaire.

Les détails sur les portées disponibles et leur utilisation peuvent être trouvés ici .

3
qza

si vous avez besoin d'ajouter des variables globales que chaque vue peut résoudre ces variables , pourquoi ne pas les définir dans une propriété ou une carte? alors utilisez spring DI , référez-vous au bean resolver de vue. il est très utile, comme statique fiable, par ex. resUrl

<property name="viewResolvers">
        <list>
            <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="viewClass"
                    value="org.springframework.web.servlet.view.JstlView" />
                <property name="attributes" ref="env" />
                <property name="exposeContextBeansAsAttributes" value="false" />
                <property name="prefix" value="${webmvc.view.prefix}" />
                <property name="suffix" value="${webmvc.view.suffix}" />
            </bean>
        </list>
    </property>
1
Arbore