Con Spring posso creare una variabile di percorso opzionale?


187

Con Spring 3.0, posso avere una variabile di percorso opzionale?

Per esempio

@RequestMapping(value = "/json/{type}", method = RequestMethod.GET)
public @ResponseBody TestBean testAjax(
        HttpServletRequest req,
        @PathVariable String type,
        @RequestParam("track") String track) {
    return new TestBean();
}

Qui vorrei /json/abco /jsonchiamare lo stesso metodo.
Una soluzione ovvia dichiara typecome parametro di richiesta:

@RequestMapping(value = "/json", method = RequestMethod.GET)
public @ResponseBody TestBean testAjax(
        HttpServletRequest req,
        @RequestParam(value = "type", required = false) String type,
        @RequestParam("track") String track) {
    return new TestBean();
}

e poi /json?type=abc&track=aao /json?track=rrfunzionerà

Risposte:


194

Non puoi avere variabili di percorso opzionali, ma puoi avere due metodi controller che chiamano lo stesso codice di servizio:

@RequestMapping(value = "/json/{type}", method = RequestMethod.GET)
public @ResponseBody TestBean typedTestBean(
        HttpServletRequest req,
        @PathVariable String type,
        @RequestParam("track") String track) {
    return getTestBean(type);
}

@RequestMapping(value = "/json", method = RequestMethod.GET)
public @ResponseBody TestBean testBean(
        HttpServletRequest req,
        @RequestParam("track") String track) {
    return getTestBean();
}

5
@Shamik: questa è una ragione convincente per non usare le variabili del percorso, secondo me. La proliferazione combinatoria può sfuggire rapidamente di mano.
Skaffman,

9
In realtà non perché il percorso non può essere così complesso mentre viene riempito con componenti opzionali. Se hai più di uno o massimo due elementi opzionali del percorso, dovresti prendere seriamente in considerazione di cambiarne alcuni per richiedere i parametri.
Patrick Cornelissen,

1
E per alcune persone, avere il secondo metodo del controller che chiama anche il primo metodo del controller può funzionare, se per esempio il diverso parametro può essere fornito con altri mezzi
chrismarx,

3
Si prega di prendere in considerazione l'aggiornamento la vostra risposta, invece di creare due metodi di controller nella versione più recente di primavera possiamo semplicemente usare @RequestMappingcon due valori come in: stackoverflow.com/questions/17821731/...
csharpfolk

omg come pensi di mantenere questi endpoint? E se invece di una sola variabile di percorso ne abbiamo 5, fai i calcoli per me, quanti endpoint faresti? Per favore, fammi un favore e sostituiscilo @PathVariablecon@RequestParam
Guilherme Alencar

114

Se si utilizza Primavera 4.1 e Java 8 è possibile utilizzare java.util.Optionalche è supportato in @RequestParam, @PathVariable, @RequestHeadere @MatrixVariablein Spring MVC -

@RequestMapping(value = {"/json/{type}", "/json" }, method = RequestMethod.GET)
public @ResponseBody TestBean typedTestBean(
    @PathVariable Optional<String> type,
    @RequestParam("track") String track) {      
    if (type.isPresent()) {
        //type.get() will return type value
        //corresponds to path "/json/{type}"
    } else {
        //corresponds to path "/json"
    }       
}

sei sicuro che funzionerebbe? La tua risposta qui suggerisce che il controller non verrà colpito se {type} è assente dal percorso. Penso che PathVariable Map sarebbe un approccio migliore o l'utilizzo di controller separati.
Anshul Tiwari,

4
Sì, se hai appena "/json/{type}"e il tipo non è presente non verrà colpito (come suggerisce la mia risposta collegata) ma qui hai value = {"/json/{type}", "/json" }. Quindi se qualcuno corrisponde al metodo del controller verrà colpito.
Aniket Thakur,

È possibile che lo stesso valore, ecc., Sia RequestParam e RequestParam?
zygimantus,

