I have to develop a project for college using Spring. I started watching some tutorials and I can't show an html page. I do the same but it returns only one string.
I'm using visual studio code.
Controller:
package com.example.springteste.controllers;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ProductController {
#GetMapping("/formulario")
public String formulario()
{
return "form";
}
}
My view is just inside templates
View:
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<main>
<section id="sectionProduct">
<div>
<div id="sectionProduct-title">
<h1>
Título
</h1>
</div>
<div id="sectionProduct-form">
<form action="">
<div class="sectionProduct-form-inputLabel">
<input type="text" id="title" name="title">
<label for="title">
Título
</label>
</div>
</form>
</div>
</div>
</section>
</main>
</body>
</html>
I believe something is missing. I am a beginner in java and spring
If you want to return a view name from the controller method handler - you have to use #Controller annotation. Also make sure you put your views into the correct directory, according to your view resolver configuration.
About #RestController - as the name suggests, it shall be used in case of REST style controllers i.e. handler methods shall return the JSON/XML response directly to the client rather using view resolvers.
In your case the handler method will return "form" to the client.
Related
Hi I'm building a skeleton of a car renting webapp and I'm trying to create a view that shows some details like location name, car name etc.
View code- car-list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Vehicle List</title>
<h2 th:text="${location1}">Locations</h2>
<table class="table table-stripped">
<thead>
<td th:text="${vehicle1Name}">Vehicle Name</td>
</tr>
</thead>
<td th:text="${vehicle2Name}">Vehicle Name</td>
</tr>
</table>
</head>
<body>
</body>
</html>
And heres my controller
package com.project.CS4125.controller;
import com.project.CS4125.model.*;
import com.project.CS4125.service.UserService;
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.RequestMapping;
import java.util.ArrayList;
import java.util.List;
#Controller
#RequestMapping("/car-list")
public class VehicleController {
#GetMapping("/car-list")
public String carList(Model model){
Vehicle VWGolf = new BasicCar();
Vehicle Duster = new SUVDecorator(new BasicCar());
Location limerick= new Location("Limerick");
model.addAttribute("location1", limerick.getLocationName());
model.addAttribute("vehicle1Name", "Volkswagen Golf");
model.addAttribute("vehicle2Name", "Dacia Duster");
return "index";
}
}
My problem is the view comes up completely empty, any help appreciated.
EDIT
Before this page I have a register and login page
index.html (register page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Register</title>
</head>
<body>
<form action="#" th:action="#{/register}" th:object="${user}"
method="post">
<p>User Name <input type="text" name="name"></p>
<p>Password <input type="password" name="password"></p>
<button type="submit">Register</button>
</form>
<button>Login Here</button>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form action="#" th:action="#{/login}" th:object="${user}"
method="post">
<p>User Name <input type="text" name="name"></p>
<p>Password <input type="password" name="password"></p>
<button type="submit">Login</button>
</form>
<button>Register Here</button>
</body>
</html>
And heres the controller for these
#Controller
#RequestMapping("/")
public class IndexController {
#Autowired
private UserService userService;
#Autowired
private CustomerFactory userFactory;
#PostMapping("/register")
public String registerUser(#ModelAttribute User user){
User u = userFactory.createUser(user.getName(), user.getPassword());
userService.saveUser(u);
return "login";
}
#GetMapping("/login")
public String login(){
return "login";
}
#PostMapping("/login")
public String loginUser(#ModelAttribute User user){
User authenticatedUser = userService.authenticate(user.getName(), user.getPassword());
System.out.println(authenticatedUser.toString());
return "car-list";
}
}
Even after adding the code from the answer below I'm still getting an empty page, after submitting the login form moving to the car list page its still empty.
I also noticed in the answer the URL is http://localhost:8080/car-list but when I try it its http://localhost:8080/login
I've just tested your code and you have two problems.
The first one is at your:
#Controller
#RequestMapping("/car-list")
public class VehicleController {
#GetMapping("/car-list")
In this GetMapping you're saying that you want to access your template at /car-list/car-list.
The seccond one is with your template name. You're returning "index" when you should return "car-list", at this you're returning the template name.
So, editting your code like this:
#Controller
#RequestMapping("/car-list")
public class VehicleController {
#GetMapping
public String carList(Model model){
model.addAttribute("location1", "Answer");
model.addAttribute("vehicle1Name", "Volkswagen Golf");
model.addAttribute("vehicle2Name", "Dacia Duster");
return "car-list";
}
}
I got:
Template working and returning
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Java, Spring Boot, FreeMarker</title>
<link href="/css/main.css" rel="stylesheet">
</head>
<script>
function myFunction() {
<#test/>
}
</script>
<body>
<h2>Java, Spring Boot, FreeMarker</h2>
<form action="/search" method="post">
Search : <input type="text" name="firstName" onkeyup="myFunction()" id = "fname">
<input type="submit" value="Submit">
</form>
<div style="background-color:lightblue">
<#macro test>
<#list empList as emp>
<div id="emp-data">
<ul>
<li>${emp}</li>
</ul>
</#list>
</div>
</#macro>
<script src="/js/main.js"></script>
</div>
</body>
When I run this code I am getting some errors on the browser console:
(index):60 Uncaught ReferenceError: myFunction is not defined at HTMLInputElement.onkeyup ((index):60) onkeyup # (index):60 – PCS 1 hour ago
Is it possible in FreeMarker to do something like that?
In a sense you can... but it doesn't do what you apparently believe it does. First all FreeMarker instructions, like <#test/>, are resolved on the server, then later the resulting output runs in the browser. So as far as the browser sees, function myFunction() { ... } contains HTML div-s directly in inside the { ... }, which is invalid JavaScript.
Im trying to render a webapge and use the thymleaf attribute "url" added with model.addAttribute but the Attribute is not beeing displayed on the html document.
My document.html file path is here:
/templates/webpage/document.html
#RequestMapping(value = "/webpage/document")
public String document(HttpServletRequest req, Model model) {
model.addAttribute("dialogurl", url);
return "/webpage/document";
}
Here is the html document
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:include="wrapperdialog :: page">
<head>
<title></title>
</head>
<body>
<div th:fragment="content">
<div class="container dialogpage">
<div class="row">
<div class="col-md-12">
<div id="typeform" th:attr="data-url=*{dialogurl}">
</div>
</div>
</div>
</div>
</div>
Please use this expression to bind dialog url: #{${dialogurl}}
<div id="typeform" th:attr="data-url=#{${dialogurl}}">
# prefix is used to specify a link and $ prefix is used to bind your model value.
Use $ to bind data.
<div id="typeform" th:attr="data-url=${dialogurl}">
Is it possible to create a dynamic replace in Thymeleaf?
I have the following controller:
#Controller
public class LoginController {
#RequestMapping("/login")
public String getLogin(Model model){
model.addAttribute("template","login");
return "index";
}
}
And the following view:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head></head>
<body>
<div th:replace="fragments/${template} :: ${template}"></div>
</body>
</html>
And i'm getting the following error:
Error resolving template "fragments/${template}", template might not exist or might not be accessible by any of the configured Template Resolvers
UPDATE
I tried to preprocess my variables like this:
<div th:replace="fragments/${__#{${template}}__} :: ${__#{${template}}__}"></div>
How ever now ${template} is getting replaced with login i have the following error now:
Exception evaluating SpringEL expression: "??login_en_US??"
Although Joe Essey's solution is working as well i solved with following code:
<div th:replace="#{'fragments/' + ${template}} :: ${template}"></div>
I believe the appropriate method to manage this behavior in thymeleaf is to use layout:fragment tags. Please correct me if I'm wrong. Here is a simple example of my layout page, and the login page which is 'dynamically' loaded:
layout.html
<html xmlns:layout="http://www.w3.org/1999/xhtml" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Layout</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
</head>
<body>
<div>
<div class="app-container">
<div th:fragment="content">
</div>
</div>
</div>
<div th:fragment="script"></div>
</body>
</html>
Then, when login gets loaded, it replaces the th:fragment div with the associated div in the html view which matches the string returned by the controller method, in this case login.html:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.w3.org/1999/xhtml"
layout:decorator="layout">
<head>
<title>Login</title>
</head>
<body>
<div th:fragment="content">
<form th:action="#{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</div>
</body>
</html>
Now, if you want to load another fragment conditionally, the approach I take is to add replace tags with th:if cases. Here's an example of a Form that displays different questions based on an attribute of the current user:
<div th:if="${foo.type)} == 'type_1'">
<div th:replace="fragments/custom-questions :: type-1-checkboxes"></div>
</div>
<div th:if="${foo.type} == 'type_2'">
<div th:replace="fragments/custom-questions :: type-2-checkboxes"></div>
</div>
Then the associated div gets loaded from the file custom-questions.html:
<div th:fragment="type-1-checkboxes">
//stuff
</div>
<div th:fragment="type-2-checkboxes">
//stuff
</div>
I am just encountering this issue (this is my first time with thymeleaf/spring). This is what solved it for me:
<div class="col-md-12" th:include="__${template}__ :: body" ...
In Thymeleaf 3.0, the following solution has worked for me:
<div th:replace="('fragments/' + ${template}) :: (${template})">
(Note however, that I use it with fixed name of the fragment and dynamic name of the template, so the parantheses around :: (${template}) might be optional.)
The solution is inspired by documentation for Thymeleaf in https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#fragment-specification-syntax
Both templatename and selector in the above examples can be fully-featured expressions (even conditionals!) like:
<div th:insert="footer :: (${user.isAdmin}? #{footer.admin} : #{footer.normaluser})"></div>
Note again how the surrounding ~{...} envelope is optional in th:insert/th:replace
<div th:insert=“${subpage}::fragementName”>
Just change subpage names and you will dynamic behaviour in thymleaf
I have a web page on which I use jQuery's AJAX to load new elements into a div. This part of my page works fine.
I now want to add a similar event to these newly-added elements. To do this I planned to use jQuery's .live() method but nothing appears to happen.
So I initially start with this
<div id="change-agent-list" class="tooltip">
<div class="top"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
Into .middle I asynchronously load markup that looks like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title></title>
</head>
<body>
<form name="main" method="post" action="/ils/agent-selector/" id="main">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTQ1MTc3ODM4NGRkg9mLyLiGNVcP/ppO9C/IbwpxdwI=" />
</div>
<ul id="content_0_agentsUL">
<li>
Agent 1
</li>
<li>
Agent 2
</li>
<li>
Agent 3
</li>
</ul>
<div id="agent-details"></div>
</form>
</body>
</html>
When the page initially loads I use this script - my intention is to add a click handler for each of the .agent-name elements that are asynchronously added later.
$j(document).ready(function () {
$j(".agent-name").live("click", function() {
var agentDetails = $j(".agent-details");
var loadingContent = '<div id="ajax-load"><img src="/sitecore/__/_images/global/ajax-load.gif" alt="AJAX content loading" /></div>';
agentDetails.show();
agentDetails.empty().html(loadingContent);
var modalURL = $j(".agent-name").attr("href");
agentDetails.load(modalURL);*/
return false;
});
});
The problem is that no events are being bound to the .agent-name elements. I've tried replacing all the inner script with a simple alert() so that I can see if any events are being bound to the .agent-name elements, and I can't get this alert() to display.
So in other words, no events are being bound to my .agent-name elements.
Even if I move the agent-name class to the list elements and change the jQuery to simply
$j(".agent-name").live("click", function() {
alert('1');
});
I still get nothing when I click on the elements.
Can anyone explain why, or how I fix this so that I can late-bind events to elements created in an AJAX callback?
I eventually solved this by using jQuery's on instead of "live".
You can only have one #agent-name because IDs are unique. You can just use $('#agents .link') since you already have a class on each anchor.
Not sure if this is helpful, but this works for me:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title></title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$(".agent-name").live("click", function() {
alert("click");
return false;
});
});
</script>
</head>
<body>
<form name="main" method="post" action="/ils/agent-selector/" id="main">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTQ1MTc3ODM4NGRkg9mLyLiGNVcP/ppO9C/IbwpxdwI=" />
</div>
<ul id="content_0_agentsUL">
<li>
Agent 1
</li>
<li>
Agent 2
</li>
<li>
Agent 3
</li>
</ul>
<div id="agent-details"></div>
</form>
</body>
</html>