I am studying Java and Spring. I'm doing a small link shortening project (eg www.google.com like gg, etc.). Implemented adding links and displaying them. But after being displayed, these links are not clickable. I tried to use hyperlink, but nothing came of it in the end. How to make links from DB (MySQL) clickable?
No repository and class with constructors, getters and setters specified.
Here is my code
#Controller
public class MainController {
DB db = new DB();
#Autowired
private LinkRepository linkRepository;
#GetMapping("/")
public String link(Model model) {
Iterable<Links> links = linkRepository.findAll();
model.addAttribute("title", "Page with links");
model.addAttribute("link", links);
return "link";
}
#GetMapping("/uslugi")
public String uslugi(Model model) {
model.addAttribute("title", "Page with services");
return "uslugi";
}
#PostMapping("/-add")
public String linkAdd(#RequestParam String long_link, #RequestParam String short_link, Model model) {
Links links = new Links(short_link, long_link);
linkRepository.save(links);
return "redirect:/";
}
}
DB
import java.sql.*;
public class DB {
private final String HOST = "localhost";
private final String PORT = "3306";
private final String DB_NAME = "spring";
private final String LOGIN = "root";
private final String PASS = "root";
private Connection dbConn = null;
private Connection getDbConnection() throws ClassNotFoundException, SQLException {
String connStr = "jdbc:mysql://" + HOST + ":" + PORT + "/" + DB_NAME +
"?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";
Class.forName("com.mysql.cj.jdbc.Driver");
dbConn = DriverManager.getConnection(connStr, LOGIN, PASS);
return dbConn;
}
public void isConnected() throws SQLException, ClassNotFoundException {
dbConn = getDbConnection();
System.out.println(dbConn.isValid(1000));
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.java10</groupId>
<artifactId>serving-web-content</artifactId>
<version>1.0-SNAPSHOT</version>
<name>java10</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>10</source><target>10</target></configuration></plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Html, if needed
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="main.css">
</head>
<header class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
<p class="h5 my-0 me-md-auto fw-normal">Java</p>
<nav class="my-2 my-md-0 me-md-3">
<a class="p-2 text-dark" href="/">Главная</a>
<a class="p-2 text-dark" href="/uslugi">Про нас</a>
</nav>
</header>
<body>
<div class="container mt-5">
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<h3 class="mt-2">Все отзывы</h3>
<div th:each="row : ${link}">
<h4 class="mt-2" th:text="${row.long_link}"/>
<h4 th:text="${row.short_link}"/>
</div>
<h1 class="mt-5" th:text="${title}"/>
<form th:action="#{/-add}" method="post">
<input type="text" name="long_link"
placeholder="Введите ссылку" class="form-control"><br>
<input type="text" name="short_link"
placeholder="Введите короткую ссылку" class="form-control"><br>
<button type="submit" class="btn btn-success">Добавить</button>
</form>
</div>
</body>
<footer class="pt-4 my-md-5 pt-md-5 border-top">
<div class="row">
<div class="col-12 col-md">
<small class="d-block mb-3 text-muted">©2021 Все права защищены</small>
</div>
</div>
</footer>
</html>
Actually, the only thing you'd have to modify to have your links be clickable, is the Thymeleaf template.
You have to replace the h4 element with an a (anchor element), like so:
<h4>
<a th:href="${row.short_link}"
th:text="${row.short_link}" />
</h4>
You can read more about the way Thymeleaf can be used to create different types of HTML elements here.
Related
I am trying to build a web application in Spring Boot. I would like to map all inputs of a web form to a Java object called UserRequest. I have tried this using a .jsp file and use modelAttribute but get an error for "modelAttribute="userRequest"" in my .jsp file:
<form:form method="POST" action="/" modelAttribute="userRequest">
"Cannot resolve symbol 'userRequest'". I am using IntelliJ. I have no idea why this is occuring (I know there is a similar thread for a Spring application, but their solution does not work for me). See more details below.
How do I fix this?
index.jsp:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<head>
<title>Find a Dance Event</title>
</head>
<body>
<h2> Find your next Dance Party</h2>
<form:form method="POST" action="/" modelAttribute="userRequest">
<form:label path="profession">Profession:</form:label>
<form:select path="Dance Event" items="${danceEvents}" /><br/>
<form:select path="Dance Style" items="${danceStyles}" /><br/>
<form:label path="street"> Street:</form:label><br>
<form:input path="street"/><br/>
<input type="submit" value="Submit">
</form:form>
</body>
</html>
pom.xml_:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>findadanceevent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>findadanceevent</name>
<description>findadanceevent</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>5.0.0-alpha.10</version>
</dependency>
<!-- Mockito extention -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.2</version>
</plugin>
</plugins>
</build>
</project>
RestServices.java:
#Service
public class RestService {
#GetMapping("/")
public String showForm(Model model){
UserRequest userRequest = new UserRequest();
model.addAttribute("userRequest",userRequest);
List<String> danceStyles = Arrays.asList("Kizomba", "Salsa", "Bachata");
List<String> danceEvents = Arrays.asList("Festival", "Class", "Workshop");
List<String> distances = Arrays.asList("2_5km", "5km", "7_5km", "10km", "over10km");
model.addAttribute("danceStyles", danceStyles);
model.addAttribute("eventType", danceEvents);
model.addAttribute("distances", distances);
return "index";
}
#PostMapping("/")
public String submitForm(#ModelAttribute("userRequest") UserRequest userRequest) {
System.out.println(userRequest);
return "register_success";
}
UserRequest.java:
public class UserRequest {
private String street;
private String typeOfEvent;
private String danceStyle;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getTypeOfEvent() {
return typeOfEvent;
}
public void setTypeOfEvent(String typeOfEvent) {
this.typeOfEvent = typeOfEvent;
}
public String getDanceStyle() {
return danceStyle;
}
public void setDanceStyle(String danceStyle) {
this.danceStyle = danceStyle;
}
#Override
public String toString() {
return "UserRequest{" +
"street='" + street + '\'' +
", typeOfEvent='" + typeOfEvent + '\'' +
", danceStyle='" + danceStyle + '\'' +
'}';
}
}
I am trying to create a new Movie. This means that I want to access the "addMovie" URL, to generate a form in which I add the title of a new movie. This title should be stored in a movieDTO already from the Thymeleaf form. Then, when I press "Submit" I want it to send me to a new page "/saveMovie" that receives the movieDTO from the previous form. Using this movieDTO, I create a new Movie and then "redirect:movie/movies-all" to show all the current movies (including the added one).
However, this does not happen. When I access the URL localhost:8081/addMovie I get these errors:
org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "movie/movie-add" - line 18, col 40)
and this one
Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'movieDTO' available as request attribute at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:153) ~[spring-webmvc-5.3.9.jar:5.3.9].
Thus, I don't understand what the issue is. Is it that it does not store the information in the movieDTO correctly (or at all)? or is it because the bean movieDTO is not sent to the post method?
The Project Structure:
The Controller:
package movie_API.movie.controllers;
import movie_API.movie.services.MovieService;
import movie_API.movie.services.beans.MovieDTO;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid;
import java.util.Arrays;
import java.util.List;
#Controller
//#RequestMapping("/something") <- if you want a general something before the other resources
public class MovieController {
private final MovieService movieService;
public MovieController(MovieService movieService) {
this.movieService = movieService;
}
#RequestMapping("/addMovie")
public String add() {
return "movie/movie-add";
}
#RequestMapping(value = "/saveMovie", method = RequestMethod.POST)
public String create(#ModelAttribute("movieDTO") #Valid MovieDTO movieDTO, Model model, BindingResult result) {
System.out.println("got into post");
if (result.hasErrors()) {
System.out.println("error in result");
return "movie/movie-add";
}
//movieService.saveNewMovie(movieDTO);
movieService.showMovies(model);
return "redirect:movie/movies-all";
}
}
The movieDTO + the corresponding getters and setters:
package movie_API.movie.services.beans;
import java.io.Serializable;
public class MovieDTO implements Serializable {
private static final long serialVersionUID = -8040351309785589042L;
private String metascore;
private String title;
private String year;
private String description;
private String genreId;
public MovieDTO(String metascore, String title, String year, String description, String genreId) {
this.metascore = metascore;
this.title = title;
this.year = year;
this.description = description;
this.genreId = genreId;
}
}
The movie-add.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Add Movie</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
</head>
<body>
<div class="container my-5">
<h2 class="mb-5">New Movie</h2>
<div class="row">
<div class="col-md-6">
<form action="#" th:action="#{/saveMovie}" th:object="${movieDTO}" method="post">
<label>
<input type="text" th:field="*{title}" name="title" class="form-control" placeholder="insert string here">
</label>
<input type="submit" class="btn btn-primary" value="Submit">
</form>
</div>
</div>
</div>
</body>
</html>
The movies-all.html:
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org/" lang="en">
<head>
<title> All Movies </title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Movies table</h2>
<p>Here are all the movies we have in the database:</p>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>metascore</th>
<th>title</th>
<th>year</th>
<th>description</th>
<th>genre</th>
</tr>
</thead>
<tbody>
<tr th:each="movie, stat: ${allMovies}">
<td th:text="${movie.id}"></td>
<td th:text="${movie.metascore}"></td>
<td th:text="${movie.title}"></td>
<td th:text="${movie.year}"></td>
<td th:text="${movie.description}"></td>
<td th:text="${allGenres[stat.index]}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
The movieService:
package movie_API.movie.services;
import movie_API.movie.models.Movie;
import movie_API.movie.repositories.GenreRepository;
import movie_API.movie.repositories.MovieRepository;
import movie_API.movie.services.beans.MovieDTO;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import java.util.List;
#Service
public class MovieService {
private final MovieRepository movieRepository;
private final GenreRepository genreRepository;
private List<Movie> movies;
private Movie movie;
public MovieService(MovieRepository movieRepository, GenreRepository genreRepository) {
this.movieRepository = movieRepository;
this.genreRepository = genreRepository;
}
public void showMovies(Model m) {
m.addAttribute("allMovies", getMovies());
//System.out.println("done with movies");
m.addAttribute("allGenres", getGenreNames());
//System.out.println("done with genres");
}
public void showMovieByID(Model m, String id) {
m.addAttribute("movie", getMovieById(id));
m.addAttribute("genreName", getGenreNameByMovieId());
}
public List<Movie> getMovies() {
movies = movieRepository.findAll();
//System.out.println(movies.get(0).toString());
return movies;
}
public Movie getMovieById(String id) {
this.movie = movieRepository.findById(id).get();
return movie;
}
public List<String> getGenreNames() {
return movieRepository.getGenreNames(movies, genreRepository);
}
public String getGenreNameByMovieId() {
String genreId = movie.getGenreId();
return genreRepository.findById(genreId).get().getName();
}
public void saveNewMovie(MovieDTO movieDTO) {
Movie movie = new Movie();
movie.setTitle(movieDTO.getTitle());
movie.setYear(movieDTO.getYear());
movie.setMetascore(movieDTO.getMetascore());
movie.setDescription(movieDTO.getDescription());
movie.setGenreId(movieDTO.getGenreId());
movieRepository.save(movie);
}
public void updateMovie(MovieDTO movieDTO, String id) {
Movie movie = movieRepository.findById(id).get();
movie.setTitle(movieDTO.getTitle());
movie.setYear(movieDTO.getYear());
movie.setMetascore(movieDTO.getMetascore());
movie.setDescription(movieDTO.getDescription());
movie.setGenreId(movieDTO.getGenreId());
movieRepository.save(movie);
}
public void deleteMovie(String id) {
movieRepository.deleteById(id);
}
}
The pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>movie_API</groupId>
<artifactId>movie</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>movie</name>
<description>Movie REST API</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Main problems:
What are the errors? Why is the movieDTO not created according to the given input from the User? (I can only assume it is not properly created because it's always null when I want to access it)
Why is the redirect not recognizing the movies-all location?
for the first error, just add an empty DTO to the model;
#RequestMapping("/addMovie")
public String add(Model model) {
model.addAttribute("movieDTO", new MovieDTO());
return "movie/movie-add";
}
For the second error, remove the "redirect:" part
movieService.showMovies(model);
return "movie/movies-all";
Then you will get the pages you want;
A warning;
Please add default constructor, setters/getters and id field to the DTO.
Error
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Apr 27 21:00:28 BST 2020
There was an unexpected error (type=Internal Server Error, status=500).
The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application
controller
package com.sales.controllers;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.sales.models.Product;
import com.sales.services.ProductService;
#Controller
public class MainController {
#Autowired
ProductService ps;
#RequestMapping(value = "/showProducts.html")
public String getProducts(Model model) {
ArrayList<Product> products = ps.getAllProducts();
model.addAttribute("products", products);
return "listProducts";
}
#RequestMapping(value = "/addProduct.html")
public String addPerson(Model model) {
Product p = new Product();
model.addAttribute("products", p);
return "addProduct";
}
}
listProducts.js
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>List of Products</title>
</head>
<body>
<h1>List of Products</h1>
<table>
<tr>
<th>Product ID</th>
<th>Description</th>
<th>Quantity in Stock</th>
</tr>
<tr>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.pId}</td>
<td>${product.pDesc}</td>
<td>${product.qtyInStock}</td>
</tr>
</c:forEach>
</tr>
<tr>
<td>Home</td>
</tr>
</table>
</body>
</html>
product class
package com.sales.models;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Min;
import org.hibernate.validator.constraints.NotBlank;
#Entity
#Table(name="PRODUCTS")
public class Product {
#Id
#GeneratedValue
#Column(name="PID")
private Long pId;
#Column(name="PDESC")
#NotBlank
private String pDesc;
#Column(name="QTYINSTOCK")
#Min(value=0)
private int qtyInStock;
#OneToMany(mappedBy="prod")
private List<Order> ordersForProduct = new ArrayList<Order>();
public Long getpId() {
return pId;
}
public void setpId(Long pId) {
this.pId = pId;
}
public String getpDesc() {
return pDesc;
}
public void setpDesc(String pDesc) {
this.pDesc = pDesc;
}
public int getQtyInStock() {
return qtyInStock;
}
public void setQtyInStock(int qtyInStock) {
this.qtyInStock = qtyInStock;
}
public List<Order> getOrdersForProduct() {
return ordersForProduct;
}
public void setOrdersForProduct(List<Order> ordersForProduct) {
this.ordersForProduct = ordersForProduct;
}
}
run class
package com.sales;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class FinalProjV1Application {
public static void main(String[] args) {
SpringApplication.run(FinalProjV1Application.class, args);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sales</groupId>
<artifactId>Sales</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>FinalProjV1</name>
<description>Sales Application</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I am new to spring boot and do not know why my #PostMapping is not working and leading to a white label error. Everything else works fine and I can add customers to the h2 database. However, once I add customers and go to URL localhost:8084/getdetails and type 1, a white label error occurs. However, the form in the ViewCustomers.jsp file is still displayed but cannot take in any input. The form should invoke toString() of the customer object and its fields.
Controller
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class FormController {
#Autowired
CustomerRepo repo;
#RequestMapping("/")
public String details() {
return "edureka";
}
#RequestMapping("/details")
public String details(Customers customers) {
repo.save(customers);
return "edureka";
}
#RequestMapping("/getdetails")
public String getdetails() {
return "ViewCustomers";
}
#PostMapping("/getdetails")
public ModelAndView getdetails(#RequestParam int cid) {
System.out.println("here");
ModelAndView mv = new ModelAndView("Retrieve");
Customers customers = repo.findById(cid).orElse(null);
mv.addObject(customers);
return mv;
}
}
edureka.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Edureka Customers</title>
</head>
<body>
<form method="post" action="details">
Enter Customer ID: <input type="text" name="cid"><br><br>
Enter Customer Name: <input type="text" name="cname"><br><br>
Enter Customer Email Address: <input type="email" name="cemail"><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
ViewCustomer.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>View Customer Details</h1>
<h2>Details as submitted as follows</h2>
<form method="getdetails" action="post">
<input type="number" name="cid"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
Retrieve.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Retrieve Customer Details</h1>
<h2>Details as submitted as follows:</h2>
<h5>${customers}</h5>
</body>
</html>
Customers.java
package com.example.demo;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Customers {
#Id
private int cid;
private String cname;
private String cemail;
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getCemail() {
return cemail;
}
public void setCemail(String cemail) {
this.cemail = cemail;
}
#Override
public String toString() {
return "Customers [cid=" + cid + ", cname=" + cname + ", cemail=" + cemail + "]";
}
}
CustomerRepo interface
package com.example.demo;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepo extends CrudRepository<Customers,Integer>{
}
SubmissionFormApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import com.example.demo.SubmissionFormApplication;
#ComponentScan
#SpringBootApplication
public class SubmissionFormApplication extends SpringBootServletInitializer{
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SubmissionFormApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SubmissionFormApplication.class, args);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.13.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>SubmissionForm</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SubmissionForm</name>
<description>First Spring Boot Web app</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jasper -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>9.0.31</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The ViewCustomer.jsp form's Method should have method as post and action as get details. The problem is in html and not spring.
A few things:
Your Controller can be annotated like #RestController instead of just #Controller.
Your mappings for POST is #PostMapping - For consistency, I would recommend your mapping for GET to be #GetMapping - So I'd replace all #RequestMapping with #GetMapping (this removes ambiguity and improves readability as well)
The form in your eureka.jsp, needs to change the URL is posting to. Instead of action=details it should point to action=getdetails
The form in your view viewcustomer.jsp has the action and the post switched (the method should be POST the action should be getdetails)
The #PostMapping("/getdetails") maps to the path "/getdetails". Such a mapping already exists. Try to map to another path in order to resolve this conflict.
As I followed this tutorial: https://spring.io/guides/gs/handling-form-submission/ after a while I came to a dead end. I tried to figure out what the problem is for some hours now. I hope you can help me.
When I submit my form, I get this error-message:
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
My App (App.java):
package de.poc.logging.main;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
My Controller (InformationController.java):
package de.poc.logging.main;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping(value = "/info")
public class InformationController {
#RequestMapping(method = RequestMethod.GET, produces = "text/html")
public String infoForm(Model model) {
model.addAttribute("information", new Information());
return "infoForm.html";
}
#RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String infoSubmit(#ModelAttribute Information information) {
return "infoResult.html";
}
}
I created an additional class for security (WebSecurityConf.java):
package de.poc.logging.main.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.frameOptions().sameOrigin()
.httpStrictTransportSecurity().disable();
http.csrf().disable();
}
}
And I have following two HTML-Files:
infoForm.html:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h1>Form</h1>
<form action="#" th:action="#{/info}" th:object="${information}" method="post">
<p>Id: <input type="text" th:field="*{id}"/></p>
<p>Message: <input type="text" th:field="*{content}"/></p>
<p><input type="submit" value="Submit"/>
<input type="reset" value="Reset"/></p>
<!--<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>-->
</form>
</body>
</html>
infoResult.html:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<h1>Result</h1>
<p th:text="'id: ' + ${information.id}"/>
<p th:text="'content: ' + ${information.content}"/>
Submit another message
</body>
</html>
Edit (additional information):
my Information.java:
package de.poc.logging.main;
public class Information {
private long id;
private String content;
public long getId() {
return id;
}
public String getContent() {
return content;
}
public void setId(long id) {
this.id = id;
}
public void setContent(String content) {
this.content = content;
}
}
my pom-dependencies:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>1.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
</dependencies>
I'm using Java 1.8u121 (jdk).
Edit2:
I tried 3 different versions of spring boot now.
Also I downloaded the project from here: https://github.com/spring-guides/gs-handling-form-submission and added spring boot via pom.xml.
The downloaded project does not work for me.
I'm getting really frustrated.
I copied your exact same classes except the web security class and tried to run. The post method is working for me. The only change I made was returning file names without the .html extension.
My controller class looks like this
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.example.models.Information;
#Controller
#RequestMapping(value = "/info")
public class InformationController {
#RequestMapping(method = RequestMethod.GET, produces = "text/html")
public String infoForm(Model model) {
model.addAttribute("information", new Information());
return "infoForm";
}
#RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String infoSubmit(#ModelAttribute Information information) {
return "infoResult";
}
}
I found the problem. My pom.xml was wrong.
The right one looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-handling-form-submission</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
Did you try with #RequestParam instead of #ModelAttribute?
Something like this..
#RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String infoSubmit(#RequestParam("info") Information information) {
return "infoResult.html";
}