Thymeleaf not loading content when I add validation in Spring Boot - spring-boot

Intro:
My app works in the general sense. All as I want. But when I set up validation (and it does work), it won't load all my hidden content. I moved it all to its own page, and it still did not work. So I am asking here with my original set up. I understand it is messy, but I will clean it up once I figure this out.
I can't find anything related to my problem, which makes me think, the way that I am doing it might not be the best approach. So pointers are more than welcome.
Problem:
Adding Validation to my forms breaks my Thymeleaf template. Unable to hide and unhide elements. It looks stuck. But on the terminal, the program does run fine.
My controller
(it's big... I still need to learn how to break it in smaller chunks.)
#Controller
#SessionAttributes({"guess", "word", "result", "level", "attempt", "message", "credits", "name", "gameScore"})
public class GameController {
private static final String WORD_TO_GUESS_CONSTANT = "WORD_TO_GUESS";
private static final String GUESSED_WORD_CONSTANT = "GUESSED_WORD";
private static final String RESULT_CONSTANT = "RESULT_WORD";
private static final String ATTEMPTS_CONSTANT = "ATTEMPTS";
private static final String TOTAL_ATTEMPTS_CONSTANT = "TOTAL_ATTEMPTS";
private static final String MESSAGE_CONSTANT = "MESSAGE";
private static final String CREDITS_CONSTANT = "CREDITS";
private static final String SELECTED_LEVEL_CONSTANT = "SELECTED_LEVEL";
private static final String NAME_CONSTANT = "NAME";
private static final String GAME_SCORE_CONSTANT = "GAME_SCORE";
private static final String SCORE_MULTIPLIER_CONSTANT = "SCORE_MULTIPLIER";
#Autowired
private RandomWordService randomWord;
#Autowired
private WordCheckService checkGuess;
#Autowired
private IsWordCorrectService isWordCorrectService;
#Autowired
private ScoreSavingService scoreSavingService;
#ModelAttribute("gameDto")
public GameDTO guessDTOForm() {
return new GameDTO();
}
#ModelAttribute("score")
public Score score() {
return new Score();
}
// GAME METHODS
#GetMapping(value = "/index")
public String home(Model model,
final HttpServletRequest request,
final HttpSession session,
GameDTO gameDTO,
Score score) {
model.addAttribute("name", session.getAttribute(NAME_CONSTANT));
model.addAttribute("levelSelected", session.getAttribute(SELECTED_LEVEL_CONSTANT));
model.addAttribute("attempt", session.getAttribute(ATTEMPTS_CONSTANT));
model.addAttribute("credits", session.getAttribute(CREDITS_CONSTANT));
model.addAttribute("attemptStart", session.getAttribute(TOTAL_ATTEMPTS_CONSTANT));
model.addAttribute("guess", session.getAttribute(GUESSED_WORD_CONSTANT));
model.addAttribute("result", session.getAttribute(RESULT_CONSTANT));
model.addAttribute("message", session.getAttribute(MESSAGE_CONSTANT));
model.addAttribute("gameScore", session.getAttribute(GAME_SCORE_CONSTANT));
model.addAttribute("lvlName", Level.values());
return "index";
}
#PostMapping(value = "/loadgame")
public String loadWord(
final HttpSession session, final HttpServletRequest request,
#ModelAttribute("score") Score score,
#Valid GameDTO gameDTO, BindingResult bindingResult,
Model model
) throws IOException {
if (bindingResult.hasErrors()) {
model.addAttribute("lvlName", Level.values());
model.addAttribute("name", session.getAttribute(NAME_CONSTANT));
model.addAttribute("levelSelected", session.getAttribute(SELECTED_LEVEL_CONSTANT));
model.addAttribute("attempt", session.getAttribute(ATTEMPTS_CONSTANT));
model.addAttribute("credits", session.getAttribute(CREDITS_CONSTANT));
model.addAttribute("attemptStart", session.getAttribute(TOTAL_ATTEMPTS_CONSTANT));
model.addAttribute("guess", session.getAttribute(GUESSED_WORD_CONSTANT));
model.addAttribute("result", session.getAttribute(RESULT_CONSTANT));
model.addAttribute("message", session.getAttribute(MESSAGE_CONSTANT));
model.addAttribute("gameScore", session.getAttribute(GAME_SCORE_CONSTANT));
return "index";
}
// NEW GAME
String word = (String) request.getSession().getAttribute(WORD_TO_GUESS_CONSTANT);
if (word == null) {
request.getSession().setAttribute(NAME_CONSTANT, gameDTO.getPlayerName());
request.getSession().setAttribute(ATTEMPTS_CONSTANT, gameDTO.getLvlName().getAttempts());
request.getSession().setAttribute(WORD_TO_GUESS_CONSTANT, randomWord.selectRandomWord());
request.getSession().setAttribute(CREDITS_CONSTANT, gameDTO.getCredit());
request.getSession().setAttribute(SELECTED_LEVEL_CONSTANT, gameDTO.getLvlName().getLvlName());
request.getSession().setAttribute(TOTAL_ATTEMPTS_CONSTANT, gameDTO.getLvlName().getAttempts());
request.getSession().setAttribute(GAME_SCORE_CONSTANT, gameDTO.getScore());
request.getSession().setAttribute(SCORE_MULTIPLIER_CONSTANT, gameDTO.getLvlName().getMultiplier());
gameDTO.setWord((String) session.getAttribute(WORD_TO_GUESS_CONSTANT));
}
model.addAttribute("message", "");
return "redirect:/index";
}
#PostMapping(value = "/guess")
public String guessWord(
final HttpSession session,
final HttpServletRequest request,
#ModelAttribute("score") Score score,
#Valid GameDTO gameDTO, BindingResult bindingResult) throws IOException {
if (bindingResult.hasErrors()) {
return "index";
}
// variables
int attempts = (int) session.getAttribute(ATTEMPTS_CONSTANT);
int credits = (int) session.getAttribute(CREDITS_CONSTANT);
int startAttempts = (int) session.getAttribute(TOTAL_ATTEMPTS_CONSTANT);
String name = (String) session.getAttribute(NAME_CONSTANT);
// check word
String wordToGuess = (String) session.getAttribute(WORD_TO_GUESS_CONSTANT);
String guess = gameDTO.getGuess();
String result = checkGuess.resultWord(wordToGuess, guess);
String lvl = (String) session.getAttribute(SELECTED_LEVEL_CONSTANT);
// adjust score according to result
boolean wordIsCorrect = isWordCorrectService.isTheWordCorrect(result, wordToGuess);
int gameScore = (int) session.getAttribute(GAME_SCORE_CONSTANT);
int scoreMultiplier = (int) request.getSession().getAttribute(SCORE_MULTIPLIER_CONSTANT);
int wrongWord = gameDTO.getWrongWord();
int initialScore = gameDTO.getStartScore();
int finalScorePerWord = initialScore * scoreMultiplier;
// GAME LOGIC
if (!wordIsCorrect) {
String message = "";
message = "Wrong! Try again!";
request.getSession().setAttribute(MESSAGE_CONSTANT, message);
request.getSession().setAttribute(ATTEMPTS_CONSTANT, --attempts);
request.getSession().setAttribute(GAME_SCORE_CONSTANT, gameScore - wrongWord);
log(GameController.class, "Updated score: " + session.getAttribute(GAME_SCORE_CONSTANT));
if (attempts == 0) {
request.getSession().setAttribute(CREDITS_CONSTANT, --credits);
message = "Sorry, the word was: [ " + session.getAttribute(WORD_TO_GUESS_CONSTANT) + " ]";
request.getSession().setAttribute(MESSAGE_CONSTANT, message);
request.getSession().setAttribute(ATTEMPTS_CONSTANT, startAttempts);
request.getSession().setAttribute(WORD_TO_GUESS_CONSTANT, randomWord.selectRandomWord());
}
if (credits == 0) {
message = "Game over!";
request.getSession().setAttribute(MESSAGE_CONSTANT, message);
request.getSession().setAttribute(GAME_SCORE_CONSTANT, gameScore);
// SAVE SCORE
score.setGameScore(gameScore);
score.setName(name);
score.setSelectedLevelName(lvl);
scoreSavingService.saveScore(score);
log(GameController.class, "Final score: " + session.getAttribute(GAME_SCORE_CONSTANT));
}
} else {
String message = "Correct! Guess another word!";
wordToGuess = randomWord.selectRandomWord();
gameDTO.setWord(wordToGuess);
request.getSession().setAttribute(MESSAGE_CONSTANT, message);
request.getSession().setAttribute(WORD_TO_GUESS_CONSTANT, wordToGuess);
request.getSession().setAttribute(ATTEMPTS_CONSTANT, startAttempts);
request.getSession().setAttribute(GAME_SCORE_CONSTANT, gameScore + finalScorePerWord);
log(GameController.class, "Current score 2: " + session.getAttribute(GAME_SCORE_CONSTANT));
}
request.getSession().setAttribute(GUESSED_WORD_CONSTANT, guess);
request.getSession().setAttribute(RESULT_CONSTANT, result);
log(GameController.class, "Attempts are now: " + session.getAttribute(ATTEMPTS_CONSTANT));
return "redirect:/index";
}
// BUTTONS
#PostMapping(value = "/save")
public String giveUpAndSaveScore(final HttpSession session,
final HttpServletRequest request,
#ModelAttribute("score") Score score) {
score.setGameScore((Integer) session.getAttribute(GAME_SCORE_CONSTANT));
score.setName((String) session.getAttribute(NAME_CONSTANT));
score.setSelectedLevelName((String) session.getAttribute(SELECTED_LEVEL_CONSTANT));
scoreSavingService.saveScore(score);
request.getSession().invalidate();
return "index";
}
#GetMapping(value = "/scores")
public String seeScores(final HttpServletRequest request, Model model) {
List<Score> scoreList = scoreSavingService.getScore(5, 1);
model.addAttribute("score", scoreList);
return "scores";
}
// CLOSE SESSION
#PostMapping(value = "/destroy")
public String restartGame(final HttpServletRequest request) {
log(GameController.class, " Session closing. Removing the data.");
request.getSession().invalidate();
return "redirect:/index";
}
// EXCEPTION HANDLERS
#ExceptionHandler(value = ArrayIndexOutOfBoundsException.class)
public String handleArrayIndexOutOfBoundsException(final Model model) {
String text = "ERROR: Could not check empty <<guess>>.";
model.addAttribute("text", text);
return "ExceptionPage";
}
#ExceptionHandler(value = NullPointerException.class)
public String handleNullPointerException(final Model model) {
String text = "ERROR: Cannot compare words because <<word to guess>> is null";
model.addAttribute("text", text);
return "ExceptionPage";
}
}
Thymeleaf template for index.html
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html lang="en" xmlns:th="www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>5Letters</title>
<link th:href="#{/bootstrap.min.css}" rel="stylesheet" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Quicksand&display=swap" rel="stylesheet">
</head>
<body>
<div class="container-sm">
<div class="col-xs-12" align="center">
<!-- HEADER -->
<img src="https://marisabel.nl/wp-content/uploads/2020/11/avatar-e1606738130828-150x150.png"
style="margin-top:2vh;">
<h1 style="margin-top:1vh; color:hotpink;"><b>5Letter Word Game</b></h1>
<h5>AKA: Lingo.</h5>
<hr>
</div>
<form method="get" th:action="#{/scores}">
<input type="submit" value="scores" class="btn btn-primary" />
</form>
<!-- Set Up Game Form -->
<div class="col-xs-12" align="center" th:hidden="${credits} != null">
<form th:action="#{/loadgame}" th:object="${gameDTO}" method="post">
<p>
<select class="form-group" th:field="*{lvlName}" id="dropDownList">
<option th:each="lvl : ${lvlName}" th:text="${lvl.lvlName}" th:value="${lvl.lvlName}">
</option>
</select>
</p>
<p><input type="text" class="form-group mx-sm-3 mb-2" id="name" th:field="*{playerName}"
th:placeholder="name" th:value="anonymous" /></p>
<p class="alert alert-danger" th:if="${#fields.hasErrors('playerName')}" th:errors="*{playerName}">
</p>
<p><input type="submit" value="start" class="btn btn-primary" /></p>
</form>
<p></p>
</div>
<!-- This whole session will load after name and level are chosen. Credits will be set to 3, triggering them to unhide -->
<div class="row">
<div class="col-xs-12 col-md-6" align="center" th:hidden="${credits} == null">
<!-- game information : always show after game setup -->
<h3 th:text="'Hello ' + ${name} + '!'"></h3>
<h3 th:text="'Level: '+ ${levelSelected}"></h3>
<h2 th:text="'Credits : '+ ${credits} + ' | Score: '+ ${gameScore}"></h2>
<h2 th:text="${attempt} + ' / ' + ${attemptStart}"></h2>
</div>
<div class="col-md-6" align="center">
<p>
<!-- Result messages and word after guessing -->
<h4 th:text="${message}"></h4>
<h2 id="result" th:text="${result}" th:hidden="${credits} == 0"></h2>
<!-- GUESS FORM -->
<form th:action="#{/guess}" th:object="${gameDTO}" method="post" th:hidden="${credits} == null">
<input id="guessField" type="text" th:field="*{guess}" placeholder="5letters" />
<p></p>
<p class="alert alert-danger" th:if="${#fields.hasErrors('guess')}" th:errors="*{guess}"></p>
<input type="submit" value="guess" th:disabled="${credits} == 0" class="btn btn-primary" />
</form>
</p>
</div>
</div>
<div class="row" style="margin-top:10vh;">
<div class="row justify-content-center" th:hidden="${credits} == null">
<div class="col col-lg-2 align-items-center">
<!-- Destroy session data and go to index -->
<form method="post" th:action="#{/destroy}">
<input type="submit" value="play again" class="btn btn-danger" />
</form>
<p></p>
</div>
<div class="col-md-auto align-items-center" width="50%">
<!-- Display last typed word -->
<h4 th:text="'Your guess was:'" th:hidden="${attempt} == ${attemptStart}"></h4>
<h2 id="guess" th:text="${guess}" th:hidden="${attempt} == ${attemptStart}"></h2>
<p></p>
</div>
<div class="col col-lg-2 align-items-center">
<!-- Stops the game if you are bored. Usually needed with EASY mode. -->
<form method="post" th:action="#{/save}">
<input type="submit" value="i'm tired" class="btn btn-danger" />
<p></p>
</form>
</div>
</div>
</div>
</body>
</html>
I moved the content I was hiding to its own page. It loads the page, but the content remains hidden. Even after taking a break I am still unable to find what is wrong. Specially when it works 100% without validation.

Related

Error resolving template [create], template might not exist or might not be accessible by any of the configured Template Resolvers

I can't figure out why I keep getting this status = 500 template error.
''There was an unexpected error (type=Internal Server Error, status=500).
Error resolving template [create], template might not exist or might not be accessible by any of the configured Template Resolvers
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [create], template might not exist or might not be accessible by any of the configured Template Resolvers''
I tried looking up resources and I coundn't resolve it.
This is what IntelliJ is saying:
This is my create.html template:
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<head th:replace="fragments :: head"></head>
<head>
<link th:href="#{/css/meetups.css}" rel="stylesheet" />
</head>
<body class="create-meetup-body">
<header th:replace="fragments :: header"></header>
<div class="navbar">
<div class="container">
<nav>
<ul class="meetup-nav">
<li>All Meetups
Create a Meetup
Delete a Meetup</li>
</ul>
</nav>
</div>
</div>
<section class="create-meetup-section">
<form method="post">
<div class="form-group">
<div class="form-wrapper">
<label class="form-name">Meetup Name:
<input th:field="${meetup.meetupName}" class="form-control">
</label>
<p class="error" th:errors="${meetup.meetupName}"></p>
<label class="form-email">Contact Email:
<input th:field="${meetup.meetupContactEmail}" class="form-control">
</label>
<p class="error" th:errors="${meetup.meetupContactEmail}"></p>
<!--label class="form-date">Date:
<input type="date" class="form-control">
</label-->
<label class="form-date">Date (mm/dd/yyy):
<input th:field="${meetup.meetupDate}" class="form-control">
</label>
<p class="error" th:errors="${meetup.meetupDate}"></p>
<label class="form-description">Description:
<textarea th:field="${meetup.meetupDescription}" class="form-control"></textarea>
</label>
<p class="error" th:errors="${meetup.meetupDescription}"></p>
<label class="form-category" th:for="category">Category:</label>
<select id="meetupCategory" name="meetupCategory">
<option value="Nature Walk">Nature Walk</option>
<option value="Cycling">Cycling</option>
<option value="Family Activity">Family Activity</option>
<option value="Athletic">Athletic</option>
</select>
<label class="form-trail" th:for="trail">Trail:</label>
<select name="trailId">
<option th:each="trail : ${trails}"
th:text="${trail.name}"
th:value="${trail.id}"></option>
</select>
</div>
</div>
<input type="submit" value="Create Meetup">
</div>
</form>
</section>
</body>
</html>
I believe create.html it's in the correct directory:
This is my controller class:
#RequestMapping("meetups")
public class MeetupController {
#Autowired
private MeetupRepository meetupRepository;
#Autowired
private TrailRepository trailRepository;
#Autowired
private AuthenticationController authenticationController;
#GetMapping
public String displayMeetups(Model model, HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
User theUser = authenticationController.getUserFromSession(session);
model.addAttribute("theUser", theUser);
}
model.addAttribute("title", "Trail Meetups");
model.addAttribute("meetups", meetupRepository.findAll());
model.addAttribute("trails", trailRepository.findAll());
return "meetups/index";
}
#GetMapping("create")
public String displayCreateMeetupsForm(Model model) {
model.addAttribute("title", "Create A New Meetup");
model.addAttribute("trails", trailRepository.findAll());
model.addAttribute(new Meetup());
return "meetups/create";
}
#PostMapping("create")
public String processCreateMeetupsForm(#ModelAttribute #Valid Meetup newMeetup,
Errors errors, Model model, #RequestParam int trailId) {
if (errors.hasErrors()) {
model.addAttribute("title", "Create A New Meetup");
return "create";
}
Optional<Trail> trailObjs = trailRepository.findById(trailId);
if (trailObjs.isPresent()) {
Trail trail = trailObjs.get();
model.addAttribute("trail", trail);
model.addAttribute("trailId", trailId);
newMeetup.setTrail(trail);
meetupRepository.save(newMeetup);
model.addAttribute("meetups", meetupRepository.findAll());
return "meetups/index";
} else {
return "redirect:";
}
}
#GetMapping("delete")
public String displayDeleteMeetupsForm(Model model, HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
User theUser = authenticationController.getUserFromSession(session);
model.addAttribute("theUser", theUser);
}
model.addAttribute("title", "Delete A Meetup");
model.addAttribute("meetups", meetupRepository.findAll());
return "meetups/delete";
}
#PostMapping("delete")
public String processDeleteMeetupsForm(#RequestParam(required = false) int[] meetupIds, Model model, HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
User theUser = authenticationController.getUserFromSession(session);
model.addAttribute("theUser", theUser);
}
if (meetupIds != null) {
for (int id : meetupIds) {
meetupRepository.deleteById(id);
}
}
return "redirect:";
}
#GetMapping("details")
public String displayMeetupDetails(#RequestParam Integer meetupId, Model model, HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
User theUser = authenticationController.getUserFromSession(session);
model.addAttribute("theUser", theUser);
}
Optional<Meetup> result = meetupRepository.findById(meetupId);
if (result.isEmpty()) {
model.addAttribute("title", "Invalid: A meetup with ID " + meetupId + "does not seem to exist.");
} else {
Meetup meetup = result.get();
model.addAttribute("title", meetup.getMeetupName() + " Details");
model.addAttribute("meetups", meetup);
model.addAttribute("trails", trailRepository.findAll());
}
return "meetups/details";
}

