Expand my Community achievements bar.

Dive into Adobe Summit 2024! Explore curated list of AEM sessions & labs, register, connect with experts, ask questions, engage, and share insights. Don't miss the excitement.
SOLVED

storing the form data into specific location in the repository.

Avatar

Former Community Member

Hi,

    I am creating a form to store the data from the client(client want a form to enter the data not in the page and components).and later we need to retrive the data from the repository and diplay dynamically.

    How to use form component to store the data in specific node structure which we need.is this possible? or i need to go with the nomal html form and then store the data where i want to store.Please guide me on this.

Thanks,

Ramya

1 Accepted Solution

Avatar

Correct answer by
Level 7

Hi, this is a  working example of of my solution here as some kind of guide. With the help of Scott's guide and this Im sure you will be on the right way:


In your JSP (or use the form component) do the equivalent of:
 

<form id="submitForm" method="post" action="/apps/my/servlets/path/create"> <input type="text" name="name" value="" /> <input type="text" name="email" value="" /> <input type="text" name="title" value="" /> <input type="text" name="phone" value="" /> <input type="submit" value="Submit"/> </form>

Here's just a mock form with some boring values to fill in...



Then in your servlet:

 

package com.test.servlet; import com.day.cq.commons.jcr.JcrUtil; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.sling.SlingServlet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.apache.sling.jcr.api.SlingRepository; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.servlet.ServletException; import java.io.IOException; import java.io.PrintWriter; @Component(immediate = true, metatype = true, name = "com.test.CreateServlet", label = "Create Servlet", description = "Test creation servlet") @SlingServlet(methods = { "POST" }, paths = "/apps/my/servlets/path/create", generateComponent = false) @Properties({ @Property(name = "service.description", value = "CreateServlet"), @Property(name = "service.vendor", value = "My Vendor") }) @SuppressWarnings({ "serial", "unused" }) public class CreateServlet extends SlingAllMethodsServlet{ private static final String CREATE_PATH = "/content"; /// Set the base path here private static final Logger log = LoggerFactory.getLogger(CreateServlet.class); @Reference private SlingRepository repository; @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { //We are not using this atm.. but you could } @Override protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { Session session = null; String name = request.getParameter("name"); String email = request.getParameter("email"); String title = request.getParameter("title"); String phone = request.getParameter("phone"); PrintWriter out = response.getWriter(); try { session = repository.loginAdministrative(null); Node firstProduct = JcrUtil.createPath(CREATE_PATH + "/" + name , "cq:Page", session); Node firstSubProduct = JcrUtil.createPath(firstProduct.getPath() + "/subproduct1", "nt:unstructured", session); Node secondSubProduct = JcrUtil.createPath(firstProduct.getPath() + "/subproduct2", "nt:unstructured", session); firstSubProduct.setProperty("email", email); firstSubProduct.setProperty("title", title); secondSubProduct.setProperty("email", email); secondSubProduct.setProperty("title", title); session.save(); out.println("That went well..."); out.flush(); out.close(); } catch (RepositoryException e) { out.println("That went not so well..."); out.flush(); out.close(); e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates. } } protected void activate(ComponentContext ctx) { log.trace("Activating my small creation servlet"); } protected void deactivate(ComponentContext ctx) { log.trace("Deactivating my small creation servlet"); } }

Here we just create a node (cq:Page) with the name that you entered in the form. It gets two nodes under neat with set values and then we add properties from the form
to these nodes. You can add more properties/values by only adding more fields and handle them and you can also skip subnodes if you want.
There are also a lot of other nice features in the JCRUtil that could help you.

In our case if we enter name = myName, email= myEmail, title=myTitle and phone = myPhone we will get the following structure

./content/myName (cq:Page)
../subproduct1 (nt:unstructured) -> with properties ( email:myEmail and title=myTitle)
../subproduct2 (nt:unstructured) -> with properties ( email:myEmail and title=myTitle)


Regards
/Johan

View solution in original post

11 Replies

Avatar

Level 7

Hi there Ramya.
It it possible to use the form component. If you read up on the documentation here http://dev.day.com/docs/en/cq/current/wcm/default_components/editmode.html#Form%20(component)

you will see that you can make use of the "Element Name" attribute (which will determine the location for that specific value) in the form together with the Store Data/Content Path to determine the location where to store the form data.

As you also pointed out it is possible to create you own post servlet to handle the form submission as well.
Some useful links on that topic:

Hope that will get you going

Regards
/Johan

Avatar

Former Community Member

Hi Johan,

Thanks for the replay.

i have to store the data in different nodes for each time form sumission with different data
Ex: under content/
                 Product1
                    subproduct1    
                    subproduct2
                    subproduct3
                Product2
                    subproduct1(related Product2)
                    subproduct2(related Product2)
                    subproduct3(related Product2)

 

In the link 

Thanks,

Ramya

Avatar

Level 7
Later here.... But yeah as storing the data inside crx is not a good idea though but if your requirements are more related to store and fectch and show thru crx then easiest way to trigger a workflow om submit of forms and read the payload data and store someherre in your crx repo node. The whole code can be written inside workflow process step and easily node Or resource apis can be used to create the node and store the properties.

Avatar

Level 7

Hi, this is a small example of how you could create a simple structure:
 

Node parentNode = resource.adaptTo(Node.class); Node firstProduct = JcrUtil.createPath(parentNode.getPath() + "/product1", "cq:Page", parentNode.getSession()); Node secondProduct = JcrUtil.createPath(parentNode.getPath() + "/product2", "cq:Page", parentNode.getSession()); Node firstSubProduct = JcrUtil.createPath(firstProduct.getPath() + "/subproduct1", "nt:unstructured", parentNode.getSession()); Node secondSubProduct = JcrUtil.createPath(firstProduct.getPath() + "/subproduct2", "nt:unstructured", parentNode.getSession()); Node thirdSubProduct = JcrUtil.createPath(secondProduct.getPath() + "/subproduct3", "nt:unstructured", parentNode.getSession()); Node fourthSubProduct = JcrUtil.createPath(secondProduct.getPath() + "/subproduct4", "nt:unstructured", parentNode.getSession()); firstSubProduct.setProperty("price", "100K"); secondSubProduct.setProperty("price", "200K"); thirdSubProduct.setProperty("price", "300K"); thirdSubProduct.setProperty("price", "400K"); parentNode.getSession().save();

 

Here we create 2 nodes (of type cq:Page). Each with 2 sub nodes as the sub products.
In this case there are of type nt:unstructured but you could have what you like there of course :)

