I am developing a webapp. In that app i have a page which have three search options based on id. If the ID is wrong i want to retain the id in search textbox and i want to show an error message. I tried that with
ModelAndView.addObject("id", value);
And this is working fine , Now i want to know if there is a better way to do this because assume i have a big form and i want to retain the value of every field than it will be difficult using the above approch. Please help!
And i am using search by ID and Name both thats why i have try and catch blocks
this is my jsp file
html>
<head>
<link rel="stylesheet" type="text/css" href="./css/style.css" />
<link rel="stylesheet" type="text/css" href="./bootstrap/css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="./bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="./bootstrap/css/bootstrap-responsive.css" />
<link rel="stylesheet" type="text/css" href="./bootstrap/css/bootstrap-responsive.min.css" />
<script>
function redirectToSearchResult(textBoxId){
window.location.href= document.getElementById(textBoxId).name+'.htm?'+'id='+document.getElementById(textBoxId).value;
}
</script>
</head>
<body>
<div class="page-header"></div>
<div id="searchByBuyer">
<label id="E_B_I"><h2>Buyer Search<h2></label><br>
<input type="text" id="S_B_B" class="text-box" name="searchByBuyer" value=${buyerId} ></input>
<input type="button" id="BuyerSearch" class="btn-custom" value="search" onclick="redirectToSearchResult('S_B_B')"/>
</div>
<div id="searchByCategory">
<label id="E_C_I"><h2>Category Search<h2></label><br>
<input type="text" id="S_B_C" class="text-box" name="searchByCategory" value=${categoryId} ></input>
<input type="button" id="CategorySearch" class="btn-custom" value="search" onclick="redirectToSearchResult('S_B_C')"/>
</div>
<div id="searchByArticle">
<label id="E_A_I"><h2>Article Search<h2></label><br>
<input type="text" id="S_B_I" class="text-box" name="searchByArticle" value=${articleId} ></input>
<input type="button" id="ArticleSearch" class="btn-custom" value="search" onclick="redirectToSearchResult('S_B_I')"/><br>
</div>
<br>
<label style="color:red; padding-left:45em; padding-top:15em"><h4>${error}</h4></label>
</body>
</html>
And this my controller
`
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class BuyerController {
#Autowired
private BuyerRepo buyerRepo;
#RequestMapping(value = "/searchByBuyer.htm", method = RequestMethod.GET)
public ModelAndView searchFields(#RequestParam(value = "id") String buyerId) throws InvalidIdException {
Buyer buyer = null;
ModelAndView buyerSearch = new ModelAndView("buyerSearch");
ModelAndView errorView = ErrorView.getErrorView("buyerId", buyerId, "Enter a valid Buyer id!");
try {
buyer = buyerRepo.getBuyer(Long.parseLong(buyerId));
} catch (NumberFormatException e) {
buyer = buyerRepo.getBuyer(buyerId);
if (buyer == null) return errorView;
} catch (Exception e) {
buyerSearch = errorView;
}
buyerSearch.addObject("buyer", buyer);
return buyerSearch;
}
}
`
This is the error and view class to create error view with parameters
`
import org.springframework.web.servlet.ModelAndView;
public class ErrorView {
public static ModelAndView getErrorView(String key, String value, String message) {
ModelAndView errorView = new ModelAndView("index");
errorView.addObject("error", message);
errorView.addObject(key, value);
return errorView;
}
}
`
Spring has JSR 303-Bean-Validation support for web forms.
This build in way is much easyer to use than some own implementation.
You need:
a command object that gets all the values from the form. Each fields can have JSR 303-Bean-Validation annotations to indicate the constaints you want to enforce
you need a web controller method with (at least) two parameters: #Valid command object, BindingResult (The BindingResult must be THE parameter after the command object)
in you web controller method you need to check the BindingResult, and if it has failure you need to render the form again
in your form you need to use form:errors to show the errors (form:errors can also show the errors for an specific field)
you need some spring configuration: <mvc:annotation-driven /> (there is more possible but this should be enough for the begin)
you need a JSR 303-Bean-Validation libary, for example: Hibernate Validator (this is not the Hibernate ORM)
But an example explain it the best: http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/
Related
I have just began to work with Html + springboot. I have prepared two files
the HTML file with a form as bellow
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Add Info</title>
<link rel="stylesheet" type="text/css" th:href="#{/css/style.css}"/>
</head>
<body>
<h1>Insert an Info:</h1>
<!--
In Thymeleaf the equivalent of
JSP's ${pageContext.request.contextPath}/edit.html
would be #{/edit.html}
-->
<form th:action="#{}" method="post">
<input type="text" th:name="Coord1"/> </br>
<input type="text" th:name="Coord2"/> </br>
<input type="text" th:name="Coord3"/> </br>
<input type="text" th:name="Coord4"/> </br>
<input type="submit"/>
</form>
<br/>
<!-- Check if errorMessage is not null and not empty -->
<div th:if="${errorMessage}" th:utext="${errorMessage}"
style="color:red;font-style:italic;">
...
</div>
</body>
</html>
I want to get the four values coord1 coord2, coord3 and coord4. My java controller file contains the lines
package com.example.project.controller;
import java.io.IOException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
#Controller
public class MainController {
#RequestMapping(value="",method=RequestMethod.GET)
public void addAObjectForm(#RequestParam("Coord1") String Coord1,#RequestParam("Coord2") String Coord2,#RequestParam("Coord3") String Coord3, #RequestParam("Coord4")String Coord4) throws IOException {
System.out.println(Coord1);
}
}I
When I run this code I get the error
[2m2021-07-12 22:28:57.206[0;39m [33m WARN[0;39m [35m18812[0;39m [2m---[0;39m [2m[nio-8080-exec-3][0;39m [36m.w.s.m.s.DefaultHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'Coord1' for method parameter type String is not present]
Could anyone help me please
you use POST action in your form, and u use GET method in your controller. match those things and update status please :)
Firstly add thymeleaf dependency in your pom.xml.
Give some action inside the:action like
<form th:action="#{detail}" method="post">
Use make controller like
#Controller
public class MainController {
#GetMapping("/")
public String show() {
return "show"; // I had given name to view part as show.html
}
#RequestMapping(value = "/detail", method = RequestMethod.POST)
public void addAObjectForm(#RequestParam(value = "Coord1", required = false) String Coord1,
#RequestParam(value = "Coord2", required = false) String Coord2,
#RequestParam(value = "Coord3", required = false) String Coord3,
#RequestParam(value = "Coord4", required = false) String Coord4) throws IOException {
System.out.println(Coord1);
}
}
I'm trying to handle a form submission with thymeleaf in my spring-boot application, i integrated
this example which worked fine on my app. I'm trying to change it a little bit, but this is what i'm getting as an exception:
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'recruiter' cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213) ~[spring-expression-5.2.3.RELEASE.jar:5.2.3.RELEASE]
...
This is the object i'm trying to handle with thymeleaf
public class FormRec {
private String recruiter;
public String getRecruiter() {
return recruiter;
}
public void setRecruiter(String recruiter) {
this.recruiter = recruiter;
}
}
This is my 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 com.service.minimicroservice.objects.FormRec;
#Controller
public class MyController {
#GetMapping("/form")
public String greetingForm(Model model) {
model.addAttribute("recForm", new FormRec());
return "form";
}
#PostMapping("/form")
public String greetingSubmit(#ModelAttribute FormRec rec) {
return "result";
}
}
result.html
<!DOCTYPE HTML>
<html xmlns:th="https://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="'Recruiter: ' + ${rec.recruiter}" />
Submit another message
</body>
</html>
part of the form.html
<body>
<form action="#" th:action="#{/form}" th:object="${recForm}" method="post">
<div class="form-row m-b-55">
<div class="name">Recruiter<br> Name</div>
<div class="value">
<div class="row row-space">
<div class="col-2">
<div class="input-group-desc">
<input class="input--style-5" type="text" name="first_name" th:field="*{recruiter}">
<label class="label--desc">Full Name</label>
</div>
</div>
...
In order to refer to a FormRec Object i use recForm as th:object in the form.html and rec to refer to it in the result.html.
Note: I pass a value to the th:field="*{recruiter}" input text when i submit the form (is not null)
You have to name the ModelAttribute rec that the data gets bound to. So in your controller method do this (notice the name = "rec"):
public String greetingSubmit(#ModelAttribute(name = "rec") FormRec rec) {
...
}
It should work.
Additional explanation:
I've had a closer look at why that happens and it's because Spring's ModelAttribute annotation by default infers from the name of the type and not the name of the parameter (the example link you provided says it's method parameter name, but it seems to be wrong).
So in this case Spring sends formRec (notice the camelCase, which it expects when the class name is called FormRec) to the result.html and not rec as you would expect.
If my explanation doesn't really make sense, then this is the Spring documentation on ModelAttribute:
The default model attribute name is inferred from the declared attribute type (i.e. the method parameter type or method return type), based on the non-qualified class name: e.g. "orderAddress" for class "mypackage.OrderAddress", or "orderAddressList" for "List".
I am really new to Spring Boot, and I am currently going through the book. Spring Boot in action.
I created and complied my first web simple web app fine, expect the css file shows up blank in the console. I have already looked up the following post:
Spring Boot - CSS not loading
Spring Boot CSS Stripped
I am using Thymleaves and my css file is placed within the static folder as the post and book states, but nothing shows up. my current external link, seems to be the correct way too.
<link rel="stylesheet" th:href="#{/main.css}" />
Although, the css appear to show in the resources in console, the css file remains blank. Below are my files and code.
File Structure:
Template:
body {
background-color: #cccccc;
font-family: arial,helvetica,sans-serif;
}
.bookHeadline {
font-size: 12pt;
font-weight: bold;
}
.bookDescription {
font-size: 10pt;
}
label {
font-weight: bold;
}
<html xmlns:th="http://www.springframework.org/schema/data/jaxb">
<head>
<title>Reading List</title>
<link rel="stylesheet" th:href="#{/main.css}" />
</head>
<body>
<h2>Your Reading List</h2>
<div th:unless="${#lists.isEmpty(books)}">
<dl th:each="book : ${books}">
<dt class="bookHeadline">
<span th:text="${book.title}">Title</span> by
<span th:text="${book.author}">Author</span>
(ISBN: <span th:text="${book.isbn}">ISBN</span>)
</dt>
<dd class="bookDescription">
<span th:if="${book.description}"
th:text="${book.description}">Description</span>
<span th:if="${book.description eq null}">
No description available</span>
</dd>
</dl>
</div>
<div th:if="${#lists.isEmpty(books)}">
<p>You have no books in your book list</p>
</div>
<hr/>
<h3>Add a book</h3>
<form method="POST">
<label for="title">Title:</label>
<input type="text" name="title" size="50"></input><br/>
<label for="author">Author:</label>
<input type="text" name="author" size="50"></input><br/>
<label for="isbn">ISBN:</label>
<input type="text" name="isbn" size="15"></input><br/>
<label for="description">Description:</label><br/>
<textarea name="description" cols="80" rows="5">
</textarea><br/>
<input type="submit"></input>
</form>
</body>
</html>
Controller:
package codenotes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
#Controller
#RequestMapping("/")
public class BookController {
private BookRepository bookRepository;
#Autowired
public BookController(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
#RequestMapping(value = "/{reader}", method = RequestMethod.GET)
public String readerBooks(
#PathVariable("reader") String reader,
Model model) {
List<Book> readingList =
bookRepository.findByReader(reader);
if (readingList != null) {
model.addAttribute("books", readingList);
}
return "readingList";
}
#RequestMapping(value = "/{reader}", method = RequestMethod.POST)
public String addToReadingList(
#PathVariable("reader") String reader, Book book) {
book.setReader(reader);
bookRepository.save(book);
return "redirect:/{reader}";
}
}
Repository:
package codenotes;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByReader(String reader);
}
I believe you should read this, how to serve static content:
http://docs.spring.io/spring-boot/docs/1.4.2.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-static-content
To sum it up, your browser is caching your static resources, such as CSS files.
In order to break this behavior, try first clean your browser cache, in google chrome you go to settings then clear browsing data.
Secondly, add these lines to your application.properties file in order to bust the cache:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
or add this instead:
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/**
spring.resources.chain.strategy.fixed.version=v12
Please make the following changes
1. Move main.css into /static/css folder
2. Change
Let me know if does not work.
If you are using Spring Auth and you're not logged in, you'll also have to make sure that the user has access to see the styling.
In the WebSecurityConfig you just have to add "*/.css" to your list of allowed routes.
#Override
protected void configure(final HttpSecurity http) throws Exception {
...
.authorizeRequests()
//allow requests to all urls that match the pattern
.antMatchers("/", "/signup", "/login", "/*.css", "/*.jpg").permitAll()
//anything else you must be logged in
...
}
I am using SpringBoot with Thymeleaf to build a trivial example to help me learn the two technologies.
I am basing my example on THIS GUIDE
The entity is a Greeting which has an Id and a Content.
I create the Greeting just fine, and I can list all the Greetings I've created.
I then wanted to add a delete option against each Greeting in the list page. When clicking delete, I want the object to be deleted and the list page served up again.
Alas, when I load the list page I get this error:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'greeting' available as request attribute
Controller and respository objects
#Controller
public class GreetingController {
#Autowired
GreetingRepo gr;
#RequestMapping(value="/greeting/list", method=RequestMethod.GET)
public String greetingsForm(Model model) {
model.addAttribute("greetings", gr.findAll());
return "greeting/list";
}
#RequestMapping(value="/greeting/delete", method=RequestMethod.POST)
public String deleteGreeting(#ModelAttribute("greeting") Greeting greeting) {
gr.delete(greeting);
return "redirect:/greeting/list";
}
}
#RepositoryRestResource
interface GreetingRepo extends JpaRepository<Greeting, Long> {
}
List.html page:
<!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>
<div th:each="greeting : ${greetings}">
<p th:text="'id: ' + ${greeting.id}" />
<p th:text="'content: ' + ${greeting.content}" />
<form action="#" th:action="#{/greeting/delete}" th:object="${greeting}" method="post">
<input type="hidden" th:field="*{id}"/>
<input type="hidden" th:field="*{content}"/>
<input type="Submit" value="Delete"/>
</form>
</div>
Add another
Show All
</body>
</html>
Would appreciate a push in the right direction here :-)
I think you miss this line .
model.addAttribute("greeting", new Greeting());
#RequestMapping(value="/greeting/list", method=RequestMethod.GET)
public String greetingsForm(Model model) {
model.addAttribute("greeting", new Greeting());
model.addAttribute("greetings", gr.findAll());
return "greeting/list";
}
you dont have to use a form to delete the greeting you can do it very easily with this approach. hide the id of the greeting within the url. so you dont need to use a form and hidden tags. and annotate the controller method with following approach, to accept incoming id of the greeting.
replace the current form with given html code and replace the delete method in the controller as well.
<a th:href="#{/greeting/{id}/delete(id=${greeting.id})}" th:text="delete"></a>
#RequestMapping(value="/greeting/{id}/delete",method=RequestMethod.GET)
public String deleteGreeting(#PathVariable int id) {
gr.delete(id);
return "redirect:/greeting/list";
}
edit:- since you need the object to be present within the controller
you can use findOne method to fetch the object from the given id.check out the following example.
<a th:href="#{/greeting/{id}/edit(id=${greeting.id})}" th:text="edit"></a>
#RequestMapping(value="/greeting/{id}/edit",method=RequestMethod.GET)
public String Edit(#PathVariable int id){
greeting greetingob = gr.findOne(id);
return "edit";
}
I have server and I should make request on button pressed also I have to call this method and when it is works I should parse json but my doesn't see controller method only main method is available
How to call
<input type="submit" onclick="#routes.Login.resp()" value="LOGIN" >
because it is not worrking Cannot resolve symbol
GET /login controllers.Login.main()
My controller:
package controllers;
import play.libs.F;
import play.libs.WS;
import play.mvc.Controller;
import play.mvc.Result;
public class Login extends Controller {
public static Result main() {
return ok(views.html.login.render());
}
public static F.Promise<Result> resp() {
String feedUrl="http://validate.jsontest.com/?json=%7B%22key%22:%22value%22%7D";
final F.Promise<Result> resultPromise = WS.url(feedUrl).get().flatMap(
new F.Function<WS.Response, F.Promise<Result>>() {
public F.Promise<Result> apply(WS.Response response) {
return WS.url(response.asJson().findPath("empty").asText()).get().map(
new F.Function<WS.Response, Result>() {
public Result apply(WS.Response response) {
return ok("size" + response.asJson().findPath("count").asInt());
}
}
);
}
}
);
return resultPromise;
}
}
view:
<!--
Author: W3layouts
Author URL: http://w3layouts.com
License: Creative Commons Attribution 3.0 Unported
License URL: http://creativecommons.org/licenses/by/3.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>LOGIN</title>
<meta charset="utf-8">
<link rel="stylesheet" media="screen" href="#routes.Assets.at("stylesheets/stylelogin.css")">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="application/x-javascript"> addEventListener("load", function() { setTimeout(hideURLbar, 0); }, false); function hideURLbar(){ window.scrollTo(0,1); } </script>
<!--webfonts-->
<link href='http://fonts.googleapis.com/css?family=Open+Sans:600italic,400,300,600,700' rel='stylesheet' type='text/css'>
<!--//webfonts-->
</head>
<body>
<!-----start-main---->
<div class="main">
<div class="login-form">
<h1>Member Login</h1>
<div class="head">
<img src="#routes.Assets.at("images/user.png")" alt=""/>
</div>
<form>
<input type="text" class="text" value="USERNAME" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'USERNAME';}" >
<input type="password" value="Password" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'Password';}">
<div class="submit">
<input type="submit" onclick="#routes.Login.main()" value="LOGIN" >
</div>
</form>
</div>
<!--//End-login-form-->
<!-----start-copyright---->
<!-----//end-copyright---->
</div>
<!-----//end-main---->
</body>
</html>
I am not sure if I also parse json properly,how to make proper GET,POST requests and parse it
As far as I know with the onclick attribute you always call a function in your JavaScript. If you want to specify an URL you need to put it into your form tag with an action attribute like <form action="#routes.Login.main()">.
The default for the HTML form tag is to send a GET. If you want to send a POST you have to specify it via an additional method="post" like <form action="#routes.Login.main()" method="post">. But then you have to change your routing too: POST /login controllers.Login.main(). If you want to post login data I'd strongly recommend to use POST because with GET your data including the password turns up in the query string of your URL.
Additionally your #routes.Login.main() method just returns the login view return ok(views.html.login.render());. Instead it should evaluate the form data you are sending.