Call Spring bean method in JSP - java

I have a java class
LayoutManager.java, which I pass as a Sprean Bean into my jsp page using
<custom:useSpringBean var="layoutManager" bean="LayoutManager"/>
How do I call methods from LayoutManager.java inside my jsp using the spring bean?
I feel like I would use some form of servlets <% %>, but not sure about the syntax
I want to call the method
public Iterable<Layouts> getSpecificLayout(String subjectName)
The only spring code I have right now is
public class UseSpringBean extends SimpleTagSupport
{
public void doTag() throws JspException, IOExceptionP
PageContext pageContext = (PageContext)getJspContext();
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(pageContext.getServletContext());
pageContext.setAttribute(var, springContext.getBean(bean), PageContxt.PAGE_SCOPE);
}

If you really want the list of Layouts to be used in the jsp page then from the spring controller you need to add this list in the ModelMap so that its visible in the jsp page.
Something like:
#RequestMapping(value="/getSpecificLayout", method = RequestMethod.GET)
public String getSpecificLayout(Stirng subjectName, ModelMap model){
Iterable<Layouts> layouts = getSpecificLayout(String subjectName);
model.addAttribute("layouts", layouts);
return "listLayouts";
}
in jsp:
<c:for items="listLayouts" var="layout">
<c:out value="layout.name"/>
</c:for>
(This is not a tested code just a sample. Sorry somehow the code editing is not working, I mean I am not able to see the inline editor).

Related

Spring #SessionAttributes shared between controllers?

I'm using Spring 4.3.7, and I got two form controllers with forms rendering using Spring form taglib in corresponding views. To preserve form data between requests (for rendering invalid forms) I store them in SessionAttributes.
LabCreateController:
#Controller
#RequestMapping(path = "/labs/create")
#SessionAttributes("form")
public class LabCreateController {
#ModelAttribute("form")
public LabCreateForm form() {
return new LabCreateForm();
}
#GetMapping
public String showForm() {
return "lab_create";
}
}
WallController:
#Controller
#RequestMapping(path = "/group/{id}/wall")
#SessionAttributes("form")
public class WallController {
#ModelAttribute("form")
public PostCreateForm form() {
return new PostCreateForm();
}
#GetMapping(path = "/new")
public String newPostGet() {
return "communities_newpost";
}
}
I open /labs/create in browser, everything is fine. Then I open /group/4/wall/new and get a following error:
Invalid property 'text' of bean class
[...LabCreateForm]
i.e it means that attribute form from LabCreateController somehow passed to WallController, though Spring documentation says:
Session attributes as indicated using this annotation correspond to a
specific handler's model attributes.
I believe it means they shouldn't be shared between controllers. Also this answer says that it is so since Spring 3.
Is it a bug or I'm missing something? If not, what is the appropriate way of storing a form inside one controller?

Why is my request hitting two controllers?

I have the following Spring controller:
#Controller
public class TypoWorkflowController {
#RequestMapping(value = "/workflow/typo-workflow/moreInfo", method = RequestMethod.GET)
public String serveMoreInfo(#RequestParam(value = "taskId", required=false) String taskId, ModelMap modelMap) {
return "typo-workflow-more-info";
}
}
My tiles-def file contains:
<definition name="typo-workflow-more-info" template="/WEB_INF/jsp/workflow/typo-workflow/moreInfo.jsp"/>
My JSP is plain old HTML.
When I hit the url /workflow/typo-workflow/moreInfo, Tomcat throws a StackOverflowError.
When I step through in debug mode, I see that I'm hitting my controller first, as I would expect, but then I hit another controller, at the method:
#Controller
#Order(value = Ordered.LOWEST_PRECEDENCE)
public class ContentServingController {
/* ... */
#RequestMapping({"/*", "/**/*"})
public ModelAndView serveContent(HttpServletResponse response, ModelMap model) {
/* ... */
}
}
As I poked around, it seeeeeeemed like we were in there to respond to a request for /WEB_INF/jsp/workflow/typo-workflow/moreInfo.jsp, but this doesn't happen for other controllers that operate in the same way (returning a View name).
So, can anyone provide me with some pointers for debugging this. Why would I be hitting a controller for a JSP anyway? Isn't a JSP supposed to be a little servlet itself?
Your tiles def is pointing to the WEB_INF folder when it should be pointing to the WEB-INF folder (dash instead of underscore) so spring doesn't know where to look within the app and is just making a normal http request, which is getting caught by the wildcard match.

How to ensure mandatory parameters are passed into a Spring MVC controller method?

Given a Spring-MVC controller method:
#RequestMapping(value = "/method")
public void method(#RequestParam int param1,
#RequestParam int param2) { /*...*/ }
If parameters are missing in the request URL, an error is reported, e.g:
JBWEB000068: message Required int parameter 'param1' is not present
I need to move the parameters into a single model class yet keep exactly the same GET request URL. So have modified method's parameter to MyModel model, which contains param1 and param2.
This works if #RequestParam is omitted but the snag is no error is reported if parameters are missing. If, on the other hand #RequestParam is included, a parameter named "model" is expected in the GET request. Is there a way to make model parameters mandatory yet keep the same request URL?
Use JSR-303 annotations to validate the object (and don't use primitives but the Object representations in that case).
public class MyObject {
#NotNull
private Integer param1;
#NotNull
private Integer param2;
// Getters / Setters
}
Controller method.
#RequestMapping(value = "/method")
public void method(#Valid MyObject obj) { /*...*/ }
If you don't have a JSR-303 provider (hibernate-validator for instance) on your classpath create a Validator and use this to validate your object.
Links.
Spring MVC reference guide
Spring Validation reference guide
You can try #ModelAttribute and method=RequestMethod.POST:
In your controller:
//...
#RequestMapping(value="/method", method=RequestMethod.POST)
public String add(#ModelAttribute("modelName") ModelClass form)
{
//.. your code
}
//..
In your JSP:
<%# taglib uri="http://www.springframework.org/tags/form" prefix="f" %>
//.. some code
<f:form action="method" method="post" modelAttribute="modelName">
</f:form>
If you are restricted to GET requests only, you might not be able to use a separate ModelClass. You need to resort to request parameters in that case.

Spring MVC session Attribute set intially

I have used the Spring MVC. I set the Session Attribute value like
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String initHome(Model model) {
if (!model.containsAttribute("clientObject")) {
model.addAttribute("clientObject", createDefaultClient());
}
return "homeMenu";
}
It is working fine if i click the home menu url(/home). but if i did not go the
home means it says error as 'session attribute clientObject is required'
so i decided to set sessionattibutes in constructor of controller
#Autowired
public MyController(Model model) {
if (!model.containsAttribute("clientObject")) {
model.addAttribute("clientObject", createDefaultClient());
}
}
it also says error
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myController'
I tried to set using the RequestMapping also like
#RequestMapping(value = "/", method = RequestMethod.GET)
public void initController(Model model) {
if (!model.containsAttribute("clientObject")) {
model.addAttribute("clientObject", createDefaultClient());
}
}
this method is also not called intially
my cointroller look like
#RequestMapping("/sample")
public class MyController {
..
..
is it possible to set the sessionAttribute value in the constructor of controller? or any other way to set the session Attribute initially?
Thanks in advance for your help.
Assuming your createDefaultClient is in the controller add a #ModelAttribute annotation to it.
#ModelAttribute("clientObject")
public ClientObject createDefaultClient() { ... }
This method will be called before any request handling method (as explained in the reference guide)
If you combine that with a #SessionAttribute annotation on your class (which you might already have). You should be able to achieve what you want.
In your request handling methods (methods annotated with #RequestMapping) you can now simply inject the client object as a method argument.
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String initHome(#ModelAttribute("clientObject") ClientObject clientObject) {
// Do something with the clientObject
return "homeMenu";
}
This will only work consistenly within the same controller, so if you need the ClientObject to be used somewhere else (another controller for instance), this isn't going to work (nor is #SessionAttributes designed for that).

Spring: Controller #RequestMapping to jsp

Using Spring 3.1.2
How do you reference the Annotated value of the CONTROLLER (not method) RequestMapping from a jsp so I can build URL's relative to the Controller. If the method level request mappings are referenced, it will cause my links to not work, so they cannot be part of the this in any way.
For example (Note that this controller's mapping is "/foo/test"):
#Controller
#RequestMapping("/foo/test")
public class FooController {
#RequestMapping(value="/this", method=RequestMethod.GET)
public String getThis() {
return "test/this";
}
#RequestMapping(value="/that", method=RequestMethod.GET)
public String getThat() {
return "test/that";
}
#RequestMapping(value="/other", method=RequestMethod.GET)
public String getOther() {
return "test/other";
}
}
...and from my this.jsp:
<%# taglib uri="http://www.springframework.org/tags" prefix="s"%>
<s:url value="${controllerRequestMapping}" var="baseUrl"/>
That
Other
The reason I need to access the RequestMapping is because my views may be accessed from multiple Controllers. Note that this controller's mapping is "/bar/test"!
#Controller
#RequestMapping("/bar/test")
public class BarController {
#RequestMapping(value="/this", method=RequestMethod.GET)
public String getThis() {
return "test/this";
}
#RequestMapping(value="/that", method=RequestMethod.GET)
public String getThat() {
return "test/that";
}
#RequestMapping(value="/other", method=RequestMethod.GET)
public String getOther() {
return "test/other";
}
}
Some of my Controller level request mappings have path variables too, so getting just the string value of the request mapping will not work. It will have to be resolved:
#Controller
#RequestMapping("/something/{anything}/test/")
public class SomethingController {
...
}
Update
Maybe if there was a way to modify the context path by appending the Controller request mapping to it BEFORE the Spring URL tag, that would solve the problem.
contextPath = contextPath/controllerRequestMapping
Then, I could do something like this because I believe Spring will automatically retrieve the current context path:
<%# taglib uri="http://www.springframework.org/tags" prefix="s"%>
That
Other
This, of course, would be optimal! Ideas? Thoughts...?
Thanks in advance!
You could get the URI using the Servlet API. There is no "Spring" way to do this as far as I know.
#RequestMapping(value="/this", method=RequestMethod.GET)
public String getThis(HttpServletRequest request, Model m) {
m.addAttribute("path", request.getRequestURI());
return "test/this";
}
Then in your JSP:
This
For more information about HttpServletRequest, see the API here.
There is no built-in way to access the #RequestMapping, but you can simply add the URL to the model and reference it from the view that way.
According to me there is no difference in putting #RequestMapping annotation at both class level and method level. Instead of that you can have the combined #RequestMapping annotation on top of the method only.
So now your method level annotation will be something like this.
#RequestMapping(value="("/foo/test/this", method=RequestMethod.GET)
or
#RequestMapping(value="("/bar/test/this", method=RequestMethod.GET)
Now since both your methods return the same view you can have just one method for both of them. And in the annotation mapping value instead of foo and bar you can inroduce one path variable {from}. So finally your annotation and the method will be like this.
#RequestMapping(value="("/{from}/test/this", method=RequestMethod.GET)
public String getThis(#PathVariable("from") String from) {
return "test/this";
}
And after doing this in your method you can perform different calculations or operations on based of the runtime value of path variable from you get. And in the JSP page you can simple get this value with ${from}.
Hope this helps you. Cheers.
See code below to access request mapping, if you are using Spring 3.1 and above. I'm not sure if this is what you require. This is just an attempt and of course i do not know of any straight forward way. Invoke getRequestMappings() from inside a method that has request mapping.
public class FooController{
private RequestMappingHandlerMapping handlerMapping = null;
#Autowired
public FooController(RequestMappingHandlerMapping handlerMapping){
this.handlerMapping = handlerMapping;
}
public Set<String> getRequestMappings(){
Map<RequestMappingInfo, HandlerMethod> handlerMap = handlerMapping.getHandlerMethods();
Iterator<RequestMappingInfo> itr = handlerMap.keySet().iterator();
while(itr.hasNext()){
RequestMappingInfo info = itr.next();
PatternsRequestCondition condition = info.getPatternsCondition();
Set<String> paths = condition.getPatterns();
HandlerMethod method = handlerMap.get(info);
if(method.getMethod().getName().equals(Thread.currentThread().getStackTrace()[2].getMethodName()))
return paths;
}
return new HashSet<String>();
}
}
As of 4.1 every #RequestMapping is assigned a default name based on the capital
letters of the class and the full method name. For example, the method getFoo
in class FooController is assigned the name "FC#getFoo". This naming strategy isenter code here
pluggable by implementing HandlerMethodMappingNamingStrategy and configuring it on your
RequestMappingHandlerMapping. Furthermore the #RequestMapping annotation includes a
name attribute that can be used to override the default strategy.
The Spring JSP tag library provides a function called mvcUrl that can be used to prepare links to
controller methods based on this mechanism.
For example given:
#RequestMapping("/people/{id}/addresses")
public class MyController {
#RequestMapping("/{country}")
public HttpEntity getAddress(#PathVariable String country) { ... }
}
The following JSP code can prepare a link:
<%# taglib uri="http://www.springframework.org/tags" prefix="s" %>
...
Get Address
Make sure you have configured your MVC using either Java Config or XML way and not both the ways.
You will get an exception as :more than one RequestMappingInfo HandlerMapping found.

Categories