Then we set some properties on these fur subproducts and finally we save it.
Hope it helps

/Johan

Avatar

Former Community Member

Hi Johan,   

    Thanks for help with coding example,

But I am facing a issue with simple form submit.

Below in jsp which has HTML form.

<form action="savenode.jsp" method="post">
<input type="text" name="Product1" >
<input type="text" name="title" size="30">
<div>
<input type="submit" value="Send" onclick>
</div>
</form>

And in savenode.jsp i am trying to create the node with name Product one.

<%@page import="java.util.Properties"%>
<%@include file="/libs/foundation/global.jsp"%>
<%@page import="java.util.Iterator"%>
<%@ page import="org.apache.jackrabbit.commons.JcrUtils"%>
<%@ page import="com.day.cq.commons.jcr.JcrUtil"%>


<%
Node parentNode = resource.adaptTo(Node.class);
Node firstProduct = JcrUtil.createPath(parentNode.getPath() + request.getParameter("Product1"), "nt:unstructured", parentNode.getSession());
firstProduct.setProperty("title", request.getParameter("title"));
parentNode.getSession().save();
%>

 

But on submit of form I am getting the error as

Error while processing /content/optum/savenode.jsp

                             
Status
500
Message
javax.jcr.nodetype.ConstraintViolationException: no matching property definition found for {}Product1
Locationinvalid link: /content/optum/savenode.jsp/content/optum/savenode.jsp
Parent Location/content/optum
Path
/content/optum/savenode.jsp
Refererhttp://localhost:4502/content/optum/pagehaswblink.html
ChangeLog
<pre></pre>

Go Back

invalid link: /content/optum/savenode.jspModified Resource

Parent of Modified Resource

 

I am rying to debug but not able to fix the issue,need help

Thanks,

Ramya

Avatar

Level 7

Hi. the code example that i was supplying was thought to be for a servlet/servlet filter that you would create yourself.
What needs to be done in that one is to change what that listen to. Either you can choose between a specific resourceType, a special selector
or even a path. Scott Macdonald has written a small guide of posting data to a search servlet here : http://scottsdigitalcommunity.blogspot.se/2013/06/posting-form-data-to-adobe-cq-using.html and even though that example only shows how to create a search servlet that listens to a specific path I'm quite sure that it will help you. Also this post will shed some more light on the topic https://blogs.adobe.com/aaa/2012/09/cq-tips-and-tricks-1-how-to-define-a-slingservlet-cq5-5-5-6.html

If you don't create your own servlet the thing that will happen is that the predefined POST handler will then intercept your post to "savenode.jsp". It will there try to add the property "Products1" on "savenode.jsp" which it's not allowed to do because of the constraint on property definitions. Once you have created you own servlet that handles a specific post e.g with your own selector or with an override on a specific resourceType you can use the code of your choice in that one and then be able to create your desired structure.

 