Load dynamic image from external url in thymleaf img tag[SringBoot]

I have a Dynamic external url that i am setting in model at controller side and trying to access in html using thymleaf tag
Here is the code:
Controller:
#RequestMapping(value = "/{id:.+}", method = RequestMethod.GET)
public String searchUser(#PathVariable("id") String data, Model model) {
/*
* if (!data.startsWith("#")) { data = "#" + data; }
*/
List<User> list = userService.searchUserUsingText(data);
if (list.isEmpty()) {
System.out.println("error");
return "404";
} else {
User user = list.get(0);
if (null != user.getName())
model.addAttribute("name", user.getName());
if (null != user.getProfession())
model.addAttribute("profession", user.getProfession());
if (null != user.getPhotoUrl()) {
System.out.println("inside image" + user.getPhotoUrl());
model.addAttribute("image" + user.getPhotoUrl());
}
return "profile";
}
}
PhotoUrl will be a external url like:
https://firebasestorage.googleapis.com/v0/b/mysocialhandle-ecfc0.appspot.com/o/images%2FFtX4VVciacM1jKdrP2NfInSyWMf1%2FFtX4VVciacM1jKdrP2NfInSyWMf1.jpg?alt=media&token=10e06c9b-044e-4e15-ab74-a55429bcb22b
Thymleaf/Html side:
<div class="container">
<div class="owner">
<div class="avatar">
<img th:src="#{${image}}" alt="Circle Image"
class="img-circle img-no-padding img-responsive">
</div>
<div class="name">
<h4 class="title" th:text="${name}">
<br />
</h4>
<h6 class="description" th:text="${profession}"></h6>
</div>
</div>
name and profession are resolved perfectly but at img Tag i am getting null.
Guys please help in this...
You have
model.addAttribute("image" + user.getPhotoUrl());
I think you meant to have
model.addAttribute("image", user.getPhotoUrl());

