Got a homework assignment that is giving me problems.... Its modifying a JSF project with two pages and a bean to fit MVC2 by adding two more pages and a controller servlet and another bean for the two additional pages. the new main page forwards to either the second new page or the old first page. My issue is response.getParameter() always results in null.
<%#page session="false" import="java.util.Iterator"%>
<%#taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%#taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<jsp:useBean id="status" scope="request" class="JSFRegistration.Status" />
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>JSP Page</title>
</head>
<body>
<% if (status!=null && !status.isSuccessful()){%>
<font color="red">Processing errors:
<ul><%Iterator errors=status.getExceptions();
while (errors.hasNext()){
Exception e = (Exception) errors.next();%>
<li><%= e.getMessage()%><%}%></ul></font><%}%>
<form action="LoginServlet" method="POST">
<% String username = request.getParameter("username");
if (username==null) username="";%>
<input type="text" name="usernameTF" value="<%=username%>" />
<% String password = request.getParameter("password");
if (password==null) password="";%>
<input type="password" name="passwordTF" value="<%=password%>" />
<input type="submit" value="Login" />
</form>
</body>
</html>
this is basically a direct copy from our book but the fields I need for the new main page. Same for the controller servlet, a direct copy except only contains the fields I need.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher view = null;
Status status = new Status();
request.setAttribute("status", status);
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username==null || username.length()==0)
status.addException(new Exception("Please enter username"));
if (password==null)
status.addException(new Exception("Please enter password"));
if (!status.isSuccessful()){
view = request.getRequestDispatcher("Login.jsp");
//view.forward(request, response);
}
else
try{
request.setAttribute("username", username);
request.setAttribute("password", password);
view = request.getRequestDispatcher("Registration.jsp");
} catch (Exception e) {
status.addException(new Exception("Error"));
view = request.getRequestDispatcher("Login.jsp");
}
view.forward(request, response);
}
and the Status class, again a direct copy from the book.
public class Status {
private ArrayList exceptions;
public Status(){
exceptions = new ArrayList();
}
public void addException(Exception exception) {
exceptions.add(exception);
}
public boolean isSuccessful(){
return (exceptions.isEmpty());
}
public Iterator getExceptions(){
return exceptions.iterator();
}
regardless of what is typed into the two boxes, stepping through a debug shows the values not getting passed to the parameters. I get the created exceptions printed above the screen for both fields if both have text, if only one has text and when both are empty.
Your request parameter names do not match the input field names. You've assigned the input fields a name of usernameTF and passwordTF. They are then available by exactly those names as request parameter, but you're attempting to get them using the names username and password. So you need either to fix the input field names, or the request parameter names so that they match each other.
By the way, why falling back from a modern MVC framework like JSF to awkward 90's style JSP with mingled business code? Is that really what the homework assignment is asking you? Also the HTML <font> element is deprecated since 1998. Where did you learn about it? Is the quality of the course really good?
Related
I tried to write my Spring Controller, using Thymeleaf, for a simple code sharing platform. So I wrote these methods
#PostMapping(value = "/api/code/new")
#ResponseBody
public String addNewCode(#RequestBody RequestCodeDTO code, Model model) {
CodeSnippet codeSnippet = new CodeSnippet();
codeSnippet.setCode(code.getCode());
codeSnippet.setDate("Jul 17, 2022");
model.addAttribute("code", codeSnippet);
return "";
}
#GetMapping(value = "/code/new")
public String returnNewCode(Model model){
return "CodeSnippet";
}
And my CodeSnippet.html is like this
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://thymeleaf.org" lang="en">
<head>
<title>Code</title>
</head>
<body>
<span id="load_date" th:text="${code.getDate()}">date</span>
<pre id="code_snippet" th:text="${code.getCode()}">code</pre>
</body>
</html>
But when I try to make this get request, I reseive "org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/CodeSnippet.html]")".
I tried to change tags of html file, change gradle build file, but it all was in vain.
After reading questions and answers on the topic, such as
Explanation of the model object in Spring
as well as the official documentation of Spring MVC, I still wonder why is a Spring MVC model attribute is not (always) accessible in the model. For example in my code below you can see a Spring MVC Controller class:
#Controller
#RequestMapping("/student")
public class StudentController {
#RequestMapping("/showForm")
public String showForm(Model model) {
Student theStudent = new Student();
model.addAttribute("student", theStudent);
return "student-form";
}
#RequestMapping("/processFormV1")
public String processStudentInput(#ModelAttribute("student") Student student, Model model) {
System.out.println("student.getFirstName(): " + student.getFirstName());
System.out.println("student.getLastName(): " + student.getLastName());
return "student-confirmation";
}
#RequestMapping("/processFormV2")
public String processStudentInput(Model model) {
Student student = (Student) model.getAttribute("student");
System.out.println("student.getFirstName(): " + student.getFirstName());
System.out.println("student.getLastName(): " + student.getLastName());
return "student-confirmation";
}
}
and this is my view, student-form.jsp:
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<title>Student Form</title>
</head>
<body>
<form:form action="processFormV2" modelAttribute="student">
First name: <form:input path="firstName"/>
<br>
Last name: <form:input path="lastName"/>
<input type = "submit" value="Submit"/>
</form:form>
</body>
</html>
Now, when the form action is processFormV2 and I submit the form, the line below gives me a null for the student:
Student student = (Student) model.getAttribute("student");
However, when I change the form action to processFormV1 and I submit the form, in the controller method I am able to read the provided values for both names of the Student correctly.
Why is this so?
What is the scope of the values in a Model? Request or Session? From what I have, I always thought the scope is session. Is that right?
How can I addObject to modelandview with modelandview parameter? I mean something like that:
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
ModelAndView m = new ModelAndView();
m.addObject("test", t, '1');
mav.addObject("site", m);
I mean I have a index file witch I deal like a template and I want to parse it to other file (template)
My second question:
Is this good solution? If not, please tell me what is preffered:)
Sorry, I'm new to Java EE and Spring
edit: source code
ModelAndView is just a container used by Spring's MVC request handling. Every object you add to ModelAndView will be added as request attribute (request#setAttribute) and then available within your JSP.
Nesting ModelAndView does not make any sense. You can just forward the request from your JSP file and all the model attributes will be still set on the request and available.
Regarding your approach:
I would say that having template JSP (such as your index) can be used. I personally prefer having TAG file with layout and then JSP files being enclosed within this layout.
<%# tag language="java" description="Content border for layout decoration." trimDirectiveWhitespaces="true" %>
<!DOCTYPE html>
<html lang="cs">
<head profile="http://www.w3.org/2005/10/profile">
<meta charset="utf-8" />
</head>
<body>
<div class="pageContent">
<jsp:doBody />
</div>
</body>
</html>
-
<%# include file="/WEB-INF/taglib.jspf"%>
<layout:admin>
THIS IS MY CONTENT
</layout:admin>
Alternatively you can use templating engine such as Apache Tiles.
How would I implement AJAX validation in struts2 which lets you know if a username is available onblur? This is what I've managed so far but the docs aren't clear:
JSP:
<%# page
language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib
prefix="s"
uri="/struts-tags"%>
<%# taglib
prefix="sj"
uri="/struts-jquery-tags"%>
<!DOCTYPE html>
<html>
<head>
<sj:head jqueryui="true" />
<!-- Don't forget these 2 files!! -->
<script
src="${pageContext.request.contextPath}/struts/utils.js"
type="text/javascript"></script>
<script
src="${pageContext.request.contextPath}/struts/css_xhtml/validation.js"
type="text/javascript"></script>
<script
type="text/javascript"
src="js/register.js"></script>
<title>Register</title>
</head>
<s:url
action="loginLink"
var="loginHREF" />
<s:url
action="forgotPasswordLink"
var="forgotPasswordHREF" />
<s:url
action="Register"
var="registerHREF" />
<body>
<s:form
theme="css_xhtml"
action="Register"
onsubmit="return myValidate()">
<s:textfield
name="user.username"
label="Username"
id="uname"
required="true"
pattern="[a-zA-Z0-9_-]{5,12}"
title="5-12 Alphanumeric characters required" />
<s:textfield
name="user.email"
label="Email"
required="true" />
<s:password
id="pass1"
name="user.password"
label="Password"
required="true"
pattern="{5,12}"
title="5-12 characters" />
<s:password
id="pass2"
label="Confirm Password"
required="true"
pattern="{5,12}" />
<s:textfield
name="user.firstName"
label="First Name"
required="true" />
<s:textfield
name="user.lastName"
label="Last Name" />
<sj:datepicker
yearRange='-90:-3'
changeYear="true"
name="user.birthDate"
readonly="true"
label="Date of Birth" />
<s:submit value="Register" />
</s:form>
<s:a href="%{loginHREF}">Login</s:a>
<s:a href="%{forgotPasswordHREF}">Forgot Password</s:a>
<script>
$("#uname").blur(function() {
var fieldData = $("#uname").serialize();
fieldData = fieldData.slice(5);
//do the POST thingies
$.ajax({
type : "POST",
url : "ValidateUsername",
cache : false,
data : fieldData,
dataType : "json",
complete : function(request) {
alert("In complete");
var form = $('form');
//clear previous validation errors, if any
//StrutsUtils.clearValidationErrors(form);
//get errors from response
var text = request.responseText;
alert(text);
var errorsObject = StrutsUtils.getValidationErrors(text);
//show errors, if any
if (errorsObject.fieldErrors) {
StrutsUtils.showValidationErrors(form, errorsObject);
}
}
});
return false;
});
</script>
</body>
</html>
Action:
#Action("ValidateUsername")
#Results(value = { #Result(name = "success", type = "json"), #Result(name = "input", type = "json") })
#ParentPackage("default")
#InterceptorRef("jsonValidationWorkflowStack")
public class ValidateUsername extends ActionSupport {
private String username;
#Override
public String execute() {
return SUCCESS;
}
#Override
public void validate() {
UserService service = new UserService();
User isTaken = service.findByUsername(username);
service.close();
if (isTaken != null)
addFieldError("user.username", "That username is taken");
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
The docs make it seem like struts2 will handle it for you if you simply add the json interceptor and set validate="true" in the sx:submit tag.
In register.js I check to see that password and confirmation password match.
Basically I would like it to validate even before submit is pressed. Right now On submit it validates it like any other normal form.
Edit: Also, is there a working method other than using dojo? It seems to block all my client side validation including the required attributes, js, etc.
Edit2:I ditched the dojo plugin, learnt some js and managed to put together what i have now. Now the only thing left is to display an error. Alerting the response text shows up a json string with only a username key value pair in it. Should i add another member to the action and process it to display an error message? because the StrutsUtils js is not working. addFieldError("user.username", "That username is taken"); does not modify the json result.
Basically, how can i add fielderrors to my json response?
Edit: I got my action to add my field errors to the json response by modifying the annotations as follows:
#Action("ValidateUsername")
#Results(value = {
#Result(name = "success", type = "json"),
#Result(name = "input", type = "json", params = { "ignoreHierarchy",
"false", "includeProperties",
"actionErrors.*,actionMessages.*,fieldErrors.*" }) })
#ParentPackage("default")
#InterceptorRef("jsonValidationWorkflowStack")
Now the only problem is in:
//clear previous validation errors, if any
**//StrutsUtils.clearValidationErrors(form);**
//get errors from response
var text = request.responseText;
alert(text);
**var errorsObject = StrutsUtils.getValidationErrors(text);**
//show errors, if any
if (errorsObject.fieldErrors) {
StrutsUtils.showValidationErrors(form, errorsObject);
}
None of the StrutsUtils functions are working. When i uncomment clearValidationErrors it does nothing and breaks the rest of the js code. errorsObject is empty and showValidation does nothing even though on printing my jon response i can see a field error with a message. How do i get StrutsUtils to work?
Also, is there a better way to implement my use case? I haven never learnt jquery/ajax and this is my first struts2 application.
Struts is available server-side. You are trying to call
var errorsObject = StrutsUtils.getValidationErrors(text); in the client-side.
StrutsUtils is a class and is not available on client-side/javascript.
There are various ways through which you can send errors.
Please refer my answer in the below link, on how to handle ajax request & response when using struts2.
How to get Ajax response in Struts2
I use JSP (Spring MVC) for showing information to remote user. I have some problems with caching of page. It looks like this:
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>My Title</title>
</head>
<body>
<jsp:include page="menu.jsp" flush="true" />
<form method="post">
Write here
<input type="text" name="inputTxt" value="${txt}" />
<input type="submit" value="OK" />
</form>
<table border="1">
...
</table>
</body>
</html>
Page should show a table of items. When user press OK button, server add information to the database and add a row to the table. All works fine. But tables shows an information depends on the logged user. So, when I login for the first time, my app works great (shows me the data, corresponding to the current user). But when I logout from current user and login from new, this page still show data for firs user. If I press F5, table update it's data and shows correct information, which corresponds to the current user. I think problems with caching.
How to avoid this problem? Any ideas?
The page is indeed likely cached by the browser. You can verify this in Firefox with Firebug. Generally, you would like to disable client side caching of dynamic content. You can achieve this by creating a Filter which is mapped on an url-pattern of *.jsp and does basically the following job in the doFilter() method.
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1
httpResponse.setHeader("Pragma", "no-cache"); // HTTP 1.0
httpResponse.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(request, response);
Those response headers will instruct the client (webbrowser) to not cache the response. Don't forget to clean the browser cache before testing.
In Spring MVC, you can create an interceptor like so:
public class DisableBrowserCachingInterceptor extends HandlerInterceptorAdapter {
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1
response.setHeader("Pragma", "no-cache"); // HTTP 1.0
response.setDateHeader("Expires", 0); // Proxies
}
}