最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - ResponseEntity: add a body to a 404 Not Found as return in GET Spring Boot Controller - Stack Overflow

programmeradmin2浏览0评论

I am developing a Controller in Spring Boot. In case the item is not found in the DB I would like to resurrect a ResponseEntity with Http code of type HttpStatus.NOT_FOUND, but also a message saying that the item was not found. The following method works but only returns HttpStatus.NOT_FOUND.

import org.springframework.http.ResponseEntity;

   @GetMapping(
            value = "/plants/{id}",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
        Optional<ResponsePlantVocDTO> responsePlantDTOOptional = service.getPlantById(id);
        return responsePlantDTOOptional.map(
                responsePlantVocDTO -> ResponseEntity
                .status(HttpStatus.FOUND)
                .body(responsePlantVocDTO))
                .orElse(
                        ResponseEntity.notFound().build()
                );
    }

I have tried other solutions but I get the following error: Required type: ResponseEntity , Provided: ResponseEntity

@GetMapping(
            value = "/plants/{id}",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
        Optional<ResponsePlantVocDTO> responsePlantDTOOptional = service.getPlantById(id);
        return responsePlantDTOOptional.map(
                responsePlantVocDTO -> ResponseEntity
                .status(HttpStatus.FOUND)
                .body(responsePlantVocDTO))
                .orElse(
                        // ResponseEntity.notFound().build()
                        ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message")
                );
    }

UPDATE: this is my controller

import jakarta.validation.Valid;
import orgr.plantvocdb.dto.PlantInfoDTO;
import orgr.plantvocdb.dto.RequestPlantVocDTO;
import orgr.plantvocdb.dto.ResponsePlantVocDTO;
import orgr.plantvocdb.service.PlantsVocService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

@RestController
@RequestMapping("/api/v1/voc")
public class PlantsVocController {


    private final PlantsVocService service;

    @Autowired
    public PlantsVocController(PlantsVocService service) {

        this.service = service;
    }


    /*
     * GETs
     * */

