swagger-ui.html 400 bad request

2019-08-20 01:12发布

问题:

I have integrated swagger in my spring boot project. All swagger endpoints are working fine but /product/swagger-ui.html is giving 400 error.

After some debugging I have found that there is conflict between two endpoints.

In my application.properties file, I am using server.contextPath=/product.

In my controller I have following mappings that I think have caused error.

ProductRestController.java

@RestController
public class ProductRestController {

    // some autowired services

    @GetMapping("/{id}")
    public ResponseEntity<ProductDTO> getProductById(
            @Min(value = 1, message = "id {javax.validation.constraints.Min.message}") @PathVariable Long id,
            @RequestAttribute Long tenantId) {
        return ResponseEntity.ok(productService.getProductById(id, tenantId));
    }

    @PutMapping("/{id}")
    public ResponseEntity<ProductDTO> updateProduct(
            @Min(value = 1, message = "id {javax.validation.constraints.Min.message}") @PathVariable Long id,
            @RequestBody HashMap<String, Object> requestBody, @RequestAttribute Long tenantId,
            @RequestAttribute Long userId) {

        ProductDTO productDTO;
        try {
            productDTO = objectMapper.convertValue(requestBody, ProductDTO.class);
        } catch (IllegalArgumentException e) {
            throw new HttpMessageNotReadableException(e.getMessage(), e);
        }

        Set<ConstraintViolation<ProductDTO>> errors = validator.validate(productDTO, ProductDTO.UpdateProduct.class);

        if (!errors.isEmpty()) {
            throw new ConstraintViolationException(errors);
        }

        return ResponseEntity.ok(productService.updateProduct(productDTO, requestBody, id, tenantId, userId));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteProduct(
            @Min(value = 1, message = "id {javax.validation.constraints.Min.message}") @PathVariable Long id,
            @RequestAttribute Long tenantId,
            @RequestParam(required = false, name = "delete_members") boolean deleteMembers) {
        productService.deleteProduct(id, tenantId, deleteMembers);
        return ResponseEntity.status(HttpStatus.NO_CONTENT).body(null);
    }

    //other mappings
}

I debugged and found that HandlerExecutionChain has forwarded this request to getProductById method and then it threw exception cannot cast from String to Long.

So I removed that mapping and again checked if it's working but this time I got HTTP 405 error. Again by debugging I found that stack trace is showing allowed methods are PUT & DELETE.

Then I removed both those mappings and checked, and it's working fine.

What I understood From this is somehow spring is picking /product/{id} mapping for /product/swagger-ui.html endpoint & then it throws error because of type mismatch.

Question is why is this happening and how to resolve this issue?

EDIT : Exception caught in DispatcherServlet.doDispatch method: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "swagger-ui"

Exception caught in same method after removing GET mapping: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported

回答1:

@GetMapping("/{id}") gives id value in String, and you are directly trying to map String to Long. Try to use: @PathVariable String id and then convert your String to Long as following:

Long longId = Long.parseLong(id);