Playframework2 like reverse routing in spring - spring

Can Anyone can advice me routing mechanism in spring.
I use thymeleaf for my view and I would like to use class names and method names for my url in views- just like in playframework.
But I like in spring that I define url before the controller method declaration.
Whaitting for Your sugestion. Thanks.

Since version 4.1, Spring Framework provides a way to generate routes to resources from templates (i.e. reverse routing in views).
You can check the reference documentation on the subject, but it's basically using auto-generated named routes for that.
I don't know if Thymeleaf supports this in its standard dialect, but you could quite easily extend it; if not, this is probably a feature that could be contributed to the Thymeleaf project.
Let's say you have a MyUserController like this:
#Controller
public class MyResourceController {
#RequestMapping("/user/{name}")
public String showUser(String name, Model model) {
...
return "show";
}
}
With such a dialect, you could then refer to an action like this:
<a th:uri="mvcUrl('MRC#ShowUser').buildAndExpand('bob')">Show user Bob</a>
<!-- will generate "/user/bob" -->

This is the general flow in spring framework.
Whenever user makes a request, it will first go to Spring's DispatcherServlet. The DispatcherServlet job is to send the request to spring mvc controller (custom controller)
You can define your custom controller like this:
Controller: (code snippet)
package nl.springexamples.mvc;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
#Controller
public class HomeController {
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test(){
return "test";
}
}
In servlet- context file , mention the directory/package path of your controller.
Example: <context:component-scan base-package="nl.springexamples.mvc"/>
In the above controller, it is returning string 'test' which is name of the view file(usually, it will be jsp).
JSP File: test.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1> Welcome to Spring!!!</h1>
</body>
</html>
Define this logical mapping of string name to view file in servlet-context like this:
Example: How to define internalViewResolver is as shown below
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value ="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
I think, that's pretty much about spring mvc and it's routing flow. I hope it helped you.

Related

What is the way to use variable expression in thymeleaf 2.5.6 version

I just create simple template by the help of thmeleaf, When I try to
access the variable from controller class by the help of variable
Expression , But I get Issue on variable expression ,In the time of
variable expression access . Showing below type of error
cannot Resolve variable name
My variable name is today which I define in my controller class
Homecontroller.kt
package com.nilmani.thymeleafdemo.controller
import org.springframework.web.bind.annotation.RestController
import org.thymeleaf.ITemplateEngine
import org.thymeleaf.context.WebContext
import java.text.SimpleDateFormat
import java.util.*
import javax.servlet.ServletContext
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
#RestController
class HomeController : IGTVGController() {
#Throws(Exception::class)
fun process(request:HttpServletRequest,response: HttpServletResponse,
servletContext: ServletContext,templateEngine: ITemplateEngine){
val dateForm:SimpleDateFormat= SimpleDateFormat("dd-mm-yyyy")
val calendar:Calendar = Calendar.getInstance()
val ctx : WebContext = WebContext(request,response,servletContext,request.locale)
ctx.setVariable("today",dateForm.format(calendar.time))
templateEngine.process("home",ctx,response.writer)
}
}
home.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Welcome TO our WebPage</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="#{/css/gtvg.css}" />
</head>
<body>
<p th:utext="#{home.welcome}">Welcome to our website</p>
<p>Today is: <span th:text= "${today}"></span></p>
</body>
</html>
error shows at this point below point
th:text= "${today}"
What is the reason for not support of variable expression . I already
added thymeleaf gradle depedency in my project.But the variable
expression not working
I don't know Kotlin, so I hope you can convert my Java answer to it.
I see you use #RestController, but if you are using Thymeleaf, use #Controller
You can have Spring Boot inject the Model class and add your attributes there
The easiest is to return a String value that represents the name of the Thymeleaf template.
Using all that, you get something like this:
#Controller
public class HomeController {
public String process(Model model) {
model.addAttribute("today", ...);
return "home"; //this refers to home.html like this
}
}
PS: You should not use Calendar anymore, see https://www.baeldung.com/java-8-date-time-intro for more info on the "new" date/time API introduced in Java 8.

Hardcoding URL in Spring