    @GetMapping(
            value = "/plants",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public List<PlantInfoDTO> getPlantsVocInfo(){
        return service.getAllPlantsInfo();
    }

    /**
     * Get Plant Voc by ID
     */
    @GetMapping(
            value = "/plants/id/{id}",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
        Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantById(id);
        return optionalResponsePlantVocDTO.map(
                responsePlantVocDTO -> ResponseEntity
                .status(HttpStatus.FOUND)
                .body(responsePlantVocDTO))
                .orElse(ResponseEntity.notFound().build());
    }

    /**
     * Get Plant Voc by IPNI (International Plant Names Index) code
     */
    @GetMapping(
            value = "/plants/ipni/{ipni}",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> getPlantByIpni(@PathVariable("ipni") String ipni){
        Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantByIpni(ipni);
        return optionalResponsePlantVocDTO.map(
                        responsePlantVocDTO -> ResponseEntity
                                .status(HttpStatus.FOUND)
                                .body(responsePlantVocDTO))
                .orElse(ResponseEntity.notFound().build());
    }

    @GetMapping(
            value = "/plants/always-emitters",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public List<PlantInfoDTO> getPlantsAlwaysEmitter(){
        return service.getAlwaysEmitters();
    }

    @GetMapping(
            value = "/plants/never-emitters",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public List<PlantInfoDTO> getPlantsNeverEmitter(){
        return service.getNeverEmitters();
    }

    @GetMapping(
            value = "/plants/mixed-emitters",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public List<PlantInfoDTO> getPlantsMixedEmitter(){
        return service.getMixedEmitters();
    }

    /*
    * POSTs
    * */

    @PostMapping(
            value = "/plants",
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> postNewPlant(
            @RequestBody
            @Valid
            RequestPlantVocDTO plantDTO
    ){
        System.out.println("ciao");
        String name = plantDTO.getName();

        ResponsePlantVocDTO newPlant = service.createPlantVoc(plantDTO);
        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body(newPlant);
    }

}

I am developing a Controller in Spring Boot. In case the item is not found in the DB I would like to resurrect a ResponseEntity with Http code of type HttpStatus.NOT_FOUND, but also a message saying that the item was not found. The following method works but only returns HttpStatus.NOT_FOUND.

import org.springframework.http.ResponseEntity;

   @GetMapping(
            value = "/plants/{id}",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
        Optional<ResponsePlantVocDTO> responsePlantDTOOptional = service.getPlantById(id);
        return responsePlantDTOOptional.map(
                responsePlantVocDTO -> ResponseEntity
                .status(HttpStatus.FOUND)
                .body(responsePlantVocDTO))
                .orElse(
                        ResponseEntity.notFound().build()
                );
    }

I have tried other solutions but I get the following error: Required type: ResponseEntity , Provided: ResponseEntity

@GetMapping(
            value = "/plants/{id}",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
        Optional<ResponsePlantVocDTO> responsePlantDTOOptional = service.getPlantById(id);
        return responsePlantDTOOptional.map(
                responsePlantVocDTO -> ResponseEntity
                .status(HttpStatus.FOUND)
                .body(responsePlantVocDTO))
                .orElse(
                        // ResponseEntity.notFound().build()
                        ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message")
                );
    }

UPDATE: this is my controller

import jakarta.validation.Valid;
import org.cnr.plantvocdb.dto.PlantInfoDTO;
import org.cnr.plantvocdb.dto.RequestPlantVocDTO;
import org.cnr.plantvocdb.dto.ResponsePlantVocDTO;
import org.cnr.plantvocdb.service.PlantsVocService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

@RestController
@RequestMapping("/api/v1/voc")
public class PlantsVocController {


    private final PlantsVocService service;

    @Autowired
    public PlantsVocController(PlantsVocService service) {

        this.service = service;
    }


    /*
     * GETs
     * */

    @GetMapping(
            value = "/plants",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public List<PlantInfoDTO> getPlantsVocInfo(){
        return service.getAllPlantsInfo();
    }

    /**
     * Get Plant Voc by ID
     */
    @GetMapping(
            value = "/plants/id/{id}",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> getPlantById(@PathVariable("id") UUID id){
        Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantById(id);
        return optionalResponsePlantVocDTO.map(
                responsePlantVocDTO -> ResponseEntity
                .status(HttpStatus.FOUND)
                .body(responsePlantVocDTO))
                .orElse(ResponseEntity.notFound().build());
    }

    /**
     * Get Plant Voc by IPNI (International Plant Names Index) code
     */
    @GetMapping(
            value = "/plants/ipni/{ipni}",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> getPlantByIpni(@PathVariable("ipni") String ipni){
        Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantByIpni(ipni);
        return optionalResponsePlantVocDTO.map(
                        responsePlantVocDTO -> ResponseEntity
                                .status(HttpStatus.FOUND)
                                .body(responsePlantVocDTO))
                .orElse(ResponseEntity.notFound().build());
    }

    @GetMapping(
            value = "/plants/always-emitters",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public List<PlantInfoDTO> getPlantsAlwaysEmitter(){
        return service.getAlwaysEmitters();
    }

    @GetMapping(
            value = "/plants/never-emitters",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public List<PlantInfoDTO> getPlantsNeverEmitter(){
        return service.getNeverEmitters();
    }

    @GetMapping(
            value = "/plants/mixed-emitters",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public List<PlantInfoDTO> getPlantsMixedEmitter(){
        return service.getMixedEmitters();
    }

    /*
    * POSTs
    * */

    @PostMapping(
            value = "/plants",
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<?> postNewPlant(
            @RequestBody
            @Valid
            RequestPlantVocDTO plantDTO
    ){
        System.out.println("ciao");
        String name = plantDTO.getName();

        ResponsePlantVocDTO newPlant = service.createPlantVoc(plantDTO);
        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body(newPlant);
    }

}
Share Improve this question edited Feb 7 at 11:35 Gianni Spear asked Feb 7 at 10:47 Gianni SpearGianni Spear 7,93624 gold badges91 silver badges140 bronze badges 6
  • Hey, make sure you are importing the correct org.springframework.http.ResponseEntity – Youcef LAIDANI Commented Feb 7 at 11:10
  • Thanks, I checked and import org.springframework.http.ResponseEntity; was imported correct (I updated my question) – Gianni Spear Commented Feb 7 at 11:17
  • Show us the full controller please – Youcef LAIDANI Commented Feb 7 at 11:18
  • Yes. I updated my question, thanks – Gianni Spear Commented Feb 7 at 11:36
  • Same problem using ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message"). – Gianni Spear Commented Feb 7 at 12:07
 |  Show 1 more comment

3 Answers 3

Reset to default 1

I advice you not to handle errors API by API. You should throw a known exception in your system with the message, parameters and any piece of information you will judge useful. And then don't code anything in your Controller but handle it through the use of a unique @ControllerAdvice class. Thus you will have only one algorithm to return 404/400 errors to your clients and not as many as you have APIs in your code.

Please see https://www.baeldung.com/exception-handling-for-rest-with-spring#controlleradvice

The type is not the same in the Optional::map you return ResponseEntity<ResponsePlantVocDTO> and in the orElse you return a ResponseEntity<String>, instead you can use simple if else like this:

Optional<ResponsePlantVocDTO> optionalResponsePlantVocDTO = service.getPlantById(id);
if (optionalResponsePlantVocDTO.isPresent()) {
    return ResponseEntity.status(HttpStatus.FOUND).body(optionalResponsePlantVocDTO.get());
} else {
    return ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message");
}

make your Controller without the

.orElse(
    // ResponseEntity.notFound().build()
    ResponseEntity.status(HttpStatus.NOT_FOUND).body("My message")
);

and focus those business rules on Service. Use Throw method, you can create a business exception class

so, basically you will do:

@GetMapping(value = "/plants/id/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResponsePlantVocDTO> getPlantById(@PathVariable("id") UUID id){
    return ResponseEntity.ok(plant);
} 

public ResponseEntity<ResponsePlantVocDTO> getPlantById(UUID id) {
    ResponsePlantVocDTO plant = repository.findById(id)
        .orElseThrow(() -> new ResourceNotFoundException("Plant not found with id: " + id));
}


On your business exception you can create a class to make it custom: 
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

Obs: its not a goot practice to transform the entity on service, you should create another level on your project for that (facade / mapper)

发布评论

评论列表(0)

  1. 暂无评论