Spring-MVC kontrol cihazında 404 tetikleyicisi?


194

404'ü tetiklemek için bir Spring 3.0 kontrol cihazını nasıl edinebilirim ?

Bir denetleyicim var @RequestMapping(value = "/**", method = RequestMethod.GET)ve denetleyiciye erişen bazı URL'ler için , kabın bir 404 ile gelmesini istiyorum.

Yanıtlar:


326

İlkbahar 3.0'dan bu yana, @ResponseStatusek açıklama ile bildirilen bir İstisna atayabilirsiniz:

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
    ...
}

@Controller
public class SomeController {
    @RequestMapping.....
    public void handleCall() {
        if (isFound()) {
            // whatever
        }
        else {
            throw new ResourceNotFoundException(); 
        }
    }
}

2
İlginç. Atış sitesinde hangi HttpStatus'un kullanılacağını belirtebilir misiniz (yani, Exception sınıfında derlenmemiş)?
— mat b

1
@mattb: Sanırım asıl önemli olan @ResponseStatus, her biri kendine ait olan güçlü bir şekilde yazılmış, iyi adlandırılmış istisna sınıflarından oluşan bir grup tanımlamanızdır @ResponseStatus. Bu şekilde, denetleyici kodunuzu HTTP durum kodlarının ayrıntısından ayırırsınız.
— skaffman

10
Bu, hata hakkında daha fazla açıklama içeren bir gövdeyi iade etmeyi desteklemek için genişletilebilir mi?
— Tom

7
@Tom:@ResponseStatus(value = HttpStatus.NOT_FOUND, reason="Your reason")
— Nailgun

6
Bu ResourceNotFound özel durumunu yalnızca akış denetimi için kullanırsanız, ResourceNotFound.fillInStackTrace()boş bir uygulama ile geçersiz kılmak iyi bir fikir olabilir .
— Ralph


36

Yöntem imzanızı HttpServletResponseparametre olarak kabul edileceği şekilde yeniden yazın , böylecesetStatus(int) onu .

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-arguments


8
Birisi http istemcisine dürtmek ops ekibini düzeltemedikleri bir grup istisna ile doldurmazken hata yaptığını söylemenin bir yolunu arıyorsa, tek doğru cevap budur.
— Alex R

4
setStatus(int)javadoc şöyle ifade eder: Bu yöntem bir hata kodu ayarlamak için kullanılırsa, kabın hata sayfası mekanizması tetiklenmez. Bir hata varsa ve arayan kişi web uygulamasında tanımlanan bir hata sayfasını çağırmak istiyorsa, sendErrorbunun yerine kullanılmalıdır.
— Philippe Gioseffi

@AlexR Ele alınan istisnalar ops ekibine su basmamalıdır. Eğer öyleyse, günlüğe kaydetme yanlış yapılıyor.
— Raedwald

25

Spring tarafından varsayılan olarak 404 için (sadece) istisna olduğunu belirtmek isterim. Ayrıntılar için Yay belgelerine bakın. Yani kendi istisnanıza ihtiyacınız yoksa bunu yapabilirsiniz:

 @RequestMapping(value = "/**", method = RequestMethod.GET)
 public ModelAndView show() throws NoSuchRequestHandlingMethodException {
    if(something == null)
         throw new NoSuchRequestHandlingMethodException("show", YourClass.class);

    ...

  }

11
Bu, Spring'in bir işleyici bulamadığı belirli bir durum için düşünülmüş görünüyor. Bahar zaman söz konusu olduğu için bir işleyici bulmak, ancak kullanıcı başka bir nedenle bir 404 dönmek istiyor.
— Roy Truelove

2
Işleyici yöntemi için ulr eşlemem dinamik olduğunda kullanıyorum. Varlık esas alındığında @PathVariable, benim görüşüme göre herhangi bir istek işleme konulmaz. Ek açıklama eklenmiş kendi İstisnenizi kullanmanın daha iyi / daha temiz olduğunu düşünüyor musunuz @ResponseStatus(value = HttpStatus.NOT_FOUND) ?
— michal.kreuzman

1
Sizin durumunuzda kulağa hoş geliyor, ancak bir istisnanın gerekli olduğu tüm durumları ele almak için sağladığınız bağlantıda bulunan istisnaları tavsiye edeceğimi bilmiyorum - bazen kendinizinkini yapmanız gerekir.
— Roy Truelove

