Hardcoding URL in Spring - 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.

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.

#RequestMapping at class level

I'm new to springboot. I want to create a class with #RequestMapping at class level. I have a static html file located resource/static/main/index.html
#Controller
#RequestMapping("/home")
public class HomeController {
#GetMapping
#ResponseBody
public String Welcome(){
return "Hello World";
}
#GetMapping("/message")
public String message(){
return "main/index.html";
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, user-scalable=yes">
<title>Hello Message!</title>
</head>
<body>
Welcome everyone!
</body>
</html>
http://localhost:8080/home display Hello World in my browser. When I enter http://localhost:8080/home/message, I get a 404 message, The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. If I remove #RequestMapping("/home") from the class level then it works. My goal is to have mulitple #GetMapping and #RequestMapping at the class level
If you are using thymeleaf then try:
#GetMapping("/message")
public String message(){
return "main/index";
}
The index view location must be resources/templates

HTML Page Doesn't Show Up on Springboot Application

I'm trying to create a registration page. The website is very simple, homepage will be returning signup page and when clicked "Submit" it should save it to the database. But I'm having trouble with getting the page.
Applicant.java
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.Date;
#Entity
#Table(name = "bayilik_basvuru")
public class Applicant {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#NotBlank(message = "İsim Soyisim Girilmelidir.")
#Column(name = "isim_soyisim")
private String adSoyad;
public Applicant() {
}
public String getAdSoyad() {
return adSoyad;
}
public void setAdSoyad(String adSoyad) {
this.adSoyad = adSoyad;
}
}
Controller
#Controller
public class HomeContoller {
#Autowired
private ApplicantDAO dao;
#RequestMapping("/")
public ModelAndView getApplicationPage(){
ModelAndView model = new ModelAndView();
Applicant applicant = new Applicant();
model.addObject("applicant",applicant);
model.setViewName("index");
return model;
}
#PostMapping("/save")
public String saveApplicant(#Valid Applicant applicant, BindingResult result){
if (result.hasErrors()) {
return "add-student";
}
dao.save(applicant);
return "index";
}
}
Index.html -> form's piece,
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Bayilik Ön Başvuru Formu</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" type="text/css" th:href="#{../css/style.css}" />
<link rel="stylesheet" type="text/css" th:href="#{../css/bootstrap-datetimepicker.min.css}" />
<link rel="stylesheet" type="text/css" th:href="#{../css/roboto-font.css}" />
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</head>
<body>
<form class="form-horizantal" th:action="#{/save}" th:object="${applicant}"
method="POST">
<div class="form-group">
<label class="col-md-4 control-label">İsim Soyisim</label>
<div class="col-md-8">
<input type="text" th:field="*{adSoyad}" class="form-control" /> <!-- it gives error at this line at the start of the th:field-->
<span th:if="${#fields.hasErrors('adSoyad')}" th:errors="*{adSoyad}" class="text-danger"></span>
</div>
</div>
</body>
</html>
I have been dealing with this for hours. I've compared it to many examples and html file looks good, controller looks good I don't know what I'm doing wrong.
In my pom file I have thymeleaf;
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
...
<dependendcies>
By the way the error is this;
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Oct 31 01:40:47 EET 2019
There was an unexpected error (type=Internal Server Error, status=500).
Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "index" - line 27, col 56) // this line is the same line I showed on the index.html file
You are not using the annotation #ModelAttribute on your /save endpoint . try using it like :
#PostMapping("/save")
public String saveApplicant( #Valid #ModelAttribute("applicant") Applicant applicant, BindingResult result){
if (result.hasErrors()) {
return "add-student";
}
dao.save(applicant);
return "index";
}
In your thymeleaf template th:object="${applicant}" expression declares the model object to use for collecting the form data. So , in your controller you have to use the annotation #ModelAttribute to bind the Applicant object to the incoming form content.
Change your get method to properly add the object:
#GetMapping("/") //simpler, more informative
public String getApplicationPage(Model model){
model.addAttribute("applicant", new Applicant()); //note method name
return "index";
}
Look at Project Lombok to greatly simplify your beans. You are missing a getter and setter for your id property and an annotation of #Getter and #Setter on the class would remove a lot of boilerplate.
You would also want the #ModelAttribute annotation on your post method for the Applicant parameter.
In the future, also please post your full stack trace.
It seems like there was an hierarchy problem on the project. Code worked after I fixed the hierarchy of files.
Thanks to repliers for their attempt to help but they couldn't know the core of the problem since I didn't attach the hierarchy's screenshot on the question.

JSP to Thymeleaf logic & forward syntax equivalent

In trying to move from JSP to Thymeleaf- in the former a Spring Boot initial class (with the main method) performed some validation on a user logging in, and if valid would present a banner.jsp. On agreeing to the banner.jsp's statement the user would click the "Ok" (on the banner.jsp), which called an index.jsp that used
<c:if test='${empty Validated}'><jsp:forward page="/do/Index" /></c:if>.
This ultimately brought up the webapp.
In converting to Thymeleaf I can get
<c:if test='${empty Validated}'><jsp:forward page="/do/Index" /></c:if> piece within the index (now .html). I'd figure something like
<div th:if="${empty Validated}" th:action="#{/do/Index}"></div>
might work, but it returns a 404 error. I'm wondering if I would , instead, need to call a controller. If that's the case I'm unsure of the syntax.
I've tried some syntax variations of the <div th:if="${empty Validated}" th:action="#{/do/Index}"></div> without success.
Index.html (as Thymeleaf)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<!--<c:if test='${empty Validated}'><jsp:forward page="/do/Index" /></c:if>-->
<div th:if="${empty Validated}" th:action="#{/do/Index}"></div>
</body>
</html>
I would want the forward functionality to be successfully mimicked in Thymeleaf so that the index.html opens the webapp
Controller
package mil.dfas.springmvc.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
/**
* #author David Higgins
*/
#Controller
public class LMSSpringController {
private static final Logger log = LoggerFactory.getLogger(LMSSpringController.class);
#Value("${messages.banner:default-value}")
private String message = "HelWd";
#RequestMapping("/banner")
public String welcome(Model model) {
log.info("Config Example");
System.out.println("LMS Controller");
model.addAttribute("msg","Forward Handled");
return "banner";
}
/* #GetMapping("/index")
public String indexHandler() {
System.out.println("index cont");
return "forward:/do/Index";
}*/
#RequestMapping(value = "/index", method = RequestMethod.POST)
public ModelAndView indexHandler(ModelMap model) {
model.addAttribute("attribute", "index");
System.out.println("index cont");
return new ModelAndView("forward:/do/Index", model);
}
#RequestMapping("/")
public void handleRequest() {
throw new RuntimeException("test exception");
}
}

Playframework2 like reverse routing in 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.

Resources