2013-02-22 23 views
18

In Spring MVC ist es einfach, die Anforderung Parameter an Methodenparameter zu binden, die die Anforderung verarbeiten. Ich benutze einfach @RequestParameter("name"). Aber kann ich das gleiche mit der Anfrage Attribut tun? Derzeit wenn ich Anfrage Attribut zugreifen will, muss ich folgendes tun:Spring MVC: Bindungsanforderungsattribut an Controller-Methodenparameter

MyClass obj = (MyClass) request.getAttribute("attr_name"); 

Aber ich möchte wirklich so etwas wie dies stattdessen verwenden:

@RequestAttribute("attr_name") MyClass obj 

Leider hat es nicht arbeite so. Kann ich die Spring-Funktionalität irgendwie erweitern und eigene "Binder" hinzufügen?

EDIT(was ich versuche zu erreichen): Ich speichere derzeit Benutzer innerhalb Anforderungsattribut angemeldet. Also, wann immer ich auf den aktuell angemeldeten Benutzer zugreifen möchte (was ziemlich in jeder Methode ist), muss ich diese zusätzliche Zeile user = (User) request.getAttribute("user"); schreiben. Ich möchte es so kurz wie möglich machen, vorzugsweise als Methodenparameter einspeisen. Oder wenn Sie einen anderen Weg kennen, wie man etwas über Abfangjäger und Controller hinweggibt, würde ich mich freuen, es zu hören.

Antwort

29

Nun, ich endlich verstanden, ein wenig wie Modelle funktionieren und was ist @ModelAttribute für. Hier ist meine Lösung.

@Controller 
class MyController 
{ 
    @ModelAttribute("user") 
    public User getUser(HttpServletRequest request) 
    { 
     return (User) request.getAttribute("user"); 
    } 

    @RequestMapping(value = "someurl", method = RequestMethod.GET) 
    public String HandleSomeUrl(@ModelAttribute("user") User user) 
    { 
     // ... do some stuff 
    } 
} 

Die getUser() Methode markiert mit @ModelAttribute Annotation automatisch alle User user Parameter markiert mit @ModelAttribute füllen. Wenn die HandleSomeUrl-Methode aufgerufen wird, sieht der Aufruf beispielsweise so aus wie MyController.HandleSomeUrl(MyController.getUser(request)). Zumindest stelle ich es mir so vor. Cool ist, dass der Benutzer auch ohne weiteren Aufwand von der JSP-Ansicht aus erreichbar ist.

Dies löst genau mein Problem, aber ich habe weitere Fragen. Gibt es einen gemeinsamen Ort, an dem ich die Methoden @ModelAttribute so setzen kann, dass sie für alle meine Controller üblich sind? Kann ich irgendwie ein Modellattribut von der Innenseite der preHandle() Methode eines Interceptor hinzufügen?

+0

Das ist perfekt! Vielen Dank. – Raff

+0

Wenn Ihre Parameternamen mit den Eigenschaften Ihres Modellobjekts übereinstimmen, benötigen Sie die zusätzliche getUser-Methode nicht. Mit spring werden diese Eigenschaften automatisch festgelegt. – chrismarx

+1

Auf diese Weise wird das Benutzerobjekt in Ihrer Methode nicht nur aus dem Ansichtsmodell, sondern auch von dessen Eigenschaften abgerufen wird durch eingehende Anfrage- oder Formularparameter gebunden (und überschrieben). Wenn zum Beispiel das Benutzerobjekt eine id-Eigenschaft hat (die viele Benutzerobjekte haben) und die Anfrage-URL oder das Formular auch einen nicht verwandten id-Parameter haben, wird die ID des Benutzerobjekts überschrieben. Dies hat einmal einen bösen Fehler in meinem Code verursacht. In diesem speziellen Fall möchten Sie nicht die formalen Bindungseigenschaften von @ModelAttribute. Eine Alternative ist 'User u = (Benutzer) model.get (" user ");' – klausch

3

Ich denke, was Sie suchen ist:

@ModelAttribute("attr_name") MyClass obj 

Sie, dass in den Parametern für ein Verfahren in Ihrem Controller verwenden können.

Hier ist ein Link ein mit Details über sie mit einigen Beispielen der Verwendung es zu What is @ModelAttribute in Spring MVC?

Diese Frage Links zu den Frühling Dokumentation zu hinterfragen. Sie könnenhere

aktualisieren

Ich bin nicht sicher, wie Sie Ihre Seiten einrichten, dass aber man kann der Benutzer als Modell Attribut ein paar verschiedene Arten hinzufügen. Ich habe hier ein einfaches Beispiel eingerichtet.

Wenn der Benutzer eine Anforderung sendet, bindet Spring das Benutzerattribut an das Benutzerobjekt in den Methodenparametern.

@RequestMapping(value = "/account/delivery", method = RequestMethod.POST) 
public ModelAndView updateDeliverySchedule(@ModelAttribute("user") User user) { 

    user = accountService.updateDeliverySchedule(user); //do something with the user 

    return new ModelAndView("account", "user", user); 
} 
+0

