I have a list of strings in the list assetList.
How can I send the list in the http response in java servlet ?
I am very new to java.
Call this method after converting your list to a string:
private void writeResponse(HttpServletResponse response, String responseString) {
try {
PrintWriter out = response.getWriter();
out.println(responseString);
out.flush();
response.flushBuffer();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
To convert the list of strings to a string, see:
Best way to convert an ArrayList to a string
A list of object is an object. So is the same as adding a object in a response (serialization) and deserializing on the other side.
OutputStream out = response.getOutputStream();
oos = new ObjectOutputStream(out);
oos.writeObject(yourSerializableObject);
More info:
How to get Object from HttpResponse?
If you are free to chose the format of the response, and the response is primarily intended to be processed by a client application, then use JSON. Turn the list of strings into a JSON array (of strings) and send that.
I'd recommend JSON because:
You are best off with a standard format / serializatio scheme than a non-standard (i.e. custom) one.
JSON is easy to generate and parse, in a wide variety of programming languages.
JSON is text based and (relatively) human readable.
There are (of course) lots of alternatives, including language specific ones (Java object serialization), alternatives that are more compact, faster to encode, decode, and so on.
But JSON is a good de-facto choice for typical web-based application protocols.
i would suggest you to read more about servlets, JSP and ManagedBeans.
for the beggining its nice to now how these things works, but later you may upgrade and using JSF for Java Web Applications.
back to your question:
the usual way is using Java "Managed" Beans for that!
lets say you send a request to the servlet, the response should be a list of persons:
you create a Bean named Person.java with id, name, tel, ...etc with getter and setter methods.
then you would make a Controller Class like PersonManager.java
this object may have a method for getting a list of Persons or an emprty list
in your servlet you init these Datas and puting it in the REQUEST Scope for your response
here is an example how to do this in a Servlet:
public class YourServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
Person p = new Person();
p.setName("Mohamad ...");
p.set....
ArrayList phones = new ArrayList();
PhoneNumber ph = new PhoneNumber();
ph.set...;
ph.set...;
al.add(ph);
ph = new PhoneNumber();
ph.set...;
ph.set...;
al.add(ph);
a.setPhoneNumbers(al);
req.setAttribute("person", p);
RequestDispatcher rd = req.getRequestDispatcher("yourResult.jsp");
rd.forward(req, res);
}
}
in your JSP you can then retrieve the results and loop over the list or what ever you would like to do with it!
Related
I have an request object, that contains a huge amount of data. But there is a filter in my code, where I need to take out just one element. At the moment I am Deserializing the whole object, which seems overkill to just get one element
This is part of a zuul filter
import com.netflix.zuul.context.RequestContext;
RequestContext ct = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
ObjectMapper mapper = new ObjectMapper();
ServletInputStream stream = null;
try {
stream = request.getInputStream();
GetPageRequest page = mapper.readValue(stream,GetPageRequest.class);
log.info("URL IN BODY "+page.getUrl());
It seems over kill to deserialize an entire object to get one element but I cant think of a more efficient and optomized way
At it's simplest the request payload can just be a string so you could read the input as a string and then parse what you want out using a regular expression or an indexOf or whatever suits best?
With thanks to everyone. I created this method. Streamed inputstream into a string Created a JSONObject which takes in and tokenizies the string
private String getURLFromRequest(ServletInputStream stream) throws IOException, JSONException {
String requestStr = IOUtils.toString(stream, "UTF-8");
JSONObject jsonObj = new JSONObject(requestStr);
return (String) jsonObj.get("url");
}
I have currently started a kind of diary project to teach myself how to code, which I write in Java. The project has a graphical interface which I realized with JavaFX.
I want to write data into a JSON file, which I enter into two text fields and a slider. Such a JSON entry should look like this:
{
"2019-01-13": {
"textfield1": "test1",
"textfield2": "test2",
"Slider": 2
}
}
I have already created a class in which the values can be passed and retrieved by the JSONWriter.
The class looks like this:
public class Entry {
private String date, textfield1, textfield2;
private Integer slider;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTextfield1() {
return textfield1;
}
public void setTextfield1(String textfield1) {
this.textfield1 = textfield1;
}
public String getTextfield2() {
return textfield2;
}
public void setTextfield2(String textfield2) {
this.textfield2 = textfield2;
}
public Integer getSlider() {
return slider;
}
public void setSlider(Integer slider) {
this.slider= slider;
}
}
The code of the JSONWriter looks like this:
void json() throws IOException {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonWriter writer = new JsonWriter(new FileWriter("test.json",true));
JsonParser parser = new JsonParser();
Object obj = parser.parse(new FileReader("test.json"));
JsonObject jsonObject = (JsonObject) obj;
System.out.println(jsonObject);
writer.beginObject();
writer.name(entry.getDate());
writer.beginObject();
writer.name("textfield1").value(entry.getTextfield1());
writer.name("textfield2").value(entry.getTextfield2());
writer.name("Slider").value(entry.getSlider());
writer.endObject();
writer.endObject();
writer.close();
}
The date is obtained from the datepicker. Later I want to filter the data from the Json file by date and transfer the containing objects (textfield 1, textfiel2, slider) into the corresponding fields.
If possible, I would also like to try to overwrite the objects of a date. This means, if an entry of the date already exists and I want to change something in the entries, it should be replaced in the JSON file, so I can retrieve it later.
If you can recommend a better memory type for this kind of application, I am open for it. But it should also be compatible with databases later on. Later I would like to deal with databases as well.
So far I have no idea how to do this because I am still at the beginning of programming. I've been looking for posts that could cover the topic, but I haven't really found anything I understand.
You could start without JsonParser and JsonWriter and use Gson's fromJson(..) and toJson(..) because your current Json format is easily mapped as a map of entry POJOs.
Creating some complex implementation with JsonParser & JsonWriter might be more efficient for big amounts of data but in that point you already should have studied how to persist to db anyway.
POJOs are easy to manipulate and they can be later easily persisted to db - for example if you decide to use technology like JPA with only few annotations.
See below simple example:
#Test
public void test() throws IOException {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
// Your current Json seems to be a map with date string as a key
// Create a corresponding type for gson to deserialize to
// correct generic types
Type type = new TypeToken<Map<String, Entry>>() {}.getType();
// Check this file name for your environment
String fileName = "src/test/java/org/example/diary/test.json";
Reader reader = new FileReader(new File(fileName));
// Read the whole diary to memory as java objects
Map<String, Entry> diary = gson.fromJson(reader, type);
// Modify one field
diary.get("2019-01-13").setTextfield1("modified field");
// Add a new date entry
Entry e = new Entry();
e.setDate("2019-01-14");
e.setScale(3);
e.setTextfield1("Dear Diary");
e.setTextfield1("I met a ...");
diary.put(e.getDate(), e);
// Store the new diary contents. Note that this one does not overwrite the
// original file but appends ".out.json" to file name to preserver the original
FileWriter fw = new FileWriter(new File(fileName + ".out.json"));
gson.toJson(diary, fw);
fw.close();
}
This should result test.json.out.json like:
{
"2019-01-13": {
"textfield1": "modified field",
"textfield2": "test2",
"Slider": 2
},
"2019-01-14": {
"date": "2019-01-14",
"textfield1": "Dear Diary",
"textfield2": "I met a ...",
"Slider": 3
}
}
Note that I also made little assumption about this:
// Just in case you meant to map "Slider" in Json as "scale"
#SerializedName("Slider")
private Integer scale;
I will give you general tips up to you to go deeper.
First of all, I recommend you this architecture that is common on web-applications or even desktop apps to get the front-end layer separately of back-end server:
Front-end (use Java Fx if you want). Tutorial: http://www.mastertheboss.com/jboss-frameworks/resteasy/rest-services-using-javafx-tutorial
Back-end (Java 1.8, Springboot, MySQL database). Example: there are tons of examples and tutorials using this stack, I recommend mykong or baeldung blogs.
The front-end will communicate to server over HTTP request through back-end REST API using JSON or XML format for messaging. In real life there are physically separated but just create 2 different java projects running on different ports.
For the back-end, just follow the tutorial to get up and running a REST API server. Set up MVC pattern: Controller layer, Service layer, Repository layer, model layer, dto layers, etc. For your specific model I recommend you the following:
selected_date: Date
inputs: Map of strings
size: Integer
On Front-end project with Java FX, just re-use the code you already wrote and add some CSS if you want. Use the components actions to call the back-end REST API to create, retrieve, update and delete your data from date-picker or whatever operation you want to do.
You will transform java objects into JSON strings permanently, I recommend you to use Gson library or Jackson library that do this in a direct way and it is not need to build the JsonObject manually. If you still want to write the JSON into a file, transform the java object into string (this is a string with the object written in JSON format) using the mentioned libraries, and then write the string into file. But I strongly believe it will more practice if you implement database.
Hope it helps
Before proceeding I realise that there's a similar question (Passing a List from Servlet to JSP) from a couple of years ago. I realise that it is possible to set the list I'm trying to pass as a session attribute but out of curiosity I wondered if it's possible to use the PrintWriter object to send the data back to the JSP page.
JSP
<script type="text/javascript">
function getEngineSchemes(engineID) {
$.get('SchemeTypeServlet', {
action: "getSchemes",
engineID: engineID
},
function(data, status){
}).fail(function() {
alert("Error obtaining schemes for engine with engine id: " + engineID);
});
}
</script>
</body>
Servlet
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Set type of response
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
//get parameters that may be passed from client to determine which methods should be called
String action = request.getParameter("action");
if(action.equalsIgnoreCase("getSchemesForEngine")) {
Integer engineID = Integer.parseInt(request.getParameter("engineID"));
List<String> schemeNames = getSchemeNamesForEngine(engineID);
response.getWriter(). //insert code to send object back to JSP
response.getWriter().flush();
}
Options
One solution I think may be reasonable would be to create a JSONObject and have something along the lines of
response.setContentType("application/json");
JSONObject json = new JSONObject();
for(String name : schemeNames) {
json.put(engineID, name);
}
response.getWriter().write(json.toJSONString());
response.getWriter().flush();
I haven't tested the above code but I just want to know if that seems like the best solution to my problem or if I'm making it overly complicated? Maybe there's a far simpler solution to my question.
I think you are having things messed up in your head. First of all, you cannot sent text or any kind of data from a servlet to a jsp. The proper way to do this is to use the session and use response.sendRedirect or RequestDispatcher.forward methods. But this will ignore any calls made before to the servlet's Writer Object.
Updates:
For now using a Map. Class that wants to send something to other instance sends the object, the routing string.
Use an object stream, use Java serializable to write the object to servlet.
Write String first and then the object.
Receiving servlet wraps input stream around a ObjectInputStream. Reads string first and then the Object. Routing string decides were it goes.
A more generic way might have been to send a class name and its declared method or a Spring bean name, but this was enough for us.
Original question
Know the basic way but want details of steps. Also know I can use Jaxb or RMI or EJB ... but would like to do this using pure serialization to a bytearray and then encode that send it from servlet 1 in jvm 1 to servlet 2 in jvm 2 (two app server instances in same LAN, same java versions and jars set up in both J2EE apps)
Basic steps are (Approcah 1) :-
serialize any Serializable object to a byte array and make a string. Exact code see below
Base64 output of 1. Is it required to base 64 or can skip step 2?
use java.util.URLEncode.encode to encode the string
use apache http components or URL class to send from servlet 1 to 2 after naming params
on Servlet 2 J2EE framework would have already URLDecoced it, now just do reverse steps and cast to object according to param name.
Since both are our apps we would know the param name to type / class mapping. Basically looking for the fastest & most convenient way of sending objects between JVMs.
Example :
POJO class to send
package tst.ser;
import java.io.Serializable;
public class Bean1 implements Serializable {
/**
* make it 2 if add something without default handling
*/
private static final long serialVersionUID = 1L;
private String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
}
* Utility *
package tst.ser;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URLEncoder;
public class SerUtl {
public static String serialize(Object o) {
String s = null;
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream(new ByteArrayOutputStream());
os.writeObject(o);
s = BAse64.encode(os.toByeArray());
//s = URLEncoder.encode(s, "UTF-8");//keep this for sending part
} catch (Exception e) {
// TODO: logger
e.printStackTrace();
return null;
} finally {
// close OS but is in RAM
try {
os.close();// not required in RAM
} catch (Exception e2) {// TODO: handle exception logger
}
os = null;
}
return s;
}
public static Object deserialize(String s) {
Object o = null;
ObjectInputStream is = null;
try {
// do base 64 decode if done in serialize
is = new ObjectInputStream(new ByteArrayInputStream(
Base64.decode(s)));
o = is.readObject();
} catch (Exception e) {
// TODO: logger
e.printStackTrace();
return null;
} finally {
// close OS but is in RAM
try {
is.close();// not required in RAM
} catch (Exception e2) {// TODO: handle exception logger
}
is = null;
}
return o;
}
}
**** sample sending servlet ***
Bean1 b = new Bean1(); b.setS("asdd");
String s = SerUtl.serialize(b);
//do UrlEncode.encode here if sending lib does not.
HttpParam p = new HttpParam ("bean1", s);
//http components send obj
**** sample receiving servlet ***
String s = request.getParameter("bean1");
Bean1 b1 = (Beean1)SerUtl.deserialize(s);
Serialize any Serializable object with to a byte array
Yes.
and make a string.
No.
Exact statements see below
os = new ObjectOutputStream(new ByteArrayOutputStream());
os.writeObject(o);
s = os.toString();
// s = Base64.encode(s);//Need this some base 64 impl like Apache ?
s = URLEncoder.encode(s, "UTF-8");
These statements don't even do what you have described, which is in any case incorrect. OutputStream.toString() doesn't turn any bytes into Strings, it just returns a unique object identifier.
Base64 output of 1.
The base64 output should use the byte array as the input, not a String. String is not a container for binary data. See below for corrected code.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
os = new ObjectOutputStream(baos);
os.writeObject(o);
os.close();
s = Base64.encode(baos.toByeArray()); // adjust to suit your API
s = URLEncoder.encode(s, "UTF-8");
This at least accomplishes your objective.
Is it required to base 64 or can skip step 2?
If you want a String you must encode it somehow.
Use java.util.URLEncode.encode to encode the string
This is only necessary if you're sending it as a GET or POST parameter.
Use apache http components or URL class to send from servlet 1 to 2 after naming params
Yes.
On Servlet 2 J2EE framework would have already URLDecoded it, now just do reverse steps and cast to object according to param name.
Yes, but remember to go directly from the base64-encoded string to the byte array, no intermediate String.
Basically looking for the fastest & most convenient way of sending objects between JVMs.
These objectives aren't necessarily reconcilable. The most convenient these days is probably XML or JSON but I doubt that these are faster than Serialization.
os = null;
Setting references that are about to fall out of scope to null is pointless.
HttpParam p = new HttpParam ("bean1", s);
It's possible that HttpParam does the URLEncoding for you. Check this.
You need not convert to string. You can post the binary data straight to the servlet, for example by creating an ObjectOutputStream on top of a HttpUrlConnection's outputstream. Set the request method to POST.
The servlet handling the post can deserialize from an ObjectStream created from the HttpServletRequest's ServletInputStream.
I'd recommend JAXB any time over binary serialization, though. The frameworks are not only great for interoperability, they also speed up development and create more robust solutions.
The advantages I see are way better tooling, type safety, and code generation, keeping your options open so you can call your code from another version or another language, and easier debugging. Don't underestimate the cost of hard to solve bugs caused by accidentally sending the wrong type or doubly escaped data to the servlet. I'd expect the performance benefits to be too small to compensate for this.
Found this Base64 impl that does a lot of the heavy lifting for me : http://iharder.net/base64
Has utility methods :
String encodeObject(java.io.Serializable serializableObject, int options )
Object decodeToObject(String encodedObject, int options, final ClassLoader loader )
Using :
try {
String dat = Base64.encodeObject(srlzblObj, options);
StringBuilder data = new StringBuilder().append("type=");
data.append(appObjTyp).append("&obj=").append(java.net.URLEncoder.encode(dat, "UTF-8"));
Use the type param to tell the receiving JVM what type of object I'm sending. Each servlet/ jsps at most receives 4 types, usually 1. Again since its our own app and classes that we are sending this is quick (as in time to send over the network) and simple.
On the other end unpack it by :
String objData = request.getParameter("obj");
Object obj = Base64.decodeToObject(objData, options, null);
Process it, encode the result, send result back:
reply = Base64.encodeObject(result, options);
out.print("rsp=" + reply);
Calling servlet / jsp gets the result:
if (reply != null && reply.length() > 4) {
String objDataFromServletParam = reply.substring(4);
Object obj = Base64.decodeToObject(objDataFromServletParam, options, null);
options can be 0 or Base64.GZIP
You can use JMS as well.
Apache Active-MQ is one good solution. You will not have to bother with all this conversion.
/**
* #param objectToQueue
* #throws JMSException
*/
public void sendMessage(Serializable objectToQueue) throws JMSException
{
ObjectMessage message = session.createObjectMessage();
message.setObject(objectToQueue);
producerForQueue.send(message);
}
/**
* #param objectToQueue
* #throws JMSException
*/
public Serializable receiveMessage() throws JMSException
{
Message message = consumerForQueue.receive(timeout);
if (message instanceof ObjectMessage)
{
ObjectMessage objMsg = (ObjectMessage) message;
Serializable sobject = objMsg.getObject();
return sobject;
}
return null;
}
My point is do not write custom code for Serialization, iff it can be avoided.
When you use AMQ, all you need to do is make your POJO serializable.
Active-MQ functions take care of serialization.
If you want fast response from AMQ, use vm-transport. It will minimize n/w overhead.
You will automatically get benefits of AMQ features.
I am suggesting this because
You have your own Applications running on network.
You need a mechanism to transfer objects.
You will need a way to monitor it as well.
If you go for custom solution, you might have to solve above things yourselves.
I'm trying to make a RESTful Web Service which implements all four CRUD operations. I got stuck in "Create" because somehow I'm not able to obtain the posted data. Here is the method I wrote. Just as a info, I'm using Jersey RI of JAX-RS + JAXB XML to serialize objects.
Here it is:
#POST
#Consumes("application/xml")
public Response createStudent(InputStream is) {
Student st = this.readStudent(is);
st.setUserId(idCounter.incrementAndGet());
studentDB.put(st.getUserId(), st);
System.out.println("Created student " + st.getUserId());
return Response.created(URI.create("/student/"+ st.getUserId())).build();
}
And the readStudent method is below:
protected Student readStudent(InputStream is){
JAXBContext ctx;
Student st = null;
try {
String xml = is.toString();
System.out.println(xml);
ctx = JAXBContext.newInstance(Student.class);
st = (Student) ctx.createUnmarshaller().unmarshal(new StringReader(xml));
return st;
} catch (JAXBException e){
e.printStackTrace();
}
finally { return st; }
}
Can someone give me some light about this? I exhausted every idea to make this works and nothing worked!
Thanks in advance.
I think your problem is the line in which you use the toString() method to get the string of the InputStream:
String xml = is.toString();
You should read the data in the input stream and append it to a new string. The toString() is a string representation of the stream, but not the contents of it. You have to use the read methods of the InputStream and append the bytes to a new String using a StringBuilder or a StringWriter.
After sweating hard looking for a answer, I've managed to fix it! It was just a missing dependency to resteasy-jaxb-provider.jar . Without this .jar the servlet wasn't able to do the automatic conversion from POJO to XML and vice-versa
I don't understand why you don't have createStudent(Student student) instead. The whole idea of jsr311 is for the parameters to also be parsed and given to the function.
EDIT
For a second I thought I was confusing things. But I found an example here http://blogs.oracle.com/enterprisetechtips/entry/configuring_json_for_restful_web
#PUT
#Consumes("application/json")
public synchronized void setStatus(StatusInfoBean status) {
...
}
So you don't even need to parse xml or json. This work is already done for you