How to get JSP Application Context inside a java class - java

I'm not very familiar with JSP, so, let's make this question an example:
suppose I have a JSP file (index.jsp) which contain those statement:
<%
MyObject mO = new MyObject();
mO.sayHelloWorld();
%>
and in the MyObject.java:
public class MyObject(){
public void sayHelloWorld(){
//something like getJSPApplicationContext.getOut.println("<p>Hello World</p>");
}
}
is there a simple way to reach this goal (without passing the JSPApplicationContext to my class?)
Maybe I'm doing something really wrong, anyway, thanks for yout help :)

Let me use this opportunity to introduce you to the V (View) in MVC (Model View Controller).
You should generally put data into the view by putting a view bean into the session on your controller. You can think of your class MyObject as a view bean as it contains information you want to display in the view. The controller in this case is your servlet (you do have a servlet, right?) and would contain the following in its doGet or doPost method;
MyObject myObject = new MyObject("Hello world");
request.setAttribute("myObject", myObject);
The next step is to have your JSP display the data from the view bean. You are strongly encouraged to use JSTL for this, rather than by putting code snippets in. The JSTL tag <c:out> can be used for displaying data in a JSP. Your JSP might contain the following;
<p>
<c:out value="${myObject.message}"/>
</p>
This will call the getMessage() method on the session object 'myObject' and output it on the page.
Just for completeness, your MyObject view bean might look like this;
public class MyObject
{
String message;
public MyObject(String message)
{
this.message = message;
}
public String getMessage()
{
return message;
}
}

This isn't how it is used.
For the purpose you have demonstrated.
You should include a Servlet or jsp or static HTML just to print Hello World like
<jsp:include page="/staticfile/helloworld.html" />
in helloworld.html
just
hello world
or include servlet
<jsp:include page="/helloworldServlet" />
and in HelloWorld Servlet doGet()
out.println("hello world");
Also See
how-to-avoid-java-code-in-jsp-files
about jsp

Without passing the context to the class method, and without storing it in a ThreadLocal variable (which I think would be a bad idea), I don't see how you could do that.
If your class needs access to the JSP context it probably means that the class should be a JSP fragment or a custom JSP tag (<custom:sayHello/>).

Related

How can I include(load) more than one jsp files in spring mvc controller class?

How can I include(load) more than one jsp files in spring mvc conroller class?
eg:
#RequestMapping("/")
public void welcome() {
include("file1.jsp");
include("file2.jsp");
include("file3.jsp");
}
At framework level, No you cannot do it. However, there is a hack you could try.
Create an array of name of pages you need to merge. Send it as a parameter to a dummy empty page.
The dummy page does this:
<c:forEach var="page" items="${pages}">
<c:import url="${page}"></c:import>
</c:forEach>
This will iterate all the JSP files that you wish to show as a single view.
Hope this helps. Let me know if any further help is required.

Java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'loginBean' available as request attribute [duplicate]

This is meant to be an extensive canonical question & answer post for these types of questions.
I'm trying to write a Spring MVC web application where users can add movie names to an in-memory collection. It's configured like so
public class Application extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {};
}
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { SpringServletConfig.class };
}
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
and
#Configuration
#ComponentScan("com.example")
public class SpringServletConfig extends WebMvcConfigurationSupport {
#Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
}
There's a single #Controller class in the com.example package
#Controller
public class MovieController {
private final CopyOnWriteArrayList<Movie> movies = new CopyOnWriteArrayList<>();
#RequestMapping(path = "/movies", method = RequestMethod.GET)
public String homePage(Model model) {
model.addAttribute("movies", movies);
return "index";
}
#RequestMapping(path = "/movies", method = RequestMethod.POST)
public String upload(#ModelAttribute("movie") Movie movie, BindingResult errors) {
if (!errors.hasErrors()) {
movies.add(movie);
}
return "redirect:/movies";
}
public static class Movie {
private String filmName;
public String getFilmName() {
return filmName;
}
public void setFilmName(String filmName) {
this.filmName = filmName;
}
}
}
WEB-INF/jsps/index.jsp contains
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Movies</title>
</head>
<body>
Current Movies:
<c:forEach items="${movies}" var="movieItem">
<ul>
<li>${movieItem.filmName}</li>
</ul>
</c:forEach>
<form:form>
<div>Movie name:</div>
<form:input path="filmName" type="text" id="name" />
<input type="submit" value="Upload">
</form:form>
</body>
</html>
The application is configured with context path /Example. When I send a GET request to
http://localhost:8080/Example/movies
the request fails, Spring MVC responds with a 500 status code, and reports the following exception and stack trace
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:154)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:117)
org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:422)
org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
org.apache.jsp.WEB_002dINF.jsps.index_jsp._jspx_meth_form_005finput_005f0(index_jsp.java:267)
org.apache.jsp.WEB_002dINF.jsps.index_jsp._jspx_meth_form_005fform_005f0(index_jsp.java:227)
org.apache.jsp.WEB_002dINF.jsps.index_jsp._jspService(index_jsp.java:142)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1257)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
I expected the JSP to generate an HTML <form> with a single text input, for a Movie name, and a submit button, that I can use to send a POST request with a new Movie. Why does the JSP servlet instead fail to render Spring's <form:form> tag?
You're trying to use Spring MVC's form tag.
This tag renders an HTML form tag and exposes a binding path to
inner tags for binding. It puts the command object in the PageContext
so that the command object can be accessed by inner tags. [..]
Let’s assume we have a domain object called User. It is a JavaBean
with properties such as firstName and lastName. We will use it as the
form backing object of our form controller which returns form.jsp.
In other words, Spring MVC will extract a command object and use its type as a blueprint for binding path expressions for form's inner tags, like input or checkbox, to render an HTML form element.
This command object is also called a model attribute and its name is specified in the form tag's modelAttribute or commandName attributes. You've omitted it in your JSP
<form:form>
You could've specified a name explicitly. Both of these are equivalent.
<form:form modelAttribute="some-example-name">
<form:form commandName="some-example-name">
NOTE: Spring 5 has removed the commandName attribute, see the upgrade notes, here.
The default attribute name is command (what you see in error message). A model attribute is an object, typically a POJO or collection of POJOs, that your application supplies to the Spring MVC stack and which the Spring MVC stack exposes to your view (ie. the M to the V in MVC).
Spring MVC collects all model attributes in a ModelMap (they all have names) and, in the case of JSPs, transfers them to the HttpServletRequest attributes, where JSP tags and EL expressions have access to them.
In your example, your #Controller handler method which handles a GET to the path /movies adds a single model attribute
model.addAttribute("movies", movies); // not named 'command'
and then forwards to the index.jsp. This JSP then tries to render
<form:form>
...
<form:input path="name" type="text" id="name" />
...
</form:form>
While rendering this, FormTag (in reality, the InputTag) tries to find a model attribute named command (the default attribute name) so that it can produce an HTML <input> element with a name attribute constructed from the path expression and the corresponding property value, ie. the result of Movie#getFilmName().
Since it cannot find it, it throws the exception you see
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
The JSP engine catches it and responds with a 500 status code. If you want to take advantage of a Movie POJO to simply construct your form correctly, you can add a model attribute explicitly with
model.addAttribute("movie", new Movie());
or have Spring MVC create and add one for you (must have an accessible parameterless constructor)
#RequestMapping(path = "/movies", method = RequestMethod.GET)
public String homePage(#ModelAttribute("command") Movie movie, Model model) {...}
Alternatively, include a #ModelAttribute annotated method in your #Controller class
#ModelAttribute("command")
public Movie defaultInstance() {
Movie movie = new Movie();
movie.setFilmName("Rocky II");
return movie;
}
Note that Spring MVC will call this method and implicitly add the object returned to its model attributes for each request handled by the enclosing #Controller.
You may have guessed from this description that Spring's form tag is more suited for rendering an HTML <form> from an existing object, with actual values. If you want to simply create a blank <form>, it may be more appropriate to construct it yourself and not rely on any model attributes.
<form method="post" action="${pageContext.request.contextPath}/movies">
<input name="filmName" type="text" />
<input type="submit" value="Upload" />
</form>
On the receiving side, your POST handler method, will still be able to extract the filmName input value and use it to initialize a Movie object.
Common Errors
As we've seen, FormTag looks for a model attribute named command by default or with the name specified in either modelAttribute or commandName. Make sure you're using the right name.
ModelMap has a addAttribute(Object) method which adds
the supplied attribute to this Map using a generated name.
where the general convention is to
return the uncapitalized short name of the [attribute's] Class, according to
JavaBeans property naming rules: So, com.myapp.Product becomes
product; com.myapp.MyProduct becomes myProduct; com.myapp.UKProduct
becomes UKProduct
If you're using this (or a similar) method or if you're using one of the #RequestMapping supported return types that represents a model attribute, make sure the generated name is what you expect.
Another common error is to bypass your #Controller method altogether. A typical Spring MVC application follows this pattern:
Send HTTP GET request
DispatcherServlet selects #RequestMapping method to handle request
Handler method generates some model attributes and returns view name
DispatcherServlet adds model attributes to HttpServletRequest and forwards request to JSP corresponding to view name
JSP renders response
If, by some misconfiguration, you skip the #RequestMapping method altogether, the attributes will not have been added. This can happen
if your HTTP request URI accesses your JSP resources directly, eg. because they are accessible, ie. outside WEB-INF, or
if the welcome-list of your web.xml contains your JSP resource, the Servlet container will render it directly, bypassing the Spring MVC stack entirely
One way or another, you want your #Controller to be invoked so that the model attributes are added appropriately.
What does BindingResult have to do with this?
A BindingResult is a container for initialization or validation of model attributes. The Spring MVC documentation states
The Errors or BindingResult parameters have to follow the model object
that is being bound immediately as the method signature might have
more than one model object and Spring will create a separate
BindingResult instance for each of them [...]
In other words, if you want to use BindingResult, it has to follow the corresponding model attribute parameter in a #RequestMapping method
#RequestMapping(path = "/movies", method = RequestMethod.POST)
public String upload(#ModelAttribute("movie") Movie movie, BindingResult errors) {
BindingResult objects are also considered model attributes. Spring MVC uses a simple naming convention to manage them, making it easy to find a corresponding regular model attribute. Since the BindingResult contains more data about the model attribute (eg. validation errors), the FormTag attempts to bind to it first. However, since they go hand in hand, it's unlikely one will exist without the other.
I tried to migrate my application to Spring5 and noticed the same issue. It was caused by the moment that the 'commandName' attribute is not supported anymore and I had to use 'modelAttribute' instead.
To make things simple with the form tag just add a "commandName" which is a horrible name for what it is actually looking for...it wants the object you named in the MdelAttribute annotation. So in this case commandName="movie".
That'll save you reading long winded explanations friend.
I had this error on a screen with multiple forms that do a search. Each form posts to its own controller method with results shown on same screen.
Problem: I missed adding the other two forms as model attributes in each controller method causing that error when screen renders with results.
Form1 -> bound to Bean1 (bean1) -> Posting to /action1
Form2 -> bound to Bean2 (bean2) -> Posting to /action2
Form3 -> bound to Bean3 (bean2) -> Posting to /action3
#PostMapping
public String blah(#ModelAttribute("bean1") Bean1 bean, Model model){
// do something with bean object
// do not miss adding other 2 beans as model attributes like below.
model.addAttribute("bean2", new Bean2());
model.addAttribute("bean3", new Bean3());
return "screen";
}
#PostMapping
public String blahBlah(#ModelAttribute("bean2") Bean2 bean, Model model){
// do something with bean object
// do not miss adding other 2 beans as model attributes like below.
model.addAttribute("bean1", new Bean1());
model.addAttribute("bean3", new Bean3());
return "screen";
}
#PostMapping
public String blahBlahBlah(#ModelAttribute("bean3") Bean3 bean, Model model){
// do something with bean object
// do not miss adding other 2 beans as model attributes like below.
model.addAttribute("bean1", new Bean1());
model.addAttribute("bean2", new Bean2());
return "screen";
}
In my case, it worked by adding modelAttribute="movie" to the form tag, and prepending the model name to the attribute, something like <form:input path="filmName" type="text" id="movie.name" />
Updating from Spring version 3 to Spring version 5, produces the same error. All answers were satisfied already in my code. Adding the annotation #ControllerAdvice solved the problem for me.
If your Model object is correctly being passed to the GET API call but still have this error, you may look at the html or jsp page also to check whether correct variables names are provided and tags are used correctly. In my case, I forgot to include the objects under the closing <form> tag.

Is it possible to leverage an ArrayList as a session scoped component - ModelAttribute - rather than creating a pojo?

Is it possible to leverage an ArrayList or HashMap as a "session scoped component" (i.e., ModelAttribute object) - rather than creating a pojo?
If possible, I'd like to create a session scoped modelattribute like - e.g., "ArrayList<MyPojo>" or "HashMap<String, MyPojo>" - to share among different controllers.
But, the only examples of modelattribute components I've seen are POJO classes annotated with "#component" and "#Scope(value="session")...etc.
Thanks for any guidance on this.
sd
You can use a ModelMap as the command bean and set the ModelMap as a session attribute.
#SessionAttributes("testform")
public class testController{
public ModelAndView testmethod(#ModelAttribute("testform") ModelMap testMap,HttpServletRequest request){
/*
Access form variable using ModelMap.
*/
}
}
** Edit to Send ArrayList **
I am not sure if you can do HashMap, but you can definitely do Array of MyPojo i.e MyPojo[]. Please find the JSP and controller below where I have added an hidden type input html element.Code below assumes that your MyPojo class has a member named selected. Hope this helps.
<%#taglib uri="/spring.tld" prefix="spring"%>
<spring:bind path="MyPojo[${statusInd.index}].selected">
input type="hidden"
name='<c:out value="${status.expression}"/>'
id='<c:out value="${status.expression}" />'
value='<c:out value="${status.value}" />' />
</spring:bind>
#SessionAttributes("testform")
public class testController{
public ModelAndView testmethod(#ModelAttribute("testform") MyPojo[] testMyPojo,HttpServletRequest request){
/*
Access form variable using ModelMap.
*/
}
}
P:S :- You need to tell your JSP that testform is the name of the command Bean for this to work.

how to pass values in JSP <form> into a java method

I have a a JSP file in this format(two select tags)-
<%# page import="mypackage.*" %>
<all the main tags>...
<form>
<select> options... </select>
<select> options... </select>
<input type="submit" value="submit" />
</form>
<textarea></textarea>
There is a java method inside "mypackage" which should take arguments from the <select> tags after clicking on submit.
The method returns a string which I want to output in the <textarea>.
How do I go about this ?
Thanks a lot guys.
Send it as HTTP POST or HTTP GET to a servlet, and receive it via doGet() or doPost() methods. You can access it via HttpServletRequest.getParameter().
void doPost(HttpServletRequest request, HttpServletResponse response)
I see that you are importing the mypackage.* classes into your JSP. Indeed, you could include Java code inside your JSP and call the class directly. Something like:
<%
MyClass c = new MyClass();
String result = c.doSomething(request.getParameter("select"));
out.println("<textarea>" + result + "</textarea>");
%>
should be sufficient (but not good: the result should be escaped).
However, this code is not very maintainable and it can be done better (the answer of kaustav datta is one standard way of doing it).
It can be done in a more elegant way using the Spring framework's MVC part: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html
It needs some configuration at the beginning and takes some time to understand, but when you got it, it is very nice.
In your case, a controller of the following form would be sufficient:
#Controller
public class SelectController {
private final class MyClass c = new MyClass();
#RequestMapping(value="/select", method = RequestMethod.POST)
public String doSelect(#RequestParam("selection") final String selection, final ModelMap model) {
final String result = c.doSomething(selection);
modelMap.addAttribute("result", result);
return "yourJsp";
}
}
request.getParameterValues("select")
here getParameterValues is a method of the request interface which returns a string in argument of this method pass name of your controller
when you get value from text box use the method request.getParameter("name");

How do set request parameter value while calling java method?

I need to call a method of java class from jsp page.. While calling that in jsp page, need to set some request parameters also. How do i do that in jsp page?
Ex :
Java class :
public void execute() {
string msg = request.getParameter("text");
}
JSP file :
I need to call the method here and also need to set parameter values (eg : &text=hello)
Please help me...
Just embed your Java code inside the JSP. The object "request" is available to get parameters (parameters can't be set). Unless you plan to forward to another JSP in another context with an attribute should be enough.
To refer to your own class do not forget to add the import statement at the beginning of the JSP (similiar to an import in a Java class).
<!-- JSP starts here -->
<%#page import="test.MyClass" %>
<%
MyClass myClass = new MyClass();
String text=myClass.execute();
// This is not neccessary for this JSP since text variable is already available locally.
// Use it to forward to another page.
request.setAttribute("text");
%>
<p>
This is the <%=text%>
</p>
You cannot set request parameters. I suggest you try using the attributes as suggested in the previous answers.
You can't set request parameters - they're meant to have come from the client.
If you need to give the method some information, you should either use normal method parameters, or some other state. The request parameters are not appropriate for this, IMO.

Categories

Resources