I have an existing spring-mvc application with different #RestController. Now I want to add a Mono<String> endpoint, and log the request timestamp with url path, as well as the response timestamp.
But how? I cannot simply #EnableWebFlux as I would have to disable spring-mvc therefor.
How could I register a filter explicit for the webflux endpoint that catches on invocation, and right before the response is written back async?
#RestController
public class FluxService {
#PostMapping
public Mono<String> post() {
return webClient.post().uri(uri).bodyValue(payload).retrieve().bodyToMono(String.class);
}
}
I want enhanced logging on the #PostMapping endpoint, not on the webClient!
MVC is a blocking/servlet based api, mixing it with webflux isn't going to work. They use different filters, security etc as MVC assumes a lot of ThreadLocal stuff. (Can I use SpringMvc and webflux together?)
If you really want to mix them like this you could use .doOnNext() once you get your mono and call your logger there.
Related
I am using Resttemplate to build an simple API gateway in spring-boot project. When my gateway receive a request from client, it dispatch the request to another Service through RESTful call, and then pass the response back to client.
My code snippet like below:
#RestController
#RequestMapping("api/v1/message")
public class GatewayController {
#PostMapping
public ResponseEntity<Response> dispatchRequest(#RequestBody Request request) {
validateInput(request);
Response response = restTemplate.post(URL_OF_ANOTHOER_SERVICE, request, ...);
return ResponseEntity.ok(response);
}
}
I have more than 100 requests per second approximately, and I know that Resttemplate is thread-safe.
My questions:
Is Resttemplate OK to do such work? Will it become bottleneck?
Is there any other suggestions?
Thank you very much.
You can try Spring Cloud Gateway or Spring Cloud Netflix.
You don`t need to build a gateway from scratch unless you want. And even if you want to, you could consider aspects such as security, maturity and maintenance
Some modules of Spring Cloud Netflix
have gone into maintenance mode, therefore, Spring Cloud Gateway might be a good option as GJohannes quoted
html file not returning in the Rest API and return the file name only like 'index' for the following code when used #RestController and working fine only for #Controller.
Here I am using spring boot REST application and index.html with bootstrap
If you know REST web services then you must know the fundamental difference between a REST API and a web application i.e. the response from a web application is generally view (HTML + CSS) because they are intended for human viewers.
REST API just returns data in form of JSON or XML because most of the REST clients are programs. This difference is also obvious in the #Controller and #RestController annotation.
#RestController = #Controller + #ResponseBody
When you use #Controller annotation then it corresponds to MVC workflow in Spring Boot and it renders the view. The key difference is that you do not need to use #ResponseBody on each and every handler method once you annotate the class with #RestController.
#ResponseBody is a Spring annotation which binds a method return value to the web response body. It is not interpreted as a view name. It uses HTTP Message converters to convert the return value to HTTP response body, based on the content-type in the request HTTP header. The content type can be JSON or XML.
It is the expected behaviour of #RestController. The main difference between #RestController and #Controller is #RestController will by-pass the view resolution but #Controller will not.
Technically , it is due to the presence of the #ResponseBody of the #RestController. #ResponseBody will enable RequestResponseBodyMethodProcessor to process the result return from the #RestController method and it will mark that the request has been fully handled within the controller method and by-pass the view resolution process (see this).
I'm developing some reactive microservices using Spring Boot 2 and Spring 5 with WebFlux reactive starter.
I'm facing the following problem: I want to handle all HTTP Statuses that I receive from calling another REST Services and throws an exception when I receive some bad HTTP Status. For example, when I call an endpoint and I receive an 404 HTTP Status, I want to throw an exception and that exception to be handled in some ExceptionHandler class, just like the way it was in Spring 4 with #ControllerAdvice.
What is the right way to do this? Hope to receive some good suggestions.
This can be addressed in two independent parts.
How to convert HTTP 404 responses received by WebClient into custom exceptions
When using WebClient, you can receive HTTP 404 responses from remote services. By default, all 4xx and 5xx client responses will be turned into WebClientResponseException. So you can directly handle those exceptions in your WebFlux app.
If you'd like to turn only 404 responses into custom exceptions, you can do the following:
WebClient webClient = //...
webClient.get().uri("/persons/1")
.retrieve()
.onStatus(httpStatus -> HttpStatus.NOT_FOUND.equals(httpStatus),
clientResponse -> Mono.error(new MyCustomException()))
.bodyToMono(...);
This is obviously done on a per client call basis.
You can achieve the same in a more reusable way with an ExchangeFilterFunction that you can set once and for all on a WebClient instance like this:
WebClient.builder().filter(myExchangeFilterFunction)...
How to handle custom exceptions in WebFlux apps
With Spring WebFlux with annotations, you can handle exceptions with methods annotated with #ExceptionHandler (see Spring Framework reference documentation).
Note: using a WebExceptionHandler is possible, but it's quite low level as you'll have no high-level support there: you'll need to manually write the response with buffers without any support for serialization.
I think what you are looking for is WebFluxResponseStatusExceptionHandler the check this for reference.
In the WebHandler API, a WebExceptionHandler can be used to to handle
exceptions from the chain of WebFilter's and the target WebHandler.
When using the WebFlux Config, registering a WebExceptionHandler is as
simple as declaring it as a Spring bean, and optionally expressing
precedence via #Order on the bean declaration or by implementing
Ordered.
This example may help, have not tried it myself.
#Component
#Order(-2)
class RestWebExceptionHandler implements WebExceptionHandler{
#Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
if (ex instanceof PostNotFoundException) {
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
// marks the response as complete and forbids writing to it
return exchange.getResponse().setComplete();
}
return Mono.error(ex);
}
}
class PostNotFoundException extends RuntimeException {
PostNotFoundException(String id) {
super("Post:" + id + " is not found.");
}
}
I came across authentication code in my company's java code. The application is a set of several REST services built on Spring MVC. There is a method that gets called in one of the authentication services on the HttpServletRequest object called getHeader(). And the method retrieves an AuthId. Why would they use HttpServletRequest in a spring MVC application? What are the benefits of using this servlet type code in the spring app? What would this method do? Any alternatives?
Spring MVC provides a lot of fabulous abstractions on top of HttpServletRequest, so you can avoid its low-level implementation details. You rarely need to access it directly.
For example, you could get a header value like Content-Type like this:
#GET
#Path("/myService")
public Response doSomething(#HeaderParam("Content-Type") String contentType) {
...
}
But there are times when you do need to access the HttpServletRequest directly--usually when you are using another API that demands it. If you are using some other library with a method you need that takes HttpServletRequest, then you got to grab it from Spring MVC directly.
For example, check out this method in this random UrlUtil class:
public static String encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
//Get a path segment
}
You have no choice but to grab HttpServletRequest from Spring MVC.
Spring MVC is built on the Servlet API. Anything you could do with a Servlet, you can therefore do with Spring MVC. What the Spring MVC framework provides is a wrapper to code a web application in a specific architectural style. This wrapper adds behavior and some times simplifies tasks.
Why would they use HttpServletRequest in a spring MVC application?
In this case, because it is the most direct way to get the header.
What are the benefits of using this servlet type code in the spring
app?
Spring doesn't have to wrap anything. You get it directly from the source.
What would this method do?
Read the javadoc.
Any alternatives?
In a #Controller class' handler method, you can declare a parameter annotated with #RequestHeader and have Spring pass an argument that it retrieves from the HttpServletRequest headers.
This is, by default, restricted to #Controller methods annotated with #RequestMapping. If your service class is a HandlerInterceptor, Filter, or other type of class and simply has a reference to the HttpServletRequest object, there is nothing more you can do than retrieve it directly with getHeader(String).
Here is an alternative : Spring MVC define the parameter annotation #RequestHeader to read httpServletRequest headers :
#RequestMapping(...)
public #ResponseBody String myMethod(#RequestHeader String AuthId){
//the value of the parameter AuthId is the value of request header named AuthId
...
}
This is the short description of my situation...
I have spring bean BookingServiceImpl which implements BookingService
BookingService has method: RoomDescription getRoomDescriptionById(String roomId);
I also have JSP page with javascript on it
I want to do something like this in javascript
var roomDescription = bookingService.getRoomDescriptionById(222);
/// ... use roomDescription
The question is: is there any existent framework which does things like that (magically allows to cal spring beans from javascript without additional boiler-plate code, assuming all parameters and method results are JSON-friendly)?
Spring provides mechanisms to expose RESTful endpoints via the Web MVC framework
The documentation is very good. A Controller definition for your specific example could look like this:
#Controller
#RequestMapping(value = "/rooms/{roomId}", method = RequestMethod.GET, produces="application/json")
#ResponseBody
public Room getRoom(#PathVariable String roomId, ModelMap modelMap) {
return bookingService.getRoomById(roomId);
}
On the javascript side, you could use jQuery to make an ajax call to retrieve the data. Here is an example of what that could look like:
$.getJSON('http://yourserver.com/rooms/222',
function(room) {
// Do something with room.description
});
This is a basic example (without proper error handling, security, etc). It's the closest thing to an existent framework that I'm aware of for Spring RESTful calls from javascript. If you need to access the Room data on the client side javascript then you'll need to expose it via some Spring construct (e.g. a Controller)
Take a look at DWR. This is as close as you will get to creating js clients.
http://directwebremoting.org/dwr/documentation/server/integration/spring.html