Spring, sadece 404 için bir istisna ve bir istisna sağladı. 404Exception adını vermeli veya bir tane oluşturmalıydılar. Ama şimdi olduğu gibi,
— 404'e

Teknik olarak sorun değil - 404 durum başlığı gönderirsiniz. Ancak otomatik hata mesajı - yanıt içeriği - muhtemelen kullanıcıya göstermek istediğiniz bir şey olmayan "adıyla istek işleme yöntemi yok ..." dır.
— Olli

24

İlkbahar 3.0.2'den beri , denetleyicinin yönteminin bir sonucu olarak ResponseEntity <T> öğesini döndürebilirsiniz :

@RequestMapping.....
public ResponseEntity<Object> handleCall() {
    if (isFound()) {
        // do what you want
        return new ResponseEntity<>(HttpStatus.OK);
    }
    else {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
}

(ResponseEntity <T>, @ResponseBody ek açıklamasından daha esnektir - başka bir soruya bakın )


2
tabii ki esnek ama bildirimsel programlamanın faydalarını yendi
— rohanagarwal

3
PROD'da Sentry veya benzeri bir şey kullanıyorsanız ve gerçek hata olmayan hatalarla spam yapmak istemiyorsanız, bu çözüm, bu istisnai olmayan durum için istisnalar kullanan çözümle karşılaştırıldığında çok daha iyidir.
— Tobias Hermann

Vücudu nasıl dolduracağınızı unutmayın (gerçek nesnenizle). generic "Object" örneği: Object returnItemBody = new Object (); return ResponseEntity.status (HttpStatus.OK) .body (returnItemBody);
— granadaCoder

16

@ControllerAdvice kullanabilirsiniz senin İstisnalar, @ControllerAdvice açıklamalı sınıf bilinen tüm Kontrolörleri yardımcı olacaktır varsayılan davranışını işlemek için.

bu yüzden herhangi bir Denetleyici 404 hatası attığında çağrılır.

aşağıdaki gibi:

@ControllerAdvice
class GlobalControllerExceptionHandler {
    @ResponseStatus(HttpStatus.NOT_FOUND)  // 404
    @ExceptionHandler(Exception.class)
    public void handleNoTFound() {
        // Nothing to do
    }
}

ve web.xml dosyasında bu 404 yanıt hatasını aşağıdaki gibi eşleyin:

<error-page>
        <error-code>404</error-code>
        <location>/Error404.html</location>
</error-page>

Umarım yardımcı olur .


2
Özel durum (ve alt sınıflar) özel durumlarını 404 durum koduyla eşlediniz. Hiç dahili sunucu hataları olduğunu düşündünüz mü? GlobalControllerExceptionHandler'ınızdakileri nasıl işlemeyi planlıyorsunuz?
— rohanagarwal

Bu REST denetleyicileri için işe yaramadı, boş bir yanıt döndürür.
— rustyx

10

Denetleyici yönteminiz dosya işleme gibi bir şey içinse ResponseEntityçok kullanışlıdır:

@Controller
public class SomeController {
    @RequestMapping.....
    public ResponseEntity handleCall() {
        if (isFound()) {
            return new ResponseEntity(...);
        }
        else {
            return new ResponseEntity(404);
        }
    }
}

9

Belirgin cevap doğru olsa da, istisnasız bunu başarmanın bir yolu vardır. Hizmet Optional<T>aranan nesneyi döndürüyor ve bu, HttpStatus.OKbulunursa ve boşsa 404 ile eşleniyor.

@Controller
public class SomeController {

    @RequestMapping.....
    public ResponseEntity<Object> handleCall() {
        return  service.find(param).map(result -> new ResponseEntity<>(result, HttpStatus.OK))
                .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }
}

@Service
public class Service{

    public Optional<Object> find(String param){
        if(!found()){
            return Optional.empty();
        }
        ...
        return Optional.of(data); 
    }

}

Genel olarak bu yaklaşımı seviyorum, ancak Optionals kullanmak bazen bir anti-desen haline geliyor. Ve koleksiyonları döndürürken karmaşıklaşıyor.
— jfzr

7

Ben HttpClientErrorException , bu gibi atma tavsiye ederim

@RequestMapping(value = "/sample/")
public void sample() {
    if (somethingIsWrong()) {
        throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
    }
}

Bunun yalnızca sunucu uygulaması çıkış akışına herhangi bir şey yazılmadan önce yapılabileceğini unutmayın.


4
Bu istisna Spring HTTP istemcisi tarafından atılır. Bahar MVC bu istisnayı tanımıyor gibi görünüyor. Hangi Bahar versiyonunu kullanıyorsunuz? Bu istisna dışında bir 404 elde ediyor musunuz?
— Eduardo

1
Bu Spring Boot'un geri dönmesine neden olur:Whitelabel Error Page \n .... \n There was an unexpected error (type=Internal Server Error, status=500). \n 404 This is your not found error
— ince

Bu bir HTTP istemcisi için bir istisnadır, bir denetleyici için değil. Bu yüzden belirtilen bağlamda kullanmak uygun değildir.
— Alexey

3

Bu biraz geç, ama Spring Data REST kullanıyorsanız o zaman zaten ek açıklama org.springframework.data.rest.webmvc.ResourceNotFoundException kullanır @ResponseStatus. Artık özel bir çalışma zamanı istisnası oluşturmanıza gerek yok.


2

Ayrıca 404 durumunu kontrol cihazınızdan döndürmek istiyorsanız, tek yapmanız gereken bunu yapmaktır

@RequestMapping(value = "/somthing", method = RequestMethod.POST)
@ResponseBody
public HttpStatus doSomthing(@RequestBody String employeeId) {
    try{
  return HttpStatus.OK;
    } 
    catch(Exception ex){ 
  return HttpStatus.NOT_FOUND;
    }
}

Bunu yaptığınızda, kontrol cihazınızdan bir 404 döndürmek istediğinizde bir 404 hatası alırsınız.


0

Basitçe hata kodu ve 404 hata sayfası eklemek için web.xml'yi kullanabilirsiniz. Ancak 404 hata sayfasının WEB-INF altında bulunmaması gerektiğinden emin olun.

<error-page>
    <error-code>404</error-code>
    <location>/404.html</location>
</error-page>

Bunu yapmanın en basit yolu bu ama bazı sınırlamaları var. Bu sayfa için başka sayfalar eklediğiniz aynı stili eklemek isteyip istemediğinizi varsayalım. Bu şekilde bunu yapamazsınız. Kullanmak zorunda@ResponseStatus(value = HttpStatus.NOT_FOUND)


Bunu yapmanın yolu ama HttpServletResponse#sendError(HttpServletResponse.SC_NOT_FOUND); return null;denetleyici kodundan düşünün . Şimdi dışarıdan yanıt, herhangi bir denetleyiciye çarpmayan normal bir 404'ten farklı görünmüyor.
— Darryl Miles

bu bir 404 tetiklemez, sadece bir tane olursa onu ele alır
— Alex R

0

Web.xml dosyasını ayar ile yapılandırın

<error-page>
    <error-code>500</error-code>
    <location>/error/500</location>
</error-page>

<error-page>
    <error-code>404</error-code>
    <location>/error/404</location>
</error-page>

Yeni denetleyici oluştur

   /**
     * Error Controller. handles the calls for 404, 500 and 401 HTTP Status codes.
     */
    @Controller
    @RequestMapping(value = ErrorController.ERROR_URL, produces = MediaType.APPLICATION_XHTML_XML_VALUE)
    public class ErrorController {


        /**
         * The constant ERROR_URL.
         */
        public static final String ERROR_URL = "/error";


        /**
         * The constant TILE_ERROR.
         */
        public static final String TILE_ERROR = "error.page";


        /**
         * Page Not Found.
         *
         * @return Home Page
         */
        @RequestMapping(value = "/404", produces = MediaType.APPLICATION_XHTML_XML_VALUE)
        public ModelAndView notFound() {

            ModelAndView model = new ModelAndView(TILE_ERROR);
            model.addObject("message", "The page you requested could not be found. This location may not be current.");

            return model;
        }

        /**
         * Error page.
         *
         * @return the model and view
         */
        @RequestMapping(value = "/500", produces = MediaType.APPLICATION_XHTML_XML_VALUE)
        public ModelAndView errorPage() {
            ModelAndView model = new ModelAndView(TILE_ERROR);
            model.addObject("message", "The page you requested could not be found. This location may not be current, due to the recent site redesign.");

            return model;
        }
}

0

Çünkü aynı şeyi yapmanın en az on yoluna sahip olmak her zaman iyidir:

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class Something {
    @RequestMapping("/path")
    public ModelAndView somethingPath() {
        return new ModelAndView("/", HttpStatus.NOT_FOUND);
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.