I am trying to get a list of objects that are sent to the server from the html form as parameters for my list, then I will loop through those entries and then return them through the springboot th:each. But it doesn't seem to be working at all. On load the form appears but when I enter a value in it, then it returns an error page and the URL however turns:
http://localhost:8080/#%7B/%7D?%24%7Bcontent%7D=hello
this output in eclipse says:
Expression "content" is not valid: only variable expressions ${...} or selection expressions *{...} are allowed in Spring field bindings
Note: content here is the value property in my form.
My controller looks like this:
#Controller
public HelloList() {
this.addUs = new ArrayList <>();
}
#RequestMapping("/")
public String getlist(#RequestParam (required = false) String content, Model model) {
if (content != null && !content.trim().isEmpty()) {
this.addUs.add(content);
}
model.addAttribute("list",addUs);
return "index";
}
the index.html looks like this
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Insert title here</title>
</head>
<body>
<div>
<ul>
<li th:each="amHere: ${addUs}">
<span th:text="${amHere}">hello! world</span>
</li>
</ul>
<form action="#{/}" method="GET">
<input type="text" name="content"/>
<input type="submit" value="Submit"/>
</form>
</div>
</body>
</html>
This might be a duplicate but it seems like most of the solutions I came across are not helping. So any help is mostly appreciated. Thank you in advance.
Turns out I was missing the initialization of my list in the constructor. I initialized the list by adding a value to it first in the constructor like this.
this.addUs.add("Hello World");
Because the #RequestMapping is mapped to the home path in my case index.html, any request gets sent there automatically.
working example
action = "#{/}" should be th:action="#{/}". That's the reason you're seeing the weird url (because it's url encoding #{/}). Thymeleaf only evaluates expressions that start with th:.
I'm not sure about the other error. It looks like the html you've pasted doesn't match up with the error you are getting.
If you urldecode http://localhost:8080/#%7B/%7D?%24%7Bcontent%7D=hello, you get http://localhost:8080/#{/}?${content}=hello, which doesn't line up with your form.
Related
Hi Guys!
I have been implementing service in Spring Boot which
allows users to send anonymouse questionaries to server.
I have already implemented most of the backend like adding users etc. and right now I have been struggling with one action which take answers from user and sends into server (save in database).
Object containing answers (filledSurvey) is being sent as empty. In this same logic in logging users fields from form are corectly send forward.
This endpoint displays questionary:
#RequestMapping(path = {"/try", "/try/{id}"})
public String tryCompletingSurvey(Model model, #PathVariable("id") Long id) {
Connection connection = connectionService.getConnection(id);
FilledSurvey filledSurvey = connection.getSurvey().getTemplate();
for (FilledQuestion filledQuestion : filledSurvey.getFilledQuestions()) {
filledQuestion.getFilledAnswers().get(0).setCheck(true);
}
model.addAttribute("filledSurvey", filledSurvey);
return "completing/completing";
}
This is thymeleaf html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Completing survey</title>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
</head>
<body>
<center>
<form action="#" th:action="#{/user/surveys/finish}" th:object="${filledSurvey}" method="post">
<!-- <div th:each="question, questionStat : ${survey.getFilledQuestions()}" >-->
<!-- <p th:text="${question.getQuestion()}"></p>-->
<!-- <div th:each="answer, answerStat: ${question.getFilledAnswers()}" >-->
<!-- <input type="radio"-->
<!-- th:name="question+${questionStat.index}"-->
<!-- th:field="*{}"-->
<!-- th:value="${true}">-->
<!-- <label th:text="${answer.answer}">-->
<!-- </label>-->
<!-- </div>-->
<!-- </div>-->
<h2>Survey name: </h2>
<h3 th:text="${filledSurvey.getSurveyName()}"></h3>
<h2>Number of questions: </h2>
<h3 th:text="${filledSurvey.filledQuestions.size()}"></h3>
<div class="col-md-6">
<input type="submit" style="align-content: center" class="btn btn-primary" value=" Send ">
</div>
</form>
</center>
</body>
</html>
And this is endpoint which stores empty object from thymeleaf:
#RequestMapping(path = "/finish", method = RequestMethod.POST)
public String getHash(FilledSurvey filledSurvey) {
StringBuilder sb = new StringBuilder();
for (FilledQuestion question : filledSurvey.getFilledQuestions()) {
for (FilledAnswer answer : question.getFilledAnswers()) {
if (answer.isCheck()) sb.append(answer.getAnswer());
}
}
LocalDateTime date = LocalDateTime.now();
sb.append(date);
String hash = sb.toString();
hash = Base64.getEncoder().encodeToString(sb.toString().getBytes());
filledSurvey.setHash(hash);
surveyMagazinService.addSurveyToMagazin(filledSurvey);
return "completing/finish";
}
I changed code to automaticly mark answers for now.
This the picture of the object in the next endpoint:
filledSurvey object
I am aware that this is common question but i have been looking for the answer for a while now and couldn't figure it out. I have no errors in the console as well. I would appreciate any help or feedback.
If I understood correctly, I see following issue:
You are using a form to submit the survey data and use the th:object="${filledSurvey}" to bind the data. But there is actually not data send back to the controller, when the form is submitted, because there are no input fields defined that have the th:field attribute applied.
The request that will be send to the server on a submit, will contain form encoded data of all fields that you assign a th:field attribute to. The controller will map the form encoded data to a FilledSurvey object using java bean convention in the getHash method.
EDIT: can you try adding the #ModelAttribute annotation:
#RequestMapping(path = "/finish", method = RequestMethod.POST)
public String getHash(#ModelAttribute FilledSurvey filledSurvey) {
...
Try adding an input field like this inside your form:
<input type="hidden" th:field="*{surveyId}" >
This should give you at least an FilledSurvey object with the id set on your "/finish" endpoint. You can then use the id to fetch the survey like its done in the first code snippet.
The way you are using the th:field within your list of questions will not work, because spring cannot map this kind of structure. See https://spring.io/guides/gs/handling-form-submission/ to understand how form submission works with spring mvc.
I hope this helps a bit, best regards ;)
My thymeleaf form is not picking up the input longUrl. When I run the application on debug, it hits the post request below with "". How can I make it pick up the form input and send it over in the body?
Thymeleaf Form:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST" th:action="#{create_short_url_thymeleaf}">
<h1>Hit Enter to Shorten Your Long Url</h1>
<input type="text" th:name="longUrl"/>
</form>
</body>
</html>
Even when I try to manually populate the value, it still doesn't make it into the controller
<input type="text" name="longUrl" value="somelongurl"/>
Controller Code:
#Controller
#RequestMapping("/api/v1")
public class UrlShorteningController {
#GetMapping("/create_short_url")
public String newShortUrl(Model model) {
model.addAttribute("longUrl",
"");
return "some-form";
}
#PostMapping("/create_short_url_thymeleaf")
ResponseEntity<String> newShortUrlFromThymeleaf(#ModelAttribute String longUrl) {
// Running the application on debug, I make it here, but the longUrl is empty.
....
}
try to replace
th:action="#{create_short_url_thymeleaf} with
th:action="#{/create_short_url_thymeleaf}
Ah, I solved it. I needed to swap that #ModelMapper annotation for a #RequestBody and now it works.
I have a file testHTML.jsp to display a string which contains some HTML special characters:
<body>
<div id="test" class="test">
<c:out value="${htmlContent}" />
</div>
</body>
Variable htmlContent is set in a SpringMVC controller:
#RequestMapping(value = "/testHTML", method = RequestMethod.GET)
public String getHTML(HttpServletRequest request) {
String content = "<html>\n<p>Test Me\n</html>\n";
request.setAttribute("htmlContent", content);
return "/test/testHTML";
}
Deploy the test app on Tomcat and use Firefox to display the jsp. The variable content is printed in its original format with angle brackets, etc. That is, the HTML special characters are escaped. This could be confirmed by viewing the source code of the rendered page of Firefox.
My question is who did the escape job during this process? The web browser (Firefox), the jsp engine, or something else? Thanks
Try to define the content in standard template. To make it cross browser compatible.
String content ="
<!DOCTYPE html>
<html>
<body>
<h1>Test Me</h1>
<p>Test Me 2.</p>
</body>
</html>";
I need to implement some basic dropdown using jsp and java, but I can't find more info how to do that. So I never write something using JSP and when I didnt find nothing that help the last options for me was to ask.
I want to get the selected value and when click the button to send the value to anoher .jsp file ("selector.jsp in my case")
Please folks help me with some easy solution.
p.P.: Sorry for my english (:
index.jsp
<FORM method="post" action="selector.jsp">
<select name="select" id="dropdown">
<%
Test t = new Test();
t.getList().add("a");
t.getList().add("b");
t.getList().add("c");
for(int i=0; i < t.getList().size(); i++){
%>
<Option value="<%t.getList().get(i);%>"><%=t.getList().get(i)%></Option>
<%}%>
</select>
<input type="submit" value="click">
selector.jsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
You selected:
<%
request.getParameter("select");
request.getParameterValues("select");
%>
</body>
</html>
I found a solution by removing
value="<%t.getList().get(i);%>"
from and leave the code just with
<Option><%=t.getList().get(i)%></Option>
but i don't know why... if someone can explain will be great.
Thx! (:
As you have indicated in your post, the problem is solved by replacing
value="<%t.getList().get(i);%>"
with
<Option><%=t.getList().get(i)%></Option>
The reason that works is as follows:
In your first form, <%t.getList().get(i);%>, you have a JSP scriptlet. This is Java code that is executed inline. In your case, this executes the "get" method. Note however that the get method returns a value, but this value is not output into the response stream.
In your second form, you have formed a JSP expression by using "<%=". "<%=" is shorthand for "out.println", thus you have provided shorthand for the following:
<Option><% out.println(t.getList().get(i)) %></Option>
This writes the return value of the method call to the output stream. So that when this output reaches the browser, there is an actual value within the Option tags.
I am using Struts 2 and Apache tiles, and I'm new to both. I am trying to "clean" some existing sources that don't feel correct to me (tell me if I'm wrong).
I have the following structure :
in a layout.jsp :
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title><tiles:getAsString name="title" /></title>
<tiles:insertAttribute name="header" />
</head>
<body>
<div id="content-size-and-border">
<s:if test="display!='nomenu'">
<tiles:insertAttribute name="menu" />
</s:if>
<div id="maincontent">
<tiles:insertAttribute name="maincontent" />
</div>
</div>
</body>
The main content part displays various jsp/action depending on the item-menu clicked.
The menu part uses some java code directly in the jsp to generate a number of sub-folders by iterating on a list.
<li class="highlight sousmenu"><a href="#"><s:text
name="menu.demarrage" /></a>
<ul class="niveau2">
<%
Locale language = (Locale) session.getAttribute("WW_TRANS_I18N_LOCALE");
// the attribute (used by i18n struts interceptor)
// set in session when the user changes the language
if (language == null)
language = request.getLocale() ;
// if the language was not changed, get the default Locale from browser
User user = ((CustomUserDetails) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal()).getBpmUser();
if (user != null) {
for (Iterator iterator = user.getProcesses().iterator(); iterator
.hasNext();) {
String processToStart = (String) iterator.next();
String processPath = BpmUiConstantes.BPMUI_PROCESS_CONFIG_ROOT + "/" + processToStart ;
String processLib = "process." + processToStart + ".label";
%>
<li>
<a href="<%=request.getContextPath()%>/restricted/DemarrerProcessAvecTache?processName=<%=processToStart%>">
<fmt:setLocale value="<%=language%>"/>
<fmt:bundle basename="<%=processPath%>">
<fmt:message key="<%=processLib%>"/>
</fmt:bundle>
</a>
</li>
<%
}
}
%>
</ul>
</li>
I was wondering if there was a better way to achieve the same result, without the java code in the jsp. Is it important to remove the java code from the jsp from a conception point of view ?
The application uses struts i18n interceptor for the language changes. Is there a way to have the menu use a struts i18n interceptor in some way?
I would definitely look more into JSTL core (C tag to use foreach) and fmt(for the locale- language), with these two libraries you should be able able to safely remove the embedded java code into your page and use a more congruent/safe approach
Here is the oracle webpage to JSTL so you can have some reference
JSTL Reference
Feel free to ask if you have any other questions.
I will add some piece of answer to the previous post :
There is no way to have this menu use a struts i18n interceptor and, above all, it is useless because ResourceBundle's Locale or fmt:bundle's Locale would not be set by this interceptor. It is necessary to specify explicitely the Locale (like I did in the code) => this part cannot be changed.
I'm still not sure about the importance of removing this java code from the jsp though.