I have a simple HTML form to send a request to a REST API. It works well, when I submit, it sends the form data to API and displays the response in the browser.
<form name="theForm" action="localhost:8080/App/rest/consumeForm" method="post">
<input name="userName" value="Bob Smith" /><br/>
<input type="submit" value="submit"/>
</form>
Browser shows:
{"address": "12 First St.", "city": "Toronto"}
I would like to capture the response. Any ideas? (no ajax or javascript, just plain old Servlet or JSP please)
PART 2:
I now POST my form to a servlet I created, which handles the request and response from the REST API. It works nicely, but it needs the form data URLEncoded. Anyone know if there is a way to convert form data to such a string, or even convert form data to JSON directly?
String charset = java.nio.charset.StandardCharsets.UTF_8.name();
String userName = "Bob Smith";
String country = "Canada";
String queryString = String.format("userName=%s&country=%s"
,URLEncoder.encode(userName, charset)
,URLEncoder.encode(country, charset)
);
Can I build the above queryString dynamically?
//// send request
URLConnection connection = new URL("localhost:8080/App/rest/consumeForm").openConnection();
connection.setDoOutput(true); // Triggers POST.
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
try (OutputStream output = connection.getOutputStream()) {
output.write(queryString.getBytes(charset));
}
//// get response
BufferedReader apiResponse = new BufferedReader(new InputStreamReader((connection.getInputStream())));
String output;
System.out.println("\n\n\nrecieved....");
while ((output = apiResponse.readLine()) != null) {
System.out.println(output);
}
I would like to capture the response. Any ideas?
Install a servlet Filter that handles this. When it receives a request for the REST API endpoint, it can feed an HttpServletResponse to the next element in the chain that is equipped with any tooling you want. You would probably find HttpServletResponseWrapper to be a useful base class for your custom-tooled response class.
The Filter implementation might be along these lines:
public class ResponseCapturingFilter implements Filter {
private static final String SERVLET_TO_FILTER = "...";
#Override
public void init(ServletConfig config) {
// ...
}
#Override
public void destroy() {
// ...
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (((HttpServletRequest) request).getServletPath().equals(SERVLET_TO_FILTER)) {
response = new MyCapturingResponseWrapper(response);
}
chain.doFilter(request, response);
}
}
To capture the response text, you would want your wrapper to override at least getOutputStream() and getWriter() appropriately.
It turns out that submitting to a servlet using POST and communicating with the REST API using the servlet works for me. There may be better ways, but this seems relatively clean for junior developers to follow and maintain. (I'm still open to other options).
I build a queryString with the form data (req is the HttpServletRequest)
String theQueryString="domainId=1";
for(Entry<String, String[]> qsParm:req.getParameterMap().entrySet()) {
theQueryString+="&"+qsParm.getKey()+"="+URLEncoder.encode(req.getParameter(qsParm.getKey()), charset);
}
// set up connection to use as API interaction
URLConnection connection = new URL("localhost:8080/App/rest/consumeForm").openConnection();
connection.setDoOutput(true); // Triggers POST apparently
connection.setRequestProperty("Accept-Charset", java.nio.charset.StandardCharsets.UTF_8.name());
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + java.nio.charset.StandardCharsets.UTF_8.name());
// send request to API via connection OutputStream
try (OutputStream output = connection.getOutputStream()) {
output.write(theQueryString.getBytes(java.nio.charset.StandardCharsets.UTF_8.name())); // this sends the request to the API url
}
// get response from connection InputStream and read as JSON
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonMap = mapper.readTree(connection.getInputStream());
// now the response can be worked with in at least two ways that I have tried
String user1 = jsonMap.get("userName").asText();
String user2 = jsonMap.at("user").getValueAsText();
Related
I have several servlets that do things server side. On a few I just encode some unnecessary data and send it back, which seems pointless. Do you have to respond ? What happens when you just say return ? I've done that before and nothing seems to go wrong but I am relatively new to servlets. Are there consequences for simply returning that go above my head ? And what exactly happens when you return;
if(request.getParameter("name").equals("saveusedcards")) {
String sessId = request.getSession().getId();
//encode request with confirmation that cards were successfully updated
if(usersUpdatedCards.get(sessId).isEmpty()){
//no cards were seen
}
boolean success = DataDAO.updateCards(usersUpdatedCards.get(sessId));
if(success){
System.out.println("Data base update successfull!");
String responseMessage = new Gson().toJson("card successfully udpated");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
System.out.println("updated cards response message: "+responseMessage);
response.getWriter().write(responseMessage);
return;
} else {
System.out.println("Data base update failed...");
String responseMessage = new Gson().toJson("card was not successfully updated");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
System.out.println("updated cards response message: "+responseMessage);
response.getWriter().write(responseMessage);
return;
}
}
The servlet must produce an HTTP response for the client, however it is perfectly acceptable to return no content in the response body. When doing so your servlet should make this clear to the client by sending a response code of 204 (no content). Reference: https://httpstatuses.com/204
Here is an example of how you would set the response code from the doGet method. You could do the same from doPost or service methods.
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Do whatever work you need to do here...
res.setStatus(HttpServletResponse. SC_NO_CONTENT); // This returns a 204
}
I want send を伴う出力となって to backend java code via http get request.
My get call url is http://localhost:8080/test/getID?id=%E3%82%92%E4%BC%B4%E3%81%86%E5%87%BA%E5%8A%9B%E3%81%A8%E3%81%AA%E3%81%A3%E3%81%A6
Java code:
#RequestMapping(value = "/getCaseId")
public ModelAndView showCaseId(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
String msg = request.getParameter("id");
System.out.println("URL:"+msg);
return new ModelAndView("showID", "idList", null);
}
Above piece of code prints URL:ãä¼´ãåºåã¨ãªã£ã¦.
So what's change i need to do get the exact Japanese text what i have passed from front end.
Try changing your msg line to:
String msg = new String(
request.getParameter("id").getBytes(StandardCharsets.ISO_8859_1),
StandardCharsets.UTF_8
);
If that will work it means that your application server (Tomcat? jetty?) is not configured correctly to handle UTF-8 in URLs.
If you use eclipse IDE, you need to check Text File encoding. Please check with the following figure.
The problem is that the submitted query string is getting mutilated on the way into your server-side script, because getParameter() uses ISO-8559-1 instead of UTF-8.
So i modified my code as below and now its working
#RequestMapping(value = "/getCaseId")
public ModelAndView showCaseId(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
String msg = new String(request.getParameter("id").getBytes("iso-8859-1"), "UTF-8")
System.out.println("URL:"+msg);
return new ModelAndView("showID", "idList", null);
}
I found this solution in http://help-forums.adobe.com/content/adobeforums/en/experience-manager-forum/adobe-experience-manager.topic.html/forum__lxgr-hi_i_am_havi.html.
I am using JSF2. I have implemented a custom faces servlet like so:
public class MyFacesServletWrapper extends MyFacesServlet {
// ...
}
wherein I'm doing some authorization checks and sending a redirect when the user is not logged in:
public void service(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (...) {
String loginURL = req.getContextPath() + "/LoginPage.faces";
res.sendRedirect(loginURL);
}
}
This works when the user tries to navigate to another page. However, this does not work when a JSF form is submitted by a JSF command link/button. The line sendRedirect() line is hit and executed, no exception is been thrown, but the user stays at the same page. Basically, there's no visual change at all.
Why does this work on page navigation, but not on form submit?
Your concrete problem is most likely caused because your JSF command link/button is actually sending an ajax request which in turn expects a special XML response. If you're sending a redirect as response to an ajax request, then it would just re-send the ajax request to that URL. This in turn fails without feedback because the redirect URL returns a whole HTML page instead of a special XML response. You should actually be returning a special XML response wherein the JSF ajax engine is been instructed to change the current window.location.
But you've actually bigger problems: using the wrong tool for the job. You should use a servlet filter for the job, not a homegrown servlet and for sure not one which supplants the FacesServlet who is the responsible for all the JSF works.
Assuming that you're performing the login in a request/view scoped JSF backing bean as follows (if you're using container managed authentication, see also 2nd example of Performing user authentication in Java EE / JSF using j_security_check):
externalContext.getSessionMap().put("user", user);
Then this kickoff example of a filter should do:
#WebFilter("/*") // Or #WebFilter(servletNames={"facesServlet"})
public class AuthorizationFilter implements Filter {
private static final String AJAX_REDIRECT_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<partial-response><redirect url=\"%s\"></redirect></partial-response>";
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String loginURL = request.getContextPath() + "/login.xhtml";
boolean loggedIn = (session != null) && (session.getAttribute("user") != null);
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER + "/");
boolean ajaxRequest = "partial/ajax".equals(request.getHeader("Faces-Request"));
if (loggedIn || loginRequest || resourceRequest)) {
if (!resourceRequest) { // Prevent browser from caching restricted resources. See also https://stackoverflow.com/q/4194207/157882
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response); // So, just continue request.
}
else if (ajaxRequest) {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().printf(AJAX_REDIRECT_XML, loginURL); // So, return special XML response instructing JSF ajax to send a redirect.
}
else {
response.sendRedirect(loginURL); // So, just perform standard synchronous redirect.
}
}
// ...
}
See also:
Using JSF 2.0 / Facelets, is there a way to attach a global listener to all AJAX calls?
FullAjaxExceptionHandler does not show session expired error page on ajax button
FacesContext.getCurrentInstance().getExternalContext().redirect("newpage.xhtml"); try this.... in place of res.sendredirect(cpath).
I am trying to implement REST type architecture without using any framework. So I am basically calling a JSP from my client end which is doing a doPost() on to the remote server providing services. Now I am able to pass the data from client to server in JSON format but I don know how to read the response. Can someone help me out with this.
Client Side:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
....
....
HttpPost httpPost = new HttpPost("http://localhost:8080/test/Login");
ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
//Send post it as a "json_message" paramter.
postParameters.add(new BasicNameValuePair("json_message", jsonStringUserLogin));
httpPost.setEntity(new UrlEncodedFormEntity(postParameters));
HttpResponse fidresponse = client.execute(httpPost);
....
....
}
Server Side:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String jsonStringUserLogin = (String)request.getParameter("json_message");
....
....
request.setAttribute("LoginResponse", "hello");
// Here I need to send some string back to the servlet which called. I am assuming
// that multiple clients will be calling this service and do not want to use
// RequestDispatcher as I need to specify the path of the servlet.
// I am looking for more like return method which I can access through
// "HttpResponse" object in the client.
}
I just started with servlets and wanted to implement a REST service by myself. If you have any other suggestion please do share... Thank You,
in doPost you simply have to do :
response.setContentType("application/json; charset=UTF-8;");
out.println("{\"key\": \"value\"}"); // json type format {"key":"value"}
and this will return json data to client or servlet..
reading returned data using jquery ajax ...
on client side using jquery do the following :
$.getJSON("your servlet address", function(data) {
var items = [];
var keys= [];
$.each(data, function(key, val) {
keys.push(key);
items.push(val);
});
alert(keys[0]+" : "+items[0]);
});
on servlet you know how to read json data
After you executed the post you can ready the response like this.
HttpEntity entity = fidresponse.getEntity();
BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent()));
String l = null;
String rest = "";
while ((l=br.readLine())!=null) {
rest=rest+l;
}
Here rest will contain your json response string.
You can also use StringBuffer.
However, I want to compress my responses with GZIP wheren possible. I tried using the Compression filter code available for free download in the headfirst site. It works great for html, images, css and javascript.
I post the filter next. It checks if GZIP is an accepted encoding and it adds gzip as Content-Encoding. See: wrappedResp.setHeader("Content-Encoding", "gzip");
public class CompressionFilter implements Filter {
private ServletContext ctx;
private FilterConfig cfg;
/**
* The init method saves the config object and a quick reference to the
* servlet context object (for logging purposes).
*/
public void init(FilterConfig cfg)
throws ServletException {
this.cfg = cfg;
ctx = cfg.getServletContext();
//ctx.log(cfg.getFilterName() + " initialized.");
}
/**
* The heart of this filter wraps the response object with a Decorator
* that wraps the output stream with a compression I/O stream.
* Compression of the output stream is only performed if and only if
* the client includes an Accept-Encoding header (specifically, for gzip).
*/
public void doFilter(ServletRequest req,
ServletResponse resp,
FilterChain fc)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// Dose the client accept GZIP compression?
String valid_encodings = request.getHeader("Accept-Encoding");
if ( (valid_encodings != null) && (valid_encodings.indexOf("gzip") > -1) ) {
// Then wrap the response object with a compression wrapper
// We'll look at this class in a minute.
CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response);
// Declare that the response content is being GZIP encoded.
wrappedResp.setHeader("Content-Encoding", "gzip");
// Chain to the next component (thus processing the request)
fc.doFilter(request, wrappedResp);
// A GZIP compression stream must be "finished" which also
// flushes the GZIP stream buffer which sends all of its
// data to the original response stream.
GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();
gzos.finish();
// The container handles the rest of the work.
//ctx.log(cfg.getFilterName() + ": finished the request.");
} else {
fc.doFilter(request, response);
//ctx.log(cfg.getFilterName() + ": no encoding performed.");
}
}
public void destroy() {
// nulling out my instance variables
cfg = null;
ctx = null;
}
}
I was using the next code to send JSON responses in Struts web application.
public ActionForward get(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
JSONObject json = // Do some logic here
RequestUtils.populateWithJSON(response, json);
return null;
}
public static void populateWithJSON(HttpServletResponse response,JSONObject json) {
if(json!=null) {
response.setContentType("text/x-json;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
try {
response.getWriter().write(json.toString());
} catch (IOException e) {
throw new ApplicationException("IOException in populateWithJSON", e);
}
}
}
It works fine without compression but if I compress JSON responses, I can not see my JSON objects anymore. I handle JSON Ajax calls with JQuery with code snippets as follows:
$.post(url,parameters, function(json) {
// Do some DOM manipulation with the data contained in the JSON Object
}, "json");
If I see the response with Firebug it is empty.
Should I refractor my compression filter to skip compression in JSON responses? or there is a workaround to this?
For me, it looks like JQuery does not recognize the response as JSON because I am adding the Gzip compression.
If I see the response with Firebug it
is empty.
There's your clue - it's not a JQuery problem, it's server-side. (I'm afraid I can't help you with that, other than to suggest you stop looking at the client-side)
There's no problem gzipping ajax responses - if you can't see the response in Firebug, then JQuery can't see it either.
you have to add one more header "content-encoding: gzip" if you are compressing it.
Have you tried with an explicit java-based client to ensure it's a problem with jQuery or browser? If java client fails, something is wrong with server response.
But I am guessing that whereas browser can deal with uncompression with direct requests, this is perhaps not applied to Ajax calls.
It's an interesting question, I hope we'll get a more definitive answer. :)