I have an action class like
public class DataProcessor extends ActionSupport{
private JSONObject object;
public JSONObject getObject() {
return object;
}
public void setObject(JSONObject object) {
this.object = object;
}
#Override
public String execute() throws Exception {
.......
return SUCCESS;
}
}
My XML mapping is like
<package name="default" extends="struts-default" namespace="/">
<action name="process" class="com.demo.DataProcessor">
<result type="success">home.jsp</result>
</action>
</package>
on jsp page if i write <s:property value="object"/> it prints json data. bt if i write
<s:property value="object.name"/>
or
<s:property value="#object.name"/>
or
<s:property value="${#object.name}"/> it is printing nothing.
How can i parse json object in jsp page?
You do not need to parse JSON you need to retrieve value from it. Assuming that your object is org.json.JSONObject you can get value from it by calling get method and passing key as string.
<s:property value="object.get('name')"/>
You can parse JSON using the library function parseJSON like in this example
<s:textfield id="name" name="name"/>
<s:textfield id="mobile" name="mobile"/>
<script type="text/javascript">
$(document).ready(function() {
var obj = $.parseJSON('<s:property value="object"/>');
$("name").val(obj.name);
$("mobile").val(obj.mobile);
});
</script>
This script will replace the values (if any) from the action bean populated when JSP was rendered. The textfields should be mapped to the action bean correspondingly.
Related
I have to modify a process made with SpringBatch, the procedure it's easy.
Actually, the program reads records from a database and exports the results to XML files (one by each table)
Now, I want to write JSON files instead XML files, I didn't find how to make it possible, but reading and reading I have something close to that I want.
I wrote an ItemProcessor class like this
#Component("jSONObjectProcessor")
public class JSONObjectProcessor implements ItemProcessor<Object, String> {
private Gson gson = new Gson();
private List<Object> array = new ArrayList<Object>();
#Override
public String process(Object item) throws Exception {
array.add(item);
return gson.toJson(array);
}
}
Obviously, if I have 6 items; this going to return 6 List, like it does right now
1st item
[
{
"number":0,
"string":"abc",
"desc":"abcdefg"
}
]
2nd item
[
{
"number":0,
"string":"abc",
"desc":"abcdefg"
},
{
"number":1000,
"string":"xyz",
"desc":"uvwxyz"
}
]
//more lists by the total of items
To write the files I'm using org.springframework.batch.item.file.FlatFileItemWriter class.
I want to find the way to return all the items in a List and give it JSON form and write this json in the file. I'm in the correct way or there are another, more elegant form. It's possible?
Thanks!
Update
I have made the changes (thanks #Sanj), but I miss the comma (,) delimiter between each object.
My ItemWriter it's defined like this
<bean id="itemWriterRegConstantes" scope="step"
class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="#{jobParameters['fileOutput']}" />
<property name="shouldDeleteIfExists" value="true" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value="," />
</bean>
</property>
<property name="footerCallback" ref="headerFooterCallback" />
<property name="headerCallback" ref="headerFooterCallback" />
</bean>
The output file now looks like this
[
{"number":0,"string":"abcd","desc":"efgh"} //no comma
{"number":1000,"string":"xyz","valor":"xyzw"}
]
How add it?
Additionaly, how can I print all the content in a single line? (to minify the content) It's possible?
My Solution
I had to create my own class (really I made change to the FlatFileItemWriter SpringBatch class, it's here
Output: a file with an one line JSON array content.
Thanks!
Return single json for every item from ItemProcessor
#Component("jSONObjectProcessor")
public class JSONObjectProcessor implements ItemProcessor<Object, String> {
private Gson gson = new Gson();
#Override
public String process(Object item) throws Exception {
return gson.toJson(item);
}
}
Create header and footer call backs. Basically they will be used to start and close the array respectively.
public class JSONHeaderFooterCallBack implements FlatFileHeaderCallback, FlatFileFooterCallback{
#Override
public void writeHeader(Writer writer) throws IOException {
writer.write("[" + System.getProperty("line.separator"));
}
#Override
public void writeFooter(Writer writer) throws IOException {
writer.write("]");
}
}
Associate the callbacks with FlatFileItemWriter
FlatFileItemWriter<String> writer = new FlatFileItemWriter<String>();
//Setting header and footer.
JSONHeaderFooterCallBack headerFooterCallback = new JSONHeaderFooterCallBack();
writer.setHeaderCallback(headerFooterCallback);
writer.setFooterCallback(headerFooterCallback);
writer.setResource(new FileSystemResource(System.getProperty("user.dir") + "/output.json"));
Now you can use "writer" to write all records as a json array to a file.
---update--
Use CustomLineAggregator to append comma at the end of every record:
public class CustomLineAggregator<String> implements LineAggregator<String> {
#Override
public String aggregate(String item) {
return item+",";
}
}
I have a Spring MVC 3.1.0 project and I have configured a ContentNegotiatingViewResolver bean to automatically generate JSON output for a given endpoint (which uses org.springframework.web.servlet.view.json.MappingJacksonJsonView).
I have a few controller methods which add data to the JSP page (via model.addAttribute("foo", fooService.getFoo());) that I don't want to appear in the JSON output.
I have tried adding a #JsonIgnore annotation to my service method getFoo() (which returns a Map<String, String>) but it doesn't work. I still see the foo object being marshalled in my JSON output when I hit that controller.
Can anyone suggest another way of achieving this or tell me why the JsonIgnore annotation is not working?
MappingJacksonJsonView serializes all the contents of the model into a json - all the objects that you have placed in your model object, so it does not matter if you have marked one of the service methods with #JsonIgnore, as long it ends up in the model which it does because of the call to model.addAttribute("foo".. it would get serialized. The fix could be simply to not add the model attribute, or to use #ResponseBody which will give you control over the specific response object that is being serialized.
Another option is to specify the exact keys that you will be using when configuring MappingJacksonJsonView:
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" name="jsonView">
<property name="modelKeys">
<set>
<value>model1</value>
<value>model2</value>
</set>
</property>
</bean>
Extend MappingJackson2JsonView class and override filterMap(Map model) method.
In the filterMap method filter out keys with the name of modelAttributes you need to exclude.
public class MappingJackson2JsonViewExt extends MappingJackson2JsonView {
private static final Set<String> EXCLUDED_KEYS = new HashSet<>();
public static void excludeModelKey(final String key) {
EXCLUDED_KEYS.add(key);
}
#Override
protected Object filterModel(final Map<String, Object> model) {
final Map<String, Object> filteredModel = model.entrySet().stream()
.filter(e -> {
final String key = e.getKey();
return !EXCLUDED_KEYS.contains(key);
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return super.filterModel(filteredModel);
}
}
I have a test method:
#Test
public void testHello_with_muleXmlConfig() throws Exception {
MuleClient client = new MuleClient("mule-config-test.xml");
client.getMuleContext().start();
MuleMessage result = client.send("http://127.0.0.1:8080/hello", "some data", null);
assertNotNull(result);
assertNull(result.getExceptionPayload());
assertFalse(result.getPayload() instanceof NullPayload);
assertEquals("hello", result.getPayloadAsString());
}
Here (client.send("http://127.0.0.1:8080/hello", "some data", null)), I'm passing the parameter/data = 'some data'.
And I have a class:
public class HelloWorld {
public String sayHello() {
return "hello";
}
}
which is exposed as spring bean in mule-config.xml:
<spring:bean id="helloWorld" class="org.mule.application.hello.HelloWorld"/>
<flow name="HelloWorld">
<inbound-endpoint address="http://127.0.0.1:8080/hello"/>
<invoke method="sayHello" object-ref="helloWorld"/>
</flow>
What I should do to pass the parameter 'hello' into the 'sayHello()' method. If just changing it to 'sayHello(String text)' - it will not work.
You need to add this to the invoke element:
methodArguments="#[message.getPayload()]" methodArgumentTypes="java.lang.String"
Not sure about how/if invoke works: I suggest you use component instead.
If you change your method to accept a String, like for example:
public String sayHello(final String text)
{
return "hello:" + text;
}
then you also need to use an object-to-string-transformer to deserialize the inbound input stream to a String:
<flow name="HelloWorld">
<inbound-endpoint address="http://127.0.0.1:8080/hello" />
<object-to-string-transformer />
<component>
<spring-object bean="helloWorld" />
</component>
</flow>
Try This :
add this in your flow :
<invoke object-ref="helloWorld" method="sayHello" methodArguments="#[message.inboundProperties.'http.query.params'.name]" doc:name="Invoke" />
and this is the invoked method :
public String sayHello(String name) {
return String.format("Hello %s!", name);
}
I am back with one more complex thing. This time i don't know whether i am logically correct.
I have to return the data from database as json object. In this json object i have return some values which is foreign key with other tables in the database. I got the values correctly from database and now i want to iterate the forien key values from my ajax success using the struts iterate tag. It is possible to iterate if we can iterate the json values an object, Anybody please share the idea if i am correct.
<s:iterator value="listdoctorProducts" status="st" >
<div class="productListing">
<h3><span><s:property value="inventory.name" /></span> - <s:property value="inventory.description" /> </h3>
<div class="productDtlLeft">
<s:iterator value="inventory.pronovaInventories" >
<img src="images/pronova/products/<s:property value="image" />" width="31" height="94" alt="" />
</s:iterator>
</div>
<s:iterator value="inventory.productRatings" status="st">
<s:if test="(#st.index+1)==1">
<s:set var="no2" value="rating" />
</s:if>
<s:else>
<s:set var="no2" value="#no2+rating" />
</s:else>
<s:set var="count" value="#st.index+1" />
</s:iterator>
<s:set var="aver" value="%{#no2*10/#count}"/>
<s:set var="result" value="#aver*1.0/10"/>
<div class="productDtlRight">
<div class="ratting">
<div class="rattingStar">bg</div>
<div class="rattingOrange" style="width:<s:property value="(#result/5)*100"/>%;">bg</div>
</div>
<span>(<s:property value="#aver*1.0/10"/>)</span>
<div class="clear"></div>
<s:set var="no2" value="0" />
<s:bean name="com.zoondia.common.calculationBean" var="decCalBeansuggestedPrice">
<s:param name="valueOne" value="retailPrice"/>
<s:param name="decimalPlace">#.##</s:param>
</s:bean>
<h4>$<s:property value="#decCalBeansuggestedPrice.decimalPointConversionResult" /></h4>
<a class="addtoCart" href="javaScript:void(0)">View All</a>
</div>
<div class="clear"></div>
</div>
</s:iterator>
In this jsp page you can see that i have a database object list in listdoctorProducts and i can get the values of productRating table by accessing this like this
<s:iterator value="inventory.productRatings" status="st">
<s:if test="(#st.index+1)==1">
<s:set var="no2" value="rating" />
</s:if>
and this code i have list here is for first page and if user click for second page i have to list the second page for the user and we need to do this in ajax by populating json values. My problem is how could i write an iterator like this if i retrieve the response as ajax?
Here is my Action class
public String getEcommerceWidgetFourJson(){
try{
Doctor DtObj = null;
Map sessionSingleDoctor = ActionContext.getContext().getSession();
Object Obj = null;
Obj = sessionSingleDoctor.get("Doctor");
DtObj = (Doctor) Obj;
int totalCount = DoctorDao.getInstance().totalNumberOfdoctorToProductsForJson(DtObj.getId());
numberOfRowsPerPage = Integer.parseInt(getText("ecommerce.widget.product.list.four"));
totalNumberOfRows = (int)Math.ceil((float)totalCount/numberOfRowsPerPage);
if(pageNum < 1){
pageNum = 1;
}else if(pageNum > lastRows){
pageNum = lastRows;
}
listdoctorProducts = DoctorDao.getInstance().getDoctorProductsAsJson(DtObj.getId(),numberOfRowsPerPage,pageNum);
}catch(Exception e){
e.printStackTrace();
}
return SUCCESS;
}
I have not added the variable declaration and setter and getter here. And here is my Dao function from where i access the data from database
public List<DoctorToProducts> getDoctorProductsAsJson(int DocId,int numberOfRowsPerPage, int pageNum){
List<DoctorToProducts> dp = null;
DoctorToProducts ldp = null;
SessionFactory sessionFactory =
(SessionFactory) ServletActionContext.getServletContext().getAttribute(HibernateListener.KEY_NAME);
Session Hibernatesession = sessionFactory.openSession();
Hibernatesession.beginTransaction();
Query q = (Query) Hibernatesession.createQuery("select id,inventory.id,doctor.id,inventory.pronovaInventories,retailPrice,unitCreditValue from DoctorToProducts where doctor.id="+DocId);
q.setFirstResult((pageNum-1)*numberOfRowsPerPage);
q.setMaxResults(numberOfRowsPerPage);
dp = q.list();
Hibernatesession.getTransaction().commit();
Hibernatesession.flush();
return dp;
}
and my struts.xml is
<action name="frPdtListPagination" class="com.zoondia.action.DoctorPdtsPagination" method="getEcommerceWidgetFourJson">
<result type="json">
</result>
</action>
Just add the action for this json call only.
This is going to be guess work on my part...
The short answer to your question is: no. That is you can't both return json and iterate over the objects in your action producing meaningful results because of the way it has been set up.
Lets change the set up so the answer becomes a yes. This is the quick version not tested:
//Not tested, this is just an example of what you can do
package com.quaternion.action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import java.util.List;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.beans.factory.annotation.Autowired;
public class DoctorActions extends ActionSupport implements Preparable {
#Autowired DoctorService doctorService; //injected from spring
List<String> doctorProducts;
#Override
public void prepare() {
doctorProducts = doctorService.getProducts();
}
#Action(results = {
#Result(type = "json", params = {
"includeProperties",
"doctorProducts"})
})
public String DoctorJsonProducts() {
return SUCCESS;
}
#Action
public String DoctorProducts(){
return SUCCESS;
}
}
Explanation of the above:
By having our Action implement Preparable struts2 will call the prepare method which uses the doctorService set doctorProducts. Note how clean the intention of the Action becomes when everything to do with Doctor management has been moved into its own service class, including transaction management.
Next note that our class creates two actions, one of which uses the json result type. The json result will serialise our list into JSON for us.
Some sort of dependency injection magic was used here, but you could have just as easily used the prepare method and a factory.
Further, the annotations cover what is required there is no need for any xml, however there is need for struts2-conventions-plugin jar and struts2-json-plugin jar.
So... you'll need to backtrack and rebuild your action to get the functionality you want because currently you have a list of json strings which is not what you want to write into your jsps.
So I'm trying to create a JSON object from a List of AcaClasses.
Action Class:
public class StudentJSONAction extends ActionSupport{
//Your result List
private List<AcaClass> gridModel;
public String getJSON() {
return execute();
}
public String execute() {
//Get the first student from the Factory and get their AcaClasses
gridModel = StudentFactory.getAll().get(0).getAcaClasses();
return SUCCESS;
}
//Getters and Setters
The StudentFactory is my interface to the hibernate database.
Struts.xml
<action name="getJSON" class="StudentJSONAction">
<result type="json">
<param name="enableSMD">true</param>
<param name="ignoreInterfaces">false</param>
</result>
</action>
When I call the getJSON action, all I get is:
{"methods":[],"objectName":null,"serviceType":"JSON-RPC","serviceUrl":"\/FlowridersSP\/getJSON","version":".1"}
This problem is very similar to mine but I would like to see if there is a solution using the Struts2 JSON Plugin
Question: Why am I not getting back a list of AcaClasses in JSON form?
My end goal is to plug in this JSON in the JQuery Grid Plugin
I am not familiar with JSON plugin, but are you correctly configuring the plugin to serialize the gridModel? A quick look at the plugin documentation suggests that you might want to set the root parameter also:
<action name="getJSON" class="StudentJSONAction">
<result type="json">
<param name="enableSMD">true</param>
<param name="ignoreInterfaces">false</param>
<param name="root">gridModel</param>
</result>
</action>
Also, try to identify if the problem is with StudentFactory or with the JSON serialization. You can set up gridModel with a list of dummy AcaClass objects and see if the serialization works correctly. Also, as suggested by #Quaternion, you can log the list of AcaClass objects loaded by StudentFactory and verify that it is loading the expected instances.