Danke, aber ich habe versucht, etwas anderes zu erreichen .. vielleicht sollte ich erklärte, dass habe. Ich verwende das Anforderungsattribut, um den aktuell angemeldeten Benutzer zu speichern. So, wie Sie 'User user = (User) session.getAttribute (" user ") aufrufen;' I call 'user = (Benutzer) request.getAttribute (" user ");'. Aber es ist ziemlich ärgerlich, das in jeder einzelnen Methode zu schreiben. Ich möchte dies so kurz wie möglich machen, vorzugsweise als Methode Parameter injizieren. – tobik

+0

Sie können diese Methode weiterhin verwenden, um das zu tun. Sie müssen nur das Benutzerobjekt zum Modell hinzufügen. Dann können Sie darauf zugreifen. Es gibt ein paar Möglichkeiten, das zu tun. Ich werde meine Antwort aktualisieren. – ssn771

+0

Ich bin nicht so vertraut mit @ SessionAttributes, aber das könnte auch für Sie arbeiten.Hier ist eine [link] (http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-sessionattrib) zu der Dokumentation darüber. – ssn771

0

Ab Frühling 3.2 kann es noch schöner gemacht werden mit Federn ControllerAdvice Annotation. Dies würde Ihnen dann einen Hinweis geben, der @ModelAttributes in einer separaten Klasse hinzufügt, die dann auf alle Ihre Controller angewendet wird.

Der Vollständigkeit halber ist es auch möglich, das @RequestAttribute ("attr-name") tatsächlich so zu machen, wie es ist. (unten von this article modifiziert unsere Forderungen entsprechen)

Zuerst müssen wir die Anmerkung definieren:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.PARAMETER) 
public @interface RequestAttribute { 
    String value(); 
} 

Dann brauchen wir ein [WebArgumentResolver] zu handhaben, was getan werden muss, wenn das Attribut zu sein gebunden

public class RequestAttributeWebArgumentResolver implements WebArgumentResolver { 

    public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest nativeWebRequest) throws Exception { 
     // Get the annotation  
     RequestAttribute requestAttributeAnnotation = methodParameter.getParameterAnnotation(RequestAttribute.class); 

     if(requestAttributeAnnotation != null) { 
      HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest(); 

      return request.getAttribute(requestAttributeAnnotation.value); 
     } 

     return UNRESOLVED; 
    } 
} 

Jetzt alles, was wir brauchen, ist dieses customresolver zu der Config hinzuzufügen, es zu lösen:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name="customArgumentResolver"> 
     <bean class="com.sergialmar.customresolver.web.support.CustomWebArgumentResolver"/> 
    </property> 
</bean> 

Und wir sind fertig!

2

Nicht die eleganteste, funktioniert aber zumindest ...

@Controller 
public class YourController { 

    @RequestMapping("/xyz") 
    public ModelAndView handle(
     @Value("#{request.getAttribute('key')}") SomeClass obj) { 

     ... 
     return new ModelAndView(...); 
    } 

} 

Quelle: http://blog.crisp.se/tag/requestattribute

0

Ja, können Sie Ihren eigenen ‚Bindemittel‘ auf die Anfrage Attribut hinzufügen - siehe spring-mvc-3-showcase oder Verwendung @Peter Szantos Lösung.

Alternativ binden Sie es als ModelAttribute, wie in anderen Antworten empfohlen.

Da es sich bei dem angemeldeten Benutzer um einen Benutzer handelt, der an den Controller übergeben werden soll, empfiehlt es sich, Spring Security zu berücksichtigen. Dann können Sie einfach haben die Principle in Ihre Methode injiziert:

@RequestMapping("/xyz") 
public String index(Principal principle) { 
    return "Hello, " + principle.getName() + "!"; 
} 
0

Im Frühjahr WebMVC 4.x, es Geräte bevorzugen HandlerMethodArgumentResolver

@Override 
public boolean supportsParameter(MethodParameter parameter) { 
    return parameter.getParameterAnnotation(RequestAttribute.class) != null; 
} 

@Override 
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, 
     NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 
    return webRequest.getAttribute(parameter.getParameterAnnotation(RequestAttribute.class).value(), NativeWebRequest.SCOPE_REQUEST); 
} 

}

Dann registrieren es in RequestMappingHandlerAdapter

4

Verwendung (ab Frühling 4.3) @RequestAttribute:

@RequestMapping(value = "someurl", method = RequestMethod.GET) 
public String handleSomeUrl(@RequestAttribute User user) { 
    // ... do some stuff 
} 

oder wenn die Anforderung Attributnamen Namen nicht mit dem Methodenparameter überein:

@RequestMapping(value = "someurl", method = RequestMethod.GET) 
public String handleSomeUrl(@RequestAttribute(name="userAttributeName") User user) { 
    // ... do some stuff 
}