I am using Spring boot and Thymeleaf as a template framework. I set a couple constants on the backend and I need to get data on the frontend via that constants.
I have the backend look like the following:
public class Constant {
public static final String MY_VAR = "test";
}
#Controller
public class MyController {
#GetMapping("/")
public String home(Model model) {
List<String> data = new ArrayList<>();
data.add("item1");
model.addAttribute(Constant.MY_VAR, data);
return "home";
}
}
and on the frontend I want to do like this:
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head>
...
</head>
<body>
<div class="container-fluid p-0">
<div th:unless="${not #lists.isEmpty(Constant.MY_VAR)}">
</div>
</div>
</body>
</html>
how can I get access to model data via constant from the backend?
You can use **ModelAndView ** to solve this problem
backend
#GetMapping("/")
public ModelAndView home() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("home");
List<String> data = new ArrayList<>();
data.add("item1");
modelAndView.addObject("test", data);
return modelAndView;
}
frontend
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head>
...
</head>
<body>
<div class="container-fluid p-0">
<div th:if="${test.size() > 0}">
<li th:each="item:${test}">
<span th:text="${item}"></span>
</li>
</div>
</div>
</body>
</html>
if u want get static attribute in your view。
you can do that
${T(packageName.Constant).MY_VAR}
so u can change your code
${not #lists.isEmpty(Constant.MY_VAR)}
to
${not #lists.isEmpty(#ctx.getVariable(T(packageName.Constant).MY_VAR))}
Related
I've created a project with a Spring Initilizr. I'm trying to parse a string into a "code.html" file and recover it with a #GetMapping. Here's the file:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Code</title>
</head>
<body>
<pre>
<p th:text="${code}">
</pre>
</body>
</html>
And here's the method:
#GetMapping("/code")
public ModelAndView getHTML(HttpServletResponse response) {
response.addHeader("Content-Type", "text/html");
ModelAndView model = new ModelAndView();
model.addObject("code", code.getCode());
model.setViewName("code.html");
return model;
}
(I have a seperate class for the code so code.getCode() just returns a string.)
Unfortunately, http://localhost:8080/code returns an empty screen. What am I doing wrong? Maybe there's an easier way to achieve the task?
i work with springboot and thymeleaft
maybe you need send only the view in the code
like this
#GetMapping("/code")
public ModelAndView getHTML(HttpServletResponse response,Model model) {
model.addAtributte("key", "code");
return new ModelAndView ("templates/code");
}
the model is shipped with the view
in the html try this
<p th:text="${key}">
or you can try the <th:block>
check thymeleaf documentation
i am using the thymeleaf and spring. i want to implement the post request.
my controller class is
public class URLController {
#RequestMapping(value = "index")
public String index1(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#RequestMapping(value = "/")
public String index(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#PostMapping("/result")
public String result(#ModelAttribute Employee employee){
System.out.print(employee.getName());
return "result";
}
}
and the html page is
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index page</title>
</head>
<body>
<form action="#" th:action="#{/result}" modelAttribute="employee" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>name: <input type="text" th:field="*{name}" /></p>
<p>phone: <input type="text" th:field="*{phone}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
there is no binding with the id field.
In your HTML, you need to use the proper syntax for your model attribute. Spring is complaining that it can't find the property id because you are providing the string employee, not the object.
modelAttribute="employee" --> th:object="${employee}"
Additionally, you can consolidate to:
#Controller //please add this
public class URLController {
#GetMapping({"/", "/index"})
public String index1(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#PostMapping("/result")
public String result(#ModelAttribute Employee employee){
System.out.print(employee.getName()); //use a logger instead
return "result"; //may want to return a different page name for clarity
}
}
Your IDE will not complain if you change your HTML tag to:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
Lastly, you may want to use the tel input type for the phone field. Doing so will allow for a custom keyboard to show for mobile users.
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 am trying adapt my app to use angular, but currently it seems that spring cannot see/communicate with angular. Here is what i have :
Controller.java:
#Controller
public class IndexController {
#RequestMapping(value = "/login", method = RequestMethod.GET, produces = {"application/json"})
public #ResponseBody Map<String, Object> getIndexPage() {
Map<String, Object> model = new HashMap<String, Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello Worl123321");
return model;
}
}
index.html:
<!doctype html>
<html>
<head>
<title>Title</title>
<!--<link href="css/angular-bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="css/app.css"/>-->
<style type="text/css">
[ng\:cloak],
[ng-cloak],
.ng-cloak {
display: none !important;
}
</style>
<script src="js/angular-bootstrap.js" type="text/javascript"></script>>
<script src="app/app.js"></script>
<script src="app/listView/listView.js"></script>
</head>
<body ng-app="myApp">
<!-- Application content -->
<div ng-include="'app/app.html'"></div>
</body>
</html>
app.html:
<div class="container">
<div ng-controller="appCtrl" ng-cloak class="ng-cloak">
{{greeting.content}}
</div>
</div>
app.js:
angular.module('myApp', [])
.controller('appCtrl', function($scope, $http) {
$http.get('/login/').success(function(data) {
$scope.greeting = data;
});
});
I just get an output like this :
{"id":"01cdab29-e0ce-45ee-abb9-64b2640859ca","content":"Hello
Worl123321"}
and there seems that no angular scripts has been loaded...
What do you use to serialise as JSON ?
This is maybe because of the Map<> that you have an extra field 'content' between your object and your data try.
$scope.greeting = data.content;
I've already heard of some problem like this with Jackson adding a "content" though it was for a hibernate problem.
If you don't want that extra field : create a wrapper class having an id and content field and use it.
My template do not see objects, passed from Spring.
My code:
public class PublicModelAndView extends ModelAndView {
#Autowired
TemplateModulesHandler templateModulesHandler;
public void init() {
setViewName("index");
CSSProcessor cSSProcessor = new CSSProcessor();
cSSProcessor.setSiteRegion("public");
super.addObject("CSSProcessor", cSSProcessor);
JSProcessor jSProcessor = new JSProcessor();
super.addObject("JSProcessor", jSProcessor);
templateModulesHandler.setPublicModelAndView(this);
}
}
Contoller's code:
#SpringBootApplication
#Controller
public class IndexPage {
#Autowired
PublicModelAndView publicModelAndView;
#Autowired
OurServicesBean ourServicesBean;
#Autowired
PortfolioBean portfolioBean;
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView indexPage() {
publicModelAndView.setTemplate("publicSiteIndexPage");
publicModelAndView.addObject("pageTitle", "TITLE!!!!!!!!!!!!!!");
publicModelAndView.addObject("ourServices", ourServicesBean.getMenu());
publicModelAndView.addObject("portfolioWorkTypes", portfolioBean.getWorkTypes());
publicModelAndView.addObject("portfolioWorks", portfolioBean.getWorks());
return publicModelAndView;
}
}
Main template's code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
>
<head th:include="headerAndFooter/fragments/header :: publicSiteHeader">
<title></title>
</head>
<body>
hello!
</body>
</html>
Fragment's code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head th:fragment="publicSiteHeader">
<title>${pageTitle}</title>
<!--[if lte IE 8]>
<script src="<?= SITE_TEMPLATE_PATH ?>/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
</body>
</html>
As result I do not see value of the object pageTitle, but I see in page output code like
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>${pageTitle}</title>
Why thymeleaf didn't paste value of the pageTitle to between title tag's open and close?
The same code works good with JSP, but do not work with thymeleaf.
Thymeleaf is not JSP, so that's why your template does not work as you expect.
Look here http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#using-texts and use something like:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<title th:text="#{pageTitle}">page title</title>
Edited - my solution is for localised texts which is good practice anyway. if you want to use content of variable than use $.