package com.example.servingwebcontent;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
#Controller
public class GreetingController {
#GetMapping("/greeting")
public String greeting(#RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
<!DOCTYPE HTML>
<html>
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Get your greeting here</p>
</body>
</html>
The examples from the official guide: https://spring.io/guides/gs/serving-web-content/
We can see that the url, that is greeting, is hardcoded.
Suppose, I write that url in 50 places. And now I want to change the url.
Is it somehow possible to escape hardcoding?
The HTTP request can be GET, POST, PUT, DELETE, and PATCH.
To map the HTTP request with your definition, you need to use #GetMapping, #PostMapping, #PutMapping, #DeleteMapping, and #PatchMapping in the controller class.
So, URL /greeting can be used in those 5 requests only. So, we can't write the same URL in 50 places in the controller class.

Need equivalent of JSP tag in Thymeleaf

I am new to Thymeleaf. In jsp world I could change the theme of my Springboot Web Application using the following tags in "head" of a jsp:
<spring:theme code="stylesheet" var="themeName" />
<link href='<spring:url value="css/${themeName}"/>' rel="stylesheet" />
What should I write "as the exact equivalent of above" if I am going to use "Thymeleaf template" instead of jsp? I am using (and must use) spring boot (with web and data). Can someone please point me a way out?
Update
Adding more information.
I have my config and beans as per following:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/static/css**", "/resources/static/**", "/static/")
.setCacheControl(CacheControl.maxAge(2, TimeUnit.HOURS).cachePublic());
}
#Bean
public ThemeSource themeSource() {
ResourceBundleThemeSource themeSource = new ResourceBundleThemeSource();
themeSource.setBasenamePrefix("theme/");
return themeSource;
}
#Bean
public ThemeResolver themeResolver() {
CookieThemeResolver resolver = new CookieThemeResolver();
resolver.setDefaultThemeName("cosmo");
return resolver;
}
And also I have bunch of (e.g. Cosmo.BootStrap.min.css) under themes folder. When I select the theme name from JSP, the theme of my entire webapp gets changed.
In short, using Thymeleaf, in my "header.html fragment", I am trying to acheive something similar to this (${somename}) -
<link href="css/${somename}.css" rel="stylesheet" type="text/css" />
For now I am clueless. Please give some guidance.
You can always build dynamic URLs in Thymeleaf like:
<head th:with="themeName=${'stylesheet'}">
<link th:href="#{|/css/${themeName}|}" rel="stylesheet"/>
</head>
Now themeName can either be populated from the controller in the Model or ModelMap class, or computed in the template HTML.

Hosting a single page application with spring boot

So I am trying to host a Single Page Application alongside a normal REST API with spring.
What this means is that all requests that goes to the normal /api/ endpoints should be handled by the respective controller and all other requests should be directed to the resources in the folder /static/built
I have gotten this to work by catching all NoHandlerFoundExceptions and redirecting to either the js file or the html file. And then used a WebMvcConfigurer to map the static content.
But this all seems like a hack to me, so is there a less hacky way of doing it?
Managed to have React+ReactRouter app working by adding following mapping:
#Controller
public class RedirectController {
#GetMapping(value = {"/{regex:\\w+}", "/**/{regex:\\w+}"})
public String forward404() {
return "forward:/";
}
}
This was inspired by https://stackoverflow.com/a/42998817/991894
The easiest way I get my SPAs to work with a Spring backend API is to have 2 different controllers: one for the root index page of the SPA and the other controller is used to manage various RESTful API endpoints:
Here are my two controllers:
MainController.java
#Controller
public class MainController {
#RequestMapping(value = "/")
public String index() {
return "index";
}
}
MonitoringController.java
#RestController
#RequestMapping(value = "api")
public class MonitoringEndpoints {
#GetMapping(path = "/health", produces = "application/hal+json")
public ResponseEntity<?> checkHealth() throws Exception {
HealthBean healthBean = new HealthBean();
healthBean.setStatus("UP");
return ResponseEntity.ok(healthBean);
}
}
Notice how the API endpoint controller utilizes the '#RestConroller' annotation while the main controller utilizes the '#Conroller' annotation. This is because of how Thymeleaf utilizes it's ViewResolver. See:
Spring Boot MVC, not returning my view
Now go ahead and place your index.html page at src/main/resources/templates/index.html because Spring by default looks for your html pages within this location.
My index.html pages looks like this:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8"/>
<title>EDP Monitoring Tool</title>
</head>
<body>
<!-- Entry point to our ReactJS single page web application -->
<div id="root"></div>
<script type="text/javascript" src="built/bundle.js"></script>
</body>
</html>
Not sure how you're wiring up your frontend, whether that is a ReactJS app or something but I believe this information would be helpful for you. Let me know if I can answer additional questions for you.
In addition, if you're using Webpack, you can set up the entry point of your JS files via the webpack.config.js file under the entry key so like so:
entry: ['./src/main/js/index.js']
I think you're looking for the term URL Rewrite.
E.g. https://getpostcookie.com/blog/url-rewriting-for-beginners/

Failed to load resource: the server responded with a status of 404 (Not Found) in spring mvc

I am trying to load the css file into jsp, it is not loading and showing the message Failed to load resource: the server responded with a status of 404 (Not Found).the following is my code
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Bootstrap Form With Spring Mvc Example</title>
<link href="<c:url value='/resources/css/bootstrap.css'/>" rel="stylesheet" media="screen">
</head>
in configuration class I have added the below code:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
I have tried all the solutions, I did not find what's the wrong,can any one help me?
Try it this way:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**")
.addResourceLocations("/css/");
}
This assumes your directory structure is:
src
main
java
resources
css
webapp
The point is that you don't specify the resources level in your resource handler.
Is your css file in WebContent folder..Please check for it.And if your are using maven it must be in resources folder.If the folder structure is correct.
Please treat the jsp pages like html ..
paste your css file near your jsp folder.And try to access it using href directly instead of using c tag.
<link href="../css/bootstrap.css" rel="stylesheet" media="screen">
This approach is dirty one.But good for jsp pages integrated thymeLeaf kindof tools.
Edit your configuration class to inherit from WebMvcConfigurerAdapter as shown below. It solved my own problem after trying a lot of other options. Hope it would work for you.
public class Config extends WebMvcConfigurerAdapter{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}

Resources