Lazy load Spring web page from Spring controller - spring

I currently have a web page that displays some text and a set of images. In my Spring controller, I have two Java functions that retrieve this data however, the images take considerably longer to load and nothing appears on the web page until the images have been loaded. Is there a way to lazy load a web page from the Spring controller? Here is my controller
#Controller
public class Controller {
#RequestMapping(value = "/location/{city}", method = RequestMethod.GET)
public String getData(#PathVariable("city") String city, Model model) throws Exception {
model.addAttribute("cityName", city);
Dashboard.getTextData(city, true);
Dashboard.getImages(city);
return "location";
}
}

I think we can go with Asynchronous methods, Asynchronous(CompletableFuture interface) methods provide multi-thread from which we can load an image, while the main thread will do its other work other than the loading the image.
for asynchronous methods in spring, you can refer this asynchronous methods

Related

Spring - store object in session without MVC

I have a clean javascript + html + css frontend project, which sends a POST request to a backend endpoint.
Backend is a SpringBoot application.
I need to store a shopping cart into server's session and not into browser's session. Previously the project was a Spring MVC + Thymeleaf app, but I am rewriting it to JS + Spring.
In previous app version is was handled by #ModelAttribute and #SessionAttribute annotations, but simple "copy-paste" of all classes and configs does not solve the issue.
Example Controller:
#Controller
#SessionAttributes("basket")
public class LabelDesignController implements IPageModel {
#ModelAttribute("basket")
public Basket populateBasketForm() {
logger.info("[Model Attribute] populating [Basket] form.");
return new Basket();
}
#PostMapping(value = "/myEndPoint", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public Object myEndPoint(#ModelAttribute("basket") Basket b, Item newItem) {
// some logic here
}
}
Item is a POJO class.
EDIT:
forgot to mention, the frontend are static HTML pages with vanilla JavaScript (even no jQuery). they are running on Nginx server. The backend is running on mvn spring-boot:run command.

How Do I configure Spring View Resolver to Ignore a Specific Url and Not Look for Its .jsp?

I am working on a web application using Spring MVC architecture. I have a controller method that will be called by an ajax post(). The request mapper in the controller has a ".html" (meant for some cleanup task)for which the Spring Internal view resolver is trying to find a matching .JSP file and throws a 404 Not Found error. I donot want to create a .JSP which is not useful in my case. I need some help to determine if there is any setting in Spring Context xml to let the view resolver ignore this url and not to look for its .JSP file.
#RequestMapping(value = "/clearSession.html")
public void unloadDAOSession(HttpServletRequest request) {...}
the InternalViewResolver is looking for clearSession.jsp which throws a 404 Resource Not found. I dont want to create a JSP which is of no use.
Are there any application Context settings in the view resolver to ignore this ".html" file and not to look for its ".jsp"?
Any help is appreciated.
Even though the return type is void it only means that the view name will be resolved based on the URL as you have seen.
One way to avoid view resoluion is to annotate the response with #ResponseBody or
bypass the view resolver by tweaking your return type to something like
#RequestMapping(value = "/clearSession.html")
public ResponseEntity<String> unloadDAOSession(HttpServletRequest request) {
...
return new ResponseEntity<String>("OK",HttpStatus.NO_CONTENT);
}
This way instead of forwarding to a view, your just adding a header and an empty body to the response stream
In case of use of ajax and traditional controller, the best approach is write the your controller for answare to the page rendering as you had done adn then write a rest end-point layer for answare to ajax request.
I just give you some piece of code for clearing what I want say:
Controller layer:
#RequestMapping(value = "/yourPage")
public void yourPage(Model mode) {...}
Rest layer:
#RequestMapping(value = "/yourAjax")
public ResponseEntity<String> yourAjax(#RequstBody YoutDTOClass postBody) {
...
return ResponseEntity.created(...).build();
}
class YoutDTOClass{
// your properties
....
}
with this schema you separate the service layer for your ajax request and the classic web layer for serving the your page.
Just an hint don't use a pattern like /yourPage.html but you should prefare a pattern like /youtPage.This balically for banefit of the view resolver abstraction of Spring, you should let to springMVC to resolve the actual view.
Even for the ajax you should use the accept header for ask the correct rappresentation of your resource and the ResponseEntity should be used for return a 201 Http status for say to your browser that the your resource was created. remember that a better approach should prefere the use of http method in REST world and then for delete a session you should be prefare delte method for delete a session and put http method for update the sate of the session.
I hope that this can help you

Best practice to access and display data from DB that is common across all pages

