I'm completely new to the Spring framework (and most web development in general), but I'm trying to hook up some heavy Java backend code to a new Spring and JSP project. My Controller's handleRequest() is kicking off a long running worker thread before it returns my request.jsp ModelAndView object. After that I'd like to be able to still interface with this Controller from my JSP form to be able to call isThreadDone() in the Controller whenever a button in the form is clicked. Based on three different results, I then redirect accordingly. Is this possible with my current approach? This seems to violate some of the Spring MVC approach, but I can't think of a good way to do this that I can wrap my head around. If anything is way off here, please excuse my ignorance. Thanks in advance.
Take a look at the Spring #Async annotation. If you annotate a Service-layer bean with that annotation, it then runs in its own thread, allowing your Controller thread to run without interruption after calling the Service method. Have that thread is set a value held at the Class level for the Service via synchronous methods, and your Controller code can just check those toggles at will to see if the process is done or not. Something like:
#Service
public myServiceClass {
private boolean isDone = false;
public synchronized void setIsDone(boolean isDone) {
isDone = isDone;
}
public synchronized boolean getIsDone() {
return isDone;
}
#Async
public void myServiceMethod() {
...long-running stuff...
setIsDone(true);
}
In the Controller:
#Controller
class MyController {
#RequestMapping
public kickOffHandlerMethod() {
myServiceClass.myServiceMethod();
}
}
#RequestMapping
public dependentHandlerMethod() {
if(myServiceClass.getIsDone()) {
...do something...
}
}
}
If more than one request might kick off the process, then I would save each isDone toggle in a HashMap with some kind of identifier. Then the threads would update individual toggles, one for each request.
Well, anything is possible, right? Based on what you've provided, you can just keep a reference to the thread--maybe in the HttpSession--so that when a new request comes in from clicking the button, you can query it and return an appropriate response.
Related
I am learning spring security and I came across the concept of filters. On reading a little bit what I understood is that dispatcher servlet receives the request first (also called the front controller for the same reason), after that it calls a certain mapper which helps to invoke the required controller method. Please let me know if my understanding is wrong somewhere.
Further I came across OncePerRequestFilter, I referred this link to understand it :
https://www.baeldung.com/spring-onceperrequestfilter
In an example mentioned here :
#Controller
public class HelloController {
#GetMapping(path = "/greeting")
public DeferredResult<String> hello(HttpServletResponse response) throws Exception {
DeferredResult<String> deferredResult = new DeferredResult<>();
executorService.submit(() -> perform(deferredResult));
return deferredResult;
}
private void perform(DeferredResult<String> dr) {
// some processing
dr.setResult("OK");
}
}
it says that if we use a normal Filter, it will be invoked twice,
1- because of the TOMCAT/http-worker thread and
2- because of the new thread branched out
My doubt is that how come branching out a new thread invokes the filter again. I mean my understanding was that filter just sits between dispatcher servlet and controller. After it has reached controller there is no filter coming in between, during the controller method processing.
Can anyone please help me understand the same.
In a nutshell, I have 2 doubts :
1- how spanning a new thread in controller may invoke the filter again, in case of async/defferedresult
2- does it means that for synchronous requests we dont need OncePerRequestFilter explicitly, It'll be anyway only once. If not, then in what case will the filter be invoked twice in case of Sync requests.
I have some problems regarding Controller usage in Spring.
Preferably, I would like to keep the Controller methods small and simply use them to call a Service function as follows:
#Controller
class controllerClass {
#RequestMapping("/foo/")
public void foo(Model model) {
Data returnedData = fooServiceFunction();
model.addAttribute("data", returnedData);
}
}
#Service
class serviceClass {
fooServiceFunction() {
Data data = methodCall();
methodCall2();
methodCall3();
return data;
}
}
However, in practise I have found this implementation difficult because I have found myself needing to check if the methods called from within the fooServiceFunction() succeeded or failed. I have been returning a custom 'Status' class from these functions which is passed to the controller to signal if the methods have executed successfully and/or any errors that have occurred (validation errors, etc.).
Now, this is fine if I do not need to return any data. But if I want to return data from the Service function and pass it to the Controller, this would mean I would need to make a custom class for EVERY Controller method which would contain:
a) the data.
b) the success status
which just seems unreasonable.
I have considered just throwing Exceptions to indicate a failure, but this doesn't seem proper.
Is there a better way? What is the optimal way to handle these situations? Or should I just write fat Controller methods that implement more of the application/business logic?
Thank you.
I think the best approach would be to throw a custom exception and then use a class annotated with
#ControllerAdvice
to deal with that exception and make it return a ResponseEntity customized according to your needs. This way the line
return data;
will only occur if there are no exceptions
I am using Spring Boot 1.4 and Java8. I want to know is it possible that if I receive a get request for an API in controller. I immediately return a response to the client and then create a background task for the request (that handle success and exception scenarios). I understand we can use completablefuture for async processing, but still from controller method for this API we generally send the response after using thenapply, exceptionally or get. That means though we have spawned a new thread. Main thread is still not free. I am looking for hit and forget kind of use case. Please suggest how it may be feasible.
as stated in comments you can use async functionality from Spring. For that you'll need a configuration like
#EnableAsync
#Configuration
public class AsyncConfig {
#Bean
public Executor threadPoolTaskExecutor() {
return new ConcurrentTaskExecutor(Executors.newCachedThreadPool());
}
}
then put the annotation on the method which is running the background task
#Async
void runBgTask() { /* ... */ }
and call it in your controller method
#GetMapping("/foo")
public Foo hello() {
runBgTask();
return new Foo();
}
I have a simple rest controller (using spring web-FLUX), that get a bean to save in database. But as usual, I would like to validate some fields of it before saving.
I have a validation method to be called before save the bean. But how could I do that in a more functional (and appropriate) manner?
I have tried something like:
public void save(Mono<MyBean> myBean) {
myBean.map(this::validateBean).map(myRepository::save)
}
But the method validateBean is not being called, only when I do something like
public void save(Mono<MyBean> myBean) {
myBean.map(this::validateBean)
.map(myRepository::save)
.subscribe();
}
I don't know if the subscribe part is the most correct one (I believe it isn't), but I think it works because is kind of a terminal operation. Am I right?
Even so, that does not solve my problem, because my validation method throws a BusinessException when something is wrong with the bean. And that is exactly what I wanna do.
[EDITED]
This is my rest controller would me something like:
#PostMapping(value = "/something")
public Mono<ResponseEntity> salvar(#RequestBody MyBean myBean) {
return myService.salvar(myBean)
.map(RestResponses::ok)
.defaultIfEmpty(RestResponses.empty());
}
I know this is not working because my service ir no returning anything. But I do not know what would be the correct way. So I just post an idea. Thanks for understanding...
Could you guys give me some help?
In a Play! controller, I can create an interceptor method that will process every request before it arrives to the appropriate action.
public class Admin extends Application {
#Before
static void checkAuthentification() {
if(session.get("user") == null) login();
// otherwise,
User loggedOnUser = User.find("byUsername", session.get("user"));
}
public static void index() {
// any way to access loggedOnUser ?
List<User> users = User.findAll();
render(users);
}
…
}
Is there a way to set a value in the interceptor and access it in the action? Sort of like request.setAttribute() in servlets?
You can use renderArgs parameter from Controller (see here) or you can store the value in the Cache (we can assume that as the value was added miliseconds ago, your value will be available while in the same request).
Interceptors and actions share the same request context (request, response, session, etc). As stated above, you may elect to use renderArgs, but keep in mind that these values will be available in your views, which may not be what you want. If you want to keep the state between your interceptor and actions, just use the request.args hash instead.