Bad request error while submitting a form in Spring 4

I'm getting a 400 bad request error while submitting my form.
I'm using spring 4.0.6 version. I don't why this is happening. Please see the below error what I'm getting.
Here is my JSP
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%# page isELIgnored="false" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<script src="<c:url value='/static/js/jquery-3.3.1.js' />"></script>
<script src="<c:url value='/static/js/bootstrap.min.js' />"></script>
<script src="<c:url value='/static/js/jquery.validate.min.js' />"></script>
<script src="<c:url value='/static/js/additional-methods.min.js' />"></script>
<script src="<c:url value='/static/js/jquery.mask.js' />"></script>
<script src="<c:url value='/static/js/jquery-ui.js' />"></script>
<link href="<c:url value='/static/css/bootstrap.min.css' />" rel="stylesheet"></link>
<link href="<c:url value='/static/css/jquery-ui.css' />" rel="stylesheet"></link>
<style>
.head-color {
background: rgb(243, 246, 234);
color: #800000;
text-align:center;
}
.date-width{
width:25% !important;
}
.error{
color:red;
}
</style>
<script type="text/javascript">
$(function() {
document.getElementById("claimFilingForm").reset();
$('.phone-us').mask('(000) 000-0000');
$('.zip-code').mask('00000-0000');
$( "#phoneAssignedDate" ).datepicker();
jQuery.validator.addMethod("valueNotEquals", function(value, element, arg){
return arg !== value;
}, "This field is required.");
jQuery.validator.setDefaults({
debug: true,
success: "valid"
});
$( "#claimFilingForm" ).validate({
rules: {
firstName: {
required: true
},
lastName: {
required: true
},
address: {
required: true
},
city: {
required: true
},
state: {
required: true
// valueNotEquals: "default"
},
nickname: {
required: true
},
zip: {
required: true,
zipcodeUS: true
},
phone: {
required: true,
phoneUS: true
},
email: {
required: true,
email: true
},
optradio: {
required: true
},
phoneAssignedDate: {
required: {
depends: function() {
return $('input[name="optradio"]:checked').val() == 'N';
}
}
},
signature: {
required: true
}
},
messages: {
},
errorPlacement: function(error, element) {
var placement = $(element).data('error');
if (placement) {
$(element).css("display","");
$(placement).append(error);
} else {
error.insertAfter(element);
}
},
submitHandler: function(form) {
if ($(form).valid())
{
form.submit();
}
return false; // prevent normal form posting
}
})
});
</script>
</head>
<body>
<div class="container">
<h2 class="well head-color">CLAIM FILING</h2>
<div class="form-group">
<span style="font-weight: bold; color: #875a24;">This is a claim in connection with a class of persons
who were successfully sent unsolicited Pollo Trophical Commercial text messages on
what are commonly called recycled numbers between March 1, 2012 and March 15, 2017</span>
</div>
<div class="col-lg-12 well">
<div class="row">
<form:form id="claimFilingForm" modelAttribute="claimant" method="POST" action="claimFiling">
<div class="col-sm-12">
<div class="form-group">
<span style="font-weight: bold;">1. You Must Provide Your Contact Information, including any nicknames or
aliases or any name you use to obtain mobile telephone service for you or your
family members</span>
</div>
<div class="row">
<div class="col-sm-6 form-group">
<label>First Name</label>
<form:input type="text" id="firstName" name="firstName" path="firstName" placeholder="Enter First Name" class="form-control" autofocus=""/>
</div>
<div class="col-sm-6 form-group">
<label>Last Name</label>
<form:input type="text" id="lastName" name="lastName" path="lastName" placeholder="Enter Last Name" class="form-control"/>
</div>
</div>
<div class="form-group">
<label>Address</label>
<form:textarea placeholder="Enter Address" id="address" name="address" path="address" rows="3" class="form-control"></form:textarea>
</div>
<div class="row">
<div class="col-sm-4 form-group">
<label>City</label>
<form:input type="text" id="city" name="city" path="city" placeholder="Enter City Name" class="form-control"/>
</div>
<div class="col-sm-4 form-group">
<label>State</label>
<form:input type="text" id="state" name="state" path="state" placeholder="Enter State Name" class="form-control"/>
</div>
<div class="col-sm-4 form-group">
<label>Zip</label>
<form:input type="text" id="zip" name="zip" path="zip" placeholder="Enter Zip5-Zip4 Code" class="form-control zip-code"/>
</div>
</div>
<div class="row">
<div class="col-sm-6 form-group">
<label>Company/Nickname/Alias</label>
<form:input type="text" id="nickname" name="nickname" path="nickname" placeholder="Enter Company/Nickname/Alias" class="form-control"/>
</div>
<div class="col-sm-6 form-group">
<label>Phone Number</label>
<form:input type="text" id="phone" name="phone" path="phone" placeholder="Enter Phone Number" class="form-control phone-us"/>
</div>
</div>
<div class="form-group">
<label>Email Address</label>
<form:input type="text" id="email" name="email" path="email" placeholder="Enter Email Address" class="form-control"/>
</div>
<div class="form-group">
<br/><br/>
<span style="font-weight: bold;">2. You Must Verify Ownership of the Number Listed Above please select one</span>
</div>
<div class="form-group radio">
<label><form:radiobutton id="optradio1" name="optradio" path="optradio" value="N" data-error="#optradio-error"/>The telephone number listed above was assigned
to me as of below mentioned date
and I did not consent to receive Pollo Trophical advertising text messages
<form:input type="text" id="phoneAssignedDate" name="phoneAssignedDate" placeholder="Select a Date" path="phoneAssignedDate" class="form-control date-width" style="cursor: pointer;" readonly="true"/></label>
</div>
<br/>
<div class="form-group radio">
<label><form:radiobutton id="optradio2" name="optradio" path="optradio" value="Y" />The number listed above was assigned to me and I consented to receive texts from Pollo Trophical</label>
</div>
<div class="form-group">
<span id="optradio-error" class="text-danger align-middle error">
<!-- Put name validation error messages here -->
</span>
</div>
<div class="form-group">
<label>Signature</label>
<form:input type="text" id="signature" name="signature" path="signature" placeholder="Enter Your Name" class="form-control"/>
</div>
<button type="submit" class="btn btn-lg btn-info">Submit</button>
</div>
</form:form>
</div>
</div>
</div>
</body>
</html>
Here is my Controller
package com.application.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.application.model.Claimant;
import com.application.service.ClaimFilingService;
#Controller
#RequestMapping("/")
public class ClaimFilingController {
#Autowired
private ClaimFilingService claimFilingService;
#RequestMapping(value = { "/" }, method = RequestMethod.GET)
public String home(ModelMap model) {
return "redirect:/claimFiling";
}
/*
* This method will serve as default GET handler.
*/
#RequestMapping(value = { "/claimFiling" }, method = RequestMethod.GET)
public String newRegistration(ModelMap model, HttpServletRequest request) {
Claimant claimant = new Claimant();
model.addAttribute("claimant", claimant);
return "claimFiling";
}
/*
* This method will be called on form submission, handling POST request It
* also validates the user input
*/
#RequestMapping(value = { "/claimFiling" }, method = RequestMethod.POST)
public String saveRegistration(#ModelAttribute("claimant") Claimant claimant, ModelMap model, HttpServletRequest request) {
String result = claimFilingService.insertClaimDetails(claimant, request);
if(!result.equalsIgnoreCase("")) {
model.addAttribute("ClaimId", result);
return "success";
}
model.addAttribute("message","Process Failed");
return "claimFiling";
}
}
Here is my Claimant model class
package com.application.model;
import java.sql.Date;
public class Claimant {
private String firstName;
private String lastName;
private String address;
private String city;
private String state;
private String zip;
private String nickname;
private String phone;
private String email;
private String optradio;
private Date phoneAssignedDate;
private String signature;
public Claimant(String firstName, String lastName, String address, String city, String state, String zip,
String nickname, String phone, String email, String optradio, Date phoneAssignedDate, String signature) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.city = city;
this.state = state;
this.zip = zip;
this.nickname = nickname;
this.phone = phone;
this.email = email;
this.optradio = optradio;
this.phoneAssignedDate = phoneAssignedDate;
this.signature = signature;
}
public Claimant() {
super();
// TODO Auto-generated constructor stub
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getOptradio() {
return optradio;
}
public void setOptradio(String optradio) {
this.optradio = optradio;
}
public Date getPhoneAssignedDate() {
return phoneAssignedDate;
}
public void setPhoneAssignedDate(Date phoneAssignedDate) {
this.phoneAssignedDate = phoneAssignedDate;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
}
I'm a beginner to spring so can some body help me to identify the problem.
Yes, I found the mistake. In the POJO class I changed the type of phoneAssignedDate to String. This resolved my problem :-)

