I have a Spring Boot app in which I created a POST method, that expects some input from the user via HTML Thymeleaf. Once the input gets fetched, I am producing a string that represents a final URL. Then I want to pass this string URL in my Configuration Class that contains a CommandLineRunner.
The problem is that CommandLineRunner gets executed upon the application start which means that my input has null values thus throwing Null Pointer Exception. Is it possible to add data for my CommandLineRunner after application's start-up and somehow the execution of the latter goes smoothy???
REST CONTROLLER CLASS
package com.andrekreou.covid.gov.controller;
import com.andrekreou.covid.gov.model.Covid;
import com.andrekreou.covid.gov.model.Date;
import com.andrekreou.covid.gov.service.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class Controller {
private final Service service;
#Autowired
public Controller(Service service) {
this.service = service;
}
#GetMapping(path = "/covid")
public List<List<Covid>> getData(){
return service.getData();
}
#PostMapping(value = "/insert/date")
public String insertDate(#ModelAttribute("date") Date date) {
String inserted_date = date.getDate();
return "https://data.gov.gr/api/v1/query/mdg_emvolio?date_from=" + inserted_date + "&date_to=" + inserted_date;
}
}
CONFIG CLASS
package com.andrekreou.covid.gov.configuration;
import com.andrekreou.covid.gov.controller.Controller;
import com.andrekreou.covid.gov.model.Covid;
import com.andrekreou.covid.gov.model.Date;
import com.andrekreou.covid.gov.repository.CovidRepo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.List;
#Configuration
public class CovidConfig {
Controller controller;
Date date;
#Bean
CommandLineRunner commandLineRunner(CovidRepo covidRepo){
return args -> {
String url = controller.insertDate(date);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.set("Authorization","Token 8329eb4fa30e567d9e3f6bfed266c8cb4c9c94ad");
HttpEntity<Object> request = new HttpEntity<>(headers);
ResponseEntity<List<Covid>> postEntity = restTemplate.exchange(
url,
HttpMethod.GET,
request,
new ParameterizedTypeReference<>() {
});
List<Covid> covidList = postEntity.getBody();
assert covidList != null;
covidRepo.saveAll(covidList);
System.out.println(covidList);
};
}
}
POJO CLASS
package com.andrekreou.covid.gov.model;
public class Date {
private String date;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
HTML THYMELEAF
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>login</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous">
<style>
body {
background-color: #3e3e3e;
color: white;
}
h2 {
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<form class="date" name="date" method="post" action="/insert/date" enctype="application/x-www-form-urlencoded">
<h2 class="form-register-heading">Please Enter Date</h2>
<p>
<label for="date" class="sr-only">Date</label>
<input type="text" id="date" name="date" class="date" placeholder="date" required=""
autofocus="">
</p>
<button class="btn btn-lg btn-primary btn-block" type="submit">Insert Date</button>
</form>
</div>
</body>
</html>
The question is a little bit strange. As you say that this functional interface is called when we run our applications with command-line(So it is called CommandLineRunner) and at that time we may give some params from command prompt like that java -jar MyApp "param1" "param2". param1 and param2 are passed to main method as params. So it is called only one time.
CommandLineRunner is a simple Spring Boot interface with a run method.
Spring Boot will automatically call the run method of all beans
implementing this interface after the application context has been
loaded.
PS: if you want to call your business logic after the completion of the method, You can you Spring AOP. if you have another scenario like performing a method in a different thread, may use ExecutorServices class in order to reach it or you can implement it by yourself.
Related
I'm building a blog app and in this instance I want to create a new post. I created a controller with #GetMapping and #PostMapping with value "/posts/new". I used
th:action = "#{'/posts/new'}" (LINE 14) in thymeleaf but when I start the web app, and access the localhost:8080/posts/new it gives the 404 error that the url is not found, but it is there...I double checked spelling, code...pretty much everything but just can't seem to figure out what mistake did I make. Here is the code:
post_new.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Blog :: New Post</title>
</head>
<body>
<div class="container">
<a th:href="#{/}">Home</a>
<form action="#"
th:action="#{'/posts/new'}"
th:object="${post}">
<input type="hidden" th:field="*{account}" />
<input type="hidden" th:field="*{createdAt}" />
<h2>Write new post</h2>
<div>
<label for="new-post-title">Title</label>
<input id="new-post-title" type="text" th:field="*{title}" placeholder="Title"/>
</div>
<div>
<label for="new-post-body">Body</label>
<textarea id="new-post-body" th:field="*{body}"></textarea>
</div>
<button type="submit">Publish post</button>
</form>
</div>
</body>
</html>
PostController.java
package com.hellion.writeup.controller;
import com.hellion.writeup.models.Account;
import com.hellion.writeup.models.Post;
import com.hellion.writeup.service.AccountService;
import com.hellion.writeup.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.Optional;
#Controller
public class PostController {
#Autowired
private PostService postService;
#Autowired
private AccountService accountService;
#GetMapping("/posts/{id}")
public String getPost(#PathVariable Long id, Model model) {
Post post = postService.getPost(id, model);
if (post != null) {
model.addAttribute("post", post);
return "post";
} else {
return "404";
}
}
#GetMapping("/posts/new")
public String createNewPost(Model model){
return postService.createNewPost(model);
}
#PostMapping("/posts/new")
public String saveNewPost(#ModelAttribute Post post){
postService.save(post);
return "redirect:/posts/" + post.getId();
}
}
PostService.java
package com.hellion.writeup.service;
import com.hellion.writeup.models.Account;
import com.hellion.writeup.models.Post;
import com.hellion.writeup.repository.PostRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
#Service
public class PostService {
#Autowired
private PostRepository postRepository;
#Autowired
private AccountService accountService;;
public Optional<Post> getById(Long id) {
return postRepository.findById(id);
}
public List<Post> getAll() {
return postRepository.findAll();
}
public Post save(Post post) {
if (post.getId() == null) {
post.setCreatedAt(LocalDateTime.now());
}
return postRepository.save(post);
}
public Post getPost(Long id, Model model) {
Optional<Post> optionalPost = getById(id);
if (optionalPost.isPresent()) {
Post post = optionalPost.get();
return post;
}
return null;
}
public String createNewPost(Model model){
Optional<Account> optionalAccount = accountService.findByEmail("user.user#domain.com");
if(optionalAccount.isPresent()){
Post post = new Post();
post.setAccount(optionalAccount.get());
model.addAttribute("post", post);
return "post_new";
}else{
return "404";
}
}
}
post.html
<!DOCTYPE HTML>
<html land= "en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE-edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link th:href="#{/styles/style.css}" rel="stylesheet" />
<title>Writeup :: Post</title>
</head>
<body>
<div class ="container">
<a th:href="#{'/'}">Home</a>
<div class="post">
<h2 th:text="${post.title}">Title</h2>
<h5 th:text="'Written by: ' + ${post.account.getFirstName()}">Account First Name</h5>
<h5 th:text="'Created on: ' + ${post.createdAt}">Created At</h5>
<p th:text="${post.body}">Body text</p>
</div>
</div>
</body>
</html>
The GET method for /posts/new invokes the method createNewPost in the service layer. If optionalAccount does not exist, the page 404 is returned. A possible issue is the optionalAccount is empty hence returning 404.
if(optionalAccount.isPresent()) {
Post post = new Post();
post.setAccount(optionalAccount.get());
model.addAttribute("post", post);
return "post_new";
} else {
return "404";
}
The th:action should be th:action="#{/posts/new}".
I found the solution...So basically, I got stackoverflow error and the solution to that is, because I was using Lombok and #Data annotation in my "model" package, the #Data was causing some bugs and by changing it to #Getter and #Setter the issue was fixed.
The output which I am getting HELLO USER DATAcom.example.demo.model.Employee#209e65b
and the output which I need HELLO USER DATA Employee(empId=99,empName=AA,empSal=200.0
Please check the image for project files
**Employee.java(Model Class)**
package com.example.demo.model;
import lombok.Data;
#Data
public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
}
**EmployeeController.java(Controller Class)**
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.demo.model.Employee;
#Controller
#RequestMapping("/employee")
public class EmployeeController {
#GetMapping("/reg")
public String showReg()
{
return "Register";
}
#PostMapping("/save")
public String readform(
#ModelAttribute Employee employee,
Model model
)
{
System.out.println(employee);
model.addAttribute("emp",employee);
return "data";
}
}
**data.html**
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>
REGISTER FORM
</title>
</head>
<body>
<pre>
HELLO USER DATA<span th:text="${emp}"></span>
</pre>
</body>
</html>
**Register.html**
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>
REGISTER FORM
</title>
</head>
<body>
<pre>
<h2>Employee Registration Page</h2>
<form th:action="#{/employee/save}" method="post">
ID : <input type="text" name="empId"/>
NAME : <input type="text" name="empName"/>
SALARY : <input type="text" name="empSalary"/>
<button type="submit" Text-align: center>CREATE</button>
</form>
</pre>
</body>
</html>
**Main_PAGE_CODE**
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MySpringBootThyemleaf21Application {
public static void main(String[] args) {
SpringApplication.run(MySpringBootThyemleaf21Application.class, args);
}
}
-------------------------------------------------------------------------------
I am getting the package and class name as an output instead of the output data which needs to be fetched from the model class and need to be displayed while using at the time of model.addattribute -> at this point I am adding the object of the model class "employee"
I have been digging around on the web and here the last two days to try to find a solution to this and I am coming up empty-handed. The application seems to function normally but I keep getting the warning mentioned in the title. It repeats itself regularly in the spring console and I have no idea what is causing it.
Full warning:
WARN 3652 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
As mentioned, this repeats itself the whole time I have the application running locally.
Here is the html page with the form:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en">
<head>
<link rel="stylesheet" href="/styles.css">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="container">
<form action="/" th:object="${url}" method="POST">
<input th:field="*{longUrl}" type="url" placeholder="Url to shorten" />
<input class="button" type="submit" value="Shorten">
</form>
<div class="formstyle">
<span class="longlink" th:text="${url.longUrl}"></span>
<span class="shortlink" ><a th:href="#{${shortUrl}}" target="_blank" rel="noopener noreferrer" th:text="${shortUrl}"></a></span>
<span class="copy"><button class="copybutton" onClick="copyUrl()">Copy</button></span>
</div>
</div>
</body>
<script th:inline="javascript">
function copyUrl() {
var tempInput = document.createElement("input");
tempInput.style = "position: absolute; left: -1000px; top: -1000px";
tempInput.value = /*[[${shortUrl}]]*/;
document.body.appendChild(tempInput);
tempInput.select();
tempInput.setSelectionRange(0, 99999)
document.execCommand("copy");
document.body.removeChild(tempInput);
}
</script>
</html>
Here is my controller class:
package com.afairbairn.urlshrt.controller;
import com.afairbairn.urlshrt.entity.Url;
import com.afairbairn.urlshrt.service.UrlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
#Controller
public class AppController {
#Autowired
private UrlService urlService;
#GetMapping("/")
public String index(Model model){
model.addAttribute("url", new Url());
return "index";
}
#PostMapping("/")
public String ConvertLongUrl(#ModelAttribute Url url, BindingResult bindingResult, Model model, HttpServletRequest request) {
String currUrl = request.getRequestURL().toString();
String shortUrl = urlService.ConvertLongUrlObject(url);
shortUrl = currUrl + shortUrl;
model.addAttribute("shortUrl", shortUrl);
return "index";
}
#GetMapping(value = "/{shortUrl}")
#Cacheable(value = "urls", key = "#shortUrl", sync = true)
public ResponseEntity GetToRedirect(#PathVariable String shortUrl) {
String url = urlService.ReturnLongUrl(shortUrl);
return ResponseEntity.status(HttpStatus.FOUND)
.location(URI.create(url))
.build();
}
}
This is my first post here so if I haven't provided some necessary details let me know.
TIA!
::UPDATE::
The problem has something to do with the second #GetMapping. When I remove it or comment it out the warning goes away. Just this line is causing the warning: #GetMapping(value = "/{shortUrl}")
I am trying to create a simple spring MVC app in Scala I did define my methods in the controller to bring back html pages based on name from resources folder but it just always brings back just index page and the rest of html pages while trying to access the route it just fails, but same application works fine in Java.
full source code is here:-
Java:-
https://github.com/kali786516/SpringConfigServer-client/tree/master/src/main/java/com/example/SpringConfigServerclient
Scala:-
https://github.com/kali786516/SpringConfigServer-client/tree/master/src/main/scala/com/ps/spring/mvc/psbankapp
Error in Scala:-
Index html Works Fine:-
but rest of the routes doesn't work in scala
Scala controller:-
package com.ps.spring.mvc.psbankapp.controllers
import org.springframework.beans.factory.annotation.Value
import org.springframework.cloud.context.config.annotation.RefreshScope
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.RequestMethod
//#RefreshScope
#Controller
//#ComponentScan(basePackages = Array("com.ps.spring.mvc.psbankapp"))
class AccountController {
#RequestMapping(value = Array("/"))
def showHomePage(): Unit = {
"index"
}
#RequestMapping(value = Array("/new"), method = Array(RequestMethod.GET))
def newAccount(): Unit = {
"newAccount"
}
#RequestMapping(value = Array("/showAccount"))
def showAccount(): Unit = {
"showAccount"
}
}
Java Controller:-
package com.example.SpringConfigServerclient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMethod;
#RefreshScope
#Controller
public class RateController {
#RequestMapping(value = "/index",method = RequestMethod.GET)
public String getIndex() {
return "index";
}
#RequestMapping(value = "/new",method = RequestMethod.GET)
public String newAccount() {
return "newAccount";
}
#RequestMapping(value = "/showAccount",method = RequestMethod.GET)
public String showAccount() {
return "showAccount";
}
}
Finally got it working by adding below context in my HTML files.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
Answer:-
Error resolving template "index", template might not exist or might not be accessible by any of the configured Template Resolvers
full html if you need:-
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Pluralsight Training: Config Client</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"></link>
</head>
<body>
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<h1>Pluralsight Training: Welcome to PS Bank Web Application index</h1>
</div>
<div class="col-md-2"></div>
</div>
</body>
</html>
I've got 2 classes - Contact and Phone, class Contact has a Set of Phones .
Here's mine controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class ContactFormController {
#Autowired
ContactRepository contactRepo;
#Autowired
PhoneRepository phoneRepo;
#RequestMapping(value = "/data", method = RequestMethod.GET)
public String showAll(Model model) {
model.addAttribute("contacts", contactRepo.findAll());
model.addAttribute("phones", phoneRepo.findAll());
return "dataresult";
}
I want to display records of my database through thymeleaf template, here's my html code :
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Dane</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>Dane</h3>
<p th:each="contact : ${contacts}">
<h4>ID:</h4>
<div th:text="${contact.id}"></div>
<h4>Name:</h4>
<div th:text="${contact.firstName}"></div>
<li th:each="item : ${contact.phones}" th:text="${item}">Item description here...</li>
<div>---------</div>
</p>
</body>
</html>
Here's what I've got as result - http://i.imgur.com/pPIA5ma.png
Phone class - http://pastebin.com/L6Sqsp9q
Contact class has a
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "contactId")
private Set phones;
How can i make my controller to display Contact id, name AND Set of phone numbers ?
What you have there is printing the Phone itself which explains your output. What you need to do is access the number field of the item. For example,
th:each="item : ${contact.phones}" th:text="${item.number}"
or,
th:each="item : ${contact.phones}" th:text="${item.getNumber()}"