Funziona, ma comunque la funzione del controller non verrà richiamata perché si aspetta un parametro lì
EliuX

15
Funziona, e dalla primavera 4.3.3, puoi anche andare @PathVariable(required = false)e ottenere null se la variabile non è presente.
Nicolai Ehemann,

76

Non è noto che è anche possibile iniettare una mappa delle variabili del percorso usando l'annotazione @PathVariable. Non sono sicuro che questa funzionalità sia disponibile in Spring 3.0 o se sia stata aggiunta in un secondo momento, ma ecco un altro modo per risolvere l'esempio:

@RequestMapping(value={ "/json/{type}", "/json" }, method=RequestMethod.GET)
public @ResponseBody TestBean typedTestBean(
    @PathVariable Map<String, String> pathVariables,
    @RequestParam("track") String track) {

    if (pathVariables.containsKey("type")) {
        return new TestBean(pathVariables.get("type"));
    } else {
        return new TestBean();
    }
}

1
Lo uso sempre. Questo è utile quando voglio un singolo metodo per gestire diversi tipi di uri es: {"/ json / {type}", "/ json / {type} / {xyz}", "/ json / {type} / {abc} "," / json / {type} / {abc} / {qualcosa} "," / json "}
Vaibs

25

Puoi usare un:

@RequestParam(value="somvalue",required=false)

per parametri opzionali piuttosto che pathVariable


1
Questa è una versione specifica, a quanto pare. No go for Spring 3.
Stu Thompson,

5
Attualmente si utilizza questo metodo per un progetto di primavera 3.1 e i documenti dicono che funziona per 2.5+, quindi sicuramente funziona per la primavera 3. EDIT: fonte .
Evan B.

22
Vero, ma non è questo il problema. L'uso dei parametri di richiesta è infatti menzionato nella domanda come "Una soluzione ovvia" , ma la domanda stessa riguarda i parametri del percorso . Questa non è una soluzione per parametri di percorso opzionali.
Arjan,

9
PathVariable e RequestParam sono diversi.
Senza tempo

10

Esempi di Spring 5 / Spring Boot 2:

blocco

@GetMapping({"/dto-blocking/{type}", "/dto-blocking"})
public ResponseEntity<Dto> getDtoBlocking(
        @PathVariable(name = "type", required = false) String type) {
    if (StringUtils.isEmpty(type)) {
        type = "default";
    }
    return ResponseEntity.ok().body(dtoBlockingRepo.findByType(type));
}

reattivo

@GetMapping({"/dto-reactive/{type}", "/dto-reactive"})
public Mono<ResponseEntity<Dto>> getDtoReactive(
        @PathVariable(name = "type", required = false) String type) {
    if (StringUtils.isEmpty(type)) {
        type = "default";
    }
    return dtoReactiveRepo.findByType(type).map(dto -> ResponseEntity.ok().body(dto));
}

6

Esempio semplificato del commento di Nicolai Ehmann e della risposta di Wildloop (funziona con Spring 4.3.3+), praticamente puoi usare required = falseora:

  @RequestMapping(value = {"/json/{type}", "/json" }, method = RequestMethod.GET)
  public @ResponseBody TestBean testAjax(@PathVariable(required = false) String type) {
    if (type != null) {
      // ...
    }
    return new TestBean();
  }



-5
$.ajax({
            type : 'GET',
            url : '${pageContext.request.contextPath}/order/lastOrder',
            data : {partyId : partyId, orderId :orderId},
            success : function(data, textStatus, jqXHR) });

@RequestMapping(value = "/lastOrder", method=RequestMethod.GET)
public @ResponseBody OrderBean lastOrderDetail(@RequestParam(value="partyId") Long partyId,@RequestParam(value="orderId",required=false) Long orderId,Model m ) {}

3
Potresti voler modificare un po 'di testo nella tua risposta, spiegando perché pensi che ciò contribuisca a risolvere il problema in questione (4 anni dopo).
Qirel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.