Spring + Thymeleaf can't pass the parameter correctly

I can't pass the parameter correctly. I know the error was in the HTML.
The error was in the code ${vo.news.likeCount}, ${vo.news.link}, and so on.
But I don't know how to use it in the correct way. Thank you.
This is a thymeleaf template:
<div class="posts">
<div th:each="vo : ${vos}">
<div class="post">
<div class="votebar">
<button class="click-like up" aria-pressed="false" title="赞同"><i class="vote-arrow"></i>
<span class="count"><span th:text="${vo.news.likeCount}"></span></span>
</button>
<button class="click-dislike down" aria-pressed="true" title="反对"><i class="vote-arrow"></i>
</button>
</div>
<div class="content" data-url="${vo.news.link}">
<div>
<img class="content-img" src="${vo.news.image}" alt="">
</div>
</div>
</div>
</div>
</div>
This is class ViewObject:
public class ViewObject {
private Map<String, Object> obj = new HashMap<String, Object>();
public void set(String key, Object value) {
obj.put(key, value);
}
public Object get(String key) {
return obj.get(key);
}
}
This is the controller method:
#RequestMapping(path = {"/", "/index"}, method = {RequestMethod.GET, RequestMethod.POST})
public String index(Model model) {
List<News> newsList = newsService.getLatesNews(0, 0, 10);
List<ViewObject> vos = new ArrayList<>();
for (News news : newsList) {
ViewObject vo = new ViewObject();
vo.set("news", news);
vo.set("user", userService.getUser(news.getUserId()));
vos.add(vo);
}
model.addAttribute("vos", vos);
return "home.html";
}
The expression vo.news.likeCount means vo.getNews().getLikeCount(). ViewObject doesn't have method getNews(). You need to structure your expressions to look the same way they would in java.
<span th:text="${vo.get('news').likeCount}"></span>
<img class="content-img" src="${vo.get('news').image}" alt="">
<div class="content" data-url="${vo.get('news').link}">
etc...

Springboot Thymeleaf : How to format row according to a condition

I have a page that displays the list of all the journals available. I want to write a thymeleaf expression language that highlights the already subscribed journals using there journal id . So for all the subscribed journals the text for the hyper-link href should be "Unsubscribe" and vice verse if its not subscribed.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<title>TBD</title>
<!--/*/ <th:block th:include="fragments/headinc :: head"></th:block> /*/-->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
</head>
<body>
<div class="container">
<h1 th:text="'Hello, ' + ${user.fullname} + '!'" />
<p>Manage your subscriptions here</p>
<form role="form" id="form-search" class="form-inline"
th:action="#{/subscriptions}" method="get">
<input type="text" class="form-control" id="filter" name="filter"
placeholder="Enter filter"></input>
<button type="submit" class="btn btn-default">
<span class="glyphicon glyphicon-search"></span> Search
</button>
<a th:href="#{/logout}" class="btn btn-link" role="button">Logout</a>
</form>
<div th:if="${not #lists.isEmpty(journals)}">
<form role="form" id="form-subscribe" th:action="#{/subscribe}"
method="post">
<input type="hidden" name="journalId" id="journalId" />
</form>
<table id="table" class="table">
<thead>
<tr>
<th>Subject</th>
<th>Filename</th>
<th>Tags</th>
<th>View</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="journal : ${journals}">
<td th:text="${journal.subject}">Id</td>
<td th:text="${journal.filename}">Product Id</td>
<td th:text="${journal.tags}">Description</td>
<td><a>View</a></td>
<td><a id="href"
th:href="'javascript:subscribe(\'' + ${journal.id} + '\');'">Subscribe</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
<script type="text/javascript">
function subscribe(journalId) {
$('#journalId').val(journalId);
$('#form-subscribe').submit();
}
</script>
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
$(document).ready(function() {
var modelAttributeValue = [[${subscriptions}]];
console.log(modelAttributeValue);
alert(modelAttributeValue);
var array = modelAttributeValue.split(';');
console.log(array);
alert(array);
});
/*]]>*/
</script>
</html>
Controller
#Controller
public class SubscriptionController {
#Autowired
private SubscriberService subscriberService;
#RequestMapping(value = "/subscribe", method = RequestMethod.POST)
String subscribe(Model model, #RequestParam("journalId") Integer journalId) {
JournalToken token = (JournalToken) SecurityContextHolder.getContext().getAuthentication();
Account user = (Account) token.getCredentials();
model.addAttribute("user", user);
Journal journal = this.subscriberService.findJournalById(journalId);
this.subscriberService.subscribeJournalForSubscriber(journal, user);
return "redirect:subscriptions";
}
#RequestMapping(value = "/subscriptions", method = RequestMethod.GET)
String list(Model model) {
JournalToken token = (JournalToken) SecurityContextHolder.getContext().getAuthentication();
Account user = (Account) token.getCredentials();
model.addAttribute("user", user);
ArrayList<Journal> journals = this.subscriberService.FindAllJournals();
model.addAttribute("journals", journals);
StringBuilder sub = new StringBuilder();
ArrayList<Subscription> subscribed = this.subscriberService.getSubscribedJournalsForSubscriber(user);
model.addAttribute("subscriptions", subscribed);
return "subscriptions";
}
}
Model subscriptions
#Entity
#Table(uniqueConstraints={#UniqueConstraint(columnNames={"userId", "journalId"})})
public class Subscription {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Version
private Integer version;
private Integer userId;
private Integer journalId;
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return this.id;
}
public void setVersion(Integer version) {
this.version = version;
}
public Integer getVersion() {
return this.version;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getUserId() {
return this.userId;
}
public void setJournalId(Integer journalId) {
this.journalId = journalId;
}
public Integer getJournalId() {
return this.journalId;
}
}
you can change your arrayList subscribed to have only the ids of journals (more optimised).
So, in the controller you can have something like this
ArrayList<Integer> subscribed =
this.subscriberService.getSubscribedJournalsForSubscriber(user); //modify it so it returns the journals ids instead of the whole object(Subscription)
then in the thymeleaf change the anchor with something like this
<a id="href" th:href="'javascript:subscribe(\'' + ${journal.id} + '\');'">
<span th:if="${#lists.contains(subscriptions, journal.id) }" th:text="Unsubscribe"> Unsubscribe </span>
<span th:if="not ${#lists.contains(subscriptions, journal.id) }" th:text="Subscribe"> Subscribe </span>
</a>
Have a look at the documentation of thymeleaf http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html
/*
* Check if element or elements are contained in list
*/
${#lists.contains(list, element)}
${#lists.containsAll(list, elements)}

Resources