@SlingServlet(paths = "/path/to/resource", methods = "POST") public class MySafeMethodServlet extends SlingSafeMethodsServlet { //.. The logic here } or @SlingServlet(selectors = "MyCreationSelector", methods = "POST") public class MySafeMethodServlet extends SlingSafeMethodsServlet { //.. The logic here }


That will give you an idea to specify that servlet either on a specific path or for all posts that has the MyCreationSelector selector in it (like savenode.MyCreationSelector.jsp)
Good Luck
/Johan

Avatar

Level 10

You can also write an OSGi bundle that stores data submitted from a form to the JCR. See this walk through that teaches you how to do this task: http://scottsdigitalcommunity.blogspot.ca/2013/01/persisting-cq-data-in-java-content.html

Avatar

Former Community Member

Hi thank you

I have gone through http://scottsdigitalcommunity.blogspot.ca/2013/01/persisting-cq-data-in-java-content.htmlits very good example but i implemented half of the part i am in progress.

But In my case we have  many fields need to added like name,Description ,image upload, vedio upload etc.

and we need to pick up the name field from the from and creat a node and add other fields as a propery to that node.

on each time form submit happens i need to create a new node by picking the name field.

If i use cq from it is creating ite one unique ID under that its storing the data.

to customize that what i need to change this is first time i am dealing with CQforms.need help.

Thanks

Ramya

Avatar

Correct answer by
Level 7

Hi, this is a  working example of of my solution here as some kind of guide. With the help of Scott's guide and this Im sure you will be on the right way:


In your JSP (or use the form component) do the equivalent of:
 

<form id="submitForm" method="post" action="/apps/my/servlets/path/create"> <input type="text" name="name" value="" /> <input type="text" name="email" value="" /> <input type="text" name="title" value="" /> <input type="text" name="phone" value="" /> <input type="submit" value="Submit"/> </form>

Here's just a mock form with some boring values to fill in...



Then in your servlet:

 

package com.test.servlet; import com.day.cq.commons.jcr.JcrUtil; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.sling.SlingServlet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.apache.sling.jcr.api.SlingRepository; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.servlet.ServletException; import java.io.IOException; import java.io.PrintWriter; @Component(immediate = true, metatype = true, name = "com.test.CreateServlet", label = "Create Servlet", description = "Test creation servlet") @SlingServlet(methods = { "POST" }, paths = "/apps/my/servlets/path/create", generateComponent = false) @Properties({ @Property(name = "service.description", value = "CreateServlet"), @Property(name = "service.vendor", value = "My Vendor") }) @SuppressWarnings({ "serial", "unused" }) public class CreateServlet extends SlingAllMethodsServlet{ private static final String CREATE_PATH = "/content"; /// Set the base path here private static final Logger log = LoggerFactory.getLogger(CreateServlet.class); @Reference private SlingRepository repository; @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { //We are not using this atm.. but you could } @Override protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { Session session = null; String name = request.getParameter("name"); String email = request.getParameter("email"); String title = request.getParameter("title"); String phone = request.getParameter("phone"); PrintWriter out = response.getWriter(); try { session = repository.loginAdministrative(null); Node firstProduct = JcrUtil.createPath(CREATE_PATH + "/" + name , "cq:Page", session); Node firstSubProduct = JcrUtil.createPath(firstProduct.getPath() + "/subproduct1", "nt:unstructured", session); Node secondSubProduct = JcrUtil.createPath(firstProduct.getPath() + "/subproduct2", "nt:unstructured", session); firstSubProduct.setProperty("email", email); firstSubProduct.setProperty("title", title); secondSubProduct.setProperty("email", email); secondSubProduct.setProperty("title", title); session.save(); out.println("That went well..."); out.flush(); out.close(); } catch (RepositoryException e) { out.println("That went not so well..."); out.flush(); out.close(); e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates. } } protected void activate(ComponentContext ctx) { log.trace("Activating my small creation servlet"); } protected void deactivate(ComponentContext ctx) { log.trace("Deactivating my small creation servlet"); } }

Here we just create a node (cq:Page) with the name that you entered in the form. It gets two nodes under neat with set values and then we add properties from the form
to these nodes. You can add more properties/values by only adding more fields and handle them and you can also skip subnodes if you want.
There are also a lot of other nice features in the JCRUtil that could help you.

In our case if we enter name = myName, email= myEmail, title=myTitle and phone = myPhone we will get the following structure

./content/myName (cq:Page)
../subproduct1 (nt:unstructured) -> with properties ( email:myEmail and title=myTitle)
../subproduct2 (nt:unstructured) -> with properties ( email:myEmail and title=myTitle)


Regards
/Johan

Avatar

Former Community Member

Hi Johan,

If i use the form component which is available in cq where i will change the action attribute of the form to action="/apps/my/servlets/path/create ? so that onsubmit i can execute my servlet.

Thanks

Ramya

Avatar

Level 1

i have followed your code in that case i am getting some error i tried a lot but couldn't solve this problem if u put some light on my issue i would be greatful thank you in advance i.e com.day.cq.commons.jcr,version=[5.7,6) -- Cannot be resolved