I have a webstore with a bunch of Spring MVC controllers defined for each JSP page such as HomePageController, CategoryPageController, ProductPageController, CartPageController etc. and all these controllers makes a call to the DB to fetch and display the menu on top of JSP pages. Each of the controllers mentioned above makes a call to the DB in order to fetch the menu.
I am using Spring 3.0 framework.
HomePageController.java
#Controller
#RequestMapping(HOME_PAGE_CONTROLLER)
public class HomePageController extends BasePageController {
#RequestMapping(method = RequestMethod.GET)
protected ModelAndView processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ModelAndView mav = new ModelAndView();
mav.addObject("menuCategories", masterDataService.getAllMenuCategories());
return showPage(mav, HOME_PAGE_URL);
}
}
I kind of feel that this call is redundant because
1) all the controllers are making this call to build the menu
2) difficult to maintain because change in business logic will require changes in multiple controllers
What is the best practice in this type of scenario? How can I avoid this call getting make from multiple controllers? Is there a way to make this call at a central location so that this piece of code does not cut across all the controllers?
Avoid duplicating code across controller classes - If all controller classes extend BasePageController:
public abstract class BasePageController {
...
#ModelAttribute
public void initMenuCategories(Model model) {
model.addAttribute("menuCategories", masterDataService.getAllMenuCategories());
}
...
}
Reduce database calls per page - Consider caching the menu categories if they don't change too often:
#Service
public class MasterDataService {
...
#Cacheable(key = "menu", value = "menu")
public List<MenuCategory> getAllMenuCategories() { ... }
...
}
You will have to add a cache named menu to your service layer configuration for this to work. See the documentation on Caching with Spring for details.

Spring JSF application flow

I have previously written Spring MVC web applications where there is a front controller and we have a request mapping in each of the methods and this method in turn invokes a service implementation finally returning a view to the UI. Now when I design JSF applications am not able to understand the flow as such -
This is what I currently have in my application:
The initial index.html redirects to the login page.
A backing bean for the login page which populates label values. Since it is an input form there is no other logic involved.
Once the user clicks on submit -> in the action method I have logic which will invoke the service(No.1) for authentication process and redirect the user to the home page by returning the name of the page
The home page displays various fields which are bound to a backing bean whose fields have to be populated by another web service call(No.2).
It is between the steps (3) and (4), I have a confusion. Previously in Spring I had an explicit mapping and I can "actually" control the logic in the front controller method. In JSF, I dont know whether the logic for No.2 web service call should be combined along with authentication call since I dont have a method to populate the beans.
It is as if I dont have the explicit control over the flow. I have read many articles trying to understand this but not am able to understand. Please provide me pointers and also some references which will actually explain this better.
Why can't you control the logic in JSF bean?Example usage with EJB
#ManagedBean
#RequestScoped
public class LoginBean {
#EJB
private AuthBean authBean;
#EJB
private UserSettings settingsBean;
private String name, password;
#PostConstruct
private void init() {
//do your initialization here
}
public String loginAction() {
User user = authBean.authenticate(user, password);
if(user != null) {
UserSetting settings = settingsBean.getSettings(user.getId());
return "home";
}
}
//setters and getters
}

How to configure which controllers Spring #ControllerAdvice will be applied to?

I have two types of controllers in my spring application.
View controllers that forward to views to generate HTML
API controllers that return JSON directly from the controllers
Both the API and View controllers are part of the same spring dispatcher servlet. Spring 3.2 introduced the #ControllerAdvice annotation to allow for a global location to handle exception.
The documentation implies that #ControllerAdvice will be applied to every controller associated with a Dispatcher Servlet.
Is there a way to configure which controllers #ControllerAdvice will apply to?
For example in my scenario I want a #ControllerAdvice for my View Controllers and separate #ControllerAdvice for my API controllers.
For people that will still find this question:
As from Spring 4 ControlerAdvice's can be limited to Controler's with the specified annotations. Take a look at:
http://blog.codeleak.pl/2013/11/controlleradvice-improvements-in-spring.html
(second half of this article) for more details.
UPDATE
I am using spring 4. You can do one of 2 below options.
(1) You can add the packages you want. (Inside those packages you have controllers that you want to follow #ControllerAdvice).
Ex:
#ControllerAdvice(basePackages={"my.pkg.a", "my.pkg.b"})
(2) You can directly add the controller classes you want.
Ex:
#ControllerAdvice(basePackageClasses={MyControllerA.class, MyControllerB.class})
I do not think this is possible now. If you can make the API and View controllers throw different Exception types, then you could define two different #ExceptionHandlers and achieve what you want.
// For handling API Exceptions
#ExceptionHandler(APIException.class) // Single API Exception
#ExceptionHandler({APIException.class, ..., ,,,}) // Multiple API Exceptions
// For handling View Exceptions
#ExceptionHandler(ViewException.class) // Single View Exception
#ExceptionHandler({ViewException.class, ..., ...}) // Multiple View Exceptions
You could use aop to translate the Exceptions coming out of APIs to a standard APIException. See this thread on spring forums.
Hope it helps.
Your exceptions should not dictate the content-type of your response. Instead check the request's Accept header for what the browser expects.
#ExceptionHandler(Throwable.class)
public #ResponseBody String handleThrowable(HttpServletRequest request, HttpServletResponse response, Throwable ex) throws IOException {
...
String header = request.getHeader("Accept");
if(supportsJsonResponse(header)) {
//return response as JSON
response.setContentType(JSON_MEDIA_TYPE.toString());
return Json.stringify(responseMap);
} else {
//return as HTML
response.setContentType("text/html");
}
#ExceptionHandler(value=Exception.class)
public ModelAndView error(Exception ex) {
return new ModelAndView("redirect:/error/m");
}
...//ErrorController
#RequestMapping(value = "/m", produces="text/html")
public ModelAndView error()...
#RequestMapping(value = "/m", produces="application/json")
#ResponseBody
public Map errorJson()...

Resources