Thymeleaf inlining and natural processing (#711)
* Expression-Based Access Control PermitAll, hasRole, hasAnyRole etc. I modified classes regards to Security * Added test cases for Spring Security Expressions * Handler Interceptor - logging example * Test for logger interceptor * Removed conflicted part * UserInterceptor (adding user information to model) * Spring Handler Interceptor - session timers * Spring Security CSRF attack protection with Thymeleaf * Fix and(); * Logger update * Changed config for Thymeleaf * Thymeleaf Natural Processing and Inlining
This commit is contained in:
parent
c5fd46e5f2
commit
72b2eacb4f
|
@ -20,6 +20,8 @@ import org.thymeleaf.templatemode.TemplateMode;
|
|||
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||
|
||||
import com.baeldung.thymeleaf.formatter.NameFormatter;
|
||||
import com.baeldung.thymeleaf.utils.ArrayUtil;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
|
@ -37,30 +39,67 @@ public class WebMVCConfig extends WebMvcConfigurerAdapter implements Application
|
|||
}
|
||||
|
||||
@Bean
|
||||
public ViewResolver viewResolver() {
|
||||
public ViewResolver htmlViewResolver() {
|
||||
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
|
||||
resolver.setTemplateEngine(templateEngine());
|
||||
resolver.setTemplateEngine(templateEngine(htmlTemplateResolver()));
|
||||
resolver.setContentType("text/html");
|
||||
resolver.setCharacterEncoding("UTF-8");
|
||||
resolver.setOrder(1);
|
||||
resolver.setViewNames(ArrayUtil.array("*.html"));
|
||||
return resolver;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public TemplateEngine templateEngine() {
|
||||
SpringTemplateEngine engine = new SpringTemplateEngine();
|
||||
engine.setEnableSpringELCompiler(true);
|
||||
engine.setTemplateResolver(templateResolver());
|
||||
return engine;
|
||||
}
|
||||
public ViewResolver javascriptViewResolver() {
|
||||
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
|
||||
resolver.setTemplateEngine(templateEngine(javascriptTemplateResolver()));
|
||||
resolver.setContentType("application/javascript");
|
||||
resolver.setCharacterEncoding("UTF-8");
|
||||
resolver.setViewNames(ArrayUtil.array("*.js"));
|
||||
return resolver;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ViewResolver plainViewResolver() {
|
||||
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
|
||||
resolver.setTemplateEngine(templateEngine(plainTemplateResolver()));
|
||||
resolver.setContentType("text/plain");
|
||||
resolver.setCharacterEncoding("UTF-8");
|
||||
resolver.setViewNames(ArrayUtil.array("*.txt"));
|
||||
return resolver;
|
||||
}
|
||||
|
||||
private ITemplateResolver templateResolver() {
|
||||
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
resolver.setApplicationContext(applicationContext);
|
||||
resolver.setPrefix("/WEB-INF/views/");
|
||||
resolver.setSuffix(".html");
|
||||
resolver.setTemplateMode(TemplateMode.HTML);
|
||||
return resolver;
|
||||
}
|
||||
private TemplateEngine templateEngine(ITemplateResolver templateResolver) {
|
||||
SpringTemplateEngine engine = new SpringTemplateEngine();
|
||||
engine.setTemplateResolver(templateResolver);
|
||||
return engine;
|
||||
}
|
||||
|
||||
private ITemplateResolver htmlTemplateResolver() {
|
||||
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
resolver.setApplicationContext(applicationContext);
|
||||
resolver.setPrefix("/WEB-INF/views/");
|
||||
resolver.setCacheable(false);
|
||||
resolver.setTemplateMode(TemplateMode.HTML);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
private ITemplateResolver javascriptTemplateResolver() {
|
||||
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
resolver.setApplicationContext(applicationContext);
|
||||
resolver.setPrefix("/WEB-INF/js/");
|
||||
resolver.setCacheable(false);
|
||||
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
private ITemplateResolver plainTemplateResolver() {
|
||||
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
resolver.setApplicationContext(applicationContext);
|
||||
resolver.setPrefix("/WEB-INF/txt/");
|
||||
resolver.setCacheable(false);
|
||||
resolver.setTemplateMode(TemplateMode.TEXT);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Description("Spring Message Resolver")
|
||||
|
|
|
@ -21,7 +21,7 @@ public class HomeController {
|
|||
|
||||
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.getDefault());
|
||||
model.addAttribute("serverTime", dateFormat.format(new Date()));
|
||||
return "home";
|
||||
return "home.html";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.thymeleaf.controller;
|
||||
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
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.baeldung.thymeleaf.utils.StudentUtils;
|
||||
|
||||
@Controller
|
||||
public class InliningController {
|
||||
|
||||
@RequestMapping(value = "/html", method = RequestMethod.GET)
|
||||
public String getExampleHTML(Model model) {
|
||||
model.addAttribute("title", "Baeldung");
|
||||
model.addAttribute("description", "<strong>Thymeleaf</strong> tutorial");
|
||||
return "inliningExample.html";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/js", method = RequestMethod.GET)
|
||||
public String getExampleJS(Model model) {
|
||||
model.addAttribute("students", StudentUtils.buildStudents());
|
||||
return "studentCheck.js";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/plain", method = RequestMethod.GET)
|
||||
public String getExamplePlain(Model model) {
|
||||
model.addAttribute("username", SecurityContextHolder.getContext().getAuthentication().getName());
|
||||
model.addAttribute("students", StudentUtils.buildStudents());
|
||||
return "studentsList.txt";
|
||||
}
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
package com.baeldung.thymeleaf.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import com.baeldung.thymeleaf.model.Student;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
@ -13,6 +11,9 @@ import org.springframework.web.bind.annotation.ModelAttribute;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import com.baeldung.thymeleaf.model.Student;
|
||||
import com.baeldung.thymeleaf.utils.StudentUtils;
|
||||
|
||||
/**
|
||||
* Handles requests for the student model.
|
||||
*
|
||||
|
@ -20,50 +21,30 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||
@Controller
|
||||
public class StudentController {
|
||||
|
||||
@RequestMapping(value = "/saveStudent", method = RequestMethod.POST)
|
||||
public String saveStudent(@Valid @ModelAttribute Student student, BindingResult errors, Model model) {
|
||||
if (!errors.hasErrors()) {
|
||||
// get mock objects
|
||||
List<Student> students = buildStudents();
|
||||
// add current student
|
||||
students.add(student);
|
||||
model.addAttribute("students", students);
|
||||
}
|
||||
return ((errors.hasErrors()) ? "addStudent" : "listStudents");
|
||||
}
|
||||
@RequestMapping(value = "/saveStudent", method = RequestMethod.POST)
|
||||
public String saveStudent(@Valid @ModelAttribute Student student, BindingResult errors, Model model) {
|
||||
if (!errors.hasErrors()) {
|
||||
// get mock objects
|
||||
List<Student> students = StudentUtils.buildStudents();
|
||||
// add current student
|
||||
students.add(student);
|
||||
model.addAttribute("students", students);
|
||||
}
|
||||
return ((errors.hasErrors()) ? "addStudent.html" : "listStudents.html");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/addStudent", method = RequestMethod.GET)
|
||||
public String addStudent(Model model) {
|
||||
model.addAttribute("student", new Student());
|
||||
return "addStudent";
|
||||
}
|
||||
@RequestMapping(value = "/addStudent", method = RequestMethod.GET)
|
||||
public String addStudent(Model model) {
|
||||
model.addAttribute("student", new Student());
|
||||
return "addStudent.html";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/listStudents", method = RequestMethod.GET)
|
||||
public String listStudent(Model model) {
|
||||
@RequestMapping(value = "/listStudents", method = RequestMethod.GET)
|
||||
public String listStudent(Model model) {
|
||||
|
||||
model.addAttribute("students", buildStudents());
|
||||
model.addAttribute("students", StudentUtils.buildStudents());
|
||||
|
||||
return "listStudents";
|
||||
}
|
||||
return "listStudents.html";
|
||||
}
|
||||
|
||||
private List<Student> buildStudents() {
|
||||
List<Student> students = new ArrayList<Student>();
|
||||
|
||||
Student student1 = new Student();
|
||||
student1.setId(1001);
|
||||
student1.setName("John Smith");
|
||||
student1.setGender('M');
|
||||
student1.setPercentage(Float.valueOf("80.45"));
|
||||
|
||||
students.add(student1);
|
||||
|
||||
Student student2 = new Student();
|
||||
student2.setId(1002);
|
||||
student2.setName("Jane Williams");
|
||||
student2.setGender('F');
|
||||
student2.setPercentage(Float.valueOf("60.25"));
|
||||
|
||||
students.add(student2);
|
||||
return students;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.thymeleaf.utils;
|
||||
|
||||
public class ArrayUtil {
|
||||
|
||||
public static String[] array(String... args) {
|
||||
return args;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung.thymeleaf.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.thymeleaf.model.Student;
|
||||
|
||||
public class StudentUtils {
|
||||
|
||||
private static List<Student> students = new ArrayList<Student>();
|
||||
|
||||
public static List<Student> buildStudents() {
|
||||
if (students.isEmpty()){
|
||||
Student student1 = new Student();
|
||||
student1.setId(1001);
|
||||
student1.setName("John Smith");
|
||||
student1.setGender('M');
|
||||
student1.setPercentage(Float.valueOf("80.45"));
|
||||
|
||||
students.add(student1);
|
||||
|
||||
Student student2 = new Student();
|
||||
student2.setId(1002);
|
||||
student2.setName("Jane Williams");
|
||||
student2.setGender('F');
|
||||
student2.setPercentage(Float.valueOf("60.25"));
|
||||
|
||||
students.add(student2);
|
||||
}
|
||||
|
||||
return students;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
var count = [[${students.size()}]];
|
||||
alert("Number of students in group: " + count);
|
|
@ -0,0 +1,8 @@
|
|||
Dear [(${username})],
|
||||
|
||||
This is the list of our students:
|
||||
[# th:each="s : ${students}"]
|
||||
- [(${s.name})]. ID: [(${s.id})]
|
||||
[/]
|
||||
Thanks,
|
||||
The Baeldung University
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Inlining example</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Title of tutorial: [[${title}]]</p>
|
||||
<p>Description: [(${description})]</p>
|
||||
</body>
|
||||
</html>
|
|
@ -4,6 +4,15 @@
|
|||
<head>
|
||||
<title>Student List</title>
|
||||
</head>
|
||||
<script type="text/javascript"
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
|
||||
<script th:inline="javascript">
|
||||
$(document).ready(function() {
|
||||
$.ajax({
|
||||
url : "/spring-thymeleaf/js",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<body>
|
||||
<h1>Student List</h1>
|
||||
<table border="1">
|
||||
|
|
|
@ -2,8 +2,8 @@ package org.baeldung.security.csrf;
|
|||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
|
@ -59,5 +59,20 @@ public class CsrfEnabledIntegrationTest {
|
|||
public void addStudentWithCSRF() throws Exception {
|
||||
mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON).param("id", "1234567").param("name", "Joe").param("gender", "M").with(testUser()).with(csrf())).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void htmlInliningTest() throws Exception {
|
||||
mockMvc.perform(get("/html").with(testUser()).with(csrf())).andExpect(status().isOk()).andExpect(view().name("inliningExample.html"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsInliningTest() throws Exception {
|
||||
mockMvc.perform(get("/js").with(testUser()).with(csrf())).andExpect(status().isOk()).andExpect(view().name("studentCheck.js"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void plainInliningTest() throws Exception {
|
||||
mockMvc.perform(get("/plain").with(testUser()).with(csrf())).andExpect(status().isOk()).andExpect(view().name("studentsList.txt"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue