How to configure custom servlet in magnolia CMS - magnolia

I am trying to do registration example in magnolia. I have a registration form, on submission of form control should be transferred to my own written servlet.
snippet for form :
<body>
<form action="./register" method="post">
Name:<input type="text" name="name"><br />
Email Id:<input type="text" name="email"><br/>
<input type="submit" value="Register">
</form>
</body>
Registration servlet class:
public class Registration extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("This is registration servlet");
}
}
I have configured module descriptor :
<servlets>
<servlet>
<name>RegistrationServlet</name>
<class>com.rbt.registration.Registration</class>
<comment>registration servlet</comment>
<mappings>
<mapping>/register</mapping>
</mappings>
</servlet>
</servlets>
and I have also configured template definition.
But when I click on submit button. It shows error that resource not found.
Please help me.

In your template, when writing html for the form you can also use action="${ctx.contextPath}/register" to have form response directed to uri on which servlet is listening.
Also please go to config:/server/filters/servlets/ and verify that RegistrationServlet is correctly add there.
Same problem (although for different servlet) was also discussed at Magnolia Forum
HTH, Jan

The mapping you configured in the module descriptor will be relative to your context path. E.g. if your base url is http://example.com:8080/public ('public' being your context path), then your servlet will responding to http://example.com:8080/public/register.
Check if that url matches the url your form is submitting to. The action="./register" is a relative path and will depend on the path of the page that contains the form.

Related

How to create shared form in ASP.NET CORE Razor Pages?

I have to create a reusable form in my page header. It should be displayed on each page. Simple input and submit button that will send a POST request.
Options that I'm aware of are partial views or view components.
I checked a documentation about view components but there is no mention that it works with forms. Only InvokeAsync method is available to initialize a view.
With partial view, it may be hard to define its page model and I don't understand where to put its POST handler.
One other option I see, somehow to place a form directly on _Layout.cshtml, but, again, it doesn't have its page model (afaik),
So what is a way to create a shared form, and where POST request should be handled?
You should use a view component, as this allows you to have a somewhat self-contained model and view interaction.
public class SharedFormViewComponent : ViewComponent
{
public Task<IViewComponentResult> InvokeAsync() =>
Task.FromResult(View(new SharedFormViewModel()));
}
Then, put your form HTML code in Views\Shared\Components\SharedForm\Default.cshtml. For your form's action, you'll need to specify a route. More on that in a sec. Then, to display your form:
#await Component.InvokeAsync("SharedForm")
Now, as you've somewhat discerned, view components can't be posted to. It's not an issue of "not supporting forms"; they're literally not part of the request pipeline, and therefore can't respond to requests such as a POST. You'll need a distinct action that will handle the POST on some controller. On your component's form tag, then:
<form asp-action="SharedFormHandlerAction" asp-controller="Foo" asp-area="" method="post">
The asp-area attribute should be provided just in case this is used in the context of different areas.
You'll also need a "return URL". This will be the URL of the current page, so that after the user successfully posts the form, they'll go back to the page they submitted it from. You can achieve that by adding a hidden input to your form:
<input type="hidden" name="returnUrl" value="#(Context.Request.Query["returnUrl"].FirstOrDefault() ?? (Context.Request.Path + Context.Request.QueryString))" />
Your handler action should then take a param like string returnUrl = null, and on success you should do:
return !string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)
? Redirect(returnUrl)
: RedirectToAction("SomeDefaultAction");
Where things get a little tricky is in handling validation errors. Since you're posting to a different action, you can't return the previous view the user was on to show the validation errors within the from in the layout or whatever. Instead, you'll want a view specific to this handler action which will simply be your shared form. You can use the view for your view component here as a partial:
<partial name="~\Views\Shared\Components\SharedForm\Default.cshtml" />
If you want to use a PageModel, you could do so in a BasePageModel class that inherits from PageModel and that all your pages inherit from. You can use a named handler (https://www.learnrazorpages.com/razor-pages/handler-methods#named-handler-methods) in the BasePageModel class to process the form submission. Add the form directly to the Layout, which will need an #model directive for your BasePageModel type.
public class BasePageModel : PageModel
{
[BindProperty]
public string SearchString { get; set; }
public void OnPostBaseSearch()
{
// process the search
}
}

display image from database on page load in servlet

I would like to show an image when the page loads in a servlet. Considering that this page is an html page, I don't really understand how the image to be displayed can be mentioned programatically(say, for example database.
Had it been a servlet, I would have just done something like the following which shows an image once the button is clicked. But how do I do the same for an html?
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("<HTML>");
out.print("<HEAD><TITLE>Upload Image</TITLE></HEAD>");
out.print("<BODY>");
out.print("<img src='images/imagethree.jpg' alt='image' />");
out.print("<img src='images/imageone.jpg' alt='image' />");
out.print("<input type=\"submit\" value=\"select\">");
out.print("</BODY>");
out.print("</HTML>");
out.close();
}
i am not sure but you can retrieve image from database at the time of init() or by using some super calling statements in doget() method like(super or this()) and after that you can assign the image.
Assume that your folder structure is something like this:
|_ Web Contents
|_ images
| |_ a.png
|_ WEB-INF
And your Context Path is SampleWebApp. following image tag will show the picture:
<img src="/SampleWebApp/images/a.png">

Display message from Servlet to JSF page

I'm trying to display success message in xhtml page from servlet but no luck, here's my code
In servlet i have
FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
FacesContext facesContext = contextFactory.getFacesContext(request.getSession().getServletContext(), request, response, lifecycle);
facesContext.addMessage( "user:displaymessagesave", new FacesMessage("user saved successfully" ));
In xhtml page inside form i have written tag for display message form id=user
<h:message class="success" for="displaymessagesave" id="displaymessagesave" />
Saving to database is happening but its not displaying any message, please suggest where i'm going wrong.
It is not possible to access FacesContext from a servlet other than FacesServlet.
Recently I faced that same problem, and what I did was, on my servlet, put the messages in the Session:
List<String> msgs=(List<String>)request.getSession().getAttribute(KEY);
if (msgs==null)
{
msgs=new ArrayList<String>();
}
msgs.add("My new message");
request.getSession().setAttribute(KEY, msgs);
Then, on the xhtml view, I added a call to put these messages on FacesContext, and a growl element:
<h:outputText value="#{managed.prepareMessages()}"/>
<p:growl id="growl" showDetail="false" life="4000" />
Finally, the prepareMessages method takes them from session and add the messages to FacesContext:
public String prepareMessages()
{
List<String> msgs = (List<String>)FacesContext.getCurrentInstance()
.getExternalContext().getSessionMap().get(KEY);
if (msgs!=null)
{
for(String msg:msgs)
{
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(msg));
}
FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().remove(KEY);
}
return "";
}
It may not be an elegant solution, but is the only one I found...
Don't give the same id for message as the "for" component. If you just want a messageholder without attaching it to a valueholder than you should use the tag.
<h:messages class="success" id="displaymessagesave" />

Spring request parameter unique within call

Massive EDIT
Let's say I have two differents controllers. One that renders the View and one that renders the <jsp:include> tags.
The ViewController :
#Controller
public class ViewController {
#Resource
private VehicleCatalogAPIService vehicleCatalogAPIService;
#RequestMapping("/en/new/{organizationUnitId}")
public String view(ModelMap modelMap, Locale locale,
#PathVariable Integer organizationUnitId,) {
Vehicles vehicles = vehicleCatalogAPIService.getVehicule(organizationUnitId);
modelMap.put("vehicles", vehicles);
return "/catalog/" + view;
}
}
The IncludeController:
#Controller
public class IncludeController{
#Resource
VehicleCatalogAPIService vehicleCatalogAPIService;
#RequestMapping(value = "/fragment/test", produces = "text/html")
public String test(ModelMap modelMap,
#RequestParam("view") String view,
#RequestParam("test") String test,
#RequestParam("vehicleId") String vehicleId,
Locale locale) {
Vehicle particularVehicle = vehicleCatalogAPIService.get(vehicleId);
modelMap.put("vehicle", vehicle);
return "/catalog/vehicle/fragments/" + view;
}
#RequestMapping(value = "/fragment/test2", produces = "text/html")
public String test(ModelMap modelMap,
#RequestParam("test") String test,
#RequestParam("view") String view,
Locale locale) {
return "/catalog/vehicle/fragments/" + view;
}
}
I hit the page in the browser : http://example.com/en/new
The ViewController is called and returns the the jsp page that has to be rendered, in this case /catalog/listing.jsp. The JSP looks like this :
<jsp:useBean id="vehicles" type="java.util.List<com.sm360.auto.webauto.webapplib.bean.display.VehicleDisplayBean>" scope="request"/>
<h1> LISTING JSP </h1>
<div>
<c:forEach items="${vehicles}" var="vehicle" begin="${k.index}" end="${k.index + k.step-1}">
<div class="c-item-out">
<content:sheet-new-vehicule vehicle="${vehicle}" isCompact="true" hasCompared="true" />
</div>
</c:forEach>
</div>
<jsp:include page="/fragment/test">
<jsp:param name="view" value="view1"/>
<jsp:param name="vehicle1" value="vehicle1"/>
<jsp:param name="test" value="test1"/>
</jsp:include>
That include now calls the IncludeController with 3 parameters : view, vehicleId and test. The proper method is invoked and the correct view is returned (view1).
The view1 contains another include :
<jsp:useBean id="vehicle" type="com.sm360.auto.webauto.webapplib.bean.display.VehicleDisplayBean" scope="request"/>
<h1> view 1 </h1>
<div>
<h2>${vehicle.name}
</div>
<jsp:include page="/fragment/test2">
<jsp:param name="view" value="view2"/>
<jsp:param name="test" value="test2"/>
</jsp:include>
In that second call, the view parameter will be "view2,view1" and the test parameter will be "test2, test1".
I would like that second include to have its own values of the parameters it passes to the controller, not a merge from the other call.
EDIT :
Following this diagram, when a <jsp:include> is met during the rendering of the view, does the process return to the Front Controller and re-Delegate the request to the Controller specified in the include tag with the same request with updated parameters?
Is it possible to have a new set of fresh parameters?
A long shot: could you just remove the view entry from the model before setting the next? I'm having a common Spring controller method in mind, please post your code for clarification.
#RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.remove("view");
model.addAttribute("view", "foobar");
return "helloWorld";
}

Spring MVC URL Path Change

I am new to web programming and Spring MVC 2.5.
I am not sure about my problem is spring sprecific or web specific in general.
I have a menu.jsp and I use jsp:include to include it in all my jsp.
<ul class="menu">
<c:url var="home" value="home.htm"/>
<c:url var="data" value="data.htm"/>
<li><span>HOME</span></li>
<li><span>DATA</span></li>
</ul>
When I hit my app the first time and calls http://localhost:8080/myapp/home.htm, everything went fine.
But when I click a link that brought me to a new url using multiactioncontroller.
#RequestMapping(value = "/epm/epmItemList.htm", method = RequestMethod.GET)
public String setupForm(Model model, HttpServletResponse response) throws IOException {
}
#RequestMapping(value = "/epm/epmdelete.htm", method = RequestMethod.GET)
public String setupForm(Model model, HttpServletResponse response) throws IOException {
}
And then I click, home again. I am getting a 404. I am not sure why, but when I check the link at my url it now it becomes:
http://localhost:8080/myapp/epm/home.htm
Spring is naturally saying no handler mapping can be found since I did not configure any mapping for these. How can I fix this problem? Thanks
Try the following change :
<ul class="menu">
<c:url var="home" value="/home.htm"/>
<c:url var="data" value="/data.htm"/>
<li><span>HOME</span></li>
<li><span>DATA</span></li>
</ul>
This way the links should be relative to your context and not relative to the local page.

Resources