За допомогою Spring я можу зробити необов'язковий змінний шлях?


187

Чи можу я мати додаткову змінну шляху із Spring 3.0?

Наприклад

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

Тут я хотів би /json/abcабо /jsonназвати той же метод.
Один очевидний спосіб оголошення typeв якості параметра запиту:

@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();
}

і тоді /json?type=abc&track=aaабо /json?track=rrбуде працювати

Відповіді:


194

Ви не можете мати необов'язкові змінні шляху, але ви можете мати два методи контролера, які викликають один і той же код послуги:

@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: На мою думку, це переконлива причина не використовувати змінні шляху. Комбінаторне розповсюдження може швидко вийти з ладу.
скафман

9
Насправді це не тому, що шлях не може бути таким складним під час заповнення додатковими компонентами. Якщо у вас є більше одного або максимум двох необов'язкових елементів шляху, слід серйозно розглянути можливість перемикання декількох з них на запит параметрів.
Патрік Корнеліссен

1
І для деяких людей, коли другий метод контролера викликає перший метод контролера, може також працювати, якщо, наприклад, інший параметр може бути наданий якимось іншим способом
chrismarx

3
Будь ласка , зверніть увагу поновлення відповіді, замість того , щоб створити два методу контролера в новій версії Spring можна використовувати тільки @RequestMappingз двома значеннями , як в: stackoverflow.com/questions/17821731 / ...
csharpfolk

omg, як ви розраховуєте підтримувати ці кінцеві точки? І якщо замість лише однієї змінної шляху у нас 5, зробіть математику для мене, скільки кінцевих точок ви зробили б? Будь ласка , зробіть мені послугу і замінити @PathVariableна@RequestParam
Гільєрме Аленкар

113

Якщо ви використовуєте Spring 4.1 і Java 8 ви можете використовувати , java.util.Optionalякий підтримується @RequestParam, @PathVariable, @RequestHeaderі @MatrixVariableв 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"
    }       
}

ти впевнений, що це спрацює? Ваша власна відповідь тут говорить про те, що контролер не потрапить, якщо {type} відсутній у шляху. Я думаю, що PathVariable Map був би кращим підходом або з використанням окремих контролерів.
Аншул Тіварі

4
Так, якщо у вас просто є "/json/{type}"і вводити його немає, він не потрапить (як підказує моя відповідна відповідь), але ось у вас є value = {"/json/{type}", "/json" }. Тож якщо будь-який один метод контролера буде відповідати.
Aniket Thakur

Чи можливо, що однакове значення та ін. Типу буде також RequestParam і RequestParam?
зигімантус

Це працює, але все одно функція контролера не буде викликана, оскільки він очікує параметр там
EliuX

15
Це працює, і починаючи з Весни 4.3.3, ви також можете перейти до @PathVariable(required = false)та отримати нульове значення, якщо змінної немає.
Ніколай Ехман

76

Невідомо, що ви також можете вводити карту змінних шляху за допомогою примітки @PathVariable. Я не впевнений, чи доступна ця функція навесні 3.0 чи вона була додана пізніше, але ось інший спосіб вирішити приклад:

@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
Я використовую його постійно. Це стає зручним, коли я хочу, щоб єдиний метод обробляв різні типи урі, наприклад: {"/ json / {type}", "/ json / {type} / {xyz}", "/ json / {type} / {abc} "," / json / {type} / {abc} / {щось} "," / json "}
Вайбс

25

Ви можете використовувати:

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

для необов'язкових парам, а не для зміни змінної


1
Здається, що ця версія є специфічною. Не вирушайте до Весни 3.
Стю Томпсон

5
В даний час використовується цей метод для проекту весни 3.1, і документи говорять, що він працює для версії 2.5+, тому він безумовно працює для Spring 3. EDIT: source .
Еван Б.

22
Щоправда, але це не про що йдеться. Використання параметрів запиту дійсно згадується у питанні як "Очевидне вирішення" , але саме питання стосується параметрів шляху . Це не є рішенням для необов'язкових параметрів шляху.
Ар'ян

9
PathVariable і RequestParam різні.
Безчасний

10

Spring 5 / Spring Boot 2 приклади:

блокування

@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));
}

реактивний

@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

Спрощений приклад коментаря Ніколая Еманна та відповіді wildloop (працює з Spring 4.3.3+), в основному ви можете використовувати required = falseзараз:

  @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
Можливо, ви захочете відредагувати текст у своїй відповіді, пояснивши, чому, на вашу думку, це сприяє вирішенню проблеми (4 роки потому).
Qirel
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.